QS100连接onenet

这里只是把数据手册中使用到的重要部分摘取出来,数据手册可以去官方的qq群获取。项目还未完成后面只展示了连接onenet的代码。

项目源码地址:https://gitee.com/xiao-liu-harbors-dreams/locator.git

AT命令处理是参考:MCU 通用AT指令处理框架_at指令框架-CSDN博客这篇文章

rt-thread环形缓冲区代码:components/drivers/ipc/ringbuffer.c · RT-Thread/rt-thread - Gitee.com

一. 简介

  • QS-100 是一款基于芯翼 XY1100 的工业级 NB-IoT 无线通信模组,具有高性能、低功耗、多频段等多

    个产品优势,协议上完全兼容 R13 和 R14,软件升级支持 R15,内嵌 TCP、UDP、MQTT、COAP 等多种通

    信协议栈,支持中国移动 OneNET ,中国联通云和中国电信 IoT 物联网云平台,方便客户应用。

  • 发射功率:23dBm±2dB

  • 灵敏度:Band 3:-116dBm±1dB

    ​ Band 5/8:-117dBm±1dB

  • USIM 卡接口:自适应模式,支持 1.8/3.0V USIM 卡

  • 主串口: 全功能串口,用于 AT 指令发送,数据传输,自适应波特率:从 4800bps 到 115200bps

二. 关键参数

  • 通讯方式:可以通过串口发送AT指令进行相关操作。串口默认波特率9600

  • 复位和唤醒:通过GPIO控制RST_WAKE引脚的高低电平实现

    image-20251018134433746

  • 工作模式:

    image-20251018134254365

image-20251018151235243

  • 工作指示灯:

image-20251018152304944

  • 功耗:

image-20251018152424334

三. 代码

1. uart

串口接收这边用的是DMA+空闲中断+环形缓冲区进行接收的数据,

usart.c

volatile uint8_t uart_rx_flag = UART_RX_IDLE;
/* 串口映射表 */
static UART_HandleTypeDef *s_uartMap[] = 
{
    [UART_NUM_1] = NULL, 
    [UART_NUM_2] = NULL, 
    [UART_NUM_3] = &huart3,
};

struct rt_ringbuffer ringbuffer;                    /* 接收环形缓冲区 */ 
static uint8_t rx_buffer[UART_BUFFER_SIZE];         /* 接收缓冲区     */
uint8_t dma_rx_buffer[UART_BUFFER_SIZE];            /* DMA接收缓冲区  */ 

/**
 * @brief  获取串口接收环形缓冲区句柄
 * 
 * @param  无
 * 
 * @retval 环形缓冲区句柄
 */
struct rt_ringbuffer* get_ringbuffer_handler(void)
{ 
  return &ringbuffer;
}

/**
 * @brief  串口发送数据
 * 
 * @param  uart_num          串口编号
 * @param  tx_data           发送的数据
 * @param  tx_data_len       发送的数据长度        
 * 
 * @retval                   返回是否发送成功
 */
com_status_t uart_send_data(uint8_t  uart_num,
                            const uint8_t* tx_data, 
                            const uint16_t tx_data_len)
{ 
  /* 检查参数 */
  if (NULL == tx_data || 0 == tx_data_len)
  {
    return COM_ERROR;
  }
  if (UART_MAX_NUM <= uart_num || NULL == s_uartMap[uart_num]) 
  {
    return COM_ERROR;
  }

  /* 发送数据 */
  if(HAL_OK == HAL_UART_Transmit(s_uartMap[uart_num], 
                                 tx_data, 
                                 tx_data_len, 
                                 1000))
  {
    return COM_OK;
  }  
  else
  {
    return COM_ERROR;
  }  
}

/**
 * @brief  串口接收数据
 * 
 * @param  uart_num          串口编号
 * @param  rx_data           接收数据
 * @param  rx_data           接收数据长度
 * 
 * @retval                   返回是否接收成功
 */
com_status_t uart_recv_data(uint8_t  uart_num,
                            uint8_t* rx_data, 
                            size_t* rx_data_len)
{
  static uint16_t rx_buffer_len = 0;
  /* 检查参数 */
  if (NULL == rx_data || NULL == rx_data_len)
  {
    return COM_ERROR;
  }
  if (UART_MAX_NUM <= uart_num || NULL == s_uartMap[uart_num]) 
  {
    return COM_ERROR;
  }

  /* 接收数据 */
  if(uart_num == UART_NUM_3 && UART_RX_OK == uart_rx_flag)
  {
    uart_rx_flag = UART_RX_IDLE;
    rx_buffer_len = rt_ringbuffer_data_len(&ringbuffer);
    if(rx_buffer_len > 0)
    {
        rt_ringbuffer_get(&ringbuffer, rx_data, rx_buffer_len);
        *rx_data_len = rx_buffer_len;
        // debug_println("uart_recv:%s, %d", rx_data, *rx_data_len);
        // HAL_Delay(200);
        return COM_OK;
    }
  }    
  return COM_TIMEOUT;
}
/* 串口中断接收回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  static uint8_t recv_total_size = 0;
  static uint8_t current_recv_size = 0;
  if(huart == &huart3)
  {
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
    {
      __HAL_UART_CLEAR_IDLEFLAG(huart);
      uart_rx_flag = UART_RX_OK;
      recv_total_size = UART_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
      current_recv_size = recv_total_size - last_rx_size;
      rt_ringbuffer_put(&ringbuffer, 
                        &dma_rx_buffer[last_rx_size], 
                        current_recv_size);
      last_rx_size = recv_total_size;
    }
  }  
}
/* DMA 半满中断回调函数  */
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
  static uint8_t recv_total_size = 0;
  static uint8_t current_recv_size = 0;
  if(huart == &huart3)
  {
    recv_total_size = UART_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
    current_recv_size = recv_total_size - last_rx_size;
    rt_ringbuffer_put(&ringbuffer, 
                      &dma_rx_buffer[last_rx_size], 
                      current_recv_size);
    last_rx_size = recv_total_size;
  }  
}
/* DMA 全满中断回调函数  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  static uint8_t current_recv_size = 0;
  if(huart == &huart3)
  {
    current_recv_size = UART_BUFFER_SIZE - last_rx_size;
    rt_ringbuffer_put(&ringbuffer, 
                      &dma_rx_buffer[last_rx_size], 
                      current_recv_size);
    last_rx_size = 0;
  }  
}

usart.h

#define UART_BUFFER_SIZE   256	   /* 缓冲区大小 */

/* 串口号  */
typedef enum 
{
    UART_NUM_1 = 1,          /* 串口1       */
    UART_NUM_2 = 2,          /* 串口2       */
    UART_NUM_3 = 3,          /* 串口3       */
    UART_MAX_NUM             /* 最大串口数量 */
} uart_num_t;

typedef enum 
{
    UART_RX_OK = 0,          /* 接收成功    */ 
    UART_RX_IDLE,            /* 未在接收    */ 
} UART_RxStatus_t;
/**
 * @brief  获取串口接收环形缓冲区句柄
 * 
 * @param  无
 * 
 * @retval 环形缓冲区句柄
 */
struct rt_ringbuffer* get_ringbuffer_handler(void);

/**
 * @brief  串口发送数据
 * 
 * @param  uart_num          串口编号
 * @param  tx_data           发送的数据
 * @param  tx_data_len       发送的数据长度        
 * 
 * @retval                   返回是否发送成功
 */
com_status_t uart_send_data(uint8_t  uart_num,
                            const uint8_t* tx_data, 
                            const uint16_t tx_data_len);

/**
 * @brief  串口接收数据
 * 
 * @param  uart_num          串口编号
 * @param  rx_data           接收数据
 * @param  rx_data           接收数据长度
 * 
 * @retval                   返回是否接收成功
 */
com_status_t uart_recv_data(uint8_t  uart_num,
                            uint8_t* rx_data, 
                            size_t* rx_data_len);

2. AT命令处理

freertos和透传部分没有使用也没有进行修改,还未测试,此次用到是裸机处理命令发送,接收以及处理URC。
AT响应的处理流程大概是下图这样

image-20251109212800069

Com_at.c

#include "Com_at.h"

/**
 * @brief 处理命令响应
 * 
 * @param client             AT客户端
 * 
 * @return com_status_t      命令处理结果
 */
static com_status_t at_process_command_response(at_client_t* client, 
                                                uint8_t* response_line)
{
    /* 获取互斥锁 */ 
    #ifdef USE_FREERTOS
    xSemaphoreTake(client->xATControlMutex, pdMAX_DELAY);
    #endif
    /* 检查期望响应 */
    if (NULL != strstr((const char*)response_line, 
                       (const char*)client->cmd_param.expect)) 
    {
        // debug_println("接收响应成功");
        client->cmd_in_progress = false;
        return client->cmd_param.handler(response_line, 
                                         client->cmd_param.output);
    } 
    else if (NULL != strstr((const char*)response_line, 
                            "OK"))                     
    { 
        client->cmd_in_progress = false;
        // debug_println("接收响应成功");
        return COM_OK;
    }
    /* 检查错误响应 */
    else if (NULL != strstr((const char*)response_line, 
                            "ERROR"))                     
    {
        debug_println("接收响应失败");
        client->cmd_in_progress = false;
        client->error_handler(response_line);
        return COM_ERROR;
    } 
    else
        return COM_TIMEOUT;
}

/**
 * @brief 处理URC
 * 
 * @param client             AT客户端
 * 
 * @return com_status_t      URC处理结果
 */
static com_status_t at_process_urc(at_client_t* client, 
                                   uint8_t* response_line)
{
    urc_entry_t* entry = NULL;          /* URC条目  */
    debug_println("开始处理URC %s", response_line);
    for (size_t i = 0; i < client->urc_count; i++) 
    {
        entry = &client->urc_table[i];
        if (NULL == strstr((const char*)response_line, 
                            (const char*)entry->prefix)) 
        {
            continue;
        }    
        if(COM_OK == entry->handler(entry->context, 
                                    response_line))
        {
            // debug_println("URC请求处理完成");
            return COM_OK;
        }
        else
        {
            debug_println("URC请求处理失败");
            return COM_ERROR;
        }    
    }
    debug_println("接收URC超时 :%s", response_line);
    return COM_TIMEOUT;
}

/**
 * @brief  处理普通模式命令
 * 
 * @param client             AT客户端实例
 * 
 * @return com_status_t      命令处理结果
 */
static com_status_t at_process_general(at_client_t* client) 
{
    static uint8_t* response_start = NULL;     /* 响应起始 */
    static uint8_t* response_end = NULL;       /* 响应结束 */
    com_status_t com_status = COM_OK;

    /* 获取互斥锁 */ 
    #ifdef USE_FREERTOS
    xSemaphoreTake(client->xATControlMutex, pdMAX_DELAY);
    #endif

    /* 检查参数  */
    if(NULL == client)
        return COM_ERROR;

    if(AT_MODE_GENERAL != client->at_mode)
        return COM_ERROR;

    /* 获取响应起始 */
    response_start = client->uart_config.rx_buf;
    
    do
    {
        /* 查找是否有多个响应 */
        response_end = (uint8_t*)strstr((const char*)response_start, 
                                        "\r\n\r\n");
        /* 每次只处理一条响应 */
        if(NULL != response_end)
        {
            *response_end = '\0';
        }     

        /* 1. 检查是否有正在发送的命令 */
        if (true == client->cmd_in_progress) 
        {
            com_status = at_process_command_response(client, response_start);
            /* 没有处理完继续检查urc */
            if(true == client->cmd_in_progress)
            {
                at_process_urc(client, response_start);
            }
        }
        /* 2. 检查URC */ 
        else
        {
            at_process_urc(client, response_start);
        }

        /* 没有响应退出 */
        if(response_end == NULL)
            break;

        /* 恢复原数据 */
        *response_end = '\r';

        /* 移动响应指针   */
        response_start = response_end + 2;
        response_end = NULL;
    }while(1);

    if(true == client->cmd_in_progress)
    {
        debug_println("接收响应超时");
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_TIMEOUT;
    }
    
    #ifdef USE_FREERTOS
    xSemaphoreGive(client->xATControlMutex);
    #endif
    
    return com_status;
}

/**
 * @brief  AT服务任务
 * 
 * @param  arg               创建任务时传递的参数
 * 
 * @return 无
 */
void at_service_task(void* arg) 
{
    at_client_t* client = (at_client_t*)arg;

    // while(1)
    // {
        memset(client->uart_config.rx_buf, 
               0, 
               client->uart_config.rx_buf_size);
        client->uart_config.rx_len = 0;

        #ifdef USE_FREERTOS
        /* 等待数据接收完成 */
        xSemaphoreTake(client->xBinarySemaphorRecvMsg, pdMAX_DELAY);
        #endif

        /* 接收数据       */
        if(COM_OK != client->uart_recv_data(client->uart_config.uart_port, 
                                            client->uart_config.rx_buf, 
                                            &client->uart_config.rx_len))
        {
            // continue;
            return;
        }    
        
        // debug_println("uart_recv_data: %s", client->uart_config.rx_buf);

        if (AT_MODE_GENERAL == client->at_mode) 
        {
            /* 普通模式处理 */ 
            at_process_general(client);
            client->cmd_in_progress = false;
        } 
        else 
        {
            /* 透传模式处理 */ 
            if (client->pass_through_param.data_cb) 
            {
                client->pass_through_param.data_cb(client);
            }
        }
    // }
}

/**
 * @brief  AT命令发送
 * 
 * @param  client            AT客户端实例
 * @param  at_cmd_param_t    AT命令参数
 * @param  retries           重试次数
 * 
 * @return 是否发送成功 
 */
com_status_t at_cmd_send(at_client_t* client)
{
    #ifdef USE_FREERTOS
    /* 获取互斥锁 */ 
    xSemaphoreTake(client->xATControlMutex, pdMAX_DELAY);
    #endif

    /* 检查参数   */
    if(NULL == client)
    {
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_ERROR;
    }    

    if(AT_MODE_GENERAL != client->at_mode)
        return COM_ERROR;

    /* 检查是否已有命令在执行 */ 
    if (true == client->cmd_in_progress) 
    {
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_BUSY;
    }

    client->cmd_in_progress = true;

    /* 清空接收缓存 */
    client->uart_config.rx_len = 0;
    memset(client->uart_config.rx_buf, 
           0, 
           client->uart_config.rx_buf_size);

    do
    {
        #ifdef USE_FREERTOS
        vTaskDelay(300);
        #else
        Com_delay_ms(300);
        #endif
        /* 发送命令 */ 
        if(COM_OK != client->uart_send_data(client->uart_config.uart_port, 
                                            (const uint8_t*)client->cmd_param.cmd, 
                                            strlen((const char*)client->cmd_param.cmd)))
        {
            continue;
        }
        /* 等待响应 */
        #ifdef USE_FREERTOS
        if(pdTRUE != xSemaphoreTake(client->xBinarySemaphorRecvMsg, 
                                    client->cmd_param.timeout))
        {
            vTaskDelay(300);
            continue;
        }
        #endif
        Com_delay_ms(client->cmd_param.timeout);

        /* 接收响应 */
        if(COM_OK != client->uart_recv_data(client->uart_config.uart_port, 
                                            client->uart_config.rx_buf, 
                                            &client->uart_config.rx_len))
        {
             continue;
        }    

        /* 处理响应 */ 
        if(COM_OK == at_process_general(client))
        {
            break;
        }
        debug_println("retry...%d", client->cmd_param.retries);
    } while (--client->cmd_param.retries);

    /* 命令处理完成 */ 
    client->cmd_in_progress = false;
    
    #ifdef USE_FREERTOS
    xSemaphoreGive(client->xATControlMutex);
    #endif

    if(client->cmd_param.retries > 0)
        return COM_OK;
    else 
        return COM_ERROR;     
}

/**
 * @brief  注册URC实现
 * 
 * @param  client            AT客户端实例
 * @param  entry             URC条目
 * 
 * @return 是否注册成功 
 */
