ワイヤレスリモコンを改造しよう7

https://tomo3i.hatenablog.com/entry/2018/11/21/082245

そこそこ順調に動いてくれていたものの、たまに固まっていることに気がついた。特にログも出していないし何が問題なのかはまったくわからない。そこでとりあえずの対策としてwatchdog timerを導入することにした。

Arduinoっていろんな種類のMCUがあって、ボードによって同じコードが動いたり動かなかったりするというのは、前回HIDで学んだことだけど、watchdog timerも似たような状況っぽい。発見したソースコードコンパイルしたらエラーなく通ったのでTinyduinoでも動かしてみることにした。

#include <avr/wdt.h>

void setup ()
{
  Serial.begin (115200);
  Serial.println ("Restarted.");
  wdt_enable (WDTO_8S);  // reset after one second, if no "pat the dog" received
}  // end of setup

void loop ()
{
  Serial.println ("Entered loop ...");
  wdt_reset ();  // give me another second to do stuff (pat the dog)
  while (true) ;   // oops, went into a loop
}  // end of loop

これで、8秒後にリセットがかかるようになった。Tinyduinoはavr/wdt.hでウォッチドッグタイマーが使えます。

あと、単に点灯し続けるのはつまらないので勝手にON/OFFさせてみることにした。

unsigned long nextOnTime = 0;
unsigned long nextOffTime = 0;
unsigned long currentTime = 0;
void blinkOnOff() {
  if (lastCommand == 1) {
    currentTime = millis();

    if (currentTime > nextOnTime) {
      modulate_out(on);
      nextOffTime = currentTime + 2000;
      nextOnTime = currentTime + 3000;
    }
    if (currentTime > nextOffTime) {
      modulate_out(off);
      nextOffTime = currentTime + 10000;
    }
  }
  else {
    nextOnTime = nextOffTime = 0;
  }
}

millis()というのは50日ぐらいでオーバーフローするらしい。今のところ3日ぐらいで固まっているから問題ないことにする。ということで、ONしたら次にOFFするタイミングとONするタイミングを決めておくことにした。このタイミング情報は、本来なら決め打ちじゃなくてHTTPでもってくるJSONのパラメーターとして実装したいところだけど、とりあえずの実装としてはこれでOKということにする。

ということで、全ソースコード

/*
  Modified Repeating WiFi Web Client
  http://arduino.cc/en/Tutorial/WiFiWebClientRepeating
*/

#include <SPI.h>
#include <WiFi101.h>
#include <avr/wdt.h>

#include "arduino_secrets.h"
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

// Initialize the WiFi client library
WiFiClient client;

// server address:
char server[] = SECRET_SERVER;

unsigned long lastConnectionTime = 0;            // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 1L * 1000L; // delay between updates, in milliseconds

#define O 4 // control signal output pin
#define SHORT 390 -20 // target - adjustment us
#define LONG  990 -10 // target - adjustment us
#define INTER 9930 -1000 // us
#define NUM 5 // repeat the same command

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete

String on    = "0001010100010101010101110";
String off   = "0001010100010101010101000";

void short_out() {
  digitalWrite(O, HIGH);
  delayMicroseconds(SHORT);
  digitalWrite(O, LOW);
  delayMicroseconds(LONG);
}

void long_out() {
  digitalWrite(O, HIGH);
  delayMicroseconds(LONG);
  digitalWrite(O, LOW);
  delayMicroseconds(SHORT);
}

void modulate_out(String s) {
  int l = s.length();
  //Serial.println(l);
  int i, j;
  short_out();
  for (j = 0; j < NUM; j++) {
    delayMicroseconds(INTER);
    for (i = 0; i < l; i++) {
      char c = s.charAt(i);
      if (c == '0') {
        short_out();
      }
      else {
        long_out();
      }
    }
  }
}


void setup() {
  wdt_enable (WDTO_8S);  // reset after one second, if no "pat the dog" received

  //Initialize serial and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  pinMode(O, OUTPUT);
  digitalWrite(O, LOW);

  WiFi.setPins(8, 2, A3, -1);
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  int wait = 5;
  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    wdt_reset ();
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 5 seconds for connection:
    delay(5000);
    wait--;
    if (wait == 0) {
      break;
    }
  }
  // you're connected now, so print out the status:
  printWiFiStatus();
}

int countDown = 0;
int checkNF = 0;
int lastCommand = 0;
int thisCommand = 0;

void checkCommand() {
  char c = client.read();
  //Serial.write(c);

  if (checkNF == 1) {
    checkNF = 0;
    if (c == 'n') { // command is on
      thisCommand = 1;
    }
    else if (c == 'f') { // command is off
      thisCommand = 0;
    }
  }
  if (countDown > 0) {
    countDown--;
    if (countDown == 0) {
      //Serial.println("check if it is o");
      if (c == 'o') {
        checkNF = 1;
      }
    }
  }
  if (c == '{') {
    //Serial.println("in JSON");
    countDown = 7;;
  }
}

void sendCommand() {
  Serial.println("command changed");
  Serial.println(thisCommand);

  if (thisCommand == 1) {
    modulate_out(on);
  }
  else {
    modulate_out(off);
  }
}

unsigned long nextOnTime = 0;
unsigned long nextOffTime = 0;
unsigned long currentTime = 0;
void blinkOnOff() {
  if (lastCommand == 1) {
    currentTime = millis();

    if (currentTime > nextOnTime) {
      modulate_out(on);
      nextOffTime = currentTime + 2000;
      nextOnTime = currentTime + 3000;
    }
    if (currentTime > nextOffTime) {
      modulate_out(off);
      nextOffTime = currentTime + 10000;
    }
  }
  else {
    nextOnTime = nextOffTime = 0;
  }
}

void loop() {
  wdt_reset ();

  while (client.available()) {
    checkCommand();
  }

  if (lastCommand != thisCommand) {
    sendCommand();
    lastCommand = thisCommand;
  }
  blinkOnOff();

  // if postingInterval seconds have passed since your last connection,
  // then connect again and send data:
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
  }

}

// this method makes a HTTP connection to the server:
void httpRequest() {
  // close any connection before send a new request.
  // This will free the socket on the WiFi shield
  client.stop();

  // if there's a successful connection:
  if (client.connect(server, 80)) {
    client.println(SECRET_HTTP_GET);
    client.println(SECRET_HTTP_HOST);
    client.println("Connection: close");
    client.println();

    // note the time that the connection was made:
    lastConnectionTime = millis();
  }
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
  }
}


void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}