タッチディスプレイ gen4-uLCD-35DT > 28文字の表示とタッチ検知 (STM32F446 Nuclero-64 + FreeRTOS) | はまった点: strlen()を使用

```txt:動作環境
Ubuntu 18.04 LTS 
display module: gen4-uLCD-35DT 
  Workshop 4 IDE v4.5.0.17 (on Windows 10 Pro)
MCU: STM32F446 Nuclero-64
  STM32CubeIDE v1.0.1 (on Ubuntu 18.04 LTS)
```

## 概要

- タッチディスプレイgen4-uLCD-35DT使用
- 28個の文字列の表示とタッチ検知
- 通信はUART (115200bps)

## 接続

- gen4-uLCD-35DT
    - 30ピンフレキシブルケーブルからgen4-IBへ
    - gen4-IBから
        - +V5: スイッチングACアダプタ(5V)
        - RX: STM32のCN9 PWM/D3 (PA10)
            - STM32のUART1のRX
        - TX: STM32のCN9 D8 (PA9)
            - STM32のUART1のTX
        - GND: 以下の二つ
            - スイッチングACアダプタ
            - STM32のGND

## 手順概要

1. Workshop 4 IDEにてViSi Genie選択し、UIを作成しておく
    - 28個のStringを配置
        - イベントなし
    - 1個のWinButtonを配置
        - イベントなし
2. STM32CubeIDEにおいてFreeRTOSを用いたシリアル通信を実装する
    - ioc設定
        - FreeRTOS
            - CMSIS_V1
            - タスク追加
                - TaskName: serialTask
                - Priority: osPriorityAboveNormal
                - EntryFunction: StartSerialTask
                - 他はデフォルトのままで
        - SYS
            - Timerbase Source: TIM14
        - UART1
            - Mode: Asynchronous
            - Baud Rate: 115200 Bits/s

## 通信

通信は以下の二つを行う

- A. Stringの書換え
- B. WinButtonのタッチ検知

Stringsの書換え例 (インデックス0のStringに3文字の`bbb`を書く)

```
tx: 02 00 03 62 62 62 63
rx: 06
```


タッチ検知例 (押下時)

```
tx: 00 06 00 06
rx: 05 06 00 01 02
```

これらの文字列はWorkshop 4 IDEのGTXを使って通信コードを確認できる。
また、ViSi-Genie Reference Manualのp6 3.1.2 Protocol Definitionsにおいても記載がある。

## 実装

STM32側の実装例

通信部分

```main.c
static unsigned char calc_checksum(unsigned char *ptr, int size)
{
	if (ptr == NULL) {
		return 0x00;
	}
	unsigned char code = 0;
	for(int idx=0; idx < size; idx++) {
		code ^= ptr[idx];
	}
	return code;
}
static void disp_setString(int idx, char *ptr, int len)
{
	// ViSi Genieで作成したStringコンポーネント28個への書き込み
	// idx: 0..27
	//
	unsigned char txbuf[20] = {0};
	unsigned char rxbuf[20] = {0};
	int pos=0;

	txbuf[pos++] = 0x02; // cmd
	txbuf[pos++] = idx;
	txbuf[pos++] = len;
	for(int loop=0; loop < len; loop++) {
		txbuf[pos++] = *(ptr+loop);
	}
	unsigned char chksm = calc_checksum(txbuf, pos);
	txbuf[pos++] = chksm;

	HAL_UART_Transmit(&huart1, (uint8_t *)txbuf, pos, 100);
	HAL_UART_Receive(&huart1, (uint8_t *)rxbuf, 1, 300);
}

static int disp_touchDetect()
{
	// 0: not touched
	// >0: touched

	unsigned char txbuf[20] = {0};
	unsigned char rxbuf[20] = {0};
	int pos=0;

	txbuf[pos++] = 0x00; // cmd
	txbuf[pos++] = 0x06;
	txbuf[pos++] = 0x00;
	unsigned char chksm = calc_checksum(txbuf, pos);
	txbuf[pos++] = chksm;

	HAL_UART_Transmit(&huart1, (uint8_t *)txbuf, pos, 100);
	HAL_UART_Receive(&huart1, (uint8_t *)rxbuf, 6, 300);

	return rxbuf[4] > 0;
}
```

シリアルタスク部分

```main.c
void StartSerialTask(void const * argument)
{
  /* USER CODE BEGIN StartSerialTask */
  /* Infinite loop */
  int state = 0;

  for(;;)
  {
	  int wrk = 0;
	  for(int idx=0; idx < 5; idx++) {
		  wrk += disp_touchDetect();
		  osDelay(100);
	  }
	  if (wrk > 0) { // 1回でもタッチがあれば状態を変更
		  state ^= 0x01;
	  }

	  for(int idx=0; idx<28; idx++) {
		  if (state == 0) {
			  disp_setString(idx, "nnnnn", strlen("nnnnn"));
		  } else {
			  disp_setString(idx, "ttttt", strlen("ttttt"));
		  }
	  }

      osDelay(300);
  }
  /* USER CODE END StartSerialTask */
}
```


## 実行例

初期状態 (nnnnが描画される)

![IMG_1266.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/13485bfd-b887-30a1-b96c-f67e89572e62.jpeg)

タッチ後 (tttttが表示される)
![IMG_1268.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/db137ee4-8486-6ca2-6002-16720e094d6a.jpeg)


さらにタッチするとnnnnnの表示に戻る。


## はまった点: strlen()を使用

シリアル送信時にコマンドの長さを見るためにstrlen()を使うという間違いをしていた。
文字列中に0x00が含まれるためstrlen()では途中までしか送信できない。

固定長となるので、バッファに入れた位置から分かるposを使うようにした。