com_status_t at_register_urc(at_client_t* client, 
                             urc_entry_t *entry)
{
    urc_entry_t* urc_entry = NULL;
    #ifdef USE_FREERTOS
    /* 获取互斥锁 */
    xSemaphoreTake(client->xATControlMutex, pdMAX_DELAY);
    #endif

    /* 检查参数  */
    if (NULL == client 
        || NULL == entry
        || NULL == entry->prefix 
        || NULL == entry->handler) 
        return COM_ERROR;
    
    /* 检查是否已存在 */
    for (size_t i = 0; i < client->urc_count; i++) 
    {
        if (0 == memcmp(client->urc_table[i].prefix, 
                        entry->prefix, 
                        strlen((const char*)client->urc_table[i].prefix))) 
        {
            /* 存在则更新 */ 
            client->urc_table[i].handler = entry->handler;
            client->urc_table[i].context = entry->context;
            #ifdef USE_FREERTOS
            xSemaphoreGive(client->xATControlMutex);
            #endif
            return COM_OK;
        }
    }
    
    /* 不存在则添加 */ 
    if (client->urc_count < client->urc_table_size) 
    {
        urc_entry = &client->urc_table[client->urc_count++];
        urc_entry->prefix = entry->prefix;
        urc_entry->handler = entry->handler;
        urc_entry->context = entry->context;
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_OK;
    }
    
    #ifdef USE_FREERTOS
    xSemaphoreGive(client->xATControlMutex);
    #endif
    return COM_ERROR;
}

/**
 * @brief  进入透传模式实现
 * 
 * @param  client        AT客户端实例
 * @param  param         透传参数
 * 
 * @return 返回是否进入成功 
 */
com_status_t at_enter_pass_through_mode(at_client_t* client, 
                                               at_pass_through_param_t* paramt) 
{
    #ifdef USE_FREERTOS
    xSemaphoreTake(client->xATControlMutex, portMAX_DELAY);
    #endif

    /* 检查参数 */
    if (NULL == client
        || NULL == paramt
        || NULL == paramt->data_cb
        || NULL == paramt->data_context)
    {
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_ERROR;
    }    
    
    client->at_mode = AT_MODE_PassThrough;
    client->pass_through_param.data_cb = paramt->data_cb;
    client->pass_through_param.data_context = paramt->data_context;
    
    #ifdef USE_FREERTOS
    xSemaphoreGive(client->xATControlMutex);
    #endif

    return COM_OK;
}

/**
 * @brief  退出透传模式实现
 * 
 * @param  client            AT客户端实例
 * 
 * @return 无
 */
com_status_t at_exit_pass_through_mode(at_client_t* client) 
{
    #ifdef USE_FREERTOS
    xSemaphoreTake(client->xATControlMutex, portMAX_DELAY);
    #endif

    /* 检查参数 */
    if(NULL == client)
    {
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_ERROR;
    }

    client->at_mode = AT_MODE_GENERAL;
    client->pass_through_param.data_cb = NULL;
    client->pass_through_param.data_context = NULL;
    
    #ifdef USE_FREERTOS
    xSemaphoreGive(client->xATControlMutex);
    #endif

    return COM_OK;
}

/**
 * @brief  透传模式发送数据实现
 * 
 * @param  client            AT客户端实例
 * @param  data              数据
 * @param  len               数据长度
 * 
 * @return 返回是否发送成功 
 */
com_status_t at_send_data(at_client_t* client, 
                          const uint8_t* data, 
                          size_t len) 
{ 
    com_status_t com_status = COM_ERROR;
    #ifdef USE_FREERTOS
    xSemaphoreTake(client->xATControlMutex, portMAX_DELAY);
    #endif

    /* 检查参数 */
    if (NULL == client 
        || NULL == data 
        || 0 == len) 
    {
        #ifdef USE_FREERTOS
        xSemaphoreGive(client->xATControlMutex);
        #endif
        return COM_ERROR;
    }

    /* 发送数据 */
    if (AT_MODE_PassThrough == client->at_mode) 
        com_status = client->uart_send_data(client->uart_config.uart_port, 
                                        data, 
                                        strlen((const char*)data));    
    #ifdef USE_FREERTOS
    xSemaphoreGive(client->xATControlMutex);
    #endif
    
    return com_status;
}

/**
 * @brief  创建AT客户端实例
 * 
 * @param  uart_port         UART端口
 * @param  default_timeout   默认超时时间
 * @param  rx_buf_size       接收缓冲区大小
 * @param  urc_table_size    URC条目数量
 * 
 * @return 返回AT客户端实例 
 */
at_client_t* at_client_create(uint8_t uart_port,
                              size_t rx_buf_size, 
                              size_t urc_table_size) 
{
    at_client_t* client = calloc(1, sizeof(at_client_t));

    if (NULL == client) 
        return NULL;
    
    /* 串口配置          */ 
    client->uart_config.uart_port = uart_port;
    client->uart_config.rx_buf_size = rx_buf_size;
    client->uart_config.rx_buf = calloc(1, rx_buf_size);

    /* 串口发送和接收方法 */
    client->uart_send_data = NULL;
    client->uart_recv_data = NULL;

    /* 错误处理方法      */
    client->error_handler  = NULL;
    
    /* 状态变量初始化    */ 
    client->cmd_in_progress = false;
    client->at_mode = AT_MODE_GENERAL;
    
    /* 创建URC表        */ 
    client->urc_table_size = urc_table_size;
    client->urc_table = calloc(1, 
                               client->urc_table_size * sizeof(urc_entry_t));
    if (NULL == client->urc_table) 
    {
        free(client->uart_config.rx_buf);
        free(client);
        return NULL;
    }
    client->urc_count = 0;

    
    #ifdef USE_FREERTOS
    /* 创建RTOS资源      */ 
    client->xATControlMutex = xSemaphoreCreateMutex();              /* AT控制互斥锁 */ 
    client->xBinarySemaphorRecvMsg = xSemaphoreCreateBinary();      /* 串口接收二值信号量 */ 

    if (NULL == client->xATControlMutex)
    {
        free(client->uart_config.rx_buf);
        free(client->urc_table);
        free(client);
        return NULL;
    }
    if (NULL == client->xBinarySemaphorRecvMsg)
    {
        vSemaphoreDelete(client->xMutexSendMsg);
        free(client->uart_config.rx_buf);
        free(client->urc_table);
        free(client);
        return NULL;
    }
    #endif

    return client;
}

/**
 * @brief  销毁AT客户端实例
 * 
 * @param  client            AT客户端实例
 * 
 * @return void
 */
void at_client_destroy(at_client_t* client) 
{
    #ifdef USE_FREERTOS
    xSemaphoreTake(client->xATControlMutex, pdMAX_DELAY);
    #endif

    if (NULL == client) 
        return;
    
    #ifdef USE_FREERTOS
    /* 停止服务任务 */ 
    if (NULL != client->task_handle) 
    {
        vTaskDelete(client->task_handle);
        client->task_handle = NULL;
    }
    #endif

    #ifdef USE_FREERTOS
    /* 释放RTOS资源 */ 
    if(NULL != xATCotrolMutex)
        vSemaphoreDelete(client->xATCotrolMutex);
    if(NULL != xBinarySemaphorRecvMsg)
        vSemaphoreDelete(client->xBinarySemaphorRecvMsg);
    #endif

    /* 释放接收缓冲区 */ 
    if (NULL != client->uart_config.rx_buf) 
        free(client->uart_config.rx_buf);
    
    /* 释放URC表     */ 
    if (NULL != client->urc_table) 
        free(client->urc_table);
    
    /* 释放实例      */
    free(client);
}
/**
 * @brief  启动AT服务任务
 * 
 * @param  client            AT客户端实例
 * 
 * @return                   是否启动成功 
 */
com_status_t at_client_start(at_client_t* client) 
{
    #ifdef USE_FREERTOS
    BaseType_t result = pdFAIL;
    xSemaphoreTake(client->xATControlMutex, pdMAX_DELAY);

    if(NULL == client)
        return COM_ERROR;

    /* 创建服务任务 */
    result = xTaskCreate(
        at_service_task,              /* 任务函数 */ 
        "AT_Service",                 /* 任务名 */ 
        configMINIMAL_STACK_SIZE * 4, /* 栈大小 */ 
        client,                       /* 参数 */ 
        tskIDLE_PRIORITY + 2,         /* 优先级 */ 
        &client->task_handle          /* 任务句柄 */ 
    );
    if(pdPASS == result)
    {
        xSemaphoreGive(client->xATControlMutex);
        return COM_OK;
    }    
    else
    {
        xSemaphoreGive(client->xATControlMutex);
        return COM_ERROR;
    }    
    #endif
    return COM_OK;
}

Com_at.h

#ifndef COM_AT_H
#define COM_AT_H

/* 用来启用匿名结构体 */
#pragma anon_unions

#ifdef USE_FREERTOS
#include "FreeRTOS.h"
#include "semphr.h"
#endif

#include "string.h"
#include "stdlib.h"

#include "stm32f1xx_hal.h"

#include "Com_Debug.h"
#include "com_config.h"
#include "Com_tool.h"

struct at_client;

/* 串口发送数据函数据 */
typedef com_status_t (*uart_send_data_t)(uint8_t  uart_num,
                                         const uint8_t* tx_data, 
                                         const uint16_t tx_data_len);

/* 串口接收数据函数据 */
typedef com_status_t (*uart_recv_data_t)(uint8_t  uart_num,
                                         uint8_t* rx_data, 
                                         size_t* rx_data_len);

/* 错误处理函数类型 */
typedef void (*error_handler_t)(uint8_t* response_line);  

/* 响应解析函数类型 */
typedef com_status_t (*response_handler_t)(uint8_t* response_line, 
                                           void* output_param);  
 
/* URC处理函数类型 */ 
typedef com_status_t (*urc_handler_t)(void* context, 
                                      const uint8_t* urc);

/* 透传数据接收回调类型 */ 
typedef void (*data_receive_cb_t)(void* context);

typedef enum 
{
    false = 0,
    true = 1
} bool;

/* at接收模式 */
typedef enum 
{
    AT_MODE_GENERAL,            /* 普通模式         */
    AT_MODE_PassThrough         /* 透传模式         */
} at_mode_t;

/* URC注册项 */ 
typedef struct 
{
    uint8_t* prefix;            /* URC前缀          */ 
    urc_handler_t handler;      /* 处理函数          */ 
    void* context;              /* 上下文指针        */ 
} urc_entry_t;

/*  UART配置参数 */
typedef struct 
{
    uint8_t uart_port;          /* UART端口号        */ 
    uint8_t* rx_buf;            /* UART接收缓冲区    */ 
    size_t rx_buf_size;         /* UART接收缓冲区大小 */ 
    size_t rx_len;              /* 已接收长度        */ 
} uart_config_t; 

/*  AT命令参数 */
typedef struct
{
    const uint8_t* cmd;         /* 命令             */ 
    const uint8_t* expect;      /* 期望响应         */
    uint32_t timeout;           /* 接收超时时间      */  
    uint8_t retries;            /* 重试次数         */
    void* output;               /* 输出参数         */
    response_handler_t handler; /* 响应处理函数      */
} at_cmd_param_t;

/* AT 透传参数 */
typedef struct
{
    data_receive_cb_t data_cb;  /* 数据接收回调      */ 
    void* data_context;         /* 数据回调上下文    */ 
} at_pass_through_param_t; 

/* AT客户端对象 */ 
typedef struct at_client 
{
    /* 串口配置参数 */ 
    uart_config_t uart_config;
    /* at 模式 */ 
    at_mode_t at_mode;   
    /* 命令执行中标志   */ 
    bool cmd_in_progress;       

    union 
    {
        /* 命令参数 */ 
        at_cmd_param_t cmd_param;
        /* 透传参数 */ 
        at_pass_through_param_t pass_through_param;
    } ;
    
    /* URC处理 */ 
    urc_entry_t* urc_table;                        /* URC注册表         */ 
    size_t urc_table_size;                         /* URC表大小         */ 
    size_t urc_count;                              /* 已注册URC数量      */ 

    /* RTOS资源 */ 
    #ifdef USE_FREERTOS
    SemaphoreHandle_t xATControlMutex;             /* AT控制互斥锁      */ 
    SemaphoreHandle_t xBinarySemaphorRecvMsg;      /* 串口接收二值信号量 */ 
    TaskHandle_t task_handle;                      /* 任务句柄 */ 
    #endif

    /* 串口发送数据      */ 
    uart_send_data_t uart_send_data;     
    /* 串口接收数据      */          
    uart_recv_data_t uart_recv_data;    
    /* 错误处理         */
    error_handler_t error_handler; 
} at_client_t;


/**
 * @brief  AT命令发送
 * 
 * @param  client              AT客户端实例
 * @param  at_cmd_param_t      AT命令参数
 * @param  retries             重试次数
 * 
 * @return 是否发送成功 
 */
com_status_t at_cmd_send(at_client_t* client);

/**
 * @brief  注册URC实现
 * 
 * @param  client            AT客户端实例
 * @param  entry             URC条目
 * 
 * @return 是否注册成功 
 */
com_status_t at_register_urc(at_client_t* client, 
                             urc_entry_t *entry);

/**
 * @brief  进入透传模式实现
 * 
 * @param  client            AT客户端实例
 * @param  param         透传参数
 * 
 * @return 返回是否进入成功 
 */
com_status_t at_enter_pass_through_mode(at_client_t* client, 
                                        at_pass_through_param_t* paramt);

/**
 * @brief  退出透传模式实现
 * 
 * @param  client            AT客户端实例
 * 
 * @return 无
 */
com_status_t at_exit_pass_through_mode(at_client_t* client);

/**
 * @brief  透传模式发送数据实现
 * 
 * @param  client            AT客户端实例
 * @param  data              数据
 * @param  len               数据长度
 * 
 * @return 返回是否发送成功 
 */
com_status_t at_send_data(at_client_t* client, 
                          const uint8_t* data, 
                          size_t len);

/**
 * @brief  创建AT客户端实例
 * 
 * @param  uart_port         UART端口
 * @param  default_timeout   默认超时时间
 * @param  rx_buf_size       接收缓冲区大小
 * @param  urc_table_size    URC条目数量
 * 
 * @return 返回AT客户端实例 
 */
at_client_t* at_client_create(uint8_t uart_port,
                              size_t rx_buf_size, 
                              size_t urc_table_size);

/**
 * @brief  销毁AT客户端实例
 * 
 * @param  client            AT客户端实例
 * 
 * @return void
 */
void at_client_destroy(at_client_t* client);

/**
 * @brief  启动AT服务任务
 * 
 * @param  client            AT客户端实例
 * 
 * @return                   是否启动成功 
 */
com_status_t at_client_start(at_client_t* client);

/**
 * @brief  AT服务任务
 * 
 * @param  arg               创建任务时传递的参数
 * 
 * @return 无
 */
void at_service_task(void* arg);

#endif

3. Int_QS100.c

#include "Int_QS100.h"

/* onenet 网络通信套件实例标识 */
static uint8_t onenet_instance = 0xFF; 

