RPi で回線遅延シュミレーターを作る続き。

UIの拡張

回線遅延シュミレーターを操作するのに、以下の順にUIを拡張した。

  1. ssh login でコマンド実行
  2. LED(8個)で状況表示
  3. Node-Red で操作
  4. M5StickC で操作

最後は、M5StickC で操作できるようにする。 ボタンを押すと、遅延msecを増やす、リセットするなど。

似たようなものは、以下で作成済み。

endpoint

最初は、遅延時間を100msecづつ伸ばすendpointを想定していたけれど、うざい。 ということで、こんなendpointを用意した。

http://rsslss.local:1880/tc?delay_msec=100

100 は、 100msec ということ。 ボタンを押す毎に、以下の設定を順繰りに繰り返すようにした。

  • 0
  • 100msec
  • 200msec
  • 500msec
  • 1000msec
  • 1500msec

Arduino プログラム

仕様

  1. 起動時に以下のAPにアクセスする。
  • SSID: rpisll
  • PASS: ソースコードの12行目に埋込
  1. WIFI接続に成功したら、ntpd( ntp.nict.jp or ntp.jst.mfeed.ad.jp ) に時刻合わせする。

  2. ボタンAを押すと、遅延時間を順次変更する

  3. ボタンBを押すと、遅延時間を 0 に変更する。

追加で利用したライブラリ

NodeRed のREST APIが返すJsonを解析するために、 ArduinoJson を利用した。

rpissl_ctl.ino · Gistcpp
#include <M5StickC.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "time.h"

//
// Setting
//
const char* SSID     = "rpilss";
const char* PASSWORD = "パスワード";
const char* lss_end_point = "http://192.168.100.1:1880/tc";

const int Delays[] = { 0, 100, 200, 500, 1000, 1500 };

#define PIN_LED 10

//
// Global Variable
//
int Delay_msec = 0;
int Delay_next_msec = 0;
char Lan_ip[128];

//
// setup RTC by NTP
//
void setup_rtc() {
  struct tm timeinfo;
  uint8_t hh, mm, ss;
  RTC_TimeTypeDef TimeStruct;

  // connect NTP server
  configTime(9 * 3600, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
  if (!getLocalTime(&timeinfo)) {
    M5.Lcd.println("Failed to obtain time");
    return;
  }

  //
  // set localtime to RTC
  //
  hh = timeinfo.tm_hour;
  mm = timeinfo.tm_min;
  ss = timeinfo.tm_sec;
  // Serial.printf("%02d:%02d:%02d\r\n", hh, mm, ss);

  TimeStruct.Hours   = hh;
  TimeStruct.Minutes = mm;
  TimeStruct.Seconds = ss;
  M5.Rtc.SetTime(&TimeStruct);
}

//
// connect wifi
//
int setup_wifi() {

  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(DARKGREY);

  WiFi.disconnect(true);
  M5.Lcd.print("Connecting to ");
  // Serial.println("Connecting to ");
  M5.Lcd.printf(SSID);
  
  WiFi.begin(SSID, PASSWORD); //connect to wifi

  int count = 100;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");
    count -= 1;
    if (count == 0) {
      // Serial.println("max try failed");
      M5.Lcd.setTextSize(3); 
      M5.Lcd.setTextColor(RED);
      M5.Lcd.setCursor(0, 0);
      M5.Lcd.println("fail wifi connect");
      return -1;
    }
  }
  M5.Lcd.println("");
  M5.Lcd.println("WiFi connected.");
  M5.Lcd.print("IP address: ");
  M5.Lcd.println(WiFi.localIP());
  M5.Lcd.println();

  return 0;
}

void setup() {
  Serial.begin(9600);
  
  M5.begin();
  M5.Axp.ScreenBreath(10);
  M5.Lcd.setRotation(3);      // 左を上にする
  M5.Lcd.setTextSize(1);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(DARKGREY);
  delay(500);

 // PIN MODE setup
  pinMode(PIN_LED, OUTPUT);              // LED

  //
  // Wifi
  //
  setup_wifi();

  //
  // setup RTC time
  //
  setup_rtc();

  // LED OFF 
  digitalWrite(PIN_LED, HIGH);
}

//
// change delay msec to RPi
//
void change_delay(int delay_msec) {

  HTTPClient http;
  int httpCode;
  char url[256];

  sprintf(url, "%s?delay_msec=%d", lss_end_point, delay_msec);
  Serial.println(url);
  http.begin(url);
  httpCode = http.PATCH((uint8_t*)"", 0); 
 
  if (httpCode == 200) {
    Stream* resp = http.getStreamPtr();

    DynamicJsonDocument json_response(255);
    deserializeJson(json_response, *resp);

    Delay_msec = json_response["delay_msec"];
    strncpy(Lan_ip, json_response["lan_ip"], sizeof(Lan_ip));
  }
  http.end();

  return;
}

void loop() {
  
  const int WAIT_TIME = 300;
  RTC_TimeTypeDef RTC_TimeStruct;
  int next_delay_msec;

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("not connect");
    if (setup_wifi() < 0) {
      return;
    }
    // Serial.println("connect ok");
  }
  
  // pinの状態など更新
  M5.update();

  int pressBtn = 0;
  int is_reset = false;
  if (M5.BtnA.wasPressed()) {
    pressBtn = 1;
  }
  if (M5.BtnB.wasPressed()) {
    is_reset = true;
    pressBtn = 2;
  }

  Delay_next_msec = 0;
  if (pressBtn) {
    
    // get time
    M5.Rtc.GetTime(&RTC_TimeStruct);
    
    M5.Lcd.setTextSize(1); 
    M5.Lcd.setCursor(32, 9*8);
    M5.Lcd.setTextColor(DARKGREEN);
    M5.Lcd.fillRect(0, 9*8, 256, 12, BLACK);
    M5.Lcd.printf("Time: %02d : %02d : %02d\n",
      RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);

    // LED ON
    digitalWrite(PIN_LED, LOW);

    Serial.println("Delay_msec");
    Serial.println(Delay_msec);
    if (!is_reset) {
      for (int i; i < sizeof(Delays); i++) {
        if (Delay_msec == Delays[i]) {
          if (i < (sizeof(Delays)-1)) {
            Delay_next_msec = Delays[i+1];
          }
          break;
        }
      }
    }

    change_delay(Delay_next_msec);

    // display
    M5.Lcd.fillRect(0, 4*8, 256, 32, BLACK);
    
    // LAN IP
    M5.Lcd.setTextSize(1); 
    M5.Lcd.setCursor(0, 4*8);
    M5.Lcd.setTextColor(DARKGREEN);
    M5.Lcd.printf("eth0 IP: %s\r\n", Lan_ip);

    // delay msec
    M5.Lcd.setTextSize(1); 
    M5.Lcd.setCursor(0, 6*8);
    M5.Lcd.setTextColor(DARKGREEN);
    M5.Lcd.printf("delay:\r\n");
    
    M5.Lcd.setTextSize(2); 
    M5.Lcd.setCursor(32, 6*8);
    M5.Lcd.setTextColor(DARKGREEN);
    M5.Lcd.printf(" %d msec\r\n", Delay_msec);

    // LED OFF
    digitalWrite(PIN_LED, HIGH);
  }

  delay(WAIT_TIME);
}