最近半年時間因為一直在忙項目的問題,一直沒有新的跟新。現在項目已經接近尾聲,自己也有一定的free時間,這次把該項目的一個新的知識點記成筆記,來提供大家學習分享。
1、項目内容
這個項目有使用到一個2G子產品(GSM6315)和nrf51822,使用2G網絡,與伺服器通信。通信方式為post,每次都是我(裝置端),去擷取伺服器的資料或者發送采集的資料給伺服器。協定是使用http/https,每次post資料時候,我需要把自己采集的資料加載到http、https協定裡面,一起給伺服器。
2、操作方式。
相信熟悉2G子產品的一個童鞋應該都知道,該子產品使用AT指令的,而且,我看了一下這個子產品的指令集資料,盡然和M26 的AT指令 有相似之處。不知道是不是互相參考了。這個地方不做辯解,随他們怎麼搞,我們主要是如何在http、https裡面增加自己的資料。大緻操作如下。
1、激活sim卡,進行入網配置
2、進行http或者https配置
3、拼接資料
4、post資料
5、從伺服器擷取資料。
3、具體操作和相關代碼
代碼隻給出部分代碼,因為這個函數是單獨封裝的,在200ms的定時器裡面進行輪詢,裡面有指令回饋逾時處理,指令錯誤處理,指令解析,資料解析等等,造成代碼很多,很長,很複雜。這裡隻給出發送指令部分,其他的需要童鞋自己去敲了 。
相關代碼(大家可以直接複制,然後修改進行使用)
switch(livall_Send_case_flag)
{
case 0 :
GSM6315_Send("ATE0",4); //關閉回顯
livall_Send_case_flag = 1;
Timeout_count_flag =10;//200ms*10 = 2000ms //指令逾時
SEGGER_RTT_printf(0,"==>1 ATE0 <==\r\n");
break ;
case 1 :
//等待序列槽指令回報
break ;
case 2:
sprintf(temp_buffer,"AT+CGDCONT=%d,\"%s\",\"%s\"",1,"IP","CMNET"); //營運商配置
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag =20;//200*20 = 4000ms//指令逾時
livall_Send_case_flag = 3;
SEGGER_RTT_printf(0,"==>2 AT+CGDCONT=1 IP,CMNET <==\r\n");
break ;
case 3:
//µÈ´ý½á¹û·µ»Ø
break ;
case 4:
sprintf(temp_buffer,"AT+CGACT=%d,%d",1,1);
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 40;//20*20 = 400ms
livall_Send_case_flag = 5;
SEGGER_RTT_printf(0,"==> 3 AT+CGACT=1.1<==\r\n");
break ;
case 5:
//等待序列槽指令回報
break ;
case 6:
sprintf(temp_buffer,"AT+QNTP=\"cn.ntp.org.cn\",123");//擷取中原標準時間配置
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 20;//200*20 = 4000ms
livall_Send_case_flag = 7;
SEGGER_RTT_printf(0,"==> 4 AT+QNTP=\"cn.ntp.org.cn\",123 <==\r\n");
break ;
case 7:
//等待序列槽指令回報
break ;
case 8:
GSM6315_Send("AT+CCLK?",8);//擷取中原標準時間
Timeout_count_flag = 100;
livall_Send_case_flag = 9;
SEGGER_RTT_printf(0,"==> 5 AT+CCLK? <==\r\n");
break ;
case 9:
//等待序列槽指令回報
break;
case 10:
if(send_ready_flag==GSM_POST_DATA )
{
lv_POST_DATA_TO_Sever(); //資料拼接
}
else if( send_ready_flag==GSM_GET_CONFIG)
{
lv_POST_GET_Helmet_Config();//資料拼接
}
else if( send_ready_flag==GSM_GET_ThresholdInfo)
{
lv_POST_GET_Helmet_ThresholdInfo();//資料拼接
}
else if(send_ready_flag==GSM_POST_SW_VER)
{
lv_POST_Helmet_SW_VER();//資料拼接
}
livall_Send_case_flag = 11;
SEGGER_RTT_printf(0,"==> 6 copy data to buffer <==\r\n");
Timeout_count_flag = 0;
break ;
case 11:
sprintf(temp_buffer,"AT+QHTTPCFG=\"requestheader\",%d",1);//http/https配置 1
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;
livall_Send_case_flag = 12;
SEGGER_RTT_printf(0,"==> 7 AT+QHTTPCFG=requestheader<==\r\n");
break ;
case 12:
//等待回報
break ;
case 13:
sprintf(temp_buffer,"AT+QHTTPCFG =\"responseheader\",%d",1);//http/https配置 2
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;
livall_Send_case_flag = 14;
SEGGER_RTT_printf(0,"==> 8 AT+QHTTPCFG = responseheader<==\r\n");
break ;
case 14:
//µÈ´ý½á¹û·µ»Ø
break ;
case 15:
POST_data_len = (strlen(buffer_URL)+2);//設定URL
sprintf(temp_buffer,"AT+QHTTPURL=%d",POST_data_len); //URL
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;
livall_Send_case_flag = 16;
SEGGER_RTT_printf(0,"==> 9 AT+QHTTPURL <==\r\n");
break ;
case 16:
//µÈ´ý½á¹û·µ»Ø
break ;
case 17:
sprintf(temp_buffer,"%s",buffer_URL);//發送URL
GSM6315_Send(temp_buffer,strlen(temp_buffer));
SEGGER_RTT_printf(0,"===>url = %s<===\r\n",temp_buffer);
Timeout_count_flag = 50;
livall_Send_case_flag = 18;
SEGGER_RTT_printf(0,"==> 10 buffer_URL<==\r\n");
break ;
case 18:
//µÈ´ý½á¹û·µ»Ø
break;
case 19:
sprintf(temp_buffer,"AT+QSSLCFG=\"httpsctxi\",%d",0); //https配置 1
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;
livall_Send_case_flag = 20;
SEGGER_RTT_printf(0,"==> 11 AT+QSSLCFG = httpsctxi <==\r\n");
break ;
case 20:
break ;
case 21:
sprintf(temp_buffer,"AT+QSSLCFG=\"https\",%d",1); //https 配置2
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;
livall_Send_case_flag = 22;
SEGGER_RTT_printf(0,"==> 12 AT+QSSLCFG = https <==\r\n");
break ;
case 22:
break ;
case 23:
sprintf(temp_buffer,"AT+QSSLCFG=\"seclevel\",%d,%d",0,0); //https 配置 3
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;//20*10 = 200ms
livall_Send_case_flag = 24;
SEGGER_RTT_printf(0,"==> 13 AT+QSSLCFG=seclevel<==\r\n");
break ;
case 24:
break ;
case 25:
POST_data_len = strlen(buffer_data); //Êý¾Ý´óС
sprintf(temp_buffer,"AT+QHTTPPOST=%d",POST_data_len); //post 資料的長度
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;//20*20 = 400ms
livall_Send_case_flag = 26;
SEGGER_RTT_printf(0,"==> 14 AT+QHTTPPOST <==\r\n");
break ;
case 26:
//µÈ´ý½á¹û·µ»Ø
break;
case 27:
SEGGER_RTT_printf(0,"%s",buffer_data);
GSM6315_Send(buffer_data,strlen(buffer_data));//開始post資料
Timeout_count_flag = 50;//20*100= 2000ms
livall_Send_case_flag = 28;
SEGGER_RTT_printf(0,"\r\n==> 15 buffer_data <==\r\n");
break ;
case 28:
//µÈ´ý½á¹û·µ»Ø
break ;
case 29:
sprintf(temp_buffer,"AT+QHTTPREAD=%d",30)//從伺服器擷取資料
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 30;//20*10 = 200ms
livall_Send_case_flag = 30;
SEGGER_RTT_printf(0,"==> 16 AT+QHTTPREAD <==\r\n");
break ;
case 30:
//µÈ´ý½á¹û·µ»Ø
break ;
case 31:
sprintf(temp_buffer,"AT+QPOWD=%d",1); //關機。
GSM6315_Send(temp_buffer,strlen(temp_buffer));
Timeout_count_flag = 50;
livall_Send_case_flag = 32;
SEGGER_RTT_printf(0,"==> 17 AT+QPOWD <==\r\n");
break ;
case 32:
break ;
4、代碼講解
這裡給大家細細講解。
①、case 10 的資料拼接?
case 10的拼接是本次的重點的重點,大家要自己看一下。下面貼出case 10 裡面的資料 拼接的部分代碼(這個涉及到項目的安全問題,暫時隻能貼出該部分)。
static void sprintf_post_data(uint8_t *buffer,uint8_t *strbuffer,uint16_t post_data_len)
{
uint8_t data_sprintf_buffer[750];
uint8_t buffer_len ;
①、http、https協定部分,必須要有不能缺少
sprintf(buffer,"POST /helmet/reportHelmetData HTTP/1.1\r\nHost: deliveryopenapi.meituan.com\r\nAccept: */*\r\nUser-Agent: QUECTEL_MODULE\r\nConnection: Keep-Alive\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length:",post_data_len);//²»Êä³ö·´À¡ÐÅÏ¢
②、此處是①部分後面協定的部分與自己私有資料的長度
sprintf(data_sprintf_buffer," %d\r\n\r\n",post_data_len);
buffer_len = strlen(data_sprintf_buffer);
③、拼接自己的私有資料
memcpy(data_sprintf_buffer+buffer_len,strbuffer,post_data_len);
memcpy((buffer+204),data_sprintf_buffer,strlen(data_sprintf_buffer));
}
下面是case 10 的完成輸出樣式,自己的資料必須是字元串格式,16進制也是可以的,但是伺服器會接收錯誤。(這裡吐槽幾句:伺服器還真是牛逼,全部都是字元串,一點不用考慮晶片資源問題。),
上面的資料拼接好了以後,就是在case 25 把整個資料(包括http,https協定資料和自己的資料)長度計算出來,通過AT指令告知2G子產品,然後在case 27把整個資料丢給子產品,子產品就會把資料丢給你的URL所指定的伺服器
②、case 11 和case 13 是http,https協定配置裡面的必要部分,不可缺少的指令、
③、case 15 是告知2G子產品,自己的URL長度 case 17 是告知2g 子產品自己的URL路勁(比如:www.baidu.com ,在case 15就是長度15(網址13位元組資料需要加上\r\n的2位元組進行換行,子產品才能接收),case 17 就是把這個路勁發送給子產品。)
④、case 19 ,case 21 ,case 23 是https協定的配置,如果使用http,這裡就不需要配置了 ,直接進入case 25 。如果使用https,這裡必須要配置并且不需要在發送URL成功以後,才能進行配置。
⑤、case 25 和 case 27 就是把case 10 拼接的資料發送給伺服器。
好了 ,到這裡酸水講解完了 。有興趣的童鞋可以自己琢磨一下。