FreeRTOSのmessageBuffer


下記の記事から続くFreeRTOSの機能に関する記事です。

https://qiita.com/tom_S/items/ea653880132e1fcfed72

FreeRTOSのmessageBufferについて説明します。streamBufferという機能もFreeRTOSにはありますが、内部的な実装はほとんど変わらないので、streamBufferの説明は割愛します

## FreeRTOSのmessageBuffer

名前はmessageBufferですが、仕様はItronやToppers等のメッセージボックス、メールボックスと似たような形です。ただし、メッセージボックスで受信するのに使うバッファはユーザ側で定義する必要があります(OS側では受信バッファを用意していない)。よって、内部的に受信側のバッファ→送信側のバッファへコピーが発生する。よってこの時間を考慮して、送るメッセージを考える必要があります。

![messageBuffer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/491992df-bf7e-acf3-8a89-7ce92750020e.png)


また、実装を見たところ各APIの内部で排他制御などを行っているわけではありません。
よって、一つのタスクもしくは割込みからメッセージが送信側、一つのタスクが受信側となることが想定されています(複数のタスクからmessageBufferの送信、受信をすることは想定されていない)。
また、uItronにおけるメッセージバッファ(先頭アドレスのみを渡すもの)は機能として存在しません。

### xMessageBufferCreate
```c
MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|| メッセージボックスを作成する |
| 引数 | xBufferSizeBytes | 一度に送受信可能なメッセージサイズ。小さすぎると動作が遅くなることがあるので注意<br>(単位はbyte) |
|返り値| | 作成に成功したメッセージボックスの<br>ID。失敗時はNULLが入る |

### xMessageBufferSend
```c
size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
                           const void *pvTxData,
                           size_t xDataLengthBytes,
                           TickType_t xTicksToWait )
size_t xMessageBufferSendISR( MessageBufferHandle_t xMessageBuffer,
                              const void *pvTxData,
                              size_t xDataLengthBytes,
                              TickType_t xTicksToWait )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|| メッセージボックスへメッセージ<br>を送る |
| 引数 | xMessageBuffer| 送信先のメッセージボックスのID |
|| pvTxData|送信するメッセージの先頭ポインタ<br>(メッセージそのものはメッセージ<br>ボックス内でコピーされ使われる) |
|| xDataLengthBytes| 送信するメッセージの長さ(byte値)。xMessageBufferCreate()で設定した値より小さければ問題ない |
|| xTicksToWait | タイムアウト時間。タイムアウトを無しに設定する場合は、FreeRTOSConfig.hにて「INCLUDE_vTaskSuspend」を1に定義し、xTicksToWaitはportMAX_DELAYを指定する。 |
|返り値| | 送信が完了したデータサイズ(byte値) |

### xMessageBufferReceive
```c
size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
                              void *pvRxData,
                              size_t xBufferLengthBytes,
                              TickType_t xTicksToWait )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|| メッセージボックスからメッセージを受信する |
| 引数 | xMessageBuffer| 受信先のメッセージボックスのID |
|| pvRxData|受信するメッセージの先頭ポインタ<br>(メッセージそのものはpvRxDataに<br>コピーされる) |
|| xBufferLengthBytes| 受信するメッセージの長さ(byte値) |
|| xTicksToWait | タイムアウト時間。タイムアウトを無しに設定する場合は、FreeRTOSConfig.hにて「INCLUDE_vTaskSuspend」を1に定義し、xTicksToWaitはportMAX_DELAYを指定する。 |
|返り値| | 受信が完了したデータサイズ(byte値) |

### vMessageBufferDelete
```c
void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|| メッセージボックスを削除する |
| 引数 | xMessageBuffer | 削除するメッセージボックスのID |
|返り値| | なし |

## サンプルソース

MessageBufferのサンプルソースコードを下記に示します。
下記のサンプルでは、メッセージを送信するタスクと受信するタスクを生成して動作させています。

```c
#include "message_buffer.h"

TaskHandle_t sendTask;
TaskHandle_t receiveTask;

MessageBufferHandle_t messageBufferHandle; /* messageBuffer の ID */

/* メッセージ送信タスク */
static void send_task(void * argument)
{
	char buffer[4]= {1,2,3,4};

	for( ;; )
	{
		vTaskDelay(100);
		/* メッセージ送信 */
		xMessageBufferSend(messageBufferHandle, &buffer[0], 4, 0x1000);
	}

    
    vTaskDelete(NULL); /* 何らかのエラーで処理が終了した場合にはタスクを削除 */
}

/* メッセージ受信タスク */
static void receive_task(void * argument)
{
	char buffer[128];
	int receiveByte = 0;

	for( ;; )
	{
        /* メッセージ受信。受信データがない場合はブロック状態になる */
		receiveByte = xMessageBufferReceive(messageBufferHandle, &buffer[receiveByte], 4, portMAX_DELAY);

        /* ここに受診したデータを使った処理を書く */
	}

    
    vTaskDelete(NULL); /* 何らかのエラーで処理が終了した場合にはタスクを削除 */
}

/* タスクとメッセージバッファの生成用の処理 */
static void StartTask(void const * argument)
{
    /* messageBuffer 作成 */
    messageBufferHandle = xMessageBufferCreate(128);

    /* 送信用のタスクを生成 */
    if (pdTRUE != xTaskCreate(send_task, "SEND_THREAD", 1024, &task1_delay, 2, &sendTask))
    {
        return;
    }
    /* 受信用のタスクを生成 */
    if (pdTRUE != xTaskCreate(receive_task, "RECEIVE_THREAD", 1024, NULL, 4, &receiveTask))
    {
        return;
    }

    
    vTaskDelete(NULL); /* 処理を終了につき、タスクを削除 */
}
```