// ThreadCli - the full OpenThread command line on the serial monitor.
//
// Everything the official `ot-cli-ftd` can do, over USB serial: inspect and
// drive the stack interactively. Open the serial monitor at 115200 with
// "Newline" line ending and try:
//
//   state                    -> leader / router / child / detached
//   dataset active           -> the network credentials in use
//   ipaddr                   -> this node's IPv6 addresses
//   neighbor table           -> who we hear directly
//   ping ff03::1             -> ping every node in the mesh
//   udp / coap / scan / help -> there is a lot more
//
// The sketch pre-configures the same demo network as the other examples, so
// boards running FormNetwork / UdpBroadcast / CoapLamp will appear as
// neighbors. Comment out the setNetwork()/start() lines to drive
// commissioning entirely from the CLI (`dataset init new`, `ifconfig up`,
// `thread start`).
//
// Note: some nRF52840 clones occasionally replay stale bytes on the USB
// serial RX path right after a command (you may see a spurious
// "Error 35: InvalidCommand" line). The input filter below drops binary
// noise; if a command gets garbled, just send it again.

#include <NiusThread.h>

#include <stdarg.h>
#include <stdio.h>

extern "C" {
#include <openthread/cli.h>
}

static const uint8_t kNetworkKey[16] = {
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
};

// OpenThread CLI output -> Serial.
static int cliOutput(void *aContext, const char *aFormat, va_list aArguments) {
  (void)aContext;
  char buf[256];
  int  len = vsnprintf(buf, sizeof(buf), aFormat, aArguments);
  if (len > 0) {
    Serial.write(buf, min((size_t)len, sizeof(buf) - 1));
  }
  return len;
}

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

  Thread.begin();
  Thread.setNetwork("ArduinoNRF", 11, 0xBEEF, kNetworkKey);
  Thread.start();

  otCliInit(Thread.instance(), cliOutput, NULL);

  Serial.println();
  Serial.println("OpenThread CLI ready - type 'help' for commands, 'state' for the role.");
  Serial.print("> ");
}

void loop() {
  static char   line[256];
  static size_t fill = 0;

  Thread.process();

  while (Serial.available()) {
    char c = (char)Serial.read();

    if (c == '\r' || c == '\n') {
      if (fill > 0) {
        Serial.println();          // echo the line break
        line[fill] = '\0';
        otCliInputLine(line);      // hand the command to OpenThread
        fill = 0;
      }
      Serial.print("> ");
    } else if (c == 0x7F || c == 0x08) {  // backspace
      if (fill > 0) {
        fill--;
        Serial.print("\b \b");
      }
    } else if (c >= 0x20 && c < 0x7F && fill < sizeof(line) - 1) {
      // printable ASCII only - drops the binary noise some clone USB
      // serial paths replay after a command
      line[fill++] = c;
      Serial.print(c);             // echo
    }
  }
}
