// 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 WII5Iridium.h * @brief Iridium 9602/9603 SBD modem driver: AT-command state machine. */ #ifndef WII5Iridium_h #define WII5Iridium_h #include #include #include #ifdef WII5_COMMS_IRIDIUM /* How to make request ? How to know when complete? void loop() { wii5Iridium.loop(); if (wii5Iridium.lastStatus) { // Check the Status of the last thing we sent } if (wii5Iridium.lastReceive) { // TODO } } DATA STRUCTURE TO Send * Wrap WII5 Binary Packet in Iridium specific data * Time it took to send (updated just before send each time) * Number of retries * Last Signal quality Useful References: https://docs.rockblock.rock7.com/reference#sbdix */ enum WII5IRIDIUM_REQUEST { WII5IRIDIUM_REQUEST_NONE, WII5IRIDIUM_REQUEST_FIRMWARE, WII5IRIDIUM_REQUEST_TIME, WII5IRIDIUM_REQUEST_SIGNALQUALITY, WII5IRIDIUM_REQUEST_SENDTEXT, WII5IRIDIUM_REQUEST_SENDBIN, }; enum WII5IRIDIUM_STATUS { WII5IRIDIUM_STATUS_READY, // Ready to send, no errors WII5IRIDIUM_STATUS_BUSY, // Busy, still sending, need to wait WII5IRIDIUM_STATUS_FAILED // Reason for failure? }; // TODO request - need to know what the input is and how to stop... enum WII5IRIDIUM_STEPS { // Just off. WII5IRIDIUM_OFF, // Turn it off - power and all WII5IRIDIUM_POWER, // Turn on power and wait 500ms WII5IRIDIUM_ALIVE, // Send "AT" until get OK or timeout WII5IRIDIUM_BOOT, // ATE1, AT&D0, AT&K0, AT+SBDMTA=0 // Firmware WII5IRIDIUM_FIRMWARE,// AT+CGMR // IMEI WII5IRIDIUM_IMEI, // AT-MSSTM // System Time WII5IRIDIUM_SYSTERMTIME, // AT-MSSTM // Signal Quality WII5IRIDIUM_SIGNALQUALITY_WAIT, WII5IRIDIUM_SIGNALQUALITY, // AT+CSQ // Choose - send Text or Binary - always returns data WII5IRIDIUM_RETRY, // Wait here a bit before rety WII5IRIDIUM_SEND_JUMP, // Are we TEXT or BINARY // Send Text WII5IRIDIUM_PREPARE_TEXT, // AT+SBDWT=RockBlocks1 WII5IRIDIUM_SEND, // AT+SBDI ... +SBDI: 1, 3, 0, 0, 0, 0 // Send Binary WII5IRIDIUM_PREPARE_BIN1, // AT+SBDWB={n} (size of data) WII5IRIDIUM_PREPARE_BIN2, // AT+SBDWB={n} (size of data) // Receive Message WII5IRIDIUM_RECEIVE, // AT+SBDRB ... AT+SBDRB (echo back) WII5IRIDIUM_RECEIVE_BIN, // first 2 bytes = size, then binary, then checksum WII5IRIDIUM_WAITING, // Waiting - hurry up and absorb // Complete WII5IRIDIUM_STOP_PREPARE, // END ! Jump to STOP_PREPARE, WII5IRIDIUM_END // Very end }; #define DEFAULT_MINUTES 5 #define IRIDIUM_RETRY_MIN 2 // Used for low power mode, how many times to rety minimum #define IRIDIUM_RETRY_MAX 20 // Maximum number of retries for normal modes // FROM IridiumSBD by Rock Blocks #define ISBD_LIBRARY_REVISION 2 #define ISBD_DEFAULT_AT_TIMEOUT 30 #define ISBD_MSSTM_RETRY_INTERVAL 10 #define ISBD_DEFAULT_SBDIX_INTERVAL 10 #define ISBD_USB_SBDIX_INTERVAL 30 #define ISBD_DEFAULT_SENDRECEIVE_TIME 300 #define ISBD_STARTUP_MAX_TIME 240 #define ISBD_MAX_MESSAGE_LENGTH 340 #define ISBD_MSSTM_WORKAROUND_FW_VER 13001 #define ISBD_SUCCESS 0 #define ISBD_ALREADY_AWAKE 1 #define ISBD_SERIAL_FAILURE 2 #define ISBD_PROTOCOL_ERROR 3 #define ISBD_CANCELLED 4 #define ISBD_NO_MODEM_DETECTED 5 #define ISBD_SBDIX_FATAL_ERROR 6 #define ISBD_SENDRECEIVE_TIMEOUT 7 #define ISBD_RX_OVERFLOW 8 #define ISBD_REENTRANT 9 #define ISBD_IS_ASLEEP 10 #define ISBD_NO_SLEEP_PIN 11 #define ISBD_NO_NETWORK 12 #define ISBD_MSG_TOO_LONG 13 enum WII5IRIDIUM_RETURNS { WII5IRIDIUM_RETURN_AT, WII5IRIDIUM_RETURN_OK, WII5IRIDIUM_RETURN_READY, WII5IRIDIUM_RETURN_ERROR, WII5IRIDIUM_RETURN_SBDI, // +SBDI, +SBDIX, +SBDIXA (moCode, &moMSN, &mtCode, &mtMSN, &mtLen, &mtRemaining) WII5IRIDIUM_RETURN_CSQ, // +CSQ:{n} WII5IRIDIUM_RETURN_MSSTM, // -MSSTM WII5IRIDIUM_RETURN_BINARY // Hard coded the binary }; /** * @brief Driver for the Iridium 9602/9603 SBD modem. * * AT-command state machine: power on, wait for the modem to come alive, * boot up (ATE1, AT&D0, AT&K0, AT+SBDMTA=0), then drive a sequence of * +CSQ / +SBDWB / +SBDIX / +SBDRB cycles to send and receive 340-byte * SBD messages. State is in WII5IRIDIUM_STEPS; see step transitions in * WII5Iridium.cpp::loop(). */ class WII5Iridium : public WII5Power, public WII5SerialManager{ public: WII5Iridium() {} virtual WII5_CONTROLLERS controllerId() {return WII5CONTROLLER_DRIVER;} virtual WII5_DRIVERS driverId() {return WII5DRIVER_COMMS_IRIDIUM;} /** @brief One-time bring-up. */ void begin(); /** @brief State-machine tick: parses serial, advances steps. */ void loop(); /** @brief Queue a firmware-version query (AT+CGMR). */ bool requestFirmware(); /** @brief Queue a binary send (uses buffer set by setBinary/setBinSize). */ bool requestSendBinary(); /** @brief Queue a text send (uses buffer set by setText). */ bool requestSendText(); /** @brief Currently-queued request type. */ WII5IRIDIUM_REQUEST currentRequest(); /** @brief Set the binary buffer + length for the next send. */ void setBinary(uint8_t* buf, uint16_t size); /** @brief Set just the size of the binary buffer (caller writes the bytes). */ void setBinSize(uint16_t size); /** @brief Set the text payload for the next send (RAM string). */ void setText(char* str); /** @brief Set the text payload for the next send (PROGMEM string). */ void setText(const __FlashStringHelper *str); /** @brief Begin a comms cycle (`force` skips initialized check). */ virtual void start(bool force = false); /** @brief Abort the current cycle. */ void stop(bool force = false); /** @brief Apply power to the Iridium modem. */ void powerOn(bool force = false); /** @brief Cut power to the Iridium modem. */ void powerOff(bool force = false); /** @brief Are we waiting on the modem to finish a step? */ bool waiting(); /** @brief Is the state machine currently in a non-idle step? */ bool isRunning(); // TODO Storage? why can't we use a 64 bit (8 byte) number? char imei[18]; // 14 or up to 16 digits? // uint32_t ; // 14 or up to 16 digits? elapsedMillis lastSince; uint8_t lastSignalQuality; uint16_t lastMOMSN; WII5IRIDIUM_SEND_RESULT lastSend; WII5IRIDIUM_RECEIVE_RESULT lastReceive; uint16_t lastReceiveLen; uint8_t* lastReceiveBuff; virtual void sendNewLine(); protected: bool running; WII5IRIDIUM_STEPS step; WII5IRIDIUM_STEPS stepLast; elapsedMillis stepWait; void programLine(uint16_t l); bool initialized; WII5IRIDIUM_REQUEST currentType; uint8_t retry; // How many times did we retry ? uint8_t sigQualRetry; // How many times did we retry ? uint8_t sigQualMin; // How many times did we retry ? uint32_t binSize; // Size of binary data to send uint16_t checksum; uint16_t loopcount; uint8_t *txData; // Firmware (and age) // Signal Quality (and age) // DateTime (and age) // Send Status (and age) (WAITING, COMPLETE, ERROR) // Send Queue ? (or external) // Receive Queue (or external) // lastCSQ // lastIMEI // lastSystemTime // lastID??? // lastStatus?? // Last Status = }; extern WII5Iridium wii5Iridium; #endif #endif