mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers: add rn2xx3 LoRa module driver
This commit is contained in:
parent
5c0b058db4
commit
b63412efa1
@ -230,6 +230,14 @@ ifneq (,$(filter rgbled,$(USEMODULE)))
|
||||
USEMODULE += color
|
||||
endif
|
||||
|
||||
ifneq (,$(filter rn2%3,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
FEATURES_REQUIRED += periph_uart
|
||||
USEMODULE += xtimer
|
||||
USEMODULE += rn2xx3
|
||||
USEMODULE += fmt
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sdcard_spi,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
FEATURES_REQUIRED += periph_spi
|
||||
|
@ -157,3 +157,6 @@ endif
|
||||
ifneq (,$(filter lis3mdl,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis3mdl/include
|
||||
endif
|
||||
ifneq (,$(filter rn2%3,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/rn2xx3/include
|
||||
endif
|
||||
|
690
drivers/include/rn2xx3.h
Normal file
690
drivers/include/rn2xx3.h
Normal file
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_rn2xx3 RN2483/RN2903 LoRa module driver
|
||||
* @ingroup drivers_netdev
|
||||
* @brief High-level driver for the RN2483/RN2903 LoRa modules
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief High-level driver for the RN2483/RN2903 LoRa modules
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef RN2XX3_H
|
||||
#define RN2XX3_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "xtimer.h"
|
||||
#include "periph/uart.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "net/netdev.h"
|
||||
|
||||
#include "net/loramac.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Maximum length of an exchanged messages with commands
|
||||
*/
|
||||
#define RN2XX3_MAX_BUF (40U)
|
||||
|
||||
/**
|
||||
* @brief Maximum length of an RX message
|
||||
*
|
||||
* LoRaMAC payload can be up to 250 bytes.
|
||||
*/
|
||||
#define RN2XX3_RX_MAX_BUF (250U)
|
||||
|
||||
/**
|
||||
* @brief Maximum delay in second to receive a reply from server.
|
||||
*/
|
||||
#define RN2XX3_REPLY_DELAY_TIMEOUT (60U)
|
||||
|
||||
/**
|
||||
* @brief Minimum sleep duration (in ms)
|
||||
*/
|
||||
#define RN2XX3_SLEEP_MIN (100U)
|
||||
|
||||
/**
|
||||
* @brief Default sleep duration (in ms)
|
||||
*/
|
||||
#ifndef RN2XX3_DEFAULT_SLEEP
|
||||
#define RN2XX3_DEFAULT_SLEEP (5000U)
|
||||
#endif
|
||||
|
||||
#if defined(MODULE_RN2903)
|
||||
#define RN2XX3_FREQ_BAND (915U)
|
||||
#elif defined(MODULE_RN2483)
|
||||
#define RN2XX3_FREQ_BAND (868U)
|
||||
#else
|
||||
#error "Unsupported module type, use either RN2483 or RN2903"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Command responses and server replies status codes
|
||||
*/
|
||||
enum {
|
||||
RN2XX3_OK, /**< Command is valid */
|
||||
RN2XX3_DATA, /**< Command returned data */
|
||||
RN2XX3_TIMEOUT, /**< Command timeout */
|
||||
/* all other error codes */
|
||||
RN2XX3_ERR_MAC_INIT, /**< Device mac initialization failed */
|
||||
RN2XX3_ERR_INVALID_PARAM, /**< Wrong command given */
|
||||
RN2XX3_ERR_NOT_JOINED, /**< Network is not joined */
|
||||
RN2XX3_ERR_NO_FREE_CH, /**< All channels are busy */
|
||||
RN2XX3_ERR_SILENT, /**< Device is in Silent Immediately state */
|
||||
RN2XX3_ERR_FR_CNT_REJOIN_NEEDED, /**< Frame counter rolled over */
|
||||
RN2XX3_ERR_BUSY, /**< MAC is not in Idle state */
|
||||
RN2XX3_ERR_MAC_PAUSED, /**< MAC was paused */
|
||||
RN2XX3_ERR_INVALID_DATA_LENGTH, /**< Wrong payload given */
|
||||
RN2XX3_ERR_KEYS_NOT_INIT, /**< Keys not configured ("mac join" command) */
|
||||
RN2XX3_ERR_SLEEP_MODE, /**< Failure because device is in sleep mode */
|
||||
/* all other reply codes */
|
||||
RN2XX3_REPLY_TX_MAC_OK, /**< MAC transmission successful */
|
||||
RN2XX3_REPLY_TX_MAC_ERR, /**< MAC transmission failed */
|
||||
RN2XX3_REPLY_TX_INVALID_DATA_LEN, /**< Application payload too large */
|
||||
RN2XX3_REPLY_TX_MAC_RX, /**< Data received from server */
|
||||
RN2XX3_REPLY_JOIN_ACCEPTED, /**< Join procedure successful */
|
||||
RN2XX3_REPLY_JOIN_DENIED, /**< Join procedure failed */
|
||||
RN2XX3_REPLY_TIMEOUT, /**< No MAC reply received from server */
|
||||
RN2XX3_REPLY_OTHER, /**< Unknown reply */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Internal states of the device
|
||||
*/
|
||||
enum {
|
||||
RN2XX3_INT_STATE_RESET, /**< the device is being reset or initialized */
|
||||
RN2XX3_INT_STATE_CMD, /**< waiting command response */
|
||||
RN2XX3_INT_STATE_IDLE, /**< waiting for incoming commands */
|
||||
RN2XX3_INT_STATE_SLEEP, /**< sleep mode */
|
||||
RN2XX3_INT_STATE_MAC_JOIN, /**< waiting for mac join procedure reply */
|
||||
RN2XX3_INT_STATE_MAC_TX, /**< waiting for mac tx reply */
|
||||
RN2XX3_INT_STATE_MAC_RX_PORT, /**< waiting for mac rx port */
|
||||
RN2XX3_INT_STATE_MAC_RX_MESSAGE, /**< waiting for mac rx message */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief LoRaMAC communication settings
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t rx2_freq; /**< Center frequency used for second receive window */
|
||||
loramac_dr_idx_t rx2_dr; /**< Datarate used for second receive window */
|
||||
uint8_t tx_port; /**< Application TX port (between 1 and 223) */
|
||||
loramac_tx_mode_t tx_mode; /**< TX mode, either confirmable of unconfirmable */
|
||||
uint8_t rx_port; /**< RX port (between 1 and 223) */
|
||||
} loramac_settings_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration parameters for RN2483/RN2903 devices
|
||||
*/
|
||||
typedef struct {
|
||||
uart_t uart; /**< UART interfaced the device is connected to */
|
||||
uint32_t baudrate; /**< baudrate to use */
|
||||
gpio_t pin_reset; /**< GPIO pin that is connected to the STATUS pin
|
||||
set to GPIO_UNDEF if not used */
|
||||
} rn2xx3_params_t;
|
||||
|
||||
/**
|
||||
* @brief RN2483/RN2903 device descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
netdev_t netdev; /**< Netdev parent struct */
|
||||
/* device driver specific fields */
|
||||
rn2xx3_params_t p; /**< configuration parameters */
|
||||
loramac_settings_t loramac; /**< loramac communication settings */
|
||||
|
||||
/* values for the UART TX state machine */
|
||||
char cmd_buf[RN2XX3_MAX_BUF]; /**< command to send data buffer */
|
||||
mutex_t cmd_lock; /**< mutex to allow only one
|
||||
* command at a time */
|
||||
uint8_t int_state; /**< current state of the device */
|
||||
|
||||
/* buffer and synchronization for command responses */
|
||||
mutex_t resp_lock; /**< mutex for waiting for command
|
||||
* response */
|
||||
char resp_buf[RN2XX3_MAX_BUF]; /**< command response data buffer */
|
||||
uint16_t resp_size; /**< counter for received char in response */
|
||||
uint8_t resp_done; /**< check if response has completed */
|
||||
|
||||
/* buffer for RX messages */
|
||||
char rx_tmp_buf[2]; /**< Temporary RX buffer used to convert
|
||||
* 2 hex characters in one byte on the
|
||||
* fly. */
|
||||
uint8_t rx_buf[RN2XX3_RX_MAX_BUF]; /**< RX data buffer */
|
||||
uint16_t rx_size; /**< counter for received char in RX */
|
||||
|
||||
/* timers */
|
||||
xtimer_t sleep_timer; /**< Timer used to count module sleep time */
|
||||
uint32_t sleep; /**< module sleep duration */
|
||||
} rn2xx3_t;
|
||||
|
||||
/**
|
||||
* @brief Prepares the given RN2XX3 device
|
||||
*
|
||||
* @param[out] dev RN2XX3 device to initialize
|
||||
* @param[in] params parameters for device initialization
|
||||
*/
|
||||
void rn2xx3_setup(rn2xx3_t *dev, const rn2xx3_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Initializes the RN2XX3 device
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return -ENXIO if UART initialization failed
|
||||
* @return RN2XX3_TIMEOUT if UART communication failed
|
||||
*/
|
||||
int rn2xx3_init(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Restarts the RN2XX2 device
|
||||
*
|
||||
* After calling this function, dev->resp_buf contains the module
|
||||
* name and version string.
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_TIMEOUT if UART communication failed
|
||||
*/
|
||||
int rn2xx3_sys_reset(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Performs a factory reset of the module
|
||||
*
|
||||
* The configuration data and user EEPPROM are reinitialized to factory default
|
||||
* values and the module reboots
|
||||
*
|
||||
* After calling this function, dev->resp_buf contains the module name and
|
||||
* version string.
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_TIMEOUT if UART communication failed
|
||||
*/
|
||||
int rn2xx3_sys_factory_reset(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Puts the RN2XX2 device in sleep mode
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_TIMEOUT if UART communication failed
|
||||
*/
|
||||
int rn2xx3_sys_sleep(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Initializes the RN2XX3 device MAC layer
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_TIMEOUT if UART communication failed
|
||||
*/
|
||||
int rn2xx3_mac_init(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Writes a command to the RN2XX3 device
|
||||
*
|
||||
* The module will immediately reply with a meaningful message if the command
|
||||
* is valid or not.
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_TIMEOUT if no response is received from the module
|
||||
* @return RN2XX3_ERR_INVALID_PARAM if command is invalid
|
||||
* @return RN2XX3_ERR_NOT_JOINED if network is not joined
|
||||
* @return RN2XX3_ERR_NO_FREE_CH if no free channel
|
||||
* @return RN2XX3_ERR_SILENT if device is in Silent state
|
||||
* @return RN2XX3_ERR_FR_CNT_REJOIN_NEEDED if frame counter rolled over
|
||||
* @return RN2XX3_ERR_BUSY if MAC is not in Idle state
|
||||
* @return RN2XX3_ERR_INVALID_DATA_LENGTH if payload is too large
|
||||
* @return RN2XX3_ERR_KEYS_NOT_INIT if keys are not configured
|
||||
*/
|
||||
int rn2xx3_write_cmd(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Writes a command to the RN2XX3 device but don't wait for timeout
|
||||
*
|
||||
* The module will immediately reply with a meaningful message if the command
|
||||
* is valid or not.
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_ERR_INVALID_PARAM if command is invalid
|
||||
* @return RN2XX3_ERR_NOT_JOINED if network is not joined
|
||||
* @return RN2XX3_ERR_NO_FREE_CH if no free channel
|
||||
* @return RN2XX3_ERR_SILENT if device is in Silent state
|
||||
* @return RN2XX3_ERR_FR_CNT_REJOIN_NEEDED if frame counter rolled over
|
||||
* @return RN2XX3_ERR_BUSY if MAC is not in Idle state
|
||||
* @return RN2XX3_ERR_INVALID_DATA_LENGTH if payload is too large
|
||||
* @return RN2XX3_ERR_KEYS_NOT_INIT if keys are not configured
|
||||
*/
|
||||
int rn2xx3_write_cmd_no_wait(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Waits for a response to a command from the device
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK on success
|
||||
* @return RN2XX3_TIMEOUT if no response is received from the module
|
||||
* @return RN2XX3_ERR_INVALID_PARAM if command is invalid
|
||||
* @return RN2XX3_ERR_NOT_JOINED if network is not joined
|
||||
* @return RN2XX3_ERR_NO_FREE_CH if no free channel
|
||||
* @return RN2XX3_ERR_SILENT if device is in Silent state
|
||||
* @return RN2XX3_ERR_FR_CNT_REJOIN_NEEDED if frame counter rolled over
|
||||
* @return RN2XX3_ERR_BUSY if MAC is not in Idle state
|
||||
* @return RN2XX3_ERR_INVALID_DATA_LENGTH if payload is too large
|
||||
* @return RN2XX3_ERR_KEYS_NOT_INIT if keys are not configured
|
||||
*/
|
||||
int rn2xx3_wait_response(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Waits for a reply from the LoRaWAN network
|
||||
*
|
||||
* @param[in] dev LoRaBee device descriptor
|
||||
* @param[in] timeout Reply wait timeout in seconds
|
||||
*
|
||||
* @return RN2XX3_REPLY_TIMEOUT when no MAC reply is received from server
|
||||
* @return RN2XX3_REPLY_TX_MAC_OK when MAC transmission succeeded
|
||||
* @return RN2XX3_REPLY_TX_MAC_ERR when MAC transmission failed
|
||||
* @return RN2XX3_REPLY_TX_MAC_RX when received downlink data from server
|
||||
* @return RN2XX3_REPLY_TX_INVALID_DATA_LEN when Application payload is too large
|
||||
* @return RN2XX3_REPLY_JOIN_ACCEPTED when the join procedure succeded
|
||||
* @return RN2XX3_REPLY_JOIN_DENIED when the join procedure failed
|
||||
* @return RN2XX3_REPLY_OTHER when an unknown reply is received
|
||||
*/
|
||||
int rn2xx3_wait_reply(rn2xx3_t *dev, uint8_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Sends data to LoRaWAN server
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
* @param[in] payload Payload to transmit
|
||||
* @param[in] payload_len Payload length to transmit
|
||||
*
|
||||
* @return RN2XX3_ERR_KEYS_NOT_INIT if the loramac params are not configured
|
||||
* @return RN2XX3_ERR_NO_FREE_CH if channels are busy
|
||||
* @return RN2XX3_ERR_SILENT if device is in Silent state
|
||||
* @return RN2XX3_ERR_BUSY if MAC layer is in idle state
|
||||
* @return RN2XX3_ERR_MAC_PAUSED if MAC layed is paused
|
||||
* @return RN2XX3_REPLY_TX_INVALID_DATA_LEN if payload is too large
|
||||
* @return RN2XX3_REPLY_TX_MAC_ERR when MAC transmission failed
|
||||
* @return RN2XX3_REPLY_TX_MAC_RX when received downlink data from server
|
||||
* @return RN2XX3_REPLY_TX_MAC_OK when MAC transmission succeeded
|
||||
*/
|
||||
int rn2xx3_mac_tx(rn2xx3_t *dev, uint8_t *payload, uint8_t payload_len);
|
||||
|
||||
/**
|
||||
* @brief Starts network activation procedure
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
* @param[in] mode Activation procedure type
|
||||
*
|
||||
* @return RN2XX3_ERR_KEYS_NOT_INIT if the loramac params are not configured
|
||||
* @return RN2XX3_ERR_NO_FREE_CH if channels are busy
|
||||
* @return RN2XX3_ERR_SILENT if device is in Silent state
|
||||
* @return RN2XX3_ERR_BUSY if MAC layer is in idle state
|
||||
* @return RN2XX3_ERR_MAC_PAUSED if MAC layed is paused
|
||||
* @return RN2XX3_REPLY_JOIN_ACCEPTED when the join procedure succeded
|
||||
* @return RN2XX3_REPLY_JOIN_DENIED when the join procedure failed
|
||||
*/
|
||||
int rn2xx3_mac_join_network(rn2xx3_t *dev, loramac_join_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Saves current LoRaMAC configuration to internal EEPROM
|
||||
*
|
||||
* The configuration parameters saved are: frequency band, end device EUI,
|
||||
* application EUI, application key, network session key, application session
|
||||
* key, end device EUI and all channel parameters.
|
||||
*
|
||||
* @param[in] dev RN2XX3 device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK if all is ok
|
||||
* @return RN2XX3_TIMEOUT if the device didn't reply
|
||||
*/
|
||||
int rn2xx3_mac_save(rn2xx3_t *dev);
|
||||
|
||||
/* Get/Set functions definitions */
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC device EUI
|
||||
*
|
||||
* The device EUI is an array of 8 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[out] eui The device EUI
|
||||
*/
|
||||
void rn2xx3_mac_get_deveui(rn2xx3_t *dev, uint8_t *eui);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC device EUI
|
||||
*
|
||||
* The device EUI is an array of 8 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] eui The device EUI
|
||||
*/
|
||||
void rn2xx3_mac_set_deveui(rn2xx3_t *dev, const uint8_t *eui);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC application EUI
|
||||
*
|
||||
* The application EUI is an array of 8 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[out] eui The application EUI
|
||||
*/
|
||||
void rn2xx3_mac_get_appeui(rn2xx3_t *dev, uint8_t *eui);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC application EUI
|
||||
*
|
||||
* The application key is an array of 8 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] eui The application EUI
|
||||
*/
|
||||
void rn2xx3_mac_set_appeui(rn2xx3_t *dev, const uint8_t *eui);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC application key
|
||||
*
|
||||
* The application key is an array of 16 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] key The application key
|
||||
*/
|
||||
void rn2xx3_mac_set_appkey(rn2xx3_t *dev, const uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC application session key
|
||||
*
|
||||
* The application session key is an array of 16 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] key The application session key
|
||||
*/
|
||||
void rn2xx3_mac_set_appskey(rn2xx3_t *dev, const uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC network session key
|
||||
*
|
||||
* The network session key is an array of 16 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] key The network session key
|
||||
*/
|
||||
void rn2xx3_mac_set_nwkskey(rn2xx3_t *dev, const uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC device address
|
||||
*
|
||||
* The device address is an array of 4 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[out] addr The device address
|
||||
*/
|
||||
void rn2xx3_mac_get_devaddr(rn2xx3_t *dev, uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC device address
|
||||
*
|
||||
* The device address is an array of 4 bytes.
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] addr The device address
|
||||
*/
|
||||
void rn2xx3_mac_set_devaddr(rn2xx3_t *dev, const uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC TX radio power index
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The radio power index
|
||||
*/
|
||||
loramac_tx_pwr_idx_t rn2xx3_mac_get_tx_power(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC transmission power index
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] power The TX power index
|
||||
*/
|
||||
void rn2xx3_mac_set_tx_power(rn2xx3_t *dev, loramac_tx_pwr_idx_t power);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC datarate
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The datarate
|
||||
*/
|
||||
loramac_dr_idx_t rn2xx3_mac_get_dr(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC datarate
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] dr The datarate
|
||||
*/
|
||||
void rn2xx3_mac_set_dr(rn2xx3_t *dev, loramac_dr_idx_t dr);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC frequency band in operation
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The frequency band
|
||||
*/
|
||||
uint16_t rn2xx3_mac_get_band(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Checks if the rn2xx3 LoRaMAC adaptive datarate is enabled/disabled
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return true if adaptive datarate is set,
|
||||
* false otherwise
|
||||
*/
|
||||
bool rn2xx3_mac_get_adr(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enables/disables the rn2xx3 LoRaMAC adaptive datarate
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] adr The adaptive datarate mode
|
||||
*/
|
||||
void rn2xx3_mac_set_adr(rn2xx3_t *dev, bool adr);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 battery level measured by the end device
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] battery The battery level:
|
||||
* - 0 means external power,
|
||||
* - 1 means low level,
|
||||
* - 254 high level,
|
||||
* - 255 means the battery level couldn't be
|
||||
* measured by the device.
|
||||
*/
|
||||
void rn2xx3_mac_set_battery(rn2xx3_t *dev, uint8_t battery);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC uplink retransmission retries number
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The number of uplink retransmission retries
|
||||
*/
|
||||
uint8_t rn2xx3_mac_get_retx(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC uplink retransmission retries number
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] retx The number of uplink retransmission retries
|
||||
*/
|
||||
void rn2xx3_mac_set_retx(rn2xx3_t *dev, uint8_t retx);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC link check interval (in seconds)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] linkchk The link check interval in seconds
|
||||
*/
|
||||
void rn2xx3_mac_set_linkchk_interval(rn2xx3_t *dev, uint16_t linkchk);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC interval delay before the first reception window (in ms)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The delay in ms
|
||||
*/
|
||||
uint16_t rn2xx3_mac_get_rx1_delay(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC interval delay before the first reception window (in ms)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] rx1 The delay in ms
|
||||
*/
|
||||
void rn2xx3_mac_set_rx1_delay(rn2xx3_t *dev, uint16_t rx1);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC interval delay before the second reception window (in ms)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The delay in ms
|
||||
*/
|
||||
uint16_t rn2xx3_mac_get_rx2_delay(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Checks the rn2xx3 LoRaMAC automatic reply state
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The automatic reply state
|
||||
*/
|
||||
bool rn2xx3_mac_get_ar(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enables/disables LoRaMAC rn2xx3 MAC automatic reply state
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] ar The automatic reply state
|
||||
*/
|
||||
void rn2xx3_mac_set_ar(rn2xx3_t *dev, bool ar);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC datarate used for second receive window
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The datarate during second receive window
|
||||
*/
|
||||
loramac_dr_idx_t rn2xx3_mac_get_rx2_dr(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC datarate used for second receive window
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] dr The datarate during second receive window
|
||||
*/
|
||||
void rn2xx3_mac_set_rx2_dr(rn2xx3_t *dev, loramac_dr_idx_t dr);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC frequency used during second receive window (in Hz)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The frequency during second receive window
|
||||
*/
|
||||
uint32_t rn2xx3_mac_get_rx2_freq(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC frequency used during second receive window (in Hz)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] freq The frequency during second receive window
|
||||
*/
|
||||
void rn2xx3_mac_set_rx2_freq(rn2xx3_t *dev, uint32_t freq);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC TX port
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The TX port
|
||||
*/
|
||||
uint8_t rn2xx3_mac_get_tx_port(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC TX port
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] port The TX port (from 1 to 223)
|
||||
*/
|
||||
void rn2xx3_mac_set_tx_port(rn2xx3_t *dev, uint8_t port);
|
||||
|
||||
/**
|
||||
* @brief Gets the rn2xx3 LoRaMAC TX mode
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The TX mode, either confirmable or unconfirmable
|
||||
*/
|
||||
loramac_tx_mode_t rn2xx3_mac_get_tx_mode(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 LoRaMAC TX mode
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] mode The TX mode, either confirmable or unconfirmable
|
||||
*/
|
||||
void rn2xx3_mac_set_tx_mode(rn2xx3_t *dev, loramac_tx_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Parses the response buffer to get the LoRaWAN RX port
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
*
|
||||
* @return The RX port (between 1 and 223)
|
||||
*/
|
||||
uint8_t rn2xx3_mac_get_rx_port(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the rn2xx3 sleep mode duration (in ms)
|
||||
*
|
||||
* @param[in] dev The rn2xx3 device descriptor
|
||||
* @param[in] sleep The sleep mode duration (ms)
|
||||
*/
|
||||
void rn2xx3_sys_set_sleep_duration(rn2xx3_t *dev, uint32_t sleep);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RN2XX3_H */
|
||||
/** @} */
|
1
drivers/rn2xx3/Makefile
Normal file
1
drivers/rn2xx3/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
117
drivers/rn2xx3/include/rn2xx3_internal.h
Normal file
117
drivers/rn2xx3/include/rn2xx3_internal.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_rn2xx3
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Internal driver definitions for the RN2483/RN2903 LoRa modules
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef RN2XX3_INTERNAL_H
|
||||
#define RN2XX3_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rn2xx3.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Convert a string of hex to an array of bytes
|
||||
*
|
||||
* This functions is faster than `fmt_hex_bytes` that doesn't work if it is
|
||||
* used in the module UART interrupt callback.
|
||||
*
|
||||
* @param[in] hex The string of hex to convert
|
||||
* @param[out] byte_array The resulting array of bytes
|
||||
*/
|
||||
void rn2xx3_hex_to_bytes(const char *hex, uint8_t *byte_array);
|
||||
|
||||
/**
|
||||
* @brief Sets internal device state
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
* @param[in] state The desired state
|
||||
*/
|
||||
void rn2xx3_set_internal_state(rn2xx3_t *dev, uint8_t state);
|
||||
|
||||
/**
|
||||
* @brief Starts writing a command with the content of the device command buffer
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
*/
|
||||
void rn2xx3_cmd_start(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Appends data to a command
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
* @param[in] data The data buffer
|
||||
* @param[in] data_len The data max length
|
||||
*/
|
||||
void rn2xx3_cmd_append(rn2xx3_t *dev, const uint8_t *data, uint8_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Finalize a command
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK if the command succeeded
|
||||
* @return RN2XX3_ERR_* otherwise
|
||||
*/
|
||||
int rn2xx3_cmd_finalize(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Starts writing a tx command
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
*/
|
||||
void rn2xx3_mac_tx_start(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Finalize the TX command
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK if the command succeeded
|
||||
* @return RN2XX3_REPLY_* otherwise
|
||||
*/
|
||||
int rn2xx3_mac_tx_finalize(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Process a command immediate response
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK if the command succeeded
|
||||
* @return RN2XX3_ERR_* otherwise
|
||||
*/
|
||||
int rn2xx3_process_response(rn2xx3_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Process a command network reply
|
||||
*
|
||||
* @param[in] dev The device descriptor
|
||||
*
|
||||
* @return RN2XX3_OK if the command succeeded
|
||||
* @return RN2XX3_REPLY_* otherwise
|
||||
*/
|
||||
int rn2xx3_process_reply(rn2xx3_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RN2XX3_INTERNAL_H */
|
||||
/** @} */
|
62
drivers/rn2xx3/include/rn2xx3_params.h
Normal file
62
drivers/rn2xx3/include/rn2xx3_params.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_rn2xx3
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Default configuration for RN2483/RN2903 devices
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef RN2XX3_PARAMS_H
|
||||
#define RN2XX3_PARAMS_H
|
||||
|
||||
#include "rn2xx3.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Set default configuration parameters for the RN2483/RN2903 driver
|
||||
* @{
|
||||
*/
|
||||
#ifndef RN2XX3_PARAM_UART
|
||||
#define RN2XX3_PARAM_UART UART_DEV(1)
|
||||
#endif
|
||||
#ifndef RN2XX3_PARAM_BAUDRATE
|
||||
#define RN2XX3_PARAM_BAUDRATE (57600U)
|
||||
#endif
|
||||
#ifndef RN2XX3_PARAM_PIN_RESET
|
||||
#define RN2XX3_PARAM_PIN_RESET (GPIO_UNDEF)
|
||||
#endif
|
||||
|
||||
#ifndef RN2XX3_PARAMS
|
||||
#define RN2XX3_PARAMS { .uart = RN2XX3_PARAM_UART, \
|
||||
.baudrate = RN2XX3_PARAM_BAUDRATE, \
|
||||
.pin_reset = RN2XX3_PARAM_PIN_RESET }
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @brief RN2483/RN2903 configuration
|
||||
*/
|
||||
static const rn2xx3_params_t rn2xx3_params[] =
|
||||
{
|
||||
RN2XX3_PARAMS
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RN2XX3_PARAMS_H */
|
||||
/** @} */
|
309
drivers/rn2xx3/rn2xx3.c
Normal file
309
drivers/rn2xx3/rn2xx3.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_rn2xx3
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Driver implementation for the RN2483/RN2903 devices
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "xtimer.h"
|
||||
#include "fmt.h"
|
||||
#include "rn2xx3_params.h"
|
||||
#include "rn2xx3.h"
|
||||
#include "rn2xx3_internal.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
/* Warning: to correctly display the debug message from sleep timer callback,,
|
||||
add CFLAGS+=-DTHREAD_STACKSIZE_IDLE=THREAD_STACKSIZE_DEFAULT to the build
|
||||
command.
|
||||
*/
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Delay when resetting the device, 10ms
|
||||
*/
|
||||
#define RESET_DELAY (10UL * US_PER_MS)
|
||||
|
||||
/*
|
||||
* Interrupt callbacks
|
||||
*/
|
||||
static void _rx_cb(void *arg, uint8_t c)
|
||||
{
|
||||
rn2xx3_t *dev = (rn2xx3_t *)arg;
|
||||
netdev_t *netdev = (netdev_t *)dev;
|
||||
|
||||
/* Avoid overflow of module response buffer */
|
||||
if (dev->resp_size >= RN2XX3_MAX_BUF) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The device closes the response with \r\n when done */
|
||||
if (c == '\r') {
|
||||
return;
|
||||
}
|
||||
else if (c == '\n') { /* response end delimiter */
|
||||
dev->resp_buf[dev->resp_size++] = '\0';
|
||||
if (dev->int_state == RN2XX3_INT_STATE_MAC_RX_MESSAGE) {
|
||||
/* RX state: closing RX buffer */
|
||||
dev->rx_buf[(dev->rx_size + 1) / 2] = 0;
|
||||
if (netdev->event_callback) {
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
|
||||
}
|
||||
}
|
||||
else if (dev->int_state == RN2XX3_INT_STATE_MAC_TX) {
|
||||
/* still in TX state: transmission complete but no data received */
|
||||
if (netdev->event_callback) {
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
|
||||
}
|
||||
}
|
||||
dev->resp_size = 0;
|
||||
dev->rx_size = 0;
|
||||
dev->resp_done = 1;
|
||||
mutex_unlock(&(dev->resp_lock));
|
||||
}
|
||||
else {
|
||||
switch (dev->int_state) {
|
||||
/* A successful mac TX command expects 2 kinds of replies:
|
||||
* - mac_tx_ok: transmission done, no data received
|
||||
* - mac_rx <port> <data>: transmission done, some data
|
||||
* received on port <port>. */
|
||||
case RN2XX3_INT_STATE_MAC_TX:
|
||||
/* some data are available */
|
||||
dev->resp_buf[dev->resp_size++] = c;
|
||||
/* if module response ends with 'rx ' after 8 received chars,
|
||||
the module starts receiving data */
|
||||
if (dev->resp_size == 8 && dev->resp_buf[4] == 'r'
|
||||
&& dev->resp_buf[5] == 'x' && dev->resp_buf[6] == ' ') {
|
||||
/* next received chars correspond to the port number */
|
||||
dev->int_state = RN2XX3_INT_STATE_MAC_RX_PORT;
|
||||
}
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_MAC_RX_PORT:
|
||||
dev->resp_buf[dev->resp_size++] = c;
|
||||
if (c == ' ') {
|
||||
dev->int_state = RN2XX3_INT_STATE_MAC_RX_MESSAGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_MAC_RX_MESSAGE:
|
||||
/* read and convert RX data (received in hex chars) */
|
||||
if (c == ' ') {
|
||||
dev->resp_buf[dev->resp_size++] = c;
|
||||
break;
|
||||
}
|
||||
dev->rx_tmp_buf[dev->rx_size % 2] = c;
|
||||
|
||||
/* We convert pairs of hex character to bytes on the fly to
|
||||
save space in memory */
|
||||
if (dev->rx_size != 0 && dev->rx_size % 2) {
|
||||
rn2xx3_hex_to_bytes(dev->rx_tmp_buf,
|
||||
&dev->rx_buf[(dev->rx_size - 1) / 2]);
|
||||
}
|
||||
dev->rx_size++;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev->resp_buf[dev->resp_size++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _sleep_timer_cb(void *arg)
|
||||
{
|
||||
DEBUG("[rn2xx3] exit sleep\n");
|
||||
rn2xx3_t *dev = (rn2xx3_t *)arg;
|
||||
dev->int_state = RN2XX3_INT_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver's "public" functions
|
||||
*/
|
||||
void rn2xx3_setup(rn2xx3_t *dev, const rn2xx3_params_t *params)
|
||||
{
|
||||
assert(dev && (params->uart < UART_NUMOF));
|
||||
|
||||
/* initialize device parameters */
|
||||
memcpy(&dev->p, params, sizeof(rn2xx3_params_t));
|
||||
|
||||
/* initialize pins and perform hardware reset */
|
||||
if (dev->p.pin_reset != GPIO_UNDEF) {
|
||||
gpio_init(dev->p.pin_reset, GPIO_OUT);
|
||||
gpio_set(dev->p.pin_reset);
|
||||
}
|
||||
/* UART is initialized later, since interrupts cannot be handled yet */
|
||||
}
|
||||
|
||||
int rn2xx3_init(rn2xx3_t *dev)
|
||||
{
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_RESET);
|
||||
|
||||
/* initialize buffers and locks*/
|
||||
dev->resp_size = 0;
|
||||
dev->cmd_buf[0] = 0;
|
||||
|
||||
/* initialize UART and GPIO pins */
|
||||
if (uart_init(dev->p.uart, dev->p.baudrate, _rx_cb, dev) != UART_OK) {
|
||||
DEBUG("[rn2xx3] init: error initializing UART\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* if reset pin is connected, do a hardware reset */
|
||||
if (dev->p.pin_reset != GPIO_UNDEF) {
|
||||
gpio_clear(dev->p.pin_reset);
|
||||
xtimer_usleep(RESET_DELAY);
|
||||
gpio_set(dev->p.pin_reset);
|
||||
}
|
||||
|
||||
dev->sleep_timer.callback = _sleep_timer_cb;
|
||||
dev->sleep_timer.arg = dev;
|
||||
|
||||
rn2xx3_sys_set_sleep_duration(dev, RN2XX3_DEFAULT_SLEEP);
|
||||
|
||||
/* sending empty command to clear uart buffer */
|
||||
if (rn2xx3_write_cmd(dev) == RN2XX3_TIMEOUT) {
|
||||
DEBUG("[rn2xx3] init: initialization failed\n");
|
||||
return RN2XX3_TIMEOUT;
|
||||
}
|
||||
|
||||
if (rn2xx3_mac_init(dev) != RN2XX3_OK) {
|
||||
DEBUG("[rn2xx3] mac: initialization failed\n");
|
||||
return RN2XX3_ERR_MAC_INIT;
|
||||
}
|
||||
|
||||
DEBUG("[rn2xx3] init: initialization successful\n");
|
||||
return RN2XX3_OK;
|
||||
}
|
||||
|
||||
int rn2xx3_sys_reset(rn2xx3_t *dev)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "sys reset");
|
||||
dev->cmd_buf[p] = 0;
|
||||
int ret = rn2xx3_write_cmd(dev);
|
||||
if (ret == RN2XX3_TIMEOUT || ret == RN2XX3_ERR_SLEEP_MODE) {
|
||||
DEBUG("[rn2xx3] reset: failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return RN2XX3_OK;
|
||||
}
|
||||
|
||||
int rn2xx3_sys_factory_reset(rn2xx3_t *dev)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"sys factoryRESET");
|
||||
dev->cmd_buf[p] = 0;
|
||||
int ret = rn2xx3_write_cmd(dev);
|
||||
if (ret == RN2XX3_TIMEOUT || ret == RN2XX3_ERR_SLEEP_MODE) {
|
||||
DEBUG("[rn2xx3] factory reset: failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return RN2XX3_OK;
|
||||
}
|
||||
|
||||
int rn2xx3_sys_sleep(rn2xx3_t *dev)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"sys sleep %lu", (unsigned long)dev->sleep);
|
||||
dev->cmd_buf[p] = 0;
|
||||
if (rn2xx3_write_cmd_no_wait(dev) == RN2XX3_ERR_INVALID_PARAM) {
|
||||
DEBUG("[rn2xx3] sleep: cannot put module in sleep mode\n");
|
||||
return RN2XX3_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_SLEEP);
|
||||
xtimer_set(&dev->sleep_timer, dev->sleep * US_PER_MS);
|
||||
|
||||
return RN2XX3_OK;
|
||||
}
|
||||
|
||||
int rn2xx3_mac_init(rn2xx3_t *dev)
|
||||
{
|
||||
rn2xx3_mac_set_dr(dev, LORAMAC_DEFAULT_DR);
|
||||
rn2xx3_mac_set_tx_power(dev, LORAMAC_DEFAULT_TX_POWER);
|
||||
rn2xx3_mac_set_tx_port(dev, LORAMAC_DEFAULT_TX_PORT);
|
||||
rn2xx3_mac_set_tx_mode(dev, LORAMAC_DEFAULT_TX_MODE);
|
||||
rn2xx3_mac_set_adr(dev, LORAMAC_DEFAULT_ADR);
|
||||
rn2xx3_mac_set_retx(dev, LORAMAC_DEFAULT_RETX);
|
||||
rn2xx3_mac_set_linkchk_interval(dev, LORAMAC_DEFAULT_LINKCHK);
|
||||
rn2xx3_mac_set_rx1_delay(dev, LORAMAC_DEFAULT_RX1_DELAY);
|
||||
rn2xx3_mac_set_ar(dev, LORAMAC_DEFAULT_AR);
|
||||
rn2xx3_mac_set_rx2_dr(dev, LORAMAC_DEFAULT_RX2_DR);
|
||||
rn2xx3_mac_set_rx2_freq(dev, LORAMAC_DEFAULT_RX2_FREQ);
|
||||
|
||||
return RN2XX3_OK;
|
||||
}
|
||||
|
||||
int rn2xx3_mac_tx(rn2xx3_t *dev, uint8_t *payload, uint8_t payload_len)
|
||||
{
|
||||
if (dev->int_state == RN2XX3_INT_STATE_SLEEP) {
|
||||
DEBUG("[rn2xx3] ABORT: device is in sleep mode\n");
|
||||
return RN2XX3_ERR_SLEEP_MODE;
|
||||
}
|
||||
|
||||
rn2xx3_mac_tx_start(dev);
|
||||
for (unsigned i = 0; i < payload_len; ++i) {
|
||||
rn2xx3_cmd_append(dev, &payload[i], 1);
|
||||
}
|
||||
|
||||
int ret = rn2xx3_mac_tx_finalize(dev);
|
||||
if (ret != RN2XX3_OK) {
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);
|
||||
DEBUG("[rn2xx3] TX command failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rn2xx3_wait_reply(dev, RN2XX3_REPLY_DELAY_TIMEOUT);
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rn2xx3_mac_join_network(rn2xx3_t *dev, loramac_join_mode_t mode)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"mac join %s",
|
||||
(mode == LORAMAC_JOIN_OTAA) ? "otaa" : "abp");
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
int ret = rn2xx3_write_cmd(dev);
|
||||
if (ret != RN2XX3_OK) {
|
||||
DEBUG("[rn2xx3] join procedure command failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_MAC_JOIN);
|
||||
|
||||
ret = rn2xx3_wait_reply(dev,
|
||||
LORAMAC_DEFAULT_JOIN_DELAY1 + \
|
||||
LORAMAC_DEFAULT_JOIN_DELAY2);
|
||||
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rn2xx3_mac_save(rn2xx3_t *dev)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "mac save");
|
||||
dev->cmd_buf[p] = 0;
|
||||
return rn2xx3_write_cmd(dev);
|
||||
}
|
338
drivers/rn2xx3/rn2xx3_getset.c
Normal file
338
drivers/rn2xx3/rn2xx3_getset.c
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_rn2xx3
|
||||
* @{
|
||||
* @file
|
||||
* @brief Implementation of get and set functions for RN2XX3
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "fmt.h"
|
||||
|
||||
#include "net/loramac.h"
|
||||
|
||||
#include "rn2xx3.h"
|
||||
#include "rn2xx3_internal.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static const char *mac = "mac";
|
||||
static const char *get = "get";
|
||||
static const char *set = "set";
|
||||
|
||||
/* internal helpers */
|
||||
static uint8_t _get_uint8_value(rn2xx3_t *dev, const char *command)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s", mac, get, command);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
|
||||
return atoi(dev->resp_buf);
|
||||
}
|
||||
|
||||
static void _set_uint8_value(rn2xx3_t *dev,
|
||||
const char *command, uint8_t value)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "%s %s %s %d",
|
||||
mac, set, command, value);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
}
|
||||
|
||||
static uint16_t _get_uint16_value(rn2xx3_t *dev, const char *command)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s", mac, get, command);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
|
||||
return atoi(dev->resp_buf);
|
||||
}
|
||||
|
||||
static void _set_uint16_value(rn2xx3_t *dev,
|
||||
const char *command, uint16_t value)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "%s %s %s %i",
|
||||
mac, set, command, value);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
}
|
||||
|
||||
static bool _get_bool_value(rn2xx3_t *dev, const char *command)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s", mac, get, command);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
|
||||
return strcmp(dev->resp_buf, "on") == 0;
|
||||
}
|
||||
|
||||
static void _set_bool_value(rn2xx3_t *dev,
|
||||
const char *command, bool value)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "%s %s %s %s",
|
||||
mac, set, command, value ? "on": "off");
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
}
|
||||
|
||||
static void _get_array_value(rn2xx3_t *dev, const char *command,
|
||||
uint8_t *value)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s", mac, get, command);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
|
||||
fmt_hex_bytes(value, dev->resp_buf);
|
||||
|
||||
}
|
||||
|
||||
static void _set_array_value(rn2xx3_t *dev, const char *command,
|
||||
const uint8_t *value, uint8_t value_len)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "%s %s %s ",
|
||||
mac, set, command);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_cmd_start(dev);
|
||||
rn2xx3_cmd_append(dev, value, value_len);
|
||||
rn2xx3_cmd_finalize(dev);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_get_deveui(rn2xx3_t *dev, uint8_t *eui)
|
||||
{
|
||||
_get_array_value(dev, "deveui", eui);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_deveui(rn2xx3_t *dev, const uint8_t *eui)
|
||||
{
|
||||
_set_array_value(dev, "deveui", eui, LORAMAC_DEVEUI_LEN);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_get_appeui(rn2xx3_t *dev, uint8_t *eui)
|
||||
{
|
||||
_get_array_value(dev, "appeui", eui);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_appeui(rn2xx3_t *dev, const uint8_t *eui)
|
||||
{
|
||||
_set_array_value(dev, "appeui", eui, LORAMAC_APPEUI_LEN);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_appkey(rn2xx3_t *dev, const uint8_t *key)
|
||||
{
|
||||
_set_array_value(dev, "appkey", key, LORAMAC_APPKEY_LEN);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_appskey(rn2xx3_t *dev, const uint8_t *key)
|
||||
{
|
||||
_set_array_value(dev, "appskey", key, LORAMAC_APPSKEY_LEN);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_nwkskey(rn2xx3_t *dev, const uint8_t *key)
|
||||
{
|
||||
_set_array_value(dev, "nwkskey", key, LORAMAC_NWKSKEY_LEN);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_get_devaddr(rn2xx3_t *dev, uint8_t *addr)
|
||||
{
|
||||
_get_array_value(dev, "devaddr", addr);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_devaddr(rn2xx3_t *dev, const uint8_t *addr)
|
||||
{
|
||||
_set_array_value(dev, "devaddr", addr, 4);
|
||||
}
|
||||
|
||||
loramac_tx_pwr_idx_t rn2xx3_mac_get_tx_power(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_uint8_value(dev, "pwridx");
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_tx_power(rn2xx3_t *dev, loramac_tx_pwr_idx_t power)
|
||||
{
|
||||
_set_uint8_value(dev, "pwridx", power);
|
||||
}
|
||||
|
||||
loramac_dr_idx_t rn2xx3_mac_get_dr(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_uint8_value(dev, "dr");
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_dr(rn2xx3_t *dev, loramac_dr_idx_t datarate)
|
||||
{
|
||||
_set_uint8_value(dev, "dr", datarate);
|
||||
}
|
||||
|
||||
uint16_t rn2xx3_mac_get_band(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_uint16_value(dev, "band");
|
||||
}
|
||||
|
||||
bool rn2xx3_mac_get_adr(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_bool_value(dev, "adr");
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_adr(rn2xx3_t *dev, bool adr)
|
||||
{
|
||||
_set_bool_value(dev, "adr", adr);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_battery(rn2xx3_t *dev, uint8_t battery)
|
||||
{
|
||||
_set_uint8_value(dev, "bat", battery);
|
||||
}
|
||||
|
||||
uint8_t rn2xx3_mac_get_retx(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_uint8_value(dev, "retx");
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_retx(rn2xx3_t *dev, uint8_t retx)
|
||||
{
|
||||
_set_uint8_value(dev, "retx", retx);
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_linkchk_interval(rn2xx3_t *dev, uint16_t linkchk)
|
||||
{
|
||||
_set_uint16_value(dev, "linkchk", linkchk);
|
||||
}
|
||||
|
||||
uint16_t rn2xx3_mac_get_rx1_delay(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_uint16_value(dev, "rxdelay1");
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_rx1_delay(rn2xx3_t *dev, uint16_t rx1)
|
||||
{
|
||||
_set_uint16_value(dev, "rxdelay1", rx1);
|
||||
}
|
||||
|
||||
uint16_t rn2xx3_mac_get_rx2_delay(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_uint16_value(dev, "rxdelay2");
|
||||
}
|
||||
|
||||
bool rn2xx3_mac_get_ar(rn2xx3_t *dev)
|
||||
{
|
||||
return _get_bool_value(dev, "ar");
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_ar(rn2xx3_t *dev, bool ar)
|
||||
{
|
||||
_set_bool_value(dev, "ar", ar);
|
||||
}
|
||||
|
||||
loramac_dr_idx_t rn2xx3_mac_get_rx2_dr(rn2xx3_t *dev)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "%s %s %s %d",
|
||||
mac, get, "rx2", RN2XX3_FREQ_BAND);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
|
||||
loramac_dr_idx_t dr = strtol(dev->resp_buf, NULL, 10);
|
||||
|
||||
return dr;
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_rx2_dr(rn2xx3_t *dev, loramac_dr_idx_t dr)
|
||||
{
|
||||
dev->loramac.rx2_dr = dr;
|
||||
dev->loramac.rx2_freq = rn2xx3_mac_get_rx2_freq(dev);
|
||||
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s %d %lu",
|
||||
mac, set, "rx2", dr,
|
||||
(unsigned long)dev->loramac.rx2_freq);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
}
|
||||
|
||||
uint32_t rn2xx3_mac_get_rx2_freq(rn2xx3_t *dev)
|
||||
{
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s %d", mac, get, "rx2", RN2XX3_FREQ_BAND);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
|
||||
uint32_t freq = strtoul(dev->resp_buf + 2, NULL, 10);
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_rx2_freq(rn2xx3_t *dev, uint32_t freq)
|
||||
{
|
||||
dev->loramac.rx2_freq = freq;
|
||||
dev->loramac.rx2_dr = rn2xx3_mac_get_rx2_dr(dev);
|
||||
|
||||
size_t p = snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1,
|
||||
"%s %s %s %d %lu",
|
||||
mac, set, "rx2", dev->loramac.rx2_dr,
|
||||
(unsigned long)freq);
|
||||
dev->cmd_buf[p] = 0;
|
||||
|
||||
rn2xx3_write_cmd(dev);
|
||||
}
|
||||
|
||||
uint8_t rn2xx3_mac_get_tx_port(rn2xx3_t *dev)
|
||||
{
|
||||
return dev->loramac.tx_port;
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_tx_port(rn2xx3_t *dev, uint8_t port)
|
||||
{
|
||||
dev->loramac.tx_port = port;
|
||||
}
|
||||
|
||||
loramac_tx_mode_t rn2xx3_mac_get_tx_mode(rn2xx3_t *dev)
|
||||
{
|
||||
return dev->loramac.tx_mode;
|
||||
}
|
||||
|
||||
void rn2xx3_mac_set_tx_mode(rn2xx3_t *dev, loramac_tx_mode_t mode)
|
||||
{
|
||||
dev->loramac.tx_mode = mode;
|
||||
}
|
||||
|
||||
uint8_t rn2xx3_mac_get_rx_port(rn2xx3_t *dev)
|
||||
{
|
||||
return strtoul(&dev->resp_buf[6], NULL, 10);
|
||||
}
|
||||
|
||||
void rn2xx3_sys_set_sleep_duration(rn2xx3_t *dev, uint32_t sleep)
|
||||
{
|
||||
if (sleep < RN2XX3_SLEEP_MIN) {
|
||||
DEBUG("[rn2xx3] sleep: duration should be greater than 100 (ms)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->sleep = sleep;
|
||||
}
|
343
drivers/rn2xx3/rn2xx3_internal.c
Normal file
343
drivers/rn2xx3/rn2xx3_internal.c
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_rn2xx3
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Internal driver implementation for the RN2483/RN2903 devices
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fmt.h"
|
||||
#include "rn2xx3_internal.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define RESP_TIMEOUT_SEC (5U)
|
||||
|
||||
static const char *closing_seq = "\r\n";
|
||||
|
||||
static void _uart_write_str(rn2xx3_t *dev, const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
if (len) {
|
||||
uart_write(dev->p.uart, (uint8_t *)str, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void isr_resp_timeout(void *arg)
|
||||
{
|
||||
rn2xx3_t *dev = (rn2xx3_t *)arg;
|
||||
mutex_unlock(&(dev->resp_lock));
|
||||
}
|
||||
|
||||
static bool _wait_reply(rn2xx3_t *dev, uint8_t timeout)
|
||||
{
|
||||
dev->resp_done = 0;
|
||||
dev->resp_size = 0;
|
||||
dev->resp_buf[0] = 0;
|
||||
|
||||
xtimer_ticks64_t sent_time = xtimer_now64();
|
||||
|
||||
xtimer_t resp_timer;
|
||||
resp_timer.callback = isr_resp_timeout;
|
||||
resp_timer.arg = dev;
|
||||
|
||||
xtimer_set(&resp_timer, (uint32_t)timeout * US_PER_SEC);
|
||||
|
||||
/* wait for results */
|
||||
while ((!dev->resp_done) &&
|
||||
xtimer_less(xtimer_diff32_64(xtimer_now64(), sent_time),
|
||||
xtimer_ticks_from_usec(timeout * US_PER_SEC))) {
|
||||
mutex_lock(&(dev->resp_lock));
|
||||
}
|
||||
|
||||
xtimer_remove(&resp_timer);
|
||||
|
||||
if (dev->resp_done == 0) {
|
||||
DEBUG("[rn2xx3] response timeout\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void rn2xx3_hex_to_bytes(const char *hex, uint8_t *byte_array)
|
||||
{
|
||||
const uint8_t charmap[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */
|
||||
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 89:;<=>? */
|
||||
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, /* @ABCDEFG */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* HIJKLMNO */
|
||||
};
|
||||
|
||||
size_t len = strlen(hex);
|
||||
for (uint8_t pos = 0; pos < len; pos += 2) {
|
||||
uint8_t idx0 = ((uint8_t)hex[pos + 0] & 0x1F) ^ 0x10;
|
||||
uint8_t idx1 = ((uint8_t)hex[pos + 1] & 0x1F) ^ 0x10;
|
||||
byte_array[pos / 2] = (uint8_t)(charmap[idx0] << 4) | charmap[idx1];
|
||||
};
|
||||
}
|
||||
|
||||
void rn2xx3_set_internal_state(rn2xx3_t *dev, uint8_t state)
|
||||
{
|
||||
if ((dev->int_state == RN2XX3_INT_STATE_SLEEP) ||
|
||||
(dev->int_state == state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ENABLE_DEBUG) {
|
||||
printf("[rn2xx3] new state: ");
|
||||
switch(state) {
|
||||
case RN2XX3_INT_STATE_CMD:
|
||||
puts("CMD");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_IDLE:
|
||||
puts("IDLE");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_MAC_JOIN:
|
||||
puts("JOIN");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_MAC_RX_MESSAGE:
|
||||
puts("RX MSG");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_MAC_RX_PORT:
|
||||
puts("RX PORT");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_MAC_TX:
|
||||
puts("TX");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_RESET:
|
||||
puts("RESET");
|
||||
break;
|
||||
|
||||
case RN2XX3_INT_STATE_SLEEP:
|
||||
puts("SLEEP");
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("UNKNOWN");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dev->int_state = state;
|
||||
}
|
||||
|
||||
int rn2xx3_write_cmd(rn2xx3_t *dev)
|
||||
{
|
||||
int ret;
|
||||
DEBUG("[rn2xx3] CMD: %s\n", dev->cmd_buf);
|
||||
|
||||
if (dev->int_state == RN2XX3_INT_STATE_SLEEP) {
|
||||
DEBUG("[rn2xx3] ABORT: device is in sleep mode\n");
|
||||
return RN2XX3_ERR_SLEEP_MODE;
|
||||
}
|
||||
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_CMD);
|
||||
|
||||
mutex_lock(&(dev->cmd_lock));
|
||||
_uart_write_str(dev, dev->cmd_buf);
|
||||
_uart_write_str(dev, closing_seq);
|
||||
|
||||
ret = rn2xx3_wait_response(dev);
|
||||
if (ret == RN2XX3_TIMEOUT) {
|
||||
mutex_unlock(&(dev->cmd_lock));
|
||||
return RN2XX3_TIMEOUT;
|
||||
}
|
||||
|
||||
mutex_unlock(&(dev->cmd_lock));
|
||||
|
||||
ret = rn2xx3_process_response(dev);
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);
|
||||
|
||||
DEBUG("[rn2xx3] RET: %d, RESP: %s\n", ret, dev->resp_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rn2xx3_write_cmd_no_wait(rn2xx3_t *dev)
|
||||
{
|
||||
DEBUG("[rn2xx3] CMD: %s\n", dev->cmd_buf);
|
||||
|
||||
if (dev->int_state == RN2XX3_INT_STATE_SLEEP) {
|
||||
DEBUG("[rn2xx3] ABORT: device is in sleep mode\n");
|
||||
return RN2XX3_ERR_SLEEP_MODE;
|
||||
}
|
||||
|
||||
mutex_lock(&(dev->cmd_lock));
|
||||
_uart_write_str(dev, dev->cmd_buf);
|
||||
_uart_write_str(dev, closing_seq);
|
||||
|
||||
DEBUG("[rn2xx3] RET: %s\n", dev->resp_buf);
|
||||
|
||||
mutex_unlock(&(dev->cmd_lock));
|
||||
|
||||
return rn2xx3_process_response(dev);
|
||||
}
|
||||
|
||||
int rn2xx3_wait_response(rn2xx3_t *dev)
|
||||
{
|
||||
if (_wait_reply(dev, RESP_TIMEOUT_SEC)) {
|
||||
return RN2XX3_TIMEOUT;
|
||||
}
|
||||
|
||||
DEBUG("[rn2xx3] RESP: %s\n", dev->resp_buf);
|
||||
|
||||
return RN2XX3_OK;
|
||||
}
|
||||
|
||||
int rn2xx3_wait_reply(rn2xx3_t *dev, uint8_t timeout)
|
||||
{
|
||||
if (_wait_reply(dev, timeout)) {
|
||||
return RN2XX3_REPLY_TIMEOUT;
|
||||
}
|
||||
|
||||
DEBUG("[rn2xx3] REPLY: %s\n", dev->resp_buf);
|
||||
|
||||
return rn2xx3_process_reply(dev);
|
||||
}
|
||||
|
||||
void rn2xx3_cmd_start(rn2xx3_t *dev)
|
||||
{
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_CMD);
|
||||
DEBUG("[rn2xx3] CMD: %s", dev->cmd_buf);
|
||||
mutex_lock(&(dev->cmd_lock));
|
||||
_uart_write_str(dev, dev->cmd_buf);
|
||||
}
|
||||
|
||||
void rn2xx3_cmd_append(rn2xx3_t *dev, const uint8_t *payload, uint8_t payload_len)
|
||||
{
|
||||
char payload_str[2];
|
||||
for (unsigned i = 0; i < payload_len; i++) {
|
||||
fmt_byte_hex(payload_str, payload[i]);
|
||||
_uart_write_str(dev, payload_str);
|
||||
}
|
||||
}
|
||||
|
||||
int rn2xx3_cmd_finalize(rn2xx3_t *dev)
|
||||
{
|
||||
DEBUG("\n");
|
||||
_uart_write_str(dev, closing_seq);
|
||||
uint8_t ret = rn2xx3_wait_response(dev);
|
||||
|
||||
mutex_unlock(&(dev->cmd_lock));
|
||||
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_IDLE);
|
||||
|
||||
DEBUG("[rn2xx3] RET: %d, RESP: %s\n", ret, dev->resp_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rn2xx3_mac_tx_start(rn2xx3_t *dev)
|
||||
{
|
||||
snprintf(dev->cmd_buf, sizeof(dev->cmd_buf) - 1, "mac tx %s %d ",
|
||||
(dev->loramac.tx_mode == LORAMAC_TX_CNF) ? "cnf" : "uncnf",
|
||||
dev->loramac.tx_port);
|
||||
|
||||
rn2xx3_cmd_start(dev);
|
||||
}
|
||||
|
||||
int rn2xx3_mac_tx_finalize(rn2xx3_t *dev)
|
||||
{
|
||||
rn2xx3_cmd_finalize(dev);
|
||||
|
||||
rn2xx3_set_internal_state(dev, RN2XX3_INT_STATE_MAC_TX);
|
||||
|
||||
return rn2xx3_process_response(dev);
|
||||
}
|
||||
|
||||
int rn2xx3_process_response(rn2xx3_t *dev)
|
||||
{
|
||||
uint8_t ret = RN2XX3_DATA;
|
||||
if (strcmp(dev->resp_buf, "ok") == 0) {
|
||||
DEBUG("[rn2xx3] command succeeded: '%s'\n", dev->cmd_buf);
|
||||
ret = RN2XX3_OK;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "invalid_param") == 0) {
|
||||
DEBUG("[rn2xx3] invalid command: '%s'\n", dev->cmd_buf);
|
||||
ret = RN2XX3_ERR_INVALID_PARAM;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "not_joined") == 0) {
|
||||
DEBUG("[rn2xx3] failed: network is not joined\n");
|
||||
ret = RN2XX3_ERR_NOT_JOINED;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "no_free_ch") == 0) {
|
||||
DEBUG("[rn2xx3] failed: all channels are busy\n");
|
||||
ret = RN2XX3_ERR_NO_FREE_CH;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "silent") == 0) {
|
||||
DEBUG("[rn2xx3] failed: all channels are busy\n");
|
||||
ret = RN2XX3_ERR_SILENT;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "frame_counter_err_rejoin_needed") == 0) {
|
||||
DEBUG("[rn2xx3] failed: Frame counter rolled over\n");
|
||||
ret = RN2XX3_ERR_FR_CNT_REJOIN_NEEDED;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "busy") == 0) {
|
||||
DEBUG("[rn2xx3] failed: MAC state is in an Idle state\n");
|
||||
ret = RN2XX3_ERR_BUSY;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "invalid_data_len") == 0) {
|
||||
DEBUG("[rn2xx3] failed: payload length too large\n");
|
||||
ret = RN2XX3_ERR_INVALID_DATA_LENGTH;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rn2xx3_process_reply(rn2xx3_t *dev)
|
||||
{
|
||||
uint8_t ret;
|
||||
if (strcmp(dev->resp_buf, "accepted") == 0) {
|
||||
DEBUG("[rn2xx3] join procedure succeeded.\n");
|
||||
ret = RN2XX3_REPLY_JOIN_ACCEPTED;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "denied") == 0) {
|
||||
DEBUG("[rn2xx3] join procedure failed.\n");
|
||||
ret = RN2XX3_REPLY_JOIN_DENIED;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "mac_tx_ok") == 0) {
|
||||
DEBUG("[rn2xx3] uplink transmission succeeded.\n");
|
||||
ret = RN2XX3_REPLY_TX_MAC_OK;
|
||||
}
|
||||
else if (strncmp(dev->resp_buf, "mac_rx", 6) == 0) {
|
||||
DEBUG("[rn2xx3] received downlink data from server.\n");
|
||||
ret = RN2XX3_REPLY_TX_MAC_RX;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "mac_err") == 0) {
|
||||
DEBUG("[rn2xx3] uplink transmission failed.\n");
|
||||
ret = RN2XX3_REPLY_TX_MAC_ERR;
|
||||
}
|
||||
else if (strcmp(dev->resp_buf, "invalid_data_len") == 0) {
|
||||
DEBUG("[rn2xx3] payload length too large.\n");
|
||||
ret = RN2XX3_REPLY_TX_MAC_ERR;
|
||||
}
|
||||
else {
|
||||
DEBUG("[rn2xx3] unknown reply.\n");
|
||||
ret = RN2XX3_REPLY_OTHER;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -98,6 +98,10 @@ PSEUDOMODULES += si7013
|
||||
PSEUDOMODULES += si7020
|
||||
PSEUDOMODULES += si7021
|
||||
|
||||
# include variants of RN2XX3 drivers as pseudo modules
|
||||
PSEUDOMODULES += rn2483
|
||||
PSEUDOMODULES += rn2903
|
||||
|
||||
# add all pseudo random number generator variants as pseudomodules
|
||||
PSEUDOMODULES += prng_%
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user