// JoinerNode - the other half of real Thread commissioning.
//
// This sketch contains NO network credentials. The board discovers a nearby
// Thread network whose Commissioner has admitted our joining passphrase
// (PSKd), runs the MeshCoP DTLS handshake, receives the network credentials
// over the secured session, and attaches. Run CommissionerNode on another
// board first.
//
// The DTLS / EC-JPAKE handshake is computed in software - expect the join
// to take a few seconds after "joining...".

#include <NiusThread.h>

static const char *kPskd = "J01NME";  // must match CommissionerNode

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 3000) {}

  Thread.begin();

  // Start factory-fresh every boot so the example always demonstrates a
  // real join. In a product you would do this only on a "reset" action and
  // otherwise just Thread.start() with the stored credentials.
  Thread.eraseNetwork();

  Serial.print("JoinerNode: joining with PSKd \"");
  Serial.print(kPskd);
  Serial.println("\"...");
  Thread.joinNetwork(kPskd);
}

void loop() {
  static ThreadClass::JoinResult lastResult = ThreadClass::JOIN_IDLE;
  static ThreadClass::Role lastRole = ThreadClass::ROLE_DISABLED;
  static uint32_t retryAtMs = 0;

  Thread.process();

  if (Thread.joinResult() != lastResult) {
    lastResult = Thread.joinResult();
    switch (lastResult) {
      case ThreadClass::JOIN_OK:
        Serial.println("join OK! credentials received and stored.");
        break;
      case ThreadClass::JOIN_FAILED:
        Serial.println("join failed (commissioner not ready yet?) - retrying in 5 s");
        retryAtMs = millis() + 5000;
        break;
      default:
        break;
    }
  }

  if (lastResult == ThreadClass::JOIN_FAILED && retryAtMs != 0 && millis() >= retryAtMs) {
    retryAtMs = 0;
    Thread.joinNetwork(kPskd);
  }

  if (Thread.role() != lastRole) {
    lastRole = Thread.role();
    Serial.print("role -> ");
    Serial.print(Thread.roleString());
    Serial.print("  rloc16=0x");
    Serial.println(Thread.rloc16(), HEX);
  }
}
