FreeRTOS Task Notification
和其它IPC方法的區別
通過中間對象
task通知——直接task通信
Task Notifications 的優缺點
優點
缺點
使用Task Notifications
xTaskNotifyGive()
vTaskNotifyGiveFromISR()
ulTaskNotifyTake()
examples
方法1
方法2
xTaskNotify() 和 xTaskNotifyFromISR()
xTaskNotify 與 xTaskNotifyGive 的區別
API原型
API參數與返回值
xTaskNotifyWait()
任務通知在設備驅動中的應用——Uart
任務通知在設備驅動中的應用——ADC
任務通知在設備驅動中的應用——Task
向server task 發送隊列的數據類型和數據結構
cloud read
server task
cloud write
server task
configUSE_TASK_NOTIFICATIONS, need set to 1 in FreeRTOSConfig.h to use task notification.
當設置為1時,每個task一個Notification State
,->Pending
orNot-Pending
每個task有一個Notification Value
, 類型為uint32_t.
和其它IPC方法的區別
通過中間對象
task通知——直接task通信
Task Notifications 的優缺點
優點
- 消息傳遞的更快,效率更高
- 內存消耗比其它IPC通信相比,明顯少很多
缺點
- 只能從ISR 發送event或者data 到task, 而不能從task發送至ISR.
- 發出的消息只能被一個task接收,但這個限制很少,因為很少有多個task從同一個通信對象獲取消息。
- 不能緩沖消息,只能保存一個值。而queue可以
- 不能向多個task廣播消息,而event group可以
- task Notification 不會因為taks的狀態為
Pengding
而去等待發送完成后,再發送。而是會直接覆蓋掉。
使用Task Notifications
xTaskNotifyGive()
/**
* @return 返回結果只有pdPASS
*/
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
vTaskNotifyGiveFromISR()
/**
*
*/
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify,
BaseType_t *pxHigherPriorityTaskWoken );
ulTaskNotifyTake()
/**
* @input xClearCountOnExit is pdTRUE, the task's notification value will be zero
* is pdFALSE, the task's notification value will be de decremented.
*/
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
examples
使用task notification 代替semaphore
方法1
xClearCountOnExit
= pdTRUE
/* The rate at which the periodic task generates software interrupts. */
const TickType_t xInterruptFrequency = pdMS_TO_TICKS( 500UL );
static void vHandlerTask( void *pvParameters )
{
/* xMaxExpectedBlockTime is set to be a little longer than the maximum expected time
between events. */
const TickType_t xMaxExpectedBlockTime = xInterruptFrequency + pdMS_TO_TICKS( 10 );
uint32_t ulEventsToProcess;
/* As per most tasks, this task is implemented within an infinite loop. */
for( ;; )
{
/* Wait to receive a notification sent directly to this task from the
interrupt service routine. */
ulEventsToProcess = ulTaskNotifyTake( pdTRUE, xMaxExpectedBlockTime );
if( ulEventsToProcess != 0 )
{
/* To get here at least one event must have occurred. Loop here until
all the pending events have been processed (in this case, just print out
a message for each event). */
while( ulEventsToProcess > 0 )
{
vPrintString( "Handler task - Processing event.\r\n" );
ulEventsToProcess--;
}
}
else
{
/* If this part of the function is reached then an interrupt did not
arrive within the expected time, and (in a real application) it may be
necessary to perform some error recovery operations. */
}
}
}
static uint32_t ulExampleInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken;
/* The xHigherPriorityTaskWoken parameter must be initialized to pdFALSE as
it will get set to pdTRUE inside the interrupt safe API function if a
context switch is required. */
xHigherPriorityTaskWoken = pdFALSE;
/* Send a notification directly to the task to which interrupt processing is
being deferred. */
vTaskNotifyGiveFromISR( /* The handle of the task to which the notification
is being sent. The handle was saved when the task
was created. */
xHandlerTask,
/* xHigherPriorityTaskWoken is used in the usual
way. */
&xHigherPriorityTaskWoken );
/* Pass the xHigherPriorityTaskWoken value into portYIELD_FROM_ISR(). If
xHigherPriorityTaskWoken was set to pdTRUE inside vTaskNotifyGiveFromISR()
then calling portYIELD_FROM_ISR() will request a context switch. If
xHigherPriorityTaskWoken is still pdFALSE then calling
portYIELD_FROM_ISR() will have no effect. The implementation of
portYIELD_FROM_ISR() used by the Windows port includes a return statement,
which is why this function does not explicitly return a value. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
方法2
xClearCountOnExit
= pdFALSE
static void vHandlerTask( void *pvParameters )
{
/* xMaxExpectedBlockTime is set to be a little longer than the maximum expected time
between events. */
const TickType_t xMaxExpectedBlockTime = xInterruptFrequency + pdMS_TO_TICKS( 10 );
/* As per most tasks, this task is implemented within an infinite loop. */
for( ;; )
{
/* Wait to receive a notification sent directly to this task from the
interrupt service routine. The xClearCountOnExit parameter is now pdFALSE,
so the task's notification value will be decremented by ulTaskNotifyTake(),
and not cleared to zero. */
if( ulTaskNotifyTake( pdFALSE, xMaxExpectedBlockTime ) != 0 )
{
/* To get here an event must have occurred. Process the event (in this
case just print out a message). */
vPrintString( "Handler task - Processing event.\r\n" );
}
else
{
/* If this part of the function is reached then an interrupt did not
arrive within the expected time, and (in a real application) it may be
necessary to perform some error recovery operations. */
}
}
}
static uint32_t ulExampleInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
/* Send a notification to the handler task multiple times. The first ‘give’ will
unblock the task, the following 'gives' are to demonstrate that the receiving
task's notification value is being used to count (latch) events - allowing the
task to process each event in turn. */
vTaskNotifyGiveFromISR( xHandlerTask, &xHigherPriorityTaskWoken );
vTaskNotifyGiveFromISR( xHandlerTask, &xHigherPriorityTaskWoken );
vTaskNotifyGiveFromISR( xHandlerTask, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
xTaskNotify() 和 xTaskNotifyFromISR()
xTaskNotify 與 xTaskNotifyGive 的區別
xTaskNotify
是比xTaskNotifyGive
更加強大的API, 可以通過下面任意一種方式,更新接收task的notification value.
- 將接收task的notification value 加1; 這里
xTaskNotify
與xTaskNotifyGive
使用效果一樣。 - 設置一位或多位 接收task的notification value. 這樣就以將notification value 視為一種輕量又高效的evnet group
- 向notification value寫入一個全新的數值,僅當接收task已經讀取的先前的值。這樣可以賦予notification value 與 長度為1的queue相似的功能。
- 向notification value寫入一個全新的數值,而不管接收task是否已經讀過了。 這樣可以賦予notification value 與
xQueueOverwrite
API 相似的mailbox 功能
API,
xTaskNotify
更加的靈活和強大,但也使用上更加復雜
調用xTaskNotify
,總是將接收task的notification state,置為pending.
API原型
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction );
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t *pxHigherPriorityTaskWoken );
API參數與返回值
eNotifyAction Value | Resultant Effect on Receiving Task |
---|---|
eNoAction | 接收task的 notification state 會被設置為pending ,但是notification value 不會被更新,並且.xTaskNotify() ulValue,沒有用到。xTaskNotify() ulValue parameter is not used. eNoAction 可以將task notification 用作 binary semaphore ,輕量又高效 |
eSetBits | 接收任務的 notification value 與 xTaskNotify() ulValue做位與,OR操作.例如ulValue為0x01時,接收任務的 notification value bit0 位將會被置1;如果ulValue 為0x06 (binary 0110),那么接收任務的 notification value bit 1 和 bit 2 將會被置1.The eSetBits 將允許接收任務的notification value 用作 輕量又高效的 'event group'. |
eIncrement | 接收任務的 notification value 加1. xTaskNotify() 參數 ulValue 沒用到. eIncrement 可以將 notification value 用作相比於一個 binary 或者counting semaphore 理加輕量而又高效的選擇此時xTaskNotify()和xTaskNotifyGive() API 一致 |
eSetValueWithoutOverwrite | 如果在xTaskNotify() 調用前,接收任務為pending 狀態時,xTaskNotify() 將會返回pdFAIL 。若接收任務不是 pending 狀態,則接收任務的notification value 將會設置為xTaskNotify() ulValue |
eSetValueWithOverwrite | 接收任務的notification value 將會設置為xTaskNotify() ulValue, 而不管調用之前的狀態。 |
xTaskNotifyWait()
xTaskNotifyWait()
相比於ulTaskNotifyTake()
更加強大, 它讓task可以等待變為pending
狀態,並提供超時機制,xTaskNotifyWait()
提供了置0notification value
bit位的選項,進入xTaskNotifyWait()
和退出xTaskNotifyWait()
時。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
- ulBitsToClearOnEntry
- 若調用
xTaskNotifyWait()
前,task沒有notification pending
,則ulBitsToClearOnEntry中所有置1的位,會清0notification value
所對應的位。 ulBitsToClearOnEntry
為0x01時,task的notification value
的第0位置清0;ulBitsToClearOnExit
為0xffffffff(ULONG_MAX)時, tasknotification value
所有位將清零
- 若調用
- ulBitsToClearOnExit
- 若xTaskNotifyWait()因為有
notification pending
而退出時,pulNotificationValue將先保存notification value
內容之后,ulBitsToClearOnExit中置的位,將清空tasknotification value
中對應的位
- 若xTaskNotifyWait()因為有
- pulNotificationValue
- pulNotificationValue 保存
notification value
被ulBitsToClearOnExit清零任何一位之前的值。 - pulNotificationValue 是可選的,不需要時置為NULL。
- pulNotificationValue 保存
- xTicksToWait
pdMS_TO_TICKS()
,portMAX_DELAY
,porPeriod_tick_ms
return value
pdTRUE
, has no notification within the xTicksToWait.
pdFALSE
, time out when waiting for notification.
任務通知在設備驅動中的應用——Uart
- 偽代碼舉例,二進制信號量,應用於驅動庫中的傳輸函數
/* Driver library function to send data to a UART. */
BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength )
{
BaseType_t xReturn;
/* Ensure the UART's transmit semaphore is not already available by attempting to take
the semaphore without a timeout. */
xSemaphoreTake( pxUARTInstance->xTxSemaphore, 0 );
/* Start the transmission. */
UART_low_level_send( pxUARTInstance, pucDataSource, uxLength );
/* Block on the semaphore to wait for the transmission to complete. If the semaphore
is obtained then xReturn will get set to pdPASS. If the semaphore take operation times
out then xReturn will get set to pdFAIL. Note that, if the interrupt occurs between
UART_low_level_send() being called, and xSemaphoreTake() being called, then the event
will be latched in the binary semaphore, and the call to xSemaphoreTake() will return
immediately. */
xReturn = xSemaphoreTake( pxUARTInstance->xTxSemaphore, pxUARTInstance->xTxTimeout );
return xReturn;
}
/*-----------------------------------------------------------*/
/* The service routine for the UART's transmit end interrupt, which executes after the
last byte has been sent to the UART. */
void xUART_TransmitEndISR( xUART *pxUARTInstance )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Clear the interrupt. */
UART_low_level_interrupt_clear( pxUARTInstance );
/* Give the Tx semaphore to signal the end of the transmission. If a task is Blocked
waiting for the semaphore then the task will be removed from the Blocked state. */
xSemaphoreGiveFromISR( pxUARTInstance->xTxSemaphore, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
上述例程可以非常正常的動作, 但是也有幾個缺點:
- 庫中使用了多個信號量
semaphores
, 增加了RAM的用量。 - 信號量
semaphores
必須提前創建並初使化后,庫才能使用它。 - 信號量
semaphores
應用場景非常廣泛,可以讓多個task進入Blocked狀態等待信號量發生,當信號量可用時,可以選擇特定的task離開Blocked狀態,而上述例程中最多不可能超過一個task等待信號量發生。
下面這個例程會使用task notification
代替,二進制信號量binary semaphore,避免了上述幾個缺陷
注意: 如果庫中使用了信號量, 庫的說明文檔中要明確說明,調用庫中的函數會改變task的notification state
和 notification value
。
- xUART 結構體中的成員變量被替換為
xTaskToNotify
,它的類型是TaskHandle_t,保存了等待UART操作完成的task的句柄handle
. xTaskGetCurrentTaskHandle()
, 是FreeRTOS的API函數用於獲取當前運行的task的句柄handle
.- 庫中沒有創建任何FreeRTOS對象,所有不會發生內存溢出,也不需要明確的初使化.
task notification
直接發送給等待UART操作完成的task,所以沒有多余的邏輯執行過程。
xUART結構體成員xTaskToNotify,同時被task和ISR使用,更新數據時需要注意以下幾點
- 如果
xTAskToNotify
可以在一個內存寫操作完成時,那么它就可以在非臨界區域更新數據,例如當FreeRTOS運行在32位處理器上,xTAskToNotify
為32-bit變量時 - 如果需要一個以上的內存寫操作才能完成更新
xTAskToNotify
,則xTAskToNotify
必須在臨界區域內更新。例如當FreeRTOS運行在16-bit處理器上時
FreeRTOS內部實現,TaskHandle_t是個指針,sizeof(TaskHandle_t) 恆等於 sizeof(void *).
/* Driver library function to send data to a UART. */
BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength )
{
BaseType_t xReturn;
/* Save the handle of the task that called this function. The book text contains notes as to
whether the following line needs to be protected by a critical section or not. */
pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle();
/* Ensure the calling task does not already have a notification pending by calling
ulTaskNotifyTake() with the xClearCountOnExit parameter set to pdTRUE, and a block time of 0
(don't block). */
ulTaskNotifyTake( pdTRUE, 0 );
/* Start the transmission. */
UART_low_level_send( pxUARTInstance, pucDataSource, uxLength );
/* Block until notified that the transmission is complete. If the notification is received
then xReturn will be set to 1 because the ISR will have incremented this task's notification
value to 1 (pdTRUE). If the operation times out then xReturn will be 0 (pdFALSE) because
this task's notification value will not have been changed since it was cleared to 0 above.
Note that, if the ISR executes between the calls to UART_low_level_send() and the call to
ulTaskNotifyTake(), then the event will be latched in the task’s notification value, and the
call to ulTaskNotifyTake() will return immediately.*/
xReturn = ( BaseType_t ) ulTaskNotifyTake( pdTRUE, pxUARTInstance->xTxTimeout );
return xReturn;
}
/*-----------------------------------------------------------*/
/* The ISR that executes after the last byte has been sent to the UART. */
void xUART_TransmitEndISR( xUART *pxUARTInstance )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* This function should not execute unless there is a task waiting to be notified. Test this
condition with an assert. This step is not strictly necessary, but will aid debugging.
configASSERT() is described in section 11.2.*/
configASSERT( pxUARTInstance->xTaskToNotify != NULL );
/* Clear the interrupt. */
UART_low_level_interrupt_clear( pxUARTInstance );
/* Send a notification directly to the task that called xUART_Send(). If the task is Blocked
waiting for the notification then the task will be removed from the Blocked state. */
vTaskNotifyGiveFromISR( pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken );
/* Now there are no tasks waiting to be notified. Set the xTaskToNotify member of the xUART
structure back to NULL. This step is not strictly necessary but will aid debugging. */
pxUARTInstance->xTaskToNotify = NULL;
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
task notification
也可以用於接收函數
- xUART_Receive()函數不包含任何互斥邏輯, 如果多個task使用xUART_Receive()函數, 需要增加互斥鎖
- UART的中斷服務函數將接收的內容保存在ram buffer中, xUART_Receive()函數返回ram buffer的內容。
- xUART_Receive()參數
uxWantedBytes
,while循環將檢測buffer中的數據長度,當數據長度滿足或者超時時退出循環。 - 調用接收函數的task會多次進入Block狀態,xUART_Receive()
/* Driver library function to receive data from a UART. */
size_t xUART_Receive( xUART *pxUARTInstance, uint8_t *pucBuffer, size_t uxWantedBytes )
{
size_t uxReceived = 0;
TickType_t xTicksToWait;
TimeOut_t xTimeOut;
/* Record the time at which this function was entered. */
vTaskSetTimeOutState( &xTimeOut );
/* xTicksToWait is the timeout value - it is initially set to the maximum receive
timeout for this UART instance. */
xTicksToWait = pxUARTInstance->xRxTimeout;
/* Save the handle of the task that called this function. The book text contains notes
as to whether the following line needs to be protected by a critical section or not. */
pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle();
/* Loop until the buffer contains the wanted number of bytes, or a timeout occurs. */
while( UART_bytes_in_rx_buffer( pxUARTInstance ) < uxWantedBytes )
{
/* Look for a timeout, adjusting xTicksToWait to account for the time spent in this
function so far. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) != pdFALSE )
{
/* Timed out before the wanted number of bytes were available, exit the loop. */
break;
}
/* The receive buffer does not yet contain the required amount of bytes. Wait for a
maximum of xTicksToWait ticks to be notified that the receive interrupt service
routine has placed more data into the buffer. It does not matter if the calling
task already had a notification pending when it called this function, if it did, it
would just iteration around this while loop one extra time. */
ulTaskNotifyTake( pdTRUE, xTicksToWait );
}
/* No tasks are waiting for receive notifications, so set xTaskToNotify back to NULL.
The book text contains notes as to whether the following line needs to be protected by
a critical section or not. */
pxUARTInstance->xTaskToNotify = NULL;
/* Attempt to read uxWantedBytes from the receive buffer into pucBuffer. The actual
number of bytes read (which might be less than uxWantedBytes) is returned. */
uxReceived = UART_read_from_receive_buffer( pxUARTInstance, pucBuffer, uxWantedBytes );
return uxReceived;
}
/*-----------------------------------------------------------*/
/* The interrupt service routine for the UART's receive interrupt */
void xUART_ReceiveISR( xUART *pxUARTInstance )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Copy received data into this UART's receive buffer and clear the interrupt. */
UART_low_level_receive( pxUARTInstance );
/* If a task is waiting to be notified of the new data then notify it now. */
if( pxUARTInstance->xTaskToNotify != NULL )
{
vTaskNotifyGiveFromISR( pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
任務通知在設備驅動中的應用——ADC
下面例程展示了如何用vTaskNotifyFromISR()
,傳遞數據給task, 而上面的例程中使用的vTaskNotifyGiveFromISR()
只能傳遞事件給task.
- ADC task
/* A task that uses an ADC. */
void vADCTask( void *pvParameters )
{
uint32_t ulADCValue;
BaseType_t xResult;
/* The rate at which ADC conversions are triggered. */
const TickType_t xADCConversionFrequency = pdMS_TO_TICKS( 50 );
for( ;; )
{
/* Wait for the next ADC conversion result. */
xResult = xTaskNotifyWait(
/* The new ADC value will overwrite the old value, so there is no need to clear any bits before waiting for the new notification value. */
0,
/* Future ADC values will overwrite the existing value, so there is no need to clear any bits before exiting xTaskNotifyWait(). */
0,
/* The address of the variable into which the task's notification value (which holds the latest ADC conversion result) will be copied. */
&ulADCValue,
/* A new ADC value should be received every xADCConversionFrequency ticks. */
xADCConversionFrequency * 2 );
if( xResult == pdPASS )
{
/* A new ADC value was received. Process it now. */
ProcessADCResult( ulADCValue );
}
else
{
/* The call to xTaskNotifyWait() did not return within the expected time,something must be wrong with the input that triggers the ADC conversion, or with the ADC itself. Handle the error here. */
}
}
}
/*-----------------------------------------------------------*/
/* The interrupt service routine that executes each time an ADC conversion completes. */
void ADC_ConversionEndISR( xADC *pxADCInstance )
{
uint32_t ulConversionResult;
BaseType_t xHigherPriorityTaskWoken = pdFALSE, xResult;
/* Read the new ADC value and clear the interrupt. */
ulConversionResult = ADC_low_level_read( pxADCInstance );
/* Send a notification, and the ADC conversion result, directly to vADCTask(). */
xResult = xTaskNotifyFromISR( xADCTaskToNotify, /* xTaskToNotify parameter. */
ulConversionResult, /* ulValue parameter. */
eSetValueWithoutOverwrite, /* eAction parameter. */
&xHigherPriorityTaskWoken );
/* If the call to xTaskNotifyFromISR() returns pdFAIL then the task is not keeping up
with the rate at which ADC values are being generated. configASSERT() is described
in section 11.2.*/
configASSERT( xResult == pdPASS );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
任務通知在設備驅動中的應用——Task
向server task 發送隊列的數據類型和數據結構
typedef enum CloudOperations
{
eRead, /* Send data to the cloud server. */
eWrite /* Receive data from the cloud server. */
} Operation_t;
typedef struct CloudCommand
{
Operation_t eOperation; /* The operation to perform (read or write). */
uint32_t ulDataID; /* Identifies the data being read or written. */
uint32_t ulDataValue; /* Only used when writing data to the cloud server. */
TaskHandle_t xTaskToNotify; /* The handle of the task performing the operation. */
} CloudCommand_t;
cloud read
/* ulDataID identifies the data to read. pulValue holds the address of the variable into
which the data received from the cloud server is to be written. */
BaseType_t CloudRead( uint32_t ulDataID, uint32_t *pulValue )
{
CloudCommand_t xRequest;
BaseType_t xReturn;
/* Set the CloudCommand_t structure members to be correct for this read request. */
xRequest.eOperation = eRead; /* This is a request to read data. */
xRequest.ulDataID = ulDataID; /* A code that identifies the data to read. */
xRequest.xTaskToNotify = xTaskGetCurrentTaskHandle(); /* Handle of the calling task. */
/* Ensure there are no notifications already pending by reading the notification value with a block time of 0, then send the structure to the server task. */
xTaskNotifyWait( 0, 0, NULL, 0 );
xQueueSend( xServerTaskQueue, &xRequest, portMAX_DELAY );
/* Wait for a notification from the server task. The server task writes the value received from the cloud server directly into this task’s notification value, so there is no need to clear any bits in the notification value on entry to or exit from the xTaskNotifyWait() function. The received value is written to *pulValue, so pulValue is passed as the address to which the notification value is written. */
xReturn = xTaskNotifyWait( 0, /* No bits cleared on entry. */
0, /* No bits to clear on exit. */
pulValue, /* Notification value into *pulValue. */
pdMS_TO_TICKS( 250 ) ); /* Wait a maximum of 250ms. */
/* If xReturn is pdPASS, then the value was obtained. If xReturn is pdFAIL, then the request timed out. */
return xReturn;
}
server task
void ServerTask( void *pvParameters )
{
CloudCommand_t xCommand;
uint32_t ulReceivedValue;
for( ;; )
{
/* Wait for the next CloudCommand_t structure to be received from a task. */
xQueueReceive( xServerTaskQueue, &xCommand, portMAX_DELAY );
switch( xCommand.eOperation ) /* Was it a read or write request? */
{
case eRead:
/* Obtain the requested data item from the remote cloud server. */
ulReceivedValue = GetCloudData( xCommand.ulDataID );
/* Call xTaskNotify() to send both a notification and the value received from the
cloud server to the task that made the request. The handle of the task is
obtained from the CloudCommand_t structure. */
xTaskNotify( xCommand.xTaskToNotify, /* The task’s handle is in the structure. */
ulReceivedValue, /* Cloud data sent as notification value. */
eSetValueWithOverwrite );
break;
/* Other switch cases go here. */
}
}
}
cloud write
/* Status bits used by the cloud write operation. */
#define SEND_SUCCESSFUL_BIT ( 0x01 << 0 )
#define OPERATION_TIMED_OUT_BIT ( 0x01 << 1 )
#define NO_INTERNET_CONNECTION_BIT ( 0x01 << 2 )
#define CANNOT_LOCATE_CLOUD_SERVER_BIT ( 0x01 << 3 )
/* A mask that has the four status bits set. */
#define CLOUD_WRITE_STATUS_BIT_MASK ( SEND_SUCCESSFUL_BIT |
OPERATION_TIMED_OUT_BIT |
NO_INTERNET_CONNECTION_BIT |
CANNOT_LOCATE_CLOUD_SERVER_BIT )
uint32_t CloudWrite( uint32_t ulDataID, uint32_t ulDataValue )
{
CloudCommand_t xRequest;
uint32_t ulNotificationValue;
/* Set the CloudCommand_t structure members to be correct for this write request. */
xRequest.eOperation = eWrite; /* This is a request to write data. */
xRequest.ulDataID = ulDataID; /* A code that identifies the data being written. */
xRequest.ulDataValue = ulDataValue; /* Value of the data written to the cloud server. */
xRequest.xTaskToNotify = xTaskGetCurrentTaskHandle(); /* Handle of the calling task. */
/* Clear the three status bits relevant to the write operation by calling
xTaskNotifyWait() with the ulBitsToClearOnExit parameter set to
CLOUD_WRITE_STATUS_BIT_MASK, and a block time of 0\. The current notification value is
not required, so the pulNotificationValue parameter is set to NULL. */
xTaskNotifyWait( 0, CLOUD_WRITE_STATUS_BIT_MASK, NULL, 0 );
/* Send the request to the server task. */
xQueueSend( xServerTaskQueue, &xRequest, portMAX_DELAY );
/* Wait for a notification from the server task. The server task writes a bitwise status
code into this task’s notification value, which is written to ulNotificationValue. */
xTaskNotifyWait( 0, /* No bits cleared on entry. | */
CLOUD_WRITE_STATUS_BIT_MASK, /* Clear relevant bits to 0 on exit. */
&ulNotificationValue, /* Notified value.*/
pdMS_TO_TICKS( 250 ) ); /* Wait a maximum of 250ms. */
/* Return the status code to the calling task. */
return ( ulNotificationValue & CLOUD_WRITE_STATUS_BIT_MASK );
server task
void ServerTask( void *pvParameters )
{
CloudCommand_t xCommand;
uint32_t ulBitwiseStatusCode;
for( ;; )
{
/* Wait for the next message. */
xQueueReceive( xServerTaskQueue, &xCommand, portMAX_DELAY );
/* Was it a read or write request? */
switch( xCommand.eOperation )
{
case eWrite:
/* Send the data to the remote cloud server. SetCloudData() returns a bitwise status code that only uses the bits defined by the CLOUD_WRITE_STATUS_BIT_MASK definition (shown in Listing 161). */
ulBitwiseStatusCode = SetCloudData( xCommand.ulDataID, xCommand.ulDataValue );
/* Send a notification to the task that made the write request. The eSetBits action is used so any status bits set in ulBitwiseStatusCode will be set in the notification value of the task being notified. All the other bits remain unchanged. The handle of the task is obtained from the CloudCommand_t structure. */
xTaskNotify( xCommand.xTaskToNotify, /* The task’s handle is in the structure. */
ulBitwiseStatusCode, /* Cloud data sent as notification value. */
eSetBits );
break;
/* Other switch cases go here. */
}
}
}