diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 0f969dc5..7956eb68 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -19,6 +19,98 @@ static void PagerClientReadBit(void) { } #endif +PagerMessage::PagerMessage(uint32_t address, uint8_t function, uint8_t* data, size_t data_len, uint8_t encoding) + : address(address) + , function(function) + , data(data) + , data_len(data_len) + , encoding(encoding) + {} + +PagerMessage::PagerMessage(uint32_t address, uint8_t* data, size_t data_len, uint8_t encoding) + : address(address) + , data(data) + , data_len(data_len) + , encoding(encoding) + { + // Automatically set function bits based on given encoding + if(encoding == RADIOLIB_PAGER_BCD) { + function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; + } else if(encoding == RADIOLIB_PAGER_ASCII) { + function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; + } + if(data_len == 0) { + function = RADIOLIB_PAGER_FUNC_BITS_TONE; + } + } + +uint32_t PagerMessage::getAddr_h() { + return address >> 3; +} + +uint32_t PagerMessage::getAddr_l() { + return address & 0x07; +} + +// get target position in batch (3 LSB from address determine frame position in batch) +uint8_t PagerMessage::getAddrFrameNr() { + return 2*getAddr_l(); +} + +uint8_t PagerMessage::getFirstDataFrameNr() { + return getAddrFrameNr()+1; +} + +// get symbol bit length based on encoding +uint8_t PagerMessage::getSymbolLength() { + if(encoding == RADIOLIB_PAGER_BCD) { + return 4; + } else if(encoding == RADIOLIB_PAGER_ASCII) { + return 7; + } else { + // invalid + return 0; + } +} + +// calculate the number of 20-bit data blocks +size_t PagerMessage::getNumDataBlocks() { + size_t numDataBlocks = (data_len * getSymbolLength()) / RADIOLIB_PAGER_MESSAGE_BITS_LENGTH; + if((data_len * getSymbolLength()) % RADIOLIB_PAGER_MESSAGE_BITS_LENGTH > 0) { + numDataBlocks += 1; + } + return numDataBlocks; +} + +// calculate number of batches needed +size_t PagerMessage::getNumBatches(){ + size_t numBatches = (getAddrFrameNr() + 1 + getNumDataBlocks()) / RADIOLIB_PAGER_BATCH_LEN; + if((getAddrFrameNr() + 1 + getNumDataBlocks()) % RADIOLIB_PAGER_BATCH_LEN > 0) { + numBatches += 1; + } + return numBatches; +} + +uint16_t PagerMessage::validate() { + if(address > RADIOLIB_PAGER_ADDRESS_MAX) { + return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); + } + + if(((data == NULL) && (data_len > 0)) || ((data != NULL) && (data_len == 0))) { + return(RADIOLIB_ERR_INVALID_PAYLOAD); + } + + if (getSymbolLength() <= 0) { + return(RADIOLIB_ERR_INVALID_ENCODING); + } + + if (function > RADIOLIB_PAGER_FUNC_BITS_ALPHA) { + return(RADIOLIB_ERR_INVALID_FUNCTION); + } + + return(RADIOLIB_ERR_NONE); +} + PagerClient::PagerClient(PhysicalLayer* phy) { phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) @@ -58,35 +150,36 @@ int16_t PagerClient::sendTone(uint32_t addr) { int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding, uint8_t function) { return(PagerClient::transmit(str.c_str(), addr, encoding, function)); } +int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding) { + return(PagerClient::transmit(str.c_str(), addr, encoding)); +} #endif int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding, uint8_t function) { return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding, function)); } +int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding) { + return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding)); +} int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding, uint8_t function) { - PagerMessage_t message; - message.addr = addr; - message.func = function; - message.data = data; - message.data_len = len; - message.encoding = encoding; + PagerMessage message(addr, function, data, len, encoding); + return(PagerClient::transmit(message)); +} +int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding) { + PagerMessage message(addr, data, len, encoding); return(PagerClient::transmit(message)); } -int16_t PagerClient::encodeData(uint32_t* buf, uint8_t* data, size_t len, uint8_t encoding) { - // get symbol bit length based on encoding - uint8_t symbolLength = (encoding == RADIOLIB_PAGER_BCD)?4:7; - // calculate the number of 20-bit data blocks - size_t numDataBlocks = (len * symbolLength) / RADIOLIB_PAGER_MESSAGE_BITS_LENGTH; - if((len * symbolLength) % RADIOLIB_PAGER_MESSAGE_BITS_LENGTH > 0) { - numDataBlocks += 1; - } + +int16_t PagerClient::encodeData(uint32_t* buf, PagerMessage &message) { + uint8_t symbolLength = message.getSymbolLength(); + uint8_t* data = message.getData(); // write the data as 20-bit code blocks int8_t remBits = 0; uint8_t dataPos = 0; - for(uint8_t blockPos = 0; blockPos < numDataBlocks; blockPos++) { + for(uint8_t blockPos = 0; blockPos < message.getNumDataBlocks(); blockPos++) { // mark this as a message code word buf[blockPos] = RADIOLIB_PAGER_MESSAGE_CODE_WORD << (RADIOLIB_PAGER_CODE_WORD_LEN - 1); @@ -104,19 +197,19 @@ int16_t PagerClient::encodeData(uint32_t* buf, uint8_t* data, size_t len, uint8_ while(symbolPos > (RADIOLIB_PAGER_FUNC_BITS_POS - symbolLength)) { uint8_t symbol; - if(dataPos < len) { + if(dataPos < message.getDataLen()) { symbol = data[dataPos++]; - } else if(dataPos >= len) { + } else { // if(dataPos >= message.getDataLen()) { // we ran out of message symbols // in BCD mode, pad the rest of the code word with spaces (0xC) - if(encoding == RADIOLIB_PAGER_BCD) { + if(message.getEncoding() == RADIOLIB_PAGER_BCD) { symbol = ' '; } else { break; } } // for BCD, encode the symbol - if(encoding == RADIOLIB_PAGER_BCD) { + if(message.getEncoding() == RADIOLIB_PAGER_BCD) { symbol = encodeBCD(symbol); } symbol = Module::reflect(symbol, 8); @@ -141,72 +234,15 @@ int16_t PagerClient::encodeData(uint32_t* buf, uint8_t* data, size_t len, uint8_ return(RADIOLIB_ERR_NONE); } -int16_t PagerClient::transmit(PagerMessage_t &message) { - uint32_t addr = message.addr; - if(addr > RADIOLIB_PAGER_ADDRESS_MAX) { - return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); - } - uint32_t addr_h = message.addr >> 3; - uint32_t addr_l = message.addr & 0x07; +int16_t PagerClient::transmit(PagerMessage &message) { - uint8_t* data = message.data; - size_t len = message.data_len; - if(((data == NULL) && (len > 0)) || ((data != NULL) && (len == 0))) { - return(RADIOLIB_ERR_INVALID_PAYLOAD); - } - - uint8_t encoding = message.encoding; - // get symbol bit length based on encoding - uint8_t symbolLength = 0; - if(encoding == RADIOLIB_PAGER_BCD) { - symbolLength = 4; - - } else if(encoding == RADIOLIB_PAGER_ASCII) { - symbolLength = 7; - - } else { - return(RADIOLIB_ERR_INVALID_ENCODING); - - } - - uint8_t function = message.func; - // Automatically set function bits based on given encoding - if (function == RADIOLIB_PAGER_FUNC_AUTO) { - if(encoding == RADIOLIB_PAGER_BCD) { - function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; - - } else if(encoding == RADIOLIB_PAGER_ASCII) { - function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; - - } else { - return(RADIOLIB_ERR_INVALID_ENCODING); - - } - if(len == 0) { - function = RADIOLIB_PAGER_FUNC_BITS_TONE; - } - } - if (function > RADIOLIB_PAGER_FUNC_BITS_ALPHA) { - return(RADIOLIB_ERR_INVALID_FUNCTION); - } - - // get target position in batch (3 LSB from address determine frame position in batch) - uint8_t framePosAddr = 2*addr_l; - - // calculate the number of 20-bit data blocks - size_t numDataBlocks = (len * symbolLength) / RADIOLIB_PAGER_MESSAGE_BITS_LENGTH; - if((len * symbolLength) % RADIOLIB_PAGER_MESSAGE_BITS_LENGTH > 0) { - numDataBlocks += 1; - } - - // calculate number of batches - size_t numBatches = (1 + framePosAddr + numDataBlocks) / RADIOLIB_PAGER_BATCH_LEN; - if((1 + framePosAddr + numDataBlocks) % RADIOLIB_PAGER_BATCH_LEN > 0) { - numBatches += 1; + uint16_t err = message.validate(); + if (err) { + return(err); } // calculate message length in 32-bit code words - size_t msgLen = RADIOLIB_PAGER_BATCH_LEN * numBatches; + size_t msgLen = RADIOLIB_PAGER_BATCH_LEN * message.getNumBatches(); #if defined(RADIOLIB_STATIC_ONLY) uint32_t msg[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -220,19 +256,20 @@ int16_t PagerClient::transmit(PagerMessage_t &message) { } // construct address frame - uint32_t frameAddr = (addr_h << RADIOLIB_PAGER_ADDRESS_POS) | (function << RADIOLIB_PAGER_FUNC_BITS_POS); + uint32_t frameAddr = (message.getAddr_h() << RADIOLIB_PAGER_ADDRESS_POS) | (message.getFunction() << RADIOLIB_PAGER_FUNC_BITS_POS); // write address code word - msg[framePosAddr] = RadioLibBCHInstance.encode(frameAddr); + msg[message.getAddrFrameNr()] = RadioLibBCHInstance.encode(frameAddr); - encodeData(msg+framePosAddr+1, data, len, encoding); + uint32_t* msg_data_ptr = msg+message.getFirstDataFrameNr(); + encodeData(msg_data_ptr, message); // transmit the preamble for(size_t i = 0; i < RADIOLIB_PAGER_PREAMBLE_LENGTH; i++) { PagerClient::write(RADIOLIB_PAGER_PREAMBLE_CODE_WORD); } - for(size_t i = 0; i < numBatches; i++) { + for(size_t i = 0; i < message.getNumBatches(); i++) { // transmit the frame synchronization word PagerClient::write(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD); diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 95ca1467..2cbabe9c 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -50,7 +50,6 @@ #define RADIOLIB_PAGER_FUNC_BITS_TONE (0b01) #define RADIOLIB_PAGER_FUNC_BITS_ACTIVATION (0b10) #define RADIOLIB_PAGER_FUNC_BITS_ALPHA (0b11) -#define RADIOLIB_PAGER_FUNC_AUTO 0xFF // the maximum allowed address (2^22 - 1) #define RADIOLIB_PAGER_ADDRESS_MAX (2097151) @@ -59,32 +58,57 @@ \struct PagerMessage_t \brief Structure to save one message. */ -struct PagerMessage_t { +class PagerMessage { + public: + /*! + \brief Default constructor. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. + \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding + */ + explicit PagerMessage(uint32_t address, uint8_t function, uint8_t* data, size_t data_len, uint8_t encoding); + explicit PagerMessage(uint32_t address, uint8_t* data, size_t data_len, uint8_t encoding); - /*! - \brief Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. - */ - uint32_t addr; + uint32_t getAddr_h(); + uint32_t getAddr_l(); + uint8_t getAddrFrameNr(); + uint8_t getFirstDataFrameNr(); + uint8_t getSymbolLength(); + uint8_t getFunction() { return function; }; + uint8_t* getData() { return data; }; + size_t getDataLen() { return data_len; }; + uint8_t getEncoding() { return encoding; }; + size_t getNumDataBlocks(); + size_t getNumBatches(); + uint16_t validate(); - /*! - \brief function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding - */ - uint8_t func; + private: + /*! + \brief Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. + */ + uint32_t address; - /*! - \brief Binary data that will be transmitted. - */ - uint8_t* data; + /*! + \brief function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding + */ + uint8_t function; - /*! - \brief Length of binary data to transmit (in bytes). - */ - size_t data_len; + /*! + \brief Binary data that will be transmitted. + */ + uint8_t* data; - /*! - \brief Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. - */ - uint8_t encoding; + /*! + \brief Length of binary data to transmit (in bytes). + */ + size_t data_len; + + /*! + \brief Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + */ + uint8_t encoding; }; /*! @@ -127,7 +151,8 @@ class PagerClient { \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + int16_t transmit(String& str, uint32_t addr, uint8_t encoding, uint8_t function); #endif /*! @@ -138,7 +163,8 @@ class PagerClient { \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(const char* str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + int16_t transmit(const char* str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + int16_t transmit(const char* str, uint32_t addr, uint8_t encoding, uint8_t function); /*! \brief Binary transmit method. Will transmit arbitrary binary data. @@ -149,16 +175,17 @@ class PagerClient { \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding, uint8_t function); /*! \brief Message transmit method. \param message Message object that will be transmitted. \returns \ref status_codes */ - int16_t transmit(PagerMessage_t &message); + int16_t transmit(PagerMessage &message); - int16_t encodeData(uint32_t* buf, uint8_t* data, size_t len, uint8_t encoding); + int16_t encodeData(uint32_t* buf, PagerMessage &message); #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*!