ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Xiaojie雷达之路---TI实战笔记---profile、chirp、advframe代码解读

2020-12-11 21:58:31  阅读:277  来源: 互联网

标签:profile frameSeq advframe VAL MRR --- CHIRP USRR ptrAdvFrameCfg


在上位机给AWR1843发送指令"advFrameCfg"后,会触发函数“MRR_MSS_CLIAdvancedFrameCfg”,如下图:
在这里插入图片描述
那么,我们要解读的就是MRR_MSS_CLIAdvancedFrameCfg这个函数,这个函数主要是对profile、chirp、advframe进行配置,下面进入这个函数,这篇文章最主要的是讲解这个函数中的下面的内容:

在这里插入图片描述

这个源程序中NUM_PROFILES为2,说明要设置2个profile模板,供chirp使用,NUM_CHIRP_PROG为5,这几个要进行组合形成burst,burst在形成subframe,subframe在形成frame。

Cfg_ProfileCfgInitParams

下面进入Cfg_ProfileCfgInitParams这个函数,查看对参数profileCfg的配置:

void Cfg_ProfileCfgInitParams (uint8_t profileNum, rlProfileCfg_t* ptrProfileCfg)
{
    /* Initialize the configuration: */
    memset ((void*)ptrProfileCfg, 0, sizeof(rlProfileCfg_t));

    if (profileNum == 0U)
    {
        /* Populate the default configuration for profile 0  */
        ptrProfileCfg->profileId             = PROFILE_MRR_PROFILE_ID;
        ptrProfileCfg->pfVcoSelect           = 0;
        ptrProfileCfg->pfCalLutUpdate        = 0;
        ptrProfileCfg->startFreqConst        = PROFILE_MRR_START_FREQ_VAL;
        ptrProfileCfg->idleTimeConst         = PROFILE_MRR_IDLE_TIME_VAL;
        ptrProfileCfg->adcStartTimeConst     = PROFILE_MRR_ADC_START_TIME_VAL;
        ptrProfileCfg->rampEndTime           = PROFILE_MRR_RAMP_END_TIME_VAL;
        ptrProfileCfg->txOutPowerBackoffCode = PROFILE_MRR_TXOUT_POWER_BACKOFF;
        ptrProfileCfg->txPhaseShifter        = PROFILE_MRR_TXPHASESHIFTER_VAL;
        ptrProfileCfg->freqSlopeConst        = PROFILE_MRR_FREQ_SLOPE_VAL;
        ptrProfileCfg->txStartTime           = PROFILE_MRR_TX_START_TIME_VAL;
        ptrProfileCfg->numAdcSamples         = PROFILE_MRR_ADC_SAMPLE_VAL;
        ptrProfileCfg->digOutSampleRate      = PROFILE_MRR_DIGOUT_SAMPLERATE_VAL;
        ptrProfileCfg->hpfCornerFreq1        = PROFILE_MRR_HPFCORNER_FREQ1_VAL;
        ptrProfileCfg->hpfCornerFreq2        = PROFILE_MRR_HPFCORNER_FREQ2_VAL;
        ptrProfileCfg->txCalibEnCfg          = 0;
        ptrProfileCfg->rxGain                = PROFILE_MRR_RX_GAIN_VAL;
    }
    else
    {
        /* Populate the default configuration for profile 1  */
        ptrProfileCfg->profileId             = PROFILE_USRR_PROFILE_ID;
        ptrProfileCfg->pfVcoSelect           = 0;
        ptrProfileCfg->pfCalLutUpdate        = 0;
        ptrProfileCfg->startFreqConst        = PROFILE_USRR_START_FREQ_VAL;
        ptrProfileCfg->idleTimeConst         = PROFILE_USRR_IDLE_TIME_VAL;
        ptrProfileCfg->adcStartTimeConst     = PROFILE_USRR_ADC_START_TIME_VAL;
        ptrProfileCfg->rampEndTime           = PROFILE_USRR_RAMP_END_TIME_VAL;
        ptrProfileCfg->txOutPowerBackoffCode = PROFILE_USRR_TXOUT_POWER_BACKOFF;
        ptrProfileCfg->txPhaseShifter        = PROFILE_USRR_TXPHASESHIFTER_VAL;
        ptrProfileCfg->freqSlopeConst        = PROFILE_USRR_FREQ_SLOPE_VAL;
        ptrProfileCfg->txStartTime           = PROFILE_USRR_TX_START_TIME_VAL;
        ptrProfileCfg->numAdcSamples         = PROFILE_USRR_ADC_SAMPLE_VAL;
        ptrProfileCfg->digOutSampleRate      = PROFILE_USRR_DIGOUT_SAMPLERATE_VAL;
        ptrProfileCfg->hpfCornerFreq1        = PROFILE_USRR_HPFCORNER_FREQ1_VAL;
        ptrProfileCfg->hpfCornerFreq2        = PROFILE_USRR_HPFCORNER_FREQ2_VAL;
        ptrProfileCfg->txCalibEnCfg          = 0;
        ptrProfileCfg->rxGain                = PROFILE_USRR_RX_GAIN_VAL;
    }
    return;
}

