diff --git a/examples/sub1GHz_RX_Layer/sub1GHz_RX_Layer.ino b/examples/sub1GHz_RX_Layer/sub1GHz_RX_Layer.ino new file mode 100755 index 0000000..b5894f1 --- /dev/null +++ b/examples/sub1GHz_RX_Layer/sub1GHz_RX_Layer.ino @@ -0,0 +1,221 @@ +/// +/// @mainpage sub1GHz_RX_Layer +/// +/// @details Additional layer for EasyLink +/// @n +/// @n +/// @n @a Developed with [embedXcode+](https://embedXcode.weebly.com) +/// +/// @author Rei Vilo +/// @author https://embeddedcomputing.weebly.com +/// @date 05 Nov 2019 10:56 +/// @version 103 +/// +/// @copyright (c) Rei Vilo, 2019 +/// @copyright CC = BY SA NC +/// +/// @see ReadMe.txt for references +/// + + +/// +/// @file sub1GHz_RX_Layer.ino +/// @brief Main sketch +/// +/// @details RX example for EasyLink additional layer +/// @n @a Developed with [embedXcode+](https://embedXcode.weebly.com) +/// +/// @author Rei Vilo +/// @author https://embeddedcomputing.weebly.com +/// @date 05 Nov 2019 10:56 +/// @version 103 +/// +/// @copyright (c) Rei Vilo, 2019 +/// @copyright CC = BY SA NC +/// +/// @see ReadMe.txt for references +/// @n +/// + + +// Core library for code-sense - IDE-based +// !!! Help: http://bit.ly/2AdU7cu +#if defined(ENERGIA) // LaunchPad specific +#include "Energia.h" +#else // error +#error Platform not defined +#endif // end IDE + + +// Set parameters +/// +/// @brief Address filtering +/// @{ +#define WITH_ADDRESS_FILTERING 1 ///< activated +#define WITHOUT_ADDRESS_FILTERING 0 ///< desacticated +#define ADDRESS_FILTERING WITH_ADDRESS_FILTERING ///< mode +/// @} + + +// Include application, user and local libraries +#include "EasyLinkLayer.h" +//#include "QuickDebug.h" + +// Define structures and classes + + +// Define variables and constants +//EasyLinkLayer myLink; +#if (ADDRESS_FILTERING == WITH_ADDRESS_FILTERING) +EasyLinkLayer myLink(true); +#else +EasyLinkLayer myLink; +#endif + +// Hub address +AddressIEEE_t addressHub = { 0x00, 0x12, 0x4B, 0x00, 0x0B, 0xCA, 0x27, 0x82 }; +AddressIEEE_t addressNode = { 0x00, 0x12, 0x4B, 0x00, 0x0A, 0x27, 0xCD, 0x6A }; // Node address + +AddressIEEE_t addressLocal; +uint16_t value; + +// Prototypes +// !!! Help: http://bit.ly/2l0ZhTa + + +// Utilities +/// +/// @brief Print IEEE address +/// @param address IEEE address +/// @param prefix default=false, true=add 0x +/// +void printAddress(AddressIEEE_t address, bool prefix = false) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (prefix) + { + Serial.print("0x"); + } + if (address[i] < 0x10) + { + Serial.print("0"); + } + Serial.print(address[i], HEX); + if (i < 7) + { + if (prefix) + { + Serial.print(", "); + } + else + { + Serial.print("."); + } + } + } + Serial.println(); +} + +/// +/// @brief Print the addresses of the filter +/// @param title default="Filter" +/// +void printFilter(String title = "Filter") +{ + AddressIEEE_t work; + Serial.println(title); + + for (uint8_t i = 0; i < EASYLINK_MAX_ADDR_FILTERS; i++) + { + // QuickDebug("Slot %i: ", i); + + Serial.print("Slot "); + Serial.print(i); + Serial.print("= "); + + myLink.getAddressFilter(i, &work); + + printAddress(work, true); + } +} + + +// Functions + +// Add setup code +// !!! Help: http://bit.ly/2BmKRzI +void setup() +{ + Serial.begin(115200); + delay(500); + Serial.println("=== sub1GHz_RX_Layer"); + + // Begin defaults to EasyLink_Phy_50kbps2gfsk + myLink.begin(); + Serial.println(myLink.version()); + +#if (ADDRESS_FILTERING == WITH_ADDRESS_FILTERING) + // Get local address + myLink.getAddressLocal(&addressLocal); + // // Other options + // // . as ui8[8] 00.12.4B.00.0A.27.CD.6A + // // . as ui64 6ACD270A.004B1200 + // uint64_t * address64 = (uint64_t*)&addressLocal; + // Serial.print((uint32_t)(*address64 >> 32), HEX); + // Serial.print("."); + // Serial.print((uint32_t)(*address64 & 0xffffffff), HEX); + Serial.print("addressLocal: "); + printAddress(addressLocal, true); + Serial.println("!!! Add this address as destination on sub1GHz_TX_Layer"); + + // Add local address to filters + myLink.setAddressFilter(1, addressLocal); +#endif + + // List the addresses of the filter + printFilter(); + + myLink.setAddressFilter(1, addressLocal); + + Serial.println(); + pinMode(RED_LED, OUTPUT); + pinMode(GREEN_LED, OUTPUT); +} + +void loop() +{ + uint8_t buffer[EASYLINK_MAX_DATA_LENGTH]; + size_t size; + AddressIEEE_t work; + + // Read the RX message, if any within 2 seconds + EasyLink_Status status = myLink.receive(&buffer, size, 2000); + + if (status == EasyLink_Status_Success) + { + memcpy(&value, &buffer, sizeof(uint16_t)); + + // QuickDebug("+ Packet received len=%i value=%i RSSI=%i sent to ", size, value, myLink.getRSSIRX()); + Serial.print("+ Packet received len="); + Serial.print(size); + Serial.print(" value="); + Serial.print(value); + Serial.print(" RSSI="); + Serial.print(myLink.getRSSIRX()); + Serial.print(" sent to "); + Serial.print(value); + myLink.getAddressDestinationRX(&work); + printAddress(work); + + digitalWrite(RED_LED, value); + } + else + { + Serial.print("! Error "); + Serial.print(status); + Serial.print(" ("); + Serial.print(myLink.getStatusString(status)); + Serial.println(")"); + } +} diff --git a/examples/sub1GHz_TX_Layer/sub1GHz_TX_Layer.ino b/examples/sub1GHz_TX_Layer/sub1GHz_TX_Layer.ino new file mode 100755 index 0000000..5ba23bb --- /dev/null +++ b/examples/sub1GHz_TX_Layer/sub1GHz_TX_Layer.ino @@ -0,0 +1,190 @@ +/// +/// @mainpage sub1GHz_TX_Layer +/// +/// @details Additional layer for EasyLink +/// @n +/// @n +/// @n @a Developed with [embedXcode+](https://embedXcode.weebly.com) +/// +/// @author Rei Vilo +/// @author https://embeddedcomputing.weebly.com +/// @date 05 Nov 2019 10:56 +/// @version 103 +/// +/// @copyright (c) Rei Vilo, 2019 +/// @copyright CC = BY SA NC +/// +/// @see ReadMe.txt for references +/// + + +/// +/// @file sub1GHz_TX_Layer.ino +/// @brief Main sketch +/// +/// @details TX example for EasyLink additional layer +/// @n @a Developed with [embedXcode+](https://embedXcode.weebly.com) +/// +/// @author Rei Vilo +/// @author https://embeddedcomputing.weebly.com +/// @date 05 Nov 2019 10:56 +/// @version 103 +/// +/// @copyright (c) Rei Vilo, 2019 +/// @copyright CC = BY SA NC +/// +/// @see ReadMe.txt for references +/// @n +/// + + +// Core library for code-sense - IDE-based +// !!! Help: http://bit.ly/2AdU7cu +#if defined(ENERGIA) // LaunchPad specific +#include "Energia.h" +#else // error +#error Platform not defined +#endif // end IDE + +// Set parameters +/// +/// @brief Address filtering +/// @{ +#define WITH_ADDRESS_FILTERING 1 ///< activated +#define WITHOUT_ADDRESS_FILTERING 0 ///< desacticated +#define ADDRESS_FILTERING WITH_ADDRESS_FILTERING ///< mode +/// @} + +// Include application, user and local libraries +#include "EasyLinkLayer.h" +//#include "QuickDebug.h" + + +// Define structures and classes + +// Define variables and constants +// EasyLinkLayer myLink; +#if (ADDRESS_FILTERING == WITH_ADDRESS_FILTERING) +EasyLinkLayer myLink(true); +#else +EasyLinkLayer myLink; +#endif + +// Node address +AddressIEEE_t addressNode = { 0x00, 0x12, 0x4B, 0x00, 0x0A, 0x27, 0xCD, 0x6A }; +AddressIEEE_t addressHub = { 0x00, 0x12, 0x4B, 0x00, 0x0B, 0xC9, 0xDB, 0x04 }; +AddressIEEE_t addressPhony = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; +AddressIEEE_t addressZero = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +AddressIEEE_t addressLocal; + +// Utilities + +/// +/// @brief Print IEEE address +/// @param address IEEE address +/// @param prefix default=false, true=add 0x +/// +void printAddress(AddressIEEE_t address, bool prefix = false) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (prefix) + { + Serial.print("0x"); + } + if (address[i] < 0x10) + { + Serial.print("0"); + } + Serial.print(address[i], HEX); + if (i < 7) + { + if (prefix) + { + Serial.print(", "); + } + else + { + Serial.print("."); + } + } + } + Serial.println(); +} + +// Add setup code +// !!! Help: http://bit.ly/2BmKRzI +void setup() +{ + Serial.begin(115200); + delay(500); + Serial.println("=== sub1GHz_TX_Layer"); + + // Begin defaults to EasyLink_Phy_50kbps2gfsk + myLink.begin(); + Serial.println(myLink.version()); + +#if (ADDRESS_FILTERING == WITH_ADDRESS_FILTERING) + // Get local address + myLink.getAddressLocal(&addressLocal); + Serial.print("addressLocal "); + printAddress(addressLocal, true); + + // Add local address to filters + myLink.setAddressFilter(1, addressLocal); +#endif + + pinMode(PUSH1, INPUT_PULLUP); + pinMode(PUSH2, INPUT_PULLUP); + pinMode(RED_LED, OUTPUT); + pinMode(GREEN_LED, OUTPUT); +} + +void loop() +{ + uint16_t value = 1 - digitalRead(PUSH1); + uint16_t address = 1 - digitalRead(PUSH2); + + // QuickDebugln("address= %i, value= %i", address, value); + Serial.print("address= "); + Serial.print(address); + Serial.print(", value= "); + Serial.println(value); + +#if (ADDRESS_FILTERING == WITH_ADDRESS_FILTERING) + // Set destination address for TX message + AddressIEEE_t * w; + if (address > 0) + { + w = &addressHub; + } + else + { + w = &addressPhony; + // w = &addressZero; + } + myLink.setAddressDestinationTX(*w); +#endif + + // Send the TX message + EasyLink_Status status = myLink.transmit(&value, sizeof(uint16_t)); + + if (status == EasyLink_Status_Success) + { + Serial.print("+ Packet sent to "); + printAddress(*w, true); + digitalWrite(GREEN_LED, HIGH); + delay(100); + digitalWrite(GREEN_LED, LOW); + } + else + { + Serial.print("! Error "); + Serial.print(status); + Serial.print(" ("); + Serial.print(myLink.getStatusString(status)); + Serial.println(")"); + } + + delay(1000); +} diff --git a/extras/sub1GHz Layer - Reference Manual.pdf b/extras/sub1GHz Layer - Reference Manual.pdf new file mode 100644 index 0000000..526e161 Binary files /dev/null and b/extras/sub1GHz Layer - Reference Manual.pdf differ diff --git a/src/EasyLinkLayer.cpp b/src/EasyLinkLayer.cpp new file mode 100644 index 0000000..57b4524 --- /dev/null +++ b/src/EasyLinkLayer.cpp @@ -0,0 +1,148 @@ +// +// EasyLinkLayer.cpp +// Library C++ code +// ---------------------------------- +// Developed with embedXcode+ +// https://embedXcode.weebly.com +// +// Details Additional layer for EasyLink +// Project sub1GHz Layer +// +// Created by Rei Vilo, 05 Nov 2019 +// Rei Vilo +// +// Copyright (c) Rei Vilo, 2019-2020 +// Licence CC = BY SA NC +// +// See EasyLinkLayer.h and ReadMe.txt for references +// + + +// Library header +#include "EasyLinkLayer.h" + +///// +///// @brief Addresses of the filter for incoming messages +///// @details Up to three addresses, 0..2 +///// @{ +///// +//AddressFilter_t _addressFilter = +//{ +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// < Broadcast address +// 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /// < Wrong hub address +// 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /// < Not used +//}; +///// @} + +EasyLinkLayer::EasyLinkLayer(bool flagAddressFiltering) +{ + _flagAddressFiltering = flagAddressFiltering; +} + +EasyLink_Status EasyLinkLayer::begin() +{ + EasyLink_Status status = EasyLink_Status_Param_Error; + + status = EasyLink::begin(); + if (_flagAddressFiltering) + { + EasyLink_setCtrl(EasyLink_Ctrl_AddSize, EASYLINK_MAX_ADDR_SIZE); + // Declare the authorised receiving addresses array + status = EasyLink_enableRxAddrFilter((uint8_t*)&_addressFilter, EASYLINK_MAX_ADDR_SIZE, EASYLINK_MAX_ADDR_FILTERS); + } + else + { + // Not set by default on CC13x2 + txPacket.dstAddr[0] = 0xaa; + } + + return status; +} + +EasyLink_Status EasyLinkLayer::setAddressFilter(uint8_t slot, AddressIEEE_t address) +{ + EasyLink_Status status = EasyLink_Status_Param_Error; + + if ((slot < EASYLINK_MAX_ADDR_FILTERS) and (_flagAddressFiltering)) + { + memcpy(_addressFilter[slot], address, sizeof(AddressIEEE_t)); + status = EasyLink_Status_Success; + + // Update the filters + status = EasyLink_enableRxAddrFilter((uint8_t*)&_addressFilter, EASYLINK_MAX_ADDR_SIZE, EASYLINK_MAX_ADDR_FILTERS); + } + return status; +} + +EasyLink_Status EasyLinkLayer::getAddressLocal(AddressIEEE_t *ieeeAddress) +{ + return EasyLink_getIeeeAddr((uint8_t*)ieeeAddress); +} + +EasyLink_Status EasyLinkLayer::getAddressFilter(uint8_t slot, AddressIEEE_t * address) +{ + EasyLink_Status status = EasyLink_Status_Param_Error; + + if ((slot < EASYLINK_MAX_ADDR_FILTERS) and (_flagAddressFiltering)) + { + AddressIEEE_t work = { 0 }; + memcpy(work, &_addressFilter[slot], sizeof(AddressIEEE_t)); + memcpy(address, work, sizeof(AddressIEEE_t)); + status = EasyLink_Status_Success; + } + return status; +} + +void EasyLinkLayer::setAddressDestinationTX(AddressIEEE_t ieeeAddress) +{ + memcpy(txPacket.dstAddr, ieeeAddress, sizeof(AddressIEEE_t)); +} + +EasyLink_Status EasyLinkLayer::transmit(const void * payload, size_t size) +{ + EasyLink_Status status = EasyLink_Status_Param_Error; + + if (size < EASYLINK_MAX_DATA_LENGTH) + { + memcpy(txPacket.payload, payload, size); + + // Set the length of the packet + txPacket.len = size; + // Transmit immediately + txPacket.absTime = EasyLink_ms_To_RadioTime(0); + + status = EasyLink::transmit(&txPacket); + } + return status; +} + +EasyLink_Status EasyLinkLayer::receive(void * payload, size_t size, uint32_t ms) +{ + rxPacket.rxTimeout = EasyLink_ms_To_RadioTime(ms); + // Turn the receiver on immediately + rxPacket.absTime = EasyLink_ms_To_RadioTime(0); + + EasyLink_Status status = EasyLink::receive(&rxPacket); + + if (status == EasyLink_Status_Success) + { + size = rxPacket.len; + memcpy(payload, rxPacket.payload, rxPacket.len); + } + return status; +} + +void EasyLinkLayer::getAddressDestinationRX(AddressIEEE_t * ieeeAddress) +{ + AddressIEEE_t work = { 0 }; + memcpy(work, &rxPacket.dstAddr, sizeof(AddressIEEE_t)); + memcpy(ieeeAddress, work, sizeof(AddressIEEE_t)); +} + +uint8_t EasyLinkLayer::getRSSIRX() +{ + return rxPacket.rssi; +} + + +// Code diff --git a/src/EasyLinkLayer.h b/src/EasyLinkLayer.h new file mode 100644 index 0000000..3f12107 --- /dev/null +++ b/src/EasyLinkLayer.h @@ -0,0 +1,165 @@ +/// +/// @file EasyLinkLayer.h +/// @brief Library header +/// @details Additional layer for EasyLink +/// @n +/// @n @b Project sub1GHz Layer +/// @n @a Developed with [embedXcode+](https://embedXcode.weebly.com) +/// +/// @author Rei Vilo +/// @author Rei Vilo +/// +/// @date 27 Feb 2020 +/// @version 104 +/// +/// @copyright (c) Rei Vilo, 2019-2020 +/// @copyright CC = BY SA NC +/// +/// @see ReadMe.txt for references +/// + + +// Core library for code-sense - IDE-based +// !!! Help: http://bit.ly/2AdU7cu +#if defined(ENERGIA) // LaunchPad specific +#include "Energia.h" +#else // error +#error Platform not defined +#endif // end IDE + +#ifndef EASYLINKLAYER_RELEASE +/// +/// @brief Release +/// +#define EASYLINKLAYER_RELEASE + +#include "EasyLink.h" + +/// +/// @brief IEEE address +/// @details uint8_t[8] +/// @note CC13xx is little endian +/// + (uint8_t[8])00.12.4B.00.0A.27.CD.6A +/// + but (uint64_t)6ACD270A004B1200 +/// @see http://www.ti.com/lit/ug/swcu117h/swcu117h.pdf +/// +typedef uint8_t AddressIEEE_t[8]; + +/// +/// @brief Addresses filter array +/// @details EASYLINK_MAX_ADDR_SIZE set to 3 +/// +typedef AddressIEEE_t AddressFilter_t[EASYLINK_MAX_ADDR_SIZE]; + +//extern AddressFilter_t addressFilter; + +/// +/// @brief EasyLinkLayer +/// @details Additional layer with address filtering for EasyLink +/// @note Basic usage: begin(), transmit() and receive() +/// +class EasyLinkLayer : public EasyLink +{ + public: + /// + /// @brief Constructor + /// @param[in] flagAddressFiltering Enable address filtering, default=false + /// @note Basic usage: no parameter, no filtering + /// @warning Both RX and TX need to have the same configuration + /// + EasyLinkLayer(bool flagAddressFiltering = false); + + /// + /// @brief Initialise and start the radio + /// @note Basic usage: begin() + /// @return EasyLink_Status_Success or EasyLink_Status_Param_Error + /// + EasyLink_Status begin(); + + /// + /// @brief Send a message + /// @param[in] payload pointer to the payload + /// @param[in] size size of the payload + /// @return EasyLink_Status_Success or EasyLink_Status_Param_Error + /// @note Maximum payload size is EASYLINK_MAX_DATA_LENGTH=128 + /// @note Basic usage: transmit(payload, size) + /// + EasyLink_Status transmit(const void * payload, size_t size); + + /// + /// @brief Receive a message + /// @param[out] payload pointer to the payload + /// @param[out] size size of the payload + /// @param[in] ms period to receive, default=2 seconds, time-out after + /// @return EasyLink_Status_Success or EasyLink_Status_Param_Error + /// @note Maximum payload size is EASYLINK_MAX_DATA_LENGTH=128 + /// @note Basic usage: receive(&payload, &size) + /// + EasyLink_Status receive(void * payload, size_t size, uint32_t ms = 2000); + + /// + /// @brief Set address to addresses filter + /// @param[in] slot 0, 1 or 2 + /// @param[in] address IEEE address to add to filters + /// @return EasyLink_Status_Success or EasyLink_Status_Param_Error + /// @note Up to three addresses can be added to the filter. + /// @n Recommended allocation of addresses + /// * @b Hub + /// * not used + /// * specific IEEE address of the hub + /// * generic address for commissioning nodes to hub + /// * @b Node + /// * general broadcast from hub to all nodes + /// * specific IEEE address of the node + /// * not used + /// @warning Not part of basic usage + /// + EasyLink_Status setAddressFilter(uint8_t slot, AddressIEEE_t address); + + /// + /// @brief Get address to addresses filter + /// @param slot:in 0, 1 or 2 + /// @param address:out IEEE address read from filters + /// @return EasyLink_Status_Success or EasyLink_Status_Param_Error + /// @note The filter contains up to three addresses. + /// @warning Not part of basic usage + /// + EasyLink_Status getAddressFilter(uint8_t slot, AddressIEEE_t * address); + + /// + /// @brief Get local address + /// @details IEEE address uint8_t[8] + /// @param[out] ieeeAddress pointer to uint8_t[8] + /// @return EasyLink_Status + /// + EasyLink_Status getAddressLocal(AddressIEEE_t * ieeeAddress); + + /// + /// @brief Set destination for TX message + /// @param[in] ieeeAddress destination address, uint8_t[8] + /// @warning Not part of basic usage + /// + void setAddressDestinationTX(AddressIEEE_t ieeeAddress); + + /// + /// @brief Get destination from RX message + /// @param[out] ieeeAddress destination address, uint8_t[8] + /// @warning Not part of basic usage + /// + void getAddressDestinationRX(AddressIEEE_t * ieeeAddress); + + /// + /// @brief Get RSSI from RX message + /// @return RSSI level + /// + uint8_t getRSSIRX(); + + private: + bool _flagAddressFiltering; + AddressFilter_t _addressFilter; + EasyLink_TxPacket txPacket; + EasyLink_RxPacket rxPacket; +}; + + +#endif // EASYLINKLAYER_RELEASE