当前位置: 首页 > ai >正文

无线定位之四 SX1302 网关源码 thread_jit 线程详解

前言

笔者计划通过无线定位系列文章、系统的描述 TDOA 无线定位和混合定位相关技术知识点,
并以实践来验证此定位系统精度。

笔者从实践出发、本篇直接走读无线定位系统关键节点、网关 SX1302 源码框架,并在源码走读过程
中、着重分析与无线定位相关的PPS时间的来龙去脉、并在后期文章中以实际代码讲解 TDOA 无线定位
实现过程及多网关综合定位内容,敬请期待。

semtech 公司在 2020年06月份推出 LR1110\LR1120 两款GNSS、WIFI和Lora(LR-HFSS)混合
定位芯片、并提供’定位云服务’的接入、国内与腾讯云合作,腾讯云也提供定位云服务接入,这是
笔者对混合无线定位技术背景简单描述、此用意看官自行审度。

第1节 主程序代码走读

主线程基本功能:
<1>. 读取 *.conf.json 文件内容、并解析内容把变量赋值到相关全局变量中;
<2>. 启动各子线程、子线程清单如下所述;
<3>. 固定周期定时检测gps的时间戳、并上报网关的状态信息;
<4>. 等待退出信号量、网络断开信号量和各子线程退出.

子线程清单.

/* threads */
void thread_up(void);               //> 上行线程:负责接收lora模块的数据、并把数据通过网络上传至网络服务器;
void thread_down(void);          //> 下行线程:负责接收服务器的数据,并把数据通过lora无线下方给终端模块;
void thread_jit(void);                 //> jit 下行数据处理线程:
void thread_gps(void);              //> gps 线程时间同步线程
void thread_valid(void);            //> 时钟校正线程
void thread_spectral_scan(void);    //> SCAN扫描线程:

主程序源码基本功能就这么多,笔者就不贴出源码对照了,下面进入我们本章主题 thread_jit 线程的代码走读。

第2节 thread_jit 程序框架描述

此线程是负责发送 queue 中数据内容至 Lora 模块的线程,此数据来源是 thread_down 线程填充至队列中,
其他线程如果有数据需要下方、也可以向此队列中填充数据。下面源码中笔者注释、内容比较简短清晰的。

2.2 thread_jit 程序框架

