The Event Queue is a simple ring buffer, whose element is a byte array of fixed size. You can use it any purpose as long as it fits. When it is used as an event queue, the meaning of each byte is supposed to be defined by the user. In this example, we define the first byte as the event id followed by event data as below:
Source file
Source file
Source file
In the current design, generation of event (Evt_EnQueue()) were to be done only in the timer routine, which is based on the SysTick interrupt. While consumption of the event (Evt_DeQueue()) is done in the main loop. This simplifies the job of preventing the race condition by calling HAL-SuspendTick() / HAL_ResumeTick() inside of the Evt_DeQueue(). More sophisticated synchronization method is required in different situations.
Source file
<<source code>>
73 /** Pushbutton input event 74 * 75 * Event Data: (PBTN_ID)(EVT_TYPE) 76 * 77 * * PBTN_ID: id of the pushbutton that generated the event 78 * * EVT_TYPE: type of the event such as single click, double click, 79 */ 80 #define EVT_PBTN_INPUT 0x10 ///< event code for pushbutton input 81 #define PBTN_SCLK 0x01 ///< single click 82 #define PBTN_LCLK 0x02 ///< long click 83 #define PBTN_DCLK 0x03 ///< double click 84 #define PBTN_TCLK 0x04 ///< triple clickPosting an event is done by calling Evt_EnQueue() with the event id and corresponding data is packed into an byte array of size EVT_QWIDTH. So for example, the PushButton task post an long click event when it detects a click that lasts certain amount of time:
156 // button pressed and long timeout passed 157 else if((pp.duration[i] > PUSHBTN_TO_LONG) && 158 (((pp.new_state >> i) & 0x01) == 0x01)) 159 { 160 // long click event 161 event[0] = EVT_PBTN_INPUT; 162 event[1] = (uint8_t)(i+1); 163 event[2] = PBTN_LCLK; 164 165 // post the event 166 Evt_EnQueue(event); 167 168 // clear log 169 PushButton_ClearLog(i); 170 171 // raise flag: this will prevent false detect after long click 172 flag = true; 173 }The event is generated by the PushButton_Routine() automatically. Thus you need to handle the event in your main loop() by calling Evt_DeQueue():
113 while (1) 114 { 115 /* USER CODE END WHILE */ 116 117 /* USER CODE BEGIN 3 */ 118 119 // check event queue 120 if(Evt_DeQueue(event)) 121 { 122 switch(event[0]) 123 { 124 // pushbutton event 125 case EVT_PBTN_INPUT: 126 127 if(event[2] == PBTN_SCLK) 128 { 129 UartPrintf("Button %d: single click.\r\n", event[1]); 130 } 131 else if(event[2] == PBTN_LCLK) 132 { 133 UartPrintf("Button %d: long click.\r\n", event[1]); 134 } 135 else if(event[2] == PBTN_DCLK) 136 { 137 UartPrintf("Button %d: double click.\r\n", event[1]); 138 } 139 else if(event[2] == PBTN_TCLK) 140 { 141 UartPrintf("Button %d: triple click.\r\n", event[1]); 142 } 143 break;
Consideration about the Race Condition
If you share data between main loop and an interrupt handler, you have the risk of race condition being occur regardless of the data type. If you can't secure the exclusive access to the data via synchronization mechanism such as semaphore, then you have to at least consider disabling the interrupt during main loop access.In the current design, generation of event (Evt_EnQueue()) were to be done only in the timer routine, which is based on the SysTick interrupt. While consumption of the event (Evt_DeQueue()) is done in the main loop. This simplifies the job of preventing the race condition by calling HAL-SuspendTick() / HAL_ResumeTick() inside of the Evt_DeQueue(). More sophisticated synchronization method is required in different situations.
61 bool Evt_DeQueue(uint8_t *event) 62 { 63 uint8_t i; 64 bool flag = false; 65 66 // suspend systick 67 HAL_SuspendTick(); 68 69 // queue is not empty 70 if(evt_queue.tail != evt_queue.head) 71 { 72 // copy event bytes into the buffer 73 for(i = 0; i < EVT_QWIDTH; i++) 74 { 75 event[i] = evt_queue.buff[evt_queue.tail][i]; 76 } 77 // move to the next position 78 evt_queue.tail = ADVANCE_QPTR(evt_queue.tail); 79 // set flag 80 flag = true; 81 } 82 83 // resume tick 84 HAL_ResumeTick(); 85 86 // return with the flag 87 return flag; 88 }
<<source code>>
Comments
Post a Comment