首先if-else结构说明对两个profile要设置不同的配置。

  1. 第一个profileId = 0,下面对一些重要的参数进行说明

     startFreqConst 起始频率:76.01GHz
     idleTimeConst 空闲时间:6us
     adcStartTimeConst adc开始时间:4.8us
     rampEndTime 斜坡结束时间:56us
     freqSlopeConst 斜坡频率:8MHz/us
     txStartTime tx 开始时间:1us
     numAdcSamples adc采样数(一个Rx):256
     digOutSampleRate 采样率:7.5MHz(7.5Msps)
     hpfCornerFreq1 高通滤波1:175KHz
     hpfCornerFreq2 高通滤波2:350KHz
     rxGain 接收增益:44dB
    
  2. 第二个profileId = 1,下面对一些重要的参数进行说明

     startFreqConst 起始频率:77.01GHz
     idleTimeConst 空闲时间:6us
     adcStartTimeConst adc开始时间:6us
     rampEndTime 斜坡结束时间:32.6us
     freqSlopeConst 斜坡频率:54MHz/us
     txStartTime tx 开始时间:1us
     numAdcSamples adc采样数(一个Rx):256
     digOutSampleRate 采样率:10MHz(10Msps)
     hpfCornerFreq1 高通滤波1:175KHz
     hpfCornerFreq2 高通滤波2:350KHz
     rxGain 接收增益:30dB
    

这就意味着对profileCfg的参数设置完毕,然后调用rlSetProfileConfig对BSS进行配置。

Cfg_ChirpCfgInitParams

下面进入Cfg_ChirpCfgInitParams这个函数,查看对参数ChirpCfg的配置:

void Cfg_ChirpCfgInitParams (uint8_t chirpNum, rlChirpCfg_t* ptrChirpCfg)
{
    /* Initialize the configuration: */
    memset ((void*)ptrChirpCfg, 0, sizeof(rlChirpCfg_t));

    if (chirpNum == 0U)
    {
        /* Populate the default configuration for chirp 0.
         *  - MRR Fast Chirp for max-velocity enhancement. */
        ptrChirpCfg->profileId       = CHIRP_MRR_0_PROFILE_ID;
        ptrChirpCfg->adcStartTimeVar = CHIRP_MRR_0_ADC_START_TIME_VAL;
        ptrChirpCfg->chirpEndIdx     = CHIRP_MRR_0_END_INDEX;
        ptrChirpCfg->chirpStartIdx   = CHIRP_MRR_0_START_INDEX;
        ptrChirpCfg->idleTimeVar     = CHIRP_MRR_0_IDLE_TIME_VAL;
        ptrChirpCfg->txEnable        = CHIRP_MRR_0_TX_CHANNEL;
        ptrChirpCfg->startFreqVar    = CHIRP_MRR_0_START_FREQ_VAL;
        ptrChirpCfg->freqSlopeVar    = CHIRP_MRR_0_FREQ_SLOPE_VAL;
    }
    else if (chirpNum == 1U)
    {
        /* Populate the default configuration for chirp 1
         *  - MRR Slow Chirp for max-velocity enhancement. */
        ptrChirpCfg->profileId       = CHIRP_MRR_1_PROFILE_ID;
        ptrChirpCfg->adcStartTimeVar = CHIRP_MRR_1_ADC_START_TIME_VAL;
        ptrChirpCfg->chirpEndIdx     = CHIRP_MRR_1_END_INDEX;
        ptrChirpCfg->chirpStartIdx   = CHIRP_MRR_1_START_INDEX;
        ptrChirpCfg->idleTimeVar     = CHIRP_MRR_1_IDLE_TIME_VAL;
        ptrChirpCfg->txEnable        = CHIRP_MRR_1_TX_CHANNEL;
        ptrChirpCfg->startFreqVar    = CHIRP_MRR_1_START_FREQ_VAL;
        ptrChirpCfg->freqSlopeVar    = CHIRP_MRR_1_FREQ_SLOPE_VAL;
    }
    else if (chirpNum == 2U)
    {
        /* Populate the default configuration for chirp 2
         *  - USRR Tx1 . */
        ptrChirpCfg->profileId       = CHIRP_USRR_0_PROFILE_ID;
        ptrChirpCfg->adcStartTimeVar = CHIRP_USRR_0_ADC_START_TIME_VAL;
        ptrChirpCfg->chirpEndIdx     = CHIRP_USRR_0_END_INDEX;
        ptrChirpCfg->chirpStartIdx   = CHIRP_USRR_0_START_INDEX;
        ptrChirpCfg->idleTimeVar     = CHIRP_USRR_0_IDLE_TIME_VAL;
        ptrChirpCfg->txEnable        = CHIRP_USRR_0_TX_CHANNEL;
        ptrChirpCfg->startFreqVar    = CHIRP_USRR_0_START_FREQ_VAL;
        ptrChirpCfg->freqSlopeVar    = CHIRP_USRR_0_FREQ_SLOPE_VAL;
    }
    else if (chirpNum == 3U)
    {
        /* Populate the default configuration for chirp 3
         *  - USRR Tx2. */
        ptrChirpCfg->profileId       = CHIRP_USRR_1_PROFILE_ID;
        ptrChirpCfg->adcStartTimeVar = CHIRP_USRR_1_ADC_START_TIME_VAL;
        ptrChirpCfg->chirpEndIdx     = CHIRP_USRR_1_END_INDEX;
        ptrChirpCfg->chirpStartIdx   = CHIRP_USRR_1_START_INDEX;
        ptrChirpCfg->idleTimeVar     = CHIRP_USRR_1_IDLE_TIME_VAL;
        ptrChirpCfg->txEnable        = CHIRP_USRR_1_TX_CHANNEL;
        ptrChirpCfg->startFreqVar    = CHIRP_USRR_1_START_FREQ_VAL;
        ptrChirpCfg->freqSlopeVar    = CHIRP_USRR_1_FREQ_SLOPE_VAL;

    }
    else if (chirpNum == 4U)
    {
        /* Populate the default configuration for chirp 4
         *  - USRR Tx3. */
        ptrChirpCfg->profileId       = CHIRP_USRR_2_PROFILE_ID;
        ptrChirpCfg->adcStartTimeVar = CHIRP_USRR_2_ADC_START_TIME_VAL;
        ptrChirpCfg->chirpEndIdx     = CHIRP_USRR_2_END_INDEX;
        ptrChirpCfg->chirpStartIdx   = CHIRP_USRR_2_START_INDEX;
        ptrChirpCfg->idleTimeVar     = CHIRP_USRR_2_IDLE_TIME_VAL;
        ptrChirpCfg->txEnable        = CHIRP_USRR_2_TX_CHANNEL;
        ptrChirpCfg->startFreqVar    = CHIRP_USRR_2_START_FREQ_VAL;
        ptrChirpCfg->freqSlopeVar    = CHIRP_USRR_2_FREQ_SLOPE_VAL;

    }


    return;
}

首先if-else结构说明对五个chirp要设置不同的配置。

  1. 第一个chirpNum = 0,下面对一些重要的参数进行说明

     profileId:0,指的是这个chirp要用id为0profile
     adcStartTimeVar:0
     chirpStartIdx:0
     chirpEndIdx:63
     idleTimeVar:0
     txEnable:tx1
     startFreqVar:0
     freqSlopeVar:0
    
  2. 第一个chirpNum = 1,下面对一些重要的参数进行说明

     profileId:0,指的是这个chirp要用id为0profile
     adcStartTimeVar:0
     chirpStartIdx:64
     chirpEndIdx:127
     idleTimeVar:11.8us
     txEnable:tx1
     startFreqVar:0
     freqSlopeVar:0
    
  3. 第一个chirpNum = 2,下面对一些重要的参数进行说明

     profileId:1,指的是这个chirp要用id为1profile
     adcStartTimeVar:0
     chirpStartIdx:128
     chirpEndIdx:128
     idleTimeVar:0
     txEnable:tx1
     startFreqVar:0
     freqSlopeVar:0
    
  4. 第一个chirpNum = 3,下面对一些重要的参数进行说明

     profileId:1,指的是这个chirp要用id为1的profile
     adcStartTimeVar:0
     chirpStartIdx:128 + 1
     chirpEndIdx:128 + 1
     idleTimeVar:0
     txEnable:tx3
     startFreqVar:0
     freqSlopeVar:0
    
  5. 第一个chirpNum = 4,下面对一些重要的参数进行说明

     profileId:1,指的是这个chirp要用id为1的profile
     adcStartTimeVar:0
     chirpStartIdx:128 + 2
     chirpEndIdx:128 + 2
     idleTimeVar:0
     txEnable:tx2
     startFreqVar:0
     freqSlopeVar:0
    

