// GPIO interface // Sets the mode of a GPIO ( digital in= 0, digital out = 1, analog = 2 ) // Returns true on successful setup. uint8_t Sodaq_RN2483::pinMode(uint8_t gpio, pinModes mode) { //sanitize inputs, //GPIO4 does not do analog debugPrintLn("setting GPIO pin"); if (mode == analog) { if (gpio==4) { return false; debugPrintLn("GPIO4 does not support analog"); } } // only handle GPIO0-13 if (gpio >13) { return false; debugPrintLn("GPIO out of bounds : 0-13 only"); } // sys set pinmode <pinname> <pinFunc> this->loraStream->print(STR_SYS_SET); this->loraStream->print(STR_GPIO_MODE); this->loraStream->print(STR_GPIO); this->loraStream->print(gpio); if (mode == digitalIn) { this->loraStream->print(STR_GPIO_MODE_DIGIN); } else if (mode == digitalOut){ this->loraStream->print(STR_GPIO_MODE_DIGOUT); } else { this->loraStream->print(STR_GPIO_MODE_ANA); } this->loraStream->print(CRLF); // parse response return expectOK(); }
/** * @brief Sends the command together with the given, paramValue (optional) * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref * @param Command Parameter to send * @return Returns true on success or false if invalid. */ bool RN2483::sendCommand(const char* command, uint8_t paramValue) { _RN2483.printf(command); _RN2483.printf("%u",paramValue); _RN2483.printf(CRLF); return expectOK(); }
/** * @brief Sends a join command to the network * @param Type of join, OTAA or ABP * @return Returns true on success or false if fail. */ bool RN2483::joinNetwork(const char* type) { _RN2483.printf(STR_CMD_JOIN); _RN2483.printf(type); _RN2483.printf(CRLF); return expectOK() && expectString(STR_ACCEPTED, 30000); }
/** * @brief Sends the command together with the given, paramValue (optional) * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref * @param Command Parameter to send * @return Returns true on success or false if invalid. */ bool RN2483::sendCommand(const char* command, const char* paramValue) { _RN2483.printf(command); if (paramValue != NULL) { _RN2483.printf(paramValue); } _RN2483.printf(CRLF); return expectOK(); }
/** * @brief Sends the command together with the given paramValue (optional) * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref. * @param Param value to send * @return Returns true on success or false if invalid. */ bool RN2483::setMacParam(const char* paramName, const char* paramValue) { _RN2483.printf(STR_CMD_SET); _RN2483.printf(paramName); _RN2483.printf(paramValue); _RN2483.printf(CRLF); return expectOK(); }
bool Sodaq_RN2483::macSave() { debugPrint("[macSave] "); this->loraStream->print(STR_CMD_SAVE); this->loraStream->print(CRLF); return expectOK(); }
// Sends a join network command to the device and waits for the response (or timeout). // Returns true on success. bool Sodaq_RN2483::joinNetwork(const char* type) { debugPrintLn("[joinNetwork]"); this->loraStream->print(STR_CMD_JOIN); this->loraStream->print(type); this->loraStream->print(CRLF); return expectOK() && expectString(STR_ACCEPTED, 10000); }
/** * @brief Sends the command together with the given, paramValue (optional) * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref * @param Command Parameter to send * @param Size of param buffer * @return Returns true on success or false if invalid. */ bool RN2483::sendCommand(const char* command, const uint8_t* paramValue, uint16_t size) { _RN2483.printf(command); for (uint16_t i = 0; i < size; ++i) { _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i])))); _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i])))); } _RN2483.printf(CRLF); return expectOK(); }
// Sends the given mac command together with the given paramValue // to the device and awaits for the response. // Returns true on success. // NOTE: paramName should include a trailing space bool Sodaq_RN2483::setMacParam(const char* paramName, const char* paramValue) { debugPrint("[setMacParam] "); debugPrint(paramName); debugPrint("= "); debugPrintLn(paramValue); this->loraStream->print(STR_CMD_SET); this->loraStream->print(paramName); this->loraStream->print(paramValue); this->loraStream->print(CRLF); return expectOK(); }
uint8_t Sodaq_RN2483::macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size) { debugPrintLn("[macTransmit]"); this->loraStream->print(STR_CMD_MAC_TX); this->loraStream->print(type); this->loraStream->print(port); this->loraStream->print(" "); for (int i = 0; i < size; ++i) { this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(payload[i])))); this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(payload[i])))); } this->loraStream->print(CRLF); if (!expectOK()) { return lookupMacTransmitError(this->inputBuffer); // inputBuffer still has the last line read } this->packetReceived = false; // prepare for receiving a new packet debugPrint("Waiting for server response"); unsigned long timeout = millis() + RECEIVE_TIMEOUT; // hard timeout while (millis() < timeout) { sodaq_wdt_reset(); debugPrint("."); if (readLn() > 0) { debugPrintLn(".");debugPrint("(");debugPrint(this->inputBuffer);debugPrintLn(")"); if (strstr(this->inputBuffer, " ") != NULL) // to avoid double delimiter search { // there is a splittable line -only case known is mac_rx debugPrintLn("Splittable response found"); return onMacRX(); } else if (strstr(this->inputBuffer, STR_RESULT_MAC_TX_OK)) { // done debugPrintLn("Received mac_tx_ok"); return NoError; } else { // lookup the error message debugPrintLn("Some other string received (error)"); return lookupMacTransmitError(this->inputBuffer); } } } debugPrintLn("Timed-out waiting for a response!"); return Timeout; }
/** * @brief Sends the command together with the given paramValue (optional) * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref. * @param Param value to send * @param Size of Param buffer * @return Returns true on success or false if invalid. */ bool RN2483::setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size) { printf("RN2483: Set MAC param: %s\n"); _RN2483.printf(STR_CMD_SET); _RN2483.printf(paramName); for (uint16_t i = 0; i < size; ++i) { _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i])))); _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i])))); } _RN2483.printf(CRLF); return expectOK(); }
// Sends the given mac command together with the given paramValue // to the device and awaits for the response. // Returns true on success. // NOTE: paramName should include a trailing space bool Sodaq_RN2483::setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size) { debugPrint("[setMacParam] "); debugPrint(paramName); debugPrint("= [array]"); this->loraStream->print(STR_CMD_SET); this->loraStream->print(paramName); for (uint16_t i = 0; i < size; ++i) { this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i])))); this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i])))); } this->loraStream->print(CRLF); return expectOK(); }
//! Read the contents of the MT SBD message buffer. //! @param[in] data buffer to hold binary data. //! @param[in] data_size size of binary data buffer. //! @return number of bytes read. unsigned readBufferMT(uint8_t* data, unsigned data_size) { ReadMode saved_read_mode = getReadMode(); Counter<double> timer(getTimeout()); uint8_t bfr[2] = {0}; uint8_t ccsum[2] = {0}; unsigned length = 0; try { // Prepare to read raw data. setReadMode(READ_MODE_RAW); // Send command. sendAT("+SBDRB"); // Read incoming data length. length = getBufferSizeMT(timer); getTask()->spew("reading %u bytes of SBD binary data", length); // Read data. if (length > data_size) throw BufferTooSmall(data_size, length); if (length > 0) { readRaw(timer, data, length); computeChecksum(data, length, ccsum); } // Read and validate. readRaw(timer, bfr, 2); if ((bfr[0] != ccsum[0]) || (bfr[1] != ccsum[1])) throw Hardware::InvalidChecksum(bfr, ccsum); setReadMode(saved_read_mode); expectOK(); } catch (...) { setReadMode(saved_read_mode); throw; } return length; }
/** * @brief Enables all the channels that belong to the given Frequency Sub-Band (FSB) * disables the rest. * @param FSB is [1, 8] or 0 to enable all channels. * @return Returns true if all channels were set successfully. */ bool RN2483::setFsbChannels(uint8_t fsb) { uint8_t first125kHzChannel = fsb > 0 ? (fsb - 1) * 8 : 0; uint8_t last125kHzChannel = fsb > 0 ? first125kHzChannel + 7 : 71; uint8_t fsb500kHzChannel = fsb + 63; bool allOk = true; for (uint8_t i = 0; i < 72; i++) { _RN2483.printf(STR_CMD_SET_CHANNEL_STATUS); _RN2483.printf("%u",i); _RN2483.printf(" "); _RN2483.printf(BOOL_TO_ONOFF(((i == fsb500kHzChannel) || (i >= first125kHzChannel && i <= last125kHzChannel)))); _RN2483.printf(CRLF); allOk &= expectOK(); } return allOk; }
/** * @brief Sends a a payload and blocks until there is a response back, * or the receive windows have closed or the hard timeout has passed. * @param Transmit type * @param Port to use for transmit * @param Payload buffer * @param Size of payload buffer * @return Returns if sucessfull or if a MAC transmit error. */ uint8_t RN2483::macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size) { _RN2483.printf(STR_CMD_MAC_TX); _RN2483.printf(type); _RN2483.printf("%u",port); _RN2483.printf(" "); for (int i = 0; i < size; ++i) { _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(payload[i])))); _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(payload[i])))); } _RN2483.printf(CRLF); if (!expectOK()) { return lookupMacTransmitError(this->inputBuffer); // inputBuffer still has the last line read } this->packetReceived = false; // prepare for receiving a new packet Timer t; t.start(); int timeout = t.read_ms() + RECEIVE_TIMEOUT; // hard timeouts while (t.read_ms() < timeout) { if (readLn() > 0) { if (strstr(this->inputBuffer, " ") != NULL) { // to avoid double delimiter search // there is a splittable line -only case known is mac_rx t.stop(); return onMacRX(); } else if (strstr(this->inputBuffer, STR_RESULT_MAC_TX_OK)) { // done t.stop(); return NoError; } else { // lookup the error message t.stop(); return lookupMacTransmitError(this->inputBuffer); } } } t.stop(); return Timedout; }
// Enables all the channels that belong to the given Frequency Sub-Band (FSB) // and disables the rest. // fsb is [1, 8] or 0 to enable all channels. // Returns true if all channels were set successfully. bool Sodaq_RN2483::setFsbChannels(uint8_t fsb) { debugPrintLn("[setFsbChannels]"); uint8_t first125kHzChannel = fsb > 0 ? (fsb - 1) * 8 : 0; uint8_t last125kHzChannel = fsb > 0 ? first125kHzChannel + 7 : 71; uint8_t fsb500kHzChannel = fsb + 63; bool allOk = true; for (uint8_t i = 0; i < 72; i++) { this->loraStream->print(STR_CMD_SET_CHANNEL_STATUS); this->loraStream->print(i); this->loraStream->print(" "); this->loraStream->print(BOOL_TO_ONOFF(((i == fsb500kHzChannel) || (i >= first125kHzChannel && i <= last125kHzChannel)))); this->loraStream->print(CRLF); allOk &= expectOK(); } return allOk; }
// Sets the digital state of a pin // Returns true on successful setting. uint8_t Sodaq_RN2483::digitalWrite(uint8_t gpio, uint8_t state) { //sanitize inputs, // only handle GPIO0-13 debugPrintLn("digitalWrite"); if (gpio >13) { return false; debugPrintLn("GPIO out of bounds : 0-13 only"); } // sys set pindig <pinname> <pinstate> // example: sys set pindig GPIO5 1 this->loraStream->print(STR_SYS_SET); this->loraStream->print(STR_GPIO_DIG); this->loraStream->print(STR_GPIO); this->loraStream->print(gpio); this->loraStream->print(" "); this->loraStream->print(state); this->loraStream->print(CRLF); // parse response return expectOK(); }