/* AT 命令表 */
static const at_cmd_t g_at_cmd_table[] = 
{ 
    // 索引             测试命令                     设置命令                        查询命令            执行命令         响应前缀          说明
    {AT_CMD_RB,        NULL,                 NULL,                               NULL,                "AT+RB\r\n",     "REBOOTING",   "设备软重启"           },
    {AT_CMD_CGATT,     "AT+CGATT=?\r\n",     "AT+CGATT=%d\r\n",                  "AT+CGATT?\r\n",     NULL,            "+CGATT:",     "PS附着/去附着"        },
    {AT_CMD_CSQ,       "AT+CSQ=?\r\n",       NULL,                               "AT+CSQ\r\n",        NULL,            "+CSQ:",       "获得信号强度指示"     },
    {AT_CMD_ATE,       NULL,                 "ATE1\r\n",                         NULL,                NULL,            "OK",          "开启串口回显"         },
    {AT_CMD_COPS,      "AT+COPS=?\r\n",      "AT+COPS=%d,%d,\"%s\",%d\r\n",      "AT+COPS?\r\n",      NULL,            "+COPS:",      "运营商选择"           },
    {AT_CMD_CGDCONT,   "AT+CGDCONT=?\r\n",   "AT+CGDCONT=%d,\"%s\",\"%s\"\r\n",  "AT+CGDCONT?\r\n" ,  NULL,            "+CGDCONT:",   "定义PDP上下文"        },
    {AT_CMD_CGACT,     "AT+CGACT=?\r\n",     "AT+CGACT=%d,%d\r\n",               "AT+CGACT?\r\n",     NULL,            "+CGACT",      "PDP上下文激活/去激活" },
    {AT_CMD_CPIN,      "AT+CPIN=?\r\n",      "AT+CPIN=\"%s\"\r\n",               "AT+CPIN?\r\n",      NULL,            "+CPIN:",      "PIN码输入与管理"      },
    {AT_CMD_CEREG,     "AT+CEREG=?\r\n",     "AT+CEREG=%d\r\n",                  "AT+CEREG?\r\n",     NULL,            "+CEREG:",     "EPS网络注册状态"      },
    {AT_CMD_NTSETID,   NULL,                 "AT+NTSETID=1,%s\r\n",              NULL,                NULL,            "OK",          "设置IMEI号"           },
    {AT_CMD_NCCID,     NULL,                 NULL,                               "AT+NCCID?\r\n",     NULL,            "+NCCID:",     "查询SIM卡ID"          },
    {AT_CMD_CGSN,      "AT+CGSN=?\r\n",      NULL,                               "AT+CGSN=%d\r\n",    NULL,            "+CGSN:",      "获取产品序列号"       },
    {AT_CMD_CIMI,      NULL,                 NULL,                               "AT+CIMI\r\n",       NULL,            "+CIMI:",      "获取IMSI号"           },
    {AT_CMD_NV,        "AT+NV=?\r\n",        "AT+NV=SET,%s,%s\r\n",              "AT+NV=GET,%s\r\n", "AT+NV=SAVE\r\n", "REBOOTING",   "NV参数动态配置"       },
    {AT_CMD_FASTOFF,   "AT+FASTOFF=?\r\n",   "AT+FASTOFF=%d\r\n",                 NULL,               NULL,            "OK",          "快速断电"             },
    {AT_CMD_WORKLOCK,  NULL,                 "AT+WORKLOCK=%d\r\n",               "AT+WORKLOCK?\r\n",  NULL,            "+WORKLOCK:",  "省电锁"               },
    {AT_CMD_CEDRXRDP,  NULL,                 NULL,                               "AT+CEDRXRDP\r\n",   NULL,            "+CEDRXRDP:",  "读取扩展DRX动态参数"  },
    {AT_CMD_NPTWEDRXS, "AT+NPTWEDRXS=?\r\n", "AT+NPTWEDRXS=%hhu,%hhu,%s,%s\r\n", "AT+NPTWEDRXS?\r\n", NULL,            "+NPTWEDRXS:", "寻呼时间窗及eDRX设置" },
    {AT_CMD_CPSMS,     "AT+CPSMS=?\r\n",     "AT+CPSMS=%d,,,%s,%s\r\n",          "AT+CPSMS?\r\n",     NULL,            "+CPSMS:",     "省电模式PSM设置"      },
    {AT_CMD_CRTDCP,    "AT+CRTDCP=?\r\n",    "AT+CRTDCP=%d\r\n",                 "AT+CRTDCP?\r\n",    NULL,            "+CRTDCP:",    "下行数据主动上报设置" },
    {AT_CMD_XNTP,      NULL,                 "AT+XNTP=%s\r\n",                   NULL,                NULL,            "+XNTP:",      "查询NTP时间"         },
};


/* QS100 请求回调函数 */
static QS100_DISCOVER_callback gs_qs100_discover_callback = NULL; 
static QS100_OBSERVE_callback gs_qs100_observe_callback = NULL;
static QS100_READ_callback gs_qs100_read_callback = NULL;
static QS100_WRITE_callback gs_qs100_write_callback = NULL;
static QS100_EXECUTE_callback gs_qs100_execute_callback = NULL;
static QS100_PARAMETER_callback gs_qs100_parameter_callback = NULL;
static QS100_EVENT_callback gs_qs100_event_callback = NULL;
static QS100_NPTWEDRXP_callback gs_qs100_nptwedrxp_callback = NULL;
static QS100_POWERON_callback gs_qs100_poweron_callback = NULL;
static QS100_SIMST_callback gs_qs100_simst_callback = NULL;

/**
 * @brief  获取命令字符串
 * 
 * @param  cmd_index         命令索引
 * @param  cmd_type          命令类型
 * 
 * @return 返回命令
 */
const uint8_t *get_at_cmd_string(at_cmd_index_t cmd_index, at_cmd_type_t cmd_type) 
{
    /* 超出命令范围退出         */
    if(AT_CMD_MAX < cmd_index)
        return NULL;

    /* 根据命令类型返回相应的命令 */
    switch (cmd_type) 
    {
        case AT_CMD_TEST:    
            return g_at_cmd_table[cmd_index].testCmd;
        case AT_CMD_SET:     
            return g_at_cmd_table[cmd_index].setCmd;
        case AT_CMD_READ:   
            return g_at_cmd_table[cmd_index].readCmd;
        case AT_CMD_EXECUTE: 
            return g_at_cmd_table[cmd_index].executeCmd;
        default: 
            return NULL;
    }
}

/**
 * @brief  获取命令前缀
 * 
 * @param  cmd_index         命令索引
 * 
 * @return 命令前缀
 */
const uint8_t *get_at_response_prefix(at_cmd_index_t cmd_index) 
{
    /* 超出命令范围退出         */
    if(AT_CMD_MAX < cmd_index)
        return NULL;

    /* 返回命令前缀            */
    return NULL;
}

/**
 * @brief  QS100 错误处理函数
 * 
 * @param  response_line       错误响应行
 * 
 * @retval 无
 */
static void error_handler(uint8_t* response_line)
{
    debug_println("err: %s", response_line);
}

/**
 * @brief  QS100 将PTW转换为二进制字符串
 * 
 * @param  PTW               寻呼时间窗口
 * 
 * @retval 返回ptw字符串
 */
const uint8_t* PTW_to_bin_str(PTW_t ptw) 
{
    static const uint8_t* bin_strings[] = 
    {
        "0000", "0001", "0010", "0011",
        "0100", "0101", "0110", "0111", 
        "1000", "1001", "1010", "1011",
        "1100", "1101", "1110", "1111"
    };
    return bin_strings[ptw];
}

/**
 * @brief  QS100 将eDRX转换为二进制字符串
 * 
 * @param  cycle             eDRX周期
 * 
 * @retval 返回eDRX字符串
 */
const uint8_t* eDRX_to_bin_str(eDRX_cycle_t cycle) 
{
    static const uint8_t* bin_strings[] = 
    {
        [EDRX_CYCLE_20_48_S]    = "0010",
        [EDRX_CYCLE_40_96_S]    = "0011", 
        [EDRX_CYCLE_81_92_S]    = "0101",
        [EDRX_CYCLE_163_84_S]   = "1001",
        [EDRX_CYCLE_327_68_S]   = "1010",
        [EDRX_CYCLE_655_36_S]   = "1011",
        [EDRX_CYCLE_1310_72_S]  = "1100",
        [EDRX_CYCLE_2621_44_S]  = "1101",
        [EDRX_CYCLE_5242_88_S]  = "1110",
        [EDRX_CYCLE_10485_76_S] = "1111"
    };
    return bin_strings[cycle];
}

/**
 * @brief  QS100 获取onenet 实例标识
 * 
 * @param  无
 * 
 * @retval 返回实例标识
 */
uint8_t QS100_get_onenet_instance(void)
{
    return onenet_instance;
}

/**
 * @brief  QS100 通用响应解析
 * 
 * @param  response_line     响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t general_response_handler(uint8_t* response_line, 
                                             void* output_param)
{
    if(NULL != strstr((char*)response_line, 
                      QS100_RESPONSE_OK))
    {
        debug_println("接收:%s.", response_line);
        return COM_OK;
    }    
    else if(NULL != strstr((char*)response_line, 
                           QS100_RESPONSE_ERROR))
    {
        debug_println("响应错误:%s", response_line);  
        return COM_ERROR; 
    }    
    else
    {
        debug_println("正在接收:%s", response_line);
        return COM_TIMEOUT;
    } 
}

/**
 * @brief  QS100 打印响应处理
 * 
 * @param  response_line     响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t print_response_handler(uint8_t* response_line, 
                                           void* output_param)
{
    if(NULL != response_line)
        debug_println("响应:%s", response_line);
    return COM_OK;
}

/**
 * @brief  QS100 处理重启命令响应
 * 
 * @param  response          响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t REBOOTING_response_handler(uint8_t* response_line, 
                                               void* output_param)
{
    debug_println("重启成功");
    return COM_OK;
}

/**
 * @brief  QS100 处理保存命令响应
 * 
 * @param  response_line     响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t NV_SAVE_response_handler(uint8_t* response_line, 
                                             void* output_param)
{
    debug_println("保存成功");
    return COM_OK;
}

/**
 * @brief  QS100 处理查询信号强度命令响应
 * 
 * @param  response_line     响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回查询结果
 */
static com_status_t CSQ_response_handler(uint8_t* response_line, 
                                         void* output_param)
{
    if(NULL == output_param)
        return COM_ERROR;
    debug_println("信号强度:%s", response_line);
    /* 信号强度为99说明没有信号 */
    if(1 == sscanf((char*)response_line, 
                    QS100_RESPONSE_CSQ, (uint8_t*)output_param))
        return COM_OK;
    else
        return COM_TIMEOUT;
}

/**
 * @brief  QS100 处理查询是否有网络
 * 
 * @param  response_line     响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t CGATT_response_handler(uint8_t* response_line, 
                                           void* output_param)
{
    if(NULL == output_param)
        return COM_ERROR;
    debug_println("网络附着:%s", response_line);
    if(1 == sscanf((const char*)response_line, 
                    QS100_RESPONSE_CGATT, 
                    (uint8_t*)output_param))
    {
        // debug_println("已连接网络 %d", *(uint8_t*)output_param);
        return COM_OK;
    }   
    else
        return COM_ERROR;
}

/**
 * @brief  QS100 处理创建onenet通信套件响应
 * 
 * @param  response_line      响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t MIPLCREATE_response_handler(uint8_t* response_line, 
                                                void* output_param)
{
    debug_println("网络通信套件:%s", response_line);

    if(1 != sscanf((const char*)response_line, 
                    QS100_RESPONSE_MIPLCREATE, 
                    &onenet_instance))
        return COM_TIMEOUT;
    debug_println("onenet_instance:%d", onenet_instance);
    return COM_OK;
}

/**
 * @brief  QS100 处理 LIFETIME 命令响应
 * 
 * @param  response_line     响应行
 * @param  output_param      返回响应参数
 * 
 * @retval                   返回处理结果
 */
static com_status_t LIFETIME_response_handler(uint8_t* response_line, 
                                              void* output_param)
{
    uint32_t* lifetime = NULL;

    if(NULL == output_param)
    {
        return COM_ERROR;
    }
    lifetime = (uint32_t*)output_param;

    if(1 != sscanf((const char*)response_line, 
                    QS100_RESPONSE_ONETRMLFT, 
                    lifetime))
        return COM_ERROR;
    
    debug_println("lifetime:%d ", *lifetime);
    return COM_OK;
}

/**
 * @brief  QS100 处理 DISCOVER URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t MIPLDISCOVER_request_handler(void* context, 
                                                 const uint8_t* urc)
{
    discover_response_t discover_response;
    debug_println("DISCOVER URC:%s", urc);
    if(3 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLDISCOVER, 
                    &discover_response.base.ref, 
                    &discover_response.base.msgid, 
                    &discover_response.base.path.objectid))
        return COM_ERROR;
    if(discover_response.base.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                      "msgid:%d, "
                      "objectid:%d", 
                                    discover_response.base.ref, 
                                    discover_response.base.msgid,
                                    discover_response.base.path.objectid);
    }   
    
    if(NULL != gs_qs100_discover_callback)
        gs_qs100_discover_callback(&discover_response);
    return COM_OK;
}

/**
 * @brief  QS100 处理 OBSERVE URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t MIPLOBSERVE_request_handler(void* context, 
                                                const uint8_t* urc)
{
    observe_response_t observe_response;
    debug_println("OBSERVE URC:%s", urc);
    if(6 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLOBSERVE, 
                    &observe_response.base.ref, 
                    &observe_response.base.msgid, 
                    &observe_response.flag, 
                    &observe_response.base.path.objectid, 
                    &observe_response.base.path.instanceid, 
                    &observe_response.base.path.resourceid))
        return COM_ERROR;
    if(observe_response.base.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                      "msgid:%d, "
                      "falg:%d, "
                      "objectid:%d, "
                      "instanceid:%d, "
                      "resourceid:%d",  
                                        observe_response.base.ref, 
                                        observe_response.base.msgid, 
                                        observe_response.flag, 
                                        observe_response.base.path.objectid, 
                                        observe_response.base.path.instanceid, 
                                        observe_response.base.path.resourceid);
    } 
    if(NULL != gs_qs100_observe_callback)
        gs_qs100_observe_callback(&observe_response);
    return COM_OK; 
}

/**
 * @brief  QS100 处理 READ URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  MIPLREAD_request_handler(void* context, 
                                              const uint8_t* urc)
{
    read_response_t read_response;
    debug_println("READ URC:%s", urc);
    if(5 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLREAD, 
                    &read_response.base.ref, 
                    &read_response.base.msgid, 
                    &read_response.base.path.objectid,
                    &read_response.base.path.instanceid,
                    &read_response.base.path.resourceid))
        return COM_ERROR;
    if(read_response.base.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                      "msgid:%d, "
                      "objectid:%d, "
                      "instanceid:%d, "
                      "resourceid:%d",
                                        read_response.base.ref, 
                                        read_response.base.msgid, 
                                        read_response.base.path.objectid,
                                        read_response.base.path.instanceid,
                                        read_response.base.path.resourceid);
    } 
    if(NULL != gs_qs100_read_callback)
        gs_qs100_read_callback(&read_response);
    return COM_OK; 
}

/**
 * @brief  QS100 处理 WRITE URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  MIPLWRITE_request_handler(void* context, 
                                               const uint8_t* urc)
{
    write_response_t write_response;
    void* response_data = NULL;
    uint8_t* filling_str = NULL;          /* 填充字符串 */
    
    /* 获取数据类型和数据长度 */
    if(1 != sscanf((const char*)urc, 
                    "%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%hhu,%hu", 
                    &write_response.valuetype, 
                    &write_response.len))
        return COM_ERROR;
    
    /* 根据发送类型选择填充字符串和发送数据 */
    switch (write_response.valuetype)
    {
    case LWM2M_TYPE_STRING:
        response_data = calloc(1, write_response.len + 1);
        write_response.data_t.str_type = response_data;
        if(NULL == write_response.data_t.str_type)
            filling_str = QS100_RESPONSE_MIPLWRITE_STR_IGNORE; 
        else 
            filling_str = QS100_RESPONSE_MIPLWRITE_STR_CAPTURE;
        break;
    case LWM2M_TYPE_OPAQUE:
        response_data = calloc(1, write_response.len * 2 + 1);
        write_response.data_t.opaque_type = response_data;
        if(NULL == write_response.data_t.opaque_type)
            filling_str = QS100_RESPONSE_MIPLWRITE_OPAQUE_IGNORE; 
        else    
            filling_str = QS100_RESPONSE_MIPLWRITE_OPAQUE_CAPTURE; 
        break;
    case LWM2M_TYPE_INTEGER:
        response_data = calloc(1, write_response.len + 1);
        filling_str = QS100_CMD_MIPLREADRSP_INT;
        write_response.data_t.int_type = response_data;
        break;
    case LWM2M_TYPE_FLOAT:
        response_data = calloc(1, write_response.len + 1);
        filling_str = QS100_CMD_MIPLREADRSP_FLOAT;
        write_response.data_t.float_type = response_data;
        break;
    case LWM2M_TYPE_BOOL:
        response_data = calloc(1, write_response.len + 1);
        filling_str = QS100_CMD_MIPLREADRSP_BOOL;
        write_response.data_t.bool_type = response_data;
        break;
    default:
        free(response_data);
        response_data = NULL;
        debug_println("数据类型错误:%d", write_response.valuetype);
        return COM_ERROR;
    }

    if(NULL == response_data
        && 9 != sscanf((const char*)urc, 
                       (const char*)filling_str, 
                       &write_response.base.ref, 
                       &write_response.base.msgid,
                       &write_response.base.path.objectid,
                       &write_response.base.path.instanceid,
                       &write_response.base.path.resourceid,
                       &write_response.valuetype,
                       &write_response.len,
                       &write_response.flag,
                       &write_response.index))
        {
            free(response_data);
            response_data = NULL;
            return COM_ERROR;   
        }   
    else if(NULL != response_data
            && 10 != sscanf((const char*)urc, 
                            (const char*)filling_str, 
                            &write_response.base.ref, 
                            &write_response.base.msgid,
                            &write_response.base.path.objectid,
                            &write_response.base.path.instanceid,
                            &write_response.base.path.resourceid,
                            &write_response.valuetype,
                            &write_response.len,
                            (char*)response_data,
                            &write_response.flag,
                            &write_response.index))
        {
            free(response_data);
            response_data = NULL;
            return COM_ERROR;   
        }   
    if(write_response.base.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                        "msgid:%d, "
                        "objectid:%d, "
                        "instanceid:%d, "
                        "resourceid:%d, "
                        "valuetype:%d, "
                        "len:%d, "
                        // "value:%s, "
                        "flag:%d, "
                        "index:%d",
                                    write_response.base.ref, 
                                    write_response.base.msgid,
                                    write_response.base.path.objectid,
                                    write_response.base.path.instanceid,
                                    write_response.base.path.resourceid,
                                    write_response.valuetype,
                                    write_response.len,
                                    // write_response.data_t.str_t,
                                    write_response.flag,
                                    write_response.index);
    } 
    if(NULL != gs_qs100_write_callback)
    {
        free(response_data);
        response_data = NULL;
        gs_qs100_write_callback(&write_response);
        return COM_OK;
    }    
    else
    {
        free(response_data);
        response_data = NULL;
        return COM_OK;
    }      
}