/* --- THREAD 3: CHECKING PACKETS TO BE SENT FROM JIT QUEUE AND SEND THEM --- */
void thread_jit(void) {int result = LGW_HAL_SUCCESS;struct lgw_pkt_tx_s pkt;int pkt_index = -1;uint32_t current_concentrator_time;enum jit_error_e jit_result;enum jit_pkt_type_e pkt_type;uint8_t tx_status;int i;while (!exit_sig && !quit_sig) {wait_ms(10);for (i = 0; i < LGW_RF_CHAIN_NB; i++) {/* transfer data and metadata to the concentrator, and schedule TX */pthread_mutex_lock(&mx_concent);lgw_get_instcnt(&current_concentrator_time);pthread_mutex_unlock(&mx_concent);//> 根据时间戳提取队列中待发送数据indexjit_result = jit_peek(&jit_queue[i], current_concentrator_time, &pkt_index);if (jit_result == JIT_ERROR_OK) {if (pkt_index > -1) {//> 提取指定 index 数据帧内容jit_result = jit_dequeue(&jit_queue[i], pkt_index, &pkt, &pkt_type);if (jit_result == JIT_ERROR_OK) {/* update beacon stats */if (pkt_type == JIT_PKT_TYPE_BEACON) {/* Compensate breacon frequency with xtal error */pthread_mutex_lock(&mx_xcorr);pkt.freq_hz = (uint32_t)(xtal_correct * (double)pkt.freq_hz);MSG_DEBUG(DEBUG_BEACON, "beacon_pkt.freq_hz=%u (xtal_correct=%.15lf)\n", pkt.freq_hz, xtal_correct);pthread_mutex_unlock(&mx_xcorr);/* Update statistics */pthread_mutex_lock(&mx_meas_dw);meas_nb_beacon_sent += 1;pthread_mutex_unlock(&mx_meas_dw);MSG("INFO: Beacon dequeued (count_us=%u)\n", pkt.count_us);}/* check if concentrator is free for sending new packet */pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish *///> 检测 网关 rf_chain 状态result = lgw_status(pkt.rf_chain, TX_STATUS, &tx_status);pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */if (result == LGW_HAL_ERROR) {MSG("WARNING: [jit%d] lgw_status failed\n", i);} else {if (tx_status == TX_EMITTING) {MSG("ERROR: concentrator is currently emitting on rf_chain %d\n", i);print_tx_status(tx_status);continue;} else if (tx_status == TX_SCHEDULED) {MSG("WARNING: a downlink was already scheduled on rf_chain %d, overwritting it...\n", i);print_tx_status(tx_status);} else {/* Nothing to do */}}/* send packet to concentrator */pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */if (spectral_scan_params.enable == true) {result = lgw_spectral_scan_abort();       //> 终止 scanif (result != LGW_HAL_SUCCESS) {MSG("WARNING: [jit%d] lgw_spectral_scan_abort failed\n", i);}}//> 发送数据至 Lora 模块result = lgw_send(&pkt);pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */if (result != LGW_HAL_SUCCESS) {pthread_mutex_lock(&mx_meas_dw);meas_nb_tx_fail += 1;pthread_mutex_unlock(&mx_meas_dw);MSG("WARNING: [jit] lgw_send failed on rf_chain %d\n", i);continue;} else {pthread_mutex_lock(&mx_meas_dw);meas_nb_tx_ok += 1;pthread_mutex_unlock(&mx_meas_dw);MSG_DEBUG(DEBUG_PKT_FWD, "lgw_send done on rf_chain %d: count_us=%u\n", i, pkt.count_us);}} else {MSG("ERROR: jit_dequeue failed on rf_chain %d with %d\n", i, jit_result);}}} else if (jit_result == JIT_ERROR_EMPTY) {/* Do nothing, it can happen */} else {MSG("ERROR: jit_peek failed on rf_chain %d with %d\n", i, jit_result);}}}MSG("\nINFO: End of JIT thread\n");
}

函数 lgw_send(&pkt); 调用到
int sx1302_send(lgw_radio_type_t radio_type, struct lgw_tx_gain_lut_s * tx_lut, bool lwan_public, struct lgw_conf_rxif_s * context_fsk, struct lgw_pkt_tx_s * pkt_data) ;
摘录函数中选择lora、fsk模式、及配置 rf前端芯片代码,如下:

 
/* Select the proper modem */switch (pkt_data->modulation) {case MOD_CW:err = lgw_reg_w(SX1302_REG_TX_TOP_GEN_CFG_0_MODULATION_TYPE(pkt_data->rf_chain), 0x00);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_CTRL_TX_IF_SRC(pkt_data->rf_chain), 0x00);CHECK_ERR(err);break;case MOD_LORA:err = lgw_reg_w(SX1302_REG_TX_TOP_GEN_CFG_0_MODULATION_TYPE(pkt_data->rf_chain), 0x00);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_CTRL_TX_IF_SRC(pkt_data->rf_chain), 0x01);CHECK_ERR(err);break;case MOD_FSK:err = lgw_reg_w(SX1302_REG_TX_TOP_GEN_CFG_0_MODULATION_TYPE(pkt_data->rf_chain), 0x01);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_CTRL_TX_IF_SRC(pkt_data->rf_chain), 0x02);CHECK_ERR(err);break;default:DEBUG_MSG("ERROR: modulation type not supported\n");return LGW_REG_ERROR;}/* Find the proper index in the TX gain LUT according to requested rf_power */for (pow_index = tx_lut->size-1; pow_index > 0; pow_index--) {if (tx_lut->lut[pow_index].rf_power <= pkt_data->rf_power) {break;}}DEBUG_PRINTF("INFO: selecting TX Gain LUT index %u\n", pow_index);/* loading calibrated Tx DC offsets */err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_I_OFFSET_I_OFFSET(pkt_data->rf_chain), tx_lut->lut[pow_index].offset_i);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_Q_OFFSET_Q_OFFSET(pkt_data->rf_chain), tx_lut->lut[pow_index].offset_q);CHECK_ERR(err);DEBUG_PRINTF("INFO: Applying IQ offset (i:%d, q:%d)\n", tx_lut->lut[pow_index].offset_i, tx_lut->lut[pow_index].offset_q);/* Set the power parameters to be used for TX */switch (radio_type) { //>根据配置文件、选择 radio_type 是SX1250 还是SX1255, 笔者选用 MiniPCIE sx1302 的发送模块 sx1250模块;case LGW_RADIO_TYPE_SX1250:pa_en = (tx_lut->lut[pow_index].pa_gain > 0) ? 1 : 0; /* only 1 bit used to control the external PA */power = (pa_en << 6) | tx_lut->lut[pow_index].pwr_idx;break;case LGW_RADIO_TYPE_SX1255:case LGW_RADIO_TYPE_SX1257:power = (tx_lut->lut[pow_index].pa_gain << 6) | (tx_lut->lut[pow_index].dac_gain << 4) | tx_lut->lut[pow_index].mix_gain;break;default:DEBUG_MSG("ERROR: radio type not supported\n");return LGW_REG_ERROR;}err = lgw_reg_w(SX1302_REG_TX_TOP_AGC_TX_PWR_AGC_TX_PWR(pkt_data->rf_chain), power);CHECK_ERR(err);/* Set the power parameters to be used for TX */switch (radio_type) {case LGW_RADIO_TYPE_SX1250:pa_en = (tx_lut->lut[pow_index].pa_gain > 0) ? 1 : 0; /* only 1 bit used to control the external PA */power = (pa_en << 6) | tx_lut->lut[pow_index].pwr_idx;break;case LGW_RADIO_TYPE_SX1255:case LGW_RADIO_TYPE_SX1257:power = (tx_lut->lut[pow_index].pa_gain << 6) | (tx_lut->lut[pow_index].dac_gain << 4) | tx_lut->lut[pow_index].mix_gain;break;default:DEBUG_MSG("ERROR: radio type not supported\n");return LGW_REG_ERROR;}err = lgw_reg_w(SX1302_REG_TX_TOP_AGC_TX_PWR_AGC_TX_PWR(pkt_data->rf_chain), power);CHECK_ERR(err);/* Set digital gain */err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_IQ_GAIN_IQ_GAIN(pkt_data->rf_chain), tx_lut->lut[pow_index].dig_gain);CHECK_ERR(err);/* Set Tx frequency */if (radio_type == LGW_RADIO_TYPE_SX1255) {freq_reg = SX1302_FREQ_TO_REG(pkt_data->freq_hz * 2);} else {freq_reg = SX1302_FREQ_TO_REG(pkt_data->freq_hz);}err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_RF_H_FREQ_RF(pkt_data->rf_chain), (freq_reg >> 16) & 0xFF);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_RF_M_FREQ_RF(pkt_data->rf_chain), (freq_reg >> 8) & 0xFF);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_RF_L_FREQ_RF(pkt_data->rf_chain), (freq_reg >> 0) & 0xFF);CHECK_ERR(err);/* Set AGC bandwidth and modulation type*/switch (pkt_data->modulation) {case MOD_LORA:mod_bw = pkt_data->bandwidth;break;case MOD_CW:case MOD_FSK:mod_bw = (0x01 << 7) | pkt_data->bandwidth;break;default:printf("ERROR: Modulation not supported\n");return LGW_REG_ERROR;}err = lgw_reg_w(SX1302_REG_TX_TOP_AGC_TX_BW_AGC_TX_BW(pkt_data->rf_chain), mod_bw);CHECK_ERR(err);/* Set AGC bandwidth and modulation type*/switch (pkt_data->modulation) {case MOD_LORA:mod_bw = pkt_data->bandwidth;break;case MOD_CW:case MOD_FSK:mod_bw = (0x01 << 7) | pkt_data->bandwidth;break;default:printf("ERROR: Modulation not supported\n");return LGW_REG_ERROR;}err = lgw_reg_w(SX1302_REG_TX_TOP_AGC_TX_BW_AGC_TX_BW(pkt_data->rf_chain), mod_bw);CHECK_ERR(err);

根据配置文件、网关选择通讯模式、参数、增益配置,接下来看看,Lora、FSK两种模式、数据下发具体配置;

 /* Configure modem */switch (pkt_data->modulation) {case MOD_CW:/* Set frequency deviation */freq_dev = ceil(fabs( (float)pkt_data->freq_offset / 10) ) * 10e3;printf("CW: f_dev %d Hz\n", (int)(freq_dev));fdev_reg = SX1302_FREQ_TO_REG(freq_dev);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_DEV_H_FREQ_DEV(pkt_data->rf_chain), (fdev_reg >>  8) & 0xFF);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_DEV_L_FREQ_DEV(pkt_data->rf_chain), (fdev_reg >>  0) & 0xFF);CHECK_ERR(err);/* Send frequency deviation to AGC fw for radio config */fdev_reg = SX1250_FREQ_TO_REG(freq_dev);err = lgw_reg_w(SX1302_REG_AGC_MCU_MCU_MAIL_BOX_WR_DATA_BYTE2_MCU_MAIL_BOX_WR_DATA, (fdev_reg >> 16) & 0xFF); /* Needed by AGC to configure the sx1250 */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_AGC_MCU_MCU_MAIL_BOX_WR_DATA_BYTE1_MCU_MAIL_BOX_WR_DATA, (fdev_reg >>  8) & 0xFF); /* Needed by AGC to configure the sx1250 */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_AGC_MCU_MCU_MAIL_BOX_WR_DATA_BYTE0_MCU_MAIL_BOX_WR_DATA, (fdev_reg >>  0) & 0xFF); /* Needed by AGC to configure the sx1250 */CHECK_ERR(err);/* Set the frequency offset (ratio of the frequency deviation)*/printf("CW: IF test mod freq %d\n", (int)(((float)pkt_data->freq_offset*1e3*64/(float)freq_dev)));err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_TEST_MOD_FREQ(pkt_data->rf_chain), (int)(((float)pkt_data->freq_offset*1e3*64/(float)freq_dev)));CHECK_ERR(err);break;case MOD_LORA:/* Set bandwidth */freq_dev = lgw_bw_getval(pkt_data->bandwidth) / 2;fdev_reg = SX1302_FREQ_TO_REG(freq_dev);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_DEV_H_FREQ_DEV(pkt_data->rf_chain), (fdev_reg >>  8) & 0xFF);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_DEV_L_FREQ_DEV(pkt_data->rf_chain), (fdev_reg >>  0) & 0xFF);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_0_MODEM_BW(pkt_data->rf_chain), pkt_data->bandwidth);CHECK_ERR(err);/* Preamble length */if (pkt_data->preamble == 0) { /* if not explicit, use recommended LoRa preamble size */pkt_data->preamble = STD_LORA_PREAMBLE;} else if (pkt_data->preamble < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */pkt_data->preamble = MIN_LORA_PREAMBLE;DEBUG_MSG("Note: preamble length adjusted to respect minimum LoRa preamble size\n");}err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG1_3_PREAMBLE_SYMB_NB(pkt_data->rf_chain), (pkt_data->preamble >> 8) & 0xFF); /* MSB */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG1_2_PREAMBLE_SYMB_NB(pkt_data->rf_chain), (pkt_data->preamble >> 0) & 0xFF); /* LSB */CHECK_ERR(err);/* LoRa datarate */err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_0_MODEM_SF(pkt_data->rf_chain), pkt_data->datarate);CHECK_ERR(err);/* Chirp filtering */chirp_lowpass = (pkt_data->datarate < 10) ? 6 : 7;err = lgw_reg_w(SX1302_REG_TX_TOP_TX_CFG0_0_CHIRP_LOWPASS(pkt_data->rf_chain), (int32_t)chirp_lowpass);CHECK_ERR(err);/* Coding Rate */err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_1_CODING_RATE(pkt_data->rf_chain), pkt_data->coderate);CHECK_ERR(err);/* Start LoRa modem */err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_2_MODEM_EN(pkt_data->rf_chain), 1);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_2_CADRXTX(pkt_data->rf_chain), 2);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG1_1_MODEM_START(pkt_data->rf_chain), 1);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_CFG0_0_CONTINUOUS(pkt_data->rf_chain), 0);CHECK_ERR(err);/* Modulation options */err = lgw_reg_w(SX1302_REG_TX_TOP_TX_CFG0_0_CHIRP_INVERT(pkt_data->rf_chain), (pkt_data->invert_pol) ? 1 : 0);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_2_IMPLICIT_HEADER(pkt_data->rf_chain), (pkt_data->no_header) ? 1 : 0);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_2_CRC_EN(pkt_data->rf_chain), (pkt_data->no_crc) ? 0 : 1);CHECK_ERR(err);/* Syncword */if ((lwan_public == false) || (pkt_data->datarate == DR_LORA_SF5) || (pkt_data->datarate == DR_LORA_SF6)) {DEBUG_MSG("Setting LoRa syncword 0x12\n");err = lgw_reg_w(SX1302_REG_TX_TOP_FRAME_SYNCH_0_PEAK1_POS(pkt_data->rf_chain), 2);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FRAME_SYNCH_1_PEAK2_POS(pkt_data->rf_chain), 4);CHECK_ERR(err);} else {DEBUG_MSG("Setting LoRa syncword 0x34\n");err = lgw_reg_w(SX1302_REG_TX_TOP_FRAME_SYNCH_0_PEAK1_POS(pkt_data->rf_chain), 6);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FRAME_SYNCH_1_PEAK2_POS(pkt_data->rf_chain), 8);CHECK_ERR(err);}/* Set Fine Sync for SF5/SF6 */if ((pkt_data->datarate == DR_LORA_SF5) || (pkt_data->datarate == DR_LORA_SF6)) {DEBUG_MSG("Enable Fine Sync\n");err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_2_FINE_SYNCH_EN(pkt_data->rf_chain), 1);CHECK_ERR(err);} else {DEBUG_MSG("Disable Fine Sync\n");err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_2_FINE_SYNCH_EN(pkt_data->rf_chain), 0);CHECK_ERR(err);}/* Set Payload length */err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_3_PAYLOAD_LENGTH(pkt_data->rf_chain), pkt_data->size);CHECK_ERR(err);/* Set PPM offset (low datarate optimization) */err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_1_PPM_OFFSET_HDR_CTRL(pkt_data->rf_chain), 0);CHECK_ERR(err);if (SET_PPM_ON(pkt_data->bandwidth, pkt_data->datarate)) {DEBUG_MSG("Low datarate optimization ENABLED\n");err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_1_PPM_OFFSET(pkt_data->rf_chain), 1);CHECK_ERR(err);} else {DEBUG_MSG("Low datarate optimization DISABLED\n");err = lgw_reg_w(SX1302_REG_TX_TOP_TXRX_CFG0_1_PPM_OFFSET(pkt_data->rf_chain), 0);CHECK_ERR(err);}break;case MOD_FSK:  //> FSK 无线通讯CHECK_NULL(context_fsk);/* Set frequency deviation */freq_dev = pkt_data->f_dev * 1e3;fdev_reg = SX1302_FREQ_TO_REG(freq_dev);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_DEV_H_FREQ_DEV(pkt_data->rf_chain), (fdev_reg >>  8) & 0xFF);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_RFFE_IF_FREQ_DEV_L_FREQ_DEV(pkt_data->rf_chain), (fdev_reg >>  0) & 0xFF);CHECK_ERR(err);/* Send frequency deviation to AGC fw for radio config */fdev_reg = SX1250_FREQ_TO_REG(freq_dev);err = lgw_reg_w(SX1302_REG_AGC_MCU_MCU_MAIL_BOX_WR_DATA_BYTE2_MCU_MAIL_BOX_WR_DATA, (fdev_reg >> 16) & 0xFF); /* Needed by AGC to configure the sx1250 */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_AGC_MCU_MCU_MAIL_BOX_WR_DATA_BYTE1_MCU_MAIL_BOX_WR_DATA, (fdev_reg >>  8) & 0xFF); /* Needed by AGC to configure the sx1250 */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_AGC_MCU_MCU_MAIL_BOX_WR_DATA_BYTE0_MCU_MAIL_BOX_WR_DATA, (fdev_reg >>  0) & 0xFF); /* Needed by AGC to configure the sx1250 */CHECK_ERR(err);/* Modulation parameters */err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_CFG_0_PKT_MODE(pkt_data->rf_chain), 1); /* Variable length */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_CFG_0_CRC_EN(pkt_data->rf_chain), (pkt_data->no_crc) ? 0 : 1);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_CFG_0_CRC_IBM(pkt_data->rf_chain), 0); /* CCITT CRC */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_CFG_0_DCFREE_ENC(pkt_data->rf_chain), 2); /* Whitening Encoding */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_MOD_FSK_GAUSSIAN_EN(pkt_data->rf_chain), 1);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_MOD_FSK_GAUSSIAN_SELECT_BT(pkt_data->rf_chain), 2);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_MOD_FSK_REF_PATTERN_EN(pkt_data->rf_chain), 1);CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_MOD_FSK_REF_PATTERN_SIZE(pkt_data->rf_chain), context_fsk->sync_word_size - 1);CHECK_ERR(err);/* Syncword */fsk_sync_word_reg = context_fsk->sync_word << (8 * (8 - context_fsk->sync_word_size));err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE0_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 0));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE1_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 8));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE2_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 16));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE3_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 24));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE4_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 32));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE5_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 40));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE6_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 48));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_REF_PATTERN_BYTE7_FSK_REF_PATTERN(pkt_data->rf_chain), (uint8_t)(fsk_sync_word_reg >> 56));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_MOD_FSK_PREAMBLE_SEQ(pkt_data->rf_chain), 0);CHECK_ERR(err);/* Set datarate */fsk_br_reg = 32000000 / pkt_data->datarate;buff[0] = (uint8_t)(fsk_br_reg >> 8);buff[1] = (uint8_t)(fsk_br_reg >> 0);err = lgw_reg_wb(SX1302_REG_TX_TOP_FSK_BIT_RATE_MSB_BIT_RATE(pkt_data->rf_chain), buff, 2);CHECK_ERR(err);/* Preamble length */if (pkt_data->preamble == 0) { /* if not explicit, use LoRaWAN preamble size */pkt_data->preamble = STD_FSK_PREAMBLE;} else if (pkt_data->preamble < MIN_FSK_PREAMBLE) { /* enforce minimum preamble size */pkt_data->preamble = MIN_FSK_PREAMBLE;DEBUG_MSG("Note: preamble length adjusted to respect minimum FSK preamble size\n");}buff[0] = (uint8_t)(pkt_data->preamble >> 8);buff[1] = (uint8_t)(pkt_data->preamble >> 0);err = lgw_reg_wb(SX1302_REG_TX_TOP_FSK_PREAMBLE_SIZE_MSB_PREAMBLE_SIZE(pkt_data->rf_chain), buff, 2);CHECK_ERR(err);/* Set Payload length */err = lgw_reg_w(SX1302_REG_TX_TOP_FSK_PKT_LEN_PKT_LENGTH(pkt_data->rf_chain), pkt_data->size);CHECK_ERR(err);break;default:printf("ERROR: Modulation not supported\n");return LGW_REG_ERROR;

