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
RN2483.cpp@7:100ab85cc6d7, 2016-11-22 (annotated)
- 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?
User | Revision | Line number | New 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 |