#define BC26 //定义引入得通讯模块 BC26 | ESP8266 #include "coap.h" #include #include "mbedtls_util.h" #include "COAPHandle.h" #include "module_wrapper.h" #include "TypeDefine.h" #include "SystemAlarm.h" #include "sys.h" #include "crc.h" #include "DrawLCDGUI.h" #include "ProgramData.h" #include "cJSON.h" #ifdef BC26 #include "bc26.h" #elif defined(ESP8266) #include "esp8266.h" #endif void endpoint_setup(void) { } coap_endpoint_t endpoints[1]= {0}; #define BUF_SIZE 1024 static uint8_t buf[BUF_SIZE]; extern uint8 tcp_connect_status; extern valid_data_t valid_data; static char iv[17] = "543yhjy97ae7fyfg"; static const char *coap_con_path="auth"; static const uint8_t coap_content_json = COAP_CONTENTTYPE_APPLICATION_JSON; static char* sign_format = "clientId%s.%sdeviceName%sproductKey%sseq%d"; static char* payload_format="{\"clientId\":\"%s.%s\",\"signmethod\":\"%s\",\"sign\":\"%s\",\"productKey\":\"%s\",\"deviceName\":\"%s\",\"seq\":%d}"; static auth_token_t auth_token = { .flag = AUTH_FAILURE, }; coap_packet_t coap_send_pkt = //coap发送包 { .hdr.ver=0x01, .hdr.t=COAP_TYPE_CON, .hdr.tkl=0, .hdr.code=COAP_METHOD_POST, .numopts=0, }; coap_packet_t coap_rec_pkt = {0}; //coap接受包 #define PAYLOAD_DATA_LEN 44 //数据包 static uint8_t pumpData[PAYLOAD_DATA_LEN]; //包数据 extern uint8_t StartToRun_flag; //当按下运行按键的时候,置位该标志 extern char mqtt_publish_topic[100]; //发布主题 extern uint8_t Alarm_flag; //报警状态 extern uint8_t Start_send ; //开始发送标志,0:发送 extern uint16_t send_cont; //数据发送次数 static uint16_t send_num = 0; static uint8_t repeat_send_count = 0;//重发次数 static uint16_t pre_send_num = 0; uint8_t repeat_send_switch = 0; //0关闭重发,1开启重发 static int firstSendFlag = 1; static int moduleInitCou = 0; //模块连续初始化次数 static uint8_t pumpState = 0; //运行状态标志 static uint16_t pumpAlarm = 0; //报警标志 static uint8_t pumpPreAlarm = 0; //预报标志 static uint8_t pumpStateLast = 0; //上次运行状态标志 static uint16_t pumpAlarmLast = 0; //上次报警标志 static uint8_t pumpPreAlarmLast = 0; //上次预报标志 static void setValue(uint8_t **p,void* data,int len) { memcpy(*p,data,len); *p+=len; } static void generateCoapKey(void) { int i = 0; char out[80]={0}; char sign_content[100]={0}; if(auth_token.flag == AUTH_SUCCESS) { snprintf(sign_content, sizeof(sign_content), "%s,%s",registInfo->deviceSecret,auth_token.random); utils_sha256(sign_content, strlen(sign_content), out); memset(auth_token.key,0,sizeof(auth_token.key)); memcpy(auth_token.key,out+8,16); //获取key } } /** * @Title 封装数据并通过mqtt发送 */ static void packPumbDataCoapSend(void) { int i = 0; //if(mqtt_status.ping_status != MQTT_SUCCESS) return; //外调该接口时,做网络判断 if(send_num < 0 ) { send_num = 0; } send_num++; send_cont = send_num; uint8_t *ptr =pumpData; unsigned short crc = 0; if(tcp_connect_status != TCP_OPEN) { return; } memset(pumpData,0,sizeof(pumpData)); *ptr++ = 0xEF; //[0] 固定值 *ptr++ = PAYLOAD_DATA_LEN-2; //[1]数据长度 *ptr++ = 0x15; //[2]泵类型,网络泵 setValue(&ptr,classification,4);//[3-6]分类标识 setValue(&ptr,&send_num,sizeof(send_num));//[7-8]数据编号 *ptr++=8; //[9]住院号长度 setValue(&ptr,&verifyInfo.hospitalNO,8); //[10-17]住院号 setValue(&ptr,&verifyInfo.sickroom,2); //[18-19]病区 setValue(&ptr,&verifyInfo.bedNO,2); //[20-21]床号 setValue(&ptr,&setParamInfo.totalDose,2); //[22-23]总量 setValue(&ptr,&setParamInfo.limitDose1,2); //[24-25]极限零 setValue(&ptr,&setParamInfo.superaddition1,2); //[26-27] 追加量 setValue(&ptr,&setParamInfo.lockTime1,2); //[28-29] 锁时时间 setValue(&ptr,&setParamInfo.continueDose1,2); //[30,31]持续量 setValue(&ptr,&realTimeData.inputDose,2); //[32-33]已输入量 *ptr++ = (uint8_t)(setParamInfo.firstDose & 0x00ff); //[34]首次量 *ptr++ = (uint8_t)( realTimeData.validCount & 0x00ff ); //[35]有效次数 *ptr++ = (uint8_t)( realTimeData.invalidCount & 0x00ff );//[36]无效次数 if( realTimeData.batteryVolt > 100 )//[37]电池电量,发送电量百分比 { *ptr++ = 100; } else { *ptr++ = realTimeData.batteryVolt; } switch( realTimeData.stateRun ) //[38]泵运行状态 { case FirstRun: case MainRun: case Airout: case PCARun: pumpData[38] = 0x02;//运行状态 0000 0010 break; case Pause: pumpData[38] = 0x04;//暂停状态 0000 0100 break; case Poweroff: pumpData[38] = 0x00;//关机状态 0000 0000 break; case Poweron: pumpData[38] = 0x01;//开机状态 0000 0001 break; default: pumpData[38] = 0x08;//待机状态 0000 1000, break; } ptr++; if( sysAlarmFlag.BubbleFault == ALARM_ON ) { pumpData[39] |= 0x01;//气泡或无液故障 0000 0001 } if( sysAlarmFlag.JamFault == ALARM_ON ) { pumpData[39] |= 0x02;//堵塞故障 0000 0010 } if( sysAlarmFlag.InputTotal == ALARM_ON ) { pumpData[39] |= 0x04;//输入总量报警 0000 0100 } if( sysAlarmFlag.MaxFault == ALARM_ON ) { pumpData[39] |= 0x08;//极限量报警 0000 1000 } if( sysAlarmFlag.VoltLowest == ALARM_ON )//电量耗尽 { pumpData[39] |= 0x10;// 0001 0000 } if( sysAlarmFlag.InputEnd == ALARM_ON )//输液结束 { pumpData[39] |= 0x20;// 0010 0000 } if( sysAlarmFlag.MotorFalt == ALARM_ON )//电机失控 { pumpData[39] |= 0x40;// 0100 0000 } if( (sysAlarmFlag.MechanicalFault == ALARM_ON ) || ( sysAlarmFlag.MechanicalFault == ALARM_CONTINUE ) )//机械故障 { pumpData[39] |= 0x80;// 1000 0010; } ptr++; if( sysAlarmFlag.NonePillCase == ALARM_ON ) { pumpData[40] |= 0x01;//未装药盒报警 0000 0001 } ptr++; if( sysAlarmFlag.InputEnding == ALARM_ON ) { pumpData[41] |= 0x01;//输液将要结束 0000 0001 } if( sysAlarmFlag.Zhentongxiaoguo == ALARM_ON ) { pumpData[41] |= 0x02;//阵痛不足预报 0000 0010 } if( sysAlarmFlag.VoltLowest == ALARM_PREPARE ) { pumpData[41] |= 0x04;//电量偏低预报 0000 0100 } ptr++; crc = CRC16_CCITT((unsigned char*)pumpData, sizeof(pumpData)-2); setValue(&ptr,&crc,2); //[42-43]CRC UsartPrintf(USART_DEBUG,"发布数据包:%d\r\n",sizeof(pumpData)); for(i = 0;i 0) { first_dose_active = 1; } //追加量结束发送数据 if(realTimeData.superaddition == 0) { if(addition_active == 1) { addition_active = 0; TaskSchedulerFlag.MqttSendFlag = TASK_FLAG_SET; //UsartPrintf(USART_DEBUG, "====superaddition====\r\n"); } } else if(realTimeData.superaddition > 0) { addition_active = 1; } } void CoapConnect(void) { static uint32 seq = 1; int buf_len = 0; char sign_content[100]={0}; char out[50]={0}; char payload_content[512]; int i=0; uint16_t coap_port = my_atoi(registInfo->port);//端口 auth_token.flag = AUTH_HANDLING; coap_send_pkt.hdr.id[0]=AUTH_MID; coap_send_pkt.hdr.id[1]=0; coap_send_pkt.numopts=5; coap_send_pkt.opts[0].num=COAP_OPTION_URI_HOST; coap_send_pkt.opts[0].buf.len=strlen(registInfo->address); coap_send_pkt.opts[0].buf.p=(uint8_t*)registInfo->address; coap_send_pkt.opts[1].num=COAP_OPTION_URI_PORT; coap_send_pkt.opts[1].buf.len=sizeof(coap_port); coap_send_pkt.opts[1].buf.p=(uint8_t*)&coap_port; coap_send_pkt.opts[2].num=COAP_OPTION_URI_PATH; coap_send_pkt.opts[2].buf.len=strlen(coap_con_path); coap_send_pkt.opts[2].buf.p=(uint8_t*)coap_con_path; coap_send_pkt.opts[3].num=COAP_OPTION_CONTENT_FORMAT, coap_send_pkt.opts[3].buf.len=sizeof(coap_content_json), coap_send_pkt.opts[3].buf.p=&coap_content_json, coap_send_pkt.opts[4].num=COAP_OPTION_ACCEPT, coap_send_pkt.opts[4].buf.len=sizeof(coap_content_json), coap_send_pkt.opts[4].buf.p=&coap_content_json, seq++; snprintf(sign_content, sizeof(sign_content), sign_format,registInfo->productKey,registInfo->deviceName,registInfo->deviceName,registInfo->productKey,seq); utils_hmac_sha1_str(sign_content, strlen(sign_content), out, registInfo->deviceSecret, strlen(registInfo->deviceSecret)); UsartPrintf(USART_DEBUG,"sign_content:%s,sign:%s\r\n",sign_content,out); snprintf(payload_content, sizeof(payload_content), payload_format,registInfo->productKey,registInfo->deviceName,"hmacsha1",out,registInfo->productKey,registInfo->deviceName,seq); coap_send_pkt.payload.len=strlen(payload_content); coap_send_pkt.payload.p=(uint8_t*)payload_content; UsartPrintf(USART_DEBUG,"auth_payload:%s\r\n",payload_content); memset(buf,0,BUF_SIZE); buf_len = BUF_SIZE; coap_build(buf,&buf_len,&coap_send_pkt); // UsartPrintf(USART_DEBUG,"\r\nauth byte,%d:\r\n",buf_len); // for(i=0;iproductKey, registInfo->deviceName,"thing","model","up_raw"}; int topic_len = sizeof(topic)/sizeof(topic[0]); int optnum = 0; int i=0; uint16_t coap_port = my_atoi(registInfo->port); coap_send_pkt.hdr.id[0]=(uint8_t)(send_num&0x00ff); coap_send_pkt.hdr.id[1]=(uint8_t)(send_num>>8); coap_send_pkt.numopts=6+topic_len; coap_send_pkt.opts[optnum].num=COAP_OPTION_URI_HOST; coap_send_pkt.opts[optnum].buf.len=strlen(registInfo->address); coap_send_pkt.opts[optnum++].buf.p=(uint8_t*)registInfo->address; coap_send_pkt.opts[optnum].num=COAP_OPTION_URI_PORT; coap_send_pkt.opts[optnum].buf.len=sizeof(coap_port); coap_send_pkt.opts[optnum++].buf.p=(uint8_t*)&coap_port; for(i=0;i 0) // 连接基站成功 { moduleInitCou = 0; if(repeat_send_switch)//有数据发送, 重设重发时间 { at_module_udpreopen(registInfo->address,registInfo->port); TaskSchedulerTimer.MQTTReSendTimer = FIVE_SECOND_TIMER; TaskSchedulerFlag.MqttReSendFlag = TASK_FLAG_CLEAR; } } TaskSchedulerFlag.NET_ONLINE_FLAG = TASK_FLAG_SET;//模块联网 if(auth_token.flag == AUTH_FAILURE) { if(tcp_connect_status == TCP_OPEN) { UsartPrintf(USART_DEBUG, "===CoapConnect=====\r\n"); CoapConnect(); //coap认证 } else { if(tcp_connect_status == TCP_CLOSED) { UsartPrintf(USART_DEBUG, "===udp open=====\r\n"); at_module_udpreopen(registInfo->address,registInfo->port); } } } if(repeat_send_switch) { if(TaskSchedulerFlag.MqttReSendFlag == TASK_FLAG_SET) { TaskSchedulerFlag.MqttReSendFlag = TASK_FLAG_CLEAR; repeat_send_count++; if(repeat_send_count == 2) { at_module_udpreopen(registInfo->address,registInfo->port); return; } if(repeat_send_count == 4) { repeat_send_switch = 0; //关闭重发 repeat_send_count = 0; module_start_status = MODULE_FAIL; //模块再次启动 module_init_status = MODULE_FAIL; tcp_connect_status = TCP_CLOSED; return; } UsartPrintf(USART_DEBUG, "\r\n===repeat send:%d=====\r\n",repeat_send_count); send_num--; packPumbDataCoapSend();//重新发送 } } } else { TaskSchedulerFlag.NET_ONLINE_FLAG = TASK_FLAG_CLEAR;//模块未联网 if(TaskSchedulerFlag.ModuleInitFlag == TASK_FLAG_SET) { TaskSchedulerFlag.ModuleInitFlag = TASK_FLAG_CLEAR; TaskSchedulerTimer.ModuleInitTimer = FIFTEEN_SECOND_TIMER; moduleInitCou++; UsartPrintf(USART_DEBUG, "===start module=====%d\r\n",moduleInitCou); if(moduleInitCou >= 2 && module_start_status == MODULE_FAIL) { moduleInitCou = 0; TaskSchedulerTimer.ModuleInitTimer = ONE_HOUR_TIMER;//连续5次启动失败,启动间隔变为半小时 at_module_low_power();//低功耗 repeat_send_switch = 0; //关闭重发 repeat_send_count = 0; return; } if(module_start_status == MODULE_FAIL) { UsartPrintf(USART_DEBUG, "===restart module=====\r\n"); at_module_start(); } else if(module_init_status == MODULE_FAIL) { UsartPrintf(USART_DEBUG, "===init module=====\r\n"); at_module_init(); } } } } /** * 处理认证信息 */ static void AuthHandle(void) { cJSON *json = NULL,*json_seqOffset=NULL,*json_random=NULL,*json_token = NULL; json = cJSON_Parse((char*)coap_rec_pkt.payload.p); if(!json) { UsartPrintf(USART_DEBUG, "json parse error,%s\r\n",cJSON_GetErrorPtr()); goto end; } json_seqOffset = cJSON_GetObjectItem(json,"seqOffset"); json_random = cJSON_GetObjectItem(json,"random"); json_token = cJSON_GetObjectItem(json,"token"); if(json_random && json_token) { memset(&auth_token,0,sizeof(auth_token)); if(json_seqOffset) { UsartPrintf(USART_DEBUG, "==认证成功=====%d,%s,%s\r\n",json_seqOffset->valueint,json_random->valuestring,json_token->valuestring); auth_token.seqOffset = json_seqOffset->valueint; } else { UsartPrintf(USART_DEBUG, "==认证成功=====%s,%s\r\n",json_random->valuestring,json_token->valuestring); auth_token.seqOffset = 100; } auth_token.flag = AUTH_SUCCESS; memcpy(auth_token.random,json_random->valuestring,strlen(json_random->valuestring)); memcpy(auth_token.token,json_token->valuestring,strlen(json_token->valuestring)); generateCoapKey(); } else { UsartPrintf(USART_DEBUG, "==认证失败=====\r\n"); // auth_token.flag = AUTH_FAILURE; } end: cJSON_Delete(json); } /** * 处理Coap返回消息 */ static void HandleCoapValidData() { int i = 0; uint16_t back_send_num = 0; int ret = coap_parse(&coap_rec_pkt, (uint8_t*)valid_data.buf, valid_data.len); UsartPrintf(USART_DEBUG, "coap back,%d:\r\n",valid_data.len); for(i=0;i0) { HandleCoapValidData(); } } //发送泵数据 static void SendCoapPumpData() { IntePumpStateCoap(); DecideSendFlagCoap(); if(TaskSchedulerFlag.MqttSendFlag == TASK_FLAG_SET && motorWorkState != MOTOR_WORK_ON) { TaskSchedulerFlag.MqttSendFlag = TASK_FLAG_CLEAR; TaskSchedulerTimer.MQTTSendTimer = TWENTY_MINUTE_TIMER; if(EngineeringModeValue.test == 0) { TaskSchedulerTimer.MQTTSendTimer = TWENTY_SECOND_TIMER; } repeat_send_switch = 1;//准备重发 repeat_send_count = 0; packPumbDataCoapSend(); TaskSchedulerTimer.MQTTReSendTimer = FIVE_SECOND_TIMER; TaskSchedulerFlag.MqttReSendFlag = TASK_FLAG_CLEAR; } } void CoapHandle(void) { ModuleKeepOnLine(); //保持网络连接 CoapHandleEvent(); //处理接收数据 if(Start_send == 0) { SendCoapPumpData(); //发送数据 } if(realTimeData.stateRun == Poweroff) { delay_ms(500); TaskSchedulerFlag.sysPowerOffFlag = TASK_FLAG_SET;//关机 } } void ModelRegister(void) { GPIO_InitTypeDef GPIO_InitStruct; /* enable clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; // GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // //GPIO_InitStruct.Pull = GPIO_NOPULL; // GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_Init(GPIOC, &GPIO_InitStruct); // BC26_WAKE_LOW(); #ifdef BC26 bc26_sal_register(); #elif defined(ESP8266) esp8266_sal_register(); #endif } /** * 模块信号强度,为负值 */ int16_t GetModeldBm(void) { uint8_t data[50]={0}; uint16 dBm = 0; #ifdef BC26 const char *SIGN = "+CSQ: "; char *signStr = NULL; at_module_cmd_back("AT+CSQ\r\n",(char*)data,sizeof(data)); signStr = strstr((const char*)data,SIGN); if(signStr) { signStr+=strlen(SIGN); dBm = my_atoi(signStr); } if(dBm >= 2 && dBm <= 30) { dBm = 109-((dBm-2)*3); //简略换算 } else { switch(dBm) { case 0: dBm = 113; break; case 1: dBm = 111; break; case 31: dBm = 51; break; default: dBm = 0; } } #elif defined(ESP8266) #endif return dBm; }