2023年4月21日金曜日

液晶に大きな数字を書く

秋月電子で販売している液晶ディスプレイAQM0802とAQM1602は、I2C接続でArduinoやESP32、RaspberryPiPicoなどに接続できます。動作電流が1mAなので、電池駆動したい場合などに重宝します。

ただ、文字が小さいため、温度や時刻などを表示すると空白が余ります。そこで大きな数字を表示できるようにしてみました。

(ちなみに、ここに書いた方法以外にも、FunctionSetコマンド(0x38)を送信してDHを1にすることで、縦が2倍のdoubleHeightFontを使うことができます)

RaspberryPiPicoとAQM0802の接続

  • Pico -> AQM0802またはAQM1602
  • GP20(I2C0SDA)-> SDA
  • GP21(I2C0SCL) -> SCL
  • 3V3 -> VDD
  • GND->GND

           RESETは変換基板上でVDDにプルアップされているためオープンでOK

ArduinoUNOなどの5Vデバイスで使用する場合の注意

SDA、SCLにレベル変換を入れるほうが良いと思います。

(入れなくても3.3Vにプルアップすれば動きますが、壊れても文句言わない)

Picoのボードファイルについて

mbedにする場合、SDA、SCLはGP6、GP7に固定されていますので注意が必要です。

特別こだわりがなければ、'Earle F. Philhower, III'バージョンを使ったほうがI2Cのピンを変更できたり、いろいろ便利です。

他の液晶

似たような液晶パネルに、ACM1602NIなどがありますが、キャラクタパターンが違うので使えません。

