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:
Tue Nov 22 10:39:17 2016 +0000
Revision:
7:100ab85cc6d7
Parent:
6:7b3abd00c921
Child:
8:c4069091afa1
Allowed expectOK to specify a timeout value.

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