SCOM Serial Communication Protocol  0.5.2
scom_frame_queue.c
Go to the documentation of this file.
1 
9 #define HAL_LOG_CHANNEL SCOM
10 #define HAL_LOG_SUBCHANNEL FRAME
11 
12 #include "hal.h"
13 #include "scom_frame_queue.h"
14 //#include "scom_log.h"
15 #include "scom_crc.h"
16 
17 #if !defined SCOM_FRAME_QUEUE_LOCK_TIMEOUT
18 #define SCOM_FRAME_QUEUE_LOCK_TIMEOUT 5000
20 #endif
21 
22 // --------------------------------------------------------------------------------------
23 // SCOMFrameQueue_Init
24 // --------------------------------------------------------------------------------------
26 {
27  size_t i;
28 
29  if (frameQueue) {
30  frameQueue->lock = OSMUTEX_Create();
31  if (frameQueue->lock) {
32  if (frameQueue->pool) {
33  // we use pool
34  for (i = 0; i < frameQueue->size; i++) {
35  frameQueue->pool[i] = (SCOMFrameQueueItem ) {
36  .next = NULL,
38  .frame = {
39  .sync = 0xFF,
40  .sof = SCOM_SOF_CHARACTER
41  }
42  };
43  }
44  }
45  frameQueue->head = NULL;
46  return true;
47  }
48  }
49 
50  return false;
51 
52 } /* SCOMFrameQueue_Init */
53 
54 
55 // --------------------------------------------------------------------------------------
56 // SCOMFrameQueue_Deinit
57 // --------------------------------------------------------------------------------------
59 {
60  if ((frameQueue) && (frameQueue->lock)) {
61  OSMUTEX_Destroy(frameQueue->lock);
62  }
63 
64 } /* SCOMFrameQueue_Deinit */
65 
66 
67 // --------------------------------------------------------------------------------------
68 // SCOMFrameQueue_Insert
69 // --------------------------------------------------------------------------------------
71 {
72  SCOMFrameQueueItem *currentPosition;
73  SCOMFrameQueueItem *prevPosition;
74  size_t i;
75  uint8_t framePriority;
76 
77  if ((frameQueue) && (frame) && (frameQueue->lock)) {
78 
79  // acquire exclusive access to the queue
80  HAL_ASSERT_AND_EXECUTE((0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT))) {
81 
82  if (frameQueue->head == NULL) {
83  // no frames in queue, this will be the first item
84  frameQueue->head = frame;
85  frame->next = NULL;
86  OSMUTEX_Give(frameQueue->lock);
87  return true;
88  }
89 
90  i = frameQueue->size;
91  framePriority = SCOMFrame_GetPriority(&frame->frame);
92 
93  currentPosition = frameQueue->head;
94  prevPosition = NULL;
95  do {
96  if (SCOMFrame_GetPriority(&currentPosition->frame) < framePriority || currentPosition->state == SCOM_FRAME_EMPTY) {
97  // current element has lower priority than our new item
98  if (prevPosition) {
99  // there is a previous item
100  // so we make the previous item lead to our new one ...
101  prevPosition->next = frame;
102  // and the new one lead to the current one
103  frame->next = currentPosition;
104  } else {
105  // there is no previous position,
106  // so we're inserting the item at the beginning of the queue...
107  frameQueue->head = frame;
108  // ..and make it lead to the old head
109  frame->next = currentPosition;
110  }
111  // release exclusive access to the queue
112  OSMUTEX_Give(frameQueue->lock);
113  return true;
114  }
115  prevPosition = currentPosition;
116  currentPosition = currentPosition->next;
117  i--;
118  } while ((currentPosition) && (i));
119 
120  // place for the new item has not been found
121  if (i) {
122  // attach item at the end of queue
123  prevPosition->next = frame;
124  frame->next = NULL;
125  // release exclusive access to the queue
126  OSMUTEX_Give(frameQueue->lock);
127  return true;
128  }
129  // release exclusive access to the queue
130  OSMUTEX_Give(frameQueue->lock);
131  }
132  }
133 
134  return false;
135 
136 } /* SCOMFrameQueue_Insert */
137 
138 
139 // --------------------------------------------------------------------------------------
140 // SCOMFrameQueue_Delete
141 // --------------------------------------------------------------------------------------
143 {
144  SCOMFrameQueueItem *currentPosition;
145  size_t i;
146 
147  if ((frameQueue) && (frame) && (frameQueue->lock) && (frameQueue->head)) {
148 
149  // acquire exclusive access to the queue
150  HAL_ASSERT_AND_EXECUTE((0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT))) {
151 
152  if (frameQueue->head == frame){
153  // we're deleting the first item in the queue
154  frameQueue->head = frame->next;
155  frame->next = NULL;
156  // release exclusive access to the queue
157  OSMUTEX_Give(frameQueue->lock);
158  return true;
159  }
160 
161  currentPosition = frameQueue->head;
162  i = frameQueue->size;
163 
164  while(i--) {
165  if(currentPosition->next == frame) {
166  currentPosition->next = frame->next;
167  frame->next = NULL;
168  // release exclusive access to the queue
169  OSMUTEX_Give(frameQueue->lock);
170  return true;
171  }
172  currentPosition = currentPosition->next;
173  }
174  // release exclusive access to the queue
175  OSMUTEX_Give(frameQueue->lock);
176  }
177  }
178 
179  return false;
180 
181 } /* SCOMFrameQueue_Delete */
182 
183 
184 // --------------------------------------------------------------------------------------
185 // SCOMFrameQueue_Append
186 // --------------------------------------------------------------------------------------
188 {
189  if ((frameQueue) && (frame) && (frameQueue->lock)) {
190  // acquire exclusive access to the queue
191  HAL_ASSERT_AND_EXECUTE((0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT))) {
192 
193  frame->next = NULL;
194 
195  if(frameQueue->head == NULL){
196  frameQueue->head = frame;
197  OSMUTEX_Give(frameQueue->lock);
198  return true;
199  } else {
200  SCOMFrameQueueItem * currentPosition = frameQueue->head;
201  while (currentPosition->next != NULL) {
202  currentPosition = currentPosition->next;
203  }
204 
205  currentPosition->next = frame;
206  // release exclusive access to the queue
207  OSMUTEX_Give(frameQueue->lock);
208  return true;
209 
210  }
211  // release exclusive access to the queue
212  OSMUTEX_Give(frameQueue->lock);
213  }
214  }
215  return false;
216 
217 } /* SCOMFrameQueue_Append */
218 
219 
220 // --------------------------------------------------------------------------------------
221 // SCOMFrameQueue_GetFirstInQueue
222 // --------------------------------------------------------------------------------------
224 {
225  SCOMFrameQueueItem *result = NULL;
226  if (frameQueue) {
227  HAL_ASSERT_AND_EXECUTE((0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT))) {
228  result = frameQueue->head;
229  OSMUTEX_Give(frameQueue->lock);
230  }
231  }
232  return result;
233 } /* SCOMFrameQueue_GetFirstInQueue */
234 
235 
236 // --------------------------------------------------------------------------------------
237 // SCOMFrameQueue_PullOutFirstInQueue
238 // --------------------------------------------------------------------------------------
240 {
241  SCOMFrameQueueItem* result = NULL;
242 
243  if ((frameQueue) && (frameQueue->lock)) {
244  // acquire exclusive access to the queue
245  HAL_ASSERT_AND_EXECUTE((0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT))) {
246 
247  if (frameQueue->head) {
248  result = frameQueue->head;
249  frameQueue->head = frameQueue->head->next;
250  }
251 
252  // release exclusive access to the queue
253  OSMUTEX_Give(frameQueue->lock);
254  }
255  }
256 
257  return result;
258 
259 } /* SCOMFrameQueue_PullOutFirstInQueue */
260 
261 
262 // --------------------------------------------------------------------------------------
263 // SCOMFrameQueue_Lock
264 // --------------------------------------------------------------------------------------
266 {
267  size_t i;
268  SCOMFrameQueueItem *result = NULL;
269 
270  if ((frameQueue) && (frameQueue->lock)) {
271 
272  // acquire exclusive access to the queue
273  HAL_ASSERT_AND_EXECUTE((0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT))) {
274 
275  if (frameQueue->pool) {
276  // we have a pool to use
277  for(i = 0; i < frameQueue->size; i++) {
278  if(frameQueue->pool[i].state == SCOM_FRAME_EMPTY){
279  frameQueue->pool[i].state = SCOM_FRAME_ALLOCATED;
280  result = &frameQueue->pool[i];
281  result->frame.size = 0;
282  result->frame.ctrl = 0;
283  break;
284  }
285  }
286  } else {
287 #if !defined SCOM_DO_NOT_USE_HEAP
288  // no pool, we use heap memory
289  result = (SCOMFrameQueueItem*)HEAP_Alloc(sizeof(SCOMFrameQueueItem));
290  if (result) {
291  result->frame.sync = 0xFF;
292  result->frame.sof = SCOM_SOF_CHARACTER;
293  result->frame.size = 0;
294  result->frame.ctrl = 0;
295  result->state = SCOM_FRAME_ALLOCATED;
296  result->next = NULL;
297 
298  // in case of heap-based frame queue we make the queue grow dynamically
299  frameQueue->size++;
300  }
301 #endif // SCOM_DO_NOT_USE_HEAP
302  }
303  // release exclusive access to the queue
304  OSMUTEX_Give(frameQueue->lock);
305  }
306 
307  }
308 
309  return result;
310 
311 } /* SCOMFrameQueue_Lock */
312 
313 
314 // --------------------------------------------------------------------------------------
315 // SCOMFrameQueue_Unlock
316 // --------------------------------------------------------------------------------------
317 void SCOMFrameQueue_Unlock(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem* frameQueueItem)
318 {
319  // if needed - delete the item from the queue
320  SCOMFrameQueue_Delete(frameQueue, frameQueueItem);
321 
322  if (frameQueue) {
323  if (frameQueue->pool) {
324  // we have a pool to use
325  // mark the item as free to use
326  frameQueueItem->state = SCOM_FRAME_EMPTY;
327  } else {
328 #if !defined SCOM_DO_NOT_USE_HEAP
329  // no pool, heap memory was used
330  HEAP_Free(frameQueueItem);
331  // in case of heap-based frame queue we make the queue shring dynamically
332  if (frameQueue->size) {
333  frameQueue->size--;
334  }
335 #endif
336  }
337  }
338 
339 } /* SCOMFrameQueue_Unlock */
340 
341 
342 // --------------------------------------------------------------------------------------
343 // SCOMFrameQueue_GetItemByFrame
344 // --------------------------------------------------------------------------------------
346 {
347  size_t i;
348 
349  // Note: exclusive access to the queue is not needed here, as we do not modify anything and the
350  // data layout is constant
351 
352  if (frameQueue->pool) {
353  // we use pool
354  for (i = 0; i < frameQueue->size; i++) {
355  if (&(frameQueue->pool[i].frame) == frame) {
356  //match!
357  return &frameQueue->pool[i];
358  }
359  }
360  } else {
361  // we use heap
362  return (SCOMFrameQueueItem*)frame;
363  }
364 
365  return NULL;
366 
367 } /* SCOMFrameQueue_GetItemByDataPtr */
368 
369 // --------------------------------------------------------------------------------------
370 // SCOMFrameQueue_GetFreeSpace
371 // --------------------------------------------------------------------------------------
373 {
374  size_t i;
375  size_t emptyFrameCounter = 0;
376 
377  if ((frameQueue) && (frameQueue->lock)) {
378 
379  if (frameQueue->pool) {
380  // we use pool
381  // acquire exclusive access to the queue
382  if (0 == OSMUTEX_Take(frameQueue->lock, SCOM_FRAME_QUEUE_LOCK_TIMEOUT)) {
383 
384  for(i = 0; i < frameQueue->size; i++) {
385  if(frameQueue->pool[i].state == SCOM_FRAME_EMPTY){
386  emptyFrameCounter++;
387  }
388  }
389 
390  // release exclusive access to the queue
391  OSMUTEX_Give(frameQueue->lock);
392  }
393  } else {
394  // we use heap
395  return 1;
396  }
397  }
398 
399  return emptyFrameCounter;
400 
401 } /* SCOMFrameQueue_GetFreeSpace */
SCOMFrameQueueItem * head
First item in the queue.
uint8_t sync
synchronization field: always 0xFF
SCOMFrameQueueItem * SCOMFrameQueue_PullOutFirstInQueue(SCOMFrameQueue *frameQueue)
SCOM version record.
Definition: scom.h:81
size_t SCOMFrameQueue_GetFreeSpace(const SCOMFrameQueue *frameQueue)
Frame queue.
Definition of a single SCOM frame queue item.
SCOMFrameQueueItem * SCOMFrameQueue_GetItemByFrame(const SCOMFrameQueue *frameQueue, const SCOMFrame *frame)
Definition of SCOM CRC functions.
size_t size
Pool size (number of managed items)
#define SCOM_SOF_CHARACTER
Definition: scom_frame.h:38
#define SCOM_FRAME_QUEUE_LOCK_TIMEOUT
Maximum time allowed to be spend waiting for access to the SCOM frame queue.
uint8_t size
frame type field
Definition: scom_frame.h:59
SCOMFrameQueueItem * next
Next item in the queue.
bool SCOMFrameQueue_Delete(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frame)
struct SCOMFrameQueueItem SCOMFrameQueueItem
Type representing a SCOM frame queue item.
uint8_t ctrl
frame control field
SCOMFrameState state
SCOM frame state.
bool SCOMFrameQueue_Init(SCOMFrameQueue *frameQueue)
SCOMFrameQueueItem * SCOMFrameQueue_Lock(SCOMFrameQueue *frameQueue)
uint8_t SCOMFrame_GetPriority(const SCOMFrame *const frame)
Definition: scom_frame.c:82
bool SCOMFrameQueue_Append(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frame)
OSMutex lock
Pool access mutex.
uint8_t sof
synchronization field: always 0xFF
Definition: scom_frame.h:56
SCOMFrameQueueItem *const pool
Frame pool items.
void SCOMFrameQueue_Unlock(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frameQueueItem)
SCOMFrameQueueItem * SCOMFrameQueue_GetFirstInQueue(SCOMFrameQueue *frameQueue)
Definition of a SCOM frame queue.
SCOMFrame frame
SCOM frame.
bool SCOMFrameQueue_Insert(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frame)
void SCOMFrameQueue_Deinit(SCOMFrameQueue *frameQueue)