#include "AQM0802BigDigit.h"
//----- I2C interface -----
void AQM0802BigDigit::WriteCommand(uint8_t data)
{
Wire.beginTransmission(0x3E);
Wire.write(0x00);
Wire.write(data);
Wire.endTransmission(true);
}
void AQM0802BigDigit::WriteData(uint8_t data)
{
Wire.beginTransmission(0x3E);
Wire.write(0x40);
Wire.write(data);
Wire.endTransmission(true);
}
void AQM0802BigDigit::createCustomChar(int index , const uint8_t* pattern)
{
WriteCommand(0x40 + index * 8);
for (int i=0; i<8; i++) WriteData(pattern[i]);
}
void AQM0802BigDigit::setCursorAtRowAndColumn(int row, int col)
{
WriteCommand(0x80 + col * 0x40 + row);
}
void AQM0802BigDigit::init()
{
WriteCommand(0x38); // Function set
WriteCommand(0x39); // Function set
WriteCommand(0x14); // Internal OSC frequency
WriteCommand(0x73); // Contrast set
WriteCommand(0x56); // Power/ICON/Contrast set
WriteCommand(0x6c); // Follower control
delay(200);
WriteCommand(0x38); // Function set
WriteCommand(0x0c); // Display ON/OFF control
WriteCommand(0x01); // Clear Display
delay(1);
WriteCommand(0x0C); // Display ON/OFF control
createCustomChar(0,image0);
createCustomChar(1,image1);
createCustomChar(2,image2);
createCustomChar(3,image3);
createCustomChar(4,image4);
createCustomChar(5,image5);
}
void AQM0802BigDigit::displayBigDigitAtColumn(uint8_t digit, uint8_t pos_x)
{
setCursorAtRowAndColumn(pos_x,0);
WriteData(bigDigitFull[digit][0]);
WriteData(bigDigitFull[digit][1]);
setCursorAtRowAndColumn(pos_x,1);
WriteData(bigDigitFull[digit][2]);
WriteData(bigDigitFull[digit][3]);
}
void AQM0802BigDigit::displayBigDigitHalfAtColumn(uint8_t digit, uint8_t pos_x)
{
setCursorAtRowAndColumn(pos_x,0);
WriteData(bigDigitHalf[digit][0]);
setCursorAtRowAndColumn(pos_x,1);
WriteData(bigDigitHalf[digit][1]);
}
#include <Arduino.h>
#include <Wire.h>
class AQM0802BigDigit
{
private:
void WriteCommand(uint8_t data);
void WriteData(uint8_t data);
void createCustomChar(int index , const uint8_t* pattern);
void setCursorAtRowAndColumn(int row, int col);
public:
void init();
void displayBigDigitAtColumn(uint8_t digit, uint8_t pos_x);
void displayBigDigitHalfAtColumn(uint8_t digit, uint8_t pos_x);
private:
//CGRAM character
const uint8_t image0[8] = { 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111 };
const uint8_t image1[8] = { 0b11111, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b11111 };
const uint8_t image2[8] = { 0b11111, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111 };
const uint8_t image3[8] = { 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111 };
const uint8_t image4[8] = { 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b11111 };
const uint8_t image5[8] = { 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b11111 };
//lookup table
const uint8_t bigDigitFull[10][4] = {
{0x09,0x0A,0x0B,0x0C}, //0
{0x20,0x7C,0x20,0x7C},
{0x00,0x01,0x0B,0x5F},
{0xFF,0x01,0x5F,0x0C},
{0x03,0x05,0x20,0x7C},
{0x02,0x00,0x5F,0x0C},
{0x02,0x00,0x0B,0x0C},
{0x09,0x0A,0x20,0x7C},
{0x02,0x01,0x0B,0x0C},
{0x02,0x01,0x5F,0x0C} // 9
};
const uint8_t bigDigitHalf[13][2] = {
{0x20,0x20}, // ' '
{0x7C,0x7C},
{0x01,0x0B},
{0x01,0x0C},
{0x66,0x7C}, //4
{0x02,0x0C},
{0x02,0x66}, //6
{0x0A,0x7C},
{0x4F,0x4F}, //8
{0x4F,0x0C}, //9
{0x20,0x2E}, //.
{0xA5,0xA5}, //:
{0xFF,0x20} //-
};
};
#include <Wire.h>
#include "AQM0802BigDigit.h"
// ------------------------------------------------------------------------------------------------------
// AQM1602, AQM0802
// This source code is written for Raspberry Pi pico, but it can also be used with ArduinoUNO by modifying the Wire settings.
// ## Raspberry Pi pico
// Please use 'Earle F. Philhower, III' version.
// When using the 'mbed' version, some changes are required in the wire definition, and the SDA and SCL port are fixed.
const uint8_t PIN_I2CSDA = 20;
const uint8_t PIN_I2CSCL = 21;
AQM0802BigDigit lcd;
void setup() {
Wire.setSDA(PIN_I2CSDA);
Wire.setSCL(PIN_I2CSCL);
Wire.begin();
lcd.init();
}
void loop() {
//Sample1 FM frequency
uint16_t freq = 740;
while (freq != 1080) {
lcd.displayBigDigitHalfAtColumn((freq / 1000 == 1),0);
lcd.displayBigDigitAtColumn((freq / 100) % 10, 1);
lcd.displayBigDigitAtColumn((freq / 10) % 10, 3);
lcd.displayBigDigitHalfAtColumn(10,5); // .
lcd.displayBigDigitAtColumn((freq) % 10, 6);
freq++;
delay(10);
}
//Sample2 clock
uint8_t time_hour = 0;
uint8_t time_min = 0;
while (time_hour < 13) {
time_min = 0;
while (time_min < 60) {
lcd.displayBigDigitHalfAtColumn((time_hour / 10), 0);
lcd.displayBigDigitAtColumn((time_hour % 10),1);
lcd.displayBigDigitHalfAtColumn(11,3); // :
lcd.displayBigDigitAtColumn((time_min / 10),4);
lcd.displayBigDigitAtColumn((time_min % 10),6);
time_min++;
delay(10);
}
time_hour++;
}
}


2022年8月12日金曜日

エレガントなdebounce(チャタリング防止)のためのArduinoコード

