A mbed library for the RN2483. Heavily based on the Sodaq_RN2483 library for Arduino (https://github.com/SodaqMoja/Sodaq_RN2483). This is currently under-going initial testing, but seems to work! Tested on a NRF51 and FRDM K64F.

Dependents:   rn2483-TestProgram

Committer:
azazeal88
Date:
Sat Nov 19 23:30:34 2016 +0000
Revision:
1:cf9b0c21907a
Parent:
0:a8609e6f88f3
Child:
2:336a025b82b5
Improved comments; added additional command functionality.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
azazeal88 0:a8609e6f88f3 1 #include "RN2483.h"
azazeal88 0:a8609e6f88f3 2 #include "StringLiterals.h"
azazeal88 0:a8609e6f88f3 3 #include "Utils.h"
azazeal88 0:a8609e6f88f3 4
azazeal88 0:a8609e6f88f3 5 // Structure for mapping error response strings and error codes.
azazeal88 1:cf9b0c21907a 6 typedef struct StringEnumPair {
azazeal88 0:a8609e6f88f3 7 const char* stringValue;
azazeal88 0:a8609e6f88f3 8 uint8_t enumValue;
azazeal88 0:a8609e6f88f3 9 } StringEnumPair_t;
azazeal88 0:a8609e6f88f3 10
azazeal88 1:cf9b0c21907a 11 /**
azazeal88 1:cf9b0c21907a 12 * @brief Create a new instance of the RN2483.
azazeal88 1:cf9b0c21907a 13 * @param Serial TX pin name.
azazeal88 1:cf9b0c21907a 14 * @param Serial RX pin name.
azazeal88 1:cf9b0c21907a 15 */
azazeal88 1:cf9b0c21907a 16 RN2483::RN2483(PinName tx, PinName rx) :
azazeal88 0:a8609e6f88f3 17 _RN2483(tx, rx, getDefaultBaudRate()),
azazeal88 0:a8609e6f88f3 18 inputBufferSize(DEFAULT_INPUT_BUFFER_SIZE),
azazeal88 0:a8609e6f88f3 19 receivedPayloadBufferSize(DEFAULT_RECEIVED_PAYLOAD_BUFFER_SIZE),
azazeal88 0:a8609e6f88f3 20 packetReceived(false),
azazeal88 1:cf9b0c21907a 21 isRN2903(false)
azazeal88 0:a8609e6f88f3 22 {
azazeal88 0:a8609e6f88f3 23 #ifdef USE_DYNAMIC_BUFFER
azazeal88 0:a8609e6f88f3 24 this->isBufferInitialized = false;
azazeal88 0:a8609e6f88f3 25 #endif
azazeal88 0:a8609e6f88f3 26 }
azazeal88 1:cf9b0c21907a 27
azazeal88 1:cf9b0c21907a 28 /**
azazeal88 1:cf9b0c21907a 29 * @brief Takes care of the init tasks common to both initOTA() and initABP.
azazeal88 1:cf9b0c21907a 30 */
azazeal88 0:a8609e6f88f3 31 void RN2483::init()
azazeal88 0:a8609e6f88f3 32 {
azazeal88 0:a8609e6f88f3 33 #ifdef USE_DYNAMIC_BUFFER
azazeal88 0:a8609e6f88f3 34 // make sure the buffers are only initialized once
azazeal88 0:a8609e6f88f3 35 if (!isBufferInitialized) {
azazeal88 0:a8609e6f88f3 36 this->inputBuffer = static_cast<char*>(malloc(this->inputBufferSize));
azazeal88 0:a8609e6f88f3 37 this->receivedPayloadBuffer = static_cast<char*>(malloc(this->receivedPayloadBufferSize));
azazeal88 0:a8609e6f88f3 38 isBufferInitialized = true;
azazeal88 0:a8609e6f88f3 39 }
azazeal88 0:a8609e6f88f3 40 #endif
azazeal88 0:a8609e6f88f3 41 // make sure the module's state is synced and woken up
azazeal88 1:cf9b0c21907a 42 sleep(259200000);
azazeal88 0:a8609e6f88f3 43 wakeUp();
azazeal88 0:a8609e6f88f3 44 }
azazeal88 0:a8609e6f88f3 45
azazeal88 1:cf9b0c21907a 46 /**
azazeal88 1:cf9b0c21907a 47 * @brief Connect to network using Over The Air activation.
azazeal88 1:cf9b0c21907a 48 * @param devEUI provided by LoRaWAN Network server registration.
azazeal88 1:cf9b0c21907a 49 * @param appEUI provided by LoRaWAN Network server registration.
azazeal88 1:cf9b0c21907a 50 * @param appKey provided by LoRaWAN Network server registration.
azazeal88 1:cf9b0c21907a 51 * @return Network confirmation if sucessfully connected.
azazeal88 1:cf9b0c21907a 52 */
azazeal88 0:a8609e6f88f3 53 bool RN2483::initOTA(const uint8_t devEUI[8], const uint8_t appEUI[8], const uint8_t appKey[16], bool adr)
azazeal88 0:a8609e6f88f3 54 {
azazeal88 0:a8609e6f88f3 55 init();
azazeal88 0:a8609e6f88f3 56 return resetDevice() &&
azazeal88 1:cf9b0c21907a 57 setMacParam(STR_DEV_EUI, devEUI, 8) &&
azazeal88 1:cf9b0c21907a 58 setMacParam(STR_APP_EUI, appEUI, 8) &&
azazeal88 1:cf9b0c21907a 59 setMacParam(STR_APP_KEY, appKey, 16) &&
azazeal88 1:cf9b0c21907a 60 setMacParam(STR_ADR, BOOL_TO_ONOFF(adr)) &&
azazeal88 1:cf9b0c21907a 61 joinNetwork(STR_OTAA);
azazeal88 0:a8609e6f88f3 62 }
azazeal88 0:a8609e6f88f3 63
azazeal88 1:cf9b0c21907a 64 /**
azazeal88 1:cf9b0c21907a 65 * @brief Initializes the device and connects to the network using Activation By Personalization.
azazeal88 1:cf9b0c21907a 66 * @param devADDR provided by LoRaWAN Network server registration.
azazeal88 1:cf9b0c21907a 67 * @param appSKey provided by LoRaWAN Network server registration.
azazeal88 1:cf9b0c21907a 68 * @param nwkSKey provided by LoRaWAN Network server registration.
azazeal88 1:cf9b0c21907a 69 * @return Returns true if the parameters was valid.
azazeal88 1:cf9b0c21907a 70 */
azazeal88 0:a8609e6f88f3 71 bool RN2483::initABP(const uint8_t devAddr[4], const uint8_t appSKey[16], const uint8_t nwkSKey[16], bool adr)
azazeal88 0:a8609e6f88f3 72 {
azazeal88 0:a8609e6f88f3 73 init();
azazeal88 0:a8609e6f88f3 74 return resetDevice() &&
azazeal88 1:cf9b0c21907a 75 setMacParam(STR_DEV_ADDR, devAddr, 4) &&
azazeal88 1:cf9b0c21907a 76 setMacParam(STR_APP_SESSION_KEY, appSKey, 16) &&
azazeal88 1:cf9b0c21907a 77 setMacParam(STR_NETWORK_SESSION_KEY, nwkSKey, 16) &&
azazeal88 1:cf9b0c21907a 78 setMacParam(STR_ADR, BOOL_TO_ONOFF(adr)) &&
azazeal88 1:cf9b0c21907a 79 joinNetwork(STR_ABP);
azazeal88 0:a8609e6f88f3 80 }
azazeal88 1:cf9b0c21907a 81
azazeal88 1:cf9b0c21907a 82 /**
azazeal88 1:cf9b0c21907a 83 * @brief Sends the given payload without acknowledgement.
azazeal88 1:cf9b0c21907a 84 * @param Port to use for transmission.
azazeal88 1:cf9b0c21907a 85 * @param Payload buffer
azazeal88 1:cf9b0c21907a 86 * @param Payload buffer size
azazeal88 1:cf9b0c21907a 87 * @return Returns 0 (NoError) when data was sucessfully fowarded to radio, otherwise returns MacTransmitErrorCode.
azazeal88 1:cf9b0c21907a 88 */
azazeal88 0:a8609e6f88f3 89 uint8_t RN2483::send(uint8_t port, const uint8_t* payload, uint8_t size)
azazeal88 0:a8609e6f88f3 90 {
azazeal88 0:a8609e6f88f3 91 return macTransmit(STR_UNCONFIRMED, port, payload, size);
azazeal88 0:a8609e6f88f3 92 }
azazeal88 0:a8609e6f88f3 93
azazeal88 1:cf9b0c21907a 94 /**
azazeal88 1:cf9b0c21907a 95 * @brief Sends the given payload with acknowledgement.
azazeal88 1:cf9b0c21907a 96 * @param Port to use for transmission.
azazeal88 1:cf9b0c21907a 97 * @param Payload buffer
azazeal88 1:cf9b0c21907a 98 * @param Payload buffer size
azazeal88 1:cf9b0c21907a 99 * @param Number of transmission retries in event of network transmission failure.
azazeal88 1:cf9b0c21907a 100 * @return Returns 0 (NoError) when network acks transmission, otherwise returns MacTransmitErrorCode.
azazeal88 1:cf9b0c21907a 101 */
azazeal88 1:cf9b0c21907a 102 uint8_t RN2483::sendReqAck(uint8_t port, const uint8_t* payload, uint8_t size, uint8_t maxRetries)
azazeal88 0:a8609e6f88f3 103 {
azazeal88 0:a8609e6f88f3 104 return macTransmit(STR_CONFIRMED, port, payload, size);
azazeal88 0:a8609e6f88f3 105 }
azazeal88 0:a8609e6f88f3 106
azazeal88 1:cf9b0c21907a 107 /**
azazeal88 1:cf9b0c21907a 108 * @brief Copies the latest received packet (optionally starting from the "payloadStartPosition" of the payload).
azazeal88 1:cf9b0c21907a 109 * @param Buffer to read into.
azazeal88 1:cf9b0c21907a 110 * @param Buffer size.
azazeal88 1:cf9b0c21907a 111 * @return Returns the number of bytes written or 0 if no packet is received since last transmission.
azazeal88 1:cf9b0c21907a 112 */
azazeal88 0:a8609e6f88f3 113 uint16_t RN2483::receive(uint8_t* buffer, uint16_t size,
azazeal88 1:cf9b0c21907a 114 uint16_t payloadStartPosition)
azazeal88 0:a8609e6f88f3 115 {
azazeal88 0:a8609e6f88f3 116
azazeal88 0:a8609e6f88f3 117 if (!this->packetReceived) {
azazeal88 0:a8609e6f88f3 118 return 0;
azazeal88 0:a8609e6f88f3 119 }
azazeal88 0:a8609e6f88f3 120
azazeal88 0:a8609e6f88f3 121 uint16_t inputIndex = payloadStartPosition * 2; // payloadStartPosition is in bytes, not hex char pairs
azazeal88 0:a8609e6f88f3 122 uint16_t outputIndex = 0;
azazeal88 0:a8609e6f88f3 123
azazeal88 0:a8609e6f88f3 124 // check that the asked starting position is within bounds
azazeal88 0:a8609e6f88f3 125 if (inputIndex >= this->receivedPayloadBufferSize) {
azazeal88 0:a8609e6f88f3 126 return 0;
azazeal88 0:a8609e6f88f3 127 }
azazeal88 0:a8609e6f88f3 128
azazeal88 0:a8609e6f88f3 129 // stop at the first string termination char, or if output buffer is over, or if payload buffer is over
azazeal88 0:a8609e6f88f3 130 while (outputIndex < size
azazeal88 1:cf9b0c21907a 131 && inputIndex + 1 < this->receivedPayloadBufferSize
azazeal88 1:cf9b0c21907a 132 && this->receivedPayloadBuffer[inputIndex] != 0
azazeal88 1:cf9b0c21907a 133 && this->receivedPayloadBuffer[inputIndex + 1] != 0) {
azazeal88 0:a8609e6f88f3 134 buffer[outputIndex] = HEX_PAIR_TO_BYTE(
azazeal88 1:cf9b0c21907a 135 this->receivedPayloadBuffer[inputIndex],
azazeal88 1:cf9b0c21907a 136 this->receivedPayloadBuffer[inputIndex + 1]);
azazeal88 0:a8609e6f88f3 137
azazeal88 0:a8609e6f88f3 138 inputIndex += 2;
azazeal88 0:a8609e6f88f3 139 outputIndex++;
azazeal88 0:a8609e6f88f3 140 }
azazeal88 0:a8609e6f88f3 141
azazeal88 0:a8609e6f88f3 142 // Note: if the payload has an odd length, the last char is discarded
azazeal88 0:a8609e6f88f3 143
azazeal88 0:a8609e6f88f3 144 buffer[outputIndex] = 0; // terminate the string
azazeal88 0:a8609e6f88f3 145
azazeal88 0:a8609e6f88f3 146 return outputIndex;
azazeal88 0:a8609e6f88f3 147 }
azazeal88 0:a8609e6f88f3 148
azazeal88 1:cf9b0c21907a 149 /**
azazeal88 1:cf9b0c21907a 150 * @brief Gets the preprogrammed EUI node address from the module.
azazeal88 1:cf9b0c21907a 151 * @param Buffer to read into.
azazeal88 1:cf9b0c21907a 152 * @param Buffer size.
azazeal88 1:cf9b0c21907a 153 * @return Returns the number of bytes written or 0 in case of error..
azazeal88 1:cf9b0c21907a 154 */
azazeal88 0:a8609e6f88f3 155 uint8_t RN2483::getHWEUI(uint8_t* buffer, uint8_t size)
azazeal88 0:a8609e6f88f3 156 {
azazeal88 0:a8609e6f88f3 157 _RN2483.printf(STR_CMD_GET_HWEUI);
azazeal88 0:a8609e6f88f3 158 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 159
azazeal88 0:a8609e6f88f3 160 // TODO move to general "read hex" method
azazeal88 0:a8609e6f88f3 161 uint8_t inputIndex = 0;
azazeal88 0:a8609e6f88f3 162 uint8_t outputIndex = 0;
azazeal88 0:a8609e6f88f3 163 Timer t;
azazeal88 0:a8609e6f88f3 164 t.start();
azazeal88 0:a8609e6f88f3 165
azazeal88 1:cf9b0c21907a 166 int start = t.read_ms ();
azazeal88 0:a8609e6f88f3 167 while (t.read_ms () < start + DEFAULT_TIMEOUT) {
azazeal88 0:a8609e6f88f3 168 if (readLn() > 0) {
azazeal88 0:a8609e6f88f3 169 while (outputIndex < size
azazeal88 1:cf9b0c21907a 170 && inputIndex + 1 < this->inputBufferSize
azazeal88 1:cf9b0c21907a 171 && this->inputBuffer[inputIndex] != 0
azazeal88 1:cf9b0c21907a 172 && this->inputBuffer[inputIndex + 1] != 0) {
azazeal88 0:a8609e6f88f3 173 buffer[outputIndex] = HEX_PAIR_TO_BYTE(
azazeal88 1:cf9b0c21907a 174 this->inputBuffer[inputIndex],
azazeal88 1:cf9b0c21907a 175 this->inputBuffer[inputIndex + 1]);
azazeal88 0:a8609e6f88f3 176 inputIndex += 2;
azazeal88 0:a8609e6f88f3 177 outputIndex++;
azazeal88 0:a8609e6f88f3 178 }
azazeal88 0:a8609e6f88f3 179 t.stop();
azazeal88 0:a8609e6f88f3 180 return outputIndex;
azazeal88 0:a8609e6f88f3 181 }
azazeal88 0:a8609e6f88f3 182 }
azazeal88 1:cf9b0c21907a 183 t.stop();
azazeal88 0:a8609e6f88f3 184 return 0;
azazeal88 0:a8609e6f88f3 185 }
azazeal88 0:a8609e6f88f3 186
azazeal88 0:a8609e6f88f3 187 #ifdef ENABLE_SLEEP
azazeal88 1:cf9b0c21907a 188 /**
azazeal88 1:cf9b0c21907a 189 * @brief Sends a serial line break to wake up the RN2483
azazeal88 1:cf9b0c21907a 190 */
azazeal88 0:a8609e6f88f3 191 void RN2483::wakeUp()
azazeal88 0:a8609e6f88f3 192 {
azazeal88 0:a8609e6f88f3 193 // "emulate" break condition
azazeal88 0:a8609e6f88f3 194 _RN2483.send_break();
azazeal88 0:a8609e6f88f3 195 // set baudrate
azazeal88 0:a8609e6f88f3 196 _RN2483.baud(getDefaultBaudRate());
azazeal88 0:a8609e6f88f3 197 _RN2483.putc((uint8_t)0x55);
azazeal88 0:a8609e6f88f3 198 }
azazeal88 0:a8609e6f88f3 199
azazeal88 1:cf9b0c21907a 200 /**
azazeal88 1:cf9b0c21907a 201 * @brief Sends the RN2483 to sleep for a finite length of time.
azazeal88 1:cf9b0c21907a 202 * @param Milliseconds to sleep for.
azazeal88 1:cf9b0c21907a 203 */
azazeal88 1:cf9b0c21907a 204 void RN2483::sleep(uint32_t sleepLength)
azazeal88 1:cf9b0c21907a 205 {
azazeal88 1:cf9b0c21907a 206 if(sleepLength < 4294967296 && sleepLength > 100) {
azazeal88 1:cf9b0c21907a 207 _RN2483.printf("%s%u",STR_CMD_SLEEP,sleepLength);
azazeal88 1:cf9b0c21907a 208 _RN2483.printf(CRLF);
azazeal88 1:cf9b0c21907a 209 }
azazeal88 1:cf9b0c21907a 210 }
azazeal88 1:cf9b0c21907a 211
azazeal88 1:cf9b0c21907a 212 /**
azazeal88 1:cf9b0c21907a 213 * @brief Sends the RN2483 to sleep for a finite length of time.
azazeal88 1:cf9b0c21907a 214 * Roughly three days.
azazeal88 1:cf9b0c21907a 215 */
azazeal88 0:a8609e6f88f3 216 void RN2483::sleep()
azazeal88 0:a8609e6f88f3 217 {
azazeal88 1:cf9b0c21907a 218 sleep(4294967295);
azazeal88 0:a8609e6f88f3 219 }
azazeal88 0:a8609e6f88f3 220
azazeal88 0:a8609e6f88f3 221 #endif
azazeal88 0:a8609e6f88f3 222
azazeal88 1:cf9b0c21907a 223 /**
azazeal88 1:cf9b0c21907a 224 * @brief Reads a line from the device serial stream.
azazeal88 1:cf9b0c21907a 225 * @param Buffer to read into.
azazeal88 1:cf9b0c21907a 226 * @param Size of buffer.
azazeal88 1:cf9b0c21907a 227 * @param Position to start from.
azazeal88 1:cf9b0c21907a 228 * @return Number of bytes read.
azazeal88 1:cf9b0c21907a 229 */
azazeal88 0:a8609e6f88f3 230 uint16_t RN2483::readLn(char* buffer, uint16_t size, uint16_t start)
azazeal88 0:a8609e6f88f3 231 {
azazeal88 0:a8609e6f88f3 232 int len = readBytesUntil('\n', buffer + start, size);
azazeal88 0:a8609e6f88f3 233 if (len > 0) {
azazeal88 0:a8609e6f88f3 234 this->inputBuffer[start + len - 1] = 0; // bytes until \n always end with \r, so get rid of it (-1)
azazeal88 0:a8609e6f88f3 235 }
azazeal88 0:a8609e6f88f3 236
azazeal88 0:a8609e6f88f3 237 return len;
azazeal88 0:a8609e6f88f3 238 }
azazeal88 0:a8609e6f88f3 239
azazeal88 1:cf9b0c21907a 240 /**
azazeal88 1:cf9b0c21907a 241 * @brief Waits for the given string.
azazeal88 1:cf9b0c21907a 242 * @param String to look for.
azazeal88 1:cf9b0c21907a 243 * @param Timeout Period
azazeal88 1:cf9b0c21907a 244 * @param Position to start from.
azazeal88 1:cf9b0c21907a 245 * @return Returns true if the string is received before a timeout.
azazeal88 1:cf9b0c21907a 246 * Returns false if a timeout occurs or if another string is received.
azazeal88 1:cf9b0c21907a 247 */
azazeal88 0:a8609e6f88f3 248 bool RN2483::expectString(const char* str, uint16_t timeout)
azazeal88 0:a8609e6f88f3 249 {
azazeal88 0:a8609e6f88f3 250 Timer t;
azazeal88 0:a8609e6f88f3 251 t.start();
azazeal88 1:cf9b0c21907a 252 int start = t.read_ms();
azazeal88 0:a8609e6f88f3 253 while (t.read_ms() < start + timeout) {
azazeal88 0:a8609e6f88f3 254 if (readLn() > 0) {
azazeal88 0:a8609e6f88f3 255 if (strstr(this->inputBuffer, str) != NULL) {
azazeal88 0:a8609e6f88f3 256 t.stop();
azazeal88 0:a8609e6f88f3 257 return true;
azazeal88 0:a8609e6f88f3 258 }
azazeal88 1:cf9b0c21907a 259 t.stop();
azazeal88 0:a8609e6f88f3 260 return false;
azazeal88 0:a8609e6f88f3 261 }
azazeal88 0:a8609e6f88f3 262 }
azazeal88 0:a8609e6f88f3 263 t.stop();
azazeal88 0:a8609e6f88f3 264 return false;
azazeal88 0:a8609e6f88f3 265 }
azazeal88 0:a8609e6f88f3 266
azazeal88 1:cf9b0c21907a 267 /**
azazeal88 1:cf9b0c21907a 268 * @brief Looks for an 'OK' response from the RN2483
azazeal88 1:cf9b0c21907a 269 * @return Returns true if the string is received before a timeout.
azazeal88 1:cf9b0c21907a 270 * Returns false if a timeout occurs or if another string is received.
azazeal88 1:cf9b0c21907a 271 */
azazeal88 0:a8609e6f88f3 272 bool RN2483::expectOK()
azazeal88 0:a8609e6f88f3 273 {
azazeal88 0:a8609e6f88f3 274 return expectString(STR_RESULT_OK);
azazeal88 0:a8609e6f88f3 275 }
azazeal88 0:a8609e6f88f3 276
azazeal88 1:cf9b0c21907a 277 /**
azazeal88 1:cf9b0c21907a 278 * @brief Sends a reset command to the module
azazeal88 1:cf9b0c21907a 279 * Also sets-up some initial parameters like power index, SF and FSB channels.
azazeal88 1:cf9b0c21907a 280 * @return Waits for sucess reponse or timeout.
azazeal88 1:cf9b0c21907a 281 */
azazeal88 0:a8609e6f88f3 282 bool RN2483::resetDevice()
azazeal88 0:a8609e6f88f3 283 {
azazeal88 0:a8609e6f88f3 284 _RN2483.printf(STR_CMD_RESET);
azazeal88 0:a8609e6f88f3 285 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 286 if (expectString(STR_DEVICE_TYPE_RN)) {
azazeal88 0:a8609e6f88f3 287 if (strstr(this->inputBuffer, STR_DEVICE_TYPE_RN2483) != NULL) {
azazeal88 0:a8609e6f88f3 288 isRN2903 = false;
azazeal88 0:a8609e6f88f3 289 return setPowerIndex(DEFAULT_PWR_IDX_868) &&
azazeal88 1:cf9b0c21907a 290 setSpreadingFactor(DEFAULT_SF_868);
azazeal88 1:cf9b0c21907a 291 } else if (strstr(this->inputBuffer, STR_DEVICE_TYPE_RN2903) != NULL) {
azazeal88 0:a8609e6f88f3 292 // TODO move into init once it is decided how to handle RN2903-specific operations
azazeal88 0:a8609e6f88f3 293 isRN2903 = true;
azazeal88 0:a8609e6f88f3 294
azazeal88 0:a8609e6f88f3 295 return setFsbChannels(DEFAULT_FSB) &&
azazeal88 1:cf9b0c21907a 296 setPowerIndex(DEFAULT_PWR_IDX_915) &&
azazeal88 1:cf9b0c21907a 297 setSpreadingFactor(DEFAULT_SF_915);
azazeal88 1:cf9b0c21907a 298 } else {
azazeal88 0:a8609e6f88f3 299 return false;
azazeal88 0:a8609e6f88f3 300 }
azazeal88 0:a8609e6f88f3 301 }
azazeal88 0:a8609e6f88f3 302 return false;
azazeal88 0:a8609e6f88f3 303 }
azazeal88 0:a8609e6f88f3 304
azazeal88 1:cf9b0c21907a 305 /**
azazeal88 1:cf9b0c21907a 306 * @brief Enables all the channels that belong to the given Frequency Sub-Band (FSB)
azazeal88 1:cf9b0c21907a 307 * disables the rest.
azazeal88 1:cf9b0c21907a 308 * @param FSB is [1, 8] or 0 to enable all channels.
azazeal88 1:cf9b0c21907a 309 * @return Returns true if all channels were set successfully.
azazeal88 1:cf9b0c21907a 310 */
azazeal88 0:a8609e6f88f3 311 bool RN2483::setFsbChannels(uint8_t fsb)
azazeal88 0:a8609e6f88f3 312 {
azazeal88 0:a8609e6f88f3 313 uint8_t first125kHzChannel = fsb > 0 ? (fsb - 1) * 8 : 0;
azazeal88 0:a8609e6f88f3 314 uint8_t last125kHzChannel = fsb > 0 ? first125kHzChannel + 7 : 71;
azazeal88 0:a8609e6f88f3 315 uint8_t fsb500kHzChannel = fsb + 63;
azazeal88 0:a8609e6f88f3 316
azazeal88 0:a8609e6f88f3 317 bool allOk = true;
azazeal88 0:a8609e6f88f3 318 for (uint8_t i = 0; i < 72; i++) {
azazeal88 0:a8609e6f88f3 319 _RN2483.printf(STR_CMD_SET_CHANNEL_STATUS);
azazeal88 0:a8609e6f88f3 320 _RN2483.printf("%u",i);
azazeal88 0:a8609e6f88f3 321 _RN2483.printf(" ");
azazeal88 0:a8609e6f88f3 322 _RN2483.printf(BOOL_TO_ONOFF(((i == fsb500kHzChannel) || (i >= first125kHzChannel && i <= last125kHzChannel))));
azazeal88 0:a8609e6f88f3 323 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 324
azazeal88 0:a8609e6f88f3 325 allOk &= expectOK();
azazeal88 0:a8609e6f88f3 326 }
azazeal88 0:a8609e6f88f3 327
azazeal88 0:a8609e6f88f3 328 return allOk;
azazeal88 0:a8609e6f88f3 329 }
azazeal88 0:a8609e6f88f3 330
azazeal88 1:cf9b0c21907a 331 /**
azazeal88 1:cf9b0c21907a 332 * @brief Sets the spreading factor.
azazeal88 1:cf9b0c21907a 333 * @param Spreading factor parameter.
azazeal88 1:cf9b0c21907a 334 * @return Returns true if was set successfully.
azazeal88 1:cf9b0c21907a 335 */
azazeal88 0:a8609e6f88f3 336 bool RN2483::setSpreadingFactor(uint8_t spreadingFactor)
azazeal88 0:a8609e6f88f3 337 {
azazeal88 0:a8609e6f88f3 338 int8_t datarate;
azazeal88 0:a8609e6f88f3 339 if (!isRN2903) {
azazeal88 0:a8609e6f88f3 340 // RN2483 SF(DR) = 7(5), 8(4), 9(3), 10(2), 11(1), 12(0)
azazeal88 0:a8609e6f88f3 341 datarate = 12 - spreadingFactor;
azazeal88 1:cf9b0c21907a 342 } else {
azazeal88 0:a8609e6f88f3 343 // RN2903 SF(DR) = 7(3), 8(2), 9(1), 10(0)
azazeal88 0:a8609e6f88f3 344 datarate = 10 - spreadingFactor;
azazeal88 0:a8609e6f88f3 345 }
azazeal88 0:a8609e6f88f3 346
azazeal88 0:a8609e6f88f3 347 if (datarate > -1) {
azazeal88 0:a8609e6f88f3 348 return setMacParam(STR_DATARATE, datarate);
azazeal88 0:a8609e6f88f3 349 }
azazeal88 0:a8609e6f88f3 350
azazeal88 0:a8609e6f88f3 351 return false;
azazeal88 0:a8609e6f88f3 352 }
azazeal88 0:a8609e6f88f3 353
azazeal88 1:cf9b0c21907a 354 /**
azazeal88 1:cf9b0c21907a 355 * @brief Sets the power index
azazeal88 1:cf9b0c21907a 356 * @param 868MHz: 1 to 5 / 915MHz: 5, 7, 8, 9 or 10.
azazeal88 1:cf9b0c21907a 357 * @return Returns true if succesful.
azazeal88 1:cf9b0c21907a 358 */
azazeal88 0:a8609e6f88f3 359 bool RN2483::setPowerIndex(uint8_t powerIndex)
azazeal88 0:a8609e6f88f3 360 {
azazeal88 0:a8609e6f88f3 361 return setMacParam(STR_PWR_IDX, powerIndex);
azazeal88 0:a8609e6f88f3 362 }
azazeal88 0:a8609e6f88f3 363
azazeal88 1:cf9b0c21907a 364 /**
azazeal88 1:cf9b0c21907a 365 * @brief Sets the time interval for the link check process. When the time expires, the next application
azazeal88 1:cf9b0c21907a 366 * packet will include a link check command to the server.
azazeal88 1:cf9b0c21907a 367 * @param Decimal number that sets the time interval in seconds, from 0 to 65535. 0 disables link check process.
azazeal88 1:cf9b0c21907a 368 * @return Returns true if parameter is valid or false if time interval is not valid.
azazeal88 1:cf9b0c21907a 369 */
azazeal88 1:cf9b0c21907a 370 bool RN2483::setLinkCheckInterval(uint8_t linkCheckInterval)
azazeal88 1:cf9b0c21907a 371 {
azazeal88 1:cf9b0c21907a 372 if(linkCheckInterval <= 65535) {
azazeal88 1:cf9b0c21907a 373 return setMacParam(STR_LNK_CHK, linkCheckInterval);
azazeal88 1:cf9b0c21907a 374 } else {
azazeal88 1:cf9b0c21907a 375 return 0;
azazeal88 1:cf9b0c21907a 376 }
azazeal88 1:cf9b0c21907a 377 }
azazeal88 1:cf9b0c21907a 378
azazeal88 1:cf9b0c21907a 379 /**
azazeal88 1:cf9b0c21907a 380 * @brief Sets the battery level required for the Device Status Answer frame in LoRaWAN Class A Protocol.
azazeal88 1:cf9b0c21907a 381 * @param temperature Decimal number between 0-255 representing battery level. 0 means external power, 1 means
azazeal88 1:cf9b0c21907a 382 * low level, 254 means high level, 255 means the device was unable to measure battery level.
azazeal88 1:cf9b0c21907a 383 * @return Returns true if battery level is valid or false if value not valid.
azazeal88 1:cf9b0c21907a 384 */
azazeal88 1:cf9b0c21907a 385 bool RN2483::setBattery(uint8_t batLvl)
azazeal88 1:cf9b0c21907a 386 {
azazeal88 1:cf9b0c21907a 387 if(batLvl <= 255) {
azazeal88 1:cf9b0c21907a 388 return setMacParam(STR_BAT, batLvl);
azazeal88 1:cf9b0c21907a 389 } else {
azazeal88 1:cf9b0c21907a 390 return 0;
azazeal88 1:cf9b0c21907a 391 }
azazeal88 1:cf9b0c21907a 392 }
azazeal88 1:cf9b0c21907a 393
azazeal88 1:cf9b0c21907a 394 /**
azazeal88 1:cf9b0c21907a 395 * @brief Sets the module operation frequency on a given channel ID.
azazeal88 1:cf9b0c21907a 396 * @param Channel ID from 3 - 15.
azazeal88 1:cf9b0c21907a 397 * @param Decimal number representing the frequency.
azazeal88 1:cf9b0c21907a 398 * 863000000 to 870000000 or 433050000 to 434790000 in Hz
azazeal88 1:cf9b0c21907a 399 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 400 */
azazeal88 1:cf9b0c21907a 401 bool RN2483::setChannelFreq(uint8_t channelID, uint32_t frequency){
azazeal88 1:cf9b0c21907a 402 if((channelID <= 15 && channelID >= 3)){
azazeal88 1:cf9b0c21907a 403 if((frequency <=870000000 && frequency >= 863000000)||(frequency <=434790000 && frequency >= 433050000)){
azazeal88 1:cf9b0c21907a 404 char buffer [15];
azazeal88 1:cf9b0c21907a 405 int bytesWritten = sprintf(buffer, "%d %d", channelID, frequency);
azazeal88 1:cf9b0c21907a 406 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 407 if(bytesWritten > 0) {
azazeal88 1:cf9b0c21907a 408 setMacParam(STR_CH_FREQ, buffer);
azazeal88 1:cf9b0c21907a 409 }
azazeal88 1:cf9b0c21907a 410 }
azazeal88 1:cf9b0c21907a 411 }
azazeal88 1:cf9b0c21907a 412 return false;
azazeal88 1:cf9b0c21907a 413 }
azazeal88 1:cf9b0c21907a 414
azazeal88 1:cf9b0c21907a 415 /**
azazeal88 1:cf9b0c21907a 416 * @brief Sets the duty cycle allowed on the given channel ID.
azazeal88 1:cf9b0c21907a 417 * @param Channel ID to set duty cycle (0-15),
azazeal88 1:cf9b0c21907a 418 * @param Duty cycle is 0 - 100% as a float.
azazeal88 1:cf9b0c21907a 419 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 420 */
azazeal88 1:cf9b0c21907a 421 bool RN2483::setDutyCycle(uint8_t channelID, float dutyCycle)
azazeal88 1:cf9b0c21907a 422 {
azazeal88 1:cf9b0c21907a 423 // Convert duty cycle into the required value using equation (100 / X) - 1
azazeal88 1:cf9b0c21907a 424 if((dutyCycle <= (float)100 && dutyCycle >=(float)0) && (channelID > 15)) {
azazeal88 1:cf9b0c21907a 425 uint8_t dutyCycleSetting = ((float)100 / dutyCycle) - 1;
azazeal88 1:cf9b0c21907a 426 // Create the string for the settings
azazeal88 1:cf9b0c21907a 427 char buffer [15];
azazeal88 1:cf9b0c21907a 428 int bytesWritten = sprintf(buffer, "%d %d", channelID, dutyCycleSetting);
azazeal88 1:cf9b0c21907a 429 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 430 if(bytesWritten > 0) {
azazeal88 1:cf9b0c21907a 431 setMacParam(STR_CH_DCYCLE, buffer);
azazeal88 1:cf9b0c21907a 432 }
azazeal88 1:cf9b0c21907a 433 }
azazeal88 1:cf9b0c21907a 434 return false;
azazeal88 1:cf9b0c21907a 435 }
azazeal88 1:cf9b0c21907a 436
azazeal88 1:cf9b0c21907a 437 /**
azazeal88 1:cf9b0c21907a 438 * @brief Sets the data rate for a given channel ID.
azazeal88 1:cf9b0c21907a 439 * Please refer to the LoRaWAN spec for the actual values.
azazeal88 1:cf9b0c21907a 440 * @param Channel ID from 0 - 15.
azazeal88 1:cf9b0c21907a 441 * @param Number representing the minimum data rate range from 0 to 7.
azazeal88 1:cf9b0c21907a 442 * @param Number representing the maximum data rate range from 0 to 7
azazeal88 1:cf9b0c21907a 443 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 444 */
azazeal88 1:cf9b0c21907a 445 bool RN2483::setDrRange(uint8_t channelID, uint8_t minRange, uint8_t maxRange){
azazeal88 1:cf9b0c21907a 446 if((channelID <= 15)&&(minRange<=7)&&(maxRange<=7)){
azazeal88 1:cf9b0c21907a 447 char buffer [15];
azazeal88 1:cf9b0c21907a 448 int bytesWritten = sprintf(buffer, "%d %d %d", channelID, minRange, maxRange);
azazeal88 1:cf9b0c21907a 449 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 450 if(bytesWritten > 0) {
azazeal88 1:cf9b0c21907a 451 return setMacParam(STR_CH_DRRANGE, buffer);
azazeal88 1:cf9b0c21907a 452 }
azazeal88 1:cf9b0c21907a 453 }
azazeal88 1:cf9b0c21907a 454 return false;
azazeal88 1:cf9b0c21907a 455 }
azazeal88 1:cf9b0c21907a 456
azazeal88 1:cf9b0c21907a 457 /**
azazeal88 1:cf9b0c21907a 458 * @brief Sets a given channel ID to be enabled or disabled.
azazeal88 1:cf9b0c21907a 459 * @param Channel ID from 0 - 15.
azazeal88 1:cf9b0c21907a 460 * @param Flag representing if channel is enabled or disabled.
azazeal88 1:cf9b0c21907a 461 * Warning: duty cycle, frequency and data range must be set for a channel
azazeal88 1:cf9b0c21907a 462 * before enabling!
azazeal88 1:cf9b0c21907a 463 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 464 */
azazeal88 1:cf9b0c21907a 465 bool RN2483::setStatus(uint8_t channelID, bool status){
azazeal88 1:cf9b0c21907a 466 if((channelID <= 15)){
azazeal88 1:cf9b0c21907a 467 int bytesWritten = 0;
azazeal88 1:cf9b0c21907a 468 char buffer [15];
azazeal88 1:cf9b0c21907a 469 if(status)
azazeal88 1:cf9b0c21907a 470 bytesWritten = sprintf(buffer, "%d %s", channelID, "on");
azazeal88 1:cf9b0c21907a 471 else {
azazeal88 1:cf9b0c21907a 472 bytesWritten = sprintf(buffer, "%d %s", channelID, "off");
azazeal88 1:cf9b0c21907a 473 }
azazeal88 1:cf9b0c21907a 474 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 475 if(bytesWritten > 0) {
azazeal88 1:cf9b0c21907a 476 return setMacParam(STR_CH_STATUS, buffer);
azazeal88 1:cf9b0c21907a 477 }
azazeal88 1:cf9b0c21907a 478 }
azazeal88 1:cf9b0c21907a 479 return false;
azazeal88 1:cf9b0c21907a 480 }
azazeal88 1:cf9b0c21907a 481
azazeal88 1:cf9b0c21907a 482 /**
azazeal88 1:cf9b0c21907a 483 * @brief The network can issue a command to silence the RN2483. This restores the module.
azazeal88 1:cf9b0c21907a 484 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 485 */
azazeal88 1:cf9b0c21907a 486 bool RN2483::forceEnable(){
azazeal88 1:cf9b0c21907a 487 return sendCommand(STR_MAC_FORCEENABLE);
azazeal88 1:cf9b0c21907a 488 }
azazeal88 1:cf9b0c21907a 489
azazeal88 1:cf9b0c21907a 490 /**
azazeal88 1:cf9b0c21907a 491 * @brief Saves configurable parameters to eeprom.
azazeal88 1:cf9b0c21907a 492 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 493 */
azazeal88 1:cf9b0c21907a 494 bool RN2483::saveConfiguration(){
azazeal88 1:cf9b0c21907a 495 return sendCommand(STR_CMD_SAVE);
azazeal88 1:cf9b0c21907a 496 }
azazeal88 1:cf9b0c21907a 497
azazeal88 1:cf9b0c21907a 498 /**
azazeal88 1:cf9b0c21907a 499 * @brief Sends the command together with the given, paramValue (optional)
azazeal88 1:cf9b0c21907a 500 * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref
azazeal88 1:cf9b0c21907a 501 * @param Command Parameter to send
azazeal88 1:cf9b0c21907a 502 * @param Size of param buffer
azazeal88 1:cf9b0c21907a 503 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 504 */
azazeal88 0:a8609e6f88f3 505 bool RN2483::sendCommand(const char* command, const uint8_t* paramValue, uint16_t size)
azazeal88 0:a8609e6f88f3 506 {
azazeal88 0:a8609e6f88f3 507 _RN2483.printf(command);
azazeal88 0:a8609e6f88f3 508
azazeal88 0:a8609e6f88f3 509 for (uint16_t i = 0; i < size; ++i) {
azazeal88 0:a8609e6f88f3 510 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 511 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 512 }
azazeal88 0:a8609e6f88f3 513
azazeal88 0:a8609e6f88f3 514 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 515
azazeal88 0:a8609e6f88f3 516 return expectOK();
azazeal88 0:a8609e6f88f3 517 }
azazeal88 0:a8609e6f88f3 518
azazeal88 1:cf9b0c21907a 519 /**
azazeal88 1:cf9b0c21907a 520 * @brief Sends the command together with the given, paramValue (optional)
azazeal88 1:cf9b0c21907a 521 * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref
azazeal88 1:cf9b0c21907a 522 * @param Command Parameter to send
azazeal88 1:cf9b0c21907a 523 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 524 */
azazeal88 0:a8609e6f88f3 525 bool RN2483::sendCommand(const char* command, uint8_t paramValue)
azazeal88 0:a8609e6f88f3 526 {
azazeal88 0:a8609e6f88f3 527 _RN2483.printf(command);
azazeal88 0:a8609e6f88f3 528 _RN2483.printf("%u",paramValue);
azazeal88 0:a8609e6f88f3 529 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 530
azazeal88 0:a8609e6f88f3 531 return expectOK();
azazeal88 0:a8609e6f88f3 532 }
azazeal88 0:a8609e6f88f3 533
azazeal88 1:cf9b0c21907a 534 /**
azazeal88 1:cf9b0c21907a 535 * @brief Sends the command together with the given, paramValue (optional)
azazeal88 1:cf9b0c21907a 536 * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref
azazeal88 1:cf9b0c21907a 537 * @param Command Parameter to send
azazeal88 1:cf9b0c21907a 538 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 539 */
azazeal88 0:a8609e6f88f3 540 bool RN2483::sendCommand(const char* command, const char* paramValue)
azazeal88 0:a8609e6f88f3 541 {
azazeal88 0:a8609e6f88f3 542 _RN2483.printf(command);
azazeal88 0:a8609e6f88f3 543 if (paramValue != NULL) {
azazeal88 0:a8609e6f88f3 544 _RN2483.printf(paramValue);
azazeal88 0:a8609e6f88f3 545 }
azazeal88 0:a8609e6f88f3 546 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 547 return expectOK();
azazeal88 0:a8609e6f88f3 548 }
azazeal88 0:a8609e6f88f3 549
azazeal88 1:cf9b0c21907a 550 /**
azazeal88 1:cf9b0c21907a 551 * @brief Sends a join command to the network
azazeal88 1:cf9b0c21907a 552 * @param Type of join, OTAA or ABP
azazeal88 1:cf9b0c21907a 553 * @return Returns true on success or false if fail.
azazeal88 1:cf9b0c21907a 554 */
azazeal88 0:a8609e6f88f3 555 bool RN2483::joinNetwork(const char* type)
azazeal88 0:a8609e6f88f3 556 {
azazeal88 0:a8609e6f88f3 557 _RN2483.printf(STR_CMD_JOIN);
azazeal88 0:a8609e6f88f3 558 _RN2483.printf(type);
azazeal88 0:a8609e6f88f3 559 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 560
azazeal88 0:a8609e6f88f3 561 return expectOK() && expectString(STR_ACCEPTED, 30000);
azazeal88 0:a8609e6f88f3 562 }
azazeal88 0:a8609e6f88f3 563
azazeal88 1:cf9b0c21907a 564 /**
azazeal88 1:cf9b0c21907a 565 * @brief Sends the command together with the given paramValue (optional)
azazeal88 1:cf9b0c21907a 566 * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref.
azazeal88 1:cf9b0c21907a 567 * @param Param value to send
azazeal88 1:cf9b0c21907a 568 * @param Size of Param buffer
azazeal88 1:cf9b0c21907a 569 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 570 */
azazeal88 0:a8609e6f88f3 571 bool RN2483::setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size)
azazeal88 0:a8609e6f88f3 572 {
azazeal88 0:a8609e6f88f3 573 _RN2483.printf(STR_CMD_SET);
azazeal88 0:a8609e6f88f3 574 _RN2483.printf(paramName);
azazeal88 0:a8609e6f88f3 575
azazeal88 0:a8609e6f88f3 576 for (uint16_t i = 0; i < size; ++i) {
azazeal88 0:a8609e6f88f3 577 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 578 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 579 }
azazeal88 0:a8609e6f88f3 580
azazeal88 0:a8609e6f88f3 581 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 582
azazeal88 0:a8609e6f88f3 583 return expectOK();
azazeal88 0:a8609e6f88f3 584 }
azazeal88 0:a8609e6f88f3 585
azazeal88 1:cf9b0c21907a 586 /**
azazeal88 1:cf9b0c21907a 587 * @brief Sends the command together with the given paramValue (optional)
azazeal88 1:cf9b0c21907a 588 * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref.
azazeal88 1:cf9b0c21907a 589 * @param Param value to send
azazeal88 1:cf9b0c21907a 590 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 591 */
azazeal88 0:a8609e6f88f3 592 bool RN2483::setMacParam(const char* paramName, uint8_t paramValue)
azazeal88 0:a8609e6f88f3 593 {
azazeal88 0:a8609e6f88f3 594 _RN2483.printf(STR_CMD_SET);
azazeal88 0:a8609e6f88f3 595 _RN2483.printf(paramName);
azazeal88 0:a8609e6f88f3 596 _RN2483.printf("%u",paramValue);
azazeal88 0:a8609e6f88f3 597 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 598
azazeal88 0:a8609e6f88f3 599 return expectOK();
azazeal88 0:a8609e6f88f3 600 }
azazeal88 0:a8609e6f88f3 601
azazeal88 1:cf9b0c21907a 602 /**
azazeal88 1:cf9b0c21907a 603 * @brief Sends the command together with the given paramValue (optional)
azazeal88 1:cf9b0c21907a 604 * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref.
azazeal88 1:cf9b0c21907a 605 * @param Param value to send
azazeal88 1:cf9b0c21907a 606 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 607 */
azazeal88 0:a8609e6f88f3 608 bool RN2483::setMacParam(const char* paramName, const char* paramValue)
azazeal88 0:a8609e6f88f3 609 {
azazeal88 0:a8609e6f88f3 610 _RN2483.printf(STR_CMD_SET);
azazeal88 0:a8609e6f88f3 611 _RN2483.printf(paramName);
azazeal88 0:a8609e6f88f3 612 _RN2483.printf(paramValue);
azazeal88 0:a8609e6f88f3 613 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 614
azazeal88 0:a8609e6f88f3 615 return expectOK();
azazeal88 0:a8609e6f88f3 616 }
azazeal88 0:a8609e6f88f3 617
azazeal88 1:cf9b0c21907a 618 /**
azazeal88 1:cf9b0c21907a 619 * @brief Returns the enum that is mapped to the given "error" message
azazeal88 1:cf9b0c21907a 620 * @param Error to lookup.
azazeal88 1:cf9b0c21907a 621 * @return Returns the enum.
azazeal88 1:cf9b0c21907a 622 */
azazeal88 0:a8609e6f88f3 623 uint8_t RN2483::lookupMacTransmitError(const char* error)
azazeal88 0:a8609e6f88f3 624 {
azazeal88 0:a8609e6f88f3 625 if (error[0] == 0) {
azazeal88 0:a8609e6f88f3 626 return NoResponse;
azazeal88 0:a8609e6f88f3 627 }
azazeal88 0:a8609e6f88f3 628
azazeal88 1:cf9b0c21907a 629 StringEnumPair_t errorTable[] = {
azazeal88 0:a8609e6f88f3 630 { STR_RESULT_INVALID_PARAM, InternalError },
azazeal88 0:a8609e6f88f3 631 { STR_RESULT_NOT_JOINED, NotConnected },
azazeal88 0:a8609e6f88f3 632 { STR_RESULT_NO_FREE_CHANNEL, Busy },
azazeal88 0:a8609e6f88f3 633 { STR_RESULT_SILENT, Busy },
azazeal88 0:a8609e6f88f3 634 { STR_RESULT_FRAME_COUNTER_ERROR, NetworkFatalError },
azazeal88 0:a8609e6f88f3 635 { STR_RESULT_BUSY, Busy },
azazeal88 0:a8609e6f88f3 636 { STR_RESULT_MAC_PAUSED, InternalError },
azazeal88 0:a8609e6f88f3 637 { STR_RESULT_INVALID_DATA_LEN, PayloadSizeError },
azazeal88 0:a8609e6f88f3 638 { STR_RESULT_MAC_ERROR, NoAcknowledgment },
azazeal88 0:a8609e6f88f3 639 };
azazeal88 0:a8609e6f88f3 640
azazeal88 0:a8609e6f88f3 641 for (StringEnumPair_t * p = errorTable; p->stringValue != NULL; ++p) {
azazeal88 0:a8609e6f88f3 642 if (strcmp(p->stringValue, error) == 0) {
azazeal88 0:a8609e6f88f3 643 return p->enumValue;
azazeal88 0:a8609e6f88f3 644 }
azazeal88 0:a8609e6f88f3 645 }
azazeal88 0:a8609e6f88f3 646
azazeal88 0:a8609e6f88f3 647 return NoResponse;
azazeal88 0:a8609e6f88f3 648 }
azazeal88 0:a8609e6f88f3 649
azazeal88 1:cf9b0c21907a 650 /**
azazeal88 1:cf9b0c21907a 651 * @brief Sends a a payload and blocks until there is a response back,
azazeal88 1:cf9b0c21907a 652 * or the receive windows have closed or the hard timeout has passed.
azazeal88 1:cf9b0c21907a 653 * @param Transmit type
azazeal88 1:cf9b0c21907a 654 * @param Port to use for transmit
azazeal88 1:cf9b0c21907a 655 * @param Payload buffer
azazeal88 1:cf9b0c21907a 656 * @param Size of payload buffer
azazeal88 1:cf9b0c21907a 657 * @return Returns if sucessfull or if a MAC transmit error.
azazeal88 1:cf9b0c21907a 658 */
azazeal88 0:a8609e6f88f3 659 uint8_t RN2483::macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size)
azazeal88 0:a8609e6f88f3 660 {
azazeal88 0:a8609e6f88f3 661 _RN2483.printf(STR_CMD_MAC_TX);
azazeal88 0:a8609e6f88f3 662 _RN2483.printf(type);
azazeal88 0:a8609e6f88f3 663 _RN2483.printf("%u",port);
azazeal88 0:a8609e6f88f3 664 _RN2483.printf(" ");
azazeal88 0:a8609e6f88f3 665
azazeal88 0:a8609e6f88f3 666 for (int i = 0; i < size; ++i) {
azazeal88 0:a8609e6f88f3 667 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(payload[i]))));
azazeal88 0:a8609e6f88f3 668 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(payload[i]))));
azazeal88 0:a8609e6f88f3 669 }
azazeal88 0:a8609e6f88f3 670
azazeal88 0:a8609e6f88f3 671 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 672
azazeal88 0:a8609e6f88f3 673 if (!expectOK()) {
azazeal88 0:a8609e6f88f3 674 return lookupMacTransmitError(this->inputBuffer); // inputBuffer still has the last line read
azazeal88 0:a8609e6f88f3 675 }
azazeal88 0:a8609e6f88f3 676
azazeal88 0:a8609e6f88f3 677 this->packetReceived = false; // prepare for receiving a new packet
azazeal88 0:a8609e6f88f3 678 Timer t;
azazeal88 0:a8609e6f88f3 679 t.start();
azazeal88 1:cf9b0c21907a 680 int timeout = t.read_ms() + RECEIVE_TIMEOUT; // hard timeouts
azazeal88 0:a8609e6f88f3 681 while (t.read_ms() < timeout) {
azazeal88 0:a8609e6f88f3 682 if (readLn() > 0) {
azazeal88 1:cf9b0c21907a 683 if (strstr(this->inputBuffer, " ") != NULL) { // to avoid double delimiter search
azazeal88 0:a8609e6f88f3 684 // there is a splittable line -only case known is mac_rx
azazeal88 0:a8609e6f88f3 685 t.stop();
azazeal88 0:a8609e6f88f3 686 return onMacRX();
azazeal88 1:cf9b0c21907a 687 } else if (strstr(this->inputBuffer, STR_RESULT_MAC_TX_OK)) {
azazeal88 0:a8609e6f88f3 688 // done
azazeal88 0:a8609e6f88f3 689 t.stop();
azazeal88 0:a8609e6f88f3 690 return NoError;
azazeal88 1:cf9b0c21907a 691 } else {
azazeal88 0:a8609e6f88f3 692 // lookup the error message
azazeal88 0:a8609e6f88f3 693 t.stop();
azazeal88 0:a8609e6f88f3 694 return lookupMacTransmitError(this->inputBuffer);
azazeal88 0:a8609e6f88f3 695 }
azazeal88 0:a8609e6f88f3 696 }
azazeal88 0:a8609e6f88f3 697 }
azazeal88 1:cf9b0c21907a 698 t.stop();
azazeal88 0:a8609e6f88f3 699 return Timedout;
azazeal88 0:a8609e6f88f3 700 }
azazeal88 0:a8609e6f88f3 701
azazeal88 1:cf9b0c21907a 702 /**
azazeal88 1:cf9b0c21907a 703 * @brief Parses the input buffer and copies the received payload into
azazeal88 1:cf9b0c21907a 704 * the "received payload" buffer when a "mac rx" message has been received.
azazeal88 1:cf9b0c21907a 705 * @return Returns 0 (NoError) or otherwise one of the MacTransmitErrorCodes.
azazeal88 1:cf9b0c21907a 706 */
azazeal88 0:a8609e6f88f3 707 uint8_t RN2483::onMacRX()
azazeal88 0:a8609e6f88f3 708 {
azazeal88 0:a8609e6f88f3 709 // parse inputbuffer, put payload into packet buffer
azazeal88 0:a8609e6f88f3 710 char* token = strtok(this->inputBuffer, " ");
azazeal88 0:a8609e6f88f3 711
azazeal88 0:a8609e6f88f3 712 // sanity check
azazeal88 0:a8609e6f88f3 713 if (strcmp(token, STR_RESULT_MAC_RX) != 0) {
azazeal88 0:a8609e6f88f3 714 return InternalError;
azazeal88 0:a8609e6f88f3 715 }
azazeal88 0:a8609e6f88f3 716
azazeal88 0:a8609e6f88f3 717 // port
azazeal88 0:a8609e6f88f3 718 token = strtok(NULL, " ");
azazeal88 0:a8609e6f88f3 719
azazeal88 0:a8609e6f88f3 720 // payload
azazeal88 0:a8609e6f88f3 721 token = strtok(NULL, " "); // until end of string
azazeal88 0:a8609e6f88f3 722
azazeal88 0:a8609e6f88f3 723 uint16_t len = strlen(token) + 1; // include termination char
azazeal88 0:a8609e6f88f3 724 memcpy(this->receivedPayloadBuffer, token, len <= this->receivedPayloadBufferSize ? len : this->receivedPayloadBufferSize);
azazeal88 0:a8609e6f88f3 725
azazeal88 0:a8609e6f88f3 726 this->packetReceived = true; // enable receive() again
azazeal88 0:a8609e6f88f3 727 return NoError;
azazeal88 0:a8609e6f88f3 728 }
azazeal88 0:a8609e6f88f3 729
azazeal88 1:cf9b0c21907a 730 /**
azazeal88 1:cf9b0c21907a 731 * @brief Private method to read serial port with timeout
azazeal88 1:cf9b0c21907a 732 * @param The time to wait for in milliseconds.
azazeal88 1:cf9b0c21907a 733 * @return Returns character or -1 on timeout
azazeal88 1:cf9b0c21907a 734 */
azazeal88 1:cf9b0c21907a 735 int RN2483::timedRead(int _timeout)
azazeal88 1:cf9b0c21907a 736 {
azazeal88 0:a8609e6f88f3 737 int c;
azazeal88 0:a8609e6f88f3 738 Timer t;
azazeal88 0:a8609e6f88f3 739 t.start();
azazeal88 1:cf9b0c21907a 740 int _startMillis = t.read_ms(); // get milliseconds
azazeal88 1:cf9b0c21907a 741 while (! _RN2483.readable() && t.read_ms() - _startMillis <_timeout) {
azazeal88 1:cf9b0c21907a 742 #ifdef YOTTA_CFG_MBED_OS
azazeal88 1:cf9b0c21907a 743 Thread::yield();
azazeal88 1:cf9b0c21907a 744 #else
azazeal88 1:cf9b0c21907a 745 wait_ms(10);
azazeal88 1:cf9b0c21907a 746 #endif
azazeal88 1:cf9b0c21907a 747 }
azazeal88 0:a8609e6f88f3 748 t.stop();
azazeal88 1:cf9b0c21907a 749 if(_RN2483.readable()) {
azazeal88 1:cf9b0c21907a 750 c = _RN2483.getc();
azazeal88 1:cf9b0c21907a 751 if (c >= 0) {
azazeal88 1:cf9b0c21907a 752 return c;
azazeal88 1:cf9b0c21907a 753 }
azazeal88 1:cf9b0c21907a 754 }
azazeal88 0:a8609e6f88f3 755 return -1; // -1 indicates timeout
azazeal88 1:cf9b0c21907a 756 }
azazeal88 0:a8609e6f88f3 757
azazeal88 1:cf9b0c21907a 758 /**
azazeal88 1:cf9b0c21907a 759 * @brief Read characters into buffer.
azazeal88 1:cf9b0c21907a 760 * Terminates if length characters have been read, timeout, or
azazeal88 1:cf9b0c21907a 761 * if the terminator character has been detected
azazeal88 1:cf9b0c21907a 762 * @param The terminator character to look for
azazeal88 1:cf9b0c21907a 763 * @param The buffer to read into.
azazeal88 1:cf9b0c21907a 764 * @param The size of the buffer.
azazeal88 1:cf9b0c21907a 765 * @return The number of bytes read. 0 means no valid data found.
azazeal88 1:cf9b0c21907a 766 */
azazeal88 0:a8609e6f88f3 767 size_t RN2483::readBytesUntil(char terminator, char *buffer, size_t length)
azazeal88 0:a8609e6f88f3 768 {
azazeal88 0:a8609e6f88f3 769 if (length < 1) return 0;
azazeal88 0:a8609e6f88f3 770 size_t index = 0;
azazeal88 0:a8609e6f88f3 771 while (index < length) {
azazeal88 0:a8609e6f88f3 772 int c = timedRead(1000);
azazeal88 0:a8609e6f88f3 773 if (c < 0 || c == terminator) break;
azazeal88 0:a8609e6f88f3 774 *buffer++ = (char)c;
azazeal88 0:a8609e6f88f3 775 index++;
azazeal88 0:a8609e6f88f3 776 }
azazeal88 1:cf9b0c21907a 777 return index; // return number of characters, not including null terminator
azazeal88 1:cf9b0c21907a 778 }
azazeal88 0:a8609e6f88f3 779
azazeal88 0:a8609e6f88f3 780 #ifdef DEBUG
azazeal88 0:a8609e6f88f3 781 int freeRam()
azazeal88 0:a8609e6f88f3 782 {
azazeal88 0:a8609e6f88f3 783 extern int __heap_start;
azazeal88 0:a8609e6f88f3 784 extern int *__brkval;
azazeal88 0:a8609e6f88f3 785 int v;
azazeal88 0:a8609e6f88f3 786 return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
azazeal88 0:a8609e6f88f3 787 }
azazeal88 0:a8609e6f88f3 788 #endif