在选定网关的通讯模式后、配置发送前端参数,发送数据如下,

 /* Set TX start delay */err = sx1302_tx_set_start_delay(pkt_data->rf_chain, radio_type, pkt_data->modulation, pkt_data->bandwidth, chirp_lowpass, &tx_start_delay);CHECK_ERR(err);/* Write payload in transmit buffer */err = lgw_reg_w(SX1302_REG_TX_TOP_TX_CTRL_WRITE_BUFFER(pkt_data->rf_chain), 0x01);CHECK_ERR(err);mem_addr = REG_SELECT(pkt_data->rf_chain, 0x5300, 0x5500);if (pkt_data->modulation == MOD_FSK) {err = lgw_mem_wb(mem_addr, (uint8_t *)(&(pkt_data->size)), 1); /* insert payload size in the packet for FSK variable mode (1 byte) */CHECK_ERR(err);err = lgw_mem_wb(mem_addr+1, &(pkt_data->payload[0]), pkt_data->size);CHECK_ERR(err);} else {err = lgw_mem_wb(mem_addr, &(pkt_data->payload[0]), pkt_data->size);CHECK_ERR(err);}err = lgw_reg_w(SX1302_REG_TX_TOP_TX_CTRL_WRITE_BUFFER(pkt_data->rf_chain), 0x00);CHECK_ERR(err);/* Trigger transmit */DEBUG_PRINTF("Start Tx: Freq:%u %s%u size:%u preamb:%u\n", pkt_data->freq_hz, (pkt_data->modulation == MOD_LORA) ? "SF" : "DR:", pkt_data->datarate, pkt_data->size, pkt_data->preamble);switch (pkt_data->tx_mode) {case IMMEDIATE:err = lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_IMMEDIATE(pkt_data->rf_chain), 0x00); /* reset state machine */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_IMMEDIATE(pkt_data->rf_chain), 0x01);CHECK_ERR(err);break;case TIMESTAMPED:count_us = pkt_data->count_us * 32 - tx_start_delay;DEBUG_PRINTF("--> programming trig delay at %u (%u)\n", pkt_data->count_us - (tx_start_delay / 32), count_us);err = lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE0_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >>  0) & 0x000000FF));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE1_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >>  8) & 0x000000FF));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE2_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >> 16) & 0x000000FF));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE3_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >> 24) & 0x000000FF));CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_DELAYED(pkt_data->rf_chain), 0x00); /* reset state machine */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_DELAYED(pkt_data->rf_chain), 0x01);CHECK_ERR(err);break;case ON_GPS:err = lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_GPS(pkt_data->rf_chain), 0x00); /* reset state machine */CHECK_ERR(err);err = lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_GPS(pkt_data->rf_chain), 0x01);CHECK_ERR(err);break;default:printf("ERROR: TX mode not supported\n");return LGW_REG_ERROR;}/* Flush write (USB BULK mode) */err = lgw_com_flush();CHECK_ERR(err);/* Setting back to SINGLE BULK write mode */err = lgw_com_set_write_mode(LGW_COM_WRITE_MODE_SINGLE);CHECK_ERR(err);/* Compute time spent in this function */_meas_time_stop(2, tm, __FUNCTION__);return LGW_REG_SUCCESS;