先日Arduinoのソースコードを書いてふと思ったのですが、 何かを作るたびに毎回同じようなコードを書いていることに気づいたため、エレガントに実装できないか考えてみました。

回路図

ESP32を使用していますが、ArduinoUNOやRaspberryPiPicoでも同じです。ただしピンを変更してください。

ソースコードと実装

SwitchInterface classの部分をコピーするなり、適当にSW_IF.hなどの名前で外部記述してincludeすれば、あとはグローバルでインスタンスするだけで使えます。(ここではBUTTONという名前)
あまりincludeするファイルを増やしたくないという方は、数十行のコードなので、inoファイルに直接コピーすると良いでしょう。

1 SwitchInterfaceクラスをコピー
2 SwitchInteface インスタンス名(ピン番号)をグローバルで記述
3 インスタンス名.onSWdown()でスイッチが押されたことを検出するので、そのあとの動作を記述


#define PIN_BUTTON 12
#define PIN_LED 26
//---- SWITCH interface class -----
class SwitchInterface {
private:
uint8_t reg;
uint8_t pin;
public:
SwitchInterface(uint8_t _pin) {
reg = 0xFF;
pin = _pin;
pinMode(pin, INPUT_PULLUP);
};
bool onSWdown(){
reg = (reg << 1) | digitalRead(pin);
if ((reg & 0x03) == 0x2) return true;
else return false;
};
bool onSWup(){
reg = (reg << 1) | digitalRead(pin);
if ((reg & 0x03) == 0x1) return true;
else return false;
};
};
// ------- end of SWITCH interface class ----
//instance Switch interface
SwitchInterface BUTTON(PIN_BUTTON);
void setup() {
pinMode(PIN_LED, OUTPUT);
}
void loop() {
if (BUTTON.onSWdown()) {
digitalWrite(PIN_LED,!digitalRead(PIN_LED));
}
delay(3); // sampling rate 3~20 msec
}
view raw debounce.ino hosted with ❤ by GitHub

debounceについて

サンプリング周期(最後のほうに記述しているdelay)は3ms~20msで良いと思います。debounceの起こる時間はおよそ3msくらいらしいので、最低でも3msec以上は必要です。
上限は20msecでも100msecでも良いのですが、あまり大きくしすぎるとスイッチの反応が遅くなります。

2022年6月16日木曜日

ESP32 secureなWiFiリモートスイッチ

 せっかくSHAとAESのハードウェアアクセラレータが使えるようになったので、WiFiを使ったリモートスイッチを暗号化して、セキュアなWiFiリモートスイッチを作ってみました。クライアント側のスケッチ、サーバ側のスケッチを2つ用意し、それぞれのフォルダに共通ライブラリをコピー&ペーストしてコンパイルしてください。

接続

クライアント側の25Pinにスイッチ、26PinにLEDと抵抗をつけます。LEDと抵抗は通信エラーが起きたときのインジケータなので、なくても大丈夫です。

サーバ側の25PinにLEDと抵抗をつけます。


クライアント側のスケッチ