这就意味着对ChirpCfg的参数设置完毕,然后调用rlSetChirpConfig对BSS进行配置。

Cfg_AdvFrameCfgInitParams

下面进入Cfg_AdvFrameCfgInitParams这个函数,查看对参数advFrameCfg的配置:

void Cfg_AdvFrameCfgInitParams (rlAdvFrameCfg_t* ptrAdvFrameCfg)
{
    uint8_t numOfSubFrame = 0U;

    /* Initialize the configuration: */
    memset ((void*)ptrAdvFrameCfg, 0, sizeof(rlAdvFrameCfg_t));

    /* Populate the default configuration: */
    ptrAdvFrameCfg->frameSeq.forceProfile  = 0;// 1: force Profile,  0: Don't force profile
    ptrAdvFrameCfg->frameSeq.numFrames     = 0;//infinite
    ptrAdvFrameCfg->frameSeq.triggerSelect = 1;//SW Trigger
    ptrAdvFrameCfg->frameSeq.frameTrigDelay= 0;

#if NUM_SUBFRAMES == 2

    /* The low resolution 80m subframe */
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].forceProfileIdx    = 0;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numLoops           = SUBFRAME_MRR_LOOP_COUNT;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfBurst         = 1;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfBurstLoops    = 1;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].chirpStartIdxOffset= 0;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfChirps        = SUBFRAME_MRR_CHIRP_END_IDX - SUBFRAME_MRR_CHIRP_START_IDX + 1;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].chirpStartIdx      = SUBFRAME_MRR_CHIRP_START_IDX;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].subFramePeriodicity= SUBFRAME_MRR_PERIODICITY_VAL;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[0].burstPeriodicity   = SUBFRAME_MRR_PERIODICITY_VAL;
    ptrAdvFrameCfg->frameData.subframeDataCfg[0].numAdcSamples = PROFILE_MRR_ADC_SAMPLE_VAL*2;
    ptrAdvFrameCfg->frameData.subframeDataCfg[0].totalChirps   = SUBFRAME_MRR_NUM_CHIRPS_TOTAL;
    ptrAdvFrameCfg->frameData.subframeDataCfg[0].numChirpsInDataPacket = 1;
    numOfSubFrame++;

    /* The high resolution 20m subframe */
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].forceProfileIdx    = 0;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].numLoops           = SUBFRAME_USRR_LOOP_COUNT;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].numOfBurst         = 1;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].numOfBurstLoops    = 1;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].chirpStartIdxOffset= 0;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].numOfChirps        = SUBFRAME_USRR_CHIRP_END_IDX - SUBFRAME_USRR_CHIRP_START_IDX + 1;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].chirpStartIdx      = SUBFRAME_USRR_CHIRP_START_IDX;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].subFramePeriodicity= SUBFRAME_USRR_PERIODICITY_VAL;
    ptrAdvFrameCfg->frameSeq.subFrameCfg[1].burstPeriodicity   = SUBFRAME_USRR_PERIODICITY_VAL;
    ptrAdvFrameCfg->frameData.subframeDataCfg[1].numAdcSamples = PROFILE_USRR_ADC_SAMPLE_VAL*2;
    ptrAdvFrameCfg->frameData.subframeDataCfg[1].totalChirps   = SUBFRAME_USRR_NUM_CHIRPS_TOTAL;
    ptrAdvFrameCfg->frameData.subframeDataCfg[1].numChirpsInDataPacket = 1;
    numOfSubFrame++;
