GeMRTOS
mq.c
Go to the documentation of this file.
1 
21 /******************************************************************************
22 * *
23 * License Agreement *
24 * Copyright (c) Ricardo L. Cayssials *
25 * All rights reserved. *
26 * *
27 ******************************************************************************/
28 
29 
30 // #include <stdio.h>
31 #include <gemrtos_core.h>
32 #include <string.h>
33 
35 
36 
43 INT32 gu_MQ_receive(GS_ECB *pevent) {
44 
45  GS_RRDS *prrds_buffer = (GS_RRDS *) 0;
46  GS_ECB *peventime = (GS_ECB *) 0;
47  G_RCB *prcb;
48 
49  GRTOS_USER_CRITICAL_SECTION_GET;
50  prcb = (G_RCB *) pevent->ECB_AssocRCB;
51  prrds_buffer = pevent->ECB_RRDS;
52 
53  if (prrds_buffer->queue_buffer.BUFFER_status == BUFFER_status_READ) {
54  if (prcb->queue.MQ_msg_seq == prrds_buffer->queue_buffer.BUFFER_msg_seq) { // message is in buffer
55  gk_check_consume(pevent);
56  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
57  return G_TRUE;
58  }
59 
60  peventime = gk_ECB_GetFree();
61  if (peventime == (GS_ECB *) 0) {
62  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
63  return G_FALSE;
64  }
65  peventime->ECBValue.i64 = (INT64) prrds_buffer->queue_buffer.BUFFER_priority.i64;
66  peventime->ECBType = G_ECBType_MESSAGE_CONSUME_WAIT;
67  gk_ECBTL_Link (peventime);
68 
69  gk_KERNEL_TASK_SUSPEND_CURRENT(); //Switch tasks and wait to send or timeout
70  // #################################################
71  GRTOS_USER_CRITICAL_SECTION_GET; // return from timeout of with access to resource
72 
73  if (peventime->ECBType == G_ECBType_MESSAGE_CONSUME_EXPIRED) {
74  gk_ECBFL_Link(peventime);
75  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
76  return G_FALSE;
77  }
78  gk_ECBFL_Link(peventime);
79 
80  } else {
81  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
82  return G_FALSE;
83  }
84 
85  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
86  return G_TRUE;
87 }
88 
99 INT32 gk_MQ_send(G_RCB *prcb, void *pmsg, INT32 msg_length, gt_time timeout) {
100 
101  // GS_RRDS *prrds_buffer = (GS_RRDS *) 0;
102  GS_ECB *pevent = (GS_ECB *) 0;
103  GS_ECB *peventime = (GS_ECB *) 0;
104  INT32 granted = G_FALSE;
105  // INT32 retorno = G_FALSE;
106 
107 
108  GRTOS_USER_CRITICAL_SECTION_GET;
109 
110 
111  if (msg_length > prcb->queue.MQ_Buffer_Length) {
112  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
113  return G_FALSE; // Message too large
114  }
115 
116  if (prcb->RCB_NextRCBWEL != (struct gs_ecb *) 0) { // It has to wait to send the message
117  pevent = gk_ECB_GetFree();
118  if (pevent == (GS_ECB *) 0) {
119  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
120  return G_FALSE;
121  }
122  peventime = gk_ECB_GetFree();
123  if (peventime == (GS_ECB *) 0) {
124  gk_ECBFL_Link(pevent);
125  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
126  return G_FALSE;
127  }
128  pevent->ECBValue.i64 = (INT64) prcb->queue.MQ_priority_send;
129  prcb->queue.MQ_priority_send++;
130  gk_RCBWEL_Link(prcb, pevent);
131 
132  peventime->ECBValue.i64 = (INT64) timeout;
133  peventime->ECBType = G_ECBType_MESSAGE_SEND_WAIT;
134  gk_ECBTL_Link (peventime);
135 
136  gk_KERNEL_TASK_SUSPEND_CURRENT(); //Switch tasks and wait to send or timeout
137  // #################################################
138  GRTOS_USER_CRITICAL_SECTION_GET; // return from timeout of with access to resource
139  gk_ECBFL_Link(peventime);
140  if (prcb->RCB_NextRCBWEL == pevent) {
141  granted = G_TRUE;
142  }
143 
144  gk_RCBWEL_Unlink(pevent);
145  gk_ECBFL_Link(pevent);
146 
147  if (granted == G_FALSE) {
148  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
149  return G_FALSE;
150  }
151  }
152 
153 
154  if (prcb->RCB_NextRCBWEL == (struct gs_ecb *) 0
155  || granted == G_TRUE) { // It is ready to send the message
156 
157  prcb->queue.MQ_Count_deliver = (INT32) 0;
158  prcb->queue.MQ_msg_Length = msg_length;
159  prcb->queue.MQ_msg_seq++;
160  memcpy(prcb->queue.MQ_PBuffer, pmsg, msg_length);
161 
162  prcb->queue.MQ_CUR_TCB = (struct gs_tcb *) gk_PCB_GetCurrentTCB();
163 
164  pevent = prcb->RCB_NextRCBGEL;
165  while (pevent != (GS_ECB *) 0) {
166  gk_check_consume((GS_ECB *) pevent);
167  pevent = pevent->ECB_NextECB;
168  }
169 
170  }
171 
172  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
173  return G_TRUE;
174 }
175 
185 G_RCB *gu_queue_create(void *pbuffer, INT32 buffer_length)
186 {
187  G_RCB *prcb;
188  GRTOS_USER_CRITICAL_SECTION_GET;
189  prcb = gk_RCB_GetFree();
190  if (prcb != (G_RCB *) 0) {
191  prcb->RCBState = GK_RCBState_QUEUE;
192  prcb->RCBType = (INT32) GK_RCBType_QUEUE;
193  prcb->RCBPriority.i64 = (INT64) G_LOWEST_PRIORITY - (INT64) 100;
194  prcb->RCBGrantedPriority.i64 = (INT64) G_LOWEST_PRIORITY - (INT64) 100;
195  prcb->RCBWaitingTimeout.i64 = (INT64) G_LATEST_TIME - (INT64) 100;
196  prcb->RCBGrantedTimeout.i64 = (INT64) G_LATEST_TIME - (INT64) 100;
197  prcb->RCB_NextRCBWEL = (struct gs_ecb *) 0;
198  prcb->RCB_NextRCBGEL = (struct gs_ecb *) 0;
199  prcb->RCB_NextRCB = (struct g_rcb *) 0;
200  prcb->RCB_NextRCBASL = (struct gs_scb *) 0;
201 
202  prcb->queue.MQ_PBuffer = (void *) pbuffer;
203  prcb->queue.MQ_Buffer_Length = buffer_length;
204  prcb->queue.MQ_Count_deliver = (INT32) 0;
205  prcb->queue.MQ_consumer_count = (INT32) 0;
206  prcb->queue.MQ_priority_send = (INT32) 0;
207  prcb->queue.MQ_priority_consume = (INT32) 0;
208  prcb->queue.MQ_msg_Length = (INT32) 0;
209  prcb->queue.MQ_msg_seq = (INT32) 0;
210  prcb->queue.MQ_CUR_TCB = (struct gs_tcb *) 0;
211 
212  }
213  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
214  return((G_RCB *) prcb);
215 }
216 
229 GS_ECB *gu_queue_consume(G_RCB *presource, void *pbuffer, INT32 buffer_length, gt_time timeout)
230 {
231  GS_RRDS *prrds_buffer = (GS_RRDS *) 0;
232  GS_ECB *pevent = (GS_ECB *) 0;
233  GS_TCB *ptcb = gk_PCB_GetCurrentTCB();
234 
235  GRTOS_USER_CRITICAL_SECTION_GET;
236 
237  // Check whether the task is already consuming from the presource
238  pevent = gk_TCB_in_RCBGEL((G_RCB *) presource, (GS_TCB *) ptcb);
239 
240  // pevent = presource->RCB_NextRCBGEL;
241  // while (pevent != (GS_ECB *) 0 && ptcb != pevent->ECB_AssocTCB) {
242  // pevent = pevent->ECB_NextECB;
243  // }
244 
245  if (pevent == (GS_ECB *) 0) { // task is not a consumer of the message queue
246  pevent = gk_ECB_GetFree();
247  if (pevent == (struct gs_ecb *) 0) return(pevent); // there is not more ECB available
248  prrds_buffer = gk_RRDS_GetFree();
249  if (prrds_buffer == (GS_RRDS *) 0) {
250  gk_ECBFL_Link(pevent);
251  return (GS_ECB *) 0;
252  }
253  pevent->ECB_RRDS = prrds_buffer;
254  pevent = gk_RCBGEL_Link(presource, pevent);
255 
256  gk_TCBAEL_Link(pevent,ptcb);
257  }
258  else { // task is already a consumer
259  prrds_buffer = pevent->ECB_RRDS;
260  }
261 
262  pevent->ECBType = G_ECBType_QUEUE_CONSUME;
263  prrds_buffer->RRDS_AsocECB = pevent;
264 
265  prrds_buffer->queue_buffer.BUFFER_status = BUFFER_status_READ;
266  prrds_buffer->queue_buffer.BUFFER_pbuffer = pbuffer;
267  prrds_buffer->queue_buffer.BUFFER_buffer_length = buffer_length;
268  prrds_buffer->queue_buffer.BUFFER_priority.i64 = (INT64) G_LOWEST_PRIORITY - (INT64) 100;
269  prrds_buffer->queue_buffer.BUFFER_timeout.i64 = (INT64) timeout;
270  prrds_buffer->queue_buffer.BUFFER_current_byte_index = (INT32) 0;
271  prrds_buffer->queue_buffer.BUFFER_msg_seq = presource->queue.MQ_msg_seq;
272 
273  // !!!!!! colocar que lea data si hay en la cola
274  gk_check_consume(pevent);
275  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
276  return pevent;
277 }
278 
286 
287  GS_RRDS *prrds_buffer = (GS_RRDS *) pevent->ECB_RRDS;
288  GS_TCB *ptcb = pevent->ECB_AssocTCB;
289  G_RCB *prcb = (G_RCB *) pevent->ECB_AssocRCB;
290  INT32 bytes_buffer;
291  INT32 bytes_msg_left;
292  INT32 bytes_to_transfer;
293  void *source_address;
294  void *destination_address;
295 
296  if (prrds_buffer->queue_buffer.BUFFER_status == BUFFER_status_NOT_READ) {
297  return G_FALSE;
298  }
299  if (prrds_buffer->queue_buffer.BUFFER_msg_seq != prcb->queue.MQ_msg_seq) {
300  return G_FALSE; // consumer is ready for next message
301  }
302  // Here the consumer is ready to read the current message
303  bytes_buffer = prrds_buffer->queue_buffer.BUFFER_buffer_length;
304  bytes_msg_left = prcb->queue.MQ_msg_Length - prrds_buffer->queue_buffer.BUFFER_current_byte_index;
305 
306  if (bytes_buffer > bytes_msg_left) bytes_to_transfer = bytes_msg_left;
307  else bytes_to_transfer = bytes_buffer;
308 
309  source_address = (void *) (prcb->queue.MQ_PBuffer + prrds_buffer->queue_buffer.BUFFER_current_byte_index);
310  destination_address = (void *) (prrds_buffer->queue_buffer.BUFFER_pbuffer);
311 
312  memcpy(destination_address, source_address, bytes_to_transfer);
313 
314  prrds_buffer->queue_buffer.BUFFER_current_byte_index += bytes_to_transfer;
315  prrds_buffer->queue_buffer.BUFFER_status = BUFFER_status_NOT_READ;
316 
317  if (ptcb->TCBState == G_TCBState_WAITING) { // it is waiting but not completed
318  gk_TCB_Unlink(ptcb);
319  gk_TCBRDYL_Link(ptcb);
320  }
321 
322  return G_TRUE;
323 }
324 
332  GS_RRDS *prrds_buffer;
333  G_RCB *prcb;
334  GS_TCB *ptcb;
335 
336  GRTOS_USER_CRITICAL_SECTION_GET;
337 
338  prrds_buffer = (GS_RRDS *) pevent->ECB_RRDS;
339  prcb = (G_RCB *) pevent->ECB_AssocRCB;
340 
341  prrds_buffer->queue_buffer.BUFFER_status = BUFFER_status_READ;
342  if (prrds_buffer->queue_buffer.BUFFER_current_byte_index != prcb->queue.MQ_msg_Length) { //all the message was not read
343  gk_check_consume(pevent); // get new data
344  return G_TRUE;
345  }
346 
347  prcb->queue.MQ_consumer_count++;
348  prrds_buffer->queue_buffer.BUFFER_current_byte_index = 0;
349  prrds_buffer->queue_buffer.BUFFER_msg_seq++;
350 
351  // Check if it was the last deliver to a consumer
352  if (prcb->queue.MQ_consumer_count == prcb->queue.MQ_Count_deliver) {
353  // Check if there is a new sender
354  if (prcb->RCB_NextRCBWEL != (struct gs_ecb *) 0) {
355  ptcb = prcb->RCB_NextRCBWEL->ECB_AssocTCB;
356  gk_TCB_Unlink(ptcb);
357  gk_TCBRDYL_Link(ptcb);
358  }
359  }
360 
361  GRTOS_CMD_CRITICAL_SECTION_RELEASE;
362  return G_TRUE;
363 }
364 
372  GS_TCB *ptcb;
373  peventime->ECBType = G_ECBType_MESSAGE_SEND_EXPIRED;
374  ptcb = peventime->ECB_AssocTCB;
375  gk_TCB_Unlink(ptcb);
376  gk_TCBRDYL_Link(ptcb);
377  return G_TRUE;
378 }
379 
387  GS_TCB *ptcb;
388  peventime->ECBType = G_ECBType_MESSAGE_CONSUME_EXPIRED;
389  ptcb = peventime->ECB_AssocTCB;
390  gk_TCB_Unlink(ptcb);
391  gk_TCBRDYL_Link(ptcb);
392  return G_TRUE;
393 }
394 
395 
397  // G_RCB *prcb = (G_RCB *) pevent->ECB_AssocRCB;
398  gk_ECB_List_Unlink((GS_ECB *) pevent);
399  gk_ECBFL_Link((GS_ECB *)pevent);
400  return G_TRUE;
401 
402 }
403 
404 OPTIMEZE_RESTORE
Resource::gk_timeout_ECB_MQ_send
INT32 gk_timeout_ECB_MQ_send(GS_ECB *peventime)
This function is called from the timed IRQ when a send timeout G_ECBType_MESSAGE_SEND_WAIT happens.
Definition: mq.c:371
INT32
unsigned INT32
Definition: gemrtos_core.h:62
Resource::gk_timeout_ECB_MQ_consume
INT32 gk_timeout_ECB_MQ_consume(GS_ECB *peventime)
This function is called from the timed IRQ when a consume timeout G_ECBType_MESSAGE_CONSUME_WAIT happ...
Definition: mq.c:386
RRDS::gk_RRDS_GetFree
GS_RRDS* gk_RRDS_GetFree(void)
Gets the pointer of a free RRDS from the free list.
Definition: gemrtos_core.c:230
Resource::gk_MQ_send
INT32 gk_MQ_send(G_RCB *prcb, void *pmsg, INT32 msg_length, gt_time timeout)
Sends a message to all the consumers. The function returns when the message was delivered to all the ...
Definition: mq.c:99
GS_TCB
struct gs_tcb GS_TCB
Definition: gemrtos_core.h:50
Task::gk_TCB_Unlink
INT32 gk_TCB_Unlink(GS_TCB *ptcb)
Unlinks the TCB according to the list it is linked.
Definition: listfunctions.c:2550
Task::gk_TCBAEL_Link
INT32 gk_TCBAEL_Link(GS_ECB *pevent, GS_TCB *ptcb)
Links an ECB to the associated ECB list of TCB.
Definition: listfunctions.c:1284
gk_QUEUE_granted_kill
INT32 gk_QUEUE_granted_kill(GS_ECB *pevent)
Definition: mq.c:396
gt_time
unsigned long long gt_time
Definition: gemrtos_core.h:65
Resource::gk_RCB_GetFree
G_RCB* gk_RCB_GetFree(void)
Unlinks an RCB from the RCBFL list and returns its pointer or NULL if no free RCB is available.
Definition: gemrtos_core.c:155
gk_KERNEL_TASK_SUSPEND_CURRENT
void gk_KERNEL_TASK_SUSPEND_CURRENT(void)
Suspends the execution of the current task and switch to Highest Priority Task.
Definition: grtos_kernel.c:502
Task::gk_TCB_in_RCBGEL
GS_ECB* gk_TCB_in_RCBGEL(G_RCB *presource, GS_TCB *ptcb)
Returns the event of the TCB that grants the resource.
Definition: listfunctions.c:2081
Event::gk_RCBWEL_Unlink
void gk_RCBWEL_Unlink(GS_ECB *pevent)
Unlinks ECB from RCB waiting list.
Definition: listfunctions.c:1135
gs_ecb
GS_ECB Event Control Block structure.
Definition: gemrtos_core.h:107
gu_MQ_consumer_mark_read
INT32 gu_MQ_consumer_mark_read(GS_ECB * pevent)
Mark the current buffer as read.
Definition: mq.c:331
gs_tcb
gs_tcb Task Control Block (TCB) structure
Definition: gemrtos_core.h:439
gs_scb
GS_SCB Signal Control Block structure.
Definition: gemrtos_core.h:393
GS_RRDS
struct gs_rrds GS_RRDS
Definition: gemrtos_core.h:53
Resource::gu_queue_consume
GS_ECB* gu_queue_consume(G_RCB *presource, void *pbuffer, INT32 buffer_length, gt_time timeout)
Creates an ECB to consume from a Message Queue.
Definition: mq.c:229
Resource::gk_RCBWEL_Link
GS_ECB* gk_RCBWEL_Link(G_RCB *presource, GS_ECB *pevent)
Links an event ECB to the resource waiting list of RCB. If no ECB is given then a new ECB is obtained...
Definition: listfunctions.c:1054
Event::gk_ECB_List_Unlink
INT32 gk_ECB_List_Unlink(GS_ECB *pevent)
Unlinks all the structures linked to a ECB.
Definition: listfunctions.c:248
Event::gk_ECBTL_Link
INT32 gk_ECBTL_Link(GS_ECB *pevent)
Links the ECB from the Time Event List.
Definition: listfunctions.c:355
INT64
unsigned long long INT64
Definition: gemrtos_core.h:61
Resource::OPTIMEZE_CODE
OPTIMEZE_CODE(3)
Receive the next message from the Message Queue.
Definition: mq.c:34
Task::gk_PCB_GetCurrentTCB
GS_TCB* gk_PCB_GetCurrentTCB(void)
Returns the task that the current processor was executing.
Definition: listfunctions.c:2262
GS_ECB
struct gs_ecb GS_ECB
Definition: gemrtos_core.h:51
Task::gk_TCBRDYL_Link
INT32 gk_TCBRDYL_Link(GS_TCB *ptcb)
Links the TCB in the Ready Task List sorted by its priority.
Definition: listfunctions.c:1653
Resource::gk_check_consume
INT32 gk_check_consume(GS_ECB * pevent)
Transfer message from the resource to the consumer.
Definition: mq.c:285
gemrtos_core.h
GEmRTOS CORE definitions.
Event::gk_ECBFL_Link
INT32 gk_ECBFL_Link(GS_ECB *pevent)
Link ECB to Free List. Removes the signals from ECB.
Definition: listfunctions.c:324
Resource::gk_RCBGEL_Link
GS_ECB* gk_RCBGEL_Link(G_RCB *presource, GS_ECB *pevent)
Links ECB to RCB granted list and return pointer to the ECB linked.
Definition: listfunctions.c:935
Event::gk_ECB_GetFree
GS_ECB* gk_ECB_GetFree(void)
Returns a pointer to a Free ECB, NULL if there is not ECB available.
Definition: gemrtos_core.c:107
G_RCB
struct g_rgb G_RCB
Definition: gemrtos_core.h:54
gu_queue_create
G_RCB* gu_queue_create(void *pbuffer, INT32 buffer_length)
Create a Resource for Queue with default settings.
Definition: mq.c:185
gu_MQ_receive
INT32 gu_MQ_receive(GS_ECB *pevent)