/*
secure WiFi remote control Client
Challenge-Handshake Authentication Protocol
https://en.wikipedia.org/wiki/Replay_attack
*/
#include "ESP32E_AES_Hardware_Accelerator.h"
#include <WiFi.h>
const char* ssid = "your ssid";
const char* password = "your password";
char hostIP[] = "192.168.11.21";
int hostPort = 4000;
uint32_t cipher_key[] = {0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c};
RTC_DATA_ATTR int bootCount = 0;
WiFiClient client;
const int LED_PIN = 26;
AES_HardwareAccelerator AES;
void setup() {
uint8_t input[256];
bootCount++;
pinMode(GPIO_NUM_25, INPUT_PULLUP);
Serial.begin(115200);
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
//Power on Reset or unknown wakeup reason
if (( bootCount == 0 ) || (wakeup_reason != ESP_SLEEP_WAKEUP_EXT0)) {
delay(1000);
Serial.println("initial boot");
deepsleep();
}
// WiFi connection
int timeout_count = 0;
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
timeout_count++;
delay(100);
if (timeout_count == 50) {
Serial.println("WiFi Connect failed.");
connectionfailed();
deepsleep();
}
}
Serial.println("WiFi Connected.");
Serial.printf("IP Address : ");
Serial.println(WiFi.localIP());
Serial.println("Connect to server");
uint32_t msg_LINK[] = {0x4C494E4B, 0x00000000, 0x00000000, 0x00000000}; //LINK
uint32_t msg_CHAL[] = {0x4348404C, 0x4C454E47, 0x00000000, 0x00000000}; //CHAL LENG
uint32_t msg_TGL[] = {0x4C454454, 0x474C0000, 0x00000000, 0x00000000}; //LEDTGL
uint32_t msg_ACK[] = {0x41434B00, 0x00000000, 0x00000000, 0x00000000}; //ACK
uint32_t msg_NACK[] = {0x4E41434B, 0x00000000, 0x00000000, 0x00000000}; //NACK
uint32_t declipt_msg[4];
uint8_t senddata[16]; //output buffer for WiFi packet
uint8_t recvdata[16]; //input buffer for WiFi packet
//connect to server
int returncode = client.connect(hostIP, hostPort, 1000);
if (returncode != 1) {
Serial.print("connection failed");
Serial.print(returncode);
connectionfailed();
deepsleep();
}
client.setTimeout(1000);
//1 : to Server, Link Request
encrypt_byte(cipher_key, msg_LINK, senddata);
client.write(senddata,sizeof(senddata));
//2: from Server, get challange code from server
while (client.available() == 0) { }
client.read(recvdata, sizeof(recvdata));
decrypt_byte(cipher_key, recvdata, declipt_msg);
if ((declipt_msg[0] != 0x4348404C) || (declipt_msg[1] != 0x4C454E47)) {
Serial.println("response error");
connectionfailed();
client.stop();
deepsleep();
}
//3: to Server, send "LED msg_TGL" command + challenge code
msg_TGL[3] = declipt_msg[3];
encrypt_byte(cipher_key, msg_TGL, senddata);
client.write(senddata, sizeof(senddata));
//4: from Server, get "ACK"
while (client.available() == 0) { }
client.read(recvdata, sizeof(recvdata));
decrypt_byte(cipher_key, recvdata, declipt_msg);
if (declipt_msg[0] == 0x41434B00) { //ACK
Serial.println("SUCCESS");
} else {
Serial.println("FAIL");
}
client.stop();
deepsleep();
}
void loop() {
}
void deepsleep() {
WiFi.disconnect(true);//disconnect WiFi as it's no longer needed
WiFi.mode(WIFI_OFF);
while (digitalRead(25) == LOW) { }
esp_sleep_enable_ext0_wakeup(GPIO_NUM_25, LOW);
Serial.println("Going to sleep now");
esp_deep_sleep_start();
}
void connectionfailed() {
Serial.println("Connection failed.");
for (int i = 0; i < 5; i++) {
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
delay(200);
}
}
void encrypt_byte(uint32_t * cipher_key, uint32_t * text, uint8_t * c_text) {
AES.enable();
AES.setMode_AES128Encrypt();
AES.setCipherKey(cipher_key);
AES.setTextReg(text);
AES.start();
AES.getTextReg(c_text);
AES.disable();
}
void decrypt_byte(uint32_t * cipher_key, uint8_t * c_text, uint32_t * text) {
AES.enable();
AES.setMode_AES128Decrypt();
AES.setCipherKey(cipher_key);
AES.setTextReg(c_text);
AES.start();
AES.getTextReg(text);
AES.disable();
}

サーバ側のスケッチ

