From 299c8efc11f645a154ef5529f483bf8a4d1a0b56 Mon Sep 17 00:00:00 2001 From: chen <15335560115@163.com> Date: 星期三, 21 五月 2025 11:49:23 +0800 Subject: [PATCH] 初步调好1s上传一条lora网关成功解析,未将测距信息放入包体,用的0x22的协议 --- keil/include/src/Radio/lora_1268.c | 742 +++++++++ keil/include/src/Radio/radio.c | 1159 ++++++++++++++ keil/include/src/Radio/radio.h | 379 ++++ keil/include/src/Radio/user.h | 22 keil/include/src/Radio/sx126x-board.h | 132 + keil/include/src/Radio/sx126x-board.c | 264 +++ keil/include/src/Radio/crc.c | 47 keil/include/src/Radio/crc.h | 24 keil/include/src/Radio/sx126x.c | 716 ++++++++ keil/include/src/Radio/lora_1268.h | 202 ++ keil/include/src/Radio/delay.c | 31 keil/include/src/Radio/sx126x.h | 1115 +++++++++++++ keil/include/src/Radio/delay.h | 16 13 files changed, 4,849 insertions(+), 0 deletions(-) diff --git a/keil/include/src/Radio/crc.c b/keil/include/src/Radio/crc.c new file mode 100644 index 0000000..68ed1c9 --- /dev/null +++ b/keil/include/src/Radio/crc.c @@ -0,0 +1,47 @@ +#include "crc.h" + + +uint16_t ComputeCrc( uint16_t crc, uint8_t dataByte, uint16_t polynomial ) +{ + uint8_t i; + + for( i = 0; i < 8; i++ ) + { + if( ( ( ( crc & 0x8000 ) >> 8 ) ^ ( dataByte & 0x80 ) ) != 0 ) + { + crc <<= 1; // shift left once + crc ^= polynomial; // XOR with polynomial + } + else + { + crc <<= 1; // shift left once + } + dataByte <<= 1; // Next data bit + } + return crc; +} + + +uint16_t RadioComputeCRC( uint8_t *buffer, uint8_t length, uint8_t crcType ) +{ + uint8_t i = 0; + uint16_t crc = 0; + uint16_t polynomial = 0; + + polynomial = ( crcType == CRC_TYPE_IBM ) ? POLYNOMIAL_IBM : POLYNOMIAL_CCITT; + crc = ( crcType == CRC_TYPE_IBM ) ? CRC_IBM_SEED : CRC_CCITT_SEED; + for( i = 0; i < length; i++ ) + { + crc = ComputeCrc( crc, buffer[i], polynomial ); + } + if( crcType == CRC_TYPE_IBM ) + { + return crc; + } + else + { + return( ( uint16_t ) ( ~crc )); + } +} + + diff --git a/keil/include/src/Radio/crc.h b/keil/include/src/Radio/crc.h new file mode 100644 index 0000000..49136fe --- /dev/null +++ b/keil/include/src/Radio/crc.h @@ -0,0 +1,24 @@ +#ifndef _CRC_H_ +#define _CRC_H_ + +#include <stdint.h> + +// CRC types +#define CRC_TYPE_CCITT 0 +#define CRC_TYPE_IBM 1 +// Polynomial = X^16 + X^12 + X^5 + 1 +#define POLYNOMIAL_CCITT 0x1021 +// Polynomial = X^16 + X^15 + X^2 + 1 +#define POLYNOMIAL_IBM 0x8005 +// Seeds +#define CRC_IBM_SEED 0xFFFF +#define CRC_CCITT_SEED 0x1D0F + + +uint16_t RadioComputeCRC( uint8_t *buffer, uint8_t length, uint8_t crcType ); +uint16_t ComputeCrc( uint16_t crc, uint8_t dataByte, uint16_t polynomial ); + + + +#endif + diff --git a/keil/include/src/Radio/delay.c b/keil/include/src/Radio/delay.c new file mode 100644 index 0000000..5e176ad --- /dev/null +++ b/keil/include/src/Radio/delay.c @@ -0,0 +1,31 @@ +#include "delay.h" +#include <stdint.h> +//#include "stm32l0xx_hal.h" + +void Delay_Us (uint32_t delay) +{ + uint8_t i=0; + uint32_t j=0; + for(i=0;i<delay;i++) + { + for(j=0;j<8;j++); + } +} + + +void Delay_Ms(uint32_t delay ) +{ + uint32_t i=0; + uint32_t j=0; + + for(i=0;i<delay;i++) + { + for(j=0;j<4540;j++); + } +} + +void HAL_Delay_nMS( uint32_t Delay ) +{ + Delay_Ms(Delay); +} + diff --git a/keil/include/src/Radio/delay.h b/keil/include/src/Radio/delay.h new file mode 100644 index 0000000..8a303bb --- /dev/null +++ b/keil/include/src/Radio/delay.h @@ -0,0 +1,16 @@ +#ifndef _DELAY_H_ +#define _DELAY_H_ + +#include<stdint.h> + +//extern volatile uint32_t TickCounter; +//extern volatile uint32_t ticktimer; + +void Delay_Us (uint32_t delay); +void Delay_Ms(uint32_t delay ); +void HAL_Delay_nMS(uint32_t Delay ); + +//#define HAL_GetTick() TickCounter + +#endif + diff --git a/keil/include/src/Radio/lora_1268.c b/keil/include/src/Radio/lora_1268.c new file mode 100644 index 0000000..4f1ec2f --- /dev/null +++ b/keil/include/src/Radio/lora_1268.c @@ -0,0 +1,742 @@ +#include <math.h> +#include <string.h> +#include "sx126x.h" +#include "sx126x-board.h" +#include "lora_1268.h" +//#include "lora_3029.h"" +#include "user.h" +#include "sx126x-board.h" +#include "string.h" +#include "stdio.h" +#include <stdlib.h> +#include "mk_spi.h" +#include "global_param.h" +#include "dw_app_anchor.h" +#include "HIDO_TypeDef.h" +#include "PCA9555.h" +#include "mk_misc.h" +/********************************************结构体**************************************************************/ +typedef enum +{ + LOWPOWER, + RX, + RX_TIMEOUT, + RX_ERROR, + TX, + TX_TIMEOUT, +}States_t; +/********************************************结构体**************************************************************/ +/********************************************变量**************************************************************/ +extern wg_state_enum wg_state; + + +/********************************************变量**************************************************************/ + +#define USE_MODEM_LORA + +#if defined( USE_MODEM_LORA ) + +#define LORA_BANDWIDTH 2 // [0: 125 kHz, + // 1: 250 kHz, + // 2: 500 kHz, + // 3: Reserved] +#define LORA_SPREADING_FACTOR 5 // [SF7..SF12] +#define LORA_CODINGRATE 1 // [1: 4/5, + // 2: 4/6, + // 3: 4/7, + // 4: 4/8] +#define LORA_PREAMBLE_LENGTH_T 8 // Same for Tx +#define LORA_PREAMBLE_LENGTH_R 8 // Same for Rx +//#define LORA_PREAMBLE_LENGTH 990 // Same for Tx and Rx +#define LORA_SYMBOL_TIMEOUT 0 // Symbols +#define LORA_FIX_LENGTH_PAYLOAD_ON false +#define LORA_IQ_INVERSION_ON_T false +#define LORA_IQ_INVERSION_ON_R false + + +#elif defined( USE_MODEM_FSK ) + +#define FSK_FDEV 5e3 // Hz +#define FSK_DATARATE 2.4e3 // bps +#define FSK_BANDWIDTH 20e3 // Hz >> DSB in sx126x +#define FSK_AFC_BANDWIDTH 100e3 // Hz +#define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx +#define FSK_FIX_LENGTH_PAYLOAD_ON false + +#else + #error "Please define a modem in the compiler options." +#endif + + +/***lora接收,发送变量定义******/ + +extern uint32_t current_count; + +extern uint32_t dev_id; +uint8_t yuyin_no_sleep_flag,no_rx_flag; +uint8_t lora_up_rec_flag; +static uint16_t source_id; +/***lora接收,发送变量定义******/ + +uint32_t wg_lost_count = 10; +//static uint8_t tx_buf[10] = {0x55, 0x44, 0x33, 0x22, 0x11}; +//static uint8_t rx_buf[10] = {0x00}; +//extern uint32_t uwbled,gpsled,loraled,powerled; +extern uint8_t bat_percent,taglist_num; +//uint8_t report_ancnum; +//uint16_t report_ancdist[ANC_MAX_NUM],report_ancid[ANC_MAX_NUM]; +extern void spi_transfer_callback(void *dev, uint32_t err_code); +extern uint16_t ancidlist_rec[TAG_NUM_IN_SYS],ancidlist_send[TAG_NUM_IN_SYS],rec_ancidlist[TAG_NUM_IN_SYS]; +extern uint8_t report_ancnum; +extern uint16_t report_ancdist[ANC_MAX_NUM],report_ancid[ANC_MAX_NUM]; +//extern wg_state_enum wg_state; +extern uint32_t wg_lost_count; +uint8_t lora_sendbuffer[200]; +uint8_t seq_num; +extern uint16_t lora_up_uwb_flag; +//extern uint8_t wg_lost_count; +uint16_t wg_report_freq,wg_report_id; +uint8_t wg_report_sf; +#define WG_LOST_SWITCH_THRES 3 +#define WG_LOST_NOUWB_COUNT 60 +#define DEFAULT_WG_ID 0xFFFF +#define DEFAULT_LR_WG_ID 0xFFFE +uint8_t lora_jianting_flag = 1; +wg_state_enum wg_state = WG_Lost; +void LoraReportFreqPoll(void) +{ + // wg_state = WG_Lost; + if(wg_lost_count++>WG_LOST_NOUWB_COUNT) + { + lora_jianting_flag = 0; + } else { + lora_jianting_flag = 1; + } + if(wg_state==WG_Lost) + { + static uint8_t channel_switch_count = 0; + // channel_switch_count = 10; + if(channel_switch_count++>1) + { +// channel_switch_count = 0; +// wg_report_id = DEFAULT_LR_WG_ID; +// wg_report_freq = LR_DATA_CHANNEL_FRQ; //如果丢失链接就进入WG管理信道。 +// wg_report_sf = LR_DATA_CHANNEL_SF; + } + else + { + wg_report_id = DEFAULT_WG_ID; + wg_report_freq = REPORT_MANGE_CHANNEL_FRQ; //如果丢失链接就进入WG管理信道。 + wg_report_sf = REPORT_CHANNEL_SF; +// wg_report_freq = TEST_MANAGE_CHANNEL_FRQ; +// wg_report_sf = TEST_MANAGE_CHANNEL_SF; + } + } else { + if(wg_lost_count>WG_LOST_SWITCH_THRES) + { + wg_state = WG_Lost; + } + } +} +static uint16_t checksum; + +//uint16_t wg_report_freq,wg_report_id; +uint8_t lora_sendbuffer[200]; +void LoraHeartBeartPoll(void) +{ + +// lora_up_uwb_flag=2; +// rf_set_default_para(); + +/*****************************心跳包上传内容************************************/ + lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_TAGHEARTBEAT; + lora_sendbuffer[MSG_LENGTH] = 14; + memcpy(&lora_sendbuffer[SOURCE_ID_IDX],&g_com_map[DEV_ID],2); + memcpy(&lora_sendbuffer[DEST_ID_IDX],&wg_report_id,2); + memcpy(&lora_sendbuffer[HB_VERSION_IDX],&g_com_map[VERSION],2); + lora_sendbuffer[HB_UWBPOWER_IDX] = g_com_map[POWER]; + lora_sendbuffer[HB_LORAPOWER_IDX] = g_com_map[LORA_POWER];//将距离校准改为了TX发射功率设置 + checksum = Checksum_u16(lora_sendbuffer,14); + memcpy(&lora_sendbuffer[14],&checksum,2); +// Radio.Send(lora_sendbuffer,16); + +/*****************************心跳包上传内容*************************************/ + +} +#define HEATBEAT_UPDATE_TIME 100 +uint16_t heatbeat_count = HEATBEAT_UPDATE_TIME-1 ; +uint16_t flag_getwgresp = 0; +int16_t intheight; //气压 +extern uint32_t dangqian_frqe; +uint16_t recnum[3]; +extern uint32_t freq_list[4]; +extern uint8_t DMA_RXBuf_BT[200]; +extern uint8_t report_ancnum; +extern uint8_t report_ancnum_bt; +uint32_t BT_SEND_lenth=0; +uint8_t BT_NUM=0; +extern uint16_t report_ancdist[ANC_MAX_NUM],report_ancid[ANC_MAX_NUM]; +extern uint8_t bat_percent; +extern uint16_t REV_RX_NUM; +extern uint16_t REV_POLL_NUM; +extern uint16_t REPLY_POLL_NUM; +uint16_t num[3]={0,0,0}; +extern uint8_t stationary_flag; +extern uint8_t SOS_KEY_STATE; +uint32_t LORA_POLL_COUNT=0; +#define GET_USERKEY gpio_pin_get_val(SOS_PIN) +void LoraReportPoll(void) +{ +//// // delay_ms(100); + +////#ifdef _USE_BAR +//// GetPressAndHeight(); +//// intheight = Height*100; +////#endif +////#ifdef _SMT_TEST +//// printf("气压值:%d",intheight); +////#endif + +////// TagListUpdate(); + +//// LoraReportFreqPoll(); +//// flag_getwgresp = 0; + +// SwitchLoraSettings(478,REPORT_CHANNEL_SF,22); + +//// if(heatbeat_count++>HEATBEAT_UPDATE_TIME && WG_Connected == wg_state) //如果心跳包到达上传时间,并且网关处于链接状态,就上传心跳包 +//// { +//// heatbeat_count = 0; +//// LoraHeartBeartPoll(); +//// return; +//// } +//// for(uint16_t i=0; i<report_ancnum-1; i++) +//// { +//// for(uint16_t j=0; j<report_ancnum-1-i; j++) +//// { +//// if(report_ancdist[j]>report_ancdist[j+1]) +//// { +//// uint16_t id,dist; +//// uint8_t bat; +//// id = report_ancid[j]; +//// dist = report_ancdist[j]; +//// report_ancid[j] = report_ancid[j+1]; +//// report_ancdist[j] = report_ancdist[j+1]; +//// report_ancid[j+1] = id; +//// report_ancdist[j+1] = dist; +//// } +//// } +//// } +//// +//// if(report_ancnum>LORA_REPORT_MAXANC_NUM) //考虑lora传输时间,最多发送10个基站数据。 +//// { +//// report_ancnum = LORA_REPORT_MAXANC_NUM; +//// } +//// +////#ifdef USE_GPS +//// lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_TAGMSGTOWG_GPS; +//// lora_sendbuffer[MSG_LENGTH] = 4*report_ancnum+30; +////#else +//// BT_NUM=DMA_RXBuf_BT[0]; +//// if(SOS_KEY_STATE) +//// { +//// BT_NUM=0; +////// } +//// lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_TAGMSGTOWG; +// lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_TAGMSGTOWG_BT; +// //lora_sendbuffer[MSG_LENGTH] = 4*report_ancnum+4*BT_NUM+ANCID_IDX+3; +////#endif +// memcpy(&lora_sendbuffer[SOURCE_ID_IDX],&g_com_map[DEV_ID],2); +// memcpy(&lora_sendbuffer[DEST_ID_IDX],&wg_report_id,2); +// lora_sendbuffer[SEQNUM_IDX] = seq_num++; +// lora_sendbuffer[BAT_IDX] = bat_percent; +//// lora_sendbuffer[STATE_IDX] = !GET_USERKEY|stationary_flag<<1; +//// //GET_USERKEY这个是那个lora——busy那个引脚 +////// lora_sendbuffer[STATE_IDX]=0x01; +////// lora_sendbuffer[GATEWAY_CHANL]=0x02; +////// lora_sendbuffer[CHANL_NUM]=0x03; +//// +////#ifdef USE_GPS +//// memcpy(&lora_sendbuffer[GPS_JINGDU_IDX],&gps_jingdu,8); +//// memcpy(&lora_sendbuffer[GPS_WEIDU_IDX],&gps_jingdu,8); +//// memcpy(&lora_sendbuffer[GPS_HEIGHT_IDX],&gps_height,8); +//// lora_sendbuffer[GPS_STATE_IDX] = gps_state; +//// lora_sendbuffer[GPS_SATEL_NUM_IDX] = gps_satel_num; +//// lora_sendbuffer[GPS_SPOWER_IDX] = gps_signalpower; +//// lora_sendbuffer[GPS_CHAFENLINGQI] = gps_chafenlingqi; +////#endif +//// memcpy(&lora_sendbuffer[BAR_HEIGHT_IDX],&intheight,2); +//// lora_sendbuffer[BT_ANCID_IDX] = report_ancnum; +//// memcpy(&lora_sendbuffer[BT_ANCID_IDX+1],report_ancid,report_ancnum*2); +//// memcpy(&lora_sendbuffer[BT_ANCID_IDX+report_ancnum*2+1],report_ancdist,report_ancnum*2); +//// uint8_t LORA_RETRANSNUSSION_BT=0; +////// +////// num[0]=REV_RX_NUM; +////// num[1]=REV_POLL_NUM; +////// num[2]=REPLY_POLL_NUM; +//// LORA_RETRANSNUSSION_BT=BT_ANCID_IDX+report_ancnum*4+1; +//// lora_sendbuffer[LORA_RETRANSNUSSION_BT] = 0x2D; //蓝牙上传标识符 + +//// memcpy(&lora_sendbuffer[LORA_RETRANSNUSSION_BT+1],&DMA_RXBuf_BT[0],BT_NUM*2+1); //基站ID +//// memcpy(&lora_sendbuffer[LORA_RETRANSNUSSION_BT+BT_NUM*2+2],&DMA_RXBuf_BT[1+BT_NUM*2],BT_NUM*2);//基站距离 +//// lora_sendbuffer[MSG_LENGTH] = LORA_RETRANSNUSSION_BT+4*BT_NUM+2; +////// } +////// if(lora_sendbuffer[LORA_RETRANSNUSSION_BT]==0x2D) +////// { +//// checksum = Checksum_u16(lora_sendbuffer,4*BT_NUM+4*report_ancnum+BT_ANCID_IDX+3); +//// memcpy(&lora_sendbuffer[LORA_RETRANSNUSSION_BT+BT_NUM*4+2],&checksum,2); +// BT_SEND_flag=BT_ANCID_IDX+report_ancnum*4+BT_NUM*4+5; +// Radio.Send(lora_sendbuffer,BT_SEND_flag); +//// LORA_POLL_COUNT++; +////// LORA_3029_SINGLE_SEND(lora_sendbuffer,ANCID_IDX+report_ancnum*4+BT_NUM*4+4,0); +////// } +////// else +////// { +////// checksum = Checksum_u16(lora_sendbuffer,4*report_ancnum+ANCID_IDX); +////// memcpy(&lora_sendbuffer[ANCID_IDX+report_ancnum*4],&checksum,2); +////// Radio.Send(lora_sendbuffer,ANCID_IDX+report_ancnum*4+BT_NUM*4+2); +////// } + + +#ifdef _USE_BAR + GetPressAndHeight(); + intheight = Height*100; +#endif +#ifdef _SMT_TEST + printf("气压值:%d",intheight); +#endif + + TagListUpdate(); + + LoraReportFreqPoll(); + flag_getwgresp = 0; + // wg_report_freq = REPORT_MANGE_CHANNEL_FRQ; + SwitchLoraSettings(wg_report_freq,REPORT_CHANNEL_SF,g_com_map[LORA_POWER]); + if(heatbeat_count++>HEATBEAT_UPDATE_TIME && WG_Connected == wg_state) //如果心跳包到达上传时间,并且网关处于链接状态,就上传心跳包 + { + heatbeat_count = 0; + LoraHeartBeartPoll(); + return; + } + for(uint16_t i=0; i<report_ancnum-1; i++) + { + for(uint16_t j=0; j<report_ancnum-1-i; j++) + { + if(report_ancdist[j]>report_ancdist[j+1]) + { + uint16_t id,dist; + uint8_t bat; + id = report_ancid[j]; + dist = report_ancdist[j]; + report_ancid[j] = report_ancid[j+1]; + report_ancdist[j] = report_ancdist[j+1]; + report_ancid[j+1] = id; + report_ancdist[j+1] = dist; + } + } + } + if(report_ancnum>LORA_REPORT_MAXANC_NUM) //考虑lora传输时间,最多发送10个基站数据。 + report_ancnum = LORA_REPORT_MAXANC_NUM; +#ifdef USE_GPS + lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_TAGMSGTOWG_GPS; + lora_sendbuffer[MSG_LENGTH] = 4*report_ancnum+30; +#else + lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_TAGMSGTOWG; + lora_sendbuffer[MSG_LENGTH] = 4*report_ancnum+ANCID_IDX; +#endif + memcpy(&lora_sendbuffer[SOURCE_ID_IDX],&g_com_map[DEV_ID],2); + memcpy(&lora_sendbuffer[DEST_ID_IDX],&wg_report_id,2); + lora_sendbuffer[SEQNUM_IDX] = seq_num++; + lora_sendbuffer[BAT_IDX] = bat_percent; + lora_sendbuffer[STATE_IDX] = !GET_USERKEY|stationary_flag<<1; +#ifdef USE_GPS + memcpy(&lora_sendbuffer[GPS_JINGDU_IDX],&gps_jingdu,8); + memcpy(&lora_sendbuffer[GPS_WEIDU_IDX],&gps_jingdu,8); + memcpy(&lora_sendbuffer[GPS_HEIGHT_IDX],&gps_height,8); + lora_sendbuffer[GPS_STATE_IDX] = gps_state; + lora_sendbuffer[GPS_SATEL_NUM_IDX] = gps_satel_num; + lora_sendbuffer[GPS_SPOWER_IDX] = gps_signalpower; + lora_sendbuffer[GPS_CHAFENLINGQI] = gps_chafenlingqi; +#endif + memcpy(&lora_sendbuffer[BAR_HEIGHT_IDX],&intheight,2); + lora_sendbuffer[ANCNUM_IDX] = report_ancnum; + memcpy(&lora_sendbuffer[ANCID_IDX],report_ancid,report_ancnum*2); + memcpy(&lora_sendbuffer[ANCID_IDX+report_ancnum*2],report_ancdist,report_ancnum*2); + checksum = Checksum_u16(lora_sendbuffer,4*report_ancnum+ANCID_IDX); + memcpy(&lora_sendbuffer[ANCID_IDX+report_ancnum*4],&checksum,2); + Radio.Send(lora_sendbuffer,ANCID_IDX+report_ancnum*4+2); + + +} + +//static uint16_t delaytime = 1200; +static uint16_t source_id; +uint8_t rec_index,rec_secdelay; +//uint16_t rec_value,rec_delaytime,rx_count; +//uint16_t rec_value,rec_delaytime,rx_count,datalen_offset; + +uint8_t shengji_flag,time=5; +extern uint32_t uwbled,gpsled,loraled,powerled; +extern struct RxDoneMsg RxDoneParams; + +//extern uint8_t Lora_tx_ancnum; +//extern uint8_t lora_seq_nb2; +extern uint16_t lora_yingda_num; +uint8_t lora_tx_flag=0; +uint8_t lora_txanchor_power_flag; +extern uint16_t Lora_tx_ancid[50]; +extern uint16_t Lora_tx_ancdist[50]; +extern uint8_t Lora_tx_anc_electricity[50]; +uint8_t lora_seq_nb1; + +extern uint8_t lora_sendbuffer[200]; +void LoraSendComMap(uint8_t cmd) +{ + uint8_t data_length = 0x50; + uint16_t checksum = 0; + lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_READPARARESP; + lora_sendbuffer[MSG_LENGTH] = data_length+11; + memcpy(&lora_sendbuffer[SOURCE_ID_IDX],&g_com_map[DEV_ID],2); + memcpy(&lora_sendbuffer[DEST_ID_IDX],&wg_report_id,2); + lora_sendbuffer[RP_CMD_IDX] = cmd; + lora_sendbuffer[RP_INDEX_IDX] = 2; + lora_sendbuffer[RP_LEN_IDX] = data_length; + memcpy(&lora_sendbuffer[9], &g_com_map[1], data_length); + checksum = Checksum_u16(lora_sendbuffer,11+data_length); + memcpy(&lora_sendbuffer[11+data_length],&checksum,2); +// LORA_3029_SINGLE_SEND(lora_sendbuffer,data_length+13,0); +// Radio.Send(lora_sendbuffer,data_length+13); + //++; + // Delay_Ms(100); +} +void LoraRspWriteCommap(uint8_t index) +{ + uint8_t data_length = 2; + uint16_t checksum = 0; + lora_sendbuffer[MSG_TYPE_IDX] = LORA_MSGTYPE_READPARARESP; + lora_sendbuffer[MSG_LENGTH] = data_length+9; + memcpy(&lora_sendbuffer[SOURCE_ID_IDX],&g_com_map[DEV_ID],2); + memcpy(&lora_sendbuffer[DEST_ID_IDX],&wg_report_id,2); + lora_sendbuffer[RP_CMD_IDX] = WGRSP_RWTAG_WRITE; + lora_sendbuffer[RP_INDEX_IDX] = index; + lora_sendbuffer[RP_LEN_IDX] = data_length; + memcpy(&lora_sendbuffer[7], &g_com_map[index/2], data_length); + checksum = Checksum_u16(lora_sendbuffer,9+data_length); + memcpy(&lora_sendbuffer[9+data_length],&checksum,2); +// Radio.Send(lora_sendbuffer,data_length+11); + +// LORA_3029_SINGLE_SEND(lora_sendbuffer,data_length+11,0); + // Delay_Ms(100); +} +uint8_t t22[20],ti; +uint8_t no_yingdaflag; +uint8_t aRxBuffer[1]; + +extern uint8_t group_id; +uint16_t lora_send_count; +uint8_t mode_flag=0; +uint32_t frqe,dangqian_frqe; + +uint8_t sum_count; +void Lora_Tx_Poll() +{ + +// if(lora_tx_flag) +// { +// OnMaster(); +//// +// //rf_enter_continous_rx(); +// } + if(lora_tx_flag) + { +// gpio_pin_set(IO_PIN_5); + + + if(lora_send_count++%10==0||lora_jianting_flag) + { + sum_count++; + lora_tx_flag=0; +#ifdef GROUPID_SWITCH + if(rec_secdelay>0) + { + rec_secdelay--; + return; + } +#endif + + LoraReportPoll(); + + } + } + + +} + +////States_t State = LOWPOWER; + +//////int8_t RssiValue = 0; +//////int8_t SnrValue = 0; +////uint8_t lora_chongfuyingda_flag; +////uint8_t Lora_rx_open_flag; +////extern u32 Loratx_frequency; +uint8_t huifushengjibao_flag; +uint8_t LoraUp_flag; +//uint8_t lora_up_rec_flag; +uint8_t flag_writepara_needreset = 0; +//uint32_t wg_lost_count = 10; +//uint32_t lora_zhuangtai; +//uint16_t current_count; +//extern wg_state_enum wg_state; +uint8_t txdone=0; +void OnTxDone( void ) +{ + txdone++; + if(flag_writepara_needreset) //配置写入完成设备需要重启 + { + printf("网关下发配置写入完成,重启"); + SCB->AIRCR = 0X05FA0000|(unsigned int)0x04; //软复位回到bootloader + } + Radio.Standby(); + if(LoraUp_flag) + { + huifushengjibao_flag=1; + Radio.Rx( 500 ); + } + else + { + Radio.Rx( 50 ); + //LORA_LED_OFF; + } +} +#define BUFFER_SIZE 255 // Define the payload size here + +extern uint8_t imu_enable,motor_enable; +extern uint8_t lora_jianting_flag,report_ancnum; +extern uint16_t motor_keeptime; +extern uint32_t dev_id; +//extern wg_state_enum wg_state; +uint16_t rec_value,rec_delaytime,rx_count,datalen_offset; +uint16_t BufferSize = BUFFER_SIZE; +uint16_t CRC16=0; +uint16_t DEST_ID=0; +uint8_t shengji_flag; +int8_t RssiValue = 0; +int8_t SnrValue = 0; +uint8_t TX_Buffer[BUFFER_SIZE]; +uint8_t RX_Buffer[BUFFER_SIZE]; +static RadioEvents_t RadioEvents; +static uint16_t delaytime = 771; +static uint16_t source_id; + + +uint8_t rec_index,rec_secdelay; +uint16_t rec_value,rx_count,datalen_offset; +int32_t target_count; +uint32_t sleep_time_count=0; +uint32_t sleep_time_count_LAST=0; +uint16_t time_count; +uint8_t LoraUp_flag; +uint16_t REV_WG_pack=0; +uint8_t rxdone=0; +void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) +{ + uint16_t checksum1; + BufferSize = size; + memcpy( RX_Buffer, payload, BufferSize ); + RssiValue = rssi; + SnrValue = snr; + Radio.Standby(); + rxdone++; + no_rx_flag = 0; + lora_up_rec_flag=1; + if(RX_Buffer[MSG_TYPE_IDX]==LORA_MSGTYPE_WGRESPTAG) + { + checksum1=Checksum_u16(RX_Buffer,BufferSize-2); + + memcpy(&DEST_ID,&RX_Buffer[DEST_ID_IDX],2); + memcpy(&CRC16,&RX_Buffer[BufferSize-2],2); + if(!memcmp(&checksum1,&RX_Buffer[BufferSize-2],2)) + if(!memcmp(&dev_id,&RX_Buffer[DEST_ID_IDX],2)) + { + memcpy(&source_id,&RX_Buffer[SOURCE_ID_IDX],2); + if(wg_state==WG_Lost) + { + wg_state = WG_Connected; + wg_report_id = source_id; + } + if(!memcmp(&wg_report_id,&RX_Buffer[SOURCE_ID_IDX],2)) + { + wg_lost_count = 0; + switch(RX_Buffer[PWTAG_RW_FLAG_IDX]) + { + case WGRSP_RWTAG_NONE: + REV_WG_pack++; + wg_report_freq = RX_Buffer[POLL_FREQ_IDX]+400; + memcpy(&rec_delaytime,&RX_Buffer[NEXTPOLL_TIME_IDX],2); + + if(report_ancnum<2) + { + datalen_offset = report_ancnum*85; + }else{ + datalen_offset = (report_ancnum-1)*46+85; + } + rec_secdelay = RX_Buffer[PWTAG_SECDELAY_IDX]; + if(BufferSize!=13||rec_secdelay>20) + { + rec_secdelay = 0; + } + if(rec_delaytime<500) + { + int t; + t++; + } +// sleep_time_count =(__MS_TO_32K_CNT(rec_delaytime)/10)- delaytime-datalen_offset; + sleep_time_count =(__MS_TO_32K_CNT(rec_delaytime)/10); + while(sleep_time_count>=32768) + { + sleep_time_count-=32768; + } + while(sleep_time_count<2000) + { + sleep_time_count+=10000; + } +// if(REV_WG_pack==1) +// { +// sleep_time_count_LAST=sleep_time_count; +// } +// if(abs(sleep_time_count_LAST-sleep_time_count)>2000||REV_WG_pack==1) +// { + sleep_timer_start(sleep_time_count); + time_count++; +// } + break; + case WGRSP_RWTAG_READ: + no_rx_flag = 1; + LoraSendComMap(WGRSP_RWTAG_READ); + break; + case WGRSP_RWTAG_WRITE: + rec_index = RX_Buffer[PWTAG_WRITE_IDX_IDX]; + switch(rec_index) + { + case 0xdd: //语音下发 + break; +// case 0x20: //蜂鸣 +// memcpy(&rec_value,&RX_Buffer[PWTAG_WRITE_VALUE_IDX],2); +// motor_keeptime = rec_value; +// break; + default : + memcpy(&rec_value,&RX_Buffer[PWTAG_WRITE_VALUE_IDX],2); + g_com_map[rec_index/2] = rec_value; + save_com_map_to_flash(); + LoraRspWriteCommap(SUBMSG_WRITE_ANCPARA); + //flag_writepara_needreset = 1; + no_rx_flag = 1; + } + + break; + case WGRSP_RWTAG_UPDATE: + rec_index = RX_Buffer[PWTAG_WRITE_IDX_IDX]; +// switch(rec_index) +// { +// case 0xaa: //升级下发 +// memcpy(&rec_wenjian_daxiao,&RX_Buffer[WRITEPARA_VALUE_IDX],2);//文件大小 +// if(rec_wenjian_daxiao>0XAC00||rec_wenjian_daxiao==0) +// {}//文件过大,超出范围 +// else +// { +// memcpy(&wangguan_up_id,&RX_Buffer[SOURCE_ID_IDX],2);//网关ID 占用2个字节 +// shengji_flag=1; +// LoraUp_flag=1; +// imu_enable=0; +// } +//// LoraUp_Poll(); +// break; +// } + break; + } + } + } + + } + if(!no_rx_flag) + { + if(lora_jianting_flag&&LoraUp_flag==0) + { + SwitchLoraSettings(UWB_CHANNEL_FRQ+group_id,UWB_CHANNEL_SF,0); + Radio.Rx(0); + } + } +} + +void OnTxTimeout( void ) +{ + Radio.Standby(); + if(lora_jianting_flag) + { + SwitchLoraSettings(UWB_CHANNEL_FRQ+group_id,UWB_CHANNEL_SF,0); + Radio.Rx(0); + } +} + +void OnRxTimeout( void ) +{ + Radio.Standby(); + if(lora_jianting_flag) + { + SwitchLoraSettings(UWB_CHANNEL_FRQ+group_id,UWB_CHANNEL_SF,0); + Radio.Rx(0); + } +} + + +void OnRxError( void ) +{ + + Radio.Standby(); + if(lora_jianting_flag) + { + SwitchLoraSettings(UWB_CHANNEL_FRQ+group_id,UWB_CHANNEL_SF,0); + Radio.Rx(0); + } +} + + + +uint16_t freq_test; +void SwitchLoraSettings(uint32_t freq,uint8_t sf,uint8_t power) +{ + Radio.Standby(); + Radio.SetChannel( freq*1000000 ); + freq_test = freq; + Radio.SetTxConfig( MODEM_LORA, power, 0, 2, + sf, LORA_CODINGRATE,LORA_PREAMBLE_LENGTH_T, LORA_FIX_LENGTH_PAYLOAD_ON, + false, 0, 0, LORA_IQ_INVERSION_ON_T, 3000 ); + + Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, + sf,LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH_R, + LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, + 0, false, 0, 0, LORA_IQ_INVERSION_ON_R, 0 ); +} + + +uint8_t active_flag; +void Lora_1268_Init(void) +{ + RadioEvents.TxDone = OnTxDone; + RadioEvents.RxDone = OnRxDone; + RadioEvents.TxTimeout = OnTxTimeout; + RadioEvents.RxTimeout = OnRxTimeout; + RadioEvents.RxError = OnRxError; + + Radio.Init( &RadioEvents ); +// SwitchLoraSettings(UWB_CHANNEL_FRQ+group_id,UWB_CHANNEL_SF,0); //切换lora接收频点 + if(active_flag) + { + Radio.Rx( 0 ); + } +// else{ +// Radio.Sleep(); +// } +// Radio.SetRxDutyCycle(RxDutyCycle_RX_time,RxDutyCycle_SLEEP_time); + +} diff --git a/keil/include/src/Radio/lora_1268.h b/keil/include/src/Radio/lora_1268.h new file mode 100644 index 0000000..13d1877 --- /dev/null +++ b/keil/include/src/Radio/lora_1268.h @@ -0,0 +1,202 @@ +#ifndef __LORA_1268_H +#define __LORA_1268_H +#include "mk_io.h" + +//BT板子更改了片选角 + +//#define LORA_CS IO_PIN_14 +#define LORA_CS IO_PIN_8 +#define LORA_MOSI IO_PIN_11 +#define LORA_MISO IO_PIN_12 +#define LORA_CLK IO_PIN_13 +#define LORA_IRQ IO_PIN_7 +#define LORA_BUSY IO_PIN_2 + +#define LORA_NRST IO_PIN_4 +#define LORA_NRST_DOWN gpio_pin_clr(IO_PIN_4) +#define LORA_NRST_UP gpio_pin_set(IO_PIN_4) + +//#define BOXING_PIN IO_PIN_1 +//#define LORA_DIO IO_PIN_4 +#define ANC_MAX_NUM 50 +#define LORA_REPORT_MAXANC_NUM 10 +//#define TEST_FREQ +#ifdef TEST_FREQ +#define LORA_UPCHANNEL_FRQ 456 +#define LORA_UPCHANNEL_SF 9 + +#define TEST_FREQ_OFFSET 1 +#define UWB_CHANNEL_FRQ 450+TEST_FREQ_OFFSET +#define UWB_CHANNEL_SF 5 + +#define LR_DATA_CHANNEL_FRQ 457 +#define LR_DATA_CHANNEL_SF 9 + +#define REPORT_MANGE_CHANNEL_FRQ 458 +TEST_FREQ_OFFSET +#define REPORT_CHANNEL_SF 7 +#else +#define LORA_UPCHANNEL_FRQ 476 +#define LORA_UPCHANNEL_SF 8 + +#define UWB_CHANNEL_FRQ 470 +#define UWB_CHANNEL_SF 5 + +#define REPORT_MANGE_CHANNEL_FRQ 478 +#define REPORT_CHANNEL_SF 7 + +#define LR_DATA_CHANNEL_FRQ 475 +#define LR_DATA_CHANNEL_SF 9 + +//#define TEST_MANAGE_CHANNEL_FRQ 457 +//#define TEST_MANAGE_CHANNEL_SF 5 + +#endif + +//LORA 数据格式 + +//免布线系统中 所有的LORA传输信息都包含在下面的MSG TYPE(消息类型)格式中,不同的消息类型,会对应不同的所有格式 +//LORA MSG TYPE的几种类型 +#define LORA_MSGTYPE_SYNC 1//网关下发给基站的同步信息 +#define LORA_MSGTYPE_CFGRSP 2//基站回复给网关配置读取信息 +#define LORA_MSGTYPE_UPDATE_CONFIRM 3//基站回复给网关升级确认信息 +#define LORA_MSGTYPE_RANGEPOLL 4//基站发起测距同步信号 +#define LORA_MSGTYPE_UPDATEFILE_REQUEST 5//基站发送给网关升级文件请求 +#define LORA_MSGTYPE_UPDATEFILE_RESP 6//网关回复基站升级文件内容 +#define LORA_MSGTYPE_ANCHEARTBEAT_POLL 7//网关回复基站升级文件内容 +#define LORA_MSGTYPE_TAGMSGTOWG 0x22//标签距离信息发给网关 +#define LORA_MSGTYPE_TAGMSGTOWG_GPS 0x23//标签距离信息发给网关 + +#define LORA_MSGTYPE_TAGMSGTOWG_BT 0x26//标签距离信息蓝牙距离信息,信号强度,发给网关 + +#define LORA_MSGTYPE_WGRESPTAG 8//网关回复标签测距定位报文 +#define LORA_MSGTYPE_TAGHEARTBEAT 0x33//标签心跳包上传 +#define LORA_MSGTYPE_READPARARESP 0x39 //标签基站回复网关读取配置指令 +//SYNC消息下 子消息类型定义 +#define SUBMSG_NONE 0//无其他消息 只是同步信号 +#define SUBMSG_READ_ANCPARA 0x11//子消息类型:读取基站配置 +#define SUBMSG_WRITE_ANCPARA 0x12//子消息类型:写基站配置 +#define SUBMSG_UPDATE_TAG 5//子消息类型:升级标签 +#define SUBMSG_UPDATE_ANC 6//子消息类型:升级基站 +//SYNC消息类型格式 +#define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 +#define MSG_LENGTH 1 //报文长度 +#define SOURCE_ID_IDX 2 //网关ID 占用2个字节 +#define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 +#define SYSTIME_IDX 6 //系统时间 +#define RANGE_STATE_IDX 7 //该网关范围是否测距标志位,为1则区域内基站测距,如果是0则区域内基站不测距 +#define SUBMSGTYPE_IDX 9 //子消息类型IDX +#define WRITEPARA_INDEX_IDX 10 //写入参数的地址IDX +#define WRITEPARA_VALUE_IDX 11 //写入参数的值,2个字节 /*在发送升级基站请求时,被替换为要发送的升级文件的大小 +#define WG_SYNC_RESERVE_IDX 13 //保留 4个字节 +//LORA_MSGTYPE_TAGMSGTOWG 标签上报网关定位报文信息格式 + +#ifdef USE_GPS + #define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 + #define MSG_LENGTH 1 //报文长度 + #define SOURCE_ID_IDX 2 //网关ID 占用2个字节 + #define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 + #define SEQNUM_IDX 6 //标签报文序号 + #define BAT_IDX 7 //标签电量 + #define STATE_IDX 8 + #define GPS_JINGDU_IDX 9 + #define GPS_WEIDU_IDX 17 + #define GPS_HEIGHT_IDX 25 + #define GPS_STATE_IDX 29 + #define GPS_SATEL_NUM_IDX 30 + #define GPS_SPOWER_IDX 31 //信号强度 + #define GPS_CHAFENLINGQI 32 //差分龄期 + #define BAR_HEIGHT_IDX 33 //气压高度 + #define ANCNUM_IDX 35 + #define ANCID_IDX 36 //校验在4*ancnum+ANCID_IDX 位置 +#else + #define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 + #define MSG_LENGTH 1 //报文长度 + #define SOURCE_ID_IDX 2 //网关ID 占用2个字节 + #define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 + #define SEQNUM_IDX 6 //标签报文序号 + #define BAT_IDX 7 //标签电量 + #define STATE_IDX 8 + #define BAR_HEIGHT_IDX 9 //气压高度 + #define GATEWAY_CHANL 9 + #define CHANL_NUM 10 + #define ANCNUM_IDX 11 + #define ANCID_IDX 12 //校验在4*ancnum+ANCID_IDX 位置 +// #define LORA_RETRANSNUSSION_BT 13 //LORA转发蓝牙协议标识符 + + +#endif +//#define LORA_MSGTYPE_WGRESPTAG 8//网关回复标签测距定位报文 格式 +#define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 +#define MSG_LENGTH 1 //报文长度 +#define SOURCE_ID_IDX 2 //网关ID 占用2个字节 +#define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 +#define NEXTPOLL_TIME_IDX 6 // +#define POLL_FREQ_IDX 8 //分配的发送频率,需要+400的偏移量。 +#define PWTAG_RW_FLAG_IDX 9 //读写标志 0无读写 1写入 2读取 +#define PWTAG_WRITE_IDX_IDX 10 //写入地址 +#define PWTAG_SECDELAY_IDX 10 //写入标签秒延迟 与读写地址共用一个位置,当有读写地址时,就没有这个参数。 +#define PWTAG_WRITE_VALUE_IDX 11 //写入值 + +#define WGRSP_RWTAG_NONE 0//网关回复标签,无读写 +#define WGRSP_RWTAG_READ 2//网关回复标签,无读写 +#define WGRSP_RWTAG_WRITE 1//网关回复标签,无读写 +#define WGRSP_RWTAG_UPDATE 0x06//网关回复标签,无读写 +//#define LORA_MSGTYPE_READPARARESP 0x39 //标签基站回复网关读取配置指令 +#define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 +#define MSG_LENGTH 1 //报文长度 +#define SOURCE_ID_IDX 2 //网关ID 占用2个字节 +#define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 +#define RP_CMD_IDX 6 //标签或者基站的设备ID 2个字节 +#define RP_INDEX_IDX 7 //标签或者基站的设备ID 2个字节 +#define RP_LEN_IDX 8 //标签或者基站的设备ID 2个字节 + +//#define LORA_MSGTYPE_TAGHEARTBEAT 0x33//标签心跳包上传 格式 +#define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 +#define MSG_LENGTH 1 //报文长度 +#define SOURCE_ID_IDX 2 //网关ID 占用2个字节 +#define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 +#define HB_VERSION_IDX 6 //标签或者基站的设备ID 2个字节 +#define HB_UWBPOWER_IDX 8 //标签或者基站的设备ID 2个字节 +#define HB_LORAPOWER_IDX 9 //标签或者基站的设备ID 2个字节 +#define HB_RESERVE_IDX 10//标签或者基站的设备ID 2个字节 + + +//#define LORA_MSGTYPE_TAGBTMSGTOWG + #define MSG_TYPE_IDX 0 //LORA MSG TYPE 定义 + #define MSG_LENGTH 1 //报文长度 + #define SOURCE_ID_IDX 2 //网关ID 占用2个字节 + #define DEST_ID_IDX 4 //标签或者基站的设备ID 2个字节 + #define SEQNUM_IDX 6 //标签报文序号 + #define BAT_IDX 7 //标签电量 + #define STATE_IDX 8 //按键/静止 + #define BAR_HEIGHT_IDX 9 //气压高度 + #define STEP_COUNT 15 + #define EXERCISE_STATE 16 + #define RESERVED_POSITION 17 +// #define GETWG_CHANL 11 //网关通道 +// #define GETCHANL_NUM 12 //通道序号 +// #define SIGNAL_STRENGTH 13 //信号强度 +// #define ERROR_TIME 14 //误差时间 + #define STATION_NUM_UWB 16 //基站数量-蓝牙 + +// #define STATION_NUM_UWB + #define BT_ANCID_IDX 15 //校验在4*ancnum+ANCID_IDX 位置 +typedef enum{ WG_Lost, //上报丢失 失去和网关通讯 + WG_Connected,// 上报中 和网关通讯正常 +}wg_state_enum; + + + + + + + + +void Lora_1268_Init(void); +void OnTxDone( void ); +void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); +void OnTxTimeout( void ); +void OnRxTimeout( void ); +void OnRxError( void ); +void SwitchLoraSettings(uint32_t freq,uint8_t sf,uint8_t power); +#endif \ No newline at end of file diff --git a/keil/include/src/Radio/radio.c b/keil/include/src/Radio/radio.c new file mode 100644 index 0000000..908a874 --- /dev/null +++ b/keil/include/src/Radio/radio.c @@ -0,0 +1,1159 @@ +/*! + * \file radio.c + * + * \brief Radio driver API definition + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + */ +// #include "stm32l0xx_hal.h" +//#include "stm32l0xx_hal_conf.h" +//#include "main.h" +#include <math.h> +#include <string.h> +#include <stdbool.h> +//#include "stm32f0xx.h" +#include "delay.h" +//#include "dw_driver.h" +//#include "gpio.h" +//#include "spi.h" +#include "radio.h" +#include "sx126x.h" +#include "sx126x-board.h" +//#include "stm32l0xx_hal_gpio.h" +#include "lora_1268.h" + +/*! + * \brief Initializes the radio + * + * \param [IN] events Structure containing the driver callback functions + */ +void RadioInit( RadioEvents_t *events ); + +/*! + * Return current radio status + * + * \param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING] + */ +RadioState_t RadioGetStatus( void ); + +/*! + * \brief Configures the radio with the given modem + * + * \param [IN] modem Modem to be used [0: FSK, 1: LoRa] + */ +void RadioSetModem( RadioModems_t modem ); + +/*! + * \brief Sets the channel frequency + * + * \param [IN] freq Channel RF frequency + */ +void RadioSetChannel( uint32_t freq ); + +/*! + * \brief Checks if the channel is free for the given time + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] freq Channel RF frequency + * \param [IN] rssiThresh RSSI threshold + * \param [IN] maxCarrierSenseTime Max time while the RSSI is measured + * + * \retval isFree [true: Channel is free, false: Channel is not free] + */ +bool RadioIsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime ); + +/*! + * \brief Generates a 32 bits random value based on the RSSI readings + * + * \remark This function sets the radio in LoRa modem mode and disables + * all interrupts. + * After calling this function either Radio.SetRxConfig or + * Radio.SetTxConfig functions must be called. + * + * \retval randomValue 32 bits random value + */ +uint32_t RadioRandom( void ); + +/*! + * \brief Sets the reception parameters + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] bandwidth Sets the bandwidth + * FSK : >= 2600 and <= 250000 Hz + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * \param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * \param [IN] coderate Sets the coding rate (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only) + * FSK : >= 2600 and <= 250000 Hz + * LoRa: N/A ( set to 0 ) + * \param [IN] preambleLen Sets the Preamble length + * FSK : Number of bytes + * LoRa: Length in symbols (the hardware adds 4 more symbols) + * \param [IN] symbTimeout Sets the RxSingle timeout value + * FSK : timeout in number of bytes + * LoRa: timeout in symbols + * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * \param [IN] payloadLen Sets payload length when fixed length is used + * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON] + * \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping + * FSK : N/A ( set to 0 ) + * LoRa: [0: OFF, 1: ON] + * \param [IN] HopPeriod Number of symbols between each hop + * FSK : N/A ( set to 0 ) + * LoRa: Number of symbols + * \param [IN] iqInverted Inverts IQ signals (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * \param [IN] rxContinuous Sets the reception in continuous mode + * [false: single mode, true: continuous mode] + */ +void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidthAfc, uint16_t preambleLen, + uint16_t symbTimeout, bool fixLen, + uint8_t payloadLen, + bool crcOn, bool FreqHopOn, uint8_t HopPeriod, + bool iqInverted, bool rxContinuous ); + +/*! + * \brief Sets the transmission parameters + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] power Sets the output power [dBm] + * \param [IN] fdev Sets the frequency deviation (FSK only) + * FSK : [Hz] + * LoRa: 0 + * \param [IN] bandwidth Sets the bandwidth (LoRa only) + * FSK : 0 + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * \param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * \param [IN] coderate Sets the coding rate (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * \param [IN] preambleLen Sets the preamble length + * FSK : Number of bytes + * LoRa: Length in symbols (the hardware adds 4 more symbols) + * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * \param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON] + * \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping + * FSK : N/A ( set to 0 ) + * LoRa: [0: OFF, 1: ON] + * \param [IN] HopPeriod Number of symbols between each hop + * FSK : N/A ( set to 0 ) + * LoRa: Number of symbols + * \param [IN] iqInverted Inverts IQ signals (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * \param [IN] timeout Transmission timeout [ms] + */ +void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preambleLen, + bool fixLen, bool crcOn, bool FreqHopOn, + uint8_t HopPeriod, bool iqInverted, uint32_t timeout ); + +/*! + * \brief Checks if the given RF frequency is supported by the hardware + * + * \param [IN] frequency RF frequency to be checked + * \retval isSupported [true: supported, false: unsupported] + */ +bool RadioCheckRfFrequency( uint32_t frequency ); + +/*! + * \brief Computes the packet time on air in ms for the given payload + * + * \Remark Can only be called once SetRxConfig or SetTxConfig have been called + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] pktLen Packet payload length + * + * \retval airTime Computed airTime (ms) for the given packet payload length + */ +uint32_t RadioTimeOnAir( RadioModems_t modem, uint8_t pktLen ); + +/*! + * \brief Sends the buffer of size. Prepares the packet to be sent and sets + * the radio in transmission + * + * \param [IN]: buffer Buffer pointer + * \param [IN]: size Buffer size + */ +void RadioSend( uint8_t *buffer, uint8_t size ); + +/*! + * \brief Sets the radio in sleep mode + */ +void RadioSleep( void ); + +/*! + * \brief Sets the radio in standby mode + */ +void RadioStandby( void ); + +/*! + * \brief Sets the radio in reception mode for the given time + * \param [IN] timeout Reception timeout [ms] + * [0: continuous, others timeout] + */ +void RadioRx( uint32_t timeout ); + +/*! + * \brief Start a Channel Activity Detection + */ +void RadioStartCad( void ); + +/*! + * \brief Sets the radio in continuous wave transmission mode + * + * \param [IN]: freq Channel RF frequency + * \param [IN]: power Sets the output power [dBm] + * \param [IN]: time Transmission mode timeout [s] + */ +void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ); + +/*! + * \brief Reads the current RSSI value + * + * \retval rssiValue Current RSSI value in [dBm] + */ +int16_t RadioRssi( RadioModems_t modem ); + +/*! + * \brief Writes the radio register at the specified address + * + * \param [IN]: addr Register address + * \param [IN]: data New register value + */ +void RadioWrite( uint16_t addr, uint8_t data ); + +/*! + * \brief Reads the radio register at the specified address + * + * \param [IN]: addr Register address + * \retval data Register value + */ +uint8_t RadioRead( uint16_t addr ); + +/*! + * \brief Writes multiple radio registers starting at address + * + * \param [IN] addr First Radio register address + * \param [IN] buffer Buffer containing the new register's values + * \param [IN] size Number of registers to be written + */ +void RadioWriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size ); + +/*! + * \brief Reads multiple radio registers starting at address + * + * \param [IN] addr First Radio register address + * \param [OUT] buffer Buffer where to copy the registers data + * \param [IN] size Number of registers to be read + */ +void RadioReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size ); + +/*! + * \brief Sets the maximum payload length. + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] max Maximum payload length in bytes + */ +void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max ); + +/*! + * \brief Sets the network to public or private. Updates the sync byte. + * + * \remark Applies to LoRa modem only + * + * \param [IN] enable if true, it enables a public network + */ +void RadioSetPublicNetwork( bool enable ); + +/*! + * \brief Gets the time required for the board plus radio to get out of sleep.[ms] + * + * \retval time Radio plus board wakeup time in ms. + */ +uint32_t RadioGetWakeupTime( void ); + +/*! + * \brief Process radio irq + */ +void RadioIrqProcess( void ); + +/*! + * \brief Sets the radio in reception mode with Max LNA gain for the given time + * \param [IN] timeout Reception timeout [ms] + * [0: continuous, others timeout] + */ +void RadioRxBoosted( uint32_t timeout ); + +/*! + * \brief Sets the Rx duty cycle management parameters + * + * \param [in] rxTime Structure describing reception timeout value + * \param [in] sleepTime Structure describing sleep timeout value + */ +void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ); + +/*! + * Radio driver structure initialization + */ +const struct Radio_s Radio = +{ + RadioInit, + RadioGetStatus, + RadioSetModem, + RadioSetChannel, + RadioIsChannelFree, + RadioRandom, + RadioSetRxConfig, + RadioSetTxConfig, + RadioCheckRfFrequency, + RadioTimeOnAir, + RadioSend, + RadioSleep, + RadioStandby, + RadioRx, + RadioStartCad, + RadioSetTxContinuousWave, + RadioRssi, + RadioWrite, + RadioRead, + RadioWriteBuffer, + RadioReadBuffer, + RadioSetMaxPayloadLength, + RadioSetPublicNetwork, + RadioGetWakeupTime, + RadioIrqProcess, + // Available on SX126x only + RadioRxBoosted, + RadioSetRxDutyCycle +}; + +/* + * Local types definition + */ + + + /*! + * FSK bandwidth definition + */ +typedef struct +{ + uint32_t bandwidth; + uint8_t RegValue; +}FskBandwidth_t; + +/*! + * Precomputed FSK bandwidth registers values + */ +const FskBandwidth_t FskBandwidths[] = +{ + { 4800 , 0x1F }, + { 5800 , 0x17 }, + { 7300 , 0x0F }, + { 9700 , 0x1E }, + { 11700 , 0x16 }, + { 14600 , 0x0E }, + { 19500 , 0x1D }, + { 23400 , 0x15 }, + { 29300 , 0x0D }, + { 39000 , 0x1C }, + { 46900 , 0x14 }, + { 58600 , 0x0C }, + { 78200 , 0x1B }, + { 93800 , 0x13 }, + { 117300, 0x0B }, + { 156200, 0x1A }, + { 187200, 0x12 }, + { 234300, 0x0A }, + { 312000, 0x19 }, + { 373600, 0x11 }, + { 467000, 0x09 }, + { 500000, 0x00 }, // Invalid Bandwidth +}; + +const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 }; + +// SF12 SF11 SF10 SF9 SF8 SF7 +static double RadioLoRaSymbTime[3][6] = {{ 32.768, 16.384, 8.192, 4.096, 2.048, 1.024 }, // 125 KHz + { 16.384, 8.192, 4.096, 2.048, 1.024, 0.512 }, // 250 KHz + { 8.192, 4.096, 2.048, 1.024, 0.512, 0.256 }}; // 500 KHz + +uint8_t MaxPayloadLength = 0xFF; + +uint32_t TxTimeout = 0; +uint32_t RxTimeout = 0; + +bool RxContinuous = false; + + +PacketStatus_t RadioPktStatus; +uint8_t RadioRxPayload[255]; + +bool IrqFired = false; + +/* + * SX126x DIO IRQ callback functions prototype + */ + +/*! + * \brief DIO 0 IRQ callback + */ +void RadioOnDioIrq( void ); + +/*! + * \brief Tx timeout timer callback + */ +void RadioOnTxTimeoutIrq( void ); + +/*! + * \brief Rx timeout timer callback + */ +void RadioOnRxTimeoutIrq( void ); + +/* + * Private global variables + */ + + +/*! + * Holds the current network type for the radio + */ +typedef struct +{ + bool Previous; + bool Current; +}RadioPublicNetwork_t; + +static RadioPublicNetwork_t RadioPublicNetwork = { false }; + +/*! + * Radio callbacks variable + */ +static RadioEvents_t* RadioEvents; + +/* + * Public global variables + */ + +/*! + * Radio hardware and global parameters + */ +SX126x_t SX126x; + +/*! + * Tx and Rx timers + */ +//TimerEvent_t TxTimeoutTimer; +//TimerEvent_t RxTimeoutTimer; + +/*! + * Returns the known FSK bandwidth registers value + * + * \param [IN] bandwidth Bandwidth value in Hz + * \retval regValue Bandwidth register value. + */ +static uint8_t RadioGetFskBandwidthRegValue( uint32_t bandwidth ) +{ + uint8_t i; + + if( bandwidth == 0 ) + { + return( 0x1F ); + } + + for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( FskBandwidth_t ) ) - 1; i++ ) + { + if( ( bandwidth >= FskBandwidths[i].bandwidth ) && ( bandwidth < FskBandwidths[i + 1].bandwidth ) ) + { + return FskBandwidths[i+1].RegValue; + } + } + // ERROR: Value not found + while( 1 ); +} +uint8_t buf[2]; +void RadioInit( RadioEvents_t *events ) +{ + RadioEvents = events; + + SX126xInit( RadioOnDioIrq ); + SX126xSetStandby( STDBY_RC ); + SX126xSetRegulatorMode( USE_DCDC ); +// printf("Lora_Init2\r\n"); + SX126xSetBufferBaseAddress( 0x00, 0x00 ); + +// SX126xReadCommand( RADIO_SET_BUFFERBASEADDRESS, buf, 2 ); + SX126xSetTxParams( 0, RADIO_RAMP_200_US ); + SX126xSetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE ); + + //Initialize driver timeout timers + //TimerInit( &TxTimeoutTimer, RadioOnTxTimeoutIrq ); + //TimerInit( &RxTimeoutTimer, RadioOnRxTimeoutIrq ); + + IrqFired = false; +} + +RadioState_t RadioGetStatus( void ) +{ + switch( SX126xGetOperatingMode( ) ) + { + case MODE_TX: + return RF_TX_RUNNING; + case MODE_RX: + return RF_RX_RUNNING; + case RF_CAD: + return RF_CAD; + default: + return RF_IDLE; + } +} + +void RadioSetModem( RadioModems_t modem ) +{ + switch( modem ) + { + default: + case MODEM_FSK: + SX126xSetPacketType( PACKET_TYPE_GFSK ); + // When switching to GFSK mode the LoRa SyncWord register value is reset + // Thus, we also reset the RadioPublicNetwork variable + RadioPublicNetwork.Current = false; + break; + case MODEM_LORA: + SX126xSetPacketType( PACKET_TYPE_LORA ); + // Public/Private network register is reset when switching modems + if( RadioPublicNetwork.Current != RadioPublicNetwork.Previous ) + { + RadioPublicNetwork.Current = RadioPublicNetwork.Previous; + RadioSetPublicNetwork( RadioPublicNetwork.Current ); + } + break; + } +} + +void RadioSetChannel( uint32_t freq ) +{ + SX126xSetRfFrequency( freq ); +} + +bool RadioIsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime ) +{ + bool status = true; + // int16_t rssi = 0; + // uint32_t carrierSenseTime = 0; + + RadioSetModem( modem ); + + RadioSetChannel( freq ); + + RadioRx( 0 ); + + HAL_Delay_nMS( 1 ); + + //carrierSenseTime = TimerGetCurrentTime( ); + + + //Perform carrier sense for maxCarrierSenseTime +// while( TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime ) +// { +// rssi = RadioRssi( modem ); +// +// if( rssi > rssiThresh ) +// { +// status = false; +// break; +// } +// } + RadioSleep( ); + return status; +} + +uint32_t RadioRandom( void ) +{ + uint8_t i; + uint32_t rnd = 0; + + /* + * Radio setup for random number generation + */ + // Set LoRa modem ON + RadioSetModem( MODEM_LORA ); + + // Set radio in continuous reception + SX126xSetRx( 0 ); + + for( i = 0; i < 32; i++ ) + { + HAL_Delay_nMS( 1 ); + // Unfiltered RSSI value reading. Only takes the LSB value + rnd |= ( ( uint32_t )SX126xGetRssiInst( ) & 0x01 ) << i; + } + + RadioSleep( ); + + return rnd; +} + +void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidthAfc, uint16_t preambleLen, + uint16_t symbTimeout, bool fixLen, + uint8_t payloadLen, + bool crcOn, bool freqHopOn, uint8_t hopPeriod, + bool iqInverted, bool rxContinuous ) +{ + + RxContinuous = rxContinuous; + + if( fixLen == true ) + { + MaxPayloadLength = payloadLen; + } + else + { + MaxPayloadLength = 0xFF; + } + + switch( modem ) + { + case MODEM_FSK: + SX126xSetStopRxTimerOnPreambleDetect( false ); + SX126x.ModulationParams.PacketType = PACKET_TYPE_GFSK; + + SX126x.ModulationParams.Params.Gfsk.BitRate = datarate; + SX126x.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1; + SX126x.ModulationParams.Params.Gfsk.Bandwidth = RadioGetFskBandwidthRegValue( bandwidth ); + + SX126x.PacketParams.PacketType = PACKET_TYPE_GFSK; + SX126x.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit + SX126x.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS; + SX126x.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3; // convert byte into bit + SX126x.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF; + SX126x.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH; + SX126x.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength; + if( crcOn == true ) + { + SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT; + } + else + { + SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF; + } + SX126x.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREE_OFF; + + RadioStandby( ); + RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); + SX126xSetModulationParams( &SX126x.ModulationParams ); + SX126xSetPacketParams( &SX126x.PacketParams ); + SX126xSetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } ); + SX126xSetWhiteningSeed( 0x01FF ); + + RxTimeout = ( uint32_t )( symbTimeout * ( ( 1.0 / ( double )datarate ) * 8.0 ) * 1000 ); + break; + + case MODEM_LORA: + SX126xSetStopRxTimerOnPreambleDetect( false ); + SX126xSetLoRaSymbNumTimeout( symbTimeout ); + SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA; + SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t )datarate; + SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth]; + SX126x.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t )coderate; + + if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || + ( ( bandwidth == 1 ) && ( datarate == 12 ) ) ) + { + SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01; + } + else + { + SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00; + } + + SX126x.PacketParams.PacketType = PACKET_TYPE_LORA; + + if( ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) || + ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) ) + { + if( preambleLen < 12 ) + { + SX126x.PacketParams.Params.LoRa.PreambleLength = 12; + } + else + { + SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; + } + } + else + { + SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; + } + + SX126x.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen; + + SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength; + SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn; + SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted; + + RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); + SX126xSetModulationParams( &SX126x.ModulationParams ); + SX126xSetPacketParams( &SX126x.PacketParams ); + + // Timeout Max, Timeout handled directly in SetRx function + RxTimeout = 0xFFFF; + + break; + } +} + +void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preambleLen, + bool fixLen, bool crcOn, bool freqHopOn, + uint8_t hopPeriod, bool iqInverted, uint32_t timeout ) +{ + + switch( modem ) + { + case MODEM_FSK: + SX126x.ModulationParams.PacketType = PACKET_TYPE_GFSK; + SX126x.ModulationParams.Params.Gfsk.BitRate = datarate; + + SX126x.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1; + SX126x.ModulationParams.Params.Gfsk.Bandwidth = RadioGetFskBandwidthRegValue( bandwidth ); + SX126x.ModulationParams.Params.Gfsk.Fdev = fdev; + + SX126x.PacketParams.PacketType = PACKET_TYPE_GFSK; + SX126x.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit + SX126x.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS; + SX126x.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3 ; // convert byte into bit + SX126x.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF; + SX126x.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH; + + if( crcOn == true ) + { + SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT; + } + else + { + SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF; + } + SX126x.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING; + + RadioStandby( ); + RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); + SX126xSetModulationParams( &SX126x.ModulationParams ); + SX126xSetPacketParams( &SX126x.PacketParams ); + SX126xSetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } ); + SX126xSetWhiteningSeed( 0x01FF ); + break; + + case MODEM_LORA: + SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA; + SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) datarate; + SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth]; + SX126x.ModulationParams.Params.LoRa.CodingRate= ( RadioLoRaCodingRates_t )coderate; + + if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || + ( ( bandwidth == 1 ) && ( datarate == 12 ) ) ) + { + SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01; + } + else + { + SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00; + } + + SX126x.PacketParams.PacketType = PACKET_TYPE_LORA; + + if( ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) || + ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) ) + { + if( preambleLen < 12 ) + { + SX126x.PacketParams.Params.LoRa.PreambleLength = 12; + } + else + { + SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; + } + } + else + { + SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; + } + + SX126x.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen; + SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength; + SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn; + SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted; + + RadioStandby( ); + RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); + SX126xSetModulationParams( &SX126x.ModulationParams ); + SX126xSetPacketParams( &SX126x.PacketParams ); + break; + } + SX126xSetRfTxPower( power ); + TxTimeout = timeout; +} + +bool RadioCheckRfFrequency( uint32_t frequency ) +{ + return true; +} + +uint32_t RadioTimeOnAir( RadioModems_t modem, uint8_t pktLen ) +{ + uint32_t airTime = 0; + + switch( modem ) + { + case MODEM_FSK: + { + airTime = rint( ( 8 * ( SX126x.PacketParams.Params.Gfsk.PreambleLength + + ( SX126x.PacketParams.Params.Gfsk.SyncWordLength >> 3 ) + + ( ( SX126x.PacketParams.Params.Gfsk.HeaderType == RADIO_PACKET_FIXED_LENGTH ) ? 0.0 : 1.0 ) + + pktLen + + ( ( SX126x.PacketParams.Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES ) ? 2.0 : 0 ) ) / + SX126x.ModulationParams.Params.Gfsk.BitRate ) * 1e3 ); + } + break; + case MODEM_LORA: + { + double ts = RadioLoRaSymbTime[SX126x.ModulationParams.Params.LoRa.Bandwidth - 4][12 - SX126x.ModulationParams.Params.LoRa.SpreadingFactor]; + // time of preamble + double tPreamble = ( SX126x.PacketParams.Params.LoRa.PreambleLength + 4.25 ) * ts; + // Symbol length of payload and time + double tmp = ceil( ( 8 * pktLen - 4 * SX126x.ModulationParams.Params.LoRa.SpreadingFactor + + 28 + 16 * SX126x.PacketParams.Params.LoRa.CrcMode - + ( ( SX126x.PacketParams.Params.LoRa.HeaderType == LORA_PACKET_FIXED_LENGTH ) ? 20 : 0 ) ) / + ( double )( 4 * ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor - + ( ( SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) * + ( ( SX126x.ModulationParams.Params.LoRa.CodingRate % 4 ) + 4 ); + double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); + double tPayload = nPayload * ts; + // Time on air + double tOnAir = tPreamble + tPayload; + // return milli seconds + airTime = floor( tOnAir + 0.999 ); + } + break; + } + return airTime; +} + +void RadioSend( uint8_t *buffer, uint8_t size ) +{ + SX126xSetDioIrqParams( IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT, + IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT, + IRQ_RADIO_NONE, + IRQ_RADIO_NONE ); + + if( SX126xGetPacketType( ) == PACKET_TYPE_LORA ) + { + SX126x.PacketParams.Params.LoRa.PayloadLength = size; + } + else + { + SX126x.PacketParams.Params.Gfsk.PayloadLength = size; + } + SX126xSetPacketParams( &SX126x.PacketParams ); + + SX126xSendPayload( buffer, size, 0 ); +// TimerSetValue( &TxTimeoutTimer, TxTimeout ); +// TimerStart( &TxTimeoutTimer ); +} + +void RadioSleep( void ) +{ + SleepParams_t params = { 0 }; + + params.Fields.WarmStart = 1; + SX126xSetSleep( params ); + + HAL_Delay_nMS( 2 ); +} + +void RadioStandby( void ) +{ + SX126xSetStandby( STDBY_RC ); +} + +void RadioRx( uint32_t timeout ) +{ + SX126xSetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, +// IRQ_RX_DONE|IRQ_RX_TX_TIMEOUT, + IRQ_RX_DONE| IRQ_RX_TX_TIMEOUT, + IRQ_RADIO_NONE, + IRQ_RADIO_NONE ); + + + if( RxContinuous == true ) + { + SX126xSetRx( 0xFFFFFF ); // Rx Continuous + } + else + { + SX126xSetRx( timeout << 6 ); + } +} + +void RadioRxBoosted( uint32_t timeout ) +{ + SX126xSetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, + IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, + IRQ_RADIO_NONE, + IRQ_RADIO_NONE ); + + + if( RxContinuous == true ) + { + SX126xSetRxBoosted( 0xFFFFFF ); // Rx Continuous + } + else + { + SX126xSetRxBoosted( timeout << 6 ); + } +} + +void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ) +{ + SX126xSetRxDutyCycle( rxTime, sleepTime ); +} + +void RadioStartCad( void ) +{ + SX126xSetCad( ); +} + +void RadioTx( uint32_t timeout ) +{ + SX126xSetTx( timeout << 6 ); +} + +void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ) +{ + SX126xSetRfFrequency( freq ); + SX126xSetRfTxPower( power ); + SX126xSetTxContinuousWave( ); + +// TimerSetValue( &RxTimeoutTimer, time * 1e3 ); +// TimerStart( &RxTimeoutTimer ); +} + +int16_t RadioRssi( RadioModems_t modem ) +{ + return SX126xGetRssiInst( ); +} + +void RadioWrite( uint16_t addr, uint8_t data ) +{ + SX126xWriteRegister( addr, data ); +} + +uint8_t RadioRead( uint16_t addr ) +{ + return SX126xReadRegister( addr ); +} + +void RadioWriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size ) +{ + SX126xWriteRegisters( addr, buffer, size ); +} + +void RadioReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size ) +{ + SX126xReadRegisters( addr, buffer, size ); +} + +void RadioWriteFifo( uint8_t *buffer, uint8_t size ) +{ + SX126xWriteBuffer( 0, buffer, size ); +} + +void RadioReadFifo( uint8_t *buffer, uint8_t size ) +{ + SX126xReadBuffer( 0, buffer, size ); +} + +void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max ) +{ + if( modem == MODEM_LORA ) + { + SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength = max; + SX126xSetPacketParams( &SX126x.PacketParams ); + } + else + { + if( SX126x.PacketParams.Params.Gfsk.HeaderType == RADIO_PACKET_VARIABLE_LENGTH ) + { + SX126x.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength = max; + SX126xSetPacketParams( &SX126x.PacketParams ); + } + } +} + +void RadioSetPublicNetwork( bool enable ) +{ + RadioPublicNetwork.Current = RadioPublicNetwork.Previous = enable; + + RadioSetModem( MODEM_LORA ); + if( enable == true ) + { + // Change LoRa modem SyncWord + SX126xWriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PUBLIC_SYNCWORD >> 8 ) & 0xFF ); + SX126xWriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PUBLIC_SYNCWORD & 0xFF ); + } + else + { + // Change LoRa modem SyncWord + SX126xWriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF ); + SX126xWriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF ); + } +} + +uint32_t RadioGetWakeupTime( void ) +{ + return( RADIO_TCXO_SETUP_TIME + RADIO_WAKEUP_TIME ); +} + +void RadioOnTxTimeoutIrq( void ) +{ + if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) ) + { + RadioEvents->TxTimeout( ); + } +} + +void RadioOnRxTimeoutIrq( void ) +{ + if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) ) + { + RadioEvents->RxTimeout( ); + } +} + +void RadioOnDioIrq( void ) +{ + IrqFired = true; +} + +void RadioIrqProcess( void ) +{ + // if( IrqFired == true ) + if(gpio_pin_get_val(LORA_IRQ)) + { + IrqFired = false; + + uint16_t irqRegs = SX126xGetIrqStatus( ); + SX126xClearIrqStatus( IRQ_RADIO_ALL ); + + if( ( irqRegs & IRQ_TX_DONE ) == IRQ_TX_DONE ) + { + + if( ( RadioEvents != NULL ) && ( RadioEvents->TxDone != NULL ) ) + { + RadioEvents->TxDone( ); + } + } + + if( ( irqRegs & IRQ_RX_DONE ) == IRQ_RX_DONE ) + { + uint8_t size; + + SX126xGetPayload( RadioRxPayload, &size , 255 ); + SX126xGetPacketStatus( &RadioPktStatus ); + if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) ) + { + RadioEvents->RxDone( RadioRxPayload, size, RadioPktStatus.Params.LoRa.RssiPkt, RadioPktStatus.Params.LoRa.SnrPkt ); + } + } + + if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR ) + { + if( ( RadioEvents != NULL ) && ( RadioEvents->RxError ) ) + { + RadioEvents->RxError( ); + } + } + + if( ( irqRegs & IRQ_CAD_DONE ) == IRQ_CAD_DONE ) + { + if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) ) + { + RadioEvents->CadDone( ( ( irqRegs & IRQ_CAD_ACTIVITY_DETECTED ) == IRQ_CAD_ACTIVITY_DETECTED ) ); + } + } + + if( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT ) + { + if( SX126xGetOperatingMode( ) == MODE_TX ) + { + if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) ) + { + RadioEvents->TxTimeout( ); + } + } + else if( SX126xGetOperatingMode( ) == MODE_RX ) + { + + if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) ) + { + RadioEvents->RxTimeout( ); + } + } + } + + if( ( irqRegs & IRQ_PREAMBLE_DETECTED ) == IRQ_PREAMBLE_DETECTED ) + { + //__NOP( ); + } + + if( ( irqRegs & IRQ_SYNCWORD_VALID ) == IRQ_SYNCWORD_VALID ) + { + //__NOP( ); + } + + if( ( irqRegs & IRQ_HEADER_VALID ) == IRQ_HEADER_VALID ) + { + //__NOP( ); + } + + if( ( irqRegs & IRQ_HEADER_ERROR ) == IRQ_HEADER_ERROR ) + { + if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) ) + { + RadioEvents->RxTimeout( ); + } + } + } +} diff --git a/keil/include/src/Radio/radio.h b/keil/include/src/Radio/radio.h new file mode 100644 index 0000000..eb61f7a --- /dev/null +++ b/keil/include/src/Radio/radio.h @@ -0,0 +1,379 @@ +/*! + * \file radio.h + * + * \brief Radio driver API definition + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + */ +#ifndef __RADIO_H__ +#define __RADIO_H__ + +#include<stdint.h> +#include<stdbool.h> + +//#define USE_MODEM_LORA + +/*! + * Radio driver supported modems + */ +typedef enum +{ + MODEM_FSK = 0, + MODEM_LORA, +}RadioModems_t; + +/*! + * Radio driver internal state machine states definition + */ +typedef enum +{ + RF_IDLE = 0, //!< The radio is idle + RF_RX_RUNNING, //!< The radio is in reception state + RF_TX_RUNNING, //!< The radio is in transmission state + RF_CAD, //!< The radio is doing channel activity detection +}RadioState_t; + +/*! + * \brief Radio driver callback functions + */ +typedef struct +{ + /*! + * \brief Tx Done callback prototype. + */ + void ( *TxDone )( void ); + /*! + * \brief Tx Timeout callback prototype. + */ + void ( *TxTimeout )( void ); + /*! + * \brief Rx Done callback prototype. + * + * \param [IN] payload Received buffer pointer + * \param [IN] size Received buffer size + * \param [IN] rssi RSSI value computed while receiving the frame [dBm] + * \param [IN] snr Raw SNR value given by the radio hardware + * FSK : N/A ( set to 0 ) + * LoRa: SNR value in dB + */ + void ( *RxDone )( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); + /*! + * \brief Rx Timeout callback prototype. + */ + void ( *RxTimeout )( void ); + /*! + * \brief Rx Error callback prototype. + */ + void ( *RxError )( void ); + /*! + * \brief FHSS Change Channel callback prototype. + * + * \param [IN] currentChannel Index number of the current channel + */ + void ( *FhssChangeChannel )( uint8_t currentChannel ); + + /*! + * \brief CAD Done callback prototype. + * + * \param [IN] channelDetected Channel Activity detected during the CAD + */ + void ( *CadDone ) ( bool channelActivityDetected ); +}RadioEvents_t; + +/*! + * \brief Radio driver definition + */ +struct Radio_s +{ + /*! + * \brief Initializes the radio + * + * \param [IN] events Structure containing the driver callback functions + */ + void ( *Init )( RadioEvents_t *events ); + /*! + * Return current radio status + * + * \param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING] + */ + RadioState_t ( *GetStatus )( void ); + /*! + * \brief Configures the radio with the given modem + * + * \param [IN] modem Modem to be used [0: FSK, 1: LoRa] + */ + void ( *SetModem )( RadioModems_t modem ); + /*! + * \brief Sets the channel frequency + * + * \param [IN] freq Channel RF frequency + */ + void ( *SetChannel )( uint32_t freq ); + /*! + * \brief Checks if the channel is free for the given time + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] freq Channel RF frequency + * \param [IN] rssiThresh RSSI threshold + * \param [IN] maxCarrierSenseTime Max time while the RSSI is measured + * + * \retval isFree [true: Channel is free, false: Channel is not free] + */ + bool ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime ); + /*! + * \brief Generates a 32 bits random value based on the RSSI readings + * + * \remark This function sets the radio in LoRa modem mode and disables + * all interrupts. + * After calling this function either Radio.SetRxConfig or + * Radio.SetTxConfig functions must be called. + * + * \retval randomValue 32 bits random value + */ + uint32_t ( *Random )( void ); + /*! + * \brief Sets the reception parameters + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] bandwidth Sets the bandwidth + * FSK : >= 2600 and <= 250000 Hz + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * \param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * \param [IN] coderate Sets the coding rate (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only) + * FSK : >= 2600 and <= 250000 Hz + * LoRa: N/A ( set to 0 ) + * \param [IN] preambleLen Sets the Preamble length + * FSK : Number of bytes + * LoRa: Length in symbols (the hardware adds 4 more symbols) + * \param [IN] symbTimeout Sets the RxSingle timeout value + * FSK : timeout in number of bytes + * LoRa: timeout in symbols + * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * \param [IN] payloadLen Sets payload length when fixed length is used + * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON] + * \param [IN] freqHopOn Enables disables the intra-packet frequency hopping + * FSK : N/A ( set to 0 ) + * LoRa: [0: OFF, 1: ON] + * \param [IN] hopPeriod Number of symbols between each hop + * FSK : N/A ( set to 0 ) + * LoRa: Number of symbols + * \param [IN] iqInverted Inverts IQ signals (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * \param [IN] rxContinuous Sets the reception in continuous mode + * [false: single mode, true: continuous mode] + */ + void ( *SetRxConfig )( RadioModems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidthAfc, uint16_t preambleLen, + uint16_t symbTimeout, bool fixLen, + uint8_t payloadLen, + bool crcOn, bool freqHopOn, uint8_t hopPeriod, + bool iqInverted, bool rxContinuous ); + /*! + * \brief Sets the transmission parameters + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] power Sets the output power [dBm] + * \param [IN] fdev Sets the frequency deviation (FSK only) + * FSK : [Hz] + * LoRa: 0 + * \param [IN] bandwidth Sets the bandwidth (LoRa only) + * FSK : 0 + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * \param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * \param [IN] coderate Sets the coding rate (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * \param [IN] preambleLen Sets the preamble length + * FSK : Number of bytes + * LoRa: Length in symbols (the hardware adds 4 more symbols) + * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * \param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON] + * \param [IN] freqHopOn Enables disables the intra-packet frequency hopping + * FSK : N/A ( set to 0 ) + * LoRa: [0: OFF, 1: ON] + * \param [IN] hopPeriod Number of symbols between each hop + * FSK : N/A ( set to 0 ) + * LoRa: Number of symbols + * \param [IN] iqInverted Inverts IQ signals (LoRa only) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * \param [IN] timeout Transmission timeout [ms] + */ + void ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preambleLen, + bool fixLen, bool crcOn, bool freqHopOn, + uint8_t hopPeriod, bool iqInverted, uint32_t timeout ); + /*! + * \brief Checks if the given RF frequency is supported by the hardware + * + * \param [IN] frequency RF frequency to be checked + * \retval isSupported [true: supported, false: unsupported] + */ + bool ( *CheckRfFrequency )( uint32_t frequency ); + /*! + * \brief Computes the packet time on air in ms for the given payload + * + * \Remark Can only be called once SetRxConfig or SetTxConfig have been called + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] pktLen Packet payload length + * + * \retval airTime Computed airTime (ms) for the given packet payload length + */ + uint32_t ( *TimeOnAir )( RadioModems_t modem, uint8_t pktLen ); + /*! + * \brief Sends the buffer of size. Prepares the packet to be sent and sets + * the radio in transmission + * + * \param [IN]: buffer Buffer pointer + * \param [IN]: size Buffer size + */ + void ( *Send )( uint8_t *buffer, uint8_t size ); + /*! + * \brief Sets the radio in sleep mode + */ + void ( *Sleep )( void ); + /*! + * \brief Sets the radio in standby mode + */ + void ( *Standby )( void ); + /*! + * \brief Sets the radio in reception mode for the given time + * \param [IN] timeout Reception timeout [ms] + * [0: continuous, others timeout] + */ + void ( *Rx )( uint32_t timeout ); + /*! + * \brief Start a Channel Activity Detection + */ + void ( *StartCad )( void ); + /*! + * \brief Sets the radio in continuous wave transmission mode + * + * \param [IN]: freq Channel RF frequency + * \param [IN]: power Sets the output power [dBm] + * \param [IN]: time Transmission mode timeout [s] + */ + void ( *SetTxContinuousWave )( uint32_t freq, int8_t power, uint16_t time ); + /*! + * \brief Reads the current RSSI value + * + * \retval rssiValue Current RSSI value in [dBm] + */ + int16_t ( *Rssi )( RadioModems_t modem ); + /*! + * \brief Writes the radio register at the specified address + * + * \param [IN]: addr Register address + * \param [IN]: data New register value + */ + void ( *Write )( uint16_t addr, uint8_t data ); + /*! + * \brief Reads the radio register at the specified address + * + * \param [IN]: addr Register address + * \retval data Register value + */ + uint8_t ( *Read )( uint16_t addr ); + /*! + * \brief Writes multiple radio registers starting at address + * + * \param [IN] addr First Radio register address + * \param [IN] buffer Buffer containing the new register's values + * \param [IN] size Number of registers to be written + */ + void ( *WriteBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size ); + /*! + * \brief Reads multiple radio registers starting at address + * + * \param [IN] addr First Radio register address + * \param [OUT] buffer Buffer where to copy the registers data + * \param [IN] size Number of registers to be read + */ + void ( *ReadBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size ); + /*! + * \brief Sets the maximum payload length. + * + * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * \param [IN] max Maximum payload length in bytes + */ + void ( *SetMaxPayloadLength )( RadioModems_t modem, uint8_t max ); + /*! + * \brief Sets the network to public or private. Updates the sync byte. + * + * \remark Applies to LoRa modem only + * + * \param [IN] enable if true, it enables a public network + */ + void ( *SetPublicNetwork )( bool enable ); + /*! + * \brief Gets the time required for the board plus radio to get out of sleep.[ms] + * + * \retval time Radio plus board wakeup time in ms. + */ + uint32_t ( *GetWakeupTime )( void ); + /*! + * \brief Process radio irq + */ + void ( *IrqProcess )( void ); + /* + * The next functions are available only on SX126x radios. + */ + /*! + * \brief Sets the radio in reception mode with Max LNA gain for the given time + * + * \remark Available on SX126x radios only. + * + * \param [IN] timeout Reception timeout [ms] + * [0: continuous, others timeout] + */ + void ( *RxBoosted )( uint32_t timeout ); + /*! + * \brief Sets the Rx duty cycle management parameters + * + * \remark Available on SX126x radios only. + * + * \param [in] rxTime Structure describing reception timeout value + * \param [in] sleepTime Structure describing sleep timeout value + */ + void ( *SetRxDutyCycle ) ( uint32_t rxTime, uint32_t sleepTime ); +}; + +/*! + * \brief Radio driver + * + * \remark This variable is defined and initialized in the specific radio + * board implementation + */ +extern const struct Radio_s Radio; + +#endif // __RADIO_H__ diff --git a/keil/include/src/Radio/sx126x-board.c b/keil/include/src/Radio/sx126x-board.c new file mode 100644 index 0000000..f705ee0 --- /dev/null +++ b/keil/include/src/Radio/sx126x-board.c @@ -0,0 +1,264 @@ +/* + ______ _ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + +Description: SX126x driver specific target board functions implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian +*/ +//#include "stm32f0xx.h" +#include "delay.h" +//#include "gpio.h" +//#include "Spi.h" +//#include "spi.h" +#include "radio.h" +#include "sx126x.h" +#include "sx126x-board.h" +#include "lora_1268.h" +#include "PCA9555.h" +//#include "main.h" +//#include "stm32l0xx_hal_spi.h" +#include "mk_spi.h" +//extern SPI_HandleTypeDef hspi1; + + +//void HAL_Delay_nMS( uint32_t Delay ) +//{ +// uint32_t tickstart = 0; +// tickstart = HAL_GetTick( ); +// while( ( HAL_GetTick( ) - tickstart ) < Delay ); +//} +//void SX126x_CS_Di( ) +//{ +// if(!HAL_GPIO_ReadPin( SPIx_CS_GPIO, SPIx_CS)) +// { +// HAL_GPIO_WritePin( SPIx_CS_GPIO, SPIx_CS,GPIO_PIN_SET); +// printf("uwb_cs_error\r\n"); +// } + +//} +void spi_transfer_callback(void *dev, uint32_t err_code) +{ + +} +static void spi_receive_callback(void *dev, uint32_t err_code) +{ + +} +/*! + * @brief Sends txBuffer and receives rxBuffer + * + * @param [IN] txBuffer Byte to be sent + * @param [OUT] rxBuffer Byte to be sent + * @param [IN] size Byte to be sent + */ +uint8_t SpiInOut( uint8_t txBuffer) +{ + uint8_t rxData = 0; + spi_transfer(SPI_ID0, &txBuffer,&rxData, 1, spi_transfer_callback); + return( rxData ); +} + + + +void SX126xReset( void ) +{ + HAL_Delay_nMS( 10 ); +// HAL_GPIO_WritePin( RADIO_nRESET_GPIO_Port, RADIO_nRESET_Pin,GPIO_PIN_RESET); +// gpio_pin_clr(LORA_NRST); + LORA_NRST_DOWN; + delay_us( 2000 ); +// HAL_GPIO_WritePin( RADIO_nRESET_GPIO_Port, RADIO_nRESET_Pin,GPIO_PIN_SET); +// gpio_pin_set(LORA_NRST); + LORA_NRST_UP; + HAL_Delay_nMS( 10 ); +} + +void SX126xWaitOnBusy( void ) +{ +// while(HAL_GPIO_ReadPin(RADIO_BUSY_GPIO_Port,RADIO_BUSY_Pin)==GPIO_PIN_SET); + while(gpio_pin_get_val(LORA_BUSY)==1); +} + + +void SX126xWakeup( void ) +{ + + gpio_pin_clr(LORA_CS); + SpiInOut(RADIO_GET_STATUS); + SpiInOut(0); + + gpio_pin_set(LORA_CS); + // Wait for chip to be ready. + SX126xWaitOnBusy( ); +} + +void SX126xWriteCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size ) +{ + + SX126xCheckDeviceReady( ); + gpio_pin_clr(LORA_CS); + SpiInOut(( uint8_t )command ); + + for( uint16_t i = 0; i < size; i++ ) + { + SpiInOut(buffer[i] ); + } + gpio_pin_set(LORA_CS); + + if( command != RADIO_SET_SLEEP ) + { + SX126xWaitOnBusy( ); + } +} + +void SX126xReadCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size ) +{ + SX126xCheckDeviceReady( ); + gpio_pin_clr(LORA_CS); +// SX126x_CS_Di( ); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_RESET); + + SpiInOut(( uint8_t )command ); + SpiInOut(0x00 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = SpiInOut(0 ); + } + gpio_pin_set(LORA_CS); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_SET); + + SX126xWaitOnBusy( ); +} + +void SX126xWriteRegisters( uint16_t address, uint8_t *buffer, uint16_t size ) +{ + SX126xCheckDeviceReady( ); +// SX126x_CS_Di( ); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_RESET); + gpio_pin_clr(LORA_CS); + SpiInOut(RADIO_WRITE_REGISTER ); + SpiInOut(( address & 0xFF00 ) >> 8 ); + SpiInOut( address & 0x00FF ); + + for( uint16_t i = 0; i < size; i++ ) + { + SpiInOut(buffer[i] ); + } + + gpio_pin_set(LORA_CS); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_SET); + + SX126xWaitOnBusy( ); +} + +void SX126xWriteRegister( uint16_t address, uint8_t value ) +{ + SX126xWriteRegisters( address, &value, 1 ); +} + +void SX126xReadRegisters( uint16_t address, uint8_t *buffer, uint16_t size ) +{ + SX126xCheckDeviceReady( ); +// SX126x_CS_Di( ); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_RESET); + gpio_pin_clr(LORA_CS); + SpiInOut(RADIO_READ_REGISTER ); + SpiInOut(( address & 0xFF00 ) >> 8 ); + SpiInOut( address & 0x00FF ); + SpiInOut( 0 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = SpiInOut(0 ); + } + gpio_pin_set(LORA_CS); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_SET); + + SX126xWaitOnBusy( ); +} + +uint8_t SX126xReadRegister( uint16_t address ) +{ + uint8_t data; + SX126xReadRegisters( address, &data, 1 ); + return data; +} + +void SX126xWriteBuffer( uint8_t offset, uint8_t *buffer, uint8_t size ) +{ + SX126xCheckDeviceReady( ); +// SX126x_CS_Di( ); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_RESET); + gpio_pin_clr(LORA_CS); + SpiInOut( RADIO_WRITE_BUFFER ); + SpiInOut( offset ); + for( uint16_t i = 0; i < size; i++ ) + { + SpiInOut( buffer[i] ); + } + gpio_pin_set(LORA_CS); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_SET); + + SX126xWaitOnBusy( ); +} + +void SX126xReadBuffer( uint8_t offset, uint8_t *buffer, uint8_t size ) +{ + SX126xCheckDeviceReady( ); +// SX126x_CS_Di( ); +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_RESET); + gpio_pin_clr(LORA_CS); + SpiInOut( RADIO_READ_BUFFER ); + SpiInOut( offset ); + SpiInOut( 0 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = SpiInOut( 0 ); + } + +// HAL_GPIO_WritePin( RADIO_NSS_GPIO_Port, RADIO_NSS_Pin,GPIO_PIN_SET); + gpio_pin_set(LORA_CS); + SX126xWaitOnBusy( ); +} + +void SX126xSetRfTxPower( int8_t power ) +{ + SX126xSetTxParams( power, RADIO_RAMP_40_US ); +} + +uint8_t SX126xGetPaSelect( uint32_t channel ) +{ +// if( GpioRead( &DeviceSel ) == 1 ) +// { +// return SX1261; +// } +// else +// { +// return SX1262; +// } + + return SX1262; +} + +void SX126xAntSwOn( void ) +{ + //GpioInit( &AntPow, ANT_SWITCH_POWER, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 ); +} + +void SX126xAntSwOff( void ) +{ + // GpioInit( &AntPow, ANT_SWITCH_POWER, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); +} + +bool SX126xCheckRfFrequency( uint32_t frequency ) +{ + // Implement check. Currently all frequencies are supported + return true; +} diff --git a/keil/include/src/Radio/sx126x-board.h b/keil/include/src/Radio/sx126x-board.h new file mode 100644 index 0000000..8add8d3 --- /dev/null +++ b/keil/include/src/Radio/sx126x-board.h @@ -0,0 +1,132 @@ +/* + ______ _ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + +Description: SX126x driver specific target board functions implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian +*/ +#ifndef __SX126x_ARCH_H__ +#define __SX126x_ARCH_H__ + +#include "sx126x.h" +/*! + * \brief Initializes the radio I/Os pins interface + */ +//void SX126xIoInit( void ); + +/*! + * \brief Initializes DIO IRQ handlers + * + * \param [IN] irqHandlers Array containing the IRQ callback functions + */ +//void SX126xIoIrqInit( DioIrqHandler dioIrq ); + +/*! + * \brief De-initializes the radio I/Os pins interface. + * + * \remark Useful when going in MCU low power modes + */ +//void SX126xIoDeInit( void ); + +/*! + * \brief HW Reset of the radio + */ +void SX126xReset( void ); + +/*! + * \brief Blocking loop to wait while the Busy pin in high + */ +void SX126xWaitOnBusy( void ); + +/*! + * \brief Wakes up the radio + */ +void SX126xWakeup( void ); + +/*! + * \brief Send a command that write data to the radio + * + * \param [in] opcode Opcode of the command + * \param [in] buffer Buffer to be send to the radio + * \param [in] size Size of the buffer to send + */ +void SX126xWriteCommand( RadioCommands_t opcode, uint8_t *buffer, uint16_t size ); + +/*! + * \brief Send a command that read data from the radio + * + * \param [in] opcode Opcode of the command + * \param [out] buffer Buffer holding data from the radio + * \param [in] size Size of the buffer + */ +void SX126xReadCommand( RadioCommands_t opcode, uint8_t *buffer, uint16_t size ); + +/*! + * \brief Write a single byte of data to the radio memory + * + * \param [in] address The address of the first byte to write in the radio + * \param [in] value The data to be written in radio's memory + */ +void SX126xWriteRegister( uint16_t address, uint8_t value ); + +/*! + * \brief Read a single byte of data from the radio memory + * + * \param [in] address The address of the first byte to write in the radio + * + * \retval value The value of the byte at the given address in radio's memory + */ +uint8_t SX126xReadRegister( uint16_t address ); + +/*! + * \brief Sets the radio output power. + * + * \param [IN] power Sets the RF output power + */ +void SX126xSetRfTxPower( int8_t power ); + +/*! + * \brief Gets the board PA selection configuration + * + * \param [IN] channel Channel frequency in Hz + * \retval PaSelect RegPaConfig PaSelect value + */ +uint8_t SX126xGetPaSelect( uint32_t channel ); + +/*! + * \brief Initializes the RF Switch I/Os pins interface + */ +void SX126xAntSwOn( void ); + +/*! + * \brief De-initializes the RF Switch I/Os pins interface + * + * \remark Needed to decrease the power consumption in MCU low power modes + */ +void SX126xAntSwOff( void ); + +/*! + * \brief Checks if the given RF frequency is supported by the hardware + * + * \param [IN] frequency RF frequency to be checked + * \retval isSupported [true: supported, false: unsupported] + */ +bool SX126xCheckRfFrequency( uint32_t frequency ); + +/*! + * Radio hardware and global parameters + */ +extern SX126x_t SX126x; + + +uint8_t SpiInOut( uint8_t txBuffer); + +#endif // __SX126x_ARCH_H__ diff --git a/keil/include/src/Radio/sx126x.c b/keil/include/src/Radio/sx126x.c new file mode 100644 index 0000000..3c375a4 --- /dev/null +++ b/keil/include/src/Radio/sx126x.c @@ -0,0 +1,716 @@ +/*! + * \file sx126x.c + * + * \brief SX126x driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + */ +#include <math.h> +#include <string.h> +#include "sx126x.h" +#include "sx126x-board.h" +#include "delay.h" + +//#define USE_TCXO +/*! + * \brief Radio registers definition + */ +typedef struct +{ + uint16_t Addr; //!< The address of the register + uint8_t Value; //!< The value of the register +}RadioRegisters_t; + +/*! + * \brief Holds the internal operating mode of the radio + */ +static RadioOperatingModes_t OperatingMode; + +/*! + * \brief Stores the current packet type set in the radio + */ +static RadioPacketTypes_t PacketType; + +/*! + * \brief Stores the last frequency error measured on LoRa received packet + */ +volatile uint32_t FrequencyError = 0; + +/*! + * \brief Hold the status of the Image calibration + */ +static bool ImageCalibrated = false; + +/* + * SX126x DIO IRQ callback functions prototype + */ + +/*! + * \brief DIO 0 IRQ callback + */ +void SX126xOnDioIrq( void ); + +/*! + * \brief DIO 0 IRQ callback + */ +void SX126xSetPollingMode( void ); + +/*! + * \brief DIO 0 IRQ callback + */ +void SX126xSetInterruptMode( void ); + +/* + * \brief Process the IRQ if handled by the driver + */ +void SX126xProcessIrqs( void ); + + +void SX126xInit( DioIrqHandler dioIrq ) +{ + SX126xReset( ); + SX126xWakeup( ); + SX126xSetStandby( STDBY_RC ); + +#ifdef USE_TCXO + CalibrationParams_t calibParam; + + SX126xSetDio3AsTcxoCtrl( TCXO_CTRL_1_7V, RADIO_TCXO_SETUP_TIME << 6 ); // convert from ms to SX126x time base + calibParam.Value = 0x7F; + SX126xCalibrate( calibParam ); + +#endif + + SX126xSetDio2AsRfSwitchCtrl( true ); + OperatingMode = MODE_STDBY_RC; +} + +RadioOperatingModes_t SX126xGetOperatingMode( void ) +{ + return OperatingMode; +} + +void SX126xCheckDeviceReady( void ) +{ + if( ( SX126xGetOperatingMode( ) == MODE_SLEEP ) || ( SX126xGetOperatingMode( ) == MODE_RX_DC ) ) + { + SX126xWakeup( ); + // Switch is turned off when device is in sleep mode and turned on is all other modes + SX126xAntSwOn( ); + } + SX126xWaitOnBusy( ); +} + +void SX126xSetPayload( uint8_t *payload, uint8_t size ) +{ + SX126xWriteBuffer( 0x00, payload, size ); +} + +uint8_t SX126xGetPayload( uint8_t *buffer, uint8_t *size, uint8_t maxSize ) +{ + uint8_t offset = 0; + + SX126xGetRxBufferStatus( size, &offset ); + if( *size > maxSize ) + { + return 1; + } + SX126xReadBuffer( offset, buffer, *size ); + return 0; +} + +void SX126xSendPayload( uint8_t *payload, uint8_t size, uint32_t timeout ) +{ + SX126xSetPayload( payload, size ); + SX126xSetTx( timeout ); +} + +uint8_t SX126xSetSyncWord( uint8_t *syncWord ) +{ + SX126xWriteRegisters( REG_LR_SYNCWORDBASEADDRESS, syncWord, 8 ); + return 0; +} + +void SX126xSetCrcSeed( uint16_t seed ) +{ + uint8_t buf[2]; + + buf[0] = ( uint8_t )( ( seed >> 8 ) & 0xFF ); + buf[1] = ( uint8_t )( seed & 0xFF ); + + switch( SX126xGetPacketType( ) ) + { + case PACKET_TYPE_GFSK: + SX126xWriteRegisters( REG_LR_CRCSEEDBASEADDR, buf, 2 ); + break; + + default: + break; + } +} + +void SX126xSetCrcPolynomial( uint16_t polynomial ) +{ + uint8_t buf[2]; + + buf[0] = ( uint8_t )( ( polynomial >> 8 ) & 0xFF ); + buf[1] = ( uint8_t )( polynomial & 0xFF ); + + switch( SX126xGetPacketType( ) ) + { + case PACKET_TYPE_GFSK: + SX126xWriteRegisters( REG_LR_CRCPOLYBASEADDR, buf, 2 ); + break; + + default: + break; + } +} + +void SX126xSetWhiteningSeed( uint16_t seed ) +{ + uint8_t regValue = 0; + + switch( SX126xGetPacketType( ) ) + { + case PACKET_TYPE_GFSK: + regValue = SX126xReadRegister( REG_LR_WHITSEEDBASEADDR_MSB ) & 0xFE; + regValue = ( ( seed >> 8 ) & 0x01 ) | regValue; + SX126xWriteRegister( REG_LR_WHITSEEDBASEADDR_MSB, regValue ); // only 1 bit. + SX126xWriteRegister( REG_LR_WHITSEEDBASEADDR_LSB, ( uint8_t )seed ); + break; + + default: + break; + } +} + +uint32_t SX126xGetRandom( void ) +{ + uint8_t buf[] = { 0, 0, 0, 0 }; + + // Set radio in continuous reception + SX126xSetRx( 0 ); + + HAL_Delay_nMS( 1 ); + + SX126xReadRegisters( RANDOM_NUMBER_GENERATORBASEADDR, buf, 4 ); + + SX126xSetStandby( STDBY_RC ); + + return ( buf[0] << 24 ) | ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3]; +} + +void SX126xSetSleep( SleepParams_t sleepConfig ) +{ + SX126xAntSwOff( ); + + SX126xWriteCommand( RADIO_SET_SLEEP, &sleepConfig.Value, 1 ); + OperatingMode = MODE_SLEEP; +} + +void SX126xSetStandby( RadioStandbyModes_t standbyConfig ) +{ + SX126xWriteCommand( RADIO_SET_STANDBY, ( uint8_t* )&standbyConfig, 1 ); + if( standbyConfig == STDBY_RC ) + { + OperatingMode = MODE_STDBY_RC; + } + else + { + OperatingMode = MODE_STDBY_XOSC; + } +} + +void SX126xSetFs( void ) +{ + SX126xWriteCommand( RADIO_SET_FS, 0, 0 ); + OperatingMode = MODE_FS; +} + +void SX126xSetTx( uint32_t timeout ) +{ + uint8_t buf[3]; + + OperatingMode = MODE_TX; + + buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( timeout & 0xFF ); + SX126xWriteCommand( RADIO_SET_TX, buf, 3 ); +} + +void SX126xSetRx( uint32_t timeout ) +{ + uint8_t buf[3]; + + OperatingMode = MODE_RX; + + buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( timeout & 0xFF ); + SX126xWriteCommand( RADIO_SET_RX, buf, 3 ); +} + +void SX126xSetRxBoosted( uint32_t timeout ) +{ + uint8_t buf[3]; + + OperatingMode = MODE_RX; + + SX126xWriteRegister( REG_RX_GAIN, 0x96 ); // max LNA gain, increase current by ~2mA for around ~3dB in sensivity + + buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( timeout & 0xFF ); + SX126xWriteCommand( RADIO_SET_RX, buf, 3 ); +} + +void SX126xSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ) +{ + uint8_t buf[6]; + + buf[0] = ( uint8_t )( ( rxTime >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( rxTime >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( rxTime & 0xFF ); + buf[3] = ( uint8_t )( ( sleepTime >> 16 ) & 0xFF ); + buf[4] = ( uint8_t )( ( sleepTime >> 8 ) & 0xFF ); + buf[5] = ( uint8_t )( sleepTime & 0xFF ); + SX126xWriteCommand( RADIO_SET_RXDUTYCYCLE, buf, 6 ); + OperatingMode = MODE_RX_DC; +} + +void SX126xSetCad( void ) +{ + SX126xWriteCommand( RADIO_SET_CAD, 0, 0 ); + OperatingMode = MODE_CAD; +} + +void SX126xSetTxContinuousWave( void ) +{ + SX126xWriteCommand( RADIO_SET_TXCONTINUOUSWAVE, 0, 0 ); +} + +void SX126xSetTxInfinitePreamble( void ) +{ + SX126xWriteCommand( RADIO_SET_TXCONTINUOUSPREAMBLE, 0, 0 ); +} + +void SX126xSetStopRxTimerOnPreambleDetect( bool enable ) +{ + SX126xWriteCommand( RADIO_SET_STOPRXTIMERONPREAMBLE, ( uint8_t* )&enable, 1 ); +} + +void SX126xSetLoRaSymbNumTimeout( uint8_t SymbNum ) +{ + SX126xWriteCommand( RADIO_SET_LORASYMBTIMEOUT, &SymbNum, 1 ); +} + +void SX126xSetRegulatorMode( RadioRegulatorMode_t mode ) +{ + SX126xWriteCommand( RADIO_SET_REGULATORMODE, ( uint8_t* )&mode, 1 ); +} + +void SX126xCalibrate( CalibrationParams_t calibParam ) +{ + SX126xWriteCommand( RADIO_CALIBRATE, ( uint8_t* )&calibParam, 1 ); +} + +void SX126xCalibrateImage( uint32_t freq ) +{ + uint8_t calFreq[2]; + + if( freq > 900000000 ) + { + calFreq[0] = 0xE1; + calFreq[1] = 0xE9; + } + else if( freq > 850000000 ) + { + calFreq[0] = 0xD7; + calFreq[1] = 0xD8; + } + else if( freq > 770000000 ) + { + calFreq[0] = 0xC1; + calFreq[1] = 0xC5; + } + else if( freq > 460000000 ) + { + calFreq[0] = 0x75; + calFreq[1] = 0x81; + } + else if( freq > 425000000 ) + { + calFreq[0] = 0x6B; + calFreq[1] = 0x6F; + } + SX126xWriteCommand( RADIO_CALIBRATEIMAGE, calFreq, 2 ); +} + +void SX126xSetPaConfig( uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut ) +{ + uint8_t buf[4]; + + buf[0] = paDutyCycle; + buf[1] = hpMax; + buf[2] = deviceSel; + buf[3] = paLut; + SX126xWriteCommand( RADIO_SET_PACONFIG, buf, 4 ); +} + +void SX126xSetRxTxFallbackMode( uint8_t fallbackMode ) +{ + SX126xWriteCommand( RADIO_SET_TXFALLBACKMODE, &fallbackMode, 1 ); +} + +void SX126xSetDioIrqParams( uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask ) +{ + uint8_t buf[8]; + + buf[0] = ( uint8_t )( ( irqMask >> 8 ) & 0x00FF ); + buf[1] = ( uint8_t )( irqMask & 0x00FF ); + buf[2] = ( uint8_t )( ( dio1Mask >> 8 ) & 0x00FF ); + buf[3] = ( uint8_t )( dio1Mask & 0x00FF ); + buf[4] = ( uint8_t )( ( dio2Mask >> 8 ) & 0x00FF ); + buf[5] = ( uint8_t )( dio2Mask & 0x00FF ); + buf[6] = ( uint8_t )( ( dio3Mask >> 8 ) & 0x00FF ); + buf[7] = ( uint8_t )( dio3Mask & 0x00FF ); + SX126xWriteCommand( RADIO_CFG_DIOIRQ, buf, 8 ); +} + +uint16_t SX126xGetIrqStatus( void ) +{ + uint8_t irqStatus[2]; + + SX126xReadCommand( RADIO_GET_IRQSTATUS, irqStatus, 2 ); + return ( irqStatus[0] << 8 ) | irqStatus[1]; +} + +void SX126xSetDio2AsRfSwitchCtrl( uint8_t enable ) +{ + SX126xWriteCommand( RADIO_SET_RFSWITCHMODE, &enable, 1 ); +} + +void SX126xSetDio3AsTcxoCtrl( RadioTcxoCtrlVoltage_t tcxoVoltage, uint32_t timeout ) +{ + uint8_t buf[4]; + + buf[0] = tcxoVoltage & 0x07; + buf[1] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[2] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[3] = ( uint8_t )( timeout & 0xFF ); + + SX126xWriteCommand( RADIO_SET_TCXOMODE, buf, 4 ); +} + +void SX126xSetRfFrequency( uint32_t frequency ) +{ + uint8_t buf[4]; + uint32_t freq = 0; + + if( ImageCalibrated == false ) + { + SX126xCalibrateImage( frequency ); + ImageCalibrated = true; + } + + freq = ( uint32_t )( ( double )frequency / ( double )FREQ_STEP ); + buf[0] = ( uint8_t )( ( freq >> 24 ) & 0xFF ); + buf[1] = ( uint8_t )( ( freq >> 16 ) & 0xFF ); + buf[2] = ( uint8_t )( ( freq >> 8 ) & 0xFF ); + buf[3] = ( uint8_t )( freq & 0xFF ); + SX126xWriteCommand( RADIO_SET_RFFREQUENCY, buf, 4 ); +} + +void SX126xSetPacketType( RadioPacketTypes_t packetType ) +{ + // Save packet type internally to avoid questioning the radio + PacketType = packetType; + SX126xWriteCommand( RADIO_SET_PACKETTYPE, ( uint8_t* )&packetType, 1 ); +} + +RadioPacketTypes_t SX126xGetPacketType( void ) +{ + return PacketType; +} + +void SX126xSetTxParams( int8_t power, RadioRampTimes_t rampTime ) +{ + uint8_t buf[2]; + + if( SX126xGetPaSelect( 0 ) == SX1261 ) + { + if( power == 15 ) + { + SX126xSetPaConfig( 0x06, 0x00, 0x01, 0x01 ); + } + else + { + SX126xSetPaConfig( 0x04, 0x00, 0x01, 0x01 ); + } + if( power >= 14 ) + { + power = 14; + } + else if( power < -3 ) + { + power = -3; + } + SX126xWriteRegister( REG_OCP, 0x18 ); // current max is 80 mA for the whole device + } + else // sx1262 + { + SX126xSetPaConfig( 0x04, 0x07, 0x00, 0x01 ); + if( power > 22 ) + { + power = 22; + } + else if( power < -3 ) + { + power = -3; + } + SX126xWriteRegister( REG_OCP, 0x38 ); // current max 160mA for the whole device + } + buf[0] = power; + buf[1] = ( uint8_t )rampTime; + SX126xWriteCommand( RADIO_SET_TXPARAMS, buf, 2 ); +} + +void SX126xSetModulationParams( ModulationParams_t *modulationParams ) +{ + uint8_t n; + uint32_t tempVal = 0; + uint8_t buf[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // Check if required configuration corresponds to the stored packet type + // If not, silently update radio packet type + if( PacketType != modulationParams->PacketType ) + { + SX126xSetPacketType( modulationParams->PacketType ); + } + + switch( modulationParams->PacketType ) + { + case PACKET_TYPE_GFSK: + n = 8; + tempVal = ( uint32_t )( 32 * ( ( double )XTAL_FREQ / ( double )modulationParams->Params.Gfsk.BitRate ) ); + buf[0] = ( tempVal >> 16 ) & 0xFF; + buf[1] = ( tempVal >> 8 ) & 0xFF; + buf[2] = tempVal & 0xFF; + buf[3] = modulationParams->Params.Gfsk.ModulationShaping; + buf[4] = modulationParams->Params.Gfsk.Bandwidth; + tempVal = ( uint32_t )( ( double )modulationParams->Params.Gfsk.Fdev / ( double )FREQ_STEP ); + buf[5] = ( tempVal >> 16 ) & 0xFF; + buf[6] = ( tempVal >> 8 ) & 0xFF; + buf[7] = ( tempVal& 0xFF ); + SX126xWriteCommand( RADIO_SET_MODULATIONPARAMS, buf, n ); + break; + case PACKET_TYPE_LORA: + n = 4; + buf[0] = modulationParams->Params.LoRa.SpreadingFactor; + buf[1] = modulationParams->Params.LoRa.Bandwidth; + buf[2] = modulationParams->Params.LoRa.CodingRate; + buf[3] = modulationParams->Params.LoRa.LowDatarateOptimize; + + SX126xWriteCommand( RADIO_SET_MODULATIONPARAMS, buf, n ); + + break; + default: + case PACKET_TYPE_NONE: + return; + } +} + +void SX126xSetPacketParams( PacketParams_t *packetParams ) +{ + uint8_t n; + uint8_t crcVal = 0; + uint8_t buf[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // Check if required configuration corresponds to the stored packet type + // If not, silently update radio packet type + if( PacketType != packetParams->PacketType ) + { + SX126xSetPacketType( packetParams->PacketType ); + } + + switch( packetParams->PacketType ) + { + case PACKET_TYPE_GFSK: + if( packetParams->Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES_IBM ) + { + SX126xSetCrcSeed( CRC_IBM_SEED ); + SX126xSetCrcPolynomial( CRC_POLYNOMIAL_IBM ); + crcVal = RADIO_CRC_2_BYTES; + } + else if( packetParams->Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES_CCIT ) + { + SX126xSetCrcSeed( CRC_CCITT_SEED ); + SX126xSetCrcPolynomial( CRC_POLYNOMIAL_CCITT ); + crcVal = RADIO_CRC_2_BYTES_INV; + } + else + { + crcVal = packetParams->Params.Gfsk.CrcLength; + } + n = 9; + buf[0] = ( packetParams->Params.Gfsk.PreambleLength >> 8 ) & 0xFF; + buf[1] = packetParams->Params.Gfsk.PreambleLength; + buf[2] = packetParams->Params.Gfsk.PreambleMinDetect; + buf[3] = ( packetParams->Params.Gfsk.SyncWordLength /*<< 3*/ ); // convert from byte to bit + buf[4] = packetParams->Params.Gfsk.AddrComp; + buf[5] = packetParams->Params.Gfsk.HeaderType; + buf[6] = packetParams->Params.Gfsk.PayloadLength; + buf[7] = crcVal; + buf[8] = packetParams->Params.Gfsk.DcFree; + break; + case PACKET_TYPE_LORA: + n = 6; + buf[0] = ( packetParams->Params.LoRa.PreambleLength >> 8 ) & 0xFF; + buf[1] = packetParams->Params.LoRa.PreambleLength; + buf[2] = packetParams->Params.LoRa.HeaderType; + buf[3] = packetParams->Params.LoRa.PayloadLength; + buf[4] = packetParams->Params.LoRa.CrcMode; + buf[5] = packetParams->Params.LoRa.InvertIQ; + break; + default: + case PACKET_TYPE_NONE: + return; + } + SX126xWriteCommand( RADIO_SET_PACKETPARAMS, buf, n ); +} + +void SX126xSetCadParams( RadioLoRaCadSymbols_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, RadioCadExitModes_t cadExitMode, uint32_t cadTimeout ) +{ + uint8_t buf[7]; + + buf[0] = ( uint8_t )cadSymbolNum; + buf[1] = cadDetPeak; + buf[2] = cadDetMin; + buf[3] = ( uint8_t )cadExitMode; + buf[4] = ( uint8_t )( ( cadTimeout >> 16 ) & 0xFF ); + buf[5] = ( uint8_t )( ( cadTimeout >> 8 ) & 0xFF ); + buf[6] = ( uint8_t )( cadTimeout & 0xFF ); + SX126xWriteCommand( RADIO_SET_CADPARAMS, buf, 5 ); + OperatingMode = MODE_CAD; +} + +void SX126xSetBufferBaseAddress( uint8_t txBaseAddress, uint8_t rxBaseAddress ) +{ + uint8_t buf[2]; + + buf[0] = txBaseAddress; + buf[1] = rxBaseAddress; + SX126xWriteCommand( RADIO_SET_BUFFERBASEADDRESS, buf, 2 ); +} + +RadioStatus_t SX126xGetStatus( void ) +{ + uint8_t stat = 0; + RadioStatus_t status; + + SX126xReadCommand( RADIO_GET_STATUS, ( uint8_t * )&stat, 1 ); + status.Value = stat; + return status; +} + +int8_t SX126xGetRssiInst( void ) +{ + uint8_t buf[1]; + int8_t rssi = 0; + + SX126xReadCommand( RADIO_GET_RSSIINST, buf, 1 ); + rssi = -buf[0] >> 1; + return rssi; +} + +void SX126xGetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBufferPointer ) +{ + uint8_t status[2]; + + SX126xReadCommand( RADIO_GET_RXBUFFERSTATUS, status, 2 ); + + // In case of LORA fixed header, the payloadLength is obtained by reading + // the register REG_LR_PAYLOADLENGTH + if( ( SX126xGetPacketType( ) == PACKET_TYPE_LORA ) && ( SX126xReadRegister( REG_LR_PACKETPARAMS ) >> 7 == 1 ) ) + { + *payloadLength = SX126xReadRegister( REG_LR_PAYLOADLENGTH ); + } + else + { + *payloadLength = status[0]; + } + *rxStartBufferPointer = status[1]; +} + +void SX126xGetPacketStatus( PacketStatus_t *pktStatus ) +{ + uint8_t status[3]; + + SX126xReadCommand( RADIO_GET_PACKETSTATUS, status, 3 ); + + pktStatus->packetType = SX126xGetPacketType( ); + switch( pktStatus->packetType ) + { + case PACKET_TYPE_GFSK: + pktStatus->Params.Gfsk.RxStatus = status[0]; + pktStatus->Params.Gfsk.RssiSync = -status[1] >> 1; + pktStatus->Params.Gfsk.RssiAvg = -status[2] >> 1; + pktStatus->Params.Gfsk.FreqError = 0; + break; + + case PACKET_TYPE_LORA: + pktStatus->Params.LoRa.RssiPkt = -status[0] >> 1; + ( status[1] < 128 ) ? ( pktStatus->Params.LoRa.SnrPkt = status[1] >> 2 ) : ( pktStatus->Params.LoRa.SnrPkt = ( ( status[1] - 256 ) >> 2 ) ); + pktStatus->Params.LoRa.SignalRssiPkt = -status[2] >> 1; + pktStatus->Params.LoRa.FreqError = FrequencyError; + break; + + default: + case PACKET_TYPE_NONE: + // In that specific case, we set everything in the pktStatus to zeros + // and reset the packet type accordingly + memset( pktStatus, 0, sizeof( PacketStatus_t ) ); + pktStatus->packetType = PACKET_TYPE_NONE; + break; + } +} + +RadioError_t SX126xGetDeviceErrors( void ) +{ + RadioError_t error; + + SX126xReadCommand( RADIO_GET_ERROR, ( uint8_t * )&error, 2 ); + return error; +} + +void SX126xClearDeviceErrors( void ) +{ + uint8_t buf[2] = { 0x00, 0x00 }; + SX126xWriteCommand( RADIO_CLR_ERROR, buf, 2 ); +} + +void SX126xClearIrqStatus( uint16_t irq ) +{ + uint8_t buf[2]; + + buf[0] = ( uint8_t )( ( ( uint16_t )irq >> 8 ) & 0x00FF ); + buf[1] = ( uint8_t )( ( uint16_t )irq & 0x00FF ); + SX126xWriteCommand( RADIO_CLR_IRQSTATUS, buf, 2 ); +} diff --git a/keil/include/src/Radio/sx126x.h b/keil/include/src/Radio/sx126x.h new file mode 100644 index 0000000..6defe61 --- /dev/null +++ b/keil/include/src/Radio/sx126x.h @@ -0,0 +1,1115 @@ +/*! + * \file sx126x.h + * + * \brief SX126x driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + */ +#ifndef __SX126x_H__ +#define __SX126x_H__ + +#include <stdint.h> +#include <stdbool.h> + + +#define SX1261 1 +#define SX1262 2 + +#ifdef USE_TCXO + /*! + * Radio complete Wake-up Time with TCXO stabilisation time + */ + #define RADIO_TCXO_SETUP_TIME 5 // [ms] +#else + /*! + * Radio complete Wake-up Time with TCXO stabilisation time + */ + #define RADIO_TCXO_SETUP_TIME 0 // No Used +#endif + +/*! + * Radio complete Wake-up Time with margin for temperature compensation + */ +#define RADIO_WAKEUP_TIME 3 // [ms] + +/*! + * \brief Compensation delay for SetAutoTx/Rx functions in 15.625 microseconds + */ +#define AUTO_RX_TX_OFFSET 2 + +/*! + * \brief LFSR initial value to compute IBM type CRC + */ +#define CRC_IBM_SEED 0xFFFF + +/*! + * \brief LFSR initial value to compute CCIT type CRC + */ +#define CRC_CCITT_SEED 0x1D0F + +/*! + * \brief Polynomial used to compute IBM CRC + */ +#define CRC_POLYNOMIAL_IBM 0x8005 + +/*! + * \brief Polynomial used to compute CCIT CRC + */ +#define CRC_POLYNOMIAL_CCITT 0x1021 + +/*! + * \brief The address of the register holding the first byte defining the CRC seed + * + */ +#define REG_LR_CRCSEEDBASEADDR 0x06BC + +/*! + * \brief The address of the register holding the first byte defining the CRC polynomial + */ +#define REG_LR_CRCPOLYBASEADDR 0x06BE + +/*! + * \brief The address of the register holding the first byte defining the whitening seed + */ +#define REG_LR_WHITSEEDBASEADDR_MSB 0x06B8 +#define REG_LR_WHITSEEDBASEADDR_LSB 0x06B9 + +/*! + * \brief The address of the register holding the packet configuration + */ +#define REG_LR_PACKETPARAMS 0x0704 + +/*! + * \brief The address of the register holding the payload size + */ +#define REG_LR_PAYLOADLENGTH 0x0702 + +/*! + * \brief The addresses of the registers holding SyncWords values + */ +#define REG_LR_SYNCWORDBASEADDRESS 0x06C0 + +/*! + * \brief The addresses of the register holding LoRa Modem SyncWord value + */ +#define REG_LR_SYNCWORD 0x0740 + +/*! + * Syncword for Private LoRa networks + */ +#define LORA_MAC_PRIVATE_SYNCWORD 0x1424 + +/*! + * Syncword for Public LoRa networks + */ +#define LORA_MAC_PUBLIC_SYNCWORD 0x3444 + +/*! + * The address of the register giving a 4 bytes random number + */ +#define RANDOM_NUMBER_GENERATORBASEADDR 0x0819 + +/*! + * The address of the register holding RX Gain value (0x94: power saving, 0x96: rx boosted) + */ +#define REG_RX_GAIN 0x08AC + +/*! + * Change the value on the device internal trimming capacitor + */ +#define REG_XTA_TRIM 0x0911 + +/*! + * Set the current max value in the over current protection + */ +#define REG_OCP 0x08E7 + +/*! + * \brief Structure describing the radio status + */ +typedef union RadioStatus_u +{ + uint8_t Value; + struct + { //bit order is lsb -> msb + uint8_t Reserved : 1; //!< Reserved + uint8_t CmdStatus : 3; //!< Command status + uint8_t ChipMode : 3; //!< Chip mode + uint8_t CpuBusy : 1; //!< Flag for CPU radio busy + }Fields; +}RadioStatus_t; + +/*! + * \brief Structure describing the error codes for callback functions + */ +typedef enum +{ + IRQ_HEADER_ERROR_CODE = 0x01, + IRQ_SYNCWORD_ERROR_CODE = 0x02, + IRQ_CRC_ERROR_CODE = 0x04, +}IrqErrorCode_t; + +enum IrqPblSyncHeaderCode_t +{ + IRQ_PBL_DETECT_CODE = 0x01, + IRQ_SYNCWORD_VALID_CODE = 0x02, + IRQ_HEADER_VALID_CODE = 0x04, +}; + +/*! + * \brief Represents the operating mode the radio is actually running + */ +typedef enum +{ + MODE_SLEEP = 0x00, //! The radio is in sleep mode + MODE_STDBY_RC, //! The radio is in standby mode with RC oscillator + MODE_STDBY_XOSC, //! The radio is in standby mode with XOSC oscillator + MODE_FS, //! The radio is in frequency synthesis mode + MODE_TX, //! The radio is in transmit mode + MODE_RX, //! The radio is in receive mode + MODE_RX_DC, //! The radio is in receive duty cycle mode + MODE_CAD //! The radio is in channel activity detection mode +}RadioOperatingModes_t; + +/*! + * \brief Declares the oscillator in use while in standby mode + * + * Using the STDBY_RC standby mode allow to reduce the energy consumption + * STDBY_XOSC should be used for time critical applications + */ +typedef enum +{ + STDBY_RC = 0x00, + STDBY_XOSC = 0x01, +}RadioStandbyModes_t; + +/*! + * \brief Declares the power regulation used to power the device + * + * This command allows the user to specify if DC-DC or LDO is used for power regulation. + * Using only LDO implies that the Rx or Tx current is doubled + */ +typedef enum +{ + USE_LDO = 0x00, // default + USE_DCDC = 0x01, +}RadioRegulatorMode_t; + +/*! + * \brief Represents the possible packet type (i.e. modem) used + */ +typedef enum +{ + PACKET_TYPE_GFSK = 0x00, + PACKET_TYPE_LORA = 0x01, + PACKET_TYPE_NONE = 0x0F, +}RadioPacketTypes_t; + +/*! + * \brief Represents the ramping time for power amplifier + */ +typedef enum +{ + RADIO_RAMP_10_US = 0x00, + RADIO_RAMP_20_US = 0x01, + RADIO_RAMP_40_US = 0x02, + RADIO_RAMP_80_US = 0x03, + RADIO_RAMP_200_US = 0x04, + RADIO_RAMP_800_US = 0x05, + RADIO_RAMP_1700_US = 0x06, + RADIO_RAMP_3400_US = 0x07, +}RadioRampTimes_t; + +/*! + * \brief Represents the number of symbols to be used for channel activity detection operation + */ +typedef enum +{ + LORA_CAD_01_SYMBOL = 0x00, + LORA_CAD_02_SYMBOL = 0x01, + LORA_CAD_04_SYMBOL = 0x02, + LORA_CAD_08_SYMBOL = 0x03, + LORA_CAD_16_SYMBOL = 0x04, +}RadioLoRaCadSymbols_t; + +/*! + * \brief Represents the Channel Activity Detection actions after the CAD operation is finished + */ +typedef enum +{ + LORA_CAD_ONLY = 0x00, + LORA_CAD_RX = 0x01, + LORA_CAD_LBT = 0x10, +}RadioCadExitModes_t; + +/*! + * \brief Represents the modulation shaping parameter + */ +typedef enum +{ + MOD_SHAPING_OFF = 0x00, + MOD_SHAPING_G_BT_03 = 0x08, + MOD_SHAPING_G_BT_05 = 0x09, + MOD_SHAPING_G_BT_07 = 0x0A, + MOD_SHAPING_G_BT_1 = 0x0B, +}RadioModShapings_t; + +/*! + * \brief Represents the modulation shaping parameter + */ +typedef enum +{ + RX_BW_4800 = 0x1F, + RX_BW_5800 = 0x17, + RX_BW_7300 = 0x0F, + RX_BW_9700 = 0x1E, + RX_BW_11700 = 0x16, + RX_BW_14600 = 0x0E, + RX_BW_19500 = 0x1D, + RX_BW_23400 = 0x15, + RX_BW_29300 = 0x0D, + RX_BW_39000 = 0x1C, + RX_BW_46900 = 0x14, + RX_BW_58600 = 0x0C, + RX_BW_78200 = 0x1B, + RX_BW_93800 = 0x13, + RX_BW_117300 = 0x0B, + RX_BW_156200 = 0x1A, + RX_BW_187200 = 0x12, + RX_BW_234300 = 0x0A, + RX_BW_312000 = 0x19, + RX_BW_373600 = 0x11, + RX_BW_467000 = 0x09, +}RadioRxBandwidth_t; + +/*! + * \brief Represents the possible spreading factor values in LoRa packet types + */ +typedef enum +{ + LORA_SF5 = 0x05, + LORA_SF6 = 0x06, + LORA_SF7 = 0x07, + LORA_SF8 = 0x08, + LORA_SF9 = 0x09, + LORA_SF10 = 0x0A, + LORA_SF11 = 0x0B, + LORA_SF12 = 0x0C, +}RadioLoRaSpreadingFactors_t; + +/*! + * \brief Represents the bandwidth values for LoRa packet type + */ +typedef enum +{ + LORA_BW_500 = 6, + LORA_BW_250 = 5, + LORA_BW_125 = 4, + LORA_BW_062 = 3, + LORA_BW_041 = 10, + LORA_BW_031 = 2, + LORA_BW_020 = 9, + LORA_BW_015 = 1, + LORA_BW_010 = 8, + LORA_BW_007 = 0, +}RadioLoRaBandwidths_t; + +/*! + * \brief Represents the coding rate values for LoRa packet type + */ +typedef enum +{ + LORA_CR_4_5 = 0x01, + LORA_CR_4_6 = 0x02, + LORA_CR_4_7 = 0x03, + LORA_CR_4_8 = 0x04, +}RadioLoRaCodingRates_t; + +/*! + * \brief Represents the preamble length used to detect the packet on Rx side + */ +typedef enum +{ + RADIO_PREAMBLE_DETECTOR_OFF = 0x00, //!< Preamble detection length off + RADIO_PREAMBLE_DETECTOR_08_BITS = 0x04, //!< Preamble detection length 8 bits + RADIO_PREAMBLE_DETECTOR_16_BITS = 0x05, //!< Preamble detection length 16 bits + RADIO_PREAMBLE_DETECTOR_24_BITS = 0x06, //!< Preamble detection length 24 bits + RADIO_PREAMBLE_DETECTOR_32_BITS = 0x07, //!< Preamble detection length 32 bit +}RadioPreambleDetection_t; + +/*! + * \brief Represents the possible combinations of SyncWord correlators activated + */ +typedef enum +{ + RADIO_ADDRESSCOMP_FILT_OFF = 0x00, //!< No correlator turned on, i.e. do not search for SyncWord + RADIO_ADDRESSCOMP_FILT_NODE = 0x01, + RADIO_ADDRESSCOMP_FILT_NODE_BROAD = 0x02, +}RadioAddressComp_t; + +/*! + * \brief Radio GFSK packet length mode + */ +typedef enum +{ + RADIO_PACKET_FIXED_LENGTH = 0x00, //!< The packet is known on both sides, no header included in the packet + RADIO_PACKET_VARIABLE_LENGTH = 0x01, //!< The packet is on variable size, header included +}RadioPacketLengthModes_t; + +/*! + * \brief Represents the CRC length + */ +typedef enum +{ + RADIO_CRC_OFF = 0x01, //!< No CRC in use + RADIO_CRC_1_BYTES = 0x00, + RADIO_CRC_2_BYTES = 0x02, + RADIO_CRC_1_BYTES_INV = 0x04, + RADIO_CRC_2_BYTES_INV = 0x06, + RADIO_CRC_2_BYTES_IBM = 0xF1, + RADIO_CRC_2_BYTES_CCIT = 0xF2, +}RadioCrcTypes_t; + +/*! + * \brief Radio whitening mode activated or deactivated + */ +typedef enum +{ + RADIO_DC_FREE_OFF = 0x00, + RADIO_DC_FREEWHITENING = 0x01, +}RadioDcFree_t; + +/*! + * \brief Holds the Radio lengths mode for the LoRa packet type + */ +typedef enum +{ + LORA_PACKET_VARIABLE_LENGTH = 0x00, //!< The packet is on variable size, header included + LORA_PACKET_FIXED_LENGTH = 0x01, //!< The packet is known on both sides, no header included in the packet + LORA_PACKET_EXPLICIT = LORA_PACKET_VARIABLE_LENGTH, + LORA_PACKET_IMPLICIT = LORA_PACKET_FIXED_LENGTH, +}RadioLoRaPacketLengthsMode_t; + +/*! + * \brief Represents the CRC mode for LoRa packet type + */ +typedef enum +{ + LORA_CRC_ON = 0x01, //!< CRC activated + LORA_CRC_OFF = 0x00, //!< CRC not used +}RadioLoRaCrcModes_t; + +/*! + * \brief Represents the IQ mode for LoRa packet type + */ +typedef enum +{ + LORA_IQ_NORMAL = 0x00, + LORA_IQ_INVERTED = 0x01, +}RadioLoRaIQModes_t; + +/*! + * \brief Represents the voltage used to control the TCXO on/off from DIO3 + */ +typedef enum +{ + TCXO_CTRL_1_6V = 0x00, + TCXO_CTRL_1_7V = 0x01, + TCXO_CTRL_1_8V = 0x02, + TCXO_CTRL_2_2V = 0x03, + TCXO_CTRL_2_4V = 0x04, + TCXO_CTRL_2_7V = 0x05, + TCXO_CTRL_3_0V = 0x06, + TCXO_CTRL_3_3V = 0x07, +}RadioTcxoCtrlVoltage_t; + +/*! + * \brief Represents the interruption masks available for the radio + * + * \remark Note that not all these interruptions are available for all packet types + */ +typedef enum +{ + IRQ_RADIO_NONE = 0x0000, + IRQ_TX_DONE = 0x0001, + IRQ_RX_DONE = 0x0002, + IRQ_PREAMBLE_DETECTED = 0x0004, + IRQ_SYNCWORD_VALID = 0x0008, + IRQ_HEADER_VALID = 0x0010, + IRQ_HEADER_ERROR = 0x0020, + IRQ_CRC_ERROR = 0x0040, + IRQ_CAD_DONE = 0x0080, + IRQ_CAD_ACTIVITY_DETECTED = 0x0100, + IRQ_RX_TX_TIMEOUT = 0x0200, + IRQ_RADIO_ALL = 0xFFFF, +}RadioIrqMasks_t; + +/*! + * \brief Represents all possible opcode understood by the radio + */ +typedef enum RadioCommands_e +{ + RADIO_GET_STATUS = 0xC0, + RADIO_WRITE_REGISTER = 0x0D, + RADIO_READ_REGISTER = 0x1D, + RADIO_WRITE_BUFFER = 0x0E, + RADIO_READ_BUFFER = 0x1E, + RADIO_SET_SLEEP = 0x84, + RADIO_SET_STANDBY = 0x80, + RADIO_SET_FS = 0xC1, + RADIO_SET_TX = 0x83, + RADIO_SET_RX = 0x82, + RADIO_SET_RXDUTYCYCLE = 0x94, + RADIO_SET_CAD = 0xC5, + RADIO_SET_TXCONTINUOUSWAVE = 0xD1, + RADIO_SET_TXCONTINUOUSPREAMBLE = 0xD2, + RADIO_SET_PACKETTYPE = 0x8A, + RADIO_GET_PACKETTYPE = 0x11, + RADIO_SET_RFFREQUENCY = 0x86, + RADIO_SET_TXPARAMS = 0x8E, + RADIO_SET_PACONFIG = 0x95, + RADIO_SET_CADPARAMS = 0x88, + RADIO_SET_BUFFERBASEADDRESS = 0x8F, + RADIO_SET_MODULATIONPARAMS = 0x8B, + RADIO_SET_PACKETPARAMS = 0x8C, + RADIO_GET_RXBUFFERSTATUS = 0x13, + RADIO_GET_PACKETSTATUS = 0x14, + RADIO_GET_RSSIINST = 0x15, + RADIO_GET_STATS = 0x10, + RADIO_RESET_STATS = 0x00, + RADIO_CFG_DIOIRQ = 0x08, + RADIO_GET_IRQSTATUS = 0x12, + RADIO_CLR_IRQSTATUS = 0x02, + RADIO_CALIBRATE = 0x89, + RADIO_CALIBRATEIMAGE = 0x98, + RADIO_SET_REGULATORMODE = 0x96, + RADIO_GET_ERROR = 0x17, + RADIO_CLR_ERROR = 0x07, + RADIO_SET_TCXOMODE = 0x97, + RADIO_SET_TXFALLBACKMODE = 0x93, + RADIO_SET_RFSWITCHMODE = 0x9D, + RADIO_SET_STOPRXTIMERONPREAMBLE = 0x9F, + RADIO_SET_LORASYMBTIMEOUT = 0xA0, +}RadioCommands_t; + +/*! + * \brief The type describing the modulation parameters for every packet types + */ +typedef struct +{ + RadioPacketTypes_t PacketType; //!< Packet to which the modulation parameters are referring to. + struct + { + struct + { + uint32_t BitRate; + uint32_t Fdev; + RadioModShapings_t ModulationShaping; + uint8_t Bandwidth; + }Gfsk; + struct + { + RadioLoRaSpreadingFactors_t SpreadingFactor; //!< Spreading Factor for the LoRa modulation + RadioLoRaBandwidths_t Bandwidth; //!< Bandwidth for the LoRa modulation + RadioLoRaCodingRates_t CodingRate; //!< Coding rate for the LoRa modulation + uint8_t LowDatarateOptimize; //!< Indicates if the modem uses the low datarate optimization + }LoRa; + }Params; //!< Holds the modulation parameters structure +}ModulationParams_t; + +/*! + * \brief The type describing the packet parameters for every packet types + */ +typedef struct +{ + RadioPacketTypes_t PacketType; //!< Packet to which the packet parameters are referring to. + struct + { + /*! + * \brief Holds the GFSK packet parameters + */ + struct + { + uint16_t PreambleLength; //!< The preamble Tx length for GFSK packet type in bit + RadioPreambleDetection_t PreambleMinDetect; //!< The preamble Rx length minimal for GFSK packet type + uint8_t SyncWordLength; //!< The synchronization word length for GFSK packet type + RadioAddressComp_t AddrComp; //!< Activated SyncWord correlators + RadioPacketLengthModes_t HeaderType; //!< If the header is explicit, it will be transmitted in the GFSK packet. If the header is implicit, it will not be transmitted + uint8_t PayloadLength; //!< Size of the payload in the GFSK packet + RadioCrcTypes_t CrcLength; //!< Size of the CRC block in the GFSK packet + RadioDcFree_t DcFree; + }Gfsk; + /*! + * \brief Holds the LoRa packet parameters + */ + struct + { + uint16_t PreambleLength; //!< The preamble length is the number of LoRa symbols in the preamble + RadioLoRaPacketLengthsMode_t HeaderType; //!< If the header is explicit, it will be transmitted in the LoRa packet. If the header is implicit, it will not be transmitted + uint8_t PayloadLength; //!< Size of the payload in the LoRa packet + RadioLoRaCrcModes_t CrcMode; //!< Size of CRC block in LoRa packet + RadioLoRaIQModes_t InvertIQ; //!< Allows to swap IQ for LoRa packet + }LoRa; + }Params; //!< Holds the packet parameters structure +}PacketParams_t; + +/*! + * \brief Represents the packet status for every packet type + */ +typedef struct +{ + RadioPacketTypes_t packetType; //!< Packet to which the packet status are referring to. + struct + { + struct + { + uint8_t RxStatus; + int8_t RssiAvg; //!< The averaged RSSI + int8_t RssiSync; //!< The RSSI measured on last packet + uint32_t FreqError; + }Gfsk; + struct + { + int8_t RssiPkt; //!< The RSSI of the last packet + int8_t SnrPkt; //!< The SNR of the last packet + int8_t SignalRssiPkt; + uint32_t FreqError; + }LoRa; + }Params; +}PacketStatus_t; + +/*! + * \brief Represents the Rx internal counters values when GFSK or LoRa packet type is used + */ +typedef struct +{ + RadioPacketTypes_t packetType; //!< Packet to which the packet status are referring to. + uint16_t PacketReceived; + uint16_t CrcOk; + uint16_t LengthError; +}RxCounter_t; + +/*! + * \brief Represents a calibration configuration + */ +typedef union +{ + struct + { + uint8_t RC64KEnable : 1; //!< Calibrate RC64K clock + uint8_t RC13MEnable : 1; //!< Calibrate RC13M clock + uint8_t PLLEnable : 1; //!< Calibrate PLL + uint8_t ADCPulseEnable : 1; //!< Calibrate ADC Pulse + uint8_t ADCBulkNEnable : 1; //!< Calibrate ADC bulkN + uint8_t ADCBulkPEnable : 1; //!< Calibrate ADC bulkP + uint8_t ImgEnable : 1; + uint8_t : 1; + }Fields; + uint8_t Value; +}CalibrationParams_t; + +/*! + * \brief Represents a sleep mode configuration + */ +typedef union +{ + struct + { + uint8_t WakeUpRTC : 1; //!< Get out of sleep mode if wakeup signal received from RTC + uint8_t Reset : 1; + uint8_t WarmStart : 1; + uint8_t Reserved : 5; + }Fields; + uint8_t Value; +}SleepParams_t; + +/*! + * \brief Represents the possible radio system error states + */ +typedef union +{ + struct + { + uint8_t Rc64kCalib : 1; //!< RC 64kHz oscillator calibration failed + uint8_t Rc13mCalib : 1; //!< RC 13MHz oscillator calibration failed + uint8_t PllCalib : 1; //!< PLL calibration failed + uint8_t AdcCalib : 1; //!< ADC calibration failed + uint8_t ImgCalib : 1; //!< Image calibration failed + uint8_t XoscStart : 1; //!< XOSC oscillator failed to start + uint8_t PllLock : 1; //!< PLL lock failed + uint8_t BuckStart : 1; //!< Buck converter failed to start + uint8_t PaRamp : 1; //!< PA ramp failed + uint8_t : 7; //!< Reserved + }Fields; + uint16_t Value; +}RadioError_t; + +/*! + * Radio hardware and global parameters + */ +typedef struct SX126x_s +{ +// Gpio_t Reset; +// Gpio_t BUSY; +// Gpio_t DIO1; +// Gpio_t DIO2; +// Gpio_t DIO3; +// Spi_t Spi; + PacketParams_t PacketParams; + PacketStatus_t PacketStatus; + ModulationParams_t ModulationParams; +}SX126x_t; + +/*! + * Hardware IO IRQ callback function definition + */ +typedef void ( DioIrqHandler )( void ); + +/*! + * SX126x definitions + */ + +/*! + * \brief Provides the frequency of the chip running on the radio and the frequency step + * + * \remark These defines are used for computing the frequency divider to set the RF frequency + */ +#define XTAL_FREQ ( double )32000000 +#define FREQ_DIV ( double )pow( 2.0, 25.0 ) +#define FREQ_STEP ( double )( XTAL_FREQ / FREQ_DIV ) + +#define RX_BUFFER_SIZE 256 + +/*! + * \brief The radio callbacks structure + * Holds function pointers to be called on radio interrupts + */ +typedef struct +{ + void ( *txDone )( void ); //!< Pointer to a function run on successful transmission + void ( *rxDone )( void ); //!< Pointer to a function run on successful reception + void ( *rxPreambleDetect )( void ); //!< Pointer to a function run on successful Preamble detection + void ( *rxSyncWordDone )( void ); //!< Pointer to a function run on successful SyncWord reception + void ( *rxHeaderDone )( bool isOk ); //!< Pointer to a function run on successful Header reception + void ( *txTimeout )( void ); //!< Pointer to a function run on transmission timeout + void ( *rxTimeout )( void ); //!< Pointer to a function run on reception timeout + void ( *rxError )( IrqErrorCode_t errCode ); //!< Pointer to a function run on reception error + void ( *cadDone )( bool cadFlag ); //!< Pointer to a function run on channel activity detected +}SX126xCallbacks_t; + +/*! + * ============================================================================ + * Public functions prototypes + * ============================================================================ + */ + +/*! + * \brief Initializes the radio driver + */ +void SX126xInit( DioIrqHandler dioIrq ); + +/*! + * \brief Gets the current Operation Mode of the Radio + * + * \retval RadioOperatingModes_t last operating mode + */ +RadioOperatingModes_t SX126xGetOperatingMode( void ); + +/*! + * \brief Wakeup the radio if it is in Sleep mode and check that Busy is low + */ +void SX126xCheckDeviceReady( void ); + +/*! + * \brief Saves the payload to be send in the radio buffer + * + * \param [in] payload A pointer to the payload + * \param [in] size The size of the payload + */ +void SX126xSetPayload( uint8_t *payload, uint8_t size ); + +/*! + * \brief Reads the payload received. If the received payload is longer + * than maxSize, then the method returns 1 and do not set size and payload. + * + * \param [out] payload A pointer to a buffer into which the payload will be copied + * \param [out] size A pointer to the size of the payload received + * \param [in] maxSize The maximal size allowed to copy into the buffer + */ +uint8_t SX126xGetPayload( uint8_t *payload, uint8_t *size, uint8_t maxSize ); + +/*! + * \brief Sends a payload + * + * \param [in] payload A pointer to the payload to send + * \param [in] size The size of the payload to send + * \param [in] timeout The timeout for Tx operation + */ +void SX126xSendPayload( uint8_t *payload, uint8_t size, uint32_t timeout ); + +/*! + * \brief Sets the Sync Word given by index used in GFSK + * + * \param [in] syncWord SyncWord bytes ( 8 bytes ) + * + * \retval status [0: OK, 1: NOK] + */ +uint8_t SX126xSetSyncWord( uint8_t *syncWord ); + +/*! + * \brief Sets the Initial value for the LFSR used for the CRC calculation + * + * \param [in] seed Initial LFSR value ( 2 bytes ) + * + */ +void SX126xSetCrcSeed( uint16_t seed ); + +/*! + * \brief Sets the seed used for the CRC calculation + * + * \param [in] seed The seed value + * + */ +void SX126xSetCrcPolynomial( uint16_t polynomial ); + +/*! + * \brief Sets the Initial value of the LFSR used for the whitening in GFSK protocols + * + * \param [in] seed Initial LFSR value + */ +void SX126xSetWhiteningSeed( uint16_t seed ); + +/*! + * \brief Gets a 32 bits random value generated by the radio + * + * \remark The radio must be in reception mode before executing this function + * + * \retval randomValue 32 bits random value + */ +uint32_t SX126xGetRandom( void ); + +/*! + * \brief Sets the radio in sleep mode + * + * \param [in] sleepConfig The sleep configuration describing data + * retention and RTC wake-up + */ +void SX126xSetSleep( SleepParams_t sleepConfig ); + +/*! + * \brief Sets the radio in configuration mode + * + * \param [in] mode The standby mode to put the radio into + */ +void SX126xSetStandby( RadioStandbyModes_t mode ); + +/*! + * \brief Sets the radio in FS mode + */ +void SX126xSetFs( void ); + +/*! + * \brief Sets the radio in transmission mode + * + * \param [in] timeout Structure describing the transmission timeout value + */ +void SX126xSetTx( uint32_t timeout ); + +/*! + * \brief Sets the radio in reception mode + * + * \param [in] timeout Structure describing the reception timeout value + */ +void SX126xSetRx( uint32_t timeout ); + +/*! + * \brief Sets the radio in reception mode with Boosted LNA gain + * + * \param [in] timeout Structure describing the reception timeout value + */ +void SX126xSetRxBoosted( uint32_t timeout ); + +/*! + * \brief Sets the Rx duty cycle management parameters + * + * \param [in] rxTime Structure describing reception timeout value + * \param [in] sleepTime Structure describing sleep timeout value + */ +void SX126xSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ); + +/*! + * \brief Sets the radio in CAD mode + */ +void SX126xSetCad( void ); + +/*! + * \brief Sets the radio in continuous wave transmission mode + */ +void SX126xSetTxContinuousWave( void ); + +/*! + * \brief Sets the radio in continuous preamble transmission mode + */ +void SX126xSetTxInfinitePreamble( void ); + +/*! + * \brief Decide which interrupt will stop the internal radio rx timer. + * + * \param [in] enable [0: Timer stop after header/syncword detection + * 1: Timer stop after preamble detection] + */ +void SX126xSetStopRxTimerOnPreambleDetect( bool enable ); + +/*! + * \brief Set the number of symbol the radio will wait to validate a reception + * + * \param [in] SymbNum number of LoRa symbols + */ +void SX126xSetLoRaSymbNumTimeout( uint8_t SymbNum ); + +/*! + * \brief Sets the power regulators operating mode + * + * \param [in] mode [0: LDO, 1:DC_DC] + */ +void SX126xSetRegulatorMode( RadioRegulatorMode_t mode ); + +/*! + * \brief Calibrates the given radio block + * + * \param [in] calibParam The description of blocks to be calibrated + */ +void SX126xCalibrate( CalibrationParams_t calibParam ); + +/*! + * \brief Calibrates the Image rejection depending of the frequency + * + * \param [in] freq The operating frequency + */ +void SX126xCalibrateImage( uint32_t freq ); + +/*! + * \brief Activate the extention of the timeout when long preamble is used + * + * \param [in] enable The radio will extend the timeout to cope with long preamble + */ +void SX126xSetLongPreamble( uint8_t enable ); + +/*! + * \brief Sets the transmission parameters + * + * \param [in] paDutyCycle Duty Cycle for the PA + * \param [in] hpMax 0 for sx1261, 7 for sx1262 + * \param [in] deviceSel 1 for sx1261, 0 for sx1262 + * \param [in] paLut 0 for 14dBm LUT, 1 for 22dBm LUT + */ +void SX126xSetPaConfig( uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut ); + +/*! + * \brief Defines into which mode the chip goes after a TX / RX done + * + * \param [in] fallbackMode The mode in which the radio goes + */ +void SX126xSetRxTxFallbackMode( uint8_t fallbackMode ); + +/*! + * \brief Write data to the radio memory + * + * \param [in] address The address of the first byte to write in the radio + * \param [in] buffer The data to be written in radio's memory + * \param [in] size The number of bytes to write in radio's memory + */ +void SX126xWriteRegisters( uint16_t address, uint8_t *buffer, uint16_t size ); + +/*! + * \brief Read data from the radio memory + * + * \param [in] address The address of the first byte to read from the radio + * \param [out] buffer The buffer that holds data read from radio + * \param [in] size The number of bytes to read from radio's memory + */ +void SX126xReadRegisters( uint16_t address, uint8_t *buffer, uint16_t size ); + +/*! + * \brief Write data to the buffer holding the payload in the radio + * + * \param [in] offset The offset to start writing the payload + * \param [in] buffer The data to be written (the payload) + * \param [in] size The number of byte to be written + */ +void SX126xWriteBuffer( uint8_t offset, uint8_t *buffer, uint8_t size ); + +/*! + * \brief Read data from the buffer holding the payload in the radio + * + * \param [in] offset The offset to start reading the payload + * \param [out] buffer A pointer to a buffer holding the data from the radio + * \param [in] size The number of byte to be read + */ +void SX126xReadBuffer( uint8_t offset, uint8_t *buffer, uint8_t size ); + +/*! + * \brief Sets the IRQ mask and DIO masks + * + * \param [in] irqMask General IRQ mask + * \param [in] dio1Mask DIO1 mask + * \param [in] dio2Mask DIO2 mask + * \param [in] dio3Mask DIO3 mask + */ +void SX126xSetDioIrqParams( uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask ); + +/*! + * \brief Returns the current IRQ status + * + * \retval irqStatus IRQ status + */ +uint16_t SX126xGetIrqStatus( void ); + +/*! + * \brief Indicates if DIO2 is used to control an RF Switch + * + * \param [in] enable true of false + */ +void SX126xSetDio2AsRfSwitchCtrl( uint8_t enable ); + +/*! + * \brief Indicates if the Radio main clock is supplied from a tcxo + * + * \param [in] tcxoVoltage voltage used to control the TCXO + * \param [in] timeout time given to the TCXO to go to 32MHz + */ +void SX126xSetDio3AsTcxoCtrl( RadioTcxoCtrlVoltage_t tcxoVoltage, uint32_t timeout ); + +/*! + * \brief Sets the RF frequency + * + * \param [in] frequency RF frequency [Hz] + */ +void SX126xSetRfFrequency( uint32_t frequency ); + +/*! + * \brief Sets the radio for the given protocol + * + * \param [in] packetType [PACKET_TYPE_GFSK, PACKET_TYPE_LORA] + * + * \remark This method has to be called before SetRfFrequency, + * SetModulationParams and SetPacketParams + */ +void SX126xSetPacketType( RadioPacketTypes_t packetType ); + +/*! + * \brief Gets the current radio protocol + * + * \retval packetType [PACKET_TYPE_GFSK, PACKET_TYPE_LORA] + */ +RadioPacketTypes_t SX126xGetPacketType( void ); + +/*! + * \brief Sets the transmission parameters + * + * \param [in] power RF output power [-18..13] dBm + * \param [in] rampTime Transmission ramp up time + */ +void SX126xSetTxParams( int8_t power, RadioRampTimes_t rampTime ); + +/*! + * \brief Set the modulation parameters + * + * \param [in] modParams A structure describing the modulation parameters + */ +void SX126xSetModulationParams( ModulationParams_t *modParams ); + +/*! + * \brief Sets the packet parameters + * + * \param [in] packetParams A structure describing the packet parameters + */ +void SX126xSetPacketParams( PacketParams_t *packetParams ); + +/*! + * \brief Sets the Channel Activity Detection (CAD) parameters + * + * \param [in] cadSymbolNum The number of symbol to use for CAD operations + * [LORA_CAD_01_SYMBOL, LORA_CAD_02_SYMBOL, + * LORA_CAD_04_SYMBOL, LORA_CAD_08_SYMBOL, + * LORA_CAD_16_SYMBOL] + * \param [in] cadDetPeak Limit for detection of SNR peak used in the CAD + * \param [in] cadDetMin Set the minimum symbol recognition for CAD + * \param [in] cadExitMode Operation to be done at the end of CAD action + * [LORA_CAD_ONLY, LORA_CAD_RX, LORA_CAD_LBT] + * \param [in] cadTimeout Defines the timeout value to abort the CAD activity + */ +void SX126xSetCadParams( RadioLoRaCadSymbols_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, RadioCadExitModes_t cadExitMode, uint32_t cadTimeout ); + +/*! + * \brief Sets the data buffer base address for transmission and reception + * + * \param [in] txBaseAddress Transmission base address + * \param [in] rxBaseAddress Reception base address + */ +void SX126xSetBufferBaseAddress( uint8_t txBaseAddress, uint8_t rxBaseAddress ); + +/*! + * \brief Gets the current radio status + * + * \retval status Radio status + */ +RadioStatus_t SX126xGetStatus( void ); + +/*! + * \brief Returns the instantaneous RSSI value for the last packet received + * + * \retval rssiInst Instantaneous RSSI + */ +int8_t SX126xGetRssiInst( void ); + +/*! + * \brief Gets the last received packet buffer status + * + * \param [out] payloadLength Last received packet payload length + * \param [out] rxStartBuffer Last received packet buffer address pointer + */ +void SX126xGetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBuffer ); + +/*! + * \brief Gets the last received packet payload length + * + * \param [out] pktStatus A structure of packet status + */ +void SX126xGetPacketStatus( PacketStatus_t *pktStatus ); + +/*! + * \brief Returns the possible system errors + * + * \retval sysErrors Value representing the possible sys failures + */ +RadioError_t SX126xGetDeviceErrors( void ); + +/*! + * \brief Clear all the errors in the device + */ +void SX126xClearDeviceErrors( void ); + +/*! + * \brief Clears the IRQs + * + * \param [in] irq IRQ(s) to be cleared + */ +void SX126xClearIrqStatus( uint16_t irq ); + +#endif // __SX126x_H__ diff --git a/keil/include/src/Radio/user.h b/keil/include/src/Radio/user.h new file mode 100644 index 0000000..6746b52 --- /dev/null +++ b/keil/include/src/Radio/user.h @@ -0,0 +1,22 @@ +#ifndef _USER_H_ +#define _USER_H_ + +//#include "stm32f0xx.h" +//#include "stm32l0xx_hal.h" + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +//#include "gpio.h" +#include "delay.h" +//#include "spi.h" + +#include "radio.h" +#include "sx126x.h" +#include "sx126x-board.h" +#include "crc.h" + + +#endif + -- Gitblit v1.9.3