295abb37ee
Firmware for an autonomous wave-measurement buoy (ATmega2560-based WII5 v2 board). Reads wave motion from a Sparton AHRS-M1/M2 IMU, samples GPS and battery state, and reports back over Iridium SBD satellite telemetry. Originally developed 2012-2024. This is the first public release. Code, documentation, and field-tested operating modes (Capture, Sleep, Position, ManualTest, SelfTest, LowBattery) are licensed under Apache 2.0 — see LICENSE and NOTICE. See README.md for an overview and build instructions, CONTRIBUTING.md for how to contribute, and DEPLOYMENTS.md for the field-deployment log.
1505 lines
52 KiB
C++
1505 lines
52 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (c) 2012-2024 Scott Penrose <scottp@dd.com.au> and WII5 Buoy contributors
|
|
//
|
|
// This file is part of WII5 Buoy firmware.
|
|
// See LICENSE for full terms.
|
|
|
|
/**
|
|
* @file WII5Commands.cpp
|
|
* @brief Command protocol handler: parses and dispatches @-prefixed commands.
|
|
*/
|
|
|
|
/*
|
|
|
|
WII5Commands - Main ability to control the wave buoy
|
|
|
|
Command Inputs
|
|
|
|
* Hardware Buttons
|
|
Use Sh3dNodeIO -> processCmd
|
|
|
|
* Serial Console
|
|
Use console.available -> processConsole
|
|
|
|
* Radio
|
|
Use Sh3dNodeNetwork.available -> processCmd
|
|
|
|
* Iridium
|
|
Use TODO (not sure yet, now this works out we have waiting Iridium Messges)
|
|
Maybe just wii5Iridium.available and next?
|
|
|
|
Naming Convensions here:
|
|
|
|
* begin - called once, as usual
|
|
* loop, loop* - Get direct acccess to hardware, such as a serial port or radio
|
|
* process* - Do something with some data we already have
|
|
* parse* - Calculate some data from probably some raw strings
|
|
|
|
Flow of Data: Serial
|
|
|
|
wii5Commands.loop()
|
|
console.loop - Basic read serial port
|
|
console.processCmd - Calculate string, and CSV output
|
|
console.available - got something
|
|
-> wii5Commands.processConsole
|
|
Got "@"
|
|
-> wii5Commands.processConsoleCsv
|
|
|
|
|
|
*/
|
|
|
|
#include <Arduino.h>
|
|
#include <TimeLib.h>
|
|
#include <WII5.h>
|
|
#include <WII5Commands.h>
|
|
#include <WII5Strings.h>
|
|
#include <MemoryFree.h>
|
|
|
|
void WII5Commands::begin() {
|
|
disableButtons = 600000;
|
|
}
|
|
|
|
/*
|
|
|
|
injectCommand - literally inject a plain text command and process it
|
|
|
|
Injecting a command can look like this:
|
|
@WII5,setting,captureoptions,90,16400,40960
|
|
1234567890123456789012345678901234567890123
|
|
1 2 3 4
|
|
44 bytes - with overheads, could be over the 50
|
|
|
|
4 bytes - command - @WII5,setting,captureoptions
|
|
2 bytes - Minutes = 1440 (2 bytes) maximum
|
|
4 bytes - Binary data
|
|
2 bytes (maybe 4) - rows
|
|
12 bytes
|
|
|
|
*/
|
|
bool WII5Commands::injectCommand(char *sendCmd) {
|
|
console.log(LOG_INFO, F("Command Inject: %s"), sendCmd);
|
|
console.clearCommand();
|
|
// Send prefix @WII5,
|
|
console.processCmd('@');
|
|
console.processCmd('W');
|
|
console.processCmd('I');
|
|
console.processCmd('I');
|
|
console.processCmd('5');
|
|
console.processCmd(',');
|
|
// Send received command
|
|
for (uint16_t k = 0; k < strlen(sendCmd); k++) {
|
|
char myChar = sendCmd[k];
|
|
console.processCmd(myChar);
|
|
}
|
|
console.processCmd('\r');
|
|
console.processCmd('\n');
|
|
// Proess command now
|
|
return true;
|
|
}
|
|
|
|
bool WII5Commands::processBinData() {
|
|
// TODO hard coded?
|
|
/*
|
|
WII5_BINDATA_3* command = wii5BinData.getCommand(wii5BinaryIridium, 340);
|
|
if (command) {
|
|
console.log(LOG_ERROR, F("processBinData injecting BinData message - %s"), command->message);
|
|
injectCommand(command->message);
|
|
}
|
|
else
|
|
*/
|
|
if (strncmp_P(wii5BinaryIridium, (PGM_P) F("@WII5,"), 6) == 0) {
|
|
console.log(LOG_ERROR, F("processBinData original (wii5) - %s"), (char*)wii5BinaryIridium);
|
|
console.log(LOG_ERROR, F("processBinData injecting Text message (wii5) - %s"), (char*)wii5BinaryIridium + 6);
|
|
injectCommand((char*)wii5BinaryIridium + 6);
|
|
}
|
|
// TODO 2024 - Is this used - consider commenting out
|
|
else if (strncmp_P(wii5BinaryIridium, (PGM_P) F("@Maths,"), 7) == 0) {
|
|
// TODO: Area should have maths
|
|
setupLast(WII5DEVICE_UNKNOWN, WII5PORT_CONSOLE, WII5AREA_WII5, WII5COMMAND_NONE);
|
|
console.log(LOG_ERROR, F("processBinData original (maths) - %s"), (char*)wii5BinaryIridium);
|
|
console.log(LOG_ERROR, F("processBinData injecting Text message (maths) - %s"), (char*)wii5BinaryIridium + 7);
|
|
if (wii5Maths.queueCommand((char*)wii5BinaryIridium + 7, strlen(wii5BinaryIridium+7))) {
|
|
// Successfully queued message (max 2)
|
|
resultLast(WII5RESULTS_SUCCESS, F("MathsQueueSuccess"));
|
|
}
|
|
else {
|
|
// Failed to queue - report
|
|
resultLast(WII5RESULTS_INVALID, F("MathsQuueFailed"));
|
|
}
|
|
return true;
|
|
}
|
|
else {
|
|
console.log(LOG_ERROR, F("processBinData failed - no Command found in packet"));
|
|
return false;
|
|
}
|
|
|
|
// Command injected - time to process it
|
|
setupLast(WII5DEVICE_UNKNOWN, WII5PORT_CONSOLE, WII5AREA_WII5, WII5COMMAND_NONE);
|
|
if (processConsoleAT()) {
|
|
console.log(LOG_INFO, F("Command Inject: SUCCESS"));
|
|
// if ( (lastCommandCmd != WII5COMMAND_NONE) && (lastCommandResult != WII5RESULT_UNKNWON) ) {
|
|
// lastCommandResult = result;
|
|
// strncpy_P(lastCommandMessage, message, sizeof(lastCommandMessage));
|
|
return true;
|
|
}
|
|
else {
|
|
console.log(LOG_INFO, F("Command Inject: FAILED/NOT EXIST"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool WII5Commands::processNetwork() {
|
|
#ifdef WII5_RADIO_LORA
|
|
if (sh3dNodeNetwork.lastValid) {
|
|
switch(int(sh3dNodeNetwork.lastPacketType)) {
|
|
case SH3D_NODE_Packet_ConsoleReceive_packetType:
|
|
console.printf(F("# REMOTE RECEIVE: Level=%d"), sh3dNodeNetwork.localConsoleReceive->level);
|
|
console.printf(F(" message=%s"), sh3dNodeNetwork.localConsoleReceive->buf);
|
|
console.printNewLine();
|
|
// TODO setup last and runCommand
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
};
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
// NOTE: Be careful this doesn't do much with the buttons, just inject into Console or similar
|
|
bool WII5Commands::processButtons() {
|
|
/* New option for keeping maths on? */
|
|
if (sh3dNodeIO.button2->isClicked()) {
|
|
console.log(LOG_INFO, F("Button2: clicked - turning on Maths CPU, hold 1h, return line on"));
|
|
// Turn on Maths. Hold maths on 1 hour. Set return line (force Maths to stay on)
|
|
wii5Maths.start(WII5MATHSMODE_BUTTON);
|
|
wii5Maths.setHold(3600);
|
|
wii5Maths.setReturnLine();
|
|
}
|
|
if (sh3dNodeIO.button2->isReleased()) {
|
|
console.log(LOG_INFO, F("Button2: released - turning off return line"));
|
|
wii5Maths.cancelReturnLine();
|
|
}
|
|
|
|
if (disableButtons < 30000) {
|
|
return false;
|
|
}
|
|
|
|
// Button still held for 10 minutes - disable it
|
|
else if (buttonActive && (buttonHeld > 600000)) {
|
|
buttonActive = false;
|
|
buttonReleased = false;
|
|
}
|
|
|
|
// Button released times up
|
|
else if (buttonReleased && (buttonReleaseWait > 500)) {
|
|
if (buttonHeld < WII5_BUTTON_HOLD_TIME) {
|
|
console.log(LOG_DEBUG, F("Button1: was held for < 5 seconds"));
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("Button1: Released, switching mode"));
|
|
|
|
// Set default mode - set in config before.
|
|
wii5Controller.setDefaultMode();
|
|
|
|
// Optional - reboot
|
|
}
|
|
buttonActive = false;
|
|
buttonReleased = false;
|
|
buttonMode = 0;
|
|
}
|
|
|
|
// OUT: Two Beeps - tell you we detected it...
|
|
else if (sh3dNodeIO.button1->isClicked()) {
|
|
console.log(LOG_INFO, F("Button1: clicked"));
|
|
if (!buttonActive) {
|
|
buttonHeld = 0;
|
|
buttonActive = true;
|
|
buttonMode = 0;
|
|
console.log(LOG_DEBUG, F("Button1: pressed - hold for 10 seconds to get current mode"));
|
|
}
|
|
buttonReleased = false;
|
|
}
|
|
|
|
// RELEASE = Actiate what we just set
|
|
else if (sh3dNodeIO.button1->isReleased()) {
|
|
console.log(LOG_INFO, F("Button1: released"));
|
|
// We are in active state - wait
|
|
if (buttonActive) {
|
|
buttonReleaseWait = 0;
|
|
buttonReleased = true;
|
|
}
|
|
}
|
|
|
|
// Still held down, count the time
|
|
// TODO 2024 - Simplify this for WII5 2024
|
|
if (buttonActive) {
|
|
wii5Controller.shared5On();
|
|
// TODO if buttonActive for more then 5 mins. Disable button !
|
|
|
|
/*
|
|
|
|
0..4999 = Do nothing
|
|
> 5000 = Inc counter & show mode
|
|
> 10000 = Inc counter &
|
|
|
|
*/
|
|
if (buttonHeld > (uint32_t)((uint32_t)((uint32_t)buttonMode * (uint32_t)WII5_BUTTON_HOLD_TIME) + (uint32_t)WII5_BUTTON_HOLD_TIME)) {
|
|
buttonMode++;
|
|
|
|
switch(buttonMode) {
|
|
// Report Status
|
|
case 1:
|
|
wii5Maths.start(WII5MATHSMODE_BUTTON);
|
|
wii5Maths.setHold(900);
|
|
if (wii5Config.getDefaultMode() == WII5MODE_CAPTURE) {
|
|
// Capture = 3 beeps
|
|
sh3dNodeIO.led2Set(LED_TRIPPLE_LONG);
|
|
}
|
|
else {
|
|
// Sleep = 2 beeps
|
|
sh3dNodeIO.led2Set(LED_DOUBLE_LONG);
|
|
}
|
|
console.log(LOG_INFO, F("Button1: held - 2 = sleep, 3 = capturue, hold 10 seconds to troggle"));
|
|
break;
|
|
|
|
// Toggle Mode - then toggle back again if a mistake
|
|
case 2:
|
|
case 3:
|
|
wii5Maths.start(WII5MATHSMODE_BUTTON);
|
|
wii5Maths.setHold(900);
|
|
// NOTE: Onl default mode for now
|
|
if (wii5Config.getDefaultMode() == WII5MODE_CAPTURE) {
|
|
console.log(LOG_INFO, F("Button1: Swap - moving from to Sleep mode - please release button, buttonMode=%d"), buttonMode);
|
|
wii5Config.setDefaultMode(WII5MODE_SLEEP);
|
|
sh3dNodeIO.led2Set(LED_DOUBLE_LONG);
|
|
}
|
|
else {
|
|
console.log(LOG_INFO, F("Button1: Swap - moving from to Capture mode - please release button, buttonMode=%d"), buttonMode);
|
|
wii5Config.setDefaultMode(WII5MODE_CAPTURE);
|
|
sh3dNodeIO.led2Set(LED_TRIPPLE_LONG);
|
|
}
|
|
break;
|
|
case 4:
|
|
console.log(LOG_INFO, F("Button1: Shutdown stage - reseting in 5 seconds"));
|
|
wii5Setup.shutdownbeep();
|
|
wii5Maths.setHold(0);
|
|
wii5Maths.powerOff(true);
|
|
wii5Maths.stop();
|
|
|
|
// Force pins output low
|
|
pinMode(SHARED_5VOLT_PIN, OUTPUT);
|
|
digitalWrite(SHARED_5VOLT_PIN, LOW);
|
|
pinMode(POWER_MATHS_PIN, OUTPUT);
|
|
digitalWrite(POWER_MATHS_PIN, LOW);
|
|
|
|
wii5Config.resetConfigData();
|
|
|
|
// Wait for Pi shutdown 5 seconds, then reset us
|
|
wii5Controller.safeDelay(5000);
|
|
|
|
// TODO - how to stop this recurring forever if button fails on. Write to EEPROM
|
|
sh3dNodeUtil.reset();
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
else {
|
|
console.log(LOG_ERROR, F("buttonMode=%d, HOLD_TIME=%d, Held=%d"), buttonMode, WII5_BUTTON_HOLD_TIME, butonHeld)
|
|
if (buttonHeld > ((buttonMode * WII5_BUTTON_HOLD_TIME) + WII5_BUTTON_HOLD_TIME)) {
|
|
|
|
}
|
|
*/
|
|
}
|
|
|
|
#if BUTTON_3>0
|
|
if (sh3dNodeIO.button3->isClicked()) {
|
|
wii5Maths.gpioClick();
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
// setupLast - Need this before runCommand - e.g. if from Console vs Iridium
|
|
bool WII5Commands::runCommand(WII5_COMMANDS cmd, char** params, uint8_t paramsLen) {
|
|
setupLast(WII5DEVICE_UNKNOWN, WII5PORT_CONSOLE, WII5AREA_WII5, cmd);
|
|
// TODO returnLast
|
|
|
|
switch(cmd) {
|
|
case WII5COMMAND_NONE:
|
|
console.log(LOG_INFO, F("ERROR: @WII5 command, no match"));
|
|
return false;
|
|
break;
|
|
|
|
case WII5COMMAND_NA:
|
|
// Handled by another module... move along.
|
|
break;
|
|
|
|
case WII5COMMAND_HELP:
|
|
console.log(LOG_INFO, F("HELP: replaced with @Help"));
|
|
break;
|
|
|
|
case WII5COMMAND_ECHO:
|
|
// TODO reply with everythng after echo - up to X chars
|
|
break;
|
|
|
|
case WII5COMMAND_PEOPLE:
|
|
// TODO: reply with everything after echo - up to X chars
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - people"));
|
|
resultLast(WII5RESULTS_NOREPLY, F("Scott Penrose <scottp@dd.com.au>"));
|
|
resultLast(WII5RESULTS_NOREPLY, F("WII5 Buoy firmware contributors"));
|
|
switch(console.getCsvVal(3)) {
|
|
case 0:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// HELLO Received - we need to send an ACK
|
|
case WII5COMMAND_HELLO:
|
|
// @WII5,hello,SourcePort,SourceDeviceType,SourceDeviceID,SourceSoftwareVersion
|
|
// @WII5,hello!,MyPort,MyDeviceType,MyDeviceID,MySoftwareVersion
|
|
// @WII5,hello,Console,Maths,100001,1
|
|
// NOTE: Device ID should be same both ends for Maths etc
|
|
console.log(LOG_DEBUG, F("Hello - port=%s, device=%s"),
|
|
console.getCsvBuffer(2),
|
|
console.getCsvBuffer(3)
|
|
);
|
|
|
|
wii5Maths.woops_on();
|
|
wii5Controller.setLastHello(
|
|
wii5Strings.parsePort(console.getCsvBuffer(2)),
|
|
wii5Strings.parseDevice(console.getCsvBuffer(3))
|
|
);
|
|
|
|
wii5Display.atCommandSend(F("hello!"), F("%S,%S,port=%S,device=%S,id=%lu,version=%S,board=%S,commit=%S,freeMemory=%d/%d"),
|
|
// Old way
|
|
F("console"),
|
|
F("wavebuoy"), // WII5_DEVICE_TYPE),
|
|
// New way
|
|
// 2 - port
|
|
F("console"),
|
|
// 3 - device
|
|
F("wavebuoy"), // WII5_DEVICE_TYPE),
|
|
// 4 - id
|
|
wii5Config.getDeviceId(),
|
|
// 5 - version
|
|
F(WII5_SOFTWARE_VERSION),
|
|
// 6 - Board
|
|
F(WII5_BOARD_NAME),
|
|
// 7 - Commit
|
|
F(WII5_SOFTWARE_COMMIT),
|
|
// TODO too long
|
|
// 8 - Free Memory / Max
|
|
freeMemory(), WII5_BOARD_MEMORY
|
|
/*
|
|
// 9 - Uptime
|
|
(uint32_t)(millis() / 60000),
|
|
// 10 - Current storage Record
|
|
wii5Config.getRecordCount(),
|
|
// 11 - mode
|
|
wii5Strings.strMode(wii5Controller.getMode())
|
|
*/
|
|
);
|
|
|
|
// Send DateTime if it is up to date and valid (we should also support RTC)
|
|
if (wii5Gps.isTimeValid()) {
|
|
console.log(LOG_DEBUG, F("Sending time - valid from GPS"));
|
|
wii5Display.atCommandSend(F("time"), F("%04d,%02d,%02d,%02d,%02d,%02d"),
|
|
int(year()), int(month()), int(day()),
|
|
int(hour()), int(minute()), int(second())
|
|
);
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("Not sending time - not valid from GPS"));
|
|
}
|
|
|
|
// Send statusDump - useful information (short version)
|
|
wii5Controller.statusDump();
|
|
break;
|
|
|
|
case WII5COMMAND_HELLOACK:
|
|
console.log(LOG_DEBUG, F("COMMAND: hello Ack - Not implemented"));
|
|
wii5Maths.woops_on();
|
|
wii5Controller.setLastHello(
|
|
wii5Strings.parsePort(console.getCsvBuffer(2)),
|
|
wii5Strings.parseDevice(console.getCsvBuffer(3))
|
|
);
|
|
|
|
/*
|
|
console.printf(F("@WII5,hello!,Console,%S,%lu,%S"),
|
|
F(WII5_DEVICE_TYPE),
|
|
wii5Config.getDeviceId(),
|
|
F(WII5_SOFTWARE_VERSION)
|
|
);
|
|
*/
|
|
|
|
break;
|
|
|
|
|
|
// Sleep 30 seconds, loop 20 seconds - check we are basic WDT
|
|
case WII5COMMAND_WAITY:
|
|
console.log(LOG_FATAL, F("Sleep 30 seconds, then loop 20 using safe loop"));
|
|
wii5Setup.sleepBefore();
|
|
sh3dNodeUtil.sleep(30);
|
|
wii5Setup.sleepAfter();
|
|
for (uint8_t n = 0; n < 20; n++) {
|
|
console.log(LOG_FATAL, F("Safe Loop %d / 20"), n);
|
|
wii5Controller.safeDelay(1000);
|
|
}
|
|
// NOTE: No break, now do loop
|
|
|
|
// Unsafe loop 20 seconds - good for internal WDT testing
|
|
case WII5COMMAND_WAITX:
|
|
console.log(LOG_FATAL, F("ABOUT To loop (no other loops for 20 seconds)"));
|
|
for (uint8_t n = 0; n < 20; n++) {
|
|
console.log(LOG_FATAL, F("UNSAFE Loop %d"), n);
|
|
delay(1000);
|
|
}
|
|
console.log(LOG_FATAL, F("End of the 20 second loop"));
|
|
break;
|
|
|
|
// Unsafe 5 minutes - should cause external WDT reset
|
|
case WII5COMMAND_WAITZ:
|
|
console.log(LOG_FATAL, F("ABOUT To loop (no other loops for 300 seconds)"));
|
|
for (uint16_t n = 0; n < 300; n++) {
|
|
console.log(LOG_FATAL, F("UNSAFE Loop %d"), n);
|
|
delay(1000);
|
|
}
|
|
console.log(LOG_FATAL, F("End of the 300 second loop"));
|
|
break;
|
|
|
|
// Safe 5 minutes - Should not cause external WDT reset
|
|
case WII5COMMAND_WAITQ:
|
|
console.log(LOG_FATAL, F("ABOUT To loop (safe delay 300 seconds)"));
|
|
for (uint16_t n = 0; n < 300; n++) {
|
|
console.log(LOG_FATAL, F("Safe Loop %d"), n);
|
|
wii5Controller.safeDelay(1000);
|
|
}
|
|
console.log(LOG_FATAL, F("End of the 300 second loop"));
|
|
break;
|
|
|
|
// Sleep 5 miniutes - should not cause external WDT reset
|
|
case WII5COMMAND_WAITS:
|
|
console.log(LOG_FATAL, F("ABOUT To Sleep for 300 seconds to check WDT"));
|
|
wii5Setup.sleepBefore();
|
|
sh3dNodeUtil.sleep(300);
|
|
wii5Setup.sleepAfter();
|
|
console.log(LOG_FATAL, F("End of the 300 second sleep"));
|
|
break;
|
|
|
|
case WII5COMMAND_STATUS:
|
|
// TODO be nice to return status
|
|
// TODO move to dipslay ?
|
|
console.log(LOG_DEBUG, F("COMMAND: Status"));
|
|
wii5Controller.statusDump(true);
|
|
break;
|
|
|
|
case WII5COMMAND_LOG_DEBUG:
|
|
console.log(LOG_INFO, F("LOG: Level set to DEBUG - test with @WII5,log,test"));
|
|
console.setLevel(LOG_ALL);
|
|
break;
|
|
|
|
case WII5COMMAND_LOG_DEFAULT:
|
|
console.log(LOG_INFO, F("LOG: Level set to INFO - test with @WII5,log,test"));
|
|
console.setLevel(LOG_INFO);
|
|
break;
|
|
|
|
case WII5COMMAND_LOG_FATAL:
|
|
console.log(LOG_INFO, F("LOG: Level set to FATAL - test with @WII5,log,test"));
|
|
console.setLevel(LOG_INFO);
|
|
break;
|
|
|
|
case WII5COMMAND_LOG_ERROR:
|
|
console.log(LOG_INFO, F("LOG: Level set to ERROR - test with @WII5,log,test"));
|
|
console.setLevel(LOG_ERROR);
|
|
break;
|
|
|
|
case WII5COMMAND_LOG_TEST:
|
|
console.printf(F("# Log Level Fatal, Error, Warn, Info, Debug"));
|
|
console.log(LOG_FATAL, F("Using FATAL millis=%d"), millis());
|
|
console.log(LOG_ERROR, F("Using ERROR millis=%d"), millis());
|
|
console.log(LOG_WARN, F("Using WARN millis=%d"), millis());
|
|
console.log(LOG_INFO, F("Using INFO millis=%d"), millis());
|
|
console.log(LOG_DEBUG, F("Using DEBUG millis=%d"), millis());
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_STATUS:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - SD Status"));
|
|
console.log(LOG_INFO, F("Storage: Current = %d"), wii5Controller.getSD());
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_DEBUG:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply Storage Debug"));
|
|
sdBlock.debug = (console.getCsvVal(3) > 0) ? true : false;
|
|
console.log(LOG_INFO, F("Storage: Debug = %d"), int(sdBlock.debug));
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_SETSTATUS:
|
|
if (sdBlock.metadataUpdateStatus( // metadataBlock, mainRecordCount, 1);
|
|
console.getCsvVal(3), console.getCsvVal(4), console.getCsvVal(5)
|
|
)
|
|
) {
|
|
console.log(LOG_INFO, F("Storage: Status Field updated %lu,%lu,%lu"), console.getCsvVal(3), console.getCsvVal(4), console.getCsvVal(5));
|
|
resultLast(WII5RESULTS_SUCCESS, F("StatusUpdated"));
|
|
}
|
|
else {
|
|
console.log(LOG_INFO, F("Storage: Status Field updated %lu,%lu,%lu"), console.getCsvVal(3), console.getCsvVal(4), console.getCsvVal(5));
|
|
resultLast(WII5RESULTS_ERROR, F("StatusFailed"));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_OFF:
|
|
resultLast(WII5RESULTS_SUCCESS, F("SD Off"));
|
|
console.log(LOG_INFO, F("SD: off"));
|
|
wii5Controller.setSDOff();
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_SD1:
|
|
wii5Controller.setSD1();
|
|
if (sdBlock.cardOpen(wii5Controller.getSD())) {
|
|
resultLast(WII5RESULTS_SUCCESS, F("SD 1 Open"));
|
|
console.log(LOG_INFO, F("SD: 1 - cardOpen - ON and Success"));
|
|
}
|
|
else {
|
|
resultLast(WII5RESULTS_ERROR, F("SD 1 Open"));
|
|
console.log(LOG_INFO, F("SD: 1 - cardOpen - Failure"));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_SD2:
|
|
wii5Controller.setSD2();
|
|
if (sdBlock.cardOpen(wii5Controller.getSD())) {
|
|
resultLast(WII5RESULTS_SUCCESS, F("SD 2 Open"));
|
|
console.log(LOG_INFO, F("SD: 2 - cardOpen - ON and Success"));
|
|
}
|
|
else {
|
|
resultLast(WII5RESULTS_ERROR, F("SD 2 Open"));
|
|
console.log(LOG_INFO, F("SD: 2 - cardOpen - Failure"));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_LIST:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - StorageList"));
|
|
sdBlock.metadataList(
|
|
console.getCsvVal(3),
|
|
console.getCsvVal(4) > 0 ? console.getCsvVal(4) : 20
|
|
);
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_VIEW:
|
|
case WII5COMMAND_STORAGE_METADATA:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - Storage View"));
|
|
wii5Display.sdBlockView(console.getCsvVal(3), false, false);
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_RESULTS:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - Storage Results"));
|
|
wii5Display.sdBlockView(console.getCsvVal(3), true, false);
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_RAW:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - Storage Raw"));
|
|
wii5Display.sdBlockView(console.getCsvVal(3), true, true);
|
|
break;
|
|
|
|
case WII5COMMAND_STORAGE_FORMAT:
|
|
if (wii5Controller.getSD() != 0) {
|
|
console.log(LOG_ERROR, F("SD Card is still active, and format may effect running capture or maths processing"));
|
|
}
|
|
|
|
if (console.getCsvVal(3) == 1) {
|
|
wii5Controller.setSD1();
|
|
}
|
|
else if (console.getCsvVal(3) == 2) {
|
|
wii5Controller.setSD2();
|
|
}
|
|
else {
|
|
// FAIL - do not continue
|
|
resultLast(WII5RESULTS_INVALID, F("SD Format: SD Invalid")); // TODO get new size
|
|
return true;
|
|
}
|
|
|
|
if (sdBlock.cardOpen(wii5Controller.getSD(), true)) {
|
|
console.log(LOG_DEBUG, F("SD: %d - cardFormat - Open"), wii5Controller.getSD());
|
|
if (sdBlock.cardClose()) {
|
|
console.log(LOG_DEBUG, F("SD: %d - cardFormat - Complete"), wii5Controller.getSD());
|
|
if (console.getCsvVal(3) == 1)
|
|
resultLast(WII5RESULTS_SUCCESS, F("SD format: 1 Complete")); // TODO get new size
|
|
else
|
|
resultLast(WII5RESULTS_SUCCESS, F("SD format: 2 Complete")); // TODO get new size
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("SD: %d - cardFormat - Failed format"), wii5Controller.getSD());
|
|
if (console.getCsvVal(3) == 1)
|
|
resultLast(WII5RESULTS_ERROR, F("SD Format Failed 1")); // TODO get new size
|
|
else
|
|
resultLast(WII5RESULTS_ERROR, F("SD Format Failed 2")); // TODO get new size
|
|
}
|
|
}
|
|
break;
|
|
|
|
// @WII5,setting,time,1988,01,28,01,02,03
|
|
case WII5COMMAND_SETTING_TIME:
|
|
when = now();
|
|
setTime(
|
|
int(console.getCsvVal(6)), int(console.getCsvVal(7)), int(console.getCsvVal(8)),
|
|
int(console.getCsvVal(5)), int(console.getCsvVal(4)), int(console.getCsvVal(3))
|
|
);
|
|
|
|
// Ignore anything less than 1 second (is there a way to do before setTime) (10 secconds)
|
|
// TODO configurable... 10 seconds safe?
|
|
// TODO abs - does it work with long
|
|
if ( ( (now() - when) > 10 ) || ( when - now() > 10) ) {
|
|
console.log(LOG_INFO, F("COMMAND: setTime RECEIVED = %04d-%02d-%02dT%02d:%02d:%02d - updating local and RTC"),
|
|
int(console.getCsvVal(3)), int(console.getCsvVal(4)), int(console.getCsvVal(5)),
|
|
int(console.getCsvVal(6)), int(console.getCsvVal(7)), int(console.getCsvVal(8))
|
|
);
|
|
#ifdef WII5_RTC
|
|
wii5RTC.setRTC(now());
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_LIST:
|
|
wii5Config.dump(true, NULL);
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_DEVICEID:
|
|
// TODO Move to function here for settings or bertter, to Config
|
|
console.log(LOG_INFO, F("COMMAND: Setting DeviceID = %lu"), console.getCsvVal(3));
|
|
// Limits - 10000 - 99999
|
|
if (console.getCsvVal(3) == 0) {
|
|
console.log(LOG_INFO, F("Support services"));
|
|
resultLast(WII5RESULTS_INVALID, F("ID: No ID"));
|
|
}
|
|
else if (
|
|
(console.getCsvVal(3) < 10000)
|
|
|| (console.getCsvVal(3) > 99999)
|
|
) {
|
|
console.log(LOG_ERROR, F("Unable to set DeviceID to '%lu' should be between 10000 - 99999"), console.getCsvVal(3));
|
|
resultLast(WII5RESULTS_INVALID, F("ID: Bad ID"));
|
|
}
|
|
else {
|
|
wii5Config.setDeviceId(console.getCsvVal(3));
|
|
lastCommandResult = WII5RESULTS_SUCCESS;
|
|
snprintf_P(
|
|
lastCommandMessage, sizeof(lastCommandMessage),
|
|
PSTR("ID: set=%lu"),
|
|
wii5Config.getDeviceId()
|
|
);
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_GPSTIMEOUT:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply - gpstimeout")); // TODO Maybe?
|
|
console.log(LOG_INFO, F("COMMAND: Setting GPSTimeout = %lu"), console.getCsvVal(3));
|
|
if (console.getCsvVal(3) == 0) {
|
|
console.log(LOG_INFO, F("COMMAND: Existing GPSTimeout = %lu"), console.getCsvVal(3));
|
|
}
|
|
else if (
|
|
(console.getCsvVal(3) < 30)
|
|
|| (console.getCsvVal(3) > 900)
|
|
) {
|
|
console.log(LOG_ERROR, F("COMMAND: Unable to set GPSTimeouta"));
|
|
}
|
|
else {
|
|
wii5Config.setGpsTimeout(console.getCsvVal(3));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_DEFAULTS:
|
|
console.log(LOG_INFO, F("COMMAND: Setting config back to defaults"));
|
|
if (console.getCsvVal(3) == 3759) {
|
|
console.log(LOG_INFO, F("COMMAND: reset counters = %lu"), console.getCsvVal(3));
|
|
wii5Config.resetCounters();
|
|
resultLast(WII5RESULTS_SUCCESS, F("CountersReset")); // TODO Maybe?
|
|
}
|
|
else {
|
|
// Reset Config Defaults... Then allow override
|
|
wii5Config.resetConfigData();
|
|
wii5Config.resetStatusData();
|
|
wii5Controller.statusDump();
|
|
resultLast(WII5RESULTS_SUCCESS, F("ConfigDefaults")); // TODO Maybe?
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SEND:
|
|
{
|
|
// Send any commands
|
|
// IMPORTANT - do not reply command here !
|
|
// strncpy(wii5Commands.lastCommandMessage, buf, bufSize < 235 ? bufSize, 235);
|
|
memset(wii5Commands.lastCommandMessage, 0, sizeof(wii5Commands.lastCommandMessage));
|
|
char *pos = wii5Commands.lastCommandMessage;
|
|
uint16_t used = 0;
|
|
for (uint8_t i = 2; i < console.getCsvCount(); i++) {
|
|
strncpy(pos, console.getCsvBuffer(i), sizeof(wii5Commands.lastCommandMessage) - used);
|
|
pos += strlen(console.getCsvBuffer(i));
|
|
used += strlen(console.getCsvBuffer(i));
|
|
if (used < sizeof(wii5Commands.lastCommandMessage)) {
|
|
*pos = ',';
|
|
pos++;
|
|
used++;
|
|
}
|
|
}
|
|
wii5Commands.lastCommandMessage[sizeof(wii5Commands.lastCommandMessage) - 1] = '\0';
|
|
console.log(LOG_FATAL, F("SEND Text Received: %s"), wii5Commands.lastCommandMessage);
|
|
wii5Communications.sendText();
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SET:
|
|
// Special case
|
|
// - set,capture,{period},{binary} - And set the default mode
|
|
// - set,sleep,{period},{binary},{until} - And set the default mode
|
|
{
|
|
WII5_MODES newMode;
|
|
newMode = wii5Strings.parseMode(console.getCsvBuffer(2));
|
|
if (newMode == WII5MODE_NONE) {
|
|
console.log(LOG_ERROR, F("COMMAND: Invalid mode '%s'"), console.getCsvBuffer(4));
|
|
resultLast(WII5RESULTS_INVALID, F("InvalidMode"));
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("COMMAND: Parsed mode = %d (%s)"), newMode, wii5Strings.strMode(newMode));
|
|
|
|
switch(newMode) {
|
|
case WII5MODE_SLEEP:
|
|
wii5Config.setSleepPeriod(console.getCsvVal(3));
|
|
wii5Config.setSleepBinaryType(console.getCsvVal(4));
|
|
wii5Config.setDefaultMode(newMode);
|
|
lastCommandResult = WII5RESULTS_SUCCESS;
|
|
snprintf_P(
|
|
lastCommandMessage, sizeof(lastCommandMessage),
|
|
PSTR("M=sleep,P=%lu,D=%lu"),
|
|
wii5Config.getSleepPeriod(), wii5Config.getSleepBinaryType()
|
|
);
|
|
break;
|
|
case WII5MODE_CAPTURE:
|
|
wii5Config.setCapturePeriod(console.getCsvVal(3));
|
|
wii5Config.setCaptureBinaryType(console.getCsvVal(4));
|
|
wii5Config.setCaptureRecords(5120);
|
|
lastCommandResult = WII5RESULTS_SUCCESS;
|
|
wii5Config.setDefaultMode(newMode);
|
|
snprintf_P(
|
|
lastCommandMessage, sizeof(lastCommandMessage),
|
|
PSTR("M=capture,P=%lu,D=%lu"),
|
|
wii5Config.getCapturePeriod(), wii5Config.getCaptureBinaryType()
|
|
);
|
|
break;
|
|
case WII5MODE_POSITION:
|
|
wii5Config.setPositionPeriod(console.getCsvVal(3));
|
|
wii5Config.setPositionBinaryType(console.getCsvVal(4));
|
|
wii5Config.setDefaultMode(newMode);
|
|
lastCommandResult = WII5RESULTS_SUCCESS;
|
|
snprintf_P(
|
|
lastCommandMessage, sizeof(lastCommandMessage),
|
|
PSTR("M=position,P=%lu,D=%lu"),
|
|
wii5Config.getPositionPeriod(), wii5Config.getPositionBinaryType()
|
|
);
|
|
break;
|
|
default:
|
|
resultLast(WII5RESULTS_INVALID, F("Not sleep, position or capture"));
|
|
break;
|
|
};
|
|
console.log(LOG_FATAL, F("Default mode saved, updating current mode to match"));
|
|
wii5Controller.setDefaultMode();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_MODE:
|
|
{
|
|
bool defMode = false;
|
|
time_t expires = 0;
|
|
if (strcmp_P(console.getCsvBuffer(3),(PGM_P) F("default")) == 0) {
|
|
console.log(LOG_INFO, F("COMMAND: Setting MODE=Defalut"));
|
|
defMode = true;
|
|
}
|
|
else {
|
|
console.log(LOG_INFO, F("COMMAND: Setting MODE=Temporary datetime=%s"), console.getCsvBuffer(3));
|
|
defMode = false;
|
|
// TODO Parse valid date time etc
|
|
// TODO Do we have a valid time. Woot !
|
|
// TODO Set expires in... (max 4 weeks?)
|
|
expires = 123;
|
|
}
|
|
|
|
WII5_MODES newMode;
|
|
if (strcmp_P(console.getCsvBuffer(4),(PGM_P) F("swap")) == 0) {
|
|
// NOTE: Onl default mode for now
|
|
if (wii5Config.getDefaultMode() == WII5MODE_CAPTURE) {
|
|
console.log(LOG_INFO, F("COMMAND: Swap - moving from Capture to Sleep mode"));
|
|
newMode = WII5MODE_SLEEP;
|
|
}
|
|
else {
|
|
console.log(LOG_ERROR, F("COMMAND: Swap - moving from to capture mode"));
|
|
newMode = WII5MODE_CAPTURE;
|
|
}
|
|
}
|
|
else {
|
|
newMode = wii5Strings.parseMode(console.getCsvBuffer(4));
|
|
}
|
|
|
|
if (newMode == WII5MODE_NONE) {
|
|
console.log(LOG_ERROR, F("COMMAND: Invalid mode '%s'"), console.getCsvBuffer(4));
|
|
resultLast(WII5RESULTS_INVALID, F("InvalidMode"));
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("COMMAND: Parsed mode = %d (%s)"), newMode, wii5Strings.strMode(newMode));
|
|
|
|
if (defMode) {
|
|
console.log(LOG_INFO, F("Default mode set to = %d (%s)"), newMode, wii5Strings.strMode(newMode));
|
|
wii5Config.setDefaultMode(newMode);
|
|
resultLast(WII5RESULTS_SUCCESS, F("mode=")); // Add new mode
|
|
}
|
|
}
|
|
|
|
// IF mode=capture, optionally set Period and Binary Type
|
|
|
|
// IF mode=position, optionally set Periods and Binary Type
|
|
|
|
// IF mode=sleep???
|
|
console.log(LOG_FATAL, F("Default mode saved, updating current mode to match"));
|
|
wii5Controller.setDefaultMode();
|
|
wii5Maths.setHold(900);
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_BATTERYOPTIONS:
|
|
resultLast(WII5RESULTS_NOREPLY, F("No reply"));
|
|
console.log(LOG_INFO, F("COMMAND: Setting Battery Low=%lu, Mide=%lu"), console.getCsvVal(3), console.getCsvVal(4));
|
|
wii5Config.setBatteryLow(console.getCsvVal(3));
|
|
wii5Config.setBatteryMid(console.getCsvVal(4));
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_DISABLELOWBATTERY:
|
|
console.log(LOG_INFO, F("COMMAND: Setting Disable Low Battery = %lu"), console.getCsvVal(3));
|
|
/*
|
|
if (
|
|
(console.getCsvVal(3) < 10000)
|
|
|| (console.getCsvVal(3) > 99999)
|
|
) {
|
|
console.log(LOG_ERROR, F("Unable to set DeviceID to '%lu' should be between 10000 - 99999"), console.getCsvVal(3));
|
|
}
|
|
else {
|
|
}
|
|
*/
|
|
wii5Config.setDisableLowBattery(console.getCsvVal(3));
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_FLAGS:
|
|
// ALL or ONE
|
|
// wii5Config.setDisableLowBattery(console.getCsvVal(3));
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_CAPTUREOPTIONS:
|
|
console.log(LOG_INFO, F("COMMAND: Setting Capture Options Period=%lu minute, Flags=%lu, Records=%lu"), console.getCsvVal(3), console.getCsvVal(4), console.getCsvVal(5));
|
|
// TODO - do we need limits here too?
|
|
if (
|
|
(console.getCsvVal(3) >= 5) // 15 Minutes TODO 15
|
|
&& (console.getCsvVal(3) <= 720) // to 12 hours
|
|
) {
|
|
wii5Config.setCapturePeriod(console.getCsvVal(3));
|
|
}
|
|
// TODO Else error
|
|
if (console.getCsvVal(4) >= 0) {
|
|
wii5Config.setCaptureBinaryType(console.getCsvVal(4));
|
|
}
|
|
if (console.getCsvVal(5) >= 0) {
|
|
wii5Config.setCaptureRecords(console.getCsvVal(5));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_POSITIONOPTIONS:
|
|
console.log(LOG_INFO, F("COMMAND: Setting Position Options = %lu,%lu"), console.getCsvVal(3), console.getCsvVal(4));
|
|
if (
|
|
(console.getCsvVal(3) >= 3) // 3 Minutes
|
|
&& (console.getCsvVal(3) <= 720) // to 12 hours
|
|
) {
|
|
wii5Config.setPositionPeriod(console.getCsvVal(3));
|
|
}
|
|
if (console.getCsvVal(4) >= 0) {
|
|
wii5Config.setPositionBinaryType(console.getCsvVal(4));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_SETTING_SLEEPOPTIONS:
|
|
console.log(LOG_INFO, F("COMMAND: Setting Sleep Options = %lu,%lu"), console.getCsvVal(3), console.getCsvVal(4));
|
|
if (
|
|
(console.getCsvVal(3) >= 2) // 2 minutes
|
|
&& (console.getCsvVal(3) <= 5760) // 4 days
|
|
) {
|
|
wii5Config.setSleepPeriod(console.getCsvVal(3));
|
|
}
|
|
if (console.getCsvVal(4) >= 0) {
|
|
wii5Config.setSleepBinaryType(console.getCsvVal(4));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_RESET:
|
|
if (console.getCsvVal(2) == 666) {
|
|
console.log(LOG_FATAL, F("COMMAND: Reset..."));
|
|
SerialConsole.flush();
|
|
sh3dNodeUtil.reset();
|
|
}
|
|
else {
|
|
console.log(LOG_FATAL, F("COMMAND: Reset failed.... did you know the code..."));
|
|
}
|
|
break;
|
|
|
|
#ifdef WII5_GPS
|
|
case WII5COMMAND_GPS_START:
|
|
console.log(LOG_INFO, F("GPS: Start"));
|
|
wii5Gps.on();
|
|
break;
|
|
|
|
case WII5COMMAND_GPS_STOP:
|
|
console.log(LOG_INFO, F("GPS: Stop"));
|
|
wii5Gps.off();
|
|
break;
|
|
|
|
case WII5COMMAND_GPS_DUMP:
|
|
console.log(LOG_INFO, F("GPS: Dump"));
|
|
wii5Gps.dump();
|
|
break;
|
|
|
|
case WII5COMMAND_GPS_PASSTHROUGH:
|
|
console.log(LOG_INFO, F("GPS: Passthrough set to %d"), console.getCsvVal(3));
|
|
wii5Gps.setPassthrough(console.getCsvVal(3) ? 1 : 0);
|
|
break;
|
|
case WII5COMMAND_GPS_DEBUG:
|
|
console.log(LOG_INFO, F("GPS: Debug set to %d"), console.getCsvVal(3));
|
|
wii5Gps.setDebug(console.getCsvVal(3) ? 1 : 0);
|
|
break;
|
|
case WII5COMMAND_GPS_TIME:
|
|
console.log(LOG_INFO, F("GPS: autoTime"));
|
|
wii5Gps.autoTime();
|
|
break;
|
|
case WII5COMMAND_GPS_POS:
|
|
console.log(LOG_INFO, F("GPS: autoPos"));
|
|
wii5Gps.autoPos();
|
|
break;
|
|
case WII5COMMAND_GPS_ACCURATE:
|
|
console.log(LOG_INFO, F("GPS: autoAccurate"));
|
|
wii5Gps.autoAccurate();
|
|
break;
|
|
|
|
#endif
|
|
|
|
case WII5COMMAND_SPARTON_MODE:
|
|
//TODO move logic to Sparton
|
|
console.log(LOG_DEBUG, F("COMMAND: SPARTON Mode - Not implemented"));
|
|
break;
|
|
|
|
case WII5COMMAND_SPARTON_DUMP:
|
|
//TODO move logic to Sparton
|
|
console.log(LOG_DEBUG, F("COMMAND: SPARTON Dump - Not implemented"));
|
|
break;
|
|
|
|
case WII5COMMAND_SPARTON_INFO:
|
|
console.log(LOG_DEBUG, F("COMMAND: SPARTON Info"));
|
|
wii5Sparton.info();
|
|
break;
|
|
|
|
case WII5COMMAND_SPARTON_PASSTHROUGH:
|
|
console.log(LOG_INFO, F("Sparton: Passthrough set to %d"), console.getCsvVal(3));
|
|
wii5Sparton.setPassthrough(console.getCsvVal(3) ? 1 : 0);
|
|
break;
|
|
|
|
case WII5COMMAND_SPARTON_DEBUG:
|
|
console.log(LOG_INFO, F("Sparton: Debug set to %d"), console.getCsvVal(3));
|
|
wii5Sparton.setDebug(console.getCsvVal(3) ? 1 : 0);
|
|
break;
|
|
|
|
// TODO @WII5,maths - seems in both directions. That is bad.
|
|
// TODO From Maths, should be @Maths not @WII5 or @WII5Maths or something
|
|
case WII5COMMAND_MATHS_BEEP:
|
|
wii5Maths.woops_on();
|
|
if(strcmp_P(console.getCsvBuffer(3),(PGM_P) F("once")) == 0) {
|
|
console.log(LOG_DEBUG, F("COMMAND: Maths Beep - once"));
|
|
wii5Controller.shared5On();
|
|
sh3dNodeIO.led2Set(LED_ONCE);
|
|
}
|
|
else if(strcmp_P(console.getCsvBuffer(3),(PGM_P) F("quiet")) == 0) {
|
|
// Special case - check the mode
|
|
wii5Controller.shared5On();
|
|
if (! wii5Maths.isMode(WII5MATHSMODE_AUTO)) {
|
|
console.log(LOG_DEBUG, F("COMMAND: Maths Beep - ONCE"));
|
|
sh3dNodeIO.led2Set(LED_ONCE);
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("COMMAND: Maths Beep - NORMAL"));
|
|
sh3dNodeIO.led2Set(LED_SHORT_LONG);
|
|
}
|
|
}
|
|
else {
|
|
console.log(LOG_DEBUG, F("COMMAND: Maths Beep"));
|
|
wii5Controller.shared5On();
|
|
sh3dNodeIO.led2Set(LED_SHORT_LONG);
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_INFO:
|
|
resultLast(WII5RESULTS_SUCCESS, F("Info Queued"));
|
|
wii5Maths.woops_on();
|
|
console.log(LOG_INFO, F("MATHS: Info"));
|
|
wii5Maths.queueCommand("info", 8);
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_BOOTED:
|
|
console.log(LOG_DEBUG, F("MathsBooted - flag for moving on"));
|
|
wii5Maths.woops_on();
|
|
wii5Controller.setLastHello(WII5PORT_CONSOLE, WII5DEVICE_MATHS);
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_RETURN:
|
|
if (console.getCsvVal(3) == 0) {
|
|
console.log(LOG_INFO, F("Maths - RETURN line - OFF"));
|
|
wii5Maths.cancelReturnLine();
|
|
}
|
|
else if (console.getCsvVal(3) == 1) {
|
|
console.log(LOG_INFO, F("Maths - RETURN line - ON"));
|
|
wii5Maths.setReturnLine();
|
|
}
|
|
else {
|
|
console.log(LOG_INFO, F("Maths - RETURN line - Unknown"));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_FLIP:
|
|
console.log(LOG_FATAL, F("COMMAND: Maths Flip (setting maths to hold 1 hour)"));
|
|
wii5Maths.setHold(3600);
|
|
wii5ModeCapture.flip();
|
|
wii5Controller.statusDump();
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_RESTART:
|
|
if(strcmp_P(console.getCsvBuffer(3),(PGM_P) F("start")) == 0) {
|
|
console.log(LOG_INFO, F("MATHS: REBOOT - start"));
|
|
}
|
|
else if(strcmp_P(console.getCsvBuffer(3),(PGM_P) F("stop")) == 0) {
|
|
console.log(LOG_INFO, F("MATHS: REBOOT - stop"));
|
|
}
|
|
else if(strcmp_P(console.getCsvBuffer(3),(PGM_P) F("update")) == 0) {
|
|
console.log(LOG_INFO, F("MATHS: REBOOT - rebooting in: %lu seconds"), console.getCsvVal(4));
|
|
}
|
|
else if(strcmp_P(console.getCsvBuffer(3),(PGM_P) F("now")) == 0) {
|
|
console.log(LOG_INFO, F("MATHS: REBOOT - rebooting now"));
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_START:
|
|
console.log(LOG_INFO, F("COMMAND: Maths Start"));
|
|
// TODO - Other?
|
|
wii5Maths.start(WII5MATHSMODE_COMMS);
|
|
wii5Controller.statusDump();
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_HALT:
|
|
case WII5COMMAND_MATHS_STOP:
|
|
console.log(LOG_INFO, F("COMMAND: Maths Stop/Halt"));
|
|
wii5Maths.stop();
|
|
wii5Controller.statusDump();
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_HOLD:
|
|
wii5Maths.woops_on();
|
|
console.log(LOG_INFO, F("COMMAND: Maths Hold %d seconds"), console.getCsvVal(3));
|
|
wii5Maths.setHold(console.getCsvVal(3));
|
|
wii5Controller.statusDump();
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_UNTIL:
|
|
console.log(LOG_INFO, F("COMMAND: Maths Until time"), console.getCsvVal(3));
|
|
wii5Maths.setMathsUntil(console.getCsvVal(3));
|
|
wii5Controller.statusDump();
|
|
break;
|
|
|
|
// TODO Need to start maths, make sure it is fullly working then send the command to Maths,do etc.
|
|
// TODO how to send responses in that case? - Multiple
|
|
case WII5COMMAND_MATHS_DO:
|
|
break;
|
|
case WII5COMMAND_MATHS_MAKE:
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_DONE:
|
|
wii5Maths.queueDone();
|
|
break;
|
|
|
|
case WII5COMMAND_MATHS_SCRIPT:
|
|
if (console.getCsvVal(3) == 1) {
|
|
console.log(LOG_INFO, F("Queue: test one,two"));
|
|
wii5Maths.queueCommand("test,one", 8);
|
|
wii5Maths.queueCommand("test,two", 8);
|
|
}
|
|
else if (console.getCsvVal(3) == 2) {
|
|
console.log(LOG_INFO, F("Queue: test one,two"));
|
|
wii5Maths.queueCommand("do,", 8);
|
|
wii5Maths.queueCommand("test,two", 8);
|
|
}
|
|
else if (console.getCsvVal(3) == 3) {
|
|
console.log(LOG_INFO, F("Queue: Maths recompile"));
|
|
wii5Maths.queueCommand("makeextra,-DDEBUG_BUILD=1", 25);
|
|
}
|
|
else {
|
|
console.log(LOG_INFO, F("Queue: Maths - bogus commands"));
|
|
wii5Maths.queueCommand("DoesNone", 8);
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_DUMP:
|
|
//TODO move logic to Controller or Display !!!
|
|
console.log(LOG_INFO, F("COMMAND: Dump ALL - Not implemented"));
|
|
break;
|
|
|
|
// Network tools
|
|
case WII5COMMAND_NETWORK_ECHO:
|
|
//TODO move logic to Controller or Network
|
|
console.log(LOG_DEBUG, F("Network: sendEcho (CONSOLE)"));
|
|
#ifdef WII5_RADIO_LORA
|
|
sh3dNodeNetwork.sendEcho();
|
|
#endif
|
|
break;
|
|
case WII5COMMAND_NETWORK_ECHOACK:
|
|
//TODO move logic to Controller or Network
|
|
#ifdef WII5_RADIO_LORA
|
|
console.log(LOG_DEBUG, F("Network: sendACK (for Echo)"));
|
|
sh3dNodeNetwork.sendACK(SH3D_NODE_Packet_Echo_packetType_ACK, SH3D_NODE_Packet_Echo_packetVersion);
|
|
#endif
|
|
break;
|
|
case WII5COMMAND_NETWORK_FAKEECHO:
|
|
//TODO move logic to Controller or Network
|
|
#ifdef WII5_RADIO_LORA
|
|
console.log(LOG_DEBUG, F("Network: Faking an echo"));
|
|
// NOTE: Used to create Fake Packets - should be in a Test Library
|
|
// TODO move to RadioLoRa
|
|
sh3dNodeRadio.lastLength = sizeof(SH3D_NODE_Packet_Echo);
|
|
sh3dNodeNetwork.localEcho->header.node.nodeType = 1;
|
|
sh3dNodeNetwork.localEcho->header.node.nodeId = 2;
|
|
sh3dNodeNetwork.localEcho->packetType = SH3D_NODE_Packet_Echo_packetType;
|
|
sh3dNodeNetwork.localEcho->packetVersion = SH3D_NODE_Packet_Echo_packetVersion;
|
|
sh3dNodeNetwork.localEcho->key = 9;
|
|
sh3dNodeNetwork.localEcho->val = 3;
|
|
sh3dNodeRadio.lastValid = true;
|
|
#endif
|
|
break;
|
|
case WII5COMMAND_NETWORK_FAKEECHOACK:
|
|
//TODO move logic to Controller or Network
|
|
#ifdef WII5_RADIO_LORA
|
|
console.log(LOG_DEBUG, F("Network: Faking an echo ack"));
|
|
// NOTE: Used to create Fake Packets - should be in a Test Library
|
|
// TODO move to RadioLoRa
|
|
sh3dNodeRadio.lastLength = sizeof(SH3D_NODE_Packet_ACK);
|
|
sh3dNodeNetwork.localACK->header.node.nodeType = 1;
|
|
sh3dNodeNetwork.localACK->header.node.nodeId = 2;
|
|
sh3dNodeNetwork.localACK->packetType = SH3D_NODE_Packet_Echo_packetType_ACK;
|
|
sh3dNodeNetwork.localACK->packetVersion = SH3D_NODE_Packet_Echo_packetVersion;
|
|
sh3dNodeRadio.lastValid = true;
|
|
#endif
|
|
break;
|
|
|
|
case WII5COMMAND_CAPTURE_START:
|
|
console.log(LOG_DEBUG, F("Capture: ManualStart requested (if not already running)"));
|
|
wii5Controller.setMode(WII5MODE_CAPTURE);
|
|
wii5ModeCapture.start();
|
|
break;
|
|
|
|
case WII5COMMAND_CAPTURE_STOP:
|
|
console.log(LOG_DEBUG, F("Capture: ManualStop requested (if running)"));
|
|
wii5Controller.setMode(WII5MODE_CAPTURE);
|
|
wii5ModeCapture.stop();
|
|
break;
|
|
|
|
case WII5COMMAND_POSITION_START:
|
|
console.log(LOG_DEBUG, F("Position: ManualStart requested (if not already running)"));
|
|
wii5Controller.setMode(WII5MODE_POSITION);
|
|
wii5ModePosition.start();
|
|
break;
|
|
|
|
case WII5COMMAND_POSITION_STOP:
|
|
console.log(LOG_DEBUG, F("Position: ManualStop requested (if running)"));
|
|
wii5Controller.setMode(WII5MODE_POSITION);
|
|
wii5ModePosition.stop();
|
|
break;
|
|
|
|
case WII5COMMAND_POSITION_PASSTHROUGH:
|
|
console.log(LOG_DEBUG, F("Position: Passthrough toggle"));
|
|
wii5Gps.setPassthrough(console.getCsvVal(3) ? 1 : 0);
|
|
wii5Gps.setDebug(console.getCsvVal(3) ? 1 : 0);
|
|
wii5Iridium.setPassthrough(console.getCsvVal(3) ? 1 : 0);
|
|
wii5Iridium.setDebug(console.getCsvVal(3) ? 1 : 0);
|
|
break;
|
|
|
|
case WII5COMMAND_MODE_POSITION:
|
|
console.log(LOG_DEBUG, F("Set: Mode=Position"));
|
|
wii5Controller.setMode(WII5MODE_POSITION);
|
|
break;
|
|
|
|
case WII5COMMAND_MODE_MANUALTEST:
|
|
console.log(LOG_DEBUG, F("Set: Mode=ManualTest"));
|
|
wii5Controller.setMode(WII5MODE_MANUALTEST);
|
|
break;
|
|
|
|
case WII5COMMAND_MODE_SELFTEST:
|
|
console.log(LOG_DEBUG, F("Set: Mode=SelfTest"));
|
|
if (strcmp_P(console.getCsvBuffer(3),(PGM_P) F("frommaths")) == 0) {
|
|
wii5ModeSelfTest.setMode(WII5SM_FROMMATHS);
|
|
}
|
|
else if (strcmp_P(console.getCsvBuffer(3),(PGM_P) F("nomaths")) == 0) {
|
|
wii5ModeSelfTest.setMode(WII5SM_NOMATHS);
|
|
}
|
|
wii5Controller.setMode(WII5MODE_SELFTEST);
|
|
break;
|
|
|
|
// TODO This should realy be CURRENt, ie, it could be the temp one
|
|
case WII5COMMAND_MODE_DEFAULT:
|
|
console.log(LOG_DEBUG, F("Set: Mode=Default"));
|
|
wii5Controller.setDefaultMode();
|
|
break;
|
|
|
|
case WII5COMMAND_MODE_CAPTURE:
|
|
console.log(LOG_DEBUG, F("Set: Capture Mode"));
|
|
wii5Controller.setMode(WII5MODE_CAPTURE);
|
|
break;
|
|
|
|
case WII5COMMAND_MODE_SLEEP:
|
|
console.log(LOG_DEBUG, F("Set: Sleep Mode (Note: Maths hold set to 5 minutes)"));
|
|
wii5Controller.setMode(WII5MODE_SLEEP);
|
|
// We must have set this from serial, lets leave MAths hold 5 mins
|
|
wii5Maths.setHold(900);
|
|
break;
|
|
|
|
case WII5COMMAND_BINDATA_LIST:
|
|
// TODO Check if we need reply..., where to store it? New var I think
|
|
console.log(LOG_DEBUG, F("BinData: List"));
|
|
wii5BinData.showSizes(lastCommandMessage, WII5_RESULT_MESSAGE);
|
|
break;
|
|
|
|
case WII5COMMAND_BINDATA_SPLIT:
|
|
// TODO Check if we need reply..., where to store it? New var I think
|
|
console.log(LOG_DEBUG, F("BinData: Split"));
|
|
wii5BinData.showSplit(console.getCsvVal(3), (uint16_t)console.getCsvVal(4), lastCommandMessage, WII5_RESULT_MESSAGE);
|
|
break;
|
|
|
|
case WII5COMMAND_WEATHER_READ:
|
|
console.log(LOG_DEBUG, F("Weather: Reading temperature"));
|
|
wii5Weather_18B20.temperatureRead();
|
|
break;
|
|
|
|
case WII5COMMAND_WEATHER_TEST:
|
|
console.log(LOG_DEBUG, F("Weather: Test Loop"));
|
|
{
|
|
for (uint16_t wtest = 0; wtest < 100; wtest++) {
|
|
console.log(LOG_INFO, F("Weather: Test Loop: n=%d"), wtest);
|
|
wii5Weather_18B20.temperatureRead();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WII5COMMAND_IRIDIUM_SEND:
|
|
console.log(LOG_DEBUG, F("Iridium: Send Text"));
|
|
wii5Iridium.setPassthrough(1); // TODO Should be configurable
|
|
// TODO What text should be configurable
|
|
wii5Iridium.setText(F("Longer example text"));
|
|
wii5Iridium.requestSendText();
|
|
break;
|
|
|
|
case WII5COMMAND_COMMUNICATIONS_DISABLED:
|
|
console.log(LOG_DEBUG, F("Communication: Disabled"));
|
|
wii5Communications.setDisabled(console.getCsvVal(3) ? 1 : 0);
|
|
break;
|
|
|
|
case WII5COMMAND_COMMUNICATIONS_TEST:
|
|
console.log(LOG_DEBUG, F("Communication: Test - once through test mode"));
|
|
wii5Communications.setAutoMode();
|
|
wii5Communications.start();
|
|
wii5Communications.setTESTING();
|
|
break;
|
|
|
|
case WII5COMMAND_COMMUNICATIONS_SIGNAL:
|
|
console.log(LOG_DEBUG, F("Communication: Signal (SD Card change)"));
|
|
wii5Communications.signalSD();
|
|
break;
|
|
|
|
case WII5COMMAND_COMMUNICATIONS_START:
|
|
console.log(LOG_DEBUG, F("Communication: Start"));
|
|
wii5Communications.start();
|
|
break;
|
|
|
|
case WII5COMMAND_COMMUNICATIONS_STOP:
|
|
console.log(LOG_DEBUG, F("Communication: Stop"));
|
|
wii5Communications.stop();
|
|
break;
|
|
|
|
case WII5COMMAND_BATTERY_START:
|
|
console.log(LOG_DEBUG, F("Battery: start"));
|
|
wii5Battery.start();
|
|
break;
|
|
|
|
default:
|
|
console.log(LOG_INFO, F("Command @ not yet implemented = '%s'."), wii5Strings.strCommand(cmd));
|
|
return false;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// doneLast - flag that the entry is now done.
|
|
void WII5Commands::doneLast() {
|
|
lastCommandAckComplete = true;
|
|
}
|
|
|
|
// setupLast - set original last entry data
|
|
// TODO - Manually need to set:
|
|
// lastCommandCmd = cmd; lastCommandParam1 = 0; lastCommandParam2 = 0; lastCommandParam3 = 0;
|
|
// lastCommandResult = WII5RESULTS_UNKNOWN; memset(&lastCommandMessage, 0, sizeof(lastCommandMessage));
|
|
void WII5Commands::setupLast(WII5_DEVICES device, WII5_PORTS port, WII5_AREAS area, WII5_COMMANDS cmd) {
|
|
if (!lastCommandAckComplete) {
|
|
console.log(LOG_DEBUG, F("Warning. Last message did not deliver and ACK, it will have been lost."));
|
|
// TODO Details - log whole of lastCommand
|
|
}
|
|
|
|
// When and Where
|
|
lastCommandAge = 0;
|
|
lastCommandT = now();
|
|
lastCommandDevice = device;
|
|
lastCommandPort = port;
|
|
lastCommandArea = area;
|
|
|
|
// Cleanup
|
|
lastCommandCmd = cmd;
|
|
lastCommandParam1 = 0;
|
|
lastCommandParam2 = 0;
|
|
lastCommandParam3 = 0;
|
|
|
|
// Results ?
|
|
lastCommandResult = WII5RESULTS_UNKNOWN;
|
|
memset(&lastCommandMessage, 0, sizeof(lastCommandMessage));
|
|
|
|
// ackComplete
|
|
lastCommandAckComplete = false;
|
|
}
|
|
|
|
void WII5Commands::resultLast(WII5_RESULTS result, const __FlashStringHelper *message) {
|
|
lastCommandResult = result;
|
|
strncpy_P(lastCommandMessage, (const char *)message, sizeof(lastCommandMessage));
|
|
}
|
|
void WII5Commands::resultLast(WII5_RESULTS result, char *message) {
|
|
lastCommandResult = result;
|
|
strncpy(lastCommandMessage, message, sizeof(lastCommandMessage));
|
|
}
|
|
void WII5Commands::resultLast(WII5_RESULTS result) {
|
|
lastCommandResult = result;
|
|
}
|
|
|
|
/*
|
|
// resultLast(...)
|
|
lastCommandResult = X
|
|
snprintf_P(
|
|
lastCommandMessage, sizeof(lastCommandMessage),
|
|
PSTR(""),
|
|
getDeviceId(), getRecordCount()
|
|
);
|
|
*/
|
|
|
|
// Work out that we have a WII5,X where X is the result
|
|
bool WII5Commands::processConsoleAT() {
|
|
if (!console.available() || (console.getCommand() != '@'))
|
|
return false;
|
|
|
|
// TODO repeat this for other systems - e.g. parsing network or iridium
|
|
if (strcmp_P(console.getCsvBuffer(0),(PGM_P) F("WII5")) == 0) {
|
|
return runCommand(
|
|
wii5Strings.parseCommand(
|
|
console.getCsvBuffer(1),
|
|
console.getCsvBuffer(2),
|
|
console.getCsvBuffer(3)
|
|
)
|
|
);
|
|
}
|
|
else if (strcmp_P(console.getCsvBuffer(0),(PGM_P) F("Help")) == 0) {
|
|
return wii5Help.processConsoleCsv();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Return false if there IS a command and it was not handled
|
|
bool WII5Commands::processConsoleStandard() {
|
|
if (console.available()) {
|
|
switch(console.getCommand()) {
|
|
// Help - Low level help before full commands
|
|
case 'h':
|
|
case 'H':
|
|
console.log(LOG_INFO, F("WII5: Simplified command and help system"));
|
|
console.log(LOG_FATAL, F(" NOTE: you may need to enable logs @WII5,log,all"));
|
|
console.log(LOG_DEBUG, F(" See @Help for full commands"));
|
|
console.log(LOG_DEBUG, F(" * - show all pins"));
|
|
console.log(LOG_DEBUG, F(" @WII5,maths,start|stop - immediate start or stop"));
|
|
console.log(LOG_DEBUG, F(" @WII5,maths,hold,300 - hold for 5 minutes"));
|
|
console.log(LOG_DEBUG, F(" @WII5,mode,manualtest - Immediate switch to manual test mode"));
|
|
console.log(LOG_DEBUG, F(" @WII5,capture,start|stop - start or stop a capture, also switches mode"));
|
|
console.log(LOG_DEBUG, F(" @WII5,mode,sleep - sleep mode."));
|
|
console.log(LOG_DEBUG, F(" Z - force a reset now (must add 666)"));
|
|
console.log(LOG_DEBUG, F(" . - set default mode"));
|
|
console.log(LOG_DEBUG, F(" ? - Status"));
|
|
break;
|
|
|
|
// RESET. usual Z666;
|
|
case 'Z':
|
|
if (console.getVal() == 666) {
|
|
sh3dNodeUtil.reset();
|
|
}
|
|
break;
|
|
|
|
// T: for manualTest Mode
|
|
case 'T':
|
|
// TODO console.log(LOG_FATAL, F("Old testmode. Inbstead = @WII5,mode,manualtest !!!"));
|
|
console.log(LOG_FATAL, F("MANUALTEST"));
|
|
wii5Controller.setMode(WII5MODE_MANUALTEST);
|
|
break;
|
|
|
|
// s: Sleep mode
|
|
case 's':
|
|
console.log(LOG_ERROR, F("Old sleepmode. Inbstead = @WII5,mode,sleep !!!"));
|
|
break;
|
|
|
|
// C for CAPTURE Mode
|
|
case 'C':
|
|
console.log(LOG_ERROR, F("Old capturemode. Inbstead = @WII5,mode,capture, @WII5,capture,start, @WII5,capture,stop !!!"));
|
|
break;
|
|
|
|
case 'W':
|
|
// TODO Danger ! Move this elsewhere and update Documents
|
|
SerialConsole.print(F("WARNING - Disabled external WDT reset pin - runCount="));
|
|
SerialConsole.println(sh3dNodeConfig.getRunCount());
|
|
wii5Controller.tempDisableWDT = true;
|
|
break;
|
|
|
|
case '*':
|
|
wii5Display.dumpPins();
|
|
break;
|
|
|
|
// Status etc
|
|
case '.':
|
|
wii5Controller.setDefaultMode();
|
|
break;
|
|
|
|
case ',':
|
|
wii5Display.printMetadata();
|
|
break;
|
|
|
|
case '?':
|
|
wii5Controller.statusDump(true);
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
WII5Commands wii5Commands;
|