/* * Copyright (c) 2020 Manivannan Sadhasivam * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_LORAWAN_LORAWAN_H_ #define ZEPHYR_INCLUDE_LORAWAN_LORAWAN_H_ /** * @file * @brief Public LoRaWAN APIs * @defgroup lorawan_api LoRaWAN APIs * @since 2.5 * @version 0.1.0 * @ingroup connectivity * @{ */ #include #include #ifdef __cplusplus extern "C" { #endif /** * @brief LoRaWAN class types. */ enum lorawan_class { LORAWAN_CLASS_A = 0x00, /**< Class A device */ LORAWAN_CLASS_B = 0x01, /**< Class B device */ LORAWAN_CLASS_C = 0x02, /**< Class C device */ }; /** * @brief LoRaWAN activation types. */ enum lorawan_act_type { LORAWAN_ACT_OTAA = 0, /**< Over-the-Air Activation (OTAA) */ LORAWAN_ACT_ABP, /**< Activation by Personalization (ABP) */ }; /** * @brief LoRaWAN channels mask sizes. */ enum lorawan_channels_mask_size { LORAWAN_CHANNELS_MASK_SIZE_AS923 = 1, /**< Region AS923 mask size */ LORAWAN_CHANNELS_MASK_SIZE_AU915 = 6, /**< Region AU915 mask size */ LORAWAN_CHANNELS_MASK_SIZE_CN470 = 6, /**< Region CN470 mask size */ LORAWAN_CHANNELS_MASK_SIZE_CN779 = 1, /**< Region CN779 mask size */ LORAWAN_CHANNELS_MASK_SIZE_EU433 = 1, /**< Region EU433 mask size */ LORAWAN_CHANNELS_MASK_SIZE_EU868 = 1, /**< Region EU868 mask size */ LORAWAN_CHANNELS_MASK_SIZE_KR920 = 1, /**< Region KR920 mask size */ LORAWAN_CHANNELS_MASK_SIZE_IN865 = 1, /**< Region IN865 mask size */ LORAWAN_CHANNELS_MASK_SIZE_US915 = 6, /**< Region US915 mask size */ LORAWAN_CHANNELS_MASK_SIZE_RU864 = 1, /**< Region RU864 mask size */ }; /** * @brief LoRaWAN datarate types. */ enum lorawan_datarate { LORAWAN_DR_0 = 0, /**< DR0 data rate */ LORAWAN_DR_1, /**< DR1 data rate */ LORAWAN_DR_2, /**< DR2 data rate */ LORAWAN_DR_3, /**< DR3 data rate */ LORAWAN_DR_4, /**< DR4 data rate */ LORAWAN_DR_5, /**< DR5 data rate */ LORAWAN_DR_6, /**< DR6 data rate */ LORAWAN_DR_7, /**< DR7 data rate */ LORAWAN_DR_8, /**< DR8 data rate */ LORAWAN_DR_9, /**< DR9 data rate */ LORAWAN_DR_10, /**< DR10 data rate */ LORAWAN_DR_11, /**< DR11 data rate */ LORAWAN_DR_12, /**< DR12 data rate */ LORAWAN_DR_13, /**< DR13 data rate */ LORAWAN_DR_14, /**< DR14 data rate */ LORAWAN_DR_15, /**< DR15 data rate */ }; /** * @brief LoRaWAN region types. */ enum lorawan_region { LORAWAN_REGION_AS923, /**< Asia 923 MHz frequency band */ LORAWAN_REGION_AU915, /**< Australia 915 MHz frequency band */ LORAWAN_REGION_CN470, /**< China 470 MHz frequency band */ LORAWAN_REGION_CN779, /**< China 779 MHz frequency band */ LORAWAN_REGION_EU433, /**< Europe 433 MHz frequency band */ LORAWAN_REGION_EU868, /**< Europe 868 MHz frequency band */ LORAWAN_REGION_KR920, /**< South Korea 920 MHz frequency band */ LORAWAN_REGION_IN865, /**< India 865 MHz frequency band */ LORAWAN_REGION_US915, /**< United States 915 MHz frequency band */ LORAWAN_REGION_RU864, /**< Russia 864 MHz frequency band */ }; /** * @brief LoRaWAN message types. */ enum lorawan_message_type { LORAWAN_MSG_UNCONFIRMED = 0, /**< Unconfirmed message */ LORAWAN_MSG_CONFIRMED, /**< Confirmed message */ }; /** * @brief LoRaWAN downlink flags. */ enum lorawan_dl_flags { LORAWAN_DATA_PENDING = BIT(0), LORAWAN_TIME_UPDATED = BIT(1), }; /** * @brief LoRaWAN join parameters for over-the-Air activation (OTAA) * * Note that all of the fields use LoRaWAN 1.1 terminology. * * All parameters are optional if a secure element is present in which * case the values stored in the secure element will be used instead. */ struct lorawan_join_otaa { /** Join EUI */ uint8_t *join_eui; /** Network Key */ uint8_t *nwk_key; /** Application Key */ uint8_t *app_key; /** * Device Nonce * * Starting with LoRaWAN 1.0.4 the DevNonce must be monotonically * increasing for each OTAA join with the same EUI. The DevNonce * should be stored in non-volatile memory by the application. */ uint16_t dev_nonce; }; /** * @brief LoRaWAN join parameters for activation by personalization (ABP) */ struct lorawan_join_abp { /** Device address on the network */ uint32_t dev_addr; /** Application session key */ uint8_t *app_skey; /** Network session key */ uint8_t *nwk_skey; /** Application EUI */ uint8_t *app_eui; }; /** * @brief LoRaWAN join parameters */ struct lorawan_join_config { /** Join parameters */ union { struct lorawan_join_otaa otaa; /**< OTAA join parameters */ struct lorawan_join_abp abp; /**< ABP join parameters */ }; /** Device EUI. Optional if a secure element is present. */ uint8_t *dev_eui; /** Activation mode */ enum lorawan_act_type mode; }; /** Flag to indicate receiving on any port */ #define LW_RECV_PORT_ANY UINT16_MAX /** * @brief LoRaWAN downlink callback parameters */ struct lorawan_downlink_cb { /** * @brief Port to handle messages for. * * - Port 0: TX packet acknowledgements * - Ports 1-255: Standard downlink port * - LW_RECV_PORT_ANY: All downlinks */ uint16_t port; /** * @brief Callback function to run on downlink data * * @note Callbacks are run on the system workqueue, * and should therefore be as short as possible. * * @param port Port message was sent on * @param flags Downlink data flags (see @ref lorawan_dl_flags) * @param rssi Received signal strength in dBm * @param snr Signal to Noise ratio in dBm * @param len Length of data received, will be 0 for ACKs * @param data Data received, will be NULL for ACKs */ void (*cb)(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len, const uint8_t *data); /** Node for callback list */ sys_snode_t node; }; /** * @brief Defines the battery level callback handler function signature. * * @retval 0 if the node is connected to an external power source * @retval 1..254 battery level, where 1 is the minimum and 254 is the maximum value * @retval 255 if the node was not able to measure the battery level */ typedef uint8_t (*lorawan_battery_level_cb_t)(void); /** * @brief Defines the datarate changed callback handler function signature. * * @param dr Updated datarate. */ typedef void (*lorawan_dr_changed_cb_t)(enum lorawan_datarate dr); /** * @brief Register a battery level callback function. * * Provide the LoRaWAN stack with a function to be called whenever a battery * level needs to be read. * * Should no callback be provided the lorawan backend will report 255. * * @param cb Pointer to the battery level function */ void lorawan_register_battery_level_callback(lorawan_battery_level_cb_t cb); /** * @brief Register a callback to be run on downlink packets * * @param cb Pointer to structure containing callback parameters */ void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb); /** * @brief Register a callback to be called when the datarate changes * * The callback is called once upon successfully joining a network and again * each time the datarate changes due to ADR. * * @param cb Pointer to datarate update callback */ void lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb); /** * @brief Join the LoRaWAN network * * Join the LoRaWAN network using OTAA or AWB. * * @param config Configuration to be used * * @return 0 if successful, negative errno code if failure */ int lorawan_join(const struct lorawan_join_config *config); /** * @brief Start the LoRaWAN stack * * This function need to be called before joining the network. * * @return 0 if successful, negative errno code if failure */ int lorawan_start(void); /** * @brief Send data to the LoRaWAN network * * Send data to the connected LoRaWAN network. * * @param port Port to be used for sending data. Must be set if the * payload is not empty. * @param data Data buffer to be sent * @param len Length of the buffer to be sent. Maximum length of this * buffer is 255 bytes but the actual payload size varies with * region and datarate. * @param type Specifies if the message shall be confirmed or unconfirmed. * Must be one of @ref lorawan_message_type. * * @return 0 if successful, negative errno code if failure */ int lorawan_send(uint8_t port, uint8_t *data, uint8_t len, enum lorawan_message_type type); /** * @brief Set the current device class * * Change the current device class. This function may be called before * or after a network connection has been established. * * @param dev_class New device class * * @return 0 if successful, negative errno code if failure */ int lorawan_set_class(enum lorawan_class dev_class); /** * @brief Set the number of tries used for transmissions * * @param tries Number of tries to be used * * @return 0 if successful, negative errno code if failure */ int lorawan_set_conf_msg_tries(uint8_t tries); /** * @brief Enable Adaptive Data Rate (ADR) * * Control whether adaptive data rate (ADR) is enabled. When ADR is enabled, * the data rate is treated as a default data rate that will be used if the * ADR algorithm has not established a data rate. ADR should normally only * be enabled for devices with stable RF conditions (i.e., devices in a mostly * static location). * * @param enable Enable or Disable adaptive data rate. */ void lorawan_enable_adr(bool enable); /** * @brief Set the channels mask. * * Change the default channels mask. When mask is not changed, all the channels * can be used for data transmission. Some Network Servers don't use all the channels, * in this case, the channels mask must be provided. * * @param channels_mask Buffer with channels mask to be used. * @param channels_mask_size Size of channels mask buffer. * * @retval 0 successful * @retval -EINVAL channels mask or channels mask size is wrong */ int lorawan_set_channels_mask(uint16_t *channels_mask, size_t channels_mask_size); /** * @brief Set the default data rate * * Change the default data rate. * * @param dr Data rate used for transmissions * * @return 0 if successful, negative errno code if failure */ int lorawan_set_datarate(enum lorawan_datarate dr); /** * @brief Get the minimum possible datarate * * The minimum possible datarate may change in response to a TxParamSetupReq * command from the network server. * * @return Minimum possible data rate */ enum lorawan_datarate lorawan_get_min_datarate(void); /** * @brief Get the current payload sizes * * Query the current payload sizes. The maximum payload size varies with * datarate, while the current payload size can be less due to MAC layer * commands which are inserted into uplink packets. * * @param max_next_payload_size Maximum payload size for the next transmission * @param max_payload_size Maximum payload size for this datarate */ void lorawan_get_payload_sizes(uint8_t *max_next_payload_size, uint8_t *max_payload_size); /** * @brief Set the region and frequency to be used * * Control the LoRa region and frequency settings. This should be called before * @a lorawan_start(). If you only have support for a single region selected via * Kconfig, this function does not need to be called at all. * * @param region The region to be selected * @return 0 if successful, negative errno otherwise */ int lorawan_set_region(enum lorawan_region region); /** * @brief Request for time according to DeviceTimeReq MAC cmd * * Append MAC DevTimeReq command. It will be processed on next send * message or force sending empty message to request time immediately. * * @param force_request Immediately send an empty message to execute the request * @return 0 if successful, negative errno otherwise */ int lorawan_request_device_time(bool force_request); /** * @brief Retrieve the current time from LoRaWAN stack updated by * DeviceTimeAns on MAC layer. * * This function uses the GPS epoch format, as used in all LoRaWAN services. * * The GPS epoch started on 1980-01-06T00:00:00Z, but has since diverged * from UTC, as it does not consider corrections like leap seconds. * * @param gps_time Synchronized time in GPS epoch format truncated to 32-bit. * * @return 0 if successful, -EAGAIN if the clock is not yet synchronized. */ int lorawan_device_time_get(uint32_t *gps_time); #ifdef CONFIG_LORAWAN_APP_CLOCK_SYNC /** * @brief Run Application Layer Clock Synchronization service * * This service sends out its current time in a regular interval (configurable * via Kconfig) and receives a correction offset from the application server if * the clock deviation is considered too large. * * Clock synchronization is required for firmware upgrades over multicast * sessions, but can also be used independent of a FUOTA process. * * @return 0 if successful, negative errno otherwise. */ int lorawan_clock_sync_run(void); /** * @brief Retrieve the current synchronized time * * This function uses the GPS epoch format, as used in all LoRaWAN services. * * The GPS epoch started on 1980-01-06T00:00:00Z, but has since diverged * from UTC, as it does not consider corrections like leap seconds. * * @param gps_time Synchronized time in GPS epoch format truncated to 32-bit. * * @return 0 if successful, -EAGAIN if the clock is not yet synchronized. */ int lorawan_clock_sync_get(uint32_t *gps_time); #endif /* CONFIG_LORAWAN_APP_CLOCK_SYNC */ #ifdef CONFIG_LORAWAN_FRAG_TRANSPORT /** * @brief Run Fragmented Data Block Transport service * * This service receives fragmented data (usually firmware images) and * stores them in the image-1 flash partition. * * After all fragments have been received, the provided callback is invoked. * * @param transport_finished_cb Callback for notification of finished data transfer. * * @return 0 if successful, negative errno otherwise. */ int lorawan_frag_transport_run(void (*transport_finished_cb)(void)); #endif /* CONFIG_LORAWAN_FRAG_TRANSPORT */ #ifdef __cplusplus } #endif /** * @} */ #endif /* ZEPHYR_INCLUDE_LORAWAN_LORAWAN_H_ */