由代码可以看出,网关发送数据发送有三种模式,立即发送、延时方式、ON_GPS发送,其中ON_GPS发送模式还需要再研究下。

第3节 总结

线程 thread_jit 固定周期检查queue队列中待发送数据、如果有数据就提取数据、出队列、发送数据。
如果本篇文章对您有所启发或帮助、请给笔者点赞助力、鼓励笔者坚持把此系列内容尽快梳理、分享出来。
谢谢。

http://www.xdnf.cn/news/5957.html

相关文章:

  • 道通EVO MAX系列无人机-支持二次开发
  • Springboot实现重试机制
  • 工具学习_VirusTotal使用
  • 集成钉钉消息推送功能
  • 软件I2C
  • python3:文件与异常
  • JSON 和 cJSON 库入门教程
  • SPI接口:原理;从设备slave如何主动给主设备master发数据?
  • 基于MNIST数据集的手写数字识别(简单全连接网络)
  • 共享代理IP带宽受限影响大吗
  • SQL:MySQL函数:数学函数(Mathematical Functions)
  • 牛客周赛96补题 D F
  • 【IC验证】systemverilog_类
  • yum安装-此系统没有注册
  • Python打包工具PyInstaller,打包之后的反编译工具pyinstxtractor
  • 2025.05.10京东机考真题算法岗-第一题
  • QT 插槽实现
  • 最短路与拓扑(1)
  • openjdk底层汇编指令调用(三)——编码
  • Ensemble Alignment Subspace Adaptation Method for Cross-Scene Classification
  • HDFS的客户端操作(1)
  • USB3.0拓展坞制作学习
  • Linux系统编程---Signal信号集
  • Profibus DP主站转Modbus RTU/TCP如何把E+H流量计接入到modbus
  • 基于单片机的视力保护仪设计与实现
  • 硬密封保温 V 型球阀:恒温工况下复杂介质控制的性价比之选-耀圣
  • RabbitMQ 核心概念与消息模型深度解析(一)
  • Linux 系统如何挂载U盘
  • 火语言RPA--EcshopV4发布商品
  • 【datawhale组队学习】coze-ai-assistant TASK01