forked from ttrftech/NanoVNA
-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathsi446x.h
445 lines (405 loc) · 15.5 KB
/
si446x.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/*
* Project: Si4463 Radio Library for AVR and Arduino
* Author: Zak Kemble, [email protected]
* 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 <stdint.h>
//#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_ */