/*
secure WiFi remote control Server
Challenge-Handshake Authentication Protocol
https://en.wikipedia.org/wiki/Replay_attack
*/
#include "ESP32E_AES_Hardware_Accelerator.h"
#include <WiFi.h>
const char* ssid = "your ssid";
const char* password = "your password";
int hostPort = 4000;
WiFiServer server(hostPort);
const int LED_PIN = 25;
uint32_t cipher_key[] = {0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c};
AES_HardwareAccelerator AES;
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
delay(500);
Serial.println();
WiFi.begin(ssid, password);
Serial.print("connecting WiFi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.println();
Serial.println("WiFi Connected.");
Serial.printf("IP Address : ");
Serial.println(WiFi.localIP());
server.begin();
Serial.println("start server");
randomSeed(100);
}
void loop() {
uint32_t msg_LINK[] = {0x4C494E4B, 0x00000000, 0x00000000, 0x00000000}; //LINK
uint32_t msg_CHAL[] = {0x4348404C, 0x4C454E47, 0x00000000, 0x00000000}; //CHAL LENG
uint32_t msg_TGL[] = {0x4C454454, 0x474C0000, 0x00000000, 0x00000000}; //LEDTGL
uint32_t msg_ACK[] = {0x41434B00, 0x00000000, 0x00000000, 0x00000000}; //ACK
uint32_t msg_NACK[] = {0x4E41434B, 0x00000000, 0x00000000, 0x00000000}; //NACK
uint32_t declipt_msg[4];
uint8_t senddata[16]; //output buffer for WiFi packet
uint8_t recvdata[16]; //input buffer for WiFi packet
WiFiClient client = server.available(); // listen for incoming clients
if (client) {
Serial.println("New Client connected.");
while (client.connected()) { // loop while the client's connected
client.setTimeout(1000);
while (client.available() == 0) { }
//1: from client, Link Request
client.read(recvdata, sizeof(recvdata));
decrypt_byte(cipher_key, recvdata, declipt_msg);
if (declipt_msg[0] != msg_LINK[0]) {
client.println("NACK");
client.stop();
Serial.println("client disconnected.");
break;
}
//2: to client, generate charrange code and send
uint32_t challenge = random(0xFFFFFFFF);
msg_CHAL[3] = challenge;
encrypt_byte(cipher_key, msg_CHAL, senddata);
client.write(senddata, sizeof(senddata));
//3: from client, command and challenge code
while (client.available() == 0) { }
client.read(recvdata, sizeof(recvdata));
decrypt_byte(cipher_key, recvdata, declipt_msg);
//4 to client, ACK /NACK
if (declipt_msg[3] == challenge) {
if ((declipt_msg[0] == 0x4C454454) && (declipt_msg[1] == 0x474C0000)) { //LEDTGL
led_toggle();
msg_ACK[3] = challenge;
encrypt_byte(cipher_key, msg_ACK, senddata);
}
} else {
msg_NACK[3] = challenge;
encrypt_byte(cipher_key, msg_NACK, senddata);
}
client.write(senddata, sizeof(senddata));
client.stop();
Serial.println("client disconnected.");
}
}
delay(1);
}
void encrypt_byte(uint32_t * cipher_key, uint32_t * text, uint8_t * c_text) {
AES.enable();
AES.setMode_AES128Encrypt();
AES.setCipherKey(cipher_key);
AES.setTextReg(text);
AES.start();
AES.getTextReg(c_text);
AES.disable();
}
void decrypt_byte(uint32_t * cipher_key, uint8_t * c_text, uint32_t * text) {
AES.enable();
AES.setMode_AES128Decrypt();
AES.setCipherKey(cipher_key);
AES.setTextReg(c_text);
AES.start();
AES.getTextReg(text);
AES.disable();
}
void led_toggle() {
if (digitalRead(LED_PIN) == HIGH) digitalWrite(LED_PIN, LOW);
else digitalWrite(LED_PIN, HIGH);
}

共通ライブラリ

