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:
Mon Nov 21 16:36:54 2016 +0000
Revision:
3:ee222a99783c
Parent:
2:336a025b82b5
Child:
4:0c066401ae12
Fixed some of the library. Still not happy with getVDD() due to strtol conversion doesn't handle errors yet.

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 3:ee222a99783c 213 * @return Returns mV as a decimal from 0 to 3600. -1 on error.
azazeal88 2:336a025b82b5 214 */
azazeal88 3:ee222a99783c 215 long RN2483::getVDD()
azazeal88 2:336a025b82b5 216 {
azazeal88 2:336a025b82b5 217 _RN2483.printf(STR_CMD_GET_VDD);
azazeal88 2:336a025b82b5 218 _RN2483.printf(CRLF);
azazeal88 2:336a025b82b5 219 char buffer[10];
azazeal88 3:ee222a99783c 220 if(readBytesUntil('\n', buffer, 10)) {
azazeal88 3:ee222a99783c 221 return strtol(buffer,NULL ,10);
azazeal88 2:336a025b82b5 222 }
azazeal88 3:ee222a99783c 223 return false;
azazeal88 2:336a025b82b5 224 }
azazeal88 2:336a025b82b5 225
azazeal88 0:a8609e6f88f3 226 #ifdef ENABLE_SLEEP
azazeal88 1:cf9b0c21907a 227 /**
azazeal88 1:cf9b0c21907a 228 * @brief Sends a serial line break to wake up the RN2483
azazeal88 1:cf9b0c21907a 229 */
azazeal88 0:a8609e6f88f3 230 void RN2483::wakeUp()
azazeal88 0:a8609e6f88f3 231 {
azazeal88 0:a8609e6f88f3 232 // "emulate" break condition
azazeal88 0:a8609e6f88f3 233 _RN2483.send_break();
azazeal88 0:a8609e6f88f3 234 // set baudrate
azazeal88 0:a8609e6f88f3 235 _RN2483.baud(getDefaultBaudRate());
azazeal88 0:a8609e6f88f3 236 _RN2483.putc((uint8_t)0x55);
azazeal88 0:a8609e6f88f3 237 }
azazeal88 0:a8609e6f88f3 238
azazeal88 1:cf9b0c21907a 239 /**
azazeal88 1:cf9b0c21907a 240 * @brief Sends the RN2483 to sleep for a finite length of time.
azazeal88 1:cf9b0c21907a 241 * @param Milliseconds to sleep for.
azazeal88 1:cf9b0c21907a 242 */
azazeal88 1:cf9b0c21907a 243 void RN2483::sleep(uint32_t sleepLength)
azazeal88 1:cf9b0c21907a 244 {
azazeal88 1:cf9b0c21907a 245 if(sleepLength < 4294967296 && sleepLength > 100) {
azazeal88 1:cf9b0c21907a 246 _RN2483.printf("%s%u",STR_CMD_SLEEP,sleepLength);
azazeal88 1:cf9b0c21907a 247 _RN2483.printf(CRLF);
azazeal88 1:cf9b0c21907a 248 }
azazeal88 1:cf9b0c21907a 249 }
azazeal88 1:cf9b0c21907a 250
azazeal88 1:cf9b0c21907a 251 /**
azazeal88 1:cf9b0c21907a 252 * @brief Sends the RN2483 to sleep for a finite length of time.
azazeal88 1:cf9b0c21907a 253 * Roughly three days.
azazeal88 1:cf9b0c21907a 254 */
azazeal88 0:a8609e6f88f3 255 void RN2483::sleep()
azazeal88 0:a8609e6f88f3 256 {
azazeal88 1:cf9b0c21907a 257 sleep(4294967295);
azazeal88 0:a8609e6f88f3 258 }
azazeal88 0:a8609e6f88f3 259
azazeal88 0:a8609e6f88f3 260 #endif
azazeal88 0:a8609e6f88f3 261
azazeal88 1:cf9b0c21907a 262 /**
azazeal88 1:cf9b0c21907a 263 * @brief Reads a line from the device serial stream.
azazeal88 1:cf9b0c21907a 264 * @param Buffer to read into.
azazeal88 1:cf9b0c21907a 265 * @param Size of buffer.
azazeal88 1:cf9b0c21907a 266 * @param Position to start from.
azazeal88 1:cf9b0c21907a 267 * @return Number of bytes read.
azazeal88 1:cf9b0c21907a 268 */
azazeal88 0:a8609e6f88f3 269 uint16_t RN2483::readLn(char* buffer, uint16_t size, uint16_t start)
azazeal88 0:a8609e6f88f3 270 {
azazeal88 0:a8609e6f88f3 271 int len = readBytesUntil('\n', buffer + start, size);
azazeal88 0:a8609e6f88f3 272 if (len > 0) {
azazeal88 0:a8609e6f88f3 273 this->inputBuffer[start + len - 1] = 0; // bytes until \n always end with \r, so get rid of it (-1)
azazeal88 0:a8609e6f88f3 274 }
azazeal88 0:a8609e6f88f3 275
azazeal88 0:a8609e6f88f3 276 return len;
azazeal88 0:a8609e6f88f3 277 }
azazeal88 0:a8609e6f88f3 278
azazeal88 1:cf9b0c21907a 279 /**
azazeal88 1:cf9b0c21907a 280 * @brief Waits for the given string.
azazeal88 1:cf9b0c21907a 281 * @param String to look for.
azazeal88 1:cf9b0c21907a 282 * @param Timeout Period
azazeal88 1:cf9b0c21907a 283 * @param Position to start from.
azazeal88 1:cf9b0c21907a 284 * @return Returns true if the string is received before a timeout.
azazeal88 1:cf9b0c21907a 285 * Returns false if a timeout occurs or if another string is received.
azazeal88 1:cf9b0c21907a 286 */
azazeal88 0:a8609e6f88f3 287 bool RN2483::expectString(const char* str, uint16_t timeout)
azazeal88 0:a8609e6f88f3 288 {
azazeal88 0:a8609e6f88f3 289 Timer t;
azazeal88 0:a8609e6f88f3 290 t.start();
azazeal88 1:cf9b0c21907a 291 int start = t.read_ms();
azazeal88 0:a8609e6f88f3 292 while (t.read_ms() < start + timeout) {
azazeal88 0:a8609e6f88f3 293 if (readLn() > 0) {
azazeal88 0:a8609e6f88f3 294 if (strstr(this->inputBuffer, str) != NULL) {
azazeal88 0:a8609e6f88f3 295 t.stop();
azazeal88 0:a8609e6f88f3 296 return true;
azazeal88 0:a8609e6f88f3 297 }
azazeal88 1:cf9b0c21907a 298 t.stop();
azazeal88 0:a8609e6f88f3 299 return false;
azazeal88 0:a8609e6f88f3 300 }
azazeal88 0:a8609e6f88f3 301 }
azazeal88 0:a8609e6f88f3 302 t.stop();
azazeal88 0:a8609e6f88f3 303 return false;
azazeal88 0:a8609e6f88f3 304 }
azazeal88 0:a8609e6f88f3 305
azazeal88 1:cf9b0c21907a 306 /**
azazeal88 1:cf9b0c21907a 307 * @brief Looks for an 'OK' response from the RN2483
azazeal88 1:cf9b0c21907a 308 * @return Returns true if the string is received before a timeout.
azazeal88 1:cf9b0c21907a 309 * Returns false if a timeout occurs or if another string is received.
azazeal88 1:cf9b0c21907a 310 */
azazeal88 0:a8609e6f88f3 311 bool RN2483::expectOK()
azazeal88 0:a8609e6f88f3 312 {
azazeal88 0:a8609e6f88f3 313 return expectString(STR_RESULT_OK);
azazeal88 0:a8609e6f88f3 314 }
azazeal88 0:a8609e6f88f3 315
azazeal88 1:cf9b0c21907a 316 /**
azazeal88 1:cf9b0c21907a 317 * @brief Sends a reset command to the module
azazeal88 1:cf9b0c21907a 318 * Also sets-up some initial parameters like power index, SF and FSB channels.
azazeal88 1:cf9b0c21907a 319 * @return Waits for sucess reponse or timeout.
azazeal88 1:cf9b0c21907a 320 */
azazeal88 0:a8609e6f88f3 321 bool RN2483::resetDevice()
azazeal88 0:a8609e6f88f3 322 {
azazeal88 0:a8609e6f88f3 323 _RN2483.printf(STR_CMD_RESET);
azazeal88 0:a8609e6f88f3 324 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 325 if (expectString(STR_DEVICE_TYPE_RN)) {
azazeal88 0:a8609e6f88f3 326 if (strstr(this->inputBuffer, STR_DEVICE_TYPE_RN2483) != NULL) {
azazeal88 0:a8609e6f88f3 327 isRN2903 = false;
azazeal88 0:a8609e6f88f3 328 return setPowerIndex(DEFAULT_PWR_IDX_868) &&
azazeal88 1:cf9b0c21907a 329 setSpreadingFactor(DEFAULT_SF_868);
azazeal88 1:cf9b0c21907a 330 } else if (strstr(this->inputBuffer, STR_DEVICE_TYPE_RN2903) != NULL) {
azazeal88 0:a8609e6f88f3 331 // TODO move into init once it is decided how to handle RN2903-specific operations
azazeal88 0:a8609e6f88f3 332 isRN2903 = true;
azazeal88 0:a8609e6f88f3 333
azazeal88 0:a8609e6f88f3 334 return setFsbChannels(DEFAULT_FSB) &&
azazeal88 1:cf9b0c21907a 335 setPowerIndex(DEFAULT_PWR_IDX_915) &&
azazeal88 1:cf9b0c21907a 336 setSpreadingFactor(DEFAULT_SF_915);
azazeal88 1:cf9b0c21907a 337 } else {
azazeal88 0:a8609e6f88f3 338 return false;
azazeal88 0:a8609e6f88f3 339 }
azazeal88 0:a8609e6f88f3 340 }
azazeal88 0:a8609e6f88f3 341 return false;
azazeal88 0:a8609e6f88f3 342 }
azazeal88 0:a8609e6f88f3 343
azazeal88 1:cf9b0c21907a 344 /**
azazeal88 1:cf9b0c21907a 345 * @brief Enables all the channels that belong to the given Frequency Sub-Band (FSB)
azazeal88 1:cf9b0c21907a 346 * disables the rest.
azazeal88 1:cf9b0c21907a 347 * @param FSB is [1, 8] or 0 to enable all channels.
azazeal88 1:cf9b0c21907a 348 * @return Returns true if all channels were set successfully.
azazeal88 1:cf9b0c21907a 349 */
azazeal88 0:a8609e6f88f3 350 bool RN2483::setFsbChannels(uint8_t fsb)
azazeal88 0:a8609e6f88f3 351 {
azazeal88 0:a8609e6f88f3 352 uint8_t first125kHzChannel = fsb > 0 ? (fsb - 1) * 8 : 0;
azazeal88 0:a8609e6f88f3 353 uint8_t last125kHzChannel = fsb > 0 ? first125kHzChannel + 7 : 71;
azazeal88 0:a8609e6f88f3 354 uint8_t fsb500kHzChannel = fsb + 63;
azazeal88 0:a8609e6f88f3 355
azazeal88 0:a8609e6f88f3 356 bool allOk = true;
azazeal88 0:a8609e6f88f3 357 for (uint8_t i = 0; i < 72; i++) {
azazeal88 0:a8609e6f88f3 358 _RN2483.printf(STR_CMD_SET_CHANNEL_STATUS);
azazeal88 0:a8609e6f88f3 359 _RN2483.printf("%u",i);
azazeal88 0:a8609e6f88f3 360 _RN2483.printf(" ");
azazeal88 0:a8609e6f88f3 361 _RN2483.printf(BOOL_TO_ONOFF(((i == fsb500kHzChannel) || (i >= first125kHzChannel && i <= last125kHzChannel))));
azazeal88 0:a8609e6f88f3 362 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 363
azazeal88 0:a8609e6f88f3 364 allOk &= expectOK();
azazeal88 0:a8609e6f88f3 365 }
azazeal88 0:a8609e6f88f3 366
azazeal88 0:a8609e6f88f3 367 return allOk;
azazeal88 0:a8609e6f88f3 368 }
azazeal88 0:a8609e6f88f3 369
azazeal88 1:cf9b0c21907a 370 /**
azazeal88 1:cf9b0c21907a 371 * @brief Sets the spreading factor.
azazeal88 1:cf9b0c21907a 372 * @param Spreading factor parameter.
azazeal88 1:cf9b0c21907a 373 * @return Returns true if was set successfully.
azazeal88 1:cf9b0c21907a 374 */
azazeal88 0:a8609e6f88f3 375 bool RN2483::setSpreadingFactor(uint8_t spreadingFactor)
azazeal88 0:a8609e6f88f3 376 {
azazeal88 0:a8609e6f88f3 377 int8_t datarate;
azazeal88 0:a8609e6f88f3 378 if (!isRN2903) {
azazeal88 0:a8609e6f88f3 379 // RN2483 SF(DR) = 7(5), 8(4), 9(3), 10(2), 11(1), 12(0)
azazeal88 0:a8609e6f88f3 380 datarate = 12 - spreadingFactor;
azazeal88 1:cf9b0c21907a 381 } else {
azazeal88 0:a8609e6f88f3 382 // RN2903 SF(DR) = 7(3), 8(2), 9(1), 10(0)
azazeal88 0:a8609e6f88f3 383 datarate = 10 - spreadingFactor;
azazeal88 0:a8609e6f88f3 384 }
azazeal88 0:a8609e6f88f3 385
azazeal88 0:a8609e6f88f3 386 if (datarate > -1) {
azazeal88 0:a8609e6f88f3 387 return setMacParam(STR_DATARATE, datarate);
azazeal88 0:a8609e6f88f3 388 }
azazeal88 0:a8609e6f88f3 389
azazeal88 0:a8609e6f88f3 390 return false;
azazeal88 0:a8609e6f88f3 391 }
azazeal88 0:a8609e6f88f3 392
azazeal88 1:cf9b0c21907a 393 /**
azazeal88 1:cf9b0c21907a 394 * @brief Sets the power index
azazeal88 1:cf9b0c21907a 395 * @param 868MHz: 1 to 5 / 915MHz: 5, 7, 8, 9 or 10.
azazeal88 1:cf9b0c21907a 396 * @return Returns true if succesful.
azazeal88 1:cf9b0c21907a 397 */
azazeal88 0:a8609e6f88f3 398 bool RN2483::setPowerIndex(uint8_t powerIndex)
azazeal88 0:a8609e6f88f3 399 {
azazeal88 0:a8609e6f88f3 400 return setMacParam(STR_PWR_IDX, powerIndex);
azazeal88 0:a8609e6f88f3 401 }
azazeal88 0:a8609e6f88f3 402
azazeal88 1:cf9b0c21907a 403 /**
azazeal88 1:cf9b0c21907a 404 * @brief Sets the time interval for the link check process. When the time expires, the next application
azazeal88 1:cf9b0c21907a 405 * packet will include a link check command to the server.
azazeal88 1:cf9b0c21907a 406 * @param Decimal number that sets the time interval in seconds, from 0 to 65535. 0 disables link check process.
azazeal88 1:cf9b0c21907a 407 * @return Returns true if parameter is valid or false if time interval is not valid.
azazeal88 1:cf9b0c21907a 408 */
azazeal88 1:cf9b0c21907a 409 bool RN2483::setLinkCheckInterval(uint8_t linkCheckInterval)
azazeal88 1:cf9b0c21907a 410 {
azazeal88 1:cf9b0c21907a 411 if(linkCheckInterval <= 65535) {
azazeal88 1:cf9b0c21907a 412 return setMacParam(STR_LNK_CHK, linkCheckInterval);
azazeal88 1:cf9b0c21907a 413 } else {
azazeal88 2:336a025b82b5 414 return false;
azazeal88 1:cf9b0c21907a 415 }
azazeal88 1:cf9b0c21907a 416 }
azazeal88 1:cf9b0c21907a 417
azazeal88 1:cf9b0c21907a 418 /**
azazeal88 1:cf9b0c21907a 419 * @brief Sets the battery level required for the Device Status Answer frame in LoRaWAN Class A Protocol.
azazeal88 1:cf9b0c21907a 420 * @param temperature Decimal number between 0-255 representing battery level. 0 means external power, 1 means
azazeal88 1:cf9b0c21907a 421 * low level, 254 means high level, 255 means the device was unable to measure battery level.
azazeal88 1:cf9b0c21907a 422 * @return Returns true if battery level is valid or false if value not valid.
azazeal88 1:cf9b0c21907a 423 */
azazeal88 1:cf9b0c21907a 424 bool RN2483::setBattery(uint8_t batLvl)
azazeal88 1:cf9b0c21907a 425 {
azazeal88 1:cf9b0c21907a 426 if(batLvl <= 255) {
azazeal88 1:cf9b0c21907a 427 return setMacParam(STR_BAT, batLvl);
azazeal88 1:cf9b0c21907a 428 } else {
azazeal88 2:336a025b82b5 429 return false;
azazeal88 1:cf9b0c21907a 430 }
azazeal88 1:cf9b0c21907a 431 }
azazeal88 1:cf9b0c21907a 432
azazeal88 1:cf9b0c21907a 433 /**
azazeal88 1:cf9b0c21907a 434 * @brief Sets the module operation frequency on a given channel ID.
azazeal88 1:cf9b0c21907a 435 * @param Channel ID from 3 - 15.
azazeal88 1:cf9b0c21907a 436 * @param Decimal number representing the frequency.
azazeal88 1:cf9b0c21907a 437 * 863000000 to 870000000 or 433050000 to 434790000 in Hz
azazeal88 1:cf9b0c21907a 438 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 439 */
azazeal88 2:336a025b82b5 440 bool RN2483::setChannelFreq(uint8_t channelID, uint32_t frequency)
azazeal88 2:336a025b82b5 441 {
azazeal88 2:336a025b82b5 442 if((channelID <= 15 && channelID >= 3)) {
azazeal88 2:336a025b82b5 443 if((frequency <=870000000 && frequency >= 863000000)||(frequency <=434790000 && frequency >= 433050000)) {
azazeal88 1:cf9b0c21907a 444 char buffer [15];
azazeal88 1:cf9b0c21907a 445 int bytesWritten = sprintf(buffer, "%d %d", channelID, frequency);
azazeal88 1:cf9b0c21907a 446 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 447 if(bytesWritten > 0) {
azazeal88 2:336a025b82b5 448 return setMacParam(STR_CH_FREQ, buffer);
azazeal88 2:336a025b82b5 449 }
azazeal88 2:336a025b82b5 450 }
azazeal88 1:cf9b0c21907a 451 }
azazeal88 1:cf9b0c21907a 452 return false;
azazeal88 1:cf9b0c21907a 453 }
azazeal88 1:cf9b0c21907a 454
azazeal88 1:cf9b0c21907a 455 /**
azazeal88 1:cf9b0c21907a 456 * @brief Sets the duty cycle allowed on the given channel ID.
azazeal88 1:cf9b0c21907a 457 * @param Channel ID to set duty cycle (0-15),
azazeal88 1:cf9b0c21907a 458 * @param Duty cycle is 0 - 100% as a float.
azazeal88 1:cf9b0c21907a 459 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 460 */
azazeal88 1:cf9b0c21907a 461 bool RN2483::setDutyCycle(uint8_t channelID, float dutyCycle)
azazeal88 1:cf9b0c21907a 462 {
azazeal88 1:cf9b0c21907a 463 // Convert duty cycle into the required value using equation (100 / X) - 1
azazeal88 1:cf9b0c21907a 464 if((dutyCycle <= (float)100 && dutyCycle >=(float)0) && (channelID > 15)) {
azazeal88 1:cf9b0c21907a 465 uint8_t dutyCycleSetting = ((float)100 / dutyCycle) - 1;
azazeal88 1:cf9b0c21907a 466 // Create the string for the settings
azazeal88 1:cf9b0c21907a 467 char buffer [15];
azazeal88 1:cf9b0c21907a 468 int bytesWritten = sprintf(buffer, "%d %d", channelID, dutyCycleSetting);
azazeal88 1:cf9b0c21907a 469 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 470 if(bytesWritten > 0) {
azazeal88 2:336a025b82b5 471 return setMacParam(STR_CH_DCYCLE, buffer);
azazeal88 1:cf9b0c21907a 472 }
azazeal88 1:cf9b0c21907a 473 }
azazeal88 1:cf9b0c21907a 474 return false;
azazeal88 1:cf9b0c21907a 475 }
azazeal88 1:cf9b0c21907a 476
azazeal88 1:cf9b0c21907a 477 /**
azazeal88 1:cf9b0c21907a 478 * @brief Sets the data rate for a given channel ID.
azazeal88 1:cf9b0c21907a 479 * Please refer to the LoRaWAN spec for the actual values.
azazeal88 1:cf9b0c21907a 480 * @param Channel ID from 0 - 15.
azazeal88 1:cf9b0c21907a 481 * @param Number representing the minimum data rate range from 0 to 7.
azazeal88 1:cf9b0c21907a 482 * @param Number representing the maximum data rate range from 0 to 7
azazeal88 1:cf9b0c21907a 483 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 484 */
azazeal88 2:336a025b82b5 485 bool RN2483::setDrRange(uint8_t channelID, uint8_t minRange, uint8_t maxRange)
azazeal88 2:336a025b82b5 486 {
azazeal88 2:336a025b82b5 487 if((channelID <= 15)&&(minRange<=7)&&(maxRange<=7)) {
azazeal88 1:cf9b0c21907a 488 char buffer [15];
azazeal88 1:cf9b0c21907a 489 int bytesWritten = sprintf(buffer, "%d %d %d", channelID, minRange, maxRange);
azazeal88 1:cf9b0c21907a 490 // Check to make sure sprintf did not return an error before sending.
azazeal88 1:cf9b0c21907a 491 if(bytesWritten > 0) {
azazeal88 1:cf9b0c21907a 492 return setMacParam(STR_CH_DRRANGE, buffer);
azazeal88 1:cf9b0c21907a 493 }
azazeal88 1:cf9b0c21907a 494 }
azazeal88 1:cf9b0c21907a 495 return false;
azazeal88 1:cf9b0c21907a 496 }
azazeal88 1:cf9b0c21907a 497
azazeal88 1:cf9b0c21907a 498 /**
azazeal88 1:cf9b0c21907a 499 * @brief Sets a given channel ID to be enabled or disabled.
azazeal88 1:cf9b0c21907a 500 * @param Channel ID from 0 - 15.
azazeal88 1:cf9b0c21907a 501 * @param Flag representing if channel is enabled or disabled.
azazeal88 1:cf9b0c21907a 502 * Warning: duty cycle, frequency and data range must be set for a channel
azazeal88 1:cf9b0c21907a 503 * before enabling!
azazeal88 1:cf9b0c21907a 504 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 505 */
azazeal88 2:336a025b82b5 506 bool RN2483::setStatus(uint8_t channelID, bool status)
azazeal88 2:336a025b82b5 507 {
azazeal88 2:336a025b82b5 508 if((channelID <= 15)) {
azazeal88 2:336a025b82b5 509 int bytesWritten = 0;
azazeal88 2:336a025b82b5 510 char buffer [15];
azazeal88 2:336a025b82b5 511 if(status)
azazeal88 2:336a025b82b5 512 bytesWritten = sprintf(buffer, "%d %s", channelID, "on");
azazeal88 2:336a025b82b5 513 else {
azazeal88 2:336a025b82b5 514 bytesWritten = sprintf(buffer, "%d %s", channelID, "off");
azazeal88 2:336a025b82b5 515 }
azazeal88 2:336a025b82b5 516 // Check to make sure sprintf did not return an error before sending.
azazeal88 2:336a025b82b5 517 if(bytesWritten > 0) {
azazeal88 2:336a025b82b5 518 return sendCommand(STR_CMD_SET_CHANNEL_STATUS, buffer);
azazeal88 2:336a025b82b5 519 }
azazeal88 1:cf9b0c21907a 520 }
azazeal88 1:cf9b0c21907a 521 return false;
azazeal88 1:cf9b0c21907a 522 }
azazeal88 1:cf9b0c21907a 523
azazeal88 1:cf9b0c21907a 524 /**
azazeal88 2:336a025b82b5 525 * @brief The network can issue a command to silence the RN2483. This restores the module.
azazeal88 1:cf9b0c21907a 526 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 527 */
azazeal88 2:336a025b82b5 528 bool RN2483::forceEnable()
azazeal88 2:336a025b82b5 529 {
azazeal88 1:cf9b0c21907a 530 return sendCommand(STR_MAC_FORCEENABLE);
azazeal88 1:cf9b0c21907a 531 }
azazeal88 1:cf9b0c21907a 532
azazeal88 1:cf9b0c21907a 533 /**
azazeal88 2:336a025b82b5 534 * @brief Saves configurable parameters to eeprom.
azazeal88 1:cf9b0c21907a 535 * @return Returns true if parameters are valid or false if not.
azazeal88 1:cf9b0c21907a 536 */
azazeal88 2:336a025b82b5 537 bool RN2483::saveConfiguration()
azazeal88 2:336a025b82b5 538 {
azazeal88 3:ee222a99783c 539 // Forced to return true currently.
azazeal88 3:ee222a99783c 540 sendCommand(STR_CMD_SAVE);
azazeal88 3:ee222a99783c 541 return true;
azazeal88 1:cf9b0c21907a 542 }
azazeal88 1:cf9b0c21907a 543
azazeal88 1:cf9b0c21907a 544 /**
azazeal88 1:cf9b0c21907a 545 * @brief Sends the command together with the given, paramValue (optional)
azazeal88 1:cf9b0c21907a 546 * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref
azazeal88 1:cf9b0c21907a 547 * @param Command Parameter to send
azazeal88 1:cf9b0c21907a 548 * @param Size of param buffer
azazeal88 1:cf9b0c21907a 549 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 550 */
azazeal88 0:a8609e6f88f3 551 bool RN2483::sendCommand(const char* command, const uint8_t* paramValue, uint16_t size)
azazeal88 0:a8609e6f88f3 552 {
azazeal88 0:a8609e6f88f3 553 _RN2483.printf(command);
azazeal88 0:a8609e6f88f3 554
azazeal88 0:a8609e6f88f3 555 for (uint16_t i = 0; i < size; ++i) {
azazeal88 0:a8609e6f88f3 556 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 557 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 558 }
azazeal88 0:a8609e6f88f3 559
azazeal88 0:a8609e6f88f3 560 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 561
azazeal88 0:a8609e6f88f3 562 return expectOK();
azazeal88 0:a8609e6f88f3 563 }
azazeal88 0:a8609e6f88f3 564
azazeal88 1:cf9b0c21907a 565 /**
azazeal88 1:cf9b0c21907a 566 * @brief Sends the command together with the given, paramValue (optional)
azazeal88 1:cf9b0c21907a 567 * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref
azazeal88 1:cf9b0c21907a 568 * @param Command Parameter to send
azazeal88 1:cf9b0c21907a 569 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 570 */
azazeal88 0:a8609e6f88f3 571 bool RN2483::sendCommand(const char* command, uint8_t paramValue)
azazeal88 0:a8609e6f88f3 572 {
azazeal88 0:a8609e6f88f3 573 _RN2483.printf(command);
azazeal88 0:a8609e6f88f3 574 _RN2483.printf("%u",paramValue);
azazeal88 0:a8609e6f88f3 575 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 576
azazeal88 0:a8609e6f88f3 577 return expectOK();
azazeal88 0:a8609e6f88f3 578 }
azazeal88 0:a8609e6f88f3 579
azazeal88 1:cf9b0c21907a 580 /**
azazeal88 1:cf9b0c21907a 581 * @brief Sends the command together with the given, paramValue (optional)
azazeal88 1:cf9b0c21907a 582 * @param Command should include a trailing space if paramValue is set. Refer to RN2483 command ref
azazeal88 1:cf9b0c21907a 583 * @param Command Parameter to send
azazeal88 1:cf9b0c21907a 584 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 585 */
azazeal88 0:a8609e6f88f3 586 bool RN2483::sendCommand(const char* command, const char* paramValue)
azazeal88 0:a8609e6f88f3 587 {
azazeal88 0:a8609e6f88f3 588 _RN2483.printf(command);
azazeal88 0:a8609e6f88f3 589 if (paramValue != NULL) {
azazeal88 0:a8609e6f88f3 590 _RN2483.printf(paramValue);
azazeal88 0:a8609e6f88f3 591 }
azazeal88 0:a8609e6f88f3 592 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 593 return expectOK();
azazeal88 0:a8609e6f88f3 594 }
azazeal88 0:a8609e6f88f3 595
azazeal88 1:cf9b0c21907a 596 /**
azazeal88 1:cf9b0c21907a 597 * @brief Sends a join command to the network
azazeal88 1:cf9b0c21907a 598 * @param Type of join, OTAA or ABP
azazeal88 1:cf9b0c21907a 599 * @return Returns true on success or false if fail.
azazeal88 1:cf9b0c21907a 600 */
azazeal88 0:a8609e6f88f3 601 bool RN2483::joinNetwork(const char* type)
azazeal88 0:a8609e6f88f3 602 {
azazeal88 0:a8609e6f88f3 603 _RN2483.printf(STR_CMD_JOIN);
azazeal88 0:a8609e6f88f3 604 _RN2483.printf(type);
azazeal88 0:a8609e6f88f3 605 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 606
azazeal88 0:a8609e6f88f3 607 return expectOK() && expectString(STR_ACCEPTED, 30000);
azazeal88 0:a8609e6f88f3 608 }
azazeal88 0:a8609e6f88f3 609
azazeal88 1:cf9b0c21907a 610 /**
azazeal88 1:cf9b0c21907a 611 * @brief Sends the command together with the given paramValue (optional)
azazeal88 1:cf9b0c21907a 612 * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref.
azazeal88 1:cf9b0c21907a 613 * @param Param value to send
azazeal88 1:cf9b0c21907a 614 * @param Size of Param buffer
azazeal88 1:cf9b0c21907a 615 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 616 */
azazeal88 0:a8609e6f88f3 617 bool RN2483::setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size)
azazeal88 0:a8609e6f88f3 618 {
azazeal88 0:a8609e6f88f3 619 _RN2483.printf(STR_CMD_SET);
azazeal88 0:a8609e6f88f3 620 _RN2483.printf(paramName);
azazeal88 0:a8609e6f88f3 621
azazeal88 0:a8609e6f88f3 622 for (uint16_t i = 0; i < size; ++i) {
azazeal88 0:a8609e6f88f3 623 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 624 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i]))));
azazeal88 0:a8609e6f88f3 625 }
azazeal88 0:a8609e6f88f3 626
azazeal88 0:a8609e6f88f3 627 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 628
azazeal88 0:a8609e6f88f3 629 return expectOK();
azazeal88 0:a8609e6f88f3 630 }
azazeal88 0:a8609e6f88f3 631
azazeal88 1:cf9b0c21907a 632 /**
azazeal88 1:cf9b0c21907a 633 * @brief Sends the command together with the given paramValue (optional)
azazeal88 1:cf9b0c21907a 634 * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref.
azazeal88 1:cf9b0c21907a 635 * @param Param value to send
azazeal88 1:cf9b0c21907a 636 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 637 */
azazeal88 0:a8609e6f88f3 638 bool RN2483::setMacParam(const char* paramName, uint8_t paramValue)
azazeal88 0:a8609e6f88f3 639 {
azazeal88 0:a8609e6f88f3 640 _RN2483.printf(STR_CMD_SET);
azazeal88 0:a8609e6f88f3 641 _RN2483.printf(paramName);
azazeal88 0:a8609e6f88f3 642 _RN2483.printf("%u",paramValue);
azazeal88 0:a8609e6f88f3 643 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 644
azazeal88 0:a8609e6f88f3 645 return expectOK();
azazeal88 0:a8609e6f88f3 646 }
azazeal88 0:a8609e6f88f3 647
azazeal88 1:cf9b0c21907a 648 /**
azazeal88 1:cf9b0c21907a 649 * @brief Sends the command together with the given paramValue (optional)
azazeal88 1:cf9b0c21907a 650 * @param MAC param should include a trailing space if paramValue is set. Refer to RN2483 command ref.
azazeal88 1:cf9b0c21907a 651 * @param Param value to send
azazeal88 1:cf9b0c21907a 652 * @return Returns true on success or false if invalid.
azazeal88 1:cf9b0c21907a 653 */
azazeal88 0:a8609e6f88f3 654 bool RN2483::setMacParam(const char* paramName, const char* paramValue)
azazeal88 0:a8609e6f88f3 655 {
azazeal88 0:a8609e6f88f3 656 _RN2483.printf(STR_CMD_SET);
azazeal88 0:a8609e6f88f3 657 _RN2483.printf(paramName);
azazeal88 0:a8609e6f88f3 658 _RN2483.printf(paramValue);
azazeal88 0:a8609e6f88f3 659 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 660
azazeal88 0:a8609e6f88f3 661 return expectOK();
azazeal88 0:a8609e6f88f3 662 }
azazeal88 0:a8609e6f88f3 663
azazeal88 1:cf9b0c21907a 664 /**
azazeal88 1:cf9b0c21907a 665 * @brief Returns the enum that is mapped to the given "error" message
azazeal88 1:cf9b0c21907a 666 * @param Error to lookup.
azazeal88 1:cf9b0c21907a 667 * @return Returns the enum.
azazeal88 1:cf9b0c21907a 668 */
azazeal88 0:a8609e6f88f3 669 uint8_t RN2483::lookupMacTransmitError(const char* error)
azazeal88 0:a8609e6f88f3 670 {
azazeal88 0:a8609e6f88f3 671 if (error[0] == 0) {
azazeal88 0:a8609e6f88f3 672 return NoResponse;
azazeal88 0:a8609e6f88f3 673 }
azazeal88 0:a8609e6f88f3 674
azazeal88 1:cf9b0c21907a 675 StringEnumPair_t errorTable[] = {
azazeal88 0:a8609e6f88f3 676 { STR_RESULT_INVALID_PARAM, InternalError },
azazeal88 0:a8609e6f88f3 677 { STR_RESULT_NOT_JOINED, NotConnected },
azazeal88 0:a8609e6f88f3 678 { STR_RESULT_NO_FREE_CHANNEL, Busy },
azazeal88 2:336a025b82b5 679 { STR_RESULT_SILENT, Silent },
azazeal88 0:a8609e6f88f3 680 { STR_RESULT_FRAME_COUNTER_ERROR, NetworkFatalError },
azazeal88 0:a8609e6f88f3 681 { STR_RESULT_BUSY, Busy },
azazeal88 0:a8609e6f88f3 682 { STR_RESULT_MAC_PAUSED, InternalError },
azazeal88 0:a8609e6f88f3 683 { STR_RESULT_INVALID_DATA_LEN, PayloadSizeError },
azazeal88 0:a8609e6f88f3 684 { STR_RESULT_MAC_ERROR, NoAcknowledgment },
azazeal88 0:a8609e6f88f3 685 };
azazeal88 0:a8609e6f88f3 686
azazeal88 0:a8609e6f88f3 687 for (StringEnumPair_t * p = errorTable; p->stringValue != NULL; ++p) {
azazeal88 0:a8609e6f88f3 688 if (strcmp(p->stringValue, error) == 0) {
azazeal88 0:a8609e6f88f3 689 return p->enumValue;
azazeal88 0:a8609e6f88f3 690 }
azazeal88 0:a8609e6f88f3 691 }
azazeal88 0:a8609e6f88f3 692
azazeal88 0:a8609e6f88f3 693 return NoResponse;
azazeal88 0:a8609e6f88f3 694 }
azazeal88 0:a8609e6f88f3 695
azazeal88 1:cf9b0c21907a 696 /**
azazeal88 1:cf9b0c21907a 697 * @brief Sends a a payload and blocks until there is a response back,
azazeal88 1:cf9b0c21907a 698 * or the receive windows have closed or the hard timeout has passed.
azazeal88 1:cf9b0c21907a 699 * @param Transmit type
azazeal88 1:cf9b0c21907a 700 * @param Port to use for transmit
azazeal88 1:cf9b0c21907a 701 * @param Payload buffer
azazeal88 1:cf9b0c21907a 702 * @param Size of payload buffer
azazeal88 1:cf9b0c21907a 703 * @return Returns if sucessfull or if a MAC transmit error.
azazeal88 1:cf9b0c21907a 704 */
azazeal88 0:a8609e6f88f3 705 uint8_t RN2483::macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size)
azazeal88 0:a8609e6f88f3 706 {
azazeal88 0:a8609e6f88f3 707 _RN2483.printf(STR_CMD_MAC_TX);
azazeal88 0:a8609e6f88f3 708 _RN2483.printf(type);
azazeal88 0:a8609e6f88f3 709 _RN2483.printf("%u",port);
azazeal88 0:a8609e6f88f3 710 _RN2483.printf(" ");
azazeal88 0:a8609e6f88f3 711
azazeal88 0:a8609e6f88f3 712 for (int i = 0; i < size; ++i) {
azazeal88 0:a8609e6f88f3 713 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(payload[i]))));
azazeal88 0:a8609e6f88f3 714 _RN2483.putc(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(payload[i]))));
azazeal88 0:a8609e6f88f3 715 }
azazeal88 0:a8609e6f88f3 716
azazeal88 0:a8609e6f88f3 717 _RN2483.printf(CRLF);
azazeal88 0:a8609e6f88f3 718
azazeal88 0:a8609e6f88f3 719 if (!expectOK()) {
azazeal88 0:a8609e6f88f3 720 return lookupMacTransmitError(this->inputBuffer); // inputBuffer still has the last line read
azazeal88 0:a8609e6f88f3 721 }
azazeal88 0:a8609e6f88f3 722
azazeal88 0:a8609e6f88f3 723 this->packetReceived = false; // prepare for receiving a new packet
azazeal88 0:a8609e6f88f3 724 Timer t;
azazeal88 0:a8609e6f88f3 725 t.start();
azazeal88 1:cf9b0c21907a 726 int timeout = t.read_ms() + RECEIVE_TIMEOUT; // hard timeouts
azazeal88 0:a8609e6f88f3 727 while (t.read_ms() < timeout) {
azazeal88 0:a8609e6f88f3 728 if (readLn() > 0) {
azazeal88 1:cf9b0c21907a 729 if (strstr(this->inputBuffer, " ") != NULL) { // to avoid double delimiter search
azazeal88 0:a8609e6f88f3 730 // there is a splittable line -only case known is mac_rx
azazeal88 0:a8609e6f88f3 731 t.stop();
azazeal88 0:a8609e6f88f3 732 return onMacRX();
azazeal88 1:cf9b0c21907a 733 } else if (strstr(this->inputBuffer, STR_RESULT_MAC_TX_OK)) {
azazeal88 0:a8609e6f88f3 734 // done
azazeal88 0:a8609e6f88f3 735 t.stop();
azazeal88 0:a8609e6f88f3 736 return NoError;
azazeal88 1:cf9b0c21907a 737 } else {
azazeal88 0:a8609e6f88f3 738 // lookup the error message
azazeal88 0:a8609e6f88f3 739 t.stop();
azazeal88 0:a8609e6f88f3 740 return lookupMacTransmitError(this->inputBuffer);
azazeal88 0:a8609e6f88f3 741 }
azazeal88 0:a8609e6f88f3 742 }
azazeal88 0:a8609e6f88f3 743 }
azazeal88 1:cf9b0c21907a 744 t.stop();
azazeal88 0:a8609e6f88f3 745 return Timedout;
azazeal88 0:a8609e6f88f3 746 }
azazeal88 0:a8609e6f88f3 747
azazeal88 1:cf9b0c21907a 748 /**
azazeal88 1:cf9b0c21907a 749 * @brief Parses the input buffer and copies the received payload into
azazeal88 1:cf9b0c21907a 750 * the "received payload" buffer when a "mac rx" message has been received.
azazeal88 1:cf9b0c21907a 751 * @return Returns 0 (NoError) or otherwise one of the MacTransmitErrorCodes.
azazeal88 1:cf9b0c21907a 752 */
azazeal88 0:a8609e6f88f3 753 uint8_t RN2483::onMacRX()
azazeal88 0:a8609e6f88f3 754 {
azazeal88 0:a8609e6f88f3 755 // parse inputbuffer, put payload into packet buffer
azazeal88 0:a8609e6f88f3 756 char* token = strtok(this->inputBuffer, " ");
azazeal88 0:a8609e6f88f3 757
azazeal88 0:a8609e6f88f3 758 // sanity check
azazeal88 0:a8609e6f88f3 759 if (strcmp(token, STR_RESULT_MAC_RX) != 0) {
azazeal88 0:a8609e6f88f3 760 return InternalError;
azazeal88 0:a8609e6f88f3 761 }
azazeal88 0:a8609e6f88f3 762
azazeal88 0:a8609e6f88f3 763 // port
azazeal88 0:a8609e6f88f3 764 token = strtok(NULL, " ");
azazeal88 0:a8609e6f88f3 765
azazeal88 0:a8609e6f88f3 766 // payload
azazeal88 0:a8609e6f88f3 767 token = strtok(NULL, " "); // until end of string
azazeal88 0:a8609e6f88f3 768
azazeal88 0:a8609e6f88f3 769 uint16_t len = strlen(token) + 1; // include termination char
azazeal88 0:a8609e6f88f3 770 memcpy(this->receivedPayloadBuffer, token, len <= this->receivedPayloadBufferSize ? len : this->receivedPayloadBufferSize);
azazeal88 0:a8609e6f88f3 771
azazeal88 0:a8609e6f88f3 772 this->packetReceived = true; // enable receive() again
azazeal88 0:a8609e6f88f3 773 return NoError;
azazeal88 0:a8609e6f88f3 774 }
azazeal88 0:a8609e6f88f3 775
azazeal88 1:cf9b0c21907a 776 /**
azazeal88 1:cf9b0c21907a 777 * @brief Private method to read serial port with timeout
azazeal88 1:cf9b0c21907a 778 * @param The time to wait for in milliseconds.
azazeal88 1:cf9b0c21907a 779 * @return Returns character or -1 on timeout
azazeal88 1:cf9b0c21907a 780 */
azazeal88 1:cf9b0c21907a 781 int RN2483::timedRead(int _timeout)
azazeal88 1:cf9b0c21907a 782 {
azazeal88 0:a8609e6f88f3 783 int c;
azazeal88 0:a8609e6f88f3 784 Timer t;
azazeal88 0:a8609e6f88f3 785 t.start();
azazeal88 3:ee222a99783c 786 unsigned long _startMillis = t.read_ms(); // get milliseconds
azazeal88 3:ee222a99783c 787 do {
azazeal88 3:ee222a99783c 788 if(_RN2483.readable()){
azazeal88 3:ee222a99783c 789 c = _RN2483.getc();
azazeal88 3:ee222a99783c 790 if (c >= 0){
azazeal88 3:ee222a99783c 791 t.stop();
azazeal88 3:ee222a99783c 792 return c;
azazeal88 3:ee222a99783c 793 }
azazeal88 3:ee222a99783c 794 }
azazeal88 3:ee222a99783c 795 } while(t.read_ms() - _startMillis <_timeout);
azazeal88 0:a8609e6f88f3 796 t.stop();
azazeal88 0:a8609e6f88f3 797 return -1; // -1 indicates timeout
azazeal88 1:cf9b0c21907a 798 }
azazeal88 0:a8609e6f88f3 799
azazeal88 1:cf9b0c21907a 800 /**
azazeal88 1:cf9b0c21907a 801 * @brief Read characters into buffer.
azazeal88 1:cf9b0c21907a 802 * Terminates if length characters have been read, timeout, or
azazeal88 1:cf9b0c21907a 803 * if the terminator character has been detected
azazeal88 1:cf9b0c21907a 804 * @param The terminator character to look for
azazeal88 1:cf9b0c21907a 805 * @param The buffer to read into.
azazeal88 1:cf9b0c21907a 806 * @param The size of the buffer.
azazeal88 1:cf9b0c21907a 807 * @return The number of bytes read. 0 means no valid data found.
azazeal88 1:cf9b0c21907a 808 */
azazeal88 0:a8609e6f88f3 809 size_t RN2483::readBytesUntil(char terminator, char *buffer, size_t length)
azazeal88 0:a8609e6f88f3 810 {
azazeal88 0:a8609e6f88f3 811 if (length < 1) return 0;
azazeal88 0:a8609e6f88f3 812 size_t index = 0;
azazeal88 0:a8609e6f88f3 813 while (index < length) {
azazeal88 0:a8609e6f88f3 814 int c = timedRead(1000);
azazeal88 0:a8609e6f88f3 815 if (c < 0 || c == terminator) break;
azazeal88 0:a8609e6f88f3 816 *buffer++ = (char)c;
azazeal88 0:a8609e6f88f3 817 index++;
azazeal88 0:a8609e6f88f3 818 }
azazeal88 1:cf9b0c21907a 819 return index; // return number of characters, not including null terminator
azazeal88 1:cf9b0c21907a 820 }
azazeal88 0:a8609e6f88f3 821
azazeal88 0:a8609e6f88f3 822 #ifdef DEBUG
azazeal88 0:a8609e6f88f3 823 int freeRam()
azazeal88 0:a8609e6f88f3 824 {
azazeal88 0:a8609e6f88f3 825 extern int __heap_start;
azazeal88 0:a8609e6f88f3 826 extern int *__brkval;
azazeal88 0:a8609e6f88f3 827 int v;
azazeal88 0:a8609e6f88f3 828 return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
azazeal88 0:a8609e6f88f3 829 }
azazeal88 0:a8609e6f88f3 830 #endif