// SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2012-2024 Scott Penrose 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 #include #include #include #include #include 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 ")); 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;