/*
* FILE: ESP32E_AES_Hardware_Accelerator.h
* AUTHOR: PiT
* PURPOSE: Arduino library for ESP32E AES Hardware Accelerator
* VERSION: 1.0.0
*/
#define DPORT_PERI_CLK_EN_REG *((volatile uint32_t *)0x3FF0001C)
#define DPORT_PERI_RST_EN_REG *((volatile uint32_t *)0x3FF00020)
#define AES_MODE_REG *((volatile uint32_t *)0x3FF01008)
#define AES_ENDIAN_REG *((volatile uint32_t *)0x3FF01040)
#define AES_KEY_0_REG *((volatile uint32_t *)0x3FF01010)
#define AES_KEY_1_REG *((volatile uint32_t *)0x3FF01014)
#define AES_KEY_2_REG *((volatile uint32_t *)0x3FF01018)
#define AES_KEY_3_REG *((volatile uint32_t *)0x3FF0101C)
#define AES_KEY_4_REG *((volatile uint32_t *)0x3FF01020)
#define AES_KEY_5_REG *((volatile uint32_t *)0x3FF01024)
#define AES_KEY_6_REG *((volatile uint32_t *)0x3FF01028)
#define AES_KEY_7_REG *((volatile uint32_t *)0x3FF0102C)
#define AES_TEXT_0_REG *((volatile uint32_t *)0x3FF01030)
#define AES_TEXT_1_REG *((volatile uint32_t *)0x3FF01034)
#define AES_TEXT_2_REG *((volatile uint32_t *)0x3FF01038)
#define AES_TEXT_3_REG *((volatile uint32_t *)0x3FF0103C)
#define AES_START_REG *((volatile uint32_t *)0x3FF01000)
#define AES_IDLE_REG *((volatile uint32_t *)0x3FF01004)
#define AES_MODE_AES128ENCRYPTION 0x00000000
#define AES_MODE_AES192ENCRYPTION 0x00000001
#define AES_MODE_AES256ENCRYPTION 0x00000002
#define AES_MODE_AES128DECRYPTION 0x00000004
#define AES_MODE_AES192DECRYPTION 0x00000005
#define AES_MODE_AES256DECRYPTION 0x00000006
#define AES_KEY_ENDIAN0 0x00000000
#define AES_KEY_ENDIAN1 0x00000001
#define AES_KEY_ENDIAN2 0x00000002
#define AES_KEY_ENDIAN3 0x00000003
#define AES_TEXT_ENDIAN0 0x00000000
#define AES_TEXT_ENDIAN1 0x00000014
#define AES_TEXT_ENDIAN2 0x00000028
#define AES_TEXT_ENDIAN3 0x0000003C
class AES_HardwareAccelerator {
public:
void enable();
void setMode_AES128Encrypt();
void setMode_AES128Decrypt();
void start();
void setCipherKey(uint32_t * cipher_key);
void setTextReg(uint32_t * textblock);
void setTextReg(uint8_t * text);
void getTextReg(uint32_t * textblock);
void getTextReg(uint8_t * text);
void disable();
};

