/* * Project: Si4463 Radio Library for AVR and Arduino * Author: Zak Kemble, contact@zakkemble.co.uk * Copyright: (C) 2017 by Zak Kemble * License: GNU GPL v3 (see License.txt) * Web: http://blog.zakkemble.co.uk/si4463-radio-library-avr-arduino/ */ #ifndef SI443X_H_ #define SI443X_H_ #include //#include "Si446x_config.h" // Address matching doesnt really work very well as the FIFO still needs to be // manually cleared after receiving a packet, so the MCU still needs to wakeup and // do stuff instead of the radio doing things automatically :/ #define SI446X_MAX_PACKET_LEN 128 ///< Maximum packet length #define SI446X_MAX_TX_POWER 127 ///< Maximum TX power (+20dBm/100mW) #define SI446X_WUT_RUN 1 ///< Wake the microcontroller when the WUT expires #define SI446X_WUT_BATT 2 ///< Take a battery measurement when the WUT expires #define SI446X_WUT_RX 4 ///< Go into RX mode for LDC time (not supported yet!) #define SI446X_GPIO_PULL_EN 0x40 ///< Pullup enable for GPIO pins #define SI446X_GPIO_PULL_DIS 0x00 ///< Pullup disable for GPIO pins #define SI446X_NIRQ_PULL_EN 0x40 ///< Pullup enable for NIRQ pin #define SI446X_NIRQ_PULL_DIS 0x00 ///< Pullup disable for NIRQ pin #define SI446X_SDO_PULL_EN 0x40 ///< Pullup enable for SDO pin #define SI446X_SDO_PULL_DIS 0x00 ///< Pullup disable for SDO pin #define SI446X_PIN_PULL_EN 0x40 ///< Pullup enable for any pin #define SI446X_PIN_PULL_DIS 0x00 ///< Pullup disable for any pin #define SI446X_GPIO_DRV_HIGH 0x00 ///< GPIO drive strength high #define SI446X_GPIO_DRV_MED_HIGH 0x20 ///< GPIO drive strength medium-high #define SI446X_GPIO_DRV_MED_LOW 0x40 ///< GPIO drive strength medium-low #define SI446X_GPIO_DRV_LOW 0x60 ///< GPIO drive strength low #define SI446X_PROP_GROUP_GLOBAL 0x00 ///< Property group global #define SI446X_PROP_GROUP_INT 0x01 ///< Property group interrupts #define SI446X_PROP_GROUP_FRR 0x02 ///< Property group fast response registers #define SI446X_PROP_GROUP_PREAMBLE 0x10 ///< Property group preamble #define SI446X_PROP_GROUP_SYNC 0x11 ///< Property group sync #define SI446X_PROP_GROUP_PKT 0x12 ///< Property group packet config #define SI446X_PROP_GROUP_MODEM 0x20 ///< Property group modem #define SI446X_PROP_GROUP_MODEM_CHFLT 0x21 ///< Property group RX coefficients #define SI446X_PROP_GROUP_PA 0x22 ///< Property group power amp #define SI446X_PROP_GROUP_SYNTH 0x23 ///< Property group synthesizer #define SI446X_PROP_GROUP_MATCH 0x30 ///< Property group address match #define SI446X_PROP_GROUP_FREQ_CONTROL 0x40 ///< Property group frequency control #define SI446X_PROP_GROUP_RX_HOP 0x50 ///< Property group RX hop #define SI446X_PROP_GROUP_PTI 0xF0 ///< Property group packet trace interface /** * @brief GPIO pin modes (see the Si446x API docs for what they all mean) */ typedef enum { SI446X_GPIO_MODE_DONOTHING = 0x00, SI446X_GPIO_MODE_TRISTATE = 0x01, SI446X_GPIO_MODE_DRIVE0 = 0x02, SI446X_GPIO_MODE_DRIVE1 = 0x03, SI446X_GPIO_MODE_INPUT = 0x04, SI446X_GPIO_MODE_32K_CLK = 0x05, SI446X_GPIO_MODE_BOOT_CLK = 0x06, SI446X_GPIO_MODE_DIV_CLK = 0x07, SI446X_GPIO_MODE_CTS = 0x08, SI446X_GPIO_MODE_INV_CTS = 0x09, SI446X_GPIO_MODE_CMD_OVERLAP = 0x0A, SI446X_GPIO_MODE_SDO = 0x0B, SI446X_GPIO_MODE_POR = 0x0C, SI446X_GPIO_MODE_CAL_WUT = 0x0D, SI446X_GPIO_MODE_WUT = 0x0E, SI446X_GPIO_MODE_EN_PA = 0x0F, SI446X_GPIO_MODE_TX_DATA_CLK = 0x10, SI446X_GPIO_MODE_RX_DATA_CLK = 0x11, SI446X_GPIO_MODE_EN_LNA = 0x12, SI446X_GPIO_MODE_TX_DATA = 0x13, SI446X_GPIO_MODE_RX_DATA = 0x14, SI446X_GPIO_MODE_RX_RAW_DATA = 0x15, SI446X_GPIO_MODE_ANTENNA_1_SW = 0x16, SI446X_GPIO_MODE_ANTENNA_2_SW = 0x17, SI446X_GPIO_MODE_VALID_PREAMBLE = 0x18, SI446X_GPIO_MODE_INVALID_PREAMBLE = 0x19, SI446X_GPIO_MODE_SYNC_WORD_DETECT = 0x1A, SI446X_GPIO_MODE_CCA = 0x1B, SI446X_GPIO_MODE_IN_SLEEP = 0x1C, SI446X_GPIO_MODE_PKT_TRACE = 0x1D, // Nothing for 0x1E (30) SI446X_GPIO_MODE_TX_RX_DATA_CLK = 0x1F, SI446X_GPIO_MODE_TX_STATE = 0x20, SI446X_GPIO_MODE_RX_STATE = 0x21, SI446X_GPIO_MODE_RX_FIFO_FULL = 0x22, SI446X_GPIO_MODE_TX_FIFO_EMPTY = 0x23, SI446X_GPIO_MODE_LOW_BATT = 0x24, SI446X_GPIO_MODE_CCA_LATCH = 0x25, SI446X_GPIO_MODE_HOPPED = 0x26, SI446X_GPIO_MODE_HOP_TABLE_WRAP = 0x27 } si446x_gpio_mode_t; /** * @brief NIRQ pin modes (see the Si446x API docs for what they all mean) */ typedef enum { SI446X_NIRQ_MODE_DONOTHING = 0x00, SI446X_NIRQ_MODE_TRISTATE = 0x01, SI446X_NIRQ_MODE_DRIVE0 = 0x02, SI446X_NIRQ_MODE_DRIVE1 = 0x03, SI446X_NIRQ_MODE_INPUT = 0x04, // SI446X_NIRQ_MODE_32K_CLK = 0x05, // SI446X_NIRQ_MODE_BOOT_CLK = 0x06, SI446X_NIRQ_MODE_DIV_CLK = 0x07, SI446X_NIRQ_MODE_CTS = 0x08, // SI446X_NIRQ_MODE_INV_CTS = 0x09, // SI446X_NIRQ_MODE_CMD_OVERLAP = 0x0A, SI446X_NIRQ_MODE_SDO = 0x0B, SI446X_NIRQ_MODE_POR = 0x0C, // SI446X_NIRQ_MODE_CAL_WUT = 0x0D, // SI446X_NIRQ_MODE_WUT = 0x0E, SI446X_NIRQ_MODE_EN_PA = 0x0F, SI446X_NIRQ_MODE_TX_DATA_CLK = 0x10, SI446X_NIRQ_MODE_RX_DATA_CLK = 0x11, SI446X_NIRQ_MODE_EN_LNA = 0x12, SI446X_NIRQ_MODE_TX_DATA = 0x13, SI446X_NIRQ_MODE_RX_DATA = 0x14, SI446X_NIRQ_MODE_RX_RAW_DATA = 0x15, SI446X_NIRQ_MODE_ANTENNA_1_SW = 0x16, SI446X_NIRQ_MODE_ANTENNA_2_SW = 0x17, SI446X_NIRQ_MODE_VALID_PREAMBLE = 0x18, SI446X_NIRQ_MODE_INVALID_PREAMBLE = 0x19, SI446X_NIRQ_MODE_SYNC_WORD_DETECT = 0x1A, SI446X_NIRQ_MODE_CCA = 0x1B, // SI446X_NIRQ_MODE_IN_SLEEP = 0x1C, SI446X_NIRQ_MODE_PKT_TRACE = 0x1D, // Nothing for 0x1E (30) SI446X_NIRQ_MODE_TX_RX_DATA_CLK = 0x1F, // SI446X_NIRQ_MODE_TX_STATE = 0x20, // SI446X_NIRQ_MODE_RX_STATE = 0x21, // SI446X_NIRQ_MODE_RX_FIFO_FULL = 0x22, // SI446X_NIRQ_MODE_TX_FIFO_EMPTY = 0x23, // SI446X_NIRQ_MODE_LOW_BATT = 0x24, // SI446X_NIRQ_MODE_CCA_LATCH = 0x25, // SI446X_NIRQ_MODE_HOPPED = 0x26, SI446X_NIRQ_MODE_NIRQ = 0x27 } si446x_nirq_mode_t; /** * @brief SDO pin modes (see the Si446x API docs for what they all mean) */ typedef enum { SI446X_SDO_MODE_DONOTHING = 0x00, SI446X_SDO_MODE_TRISTATE = 0x01, SI446X_SDO_MODE_DRIVE0 = 0x02, SI446X_SDO_MODE_DRIVE1 = 0x03, SI446X_SDO_MODE_INPUT = 0x04, SI446X_SDO_MODE_32K_CLK = 0x05, // SI446X_SDO_MODE_BOOT_CLK = 0x06, SI446X_SDO_MODE_DIV_CLK = 0x07, SI446X_SDO_MODE_CTS = 0x08, // SI446X_SDO_MODE_INV_CTS = 0x09, // SI446X_SDO_MODE_CMD_OVERLAP = 0x0A, SI446X_SDO_MODE_SDO = 0x0B, SI446X_SDO_MODE_POR = 0x0C, // SI446X_SDO_MODE_CAL_WUT = 0x0D, SI446X_SDO_MODE_WUT = 0x0E, SI446X_SDO_MODE_EN_PA = 0x0F, SI446X_SDO_MODE_TX_DATA_CLK = 0x10, SI446X_SDO_MODE_RX_DATA_CLK = 0x11, SI446X_SDO_MODE_EN_LNA = 0x12, SI446X_SDO_MODE_TX_DATA = 0x13, SI446X_SDO_MODE_RX_DATA = 0x14, SI446X_SDO_MODE_RX_RAW_DATA = 0x15, SI446X_SDO_MODE_ANTENNA_1_SW = 0x16, SI446X_SDO_MODE_ANTENNA_2_SW = 0x17, SI446X_SDO_MODE_VALID_PREAMBLE = 0x18, SI446X_SDO_MODE_INVALID_PREAMBLE = 0x19, SI446X_SDO_MODE_SYNC_WORD_DETECT = 0x1A, SI446X_SDO_MODE_CCA = 0x1B, // SI446X_SDO_MODE_IN_SLEEP = 0x1C, // SI446X_SDO_MODE_PKT_TRACE = 0x1D, // Nothing for 0x1E (30) // SI446X_SDO_MODE_TX_RX_DATA_CLK = 0x1F, // SI446X_SDO_MODE_TX_STATE = 0x20, // SI446X_SDO_MODE_RX_STATE = 0x21, // SI446X_SDO_MODE_RX_FIFO_FULL = 0x22, // SI446X_SDO_MODE_TX_FIFO_EMPTY = 0x23, // SI446X_SDO_MODE_LOW_BATT = 0x24, // SI446X_SDO_MODE_CCA_LATCH = 0x25, // SI446X_SDO_MODE_HOPPED = 0x26, // SI446X_SDO_MODE_HOP_TABLE_WRAP = 0x27 } si446x_sdo_mode_t; /** * @brief Data structure for storing chip info from ::Si446x_getInfo() */ typedef struct { uint8_t chipRev; ///< Chip revision uint16_t part; ///< Part ID uint8_t partBuild; ///< Part build uint16_t id; ///< ID uint8_t customer; ///< Customer uint8_t romId; ///< ROM ID (3 = revB1B, 6 = revC2A) uint8_t revExternal; ///< Revision external uint8_t revBranch; ///< Revision branch uint8_t revInternal; ///< Revision internal uint16_t patch; ///< Patch uint8_t func; ///< Function } si446x_info_t; /** * @brief GPIOs for passing to ::Si446x_writeGPIO(), or for masking when reading from ::Si446x_readGPIO() */ typedef enum { SI446X_GPIO0 = 0, ///< GPIO 1 SI446X_GPIO1 = 1, ///< GPIO 2 SI446X_GPIO2 = 2, ///< GPIO 3 SI446X_GPIO3 = 3, ///< GPIO 4 SI446X_NIRQ = 4, ///< NIRQ SI446X_SDO = 5 ///< SDO } si446x_gpio_t; /** * @brief Radio states, returned from ::Si446x_getState() */ typedef enum { SI446X_STATE_NOCHANGE = 0x00, SI446X_STATE_SLEEP = 0x01, ///< This will never be returned since SPI activity will wake the radio into ::SI446X_STATE_SPI_ACTIVE SI446X_STATE_SPI_ACTIVE = 0x02, SI446X_STATE_READY = 0x03, SI446X_STATE_READY2 = 0x04, ///< Will return as ::SI446X_STATE_READY SI446X_STATE_TX_TUNE = 0x05, ///< Will return as ::SI446X_STATE_TX SI446X_STATE_RX_TUNE = 0x06, ///< Will return as ::SI446X_STATE_RX SI446X_STATE_TX = 0x07, SI446X_STATE_RX = 0x08 } si446x_state_t; #define SI446X_CBS_SENT _BV(5+8) ///< Enable/disable packet sent callback //#define SI446X_CBS_RXCOMPLETE _BV(4+8) //#define SI446X_CBS_RXINVALID _BV(3+8) #define SI446X_CBS_RXBEGIN _BV(0) ///< Enable/disable packet receive begin callback //#define SI446X_CBS_INVALIDSYNC _BV(5) ///< Don't use this, it's used internally by the library /** * @brief Initialise, must be called before anything else! * * @return (none) */ void Si446x_init(void); /** * @brief Get chip info, see ::si446x_info_t * * @see ::si446x_info_t * @param [info] Pointer to allocated ::si446x_info_t struct to place data into * @return (none) */ void Si446x_getInfo(si446x_info_t* info); /** * @brief Get the current RSSI, the chip needs to be in receive mode for this to work * * @return The current RSSI in dBm (usually between -130 and 0) */ int16_t Si446x_getRSSI(void); /** * @brief Set the transmit power. The output power does not follow the \p pwr value, see the Si446x datasheet for a pretty graph * * 0 = -32dBm (<1uW)\n * 7 = 0dBm (1mW)\n * 12 = 5dBm (3.2mW)\n * 22 = 10dBm (10mW)\n * 40 = 15dBm (32mW)\n * 100 = 20dBm (100mW) * * @param [pwr] A value from 0 to 127 * @return (none) */ void Si446x_setTxPower(uint8_t pwr); /** * @brief Enable or disable callbacks. This is mainly to configure what events should wake the microcontroller up. * * @param [callbacks] The callbacks to configure (multiple callbacks should be bitewise OR'd together) * @param [state] Enable or disable the callbacks passed in \p callbacks parameter (1 = Enable, 0 = Disable) * @return (none) */ void Si446x_setupCallback(uint16_t callbacks, uint8_t state); /** * @brief Read received data from FIFO * * @param [buff] Pointer to buffer to place data * @param [len] Number of bytes to read, make sure not to read more bytes than what the FIFO has stored. The number of bytes that can be read is passed in the ::SI446X_CB_RXCOMPLETE() callback. * @return (none) */ void Si446x_read(void* buff, uint8_t len); /** * @brief Transmit a packet * * @param [packet] Pointer to packet data * @param [len] Number of bytes to transmit, maximum of ::SI446X_MAX_PACKET_LEN If configured for fixed length packets then this parameter is ignored and the length is set by ::SI446X_FIXED_LENGTH in Si446x_config.h * @param [channel] Channel to transmit data on (0 - 255) * @param [onTxFinish] What state to enter when the packet has finished transmitting. Usually ::SI446X_STATE_SLEEP or ::SI446X_STATE_RX * @return 0 on failure (already transmitting), 1 on success (has begun transmitting) */ uint8_t Si446x_TX(void* packet, uint8_t len, uint8_t channel, si446x_state_t onTxFinish); /** * @brief Enter receive mode * * Entering RX mode will abort any transmissions happening at the time * * @param [channel] Channel to listen to (0 - 255) * @return (none) */ void Si446x_RX(uint8_t channel); /*-* * @brief Changes will be applied next time the radio enters RX mode (NOT SUPPORTED) * * @param [mode] TODO * @param [address] TODO * @return (none) */ //void Si446x_setAddress(si446x_addrMode_t mode, uint8_t address); /** * @brief Set the low battery voltage alarm * * The ::SI446X_CB_LOWBATT() callback will be ran when the supply voltage drops below this value. The WUT must be configured with ::Si446x_setupWUT() to enable periodically checking the battery level. * * @param [voltage] The low battery threshold in millivolts (1050 - 3050). * @return (none) */ void Si446x_setLowBatt(uint16_t voltage); /** * @brief Configure the wake up timer * * This function will also reset the timer.\n *\n * The Wake Up Timer (WUT) can be used to periodically run a number of features:\n * ::SI446X_WUT_RUN Simply wake up the microcontroller when the WUT expires and run the ::SI446X_CB_WUT() callback.\n * ::SI446X_WUT_BATT Check battery voltage - If the battery voltage is below the threshold set by ::Si446x_setLowBatt() then wake up the microcontroller and run the ::SI446X_CB_LOWBATT() callback.\n * ::SI446X_WUT_RX Enter receive mode for a length of time determinded by the ldc and r parameters (NOT SUPPORTED YET! dont use this option)\n *\n * For more info see the GLOBAL_WUT_M, GLOBAL_WUT_R and GLOBAL_WUT_LDC properties in the Si446x API docs.\n * * @note When first turning on the WUT this function will take around 300us to complete * @param [r] Exponent value for WUT and LDC (Maximum valus is 20) * @param [m] Mantissia value for WUT * @param [ldc] Mantissia value for LDC (NOT SUPPORTED YET, just pass 0 for now) * @param [config] Which WUT features to enable ::SI446X_WUT_RUN ::SI446X_WUT_BATT ::SI446X_WUT_RX These can be bitwise OR'ed together to enable multiple features. * @return (none) */ void Si446x_setupWUT(uint8_t r, uint16_t m, uint8_t ldc, uint8_t config); /** * @brief Disable the wake up timer * * @return (none) */ void Si446x_disableWUT(void); /** * @brief Enter sleep mode * * If WUT is enabled then the radio will keep the internal 32KHz RC enabled with a current consumption of 740nA, otherwise the current consumption will be 40nA without WUT. * Sleep will fail if the radio is currently transmitting. * * @note Any SPI communications with the radio will wake the radio into ::SI446X_STATE_SPI_ACTIVE mode. ::Si446x_sleep() will need to called again to put it back into sleep mode. * * @return 0 on failure (busy transmitting something), 1 on success */ uint8_t Si446x_sleep(void); /** * @brief Get the radio status * * @see ::si446x_state_t * @return The current radio status */ si446x_state_t Si446x_getState(void); /** * @brief Read pin ADC value * * @param [pin] The GPIO pin number (0 - 3) * @return ADC value (0 - 2048, where 2048 is 3.6V) */ uint16_t Si446x_adc_gpio(uint8_t pin); /** * @brief Read supply voltage * * @return Supply voltage in millivolts */ uint16_t Si446x_adc_battery(void); /** * @brief Read temperature * * @return Temperature in C */ float Si446x_adc_temperature(void); /** * @brief Configure GPIO/NIRQ/SDO pin * * @note NIRQ and SDO pins should not be changed, unless you really know what you're doing. 2 of the GPIO pins (usually 0 and 1) are also usually used for the RX/TX RF switch and should also be left alone. * * @param [pin] The pin, this can only take a single pin (don't use bitwise OR), see ::si446x_gpio_t * @param [value] The new pin mode, this can be bitwise OR'd with the ::SI446X_PIN_PULL_EN option, see ::si446x_gpio_mode_t ::si446x_nirq_mode_t ::si446x_sdo_mode_t * @return (none) */ void Si446x_writeGPIO(si446x_gpio_t pin, uint8_t value); /** * @brief Read GPIO pin states * * @return The pin states. Use ::si446x_gpio_t to mask the value to get the state for the desired pin. */ uint8_t Si446x_readGPIO(void); /** * @brief Get all values of a property group * * @param [buff] Pointer to memory to place group values, if this is NULL then nothing will be dumped, just the group size is returned * @param [group] The group to dump * @return Size of the property group */ uint8_t Si446x_dump(void* buff, uint8_t group); #endif /* SI443X_H_ */