#else
    #ifdef SUBFRAME_CONF_MRR
        /* The low resolution 80m subframe */
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].forceProfileIdx    = 0;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numLoops           = SUBFRAME_MRR_LOOP_COUNT;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfBurst         = 1;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfBurstLoops    = 1;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].chirpStartIdxOffset= 0;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfChirps        = SUBFRAME_MRR_CHIRP_END_IDX - SUBFRAME_MRR_CHIRP_START_IDX + 1;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].chirpStartIdx      = SUBFRAME_MRR_CHIRP_START_IDX;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].subFramePeriodicity= SUBFRAME_MRR_PERIODICITY_VAL;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].burstPeriodicity   = SUBFRAME_MRR_PERIODICITY_VAL;
        ptrAdvFrameCfg->frameData.subframeDataCfg[0].numAdcSamples = PROFILE_MRR_ADC_SAMPLE_VAL*2;
        ptrAdvFrameCfg->frameData.subframeDataCfg[0].totalChirps   = SUBFRAME_MRR_NUM_CHIRPS_TOTAL;
        ptrAdvFrameCfg->frameData.subframeDataCfg[0].numChirpsInDataPacket = 1;
        numOfSubFrame++;
    #else
    #ifdef SUBFRAME_CONF_USRR
        /* The high resolution 20m subframe */
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].forceProfileIdx    = 0;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numLoops           = SUBFRAME_USRR_LOOP_COUNT;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfBurst         = 1;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfBurstLoops    = 1;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].chirpStartIdxOffset= 0;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].numOfChirps        = SUBFRAME_USRR_CHIRP_END_IDX - SUBFRAME_USRR_CHIRP_START_IDX + 1;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].chirpStartIdx      = SUBFRAME_USRR_CHIRP_START_IDX;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].subFramePeriodicity= SUBFRAME_USRR_PERIODICITY_VAL;
        ptrAdvFrameCfg->frameSeq.subFrameCfg[0].burstPeriodicity   = SUBFRAME_USRR_PERIODICITY_VAL;
        ptrAdvFrameCfg->frameData.subframeDataCfg[0].numAdcSamples = PROFILE_USRR_ADC_SAMPLE_VAL;
        ptrAdvFrameCfg->frameData.subframeDataCfg[0].totalChirps   = SUBFRAME_USRR_NUM_CHIRPS_TOTAL;
        ptrAdvFrameCfg->frameData.subframeDataCfg[0].numChirpsInDataPacket = 1;
        numOfSubFrame++;
    #endif
    #endif
#endif
    ptrAdvFrameCfg->frameSeq.numOfSubFrames = numOfSubFrame;
    ptrAdvFrameCfg->frameData.numSubFrames  = numOfSubFrame;

    return;
}

首先说明一些frame的基本配置:

frameSeq.forceProfile:0  说明在chirp进行传输的时候要用profile中的配置
frameSeq.numFrames:0  说明frame是一直有,直到设备停止
frameSeq.triggerSelect:1 说明触发frame是软件中断,当调用rlSensorStart 这个API时,对帧进行触发,但是会有一定的延迟
frameSeq.frameTrigDelay:0 说明帧触发的延迟是0

由于在本程序中NUM_SUBFRAMES为1,说明只有一个subframe,且宏定义的是SUBFRAME_CONF_USRR,因此程序直接跳到下图:
在这里插入图片描述

frameSeq.subFrameCfg[0].forceProfileIdx:0 
frameSeq.subFrameCfg[0].numLoops:64 每个chirp在burst中循环的次数
frameSeq.subFrameCfg[0].numOfBurst:1 subframe中burst的数量
frameSeq.subFrameCfg[0].numOfBurstLoops:1 在subframe中burst中循环的次数
frameSeq.subFrameCfg[0].chirpStartIdxOffset:0
frameSeq.subFrameCfg[0].numOfChirps:3 每个burst中包含3个chirp
frameSeq.subFrameCfg[0].chirpStartIdx:128 chirp开始的ID
frameSeq.subFrameCfg[0].subFramePeriodicity:50ms 一个subframe持续的时间
frameSeq.subFrameCfg[0].burstPeriodicity:50ms 一个burst持续的时间
frameData.subframeDataCfg[0].numAdcSamples:256 ADC的采样数
frameData.subframeDataCfg[0].totalChirps:192 总共的chirp数
frameData.subframeDataCfg[0].numChirpsInDataPacket:1 将一个chirp打包发送到DSP

在frame中subFrame都为1

ptrAdvFrameCfg->frameSeq.numOfSubFrames = 1;
ptrAdvFrameCfg->frameData.numSubFrames  = 1;

关于案例中的profile、chirp、advframe已经解释完毕,下面用一个图来进行表示:
在这里插入图片描述
ok,本篇文章到这里就结束了

标签:profile,frameSeq,advframe,VAL,MRR,---,CHIRP,USRR,ptrAdvFrameCfg
来源: https://blog.csdn.net/Xiao_Jie123/article/details/111033834

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有