无线定位之四 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);
            //> 根据时间戳提取队列中待发送数据index
            jit_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();       //> 终止 scan
                            if (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队列中待发送数据、如果有数据就提取数据、出队列、发送数据。
如果本篇文章对您有所启发或帮助、请给笔者点赞助力、鼓励笔者坚持把此系列内容尽快梳理、分享出来。
谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值