/*
* FILE: ESP32E_AES_Hardware_Accelerator.cpp
* AUTHOR: PiT
* PURPOSE: Arduino library for ESP32E AES Hardware Accelerator
* VERSION: 1.0.0
*/
#include <Arduino.h>
#include "ESP32E_AES_Hardware_Accelerator.h"
void AES_HardwareAccelerator::enable() {
DPORT_PERI_CLK_EN_REG = DPORT_PERI_CLK_EN_REG | 0x00000001; // peripheral clock enable
DPORT_PERI_RST_EN_REG = DPORT_PERI_RST_EN_REG & (~(0x00000001 | 0x00000008 | 0x00000010)); // peripheral reset
}
void AES_HardwareAccelerator::setMode_AES128Encrypt() {
AES_MODE_REG = AES_MODE_AES128ENCRYPTION;
AES_ENDIAN_REG = AES_KEY_ENDIAN2 | AES_TEXT_ENDIAN2;
}
void AES_HardwareAccelerator::setMode_AES128Decrypt() {
AES_MODE_REG = AES_MODE_AES128DECRYPTION;
AES_ENDIAN_REG = AES_KEY_ENDIAN2 | AES_TEXT_ENDIAN2;
}
void AES_HardwareAccelerator::start() {
AES_START_REG = 0x00000001;
while (AES_IDLE_REG) {}
}
void AES_HardwareAccelerator::setCipherKey(uint32_t * cipher_key) {
AES_KEY_0_REG = cipher_key[0];
AES_KEY_1_REG = cipher_key[1];
AES_KEY_2_REG = cipher_key[2];
AES_KEY_3_REG = cipher_key[3];
}
void AES_HardwareAccelerator::setTextReg(uint32_t * text) {
AES_TEXT_0_REG = text[0];
AES_TEXT_1_REG = text[1];
AES_TEXT_2_REG = text[2];
AES_TEXT_3_REG = text[3];
}
void AES_HardwareAccelerator::setTextReg(uint8_t * text) {
uint32_t temp;
temp = text[0];
temp = (temp << 8) + text[1];
temp = (temp << 8) + text[2];
temp = (temp << 8) + text[3];
AES_TEXT_0_REG = temp;
temp = text[4];
temp = (temp << 8) + text[5];
temp = (temp << 8) + text[6];
temp = (temp << 8) + text[7];
AES_TEXT_1_REG = temp;
temp = text[8];
temp = (temp << 8) + text[9];
temp = (temp << 8) + text[10];
temp = (temp << 8) + text[11];
AES_TEXT_2_REG = temp;
temp = text[12];
temp = (temp << 8) + text[13];
temp = (temp << 8) + text[14];
temp = (temp << 8) + text[15];
AES_TEXT_3_REG = temp;
}
void AES_HardwareAccelerator::getTextReg(uint32_t * text) {
text[0] = AES_TEXT_0_REG;
text[1] = AES_TEXT_1_REG;
text[2] = AES_TEXT_2_REG;
text[3] = AES_TEXT_3_REG;
}
void AES_HardwareAccelerator::getTextReg(uint8_t * text) {
uint32_t temp;
temp = AES_TEXT_0_REG;
text[0] = temp >> 24;
text[1] = temp >> 16;
text[2] = temp >> 8;
text[3] = temp;
temp = AES_TEXT_1_REG;
text[4] = temp >> 24;
text[5] = temp >> 16;
text[6] = temp >> 8;
text[7] = temp;
temp = AES_TEXT_2_REG;
text[8] = temp >> 24;
text[9] = temp >> 16;
text[10] = temp >> 8;
text[11] = temp;
temp = AES_TEXT_3_REG;
text[12] = temp >> 24;
text[13] = temp >> 16;
text[14] = temp >> 8;
text[15] = temp;
}
void AES_HardwareAccelerator::disable() {
DPORT_PERI_CLK_EN_REG = 0x00000000; // peripheral clock enable
DPORT_PERI_RST_EN_REG = 0x0000000F; // peripheral reset
}

普通のWiFiリモコンとの違い

通信の内容をAES128を使って暗号化しています。

LEDを制御するコマンドがLEDTGLのみなので、通信するデータに乱数(Salt)をのせて、暗号文が通信毎に変わるようにしています。ただし、通信1発目のリンクリクエストについては、Saltを加えてもサーバは反応するしかないため、何もしていません。

サーバ側からワンタイムパスワード(Challenge)を送信し、クライアント側からはコマンドにワンタイムパスワードを加えた文字列を暗号化してサーバに送信します。サーバ側でワンタイムパスワードを比較することで、リプレイアタックされてもコマンドを受け付けないようにしています。

より詳しく知りたい方は、

リプレイアタック、チャレンジーハンドシェイク、CHAP

などを検索してください。