/**
 * @brief  QS100 处理 EXECUTE URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  EXECUTE_request_handler(void* context, 
                                             const uint8_t* urc)
{
    execute_response_t execute_response;
    debug_println("EXECUTE URC:%s", urc);
    if(NULL == execute_response.arguments 
        && 6 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLEXECUTE_IGNORE, 
                    &execute_response.base.ref, 
                    &execute_response.base.msgid, 
                    &execute_response.base.path.objectid,
                    &execute_response.base.path.instanceid,
                    &execute_response.base.path.resourceid,
                    &execute_response.len))
        return COM_ERROR;
    else if(NULL != execute_response.arguments 
            && 7 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLEXECUTE_CAPTURE, 
                    &execute_response.base.ref, 
                    &execute_response.base.msgid, 
                    &execute_response.base.path.objectid,
                    &execute_response.base.path.instanceid,
                    &execute_response.base.path.resourceid,
                    &execute_response.len,
                    execute_response.arguments))
        return COM_ERROR;
    if(execute_response.base.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                      "msgid:%d, "
                      "objectid:%d, "
                      "instanceid:%d, "
                      "resourceid:%d"
                      "len:%d",
                    //   "arguments:%s"
                                        execute_response.base.ref, 
                                        execute_response.base.msgid, 
                                        execute_response.base.path.objectid,
                                        execute_response.base.path.instanceid,
                                        execute_response.base.path.resourceid,
                                        execute_response.len);
    } 
    if(NULL != gs_qs100_execute_callback)
        gs_qs100_execute_callback(&execute_response);
    return COM_OK;
}

/**
 * @brief  QS100 处理 PARAMETER URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  PARAMETER_request_handler(void* context, 
                                               const uint8_t* urc)
{
    parameter_response_t parameter_response;
    debug_println("PARAMETER URC:%s", urc);
    if(NULL == parameter_response.parameter 
        && 6 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLPARAMETER_IGNORE, 
                    &parameter_response.base.ref, 
                    &parameter_response.base.msgid, 
                    &parameter_response.base.path.objectid,
                    &parameter_response.base.path.instanceid,
                    &parameter_response.base.path.resourceid,
                    &parameter_response.len))
        return COM_ERROR;
    if(NULL != parameter_response.parameter 
        && 7 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLPARAMETER_CAPTURE, 
                    &parameter_response.base.ref, 
                    &parameter_response.base.msgid, 
                    &parameter_response.base.path.objectid,
                    &parameter_response.base.path.instanceid,
                    &parameter_response.base.path.resourceid,
                    &parameter_response.len,
                    parameter_response.parameter))
        return COM_ERROR;
    if(parameter_response.base.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                      "msgid:%d, "
                      "objectid:%d, "
                      "instanceid:%d, "
                      "resourceid:%d"
                      "len:%d",
                    //   "parameter:%s"
                                        parameter_response.base.ref, 
                                        parameter_response.base.msgid, 
                                        parameter_response.base.path.objectid,
                                        parameter_response.base.path.instanceid,
                                        parameter_response.base.path.resourceid,
                                        parameter_response.len);
    } 
    if(NULL != gs_qs100_parameter_callback)
        gs_qs100_parameter_callback(&parameter_response);
    return COM_OK;
}

/**
 * @brief  QS100 处理 EVENT URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  EVENT_request_handler(void* context, 
                                           const uint8_t* urc)
{
    event_response_t event_response;
    debug_println("EVENT URC:%s", urc);
    if(2 != sscanf((const char*)urc, 
                    QS100_RESPONSE_MIPLEVENT, 
                    &event_response.ref,
                    &event_response.evtid))
        return COM_ERROR;
    if(event_response.ref == onenet_instance)
    {
        debug_println("instance:%d, "
                      "evtid:%d, ",
                                    event_response.ref, 
                                    event_response.evtid);
    } 
    if(NULL != gs_qs100_event_callback)
        gs_qs100_event_callback(&event_response);
    return COM_OK;
}

/**
 * @brief  QS100 处理 NPTWEDRXP URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  NPTWEDRXP_response_handler(void* context, 
                                                const uint8_t* urc)
{
    nptwedrxp_response_t nptwedrxp_response;
    debug_println("NPTWEDRXP URC:%s", urc);
    if(5 != sscanf((const char*)urc, 
                    QS100_RESPONSE_NPTWEDRXP, 
                    &nptwedrxp_response.AcT_type, 
                    (char*)nptwedrxp_response.requested_PTW, 
                    (char*)nptwedrxp_response.requested_eDRX_value,  
                    (char*)nptwedrxp_response.eDRX_value, 
                    (char*)nptwedrxp_response.PTW))
        return COM_ERROR;
    debug_println("AcT_type:%d, "
                  "requested_PTW:%s, "
                  "requested_eDRX_value:%s, "
                  "eDRX_value:%s, "
                  "PTW:%s",
                                    nptwedrxp_response.AcT_type,
                                    nptwedrxp_response.requested_PTW,
                                    nptwedrxp_response.requested_eDRX_value,
                                    nptwedrxp_response.eDRX_value,
                                    nptwedrxp_response.PTW
        );
    if(NULL != gs_qs100_nptwedrxp_callback)
        gs_qs100_nptwedrxp_callback(&nptwedrxp_response);
    return COM_OK;
}

/**
 * @brief  QS100 处理 POWERON URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  POWERON_response_handler(void* context, 
                                              const uint8_t* urc)
{ 
    uint8_t status = 0;
    debug_println("POWERON URC:%s", urc);
    if(1 != sscanf((const char*)urc, 
                    QS100_RESPONSE_POWERON, 
                    &status))
        return COM_ERROR;
    debug_println("status:%d, ", status);

    if(NULL != gs_qs100_poweron_callback)
        gs_qs100_poweron_callback(status);
    return COM_OK;
}

/**
 * @brief  QS100 处理 SIMST URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  SIMST_response_handler(void* context, 
                                            const uint8_t* urc)
{
    uint8_t status = 0;
    debug_println("SIMST URC:%s", urc);
    if(1 != sscanf((const char*)urc, 
                    QS100_RESPONSE_SIMST, 
                    &status))
        return COM_ERROR;
    debug_println("status:%d, ", status);

    if(NULL != gs_qs100_simst_callback)
        gs_qs100_simst_callback(status);
    return COM_OK;
}

/**
 * @brief  QS100 处理串口回显 URC
 * 
 * @param  context           上下文指针
 * @param  urc               设备主动上报的消息
 * 
 * @retval                   返回处理结果
 */
static com_status_t  ECHO_response_handler(void* context, 
                                           const uint8_t* urc)
{
    debug_println("串口回显:%s", urc);
    return COM_OK;
}

/**
 * @brief  QS100 唤醒
 * 
 * @param  无
 * 
 * @retval 无
 */
 void Int_QS100_wakeup(void)
{
    QS100_WAKEUP_H;
    Com_delay_s(1);
    QS100_WAKEUP_L;
    Com_delay_s(1);
}

/**
 * @brief  QS100 重启
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_reset(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_RB, AT_CMD_EXECUTE);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_RB);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = REBOOTING_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 打开串口回显
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_ATE(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_ATE, AT_CMD_SET);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_ATE);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = general_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 设置IMEI
 * 
 * @param  imei              IMEI
 * @param  imei              IMEI 号
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_set_IMEI(at_client_t* client, 
                                 uint8_t *imei)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));

    if(NULL == imei)
        return COM_ERROR;

    snprintf((char*)cmd, 
             sizeof(cmd), 
             (const char*)get_at_cmd_string(AT_CMD_NTSETID, AT_CMD_SET), 
             imei);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_NTSETID);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = general_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询信号强度
 * 
 * @param  client            at 客户端句柄 
 * @param  rssi              返回信号强度
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CSQ(at_client_t* client, 
                                 uint8_t* rssi)
{
    if(NULL == rssi)
        return COM_ERROR;

    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CSQ, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CSQ);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = rssi;
    client->cmd_param.handler = CSQ_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询运营商
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_COPS(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_COPS, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_COPS);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询 PDP 上下文
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CGDCONT(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CGDCONT, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CGDCONT);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 设置 PDP 上下文
 * 
 * @param  client            at 客户端句柄 
 * @param  pdp               PDP 参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_set_CGDCONT(at_client_t* client,
                                   PDP_t *pdp)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));

    if(NULL == pdp)
        return COM_ERROR;

    snprintf((char*)cmd, 
             sizeof(cmd), 
             (const char*)get_at_cmd_string(AT_CMD_CGDCONT, AT_CMD_SET), 
             pdp->cid,
             pdp->PDP_type,
             pdp->APN);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 激活/断开 PDP 上下文
 * 
 * @param  client            at 客户端句柄 
 * @param  pdp               pdp 参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_set_CGACT(at_client_t* client,
                                 PDP_t *pdp)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));

    if(NULL == pdp)
        return COM_ERROR;

    snprintf((char*)cmd, 
             sizeof(cmd), 
             (const char*)get_at_cmd_string(AT_CMD_CGACT, AT_CMD_SET), 
             pdp->status,
             pdp->cid);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询是否需要输入pin码
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CPIN(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CPIN, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CPIN);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询网络注册状态
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CEREG(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CEREG, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CEREG);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询SIM卡ID
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_NCCID(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_NCCID, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_NCCID);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询IMEI号
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_IMEI(at_client_t* client)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));

    snprintf((char*)cmd, 
             sizeof(cmd), 
             (const char*)get_at_cmd_string(AT_CMD_CGSN, AT_CMD_READ), 
             1);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CGSN);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询IMSI号
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_IMSI(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CIMI, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CIMI);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 保存NV
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_execute_NV_SAVE(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_NV, AT_CMD_EXECUTE);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_NV);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = NV_SAVE_response_handler;
    
    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询是否有网络
 * 
 * @param  client            at 客户端句柄 
 * @param  attach            返回网络附着状态
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_query_CGATT(at_client_t* client, 
                                    uint8_t* attach)
{
    if(NULL == attach)
        return COM_ERROR;

    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CGATT, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CGATT);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = attach;
    client->cmd_param.handler = CGATT_response_handler;
    
    return at_cmd_send(client);
}

/**
 * @brief  查询省电锁
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回查询结果
 */
 com_status_t Int_QS100_query_WORKLOCK(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_WORKLOCK, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_WORKLOCK);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;
    
    return at_cmd_send(client);
}

/**
 * @brief  设置省电锁
 * 
 * @param  client            at 客户端句柄 
 * @param  switch_mode       省电锁状态
 * 
 * @retval                   返回查询结果
 */
 com_status_t Int_QS100_set_WORKLOCK(at_client_t* client, 
                                     uint8_t switch_mode)
{
    uint8_t cmd[32];
    memset(cmd, 0, sizeof(cmd));

    snprintf((char*)cmd, 
            sizeof(cmd),
            (const char*)get_at_cmd_string(AT_CMD_WORKLOCK, AT_CMD_SET),
            switch_mode);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;
    
    return at_cmd_send(client);
}


/**
 * @brief  查询扩展 DRX 动态参数
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_query_CEDRXRDP(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CEDRXRDP, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CEDRXRDP);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;
    
    return at_cmd_send(client);
}

/**
 * @brief  查询寻呼时间窗及 eDRX
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回查询结果
 */
 com_status_t Int_QS100_query_NPTWEDRXS(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_NPTWEDRXS, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_NPTWEDRXS);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;
    
    return at_cmd_send(client);
}

/**
 * @brief  设置寻呼时间窗及 eDRX
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回设置结果
 */
 com_status_t Int_QS100_set_eDRX(at_client_t* client, 
                                 eDRX_t eDRX)
{
    uint8_t cmd[32];
    memset(cmd, 0, sizeof(cmd));

    snprintf((char*)cmd, 
            sizeof(cmd),
            (const char*)get_at_cmd_string(AT_CMD_NPTWEDRXS, AT_CMD_SET),
            eDRX.mode,
            QS100_EDRX_NB_S1_MODE,
            eDRX.PTW,
            eDRX.eDRX_value);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;
    
    if(COM_OK == at_cmd_send(client))
    {
        return Int_QS100_execute_NV_SAVE(client);
    }
    return COM_ERROR;
}

/**
 * @brief  查询 PSM 参数
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_query_CPSMS(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CPSMS, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CPSMS);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  设置 PSM
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回设置结果
 */
 com_status_t Int_QS100_set_PSM(at_client_t* client, 
                                PSM_t PSM)
{
    uint8_t cmd[32];
    memset(cmd, 0, sizeof(cmd));

    snprintf((char*)cmd, 
            sizeof(cmd),
            (const char*)get_at_cmd_string(AT_CMD_CPSMS, AT_CMD_SET),
            PSM.mode,
            PSM.T3412_time,
            PSM.T3324_time);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    if(COM_OK == at_cmd_send(client))
    {
        debug_println("Int_QS100_NV_SAVE");
        return Int_QS100_execute_NV_SAVE(client);
    }
    debug_println("Int_QS100_PSM_CONFIG failed");
    return COM_ERROR;
}

/**
* @brief  QS100 查询主动上报下行数据
* 
* @param  client            at 客户端句柄 
* 
* @retval                   返回执行结果
*/
com_status_t Int_QS100_query_CRTDCP(at_client_t* client)
{
    client->cmd_param.cmd = get_at_cmd_string(AT_CMD_CRTDCP, AT_CMD_READ);
    client->cmd_param.expect = get_at_response_prefix(AT_CMD_CRTDCP);
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
* @brief  QS100 设置主动上报下行数据
* 
* @param  client            at 客户端句柄 
* @param  reporting         是否主动上报下行数据
* 
* @retval                   返回执行结果
*/
com_status_t Int_QS100_set_CRTDCP(at_client_t* client,
                                  uint8_t reporting)
{
    uint8_t cmd[32];
    memset(cmd, 0, sizeof(cmd));

    snprintf((char*)cmd, 
            sizeof(cmd),
            (const char*)get_at_cmd_string(AT_CMD_CRTDCP, AT_CMD_SET),
            reporting);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询onenet通讯套件版本号
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_NV_MIPLVER(at_client_t* client)
{
    client->cmd_param.cmd = QS100_CMD_NV_MIPLVER;
    client->cmd_param.expect = QS100_RESPONSE_PREFIX_MIPLVER;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 创建onenet通讯套件
 * 
* @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLCREATE(at_client_t* client)
{
    client->cmd_param.cmd = QS100_CMD_MIPLSTART;
    client->cmd_param.expect = QS100_RESPONSE_PREFIX_MIPLCREATE;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = MIPLCREATE_response_handler;

    if(COM_OK != at_cmd_send(client))
    {
        uint8_t cmd[512];
        memset(cmd, 0, sizeof(cmd));
        /*  命令参数:  
            配置文件总长度 
            配置文件 
            配置文件序号(可以将配置文件分为多次发送) 
            当前指令配置文件长度 
            消息标志 0: 最后一条消息 1: 第一条消息 2: 中间消息 */
        snprintf((char*)cmd, 
                 sizeof(cmd), 
                 QS100_CMD_MIPLCREATE, 
                 strlen(QS100_CONFIG) / 2, 
                 QS100_CONFIG, 
                 0, 
                 strlen(QS100_CONFIG) / 2, 
                 0);
        // debug_println("%s", cmd);

        client->cmd_param.cmd = cmd;
        client->cmd_param.expect = QS100_RESPONSE_PREFIX_MIPLCREATE;
        client->cmd_param.retries = 10;
        client->cmd_param.timeout = 500;
        client->cmd_param.output = NULL;
        client->cmd_param.handler = MIPLCREATE_response_handler;

        return at_cmd_send(client);
    }
    return COM_OK;
}

/**
 * @brief  QS100 删除onenet通讯套件
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLDELETE(at_client_t* client)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    /*  命令参数:  
        实例标识 */
    snprintf((char*)cmd, 
             sizeof(cmd), 
             QS100_CMD_MIPLDELETE, 
             onenet_instance);
    debug_println("%s", cmd);
    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 增加 LwM2M 实例
 * 
 * @param  client            at 客户端句柄 
 * @param  mipladdob_cmd     命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLADDOB(at_client_t* client, 
                                  mipladdob_cmd_t mipladdob_cmd)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLADDOB,
             onenet_instance,
             mipladdob_cmd.objectid,
             mipladdob_cmd.instancecount,
             mipladdob_cmd.instancebitmap,
             mipladdob_cmd.attributecount,
             mipladdob_cmd.actioncount);
    debug_println("%s", cmd);
    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = general_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 删除 LwM2M 实例
 * 
 * @param  client            at 客户端句柄 
 * @param  objectid          对象id
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLDELOBJ(at_client_t* client, 
                                  uint16_t objectid)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLDELOBJ,
             onenet_instance,
             objectid);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 发起注册请求
 * 
 * @param  client            at 客户端句柄 
 * @param  lifetime          生命周期
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLOPEN(at_client_t* client, 
                                 uint16_t lifetime)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    /*  命令参数:  
        实例标识
        生命周期 最少120s*/
    if(lifetime < 120)
        lifetime = 3000;
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLOPEN,
             onenet_instance,
             lifetime);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 发送注销请求
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLCLOSE(at_client_t* client)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    /*  命令参数:  
        实例标识 */
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLCLOSE,
             onenet_instance);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 Discover请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  discover_cmd      命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLDISCOVERRSP(at_client_t* client, 
                                        discoverrsp_cmd_t discover_cmd)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLDISCOVERRSP,
             onenet_instance,
             discover_cmd.msgid,
             discover_cmd.result,
             discover_cmd.length,
             discover_cmd.valuestring);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 Observe请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  observersp_cmd    命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLOBSERVERSP(at_client_t* client, 
                                       observersp_cmd_t observersp_cmd)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd,   
             sizeof(cmd),
             QS100_CMD_MIPLOBSERVERSP,
             onenet_instance,
             observersp_cmd.msgid,
             observersp_cmd.result);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 Read 请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  readrsp_cmd       命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLREADRSP(at_client_t* client, 
                                    readrsp_cmd_t readrsp_cmd)
{
    uint8_t cmd[380];
    uint8_t* filling_str = NULL;          /* 填充字符串 */
    void* value = NULL;                   /* 数据指针   */
    uint16_t len = 0;                     /* 数据长度   */
    memset(cmd, 0, sizeof(cmd));
    /* 最多发送160字节数据 */
    if(LWM2M_READ_DATA_MAX_LEN < readrsp_cmd.len)
        return COM_ERROR;
    /* 根据发送类型选择填充字符串和发送数据 */
    switch (readrsp_cmd.valuetype)
    {
    case LWM2M_TYPE_STRING:
        filling_str = QS100_CMD_MIPLREADRSP_STR;
        value = readrsp_cmd.data_t.str_type;
        len = readrsp_cmd.len;
        break;
    case LWM2M_TYPE_OPAQUE:
        filling_str = QS100_CMD_MIPLREADRSP_OPAQUE;
        value = readrsp_cmd.data_t.opaque_type;
        len = readrsp_cmd.len * 2;
        break;
    case LWM2M_TYPE_INTEGER:
        filling_str = QS100_CMD_MIPLREADRSP_INT;
        value = (void*)&readrsp_cmd.data_t.int_type;
        len = readrsp_cmd.len;
        break;
    case LWM2M_TYPE_FLOAT:
        filling_str = QS100_CMD_MIPLREADRSP_FLOAT;
        value = (void*)&readrsp_cmd.data_t.float_type;
        len = readrsp_cmd.len;
        break;
    case LWM2M_TYPE_BOOL:
        filling_str = QS100_CMD_MIPLREADRSP_BOOL;
        value = (void*)&readrsp_cmd.data_t.bool_type;
        len = readrsp_cmd.len;
        break;
    default:
        debug_println("数据类型错误:%d", readrsp_cmd.valuetype);
        return COM_ERROR;
    }

    snprintf((char*)cmd,
            sizeof(cmd),
            (const char*)filling_str,
            onenet_instance,
            readrsp_cmd.base.msgid,
            readrsp_cmd.result,
            readrsp_cmd.base.path.objectid,
            readrsp_cmd.base.path.instanceid,
            readrsp_cmd.base.path.resourceid,
            readrsp_cmd.valuetype,
            readrsp_cmd.len,
            len,
            (uint8_t*)value,
            0,
            MSG_FLAG_LAST);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 Write请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  writersp_cmd      命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLWRITERSP(at_client_t* client, 
                                     writersp_cmd_t writersp_cmd)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLWRITERSP,
             onenet_instance,
             writersp_cmd.msgid,
             writersp_cmd.result);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 Execute 请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  executersp_cmd    命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLEXECUTERSP(at_client_t* client, 
                                       executersp_cmd_t executersp_cmd)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
             sizeof(cmd), 
             QS100_CMD_MIPLEXECUTERSP,
             onenet_instance,
             executersp_cmd.msgid,
             executersp_cmd.result);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 PARAMETERRSP 请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  parameterrsp_cmd  命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLPARAMETERRSP(at_client_t* client, 
                                         parameterrsp_cmd_t parameterrsp_cmd)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
            sizeof(cmd),
            QS100_CMD_MIPLPARAMETERRSP,
            onenet_instance,
            parameterrsp_cmd.msgid,
            parameterrsp_cmd.result);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 Notify 数据到 ONENET 云端
 * 
 * @param  client            at 客户端句柄 
 * @param  notify_cmd        命令参数
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLNOTIFY(at_client_t* client, 
                                   notify_cmd_t notify_cmd)
{
    /* QS100 notify ackid */
    static uint16_t ackid = 100;
    uint8_t cmd[350];
    uint8_t* filling_str = NULL;          /* 填充字符串 */
    void* value = NULL;                   /* 数据指针    */
    uint16_t data_len = 0;                /* 数据长度    */
    uint8_t cmd_index = 0;                /* 指令序号    */
    uint8_t cmd_flag = 0;                 /* 数据标志    */
    uint16_t notify_max_len = 0;          /* 最大数据长度 */
    uint8_t i = 1;
    memset(cmd, 0, sizeof(cmd));
    switch (notify_cmd.valuetype)
    {
    case LWM2M_TYPE_STRING:
        filling_str = QS100_CMD_MIPLNOTIFY_STR;
        value = notify_cmd.data_t.str_type;
        notify_max_len = LWM2M_NOTIFY_DATA_MAX_LEN;
        data_len = notify_cmd.len;   
        break;
    case LWM2M_TYPE_OPAQUE:
        filling_str = QS100_CMD_MIPLNOTIFY_OPAQUE;
        value = notify_cmd.data_t.opaque_type;
        notify_max_len = LWM2M_NOTIFY_DATA_MAX_LEN * 2;
        data_len = notify_cmd.len * 2; 
        break;
    case LWM2M_TYPE_INTEGER:
        filling_str = QS100_CMD_MIPLNOTIFY_INT;
        value = (void*)&notify_cmd.data_t.int_type;
        notify_max_len = LWM2M_NOTIFY_DATA_MAX_LEN;
        data_len = notify_cmd.len; 
        break;
    case LWM2M_TYPE_FLOAT:
        filling_str = QS100_CMD_MIPLNOTIFY_FLOAT;
        value = (void*)&notify_cmd.data_t.float_type;
        notify_max_len = LWM2M_NOTIFY_DATA_MAX_LEN;
        data_len = notify_cmd.len; 
        break;
    case LWM2M_TYPE_BOOL:
        filling_str = QS100_CMD_MIPLNOTIFY_BOOL;
        value = (void*)&notify_cmd.data_t.bool_type;
        notify_max_len = LWM2M_NOTIFY_DATA_MAX_LEN;
        data_len = notify_cmd.len; 
        break;
    default:
        debug_println("数据类型错误:%d", notify_cmd.valuetype);
        return COM_ERROR;
    }
    /* 获取指令序号   */
    cmd_index = (data_len > notify_max_len) ? (data_len / notify_max_len) : 0;
    cmd_flag = MSG_FLAG_FIRST;
    for(i = 0; i < cmd_index; i++)
    {
        snprintf((char*)cmd,
                 sizeof(cmd),
                 (const char*)filling_str,
                 onenet_instance,
                 notify_cmd.base.msgid,
                 notify_cmd.base.path.objectid,
                 notify_cmd.base.path.instanceid,
                 notify_cmd.base.path.resourceid,
                 notify_cmd.valuetype,
                 LWM2M_NOTIFY_DATA_MAX_LEN,
                 notify_max_len,
                 (uint8_t*)value + i * notify_max_len,
                 cmd_index - i,
                 cmd_flag,
                 ackid);    
        debug_println("%s", cmd);

        client->cmd_param.cmd = cmd;
        client->cmd_param.expect = QS100_RESPONSE_OK;
        client->cmd_param.retries = 10;
        client->cmd_param.timeout = 500;
        client->cmd_param.output = NULL;
        client->cmd_param.handler = general_response_handler;

        if(COM_OK !=  at_cmd_send(client))
            return COM_ERROR;
        memset(cmd, 0, sizeof(cmd));
        cmd_flag = MSG_FLAG_MIDDLE;
        data_len -= notify_max_len;
    }
    cmd_flag = MSG_FLAG_LAST;

    snprintf((char*)cmd,
            sizeof(cmd),
            (const char*)filling_str,
            onenet_instance,
            notify_cmd.base.msgid,
            notify_cmd.base.path.objectid,
            notify_cmd.base.path.instanceid,
            notify_cmd.base.path.resourceid,
            notify_cmd.valuetype,
            notify_cmd.len - i * LWM2M_NOTIFY_DATA_MAX_LEN,
            notify_max_len - i * notify_max_len,
            (uint8_t*)value + i * notify_max_len,
            0,
            MSG_FLAG_LAST,
            ackid);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = general_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 发送更新请求
 * 
 * @param  client            at 客户端句柄 
 * @param  lifetime          更新的 lifetime 值(0:为默认24小时,最短120s)
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_MIPLUPDATE(at_client_t* client, 
                                   uint16_t lifetime)
{
    uint8_t cmd[64];
    memset(cmd, 0, sizeof(cmd));
    snprintf((char*)cmd, 
             sizeof(cmd),
             QS100_CMD_MIPLUPDATE,
             onenet_instance,
             lifetime,
             0);
    debug_println("%s", cmd);

    client->cmd_param.cmd = cmd;
    client->cmd_param.expect = QS100_RESPONSE_OK;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = NULL;
    client->cmd_param.handler = print_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 查询当前 ONENET 剩余 LIFETIME 时间
 * 
 * @param  client            at 客户端句柄 
 * @param  lifetime          返回剩余时间
 * 
 * @retval                   返回执行结果
 */
 com_status_t Int_QS100_ONETRMLFT(at_client_t* client, 
                                  uint32_t *lifetime)
{
    client->cmd_param.cmd = QS100_CMD_ONETRMLFT;
    client->cmd_param.expect = QS100_RESPONSE_ONETRMLFT;
    client->cmd_param.retries = 10;
    client->cmd_param.timeout = 500;
    client->cmd_param.output = lifetime;
    client->cmd_param.handler = LIFETIME_response_handler;

    return at_cmd_send(client);
}

/**
 * @brief  QS100 注册 URC
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval 无
 */
static com_status_t Int_QS100_reg_urc(at_client_t* client)
{
    urc_entry_t entry ;
    com_status_t com_status = COM_ERROR;
    entry.handler = MIPLDISCOVER_request_handler;
    entry.prefix = QS100_URC_MIPLDISCOVER;
    entry.context = NULL;
    com_status = at_register_urc(client, &entry);
    if(COM_OK == com_status)
    {
        entry.handler = MIPLOBSERVE_request_handler;
        entry.prefix = QS100_URC_MIPLOBSERVE;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = MIPLREAD_request_handler;
        entry.prefix = QS100_URC_MIPLREAD;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = MIPLWRITE_request_handler;
        entry.prefix = QS100_URC_MIPLWRITE;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = EXECUTE_request_handler;
        entry.prefix = QS100_URC_MIPLEXECUTE;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = PARAMETER_request_handler;
        entry.prefix = QS100_URC_MIPLPARAMETER;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = EVENT_request_handler;
        entry.prefix = QS100_URC_MIPLEVENT;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = NPTWEDRXP_response_handler;
        entry.prefix = QS100_URC_NPTWEDRXP;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = POWERON_response_handler;
        entry.prefix = QS100_URC_POWERON;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = SIMST_response_handler;
        entry.prefix = QS100_URC_SIMST;
        com_status = at_register_urc(client, &entry);
    }
    if(COM_OK == com_status)
    {
        entry.handler = ECHO_response_handler;
        entry.prefix = QS100_URC_ECHO;
        com_status = at_register_urc(client, &entry);
    }
    return com_status;
}

/**
 * @brief  QS100 初始化
 * 
 * @param  无
 * 
 * @retval 无
 */
at_client_t* Int_QS100_init(void)
{
    at_client_t* client = NULL;
    /* 创建串口客户端 */
    client = at_client_create(
                QS100_UART_NUM, 
                QS100_RX_BUF_SIZE, 
                AT_URC_TABLE_LEN);
    if(NULL == client)
        debug_println("QS100 创建失败");

    /* 串口数据发送和接收函数注册 */
    client->uart_send_data = uart_send_data;
    client->uart_recv_data = uart_recv_data;
    /* 错误处理函数注册          */
    client->error_handler = error_handler;
    /* 注册 URC                 */
    Int_QS100_reg_urc(client);
    /* 重启 */
    if(COM_OK != Int_QS100_reset(client))
        debug_println("QS100 重启失败"); 
    /* 打开串口回显 */
    // if(COM_OK != Int_QS100_ATE(client))
    //     debug_println("QS100 串口回显打开失败");
    return client;
}

/** 
 * @brief  QS100 模块任务
 * 
 * @param  client            at 客户端句柄
 * 
 * @retval 无
 */
void Int_QS100_task(at_client_t* client)
{
    at_service_task(client);
}

/**
 * @brief  QS100 基础命令测试
 * 
  * @param  client            at 客户端句柄 
 * 
 * @retval 无
 */
void Int_QS100_test(at_client_t* client)
{
    uint8_t rssi = 0;
    uint8_t attach = 0;
    /* QS100 设置IMEI测试 */
    // if(COM_OK != Int_QS100_set_IMEI(client, QS100_IMEI))
    //     debug_println("QS100 设置IMEI失败");
    Com_delay_s(1);
    /* QS100 查询信号强度测试 */
    if(COM_OK != Int_QS100_query_CSQ(client, &rssi)) 
        debug_println("QS100 查询信号强度失败");
    Com_delay_s(1);
    /* QS100 查询运营商测试 */
    if(COM_OK != Int_QS100_query_COPS(client))
        debug_println("QS100 查询运营商失败");
    Com_delay_s(1);
    /* QS100 查询APN设置测试 */
    if(COM_OK != Int_QS100_query_CGDCONT(client))
        debug_println("QS100 查询APN设置失败");
    Com_delay_s(1);
    /* QS100 查询是否需要输入pin码测试 */
    if(COM_OK != Int_QS100_query_CPIN(client))
        debug_println("QS100 查询PIN码状态失败");
    Com_delay_s(1);
    /* QS100 查询网络注册状态测试 */
    if(COM_OK != Int_QS100_query_CEREG(client))
        debug_println("QS100 查询网络注册状态失败");
    Com_delay_s(1);
    /* QS100 查询SIM卡ID测试 */
    if(COM_OK != Int_QS100_query_NCCID(client))
        debug_println("QS100 查询SIM卡ID失败");
    Com_delay_s(1);
    /* QS100 获取IMEI号测试 */
    if(COM_OK != Int_QS100_query_IMEI(client))
        debug_println("QS100 获取IMEI号失败");
    Com_delay_s(1);
    /* QS100 获取IMSI号测试 */
    if(COM_OK != Int_QS100_query_IMSI(client))
        debug_println("QS100 获取IMSI号失败");
    Com_delay_s(1);
    /* QS100 查询onenet通讯套件版本号测试 */
    if(COM_OK != Int_QS100_query_NV_MIPLVER(client))
        debug_println("QS100 查询onenet通讯套件版本号失败");
    Com_delay_s(1);
    // /* QS100 保存NV测试 */
    // // if(COM_OK != Int_QS100_NV_SAVE(client))
    // //     debug_println("QS100 保存NV失败");
    // // Com_delay_s(1);
    /* QS100 查看使用有网络测试 */
    if(COM_OK != Int_QS100_query_CGATT(client, &attach))
        debug_println("QS100 查询网络附着状态失败");
    Com_delay_s(1);
}

/**
 * @brief  注册QS100 DISCOVER 事件回调函数
 * 
 * @param  callback         DISCOVER 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_DISCOVER_callback(QS100_DISCOVER_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;

    gs_qs100_discover_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 OBSERVE 事件回调函数
 * 
 * @param  callback          OBSERVE 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_OBSERVE_callback(QS100_OBSERVE_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;

    gs_qs100_observe_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 READ 事件回调函数
 * 
 * @param  callback          READ 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_READ_callback(QS100_READ_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;

    gs_qs100_read_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 WRITE 事件回调函数
 * 
 * @param  callback          WRITE 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_WRITE_callback(QS100_WRITE_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;

    gs_qs100_write_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 EXECUTE 事件回调函数
 * 
 * @param  callback          EXECUTE 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_EXECUTE_callback(QS100_EXECUTE_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;

    gs_qs100_execute_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 PARAMETER 事件回调函数
 * 
 * @param  callback          PARAMETER 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_PARAMETER_callback(QS100_PARAMETER_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;
    
    gs_qs100_parameter_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 EVENT 事件回调函数
 * 
 * @param  callback          EVENT 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_EVENT_callback(QS100_EVENT_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;
   
    gs_qs100_event_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 NPTWEDRXP 事件回调函数
 * 
 * @param  callback          NPTWEDRXP事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_NPTWEDRXP_callback(QS100_NPTWEDRXP_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;
    
    gs_qs100_nptwedrxp_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 POWERON 事件回调函数
 * 
 * @param  callback          POWERON 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_POWERON_callback(QS100_POWERON_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;
    
    gs_qs100_poweron_callback = callback;
    return COM_OK;
}

/**
 * @brief  注册QS100 SIMST 事件回调函数
 * 
 * @param  callback          SIMST 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_SIMST_callback(QS100_SIMST_callback callback)
{
    if (callback == NULL) 
        return COM_ERROR;
    
    gs_qs100_simst_callback = callback;
    return COM_OK;
}

Int_QS100.h

#ifndef INT_QS100_H
#define INT_QS100_H

#include <stdio.h>
#include "stdlib.h"

#include "stm32f1xx_hal.h"
#include "usart.h"
#include "gpio.h"
#include "dma.h"

#include "Com_at.h"
#include "Int_QS100_cmd_def.h"

/* QS100串口接收缓冲区大小   */
#define QS100_RX_BUF_SIZE               UART_BUFFER_SIZE
/* QS100串口号              */
#define QS100_UART_NUM                  UART_NUM_3
/* URC表大小                */
#define AT_URC_TABLE_LEN                20
/* QS100 IMEI              */
#define QS100_IMEI                      "13245678912344"

/* QS100 onenet配置文件     */
#define QS100_CONFIG                    "130040f10003f2003204001100000000"\
                                        "00000000123138332e3233302e34302e"\
                                        "34303a35363833000f41757468436f64"\
                                        "653a3b50534b3a3bf30008e400c80000"

/* 发送最大重试次数          */
#define QS100_TX_MAX_RETRIES            10
/* 接收最大重试次数          */
#define QS100_RX_MAX_RETRIES            10
/* LwM2M read 数据最大长度   */
#define LWM2M_READ_DATA_MAX_LEN         150
/* LwM2M notify 数据最大长度 */
#define LWM2M_NOTIFY_DATA_MAX_LEN       500
/* EDRX 接入技术类型         */
#define QS100_EDRX_NB_S1_MODE           5
                             
/* wakeup引脚操作            */
#define QS100_WAKEUP_L HAL_GPIO_WritePin(QS100_WAKEUP_GPIO_Port, QS100_WAKEUP_Pin, GPIO_PIN_RESET)
#define QS100_WAKEUP_H HAL_GPIO_WritePin(QS100_WAKEUP_GPIO_Port, QS100_WAKEUP_Pin, GPIO_PIN_SET)
/* AT命令表大小             */
#define AT_CMD_TABLE_SIZE (sizeof(g_at_cmd_table) / sizeof(g_at_cmd_table[0]))

/* onenet 相关命令 */
#define QS100_CMD_NV_MIPLVER                    "AT+MIPLVER?\r\n"                                           /* 查询onenet通讯套件版本号              */
#define QS100_CMD_MIPLCREATE                    "AT+MIPLCREATE=%d,%s,%d,%d,%d\r\n"                          /* 创建onenet通讯套件                   */
#define QS100_CMD_MIPLSTART                     "AT+MIPLCREATE\r\n"                                         /* 启动onenet通讯套件                   */
#define QS100_CMD_MIPLDELETE                    "AT+MIPLDELETE=%d\r\n"                                      /* 删除onenet通讯套件                   */
#define QS100_CMD_MIPLADDOB                     "AT+MIPLADDOBJ=%d,%d,%d,\"%s\",%d,%d\r\n"                   /* 增加 LwM2M 实例                      */
#define QS100_CMD_MIPLDELOBJ                    "AT+MIPLDELOBJ=%d,%d\r\n"                                   /* 删除 LwM2M 实例                      */
#define QS100_CMD_MIPLOPEN                      "AT+MIPLOPEN=%d,%d\r\n"                                     /* 发起注册请求                         */
#define QS100_CMD_MIPLCLOSE                     "AT+MIPLCLOSE=%d\r\n"                                       /* 发送注销请求                         */
#define QS100_CMD_MIPLDISCOVERRSP               "AT+MIPLDISCOVERRSP=%d,%d,%d,%d,\"%s\"\r\n"                 /* Discover请求的响应                   */
#define QS100_CMD_MIPLOBSERVERSP                "AT+MIPLOBSERVERSP=%d,%d,%d\r\n"                            /* Observe请求的响应                    */
#define QS100_CMD_MIPLREADRSP_STR               "AT+MIPLREADRSP=%d,%d,%d,%d,%d,%d,%d,%d,\"%.*s\",%d,%d\r\n" /* Read str请求的响应                   */
#define QS100_CMD_MIPLREADRSP_OPAQUE            "AT+MIPLREADRSP=%d,%d,%d,%d,%d,%d,%d,%d,%.*s,%d,%d\r\n"     /* Read opaque请求的响应                */
#define QS100_CMD_MIPLREADRSP_INT               "AT+MIPLREADRSP=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"       /* Read int请求的响应                   */
#define QS100_CMD_MIPLREADRSP_FLOAT             "AT+MIPLREADRSP=%d,%d,%d,%d,%d,%d,%d,%d,%f,%d,%d\r\n"       /* Read float请求的响应                 */
#define QS100_CMD_MIPLREADRSP_BOOL              "AT+MIPLREADRSP=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"       /* Read bool请求的响应                  */
#define QS100_CMD_MIPLWRITERSP                  "AT+MIPLWRITERSP=%d,%d,%d\r\n"                              /* Write请求的响应                      */
#define QS100_CMD_MIPLEXECUTERSP                "AT+MIPLEXECUTERSP=%d,%d,%d\r\n"                            /* Execute 请求的响应                   */
#define QS100_CMD_MIPLPARAMETERRSP              "AT+MIPLPARAMETERRSP=%d,%d,%d\r\n"                          /* Write 属性请求的响应                 */
#define QS100_CMD_MIPLNOTIFY_STR                "AT+MIPLNOTIFY=%d,%d,%d,%d,%d,%d,%d,\"%.*s\",%d,%d,%d\r\n"  /* Notify 数据到 ONENET 云端            */
#define QS100_CMD_MIPLNOTIFY_OPAQUE             "AT+MIPLNOTIFY=%d,%d,%d,%d,%d,%d,%d,%.*s,%d,%d,%d\r\n"      /* Notify 数据到 ONENET 云端            */
#define QS100_CMD_MIPLNOTIFY_INT                "AT+MIPLNOTIFY=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"        /* Notify 数据到 ONENET 云端            */
#define QS100_CMD_MIPLNOTIFY_FLOAT              "AT+MIPLNOTIFY=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"        /* Notify 数据到 ONENET 云端            */
#define QS100_CMD_MIPLNOTIFY_BOOL               "AT+MIPLNOTIFY=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"        /* Notify 数据到 ONENET 云端            */
#define QS100_CMD_MIPLUPDATE                    "AT+MIPLUPDATE=%d,%d,%d\r\n"                                /* 发送更新请求                         */
#define QS100_CMD_ONETRMLFT                     "AT+ONETRMLFT\r\n"                                          /* 查询当前 ONENET 剩余 LIFETIME 时间    */

/* 通用响应解析    */
#define QS100_RESPONSE_CSQ                      "%*[^:]:%hhu"                                               /* 查询信号强度 响应                     */
#define QS100_RESPONSE_MIPLCREATE               "%*[^:]:%hhu"                                               /* 创建网络通信套件 响应                  */
#define QS100_RESPONSE_NPTWEDRXP                "%*[^:]:%hhu,\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\""   /* NPTWEDRXP 事件通知                    */
#define QS100_RESPONSE_CGATT                    "%*[^:]:%hhu\r\n"                                           /* 网络注册状态主动上报                   */
#define QS100_RESPONSE_POWERON                  "%*[^:]:%hhu\r\n"                                           /* 上电完成主动上报                      */ 
#define QS100_RESPONSE_SIMST                    "%*[^:]:%hhu\r\n"                                           /* SIM卡状态主动上报                     */

/* onenet 响应格式 */
#define QS100_RESPONSE_ONETRMLFT                "%*[^:]:%u\r\n"                                             /* 查询当前 ONENET 剩余 LIFETIME 时间    */
#define QS100_RESPONSE_MIPLDISCOVER             "%*[^:]:%hhu,%u,%hd\r\n"                                    /* 主动上报Discover 请求                 */
#define QS100_RESPONSE_MIPLOBSERVE              "%*[^:]:%hhu,%u,%hhu,%hd,%hd,%hd\r\n"                       /* 主动上报 Observe 请求                 */
#define QS100_RESPONSE_MIPLREAD                 "%*[^:]:%hhu,%u,%hd,%hd,%hd\r\n"                            /* 主动上报 Read 请求                    */
#define QS100_RESPONSE_MIPLWRITE_STR_CAPTURE    "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,\"%s\",%hhu,%hhu\r\n"  /* 主动上报 Write str请求                */
#define QS100_RESPONSE_MIPLWRITE_STR_IGNORE     "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,\"%*s\",%hhu,%hhu\r\n" /* 主动上报 Write str请求 获取数据长度    */
#define QS100_RESPONSE_MIPLWRITE_OPAQUE_CAPTURE "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,%s,%hhu,%hhu\r\n"      /* 主动上报 Write opaque请求             */
#define QS100_RESPONSE_MIPLWRITE_OPAQUE_IGNORE  "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,%*s,%hhu,%hhu\r\n"     /* 主动上报 Write opaque请求 获取数据长度 */
#define QS100_RESPONSE_MIPLWRITE_INT            "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,%lld,%hhu,%hhu\r\n"    /* 主动上报 Write int 获取数据长度        */
#define QS100_RESPONSE_MIPLWRITE_FLAOT          "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,%f,%hhu,%hhu\r\n"      /* 主动上报 Write float 请求             */
#define QS100_RESPONSE_MIPLWRITE_BOOL           "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%hu,%hhu,%hhu,%hhu\r\n"    /* 主动上报 Write bool 请求 获取数据长度  */
#define QS100_RESPONSE_MIPLEXECUTE_CAPTURE      "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%s\r\n"                    /* 主动上报 Execute 请求                 */
#define QS100_RESPONSE_MIPLEXECUTE_IGNORE       "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%*s\r\n"                   /* 主动上报 Execute 请求 获取数据长度     */
#define QS100_RESPONSE_MIPLPARAMETER_CAPTURE    "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%s\r\n"                    /* 主动上报 Write 属性请求               */
#define QS100_RESPONSE_MIPLPARAMETER_IGNORE     "%*[^:]:%hhu,%u,%hd,%hd,%hd,%hhu,%*s\r\n"                   /* 主动上报 Write 属性请求 获取数据长度   */
#define QS100_RESPONSE_MIPLEVENT                "%*[^:]:%hhu,%hhu"                                          /* 主动上报 EVENT 事件通知               */

/* 响应前缀 */
#define QS100_RESPONSE_OK                       "OK"                                                        /* 响应成功                             */
#define QS100_RESPONSE_ERROR                    "ERROR"                                                     /* 响应失败                             */
#define QS100_RESPONSE_PREFIX_MIPLCREATE        "+MIPLCREATE:"                                              /* 创创建 ONENET 通信套件实例            */
#define QS100_RESPONSE_PREFIX_MIPLVER           "+MIPLVER:"                                                 /* 查询当前 ONENET 通信套件版本          */

/* 主动上报 URC */
#define QS100_URC_ECHO                          "AT+"                                                       /* 串口回显                             */
#define QS100_URC_POWERON                       "+POWERON:"                                                 /* 上电完成主动上报                      */
#define QS100_URC_SIMST                         "SIMST:"                                                    /* SIM卡状态主动上报                     */
#define QS100_URC_MIPLDISCOVER                  "+MIPLDISCOVER:"                                            /* 主动上报Discover                     */
#define QS100_URC_MIPLOBSERVE                   "+MIPLOBSERVE:"                                             /* 主动上报 Observe                     */
#define QS100_URC_MIPLREAD                      "+MIPLREAD:"                                                /* 主动上报 Read                        */
#define QS100_URC_MIPLWRITE                     "+MIPLWRITE:"                                               /* 主动上报 Write                       */
#define QS100_URC_MIPLEXECUTE                   "+MIPLEXECUTE:"                                             /* 主动上报 Execute                     */
#define QS100_URC_MIPLPARAMETER                 "+MIPLPARAMETER:"                                           /* 主动上报 Write                       */
#define QS100_URC_MIPLEVENT                     "+MIPLEVENT:"                                               /* 主动上报 EVENT                       */
#define QS100_URC_NPTWEDRXP                     "+NPTWEDRXP:"                                               /* 主动上报 NPTWEDRXP                   */

/* AT命令结构体类型 */
typedef struct
{ 
    uint16_t index;                    /* 命令在列表中的序号                  */
    const uint8_t *testCmd;            /* 测试命令 AT+<X>=?                  */
    const uint8_t *setCmd;             /* 设置命令 AT+<X>=<...>              */
    const uint8_t *readCmd;            /* 查询命令 AT+<X>?                   */
    const uint8_t *executeCmd;         /* 执行命令 AT+<X>                    */
    const uint8_t *responsePrefix;     /* 期望的响应前缀                     */
    const uint8_t *cmdInfor;           /* 命令注释说明                       */
} at_cmd_t;

/* AT命令类型      */
typedef enum 
{
    AT_CMD_TEST = 0,                   /* 测试命令                           */
    AT_CMD_SET,                        /* 设置命令                           */
    AT_CMD_READ,                       /* 查询命令                           */
    AT_CMD_EXECUTE                     /* 执行命令                           */
} at_cmd_type_t;

/* AT命令索引       */
typedef enum 
{
    AT_CMD_RB = 0,                     /* 设备软重启                         */
    AT_CMD_CGATT,                      /* PS附着/去附着                      */
    AT_CMD_CSQ,                        /* 获得信号强度指示                    */
    AT_CMD_ATE,                        /* 开启串口回显                        */
    AT_CMD_COPS,                       /* 运营商选择                          */
    AT_CMD_CGDCONT,                    /* 定义PDP上下文                       */
    AT_CMD_CGACT,                      /* PDP上下文激活/去激活                */
    AT_CMD_CPIN,                       /* PIN码输入与管理                     */
    AT_CMD_CEREG,                      /* EPS网络注册状态                     */
    AT_CMD_NTSETID,                    /* 设置IMEI号                         */
    AT_CMD_NCCID,                      /* 查询SIM卡ID                        */
    AT_CMD_CGSN,                       /* 获取产品序列号                      */
    AT_CMD_CIMI,                       /* 获取IMSI号                         */
    AT_CMD_NV,                         /* NV参数动态配置                      */
    AT_CMD_FASTOFF,                    /* 快速断电                            */
    AT_CMD_WORKLOCK,                   /* 省电锁                              */
    AT_CMD_CEDRXRDP,                   /* 读取扩展DRX动态参数                  */
    AT_CMD_NPTWEDRXS,                  /* 寻呼时间窗及eDRX设置                 */
    AT_CMD_CPSMS,                      /* 省电模式PSM设置                     */
    AT_CMD_CRTDCP,                     /* 下行数据主动上报设置                 */
    AT_CMD_XNTP,                       /* 查询NTP时间                         */
    
    AT_CMD_MAX                         /* 命令总数,用于边界检查               */
} at_cmd_index_t;

/* onenet 事件类型 */
typedef enum 
{
    ONENET_EVENT_BOOTSTRAP_START = 1,  /* 引导启动事件                        */
    ONENET_EVENT_BOOTSTRAP_SUCCESS,    /* 引导成功                            */
    ONENET_EVENT_BOOTSTRAP_FAILED,     /* 引导失败                            */
    ONENET_EVENT_CONNECT_SUCCESS,      /* 连接成功                            */
    ONENET_EVENT_CONNECT_FAILED,       /* 连接失败                            */
    ONENET_EVENT_REG_SUCCESS,          /* 注册成功                            */
    ONENET_EVENT_REG_FAILED,           /* 注册失败                            */
    ONENET_EVENT_REG_TIMEOUT,          /* 注册超时                            */
    ONENET_EVENT_LIFETIME_TIMEOUT,     /* 生命周期超时                        */
    ONENET_EVENT_STATUS_HALT,          /* 状态停止                            */
    ONENET_EVENT_UPDATE_SUCCESS,       /* 更新成功                            */
    ONENET_EVENT_UPDATE_FAILED,        /* 更新失败                            */
    ONENET_EVENT_UPDATE_TIMEOUT,       /* 更新超时                            */
    ONENET_EVENT_UPDATE_NEED,          /* 需要更新                            */
    ONENET_EVENT_UNREG_DONE,           /* 注销完成                            */
    ONENET_EVENT_RESPONSE_FAILED = 20, /* 响应失败                            */
    ONENET_EVENT_RESPONSE_SUCCESS,     /* 响应成功                            */
    ONENET_EVENT_NOTIFY_FAILED = 25,   /* 通知失败                            */
    ONENET_EVENT_NOTIFY_SUCCESS,       /* 通知成功                            */
    ONENET_EVENT_MAX,                  /* 事件最大值                          */
} onenet_event_t;

// /* 响应解析函数类型 */
// typedef com_status_t (*response_handler)(uint8_t* response, 
//                                          void* output_param); 

/* 消息标识 */
typedef enum {
    MSG_FLAG_LAST   = 0,               /* 最后一条消息                         */ 
    MSG_FLAG_FIRST  = 1,               /* 第一条消息                          */   
    MSG_FLAG_MIDDLE = 2                /* 中间消息                            */ 
} message_flag_t;

/* eDRX模式 */
typedef enum 
{
    EDRX_DISABLED = 0,                 /* 不使用eDRX                          */ 
    EDRX_ENABLED = 1,                  /* 使用eDRX                            */ 
    EDRX_ENABLED_WITH_REPORT = 2,      /* 使用eDRX,当网络参数发生变化时主动上报 */ 
    EDRX_DISABLED_WITH_RESET = 3       /* 不使用eDRX,且指令中其他参数值无效, 
                                          如果可以则直接将其他参数值恢复出厂值   */ 
} eDRX_mode_t;  

/* PSM 模式 */
typedef enum 
{
    PSM_DISABLED = 0,                  /* 不使用PSM */ 
    PSM_ENABLED = 1,                   /* 使用PSM */ 
    PSM_RESTORE_DEFAULT = 2            /* 不使用PSM,且设置指令中其他参数值无效,
                                          如果可以则直接将其他参数值恢复出厂值   */ 
} psm_mode_t;

/* PTW时间 */
typedef enum 
{
    PTW_2_56S   = 0x00,                /* 0000                                */ 
    PTW_5_12S   = 0x01,                /* 0001                                */ 
    PTW_7_68S   = 0x02,                /* 0010                                */ 
    PTW_10_24S  = 0x03,                /* 0011                                */ 
    PTW_12_80S  = 0x04,                /* 0100                                */ 
    PTW_15_36S  = 0x05,                /* 0101                                */ 
    PTW_17_92S  = 0x06,                /* 0110                                */ 
    PTW_20_48S  = 0x07,                /* 0111                                */ 
    PTW_23_04S  = 0x08,                /* 1000                                */ 
    PTW_25_60S  = 0x09,                /* 1001                                */ 
    PTW_28_16S  = 0x0A,                /* 1010                                */ 
    PTW_30_72S  = 0x0B,                /* 1011                                */ 
    PTW_33_28S  = 0x0C,                /* 1100                                */ 
    PTW_35_84S  = 0x0D,                /* 1101                                */ 
    PTW_38_40S  = 0x0E,                /* 1110                                */ 
    PTW_40_96S  = 0x0F                 /* 1111                                */ 
} PTW_t;

/* eDRX周期 */
typedef enum {
    EDRX_CYCLE_20_48_S   = 0x02,       /* 0010                                */  
    EDRX_CYCLE_40_96_S   = 0x03,       /* 0011                                */   
    EDRX_CYCLE_81_92_S   = 0x05,       /* 0101                                */  
    EDRX_CYCLE_163_84_S  = 0x09,       /* 1001                                */  
    EDRX_CYCLE_327_68_S  = 0x0A,       /* 1010                                */  
    EDRX_CYCLE_655_36_S  = 0x0B,       /* 1011                                */  
    EDRX_CYCLE_1310_72_S = 0x0C,       /* 1100                                */  
    EDRX_CYCLE_2621_44_S = 0x0D,       /* 1101                                */  
    EDRX_CYCLE_5242_88_S = 0x0E,       /* 1110                                */  
    EDRX_CYCLE_10485_76_S= 0x0F        /* 1111                                */  
} eDRX_cycle_t;

/* eDRX参数 */
typedef struct 
{
    eDRX_mode_t mode;                  /* eDRX模式                            */
    const uint8_t* PTW;                /* PTW时间                             */
    const uint8_t* eDRX_value;         /* eDRX周期                            */
} eDRX_t;

/* PSM参数 */
typedef struct 
{
    psm_mode_t mode;                  /* PSM模式                              */
    const uint8_t* T3412_time;        /* T3412时间                            */
    const uint8_t* T3324_time;        /* T3324时间                            */
} PSM_t;

/* PDP参数 */
typedef struct 
{
    uint8_t cid;                      /* PDP实例ID                            */
    const uint8_t* PDP_type;          /* 数据包交换协议类型                     */
    const uint8_t* APN;               /* APN                                  */
    uint8_t status;                   /* PDP状态                               */
} PDP_t;

/* LwM2M 增加实例 */
typedef struct 
{
    uint16_t objectid;               /* 对象id                                */
    uint8_t instancecount;           /* 实例个数                              */
    uint8_t* instancebitmap;         /* 实例位图                              */
    uint8_t attributecount;          /* 属性个数                              */
    uint8_t actioncount;             /* 操作个数                              */
} mipladdob_cmd_t;

/* LwM2M 资源路径 */
typedef struct 
{
    int16_t objectid;                /* 对象id                                */
    int16_t instanceid;              /* 实例id                                */
    int16_t resourceid;              /* 资源id                                */
} lwm2m_path_t;

/* 基础命令 */
typedef struct 
{
    uint8_t ref;                     /* 实例标识                              */    
    uint32_t msgid;                  /* 消息id                                */
    lwm2m_path_t path;               /* lwm2m2m 资源路径                      */
} cmd_base_t;

/* DISCOVERRSP 命令参数 */
typedef struct 
{    
    uint32_t msgid;                  /* 消息id                                */
    uint8_t result;                  /* 操作结果                              */
    uint8_t length;                  /* 返回 valuestring 的长度               */
    uint8_t* valuestring;            /* object 的属性要求,多个属性放置
                                        双引号“”中,使用分号“;”隔开            */   
} discoverrsp_cmd_t;

/* DISCOVER 命令参数 */
typedef struct 
{
    cmd_base_t base;                 /* 基础命令参数                           */
} discover_response_t;

/* OBSERVERSP 命令参数 */
typedef struct 
{
    uint32_t msgid;                  /* 消息id                                */
    uint8_t result;                  /* 操作结果                              */
} observersp_cmd_t;

/* OBSERVE 命令参数 */
typedef struct 
{
    cmd_base_t base;                 /* 基础命令参数                          */
    uint8_t flag;                    /* 操作标志                              */
} observe_response_t;

/* READRSP 命令参数 */
typedef struct
{
    cmd_base_t base;                 /* 基础命令参数                          */
    uint8_t result;                  /* 操作结果                             */
    uint8_t valuetype;               /* 发送的数据类型                        */
    uint16_t len;                    /* 发送的数据长度                        */
    union 
    {
        int64_t int_type;            /* 写入整型                             */
        uint8_t * opaque_type;       /* 写入16进制数据                       */
        uint8_t* str_type;           /* 写入字符串                           */
        float float_type;            /* 写入浮点型                           */
        uint8_t bool_type;           /* 写入布尔型                           */
    } data_t;
    message_flag_t flag;             /* 消息标志                             */
    uint8_t index;                   /* 指令序号(可以将一条消息分为多次发送) 
                                        则 index 从 N-1 至 0,
                                        index 编号为 0 时表示本次指令结束     */ 
} readrsp_cmd_t;

/* READ 命令参数 */
typedef struct
{
    cmd_base_t base;                 /* 基础命令参数                         */
} read_response_t;

/* WRITERSP 命令参数 */
typedef struct
{
    uint32_t msgid;                  /* 消息id                              */  
    uint8_t result;                  /* 操作结果                            */
} writersp_cmd_t;

/* WRITE 命令参数 */
typedef struct
{
    cmd_base_t base;                 /* 基础命令参数                        */
    uint8_t result;                  /* 操作结果                            */
    uint8_t valuetype;               /* 写入的数据类型                      */
    uint16_t len;                    /* 写入的数据长度                      */
    union 
    {
        int64_t* int_type;           /* 写入整型                            */
        uint8_t * opaque_type;       /* 写入16进制数据                      */
        uint8_t* str_type;           /* 写入字符串                          */
        float* float_type;           /* 写入浮点型                          */
        uint8_t* bool_type;          /* 写入布尔型                          */
    } data_t;
    message_flag_t flag;             /* 消息标志                            */
    uint8_t index;                   /* 指令序号(可以将一条消息分为多次发送) 
                                        则 index 从 N-1 至 0,
                                        index 编号为 0 时表示本次指令结束     */ 
} write_response_t;

/* EXECUTERSP 命令参数 */
typedef struct 
{
    uint32_t msgid;                  /* 消息id                              */
    uint8_t result;                  /* 操作结果                            */
} executersp_cmd_t;

/* EXECUTE 命令参数 */
typedef struct 
{
    cmd_base_t base;                 /* 基础命令参数                        */
    uint8_t len;                     /* 参数的字符长度                       */       
    uint8_t* arguments;              /* 执行的字符串格式参数                 */
} execute_response_t;

/* PARAMETERRSP 命令参数 */
typedef struct 
{
    uint32_t msgid;                  /* 消息id                              */
    uint8_t result;                  /* 操作结果                            */
} parameterrsp_cmd_t;

/* PARAMETER 命令参数 */
typedef struct 
{
    cmd_base_t base;                 /* 基础命令参数                         */
    uint8_t len;                     /* 参数的字符长度                       */       
    uint8_t* parameter;              /* 策略参数                            */
} parameter_response_t;

/* NOTIFY 命令参数 */
typedef struct 
{
    cmd_base_t base;                 /* 基础命令参数                         */
    uint8_t valuetype;               /* 发送的数据类型                       */
    uint8_t len;                     /* 发送的数据长度                       */
    union 
    {
        uint32_t int_type;           /* 发送整型                             */
        uint8_t * opaque_type;       /* 发送16进制数据                       */
        uint8_t* str_type;           /* 发送字符串                           */
        float float_type;            /* 发送浮点型                           */
        uint8_t bool_type;           /* 发送布尔型                           */
    } data_t;
    message_flag_t flag;             /* 消息标志                             */
    uint8_t index;                   /* 指令序号(可以将一条消息分为多次发送) 
                                        则 index 从 N-1 至 0,
                                        index 编号为 0 时表示本次指令结束     */
    uint8_t ackid;                   /* 确认id                               */
} notify_cmd_t; 

/* EVENT 命令参数 */
typedef struct 
{
    uint8_t ref;                     /* 实例标识                             */
    uint8_t evtid;                   /* 事件id                              */
    uint16_t params;                 /* 参数                                */
} event_response_t;

/* NPTWEDRXP 命令参数 */
typedef struct 
{
    uint8_t AcT_type;                /* 接入技术类型                         */
    uint8_t requested_PTW[5];        /* 请求的PTW                            */
    uint8_t requested_eDRX_value[5]; /* 请求的eDRX值                         */
    uint8_t PTW[5];                  /* 实际的PTW                            */
    uint8_t eDRX_value[5];           /* 实际的eDRX值                         */
} nptwedrxp_response_t;

/* LWM2M 状态码 */
typedef enum 
{
    LWM2M_STATUS_OK_1 = 1,                /* 2.05 Content - 操作正确完成     */ 
    LWM2M_STATUS_OK_2 = 2,                /* 2.04 Content - 操作正确完成     */ 
    LWM2M_STATUS_BAD_REQUEST = 11,        /* 4.00 Bad Request               */ 
    LWM2M_STATUS_UNAUTHORIZED = 12,       /* 4.01 Unauthorized              */ 
    LWM2M_STATUS_NOT_FOUND = 13,          /* 4.04 Not Found                 */ 
    LWM2M_STATUS_METHOD_NOT_ALLOWED = 14, /* 4.05 Method Not Allowed        */ 
    LWM2M_STATUS_NOT_ACCEPTABLE = 15,     /* 4.06 Not Acceptable            */ 
} lwm2m_status_code_t;

/* LWM2M 数据类型 */
typedef enum 
{
    LWM2M_TYPE_STRING  = 1,               /* 字符串类型                     */ 
    LWM2M_TYPE_OPAQUE  = 2,               /* 不透明的二进制数据              */ 
    LWM2M_TYPE_INTEGER = 3,               /* 整数类型                       */ 
    LWM2M_TYPE_FLOAT   = 4,               /* 浮点数类型                      */ 
    LWM2M_TYPE_BOOL    = 5,               /* 布尔类型                       */ 
} lwm2m_data_type_t;

/* 重启原因枚举  */
typedef enum 
{
    RESET_REASON_POWER_ON         = 0,    /* 正常的上电动作                   */
    RESET_REASON_PIN_RESET        = 1,    /* PIN 复位,供外部进行芯片的硬复位  */
    RESET_REASON_SOFT_RESET       = 2,    /* 软重启功能                       */
    RESET_REASON_UTC_WAKEUP       = 3,    /* UTC 唤醒动作                     */
    RESET_REASON_EXT_PIN_WAKEUP   = 4,    /* 外部 PIN 唤醒,常与数据通信绑定   */
    RESET_REASON_WDT_RESET        = 5,    /* 硬件看门狗重启                   */
    RESET_REASON_UNKNOWN          = 6     /* 未知的异常重启,如电容放电不充分等 */
} reset_reason_t;

/* 卡状态枚举 */
typedef enum 
{
    CARD_STATUS_NO_CARD           = 0,    /* 无卡                            */
    CARD_STATUS_INIT_SUCCESS      = 1,    /* 开机上电或深睡唤醒,卡初始化成功  */
    CARD_STATUS_DEEP_SLEEP_WAKE   = 2     /* 深睡唤醒,未做卡初始化,
                                            保持深睡前卡状态,
                                            不支持深睡期间热插拔              */
} card_status_t;

/* QS100 DISCOVER 请求回调函数 */
typedef void (*QS100_DISCOVER_callback)(discover_response_t* discover_response);

/* QS100 OBSERVE 请求回调函数 */
typedef void (*QS100_OBSERVE_callback)(observe_response_t* observe_response);

/* QS100 READ 请求回调函数 */
typedef void (*QS100_READ_callback)(read_response_t* read_response);

/* QS100 WRITE 请求回调函数 */
typedef void (*QS100_WRITE_callback)(write_response_t* write_response);

/* QS100 EXECUTE 请求回调函数 */
typedef void (*QS100_EXECUTE_callback)(execute_response_t* execute_response);

/* QS100 PARAMETER 请求回调函数 */
typedef void (*QS100_PARAMETER_callback)(parameter_response_t* parameter_response);

/* QS100 EVENT 请求回调函数 */
typedef void (*QS100_EVENT_callback)(event_response_t* event_response);

/* QS100 NPTWEDRXP 请求回调函数 */
typedef void (*QS100_NPTWEDRXP_callback)(nptwedrxp_response_t* nptwedrxp_response);

/* QS100 POWERON 请求回调函数 */
typedef void (*QS100_POWERON_callback)(uint8_t status);

/* QS100 SIMST 请求回调函数 */
typedef void (*QS100_SIMST_callback)(uint8_t status);

/**
 * @brief  获取命令字符串
 * 
 * @param  cmd_index         命令索引
 * @param  cmd_type          命令类型
 * 
 * @return 返回命令
 */
const uint8_t *get_at_cmd_string(at_cmd_index_t cmd_index, 
                                 at_cmd_type_t cmd_type);

/**
 * @brief  获取命令前缀
 * 
 * @param  cmd_index         命令索引
 * 
 * @return 命令前缀
 */
const uint8_t *get_at_response_prefix(at_cmd_index_t cmd_index);

/**
 * @brief  QS100 将PTW转换为二进制字符串
 * 
 * @param  PTW               寻呼时间窗口
 * 
 * @retval 返回ptw字符串
 */
const uint8_t* PTW_to_bin_str(PTW_t ptw);

/**
 * @brief  QS100 将eDRX转换为二进制字符串
 * 
 * @param  cycle             eDRX周期
 * 
 * @retval 返回eDRX字符串
 */
const uint8_t* eDRX_to_bin_str(eDRX_cycle_t cycle);

/**
 * @brief  QS100 获取onenet 实例标识
 * 
 * @param  无
 * 
 * @retval 返回实例标识
 */
uint8_t QS100_get_onenet_instance(void);
/**
 * @brief  QS100 唤醒
 * 
 * @param  无
 * 
 * @retval 无
 */
void Int_QS100_wakeup(void);

/**
 * @brief  QS100 重启
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_reset(at_client_t* client);

/**
 * @brief  QS100 打开串口回显
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_ATE(at_client_t* client);

/**
 * @brief  QS100 设置IMEI
 * 
 * @param  imei              IMEI
 * @param  imei              IMEI 号
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_set_IMEI(at_client_t* client, 
                                 uint8_t *imei);

/**
 * @brief  QS100 查询信号强度
 * 
 * @param  client            at 客户端句柄 
 * @param  rssi              返回信号强度
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CSQ(at_client_t* client, 
                                 uint8_t* rssi);

/**
 * @brief  QS100 查询运营商
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_COPS(at_client_t* client);

/**
 * @brief  QS100 查询 PDP 上下文
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CGDCONT(at_client_t* client);

/**
 * @brief  QS100 设置 PDP 上下文
 * 
 * @param  client            at 客户端句柄 
 * @param  pdp               PDP 参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_set_CGDCONT(at_client_t* client,
                                   PDP_t *pdp);

/**
 * @brief  QS100 激活/断开 PDP 上下文
 * 
 * @param  client            at 客户端句柄 
 * @param  pdp               pdp 参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_set_CGACT(at_client_t* client,
                                 PDP_t *pdp);

/**
 * @brief  QS100 查询是否需要输入pin码
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CPIN(at_client_t* client);

/**
 * @brief  QS100 查询网络注册状态
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CEREG(at_client_t* client);

/**
 * @brief  QS100 查询SIM卡ID
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_NCCID(at_client_t* client);

/**
 * @brief  QS100 查询IMEI号
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_IMEI(at_client_t* client);

/**
 * @brief  QS100 查询IMSI号
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_IMSI(at_client_t* client);

/**
 * @brief  QS100 保存NV
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_execute_NV_SAVE(at_client_t* client);

/**
 * @brief  QS100 查询是否有网络
 * 
 * @param  client            at 客户端句柄 
 * @param  attach            返回网络附着状态
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CGATT(at_client_t* client, 
                                    uint8_t* attach);

/**
 * @brief  查询省电锁
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回查询结果
 */
com_status_t Int_QS100_query_WORKLOCK(at_client_t* client);

/**
 * @brief  设置省电锁
 * 
 * @param  client            at 客户端句柄 
 * @param  switch_mode       省电锁状态
 * 
 * @retval                   返回查询结果
 */
com_status_t Int_QS100_set_WORKLOCK(at_client_t* client, 
                                     uint8_t switch_mode);

/**
 * @brief  查询扩展 DRX 动态参数
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CEDRXRDP(at_client_t* client);

/**
 * @brief  查询寻呼时间窗及 eDRX
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回查询结果
 */
com_status_t Int_QS100_query_NPTWEDRXS(at_client_t* client);

/**
 * @brief  设置寻呼时间窗及 eDRX
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回设置结果
 */
com_status_t Int_QS100_set_eDRX(at_client_t* client, 
                                 eDRX_t eDRX);

/**
 * @brief  查询 PSM 参数
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_CPSMS(at_client_t* client);

/**
 * @brief  设置 PSM
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回设置结果
 */
com_status_t Int_QS100_set_PSM(at_client_t* client, 
                                PSM_t PSM);

/**
* @brief  QS100 查询主动上报下行数据
* 
* @param  client            at 客户端句柄 
* 
* @retval                   返回执行结果
*/
com_status_t Int_QS100_query_CRTDCP(at_client_t* client);

/**
* @brief  QS100 设置主动上报下行数据
* 
* @param  client            at 客户端句柄 
* @param  reporting         是否主动上报下行数据
* 
* @retval                   返回执行结果
*/
com_status_t Int_QS100_set_CRTDCP(at_client_t* client,
                                  uint8_t reporting);

/**
 * @brief  QS100 查询onenet通讯套件版本号
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_query_NV_MIPLVER(at_client_t* client);

/**
 * @brief  QS100 创建onenet通讯套件
 * 
* @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLCREATE(at_client_t* client);

/**
 * @brief  QS100 删除onenet通讯套件
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLDELETE(at_client_t* client);

/**
 * @brief  QS100 增加 LwM2M 实例
 * 
 * @param  client            at 客户端句柄 
 * @param  mipladdob_cmd     命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLADDOB(at_client_t* client, 
                                  mipladdob_cmd_t mipladdob_cmd);

/**
 * @brief  QS100 删除 LwM2M 实例
 * 
 * @param  client            at 客户端句柄 
 * @param  objectid          对象id
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLDELOBJ(at_client_t* client, 
                                  uint16_t objectid);

/**
 * @brief  QS100 发起注册请求
 * 
 * @param  client            at 客户端句柄 
 * @param  lifetime          生命周期
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLOPEN(at_client_t* client, 
                                 uint16_t lifetime);

/**
 * @brief  QS100 发送注销请求
 * 
 * @param  client            at 客户端句柄 
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLCLOSE(at_client_t* client);

/**
 * @brief  QS100 Discover请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  discover_cmd      命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLDISCOVERRSP(at_client_t* client, 
                                        discoverrsp_cmd_t discover_cmd);

/**
 * @brief  QS100 Observe请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  observersp_cmd    命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLOBSERVERSP(at_client_t* client, 
                                       observersp_cmd_t observersp_cmd);

/**
 * @brief  QS100 Read 请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  readrsp_cmd       命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLREADRSP(at_client_t* client, 
                                    readrsp_cmd_t readrsp_cmd);

/**
 * @brief  QS100 Write请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  writersp_cmd      命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLWRITERSP(at_client_t* client, 
                                     writersp_cmd_t writersp_cmd);

/**
 * @brief  QS100 Execute 请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  executersp_cmd    命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLEXECUTERSP(at_client_t* client, 
                                       executersp_cmd_t executersp_cmd);

/**
 * @brief  QS100 PARAMETERRSP 请求的响应
 * 
 * @param  client            at 客户端句柄 
 * @param  parameterrsp_cmd  命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLPARAMETERRSP(at_client_t* client, 
                                         parameterrsp_cmd_t parameterrsp_cmd);

/**
 * @brief  QS100 Notify 数据到 ONENET 云端
 * 
 * @param  client            at 客户端句柄 
 * @param  notify_cmd        命令参数
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLNOTIFY(at_client_t* client, 
                                   notify_cmd_t notify_cmd);

/**
 * @brief  QS100 发送更新请求
 * 
 * @param  client            at 客户端句柄 
 * @param  lifetime          更新的 lifetime 值(0:为默认24小时,最短120s)
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_MIPLUPDATE(at_client_t* client, 
                                   uint16_t lifetime);

/**
 * @brief  QS100 查询当前 ONENET 剩余 LIFETIME 时间
 * 
 * @param  client            at 客户端句柄 
 * @param  lifetime          返回剩余时间
 * 
 * @retval                   返回执行结果
 */
com_status_t Int_QS100_ONETRMLFT(at_client_t* client, 
                                  uint32_t *lifetime);

/**
 * @brief  QS100 初始化
 * 
 * @param  无
 * 
 * @retval 无
 */
at_client_t* Int_QS100_init(void);

/** 
 * @brief  QS100 模块任务
 * 
 * @param  client            at 客户端句柄
 * 
 * @retval 无
 */
void Int_QS100_task(at_client_t* client);

/**
 * @brief  QS100 基础命令测试
 * 
  * @param  client            at 客户端句柄 
 * 
 * @retval 无
 */
void Int_QS100_test(at_client_t* client);

/**
 * @brief  注册QS100 DISCOVER 事件回调函数
 * 
 * @param  callback         DISCOVER 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_DISCOVER_callback(QS100_DISCOVER_callback callback);

/**
 * @brief  注册QS100 OBSERVE 事件回调函数
 * 
 * @param  callback          OBSERVE 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_OBSERVE_callback(QS100_OBSERVE_callback callback);

/**
 * @brief  注册QS100 READ 事件回调函数
 * 
 * @param  callback          READ 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_READ_callback(QS100_READ_callback callback);

/**
 * @brief  注册QS100 WRITE 事件回调函数
 * 
 * @param  callback          WRITE 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_WRITE_callback(QS100_WRITE_callback callback);

/**
 * @brief  注册QS100 EXECUTE 事件回调函数
 * 
 * @param  callback          EXECUTE 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_EXECUTE_callback(QS100_EXECUTE_callback callback);

/**
 * @brief  注册QS100 PARAMETER 事件回调函数
 * 
 * @param  callback          PARAMETER 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_PARAMETER_callback(QS100_PARAMETER_callback callback);

/**
 * @brief  注册QS100 EVENT 事件回调函数
 * 
 * @param  callback          EVENT 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_EVENT_callback(QS100_EVENT_callback callback);

/**
 * @brief  注册QS100 NPTWEDRXP 事件回调函数
 * 
 * @param  callback          NPTWEDRXP事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_NPTWEDRXP_callback(QS100_NPTWEDRXP_callback callback);

/**
 * @brief  注册QS100 POWERON 事件回调函数
 * 
 * @param  callback          POWERON 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_POWERON_callback(QS100_POWERON_callback callback);

/**
 * @brief  注册QS100 SIMST 事件回调函数
 * 
 * @param  callback          SIMST 事件处理函数
 * 
 * @retval 注册是否成功
 */
com_status_t QS100_register_SIMST_callback(QS100_SIMST_callback callback);


#endif

4. 连接onenet

#define LWM2M_OBJECT_COUNT                   1       /* 对象个数     */
#define LWM2M_INSTANCE_COUNT                 1       /* 实例个数     */
#define LWM2M_RESOURCE_COUNT                 2       /* 资源个数     */

#define LWM2M_OBJECT_UPLOAD_DATA             3300  /* 上传数据对象  */
#define LMM2M_RESOURCES_READ                 5750      /* 读资源 id     */
#define LMM2M_RESOURCES_WRITE                5701      /* 写资源 id     */

/**
 * @brief  连接onenet
 * 
 * @param  无
 * 
 * @retval 返回执行结果
 */
com_status_t App_connect_onenet(void)
{
    uint8_t attach = 0;
    do
    {
        if(COM_OK != Int_QS100_query_CGATT(client, &attach))
        {
            debug_println("QS100 网络附着失败");
            return COM_ERROR;
        }
        Com_delay_ms(300);
    } while (0 == attach);
    
    /* 创建onenet通信套件 */
    if(COM_OK != Int_QS100_MIPLCREATE(client))
    {
        debug_println("QS100 创建onenet通信套件失败");
        return COM_ERROR;
    }    

    /* 添加LwM2M实例 */
    mipladdob_cmd_t mipladdob_cmd;
    mipladdob_cmd.objectid = LWM2M_OBJECT_UPLOAD_DATA;
    mipladdob_cmd.instancecount = LWM2M_INSTANCE_COUNT;
    mipladdob_cmd.instancebitmap = instance_bitmap;
    mipladdob_cmd.attributecount = LWM2M_RESOURCE_COUNT;
    mipladdob_cmd.actioncount = 0;
    if(COM_OK != Int_QS100_MIPLADDOB(client, mipladdob_cmd))
    {
        debug_println("QS100 添加LwM2M实例失败");
        return COM_ERROR;
    }   
    /* 发起注册请求 */
    if(COM_OK != Int_QS100_MIPLOPEN(client, 3000))
    {
        debug_println("QS100 发起注册请求失败");
        return COM_ERROR;
    }
    return COM_OK;
}

/**
 * @brief  处理响应
 * 
 * @param  无
 * 
 * @retval 返回执行结果
 */
void App_response_handler(void)
{
    extern volatile uint8_t timer_flag;
    while(1)
    {
        if(timer_flag == 1)
        {
            timer_flag = 0;
            App_locator_upload_data();
        }    
        Int_QS100_task(client);
    }
}

四. 遇到的问题及解决办法

1. QS100上必须插物联卡

2. 出现,发送AT+CGATT指令,显示未附着,没有网络连接。

发送AT+CSQ接收到+CSQ:99,0说明没有信号,可能是SIM卡不能使用或者模组刚上电需等待一会。

如果信号正常发送:

  • AT+CPIN? :查询是否需要输入pin码,如果接收不为READY,则SIM卡需要输入密码解锁,可根据命令手册5.1解锁

  • AT+COPS?: 查询运营商,查看是否和物联卡的运营商信息相同,查看卡是否正常

    PLMN 运营商
    46000 中国移动 (GSM)
    46001 中国联通 (GSM)
    46002 中国移动 (TD-S)
    46003 中国电信 (CDMA)
    46005 中国电信 (CDMA)
    46006 中国联通 (WCDMA)
    46007 中国移动 (TD-S)
    46008 中国移动
    46009 中国联通
    46011 中国电信 (FDD-LTE)
  • AT+CEREG?: 查询网络注册状态,结果+CEREG:0,1第二位是否为1,如果为0说明没有网络连接,查看物联卡是否能使用

  • AT+NCCID?: 查询SIM卡ID,查看是否和SIM卡标识相同,如果识别不到,把卡拿出清理一下SIM卡接触点,如果还是识别不到换张卡再试试。

3. IMEI 查询全是0

使用这两个命令设置IMEI

/* QS100 设置IMEI */
if(COM_OK != Int_QS100_set_IMEI(client, QS100_IMEI))
    debug_println("QS100 设置IMEI失败");
/* QS100 保存NV */
if(COM_OK != Int_QS100_execute_NV_SAVE(client))
    debug_println("QS100 保存NV失败");
/* 重启 */
if(COM_OK != Int_QS100_reset(client))
    debug_println("QS100 重启失败");

4. 创建onenet通信套件

第一次创建需要将先将配置文件写入NV中,可以直接使用代码中的配置文件无需修改。也可通过官方qq群中的这个文件夹生成配置文件,具体查看文件夹中readme文件,生成后替换掉代码中的配置文件。

image-20251020163636962

/* QS100 onenet配置文件 */
#define QS100_CONFIG         "130040f10003f2003204001100000000"\
                             "00000000123138332e3233302e34302e"\
                             "34303a35363833000f41757468436f64"\
                             "653a3b50534b3a3bf30008e400c80000"

if(COM_OK == Int_QS100_MIPLCREATE(client))
    debug_println("QS100 创建onenet通信套件失败");
if(COM_OK != Int_QS100_execute_NV_SAVE(client))
	debug_println("QS100 保存NV失败");
if(COM_OK != Int_QS100_reset(client))
	debug_println("QS100 重启失败");

5.进入不了eDRX模式

image-20251103194232519

可以问问卖卡的这个卡支不支持eDRX,换张支持的卡。

6. 上报数据错误

上报数据太长可能会发生平台收到数据而模式响应上报失败。所以notifi时要加上ackid,这样当上报成功或失败时平台也会下发一个event事件。

7. 平台下发数据是asscii码

这点可以在onenet平台的文档中心或文档中心都有说明

image-20251109235034595

posted @ 2025-11-09 23:58  2666666  阅读(167)  评论(0)    收藏  举报