mcuCmds.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. #include "atCmdList.h"
  2. #include "mcuCmds.h"
  3. #include "devMsg.h"
  4. #include "para.h"
  5. #include "nmea.h"
  6. #include "app.h"
  7. #include "records.h"
  8. #define MCU_PRO_CRC16_INIT 0x1234
  9. const T_INT8 *cmdListTable[]=
  10. {
  11. "DevInfo",
  12. "KeyPress",
  13. "KeyFree",
  14. "Motion",
  15. "NearDev",
  16. "ShutDown",
  17. "LowPower",
  18. "\r\n",
  19. ""
  20. };
  21. typedef enum{
  22. CMD_MUC_DEVINFO,
  23. CMD_MCU_KEYPRESS,
  24. CMD_MCU_KEYFREE,
  25. CMD_MCU_MOTION,
  26. CMD_MCU_NEARDEV,
  27. CMD_MCU_SHUTDOWN,
  28. CMD_MCU_LOWPOWER,
  29. CMD_MCU_NONE=-1
  30. }CMD_MCU_TYPEDEF;
  31. #define BAT_TABLE_NUM 9
  32. const unsigned char batTable[BAT_TABLE_NUM][2]={
  33. {33,3}, //<=3.3 3%
  34. {34,10}, //<=3.4 10%
  35. {35,26}, //<=3.5 26%
  36. {36,52}, //<=3.6 52%
  37. {37,65}, //<=3.7 65%
  38. {38,75}, //<=3.8 75%
  39. {39,86}, //<=3.9 86%
  40. {40,93}, //<=4.0 93%
  41. {41,100} //>4.0 100%
  42. };
  43. void batSwitchNow(void){
  44. const char lowperTable[]="RT+LSHTTS=1,\"C9E8B1B8B5E7C1BFB5CDA3ACC7EBBCB0CAB1B3E4B5E7\"";
  45. int i;
  46. //低电检测
  47. static int64_t lbatTime=0;
  48. static T_BOOL lbatReport=FALSE;
  49. static T_BOOL firstLbat=FALSE;
  50. int64_t curTime,dttime;
  51. if(app.bat>34){//未到低电压
  52. lbatReport=FALSE;
  53. firstLbat=FALSE;
  54. app.warnStatus=WARN_NORMAL;
  55. wlog_warn("bat normal");
  56. }else{//低电压了
  57. if(FALSE==firstLbat){
  58. wlog_warn("bat first low");
  59. lbatTime=LSAPI_OSI_UpTime();
  60. firstLbat=TRUE;
  61. }else{
  62. curTime=LSAPI_OSI_UpTime();
  63. dttime=curTime-lbatTime;
  64. wlog_warn("bat status:%lld,%lld,%lld",lbatTime,dttime,curTime);
  65. //检测是否持续了1分钟
  66. if(dttime>=60000 && lbatReport==FALSE){
  67. //提示"设备电量低,请及时充电",同时上报低压事件0x0e
  68. wlog_warn("low power, report now");
  69. lbatReport=TRUE;
  70. if(app.vcharge<=30) cmdTTSHandler(lowperTable, strlen(lowperTable));
  71. else wlog_warn("skip voice warn when charging");
  72. app.warnStatus=WARN_LOW_PWR;
  73. warnSendNow(WARN_LOW_PWR);
  74. }
  75. }
  76. }
  77. //电压百分比判定
  78. for(i=0;i<BAT_TABLE_NUM;i++){
  79. if(app.bat<=batTable[i][0]){
  80. app.vBatPersent=batTable[i][1];
  81. goto BAT_END;
  82. }
  83. }
  84. app.vBatPersent=100;
  85. BAT_END:
  86. wlog_info("Bat=%d,persent=%d",app.bat,app.vBatPersent);
  87. }
  88. void KeyHandler(unsigned char keyvalue,unsigned char keyType);
  89. void McuStringHandler(unsigned char *msg, int cmd_len){
  90. T_BOOL needUpdateMcu=FALSE;
  91. T_INT16 cmd,i,j;
  92. T_UINT32 psn;
  93. int tmp,index;
  94. T_UINT16 crc16A,crc16B;
  95. unsigned char *ptr=msg+cmd_len-4;
  96. unsigned char KeyPress,KeyFree,temp[2];
  97. char SubStr[20];
  98. char *ver;
  99. T_BOOL needFeedBackDevInfo=FALSE;
  100. //wlog_info("Get[%d]:%s",cmd_len,msg);//msg,cmd_len没回车换行也没>>
  101. //计算CRC16
  102. if(0!=restoreDataFormatByHex(ptr,4)){//获取最后的crc16串
  103. wlog_warn("get mcu crc16 failed:%s",ptr);
  104. return;
  105. }
  106. crc16A=((unsigned short)ptr[0]<<8)|ptr[1];
  107. crc16B=crc16Check(MCU_PRO_CRC16_INIT,msg,cmd_len-4-1);//不算crc16前面那个逗号
  108. if(crc16A != crc16B){
  109. wlog_warn("mcu crc16 unfit:%04x,%04x",crc16A,crc16B);
  110. return;
  111. }
  112. cmd_len -= 5;//长度去掉4个字节CRC和一个逗号
  113. cmd=matchCmdList(cmdListTable,msg);
  114. switch(cmd){
  115. case CMD_MUC_DEVINFO://DevInfo,RTL271MCU_V101,200510001,38,30,e209 -->设备信息:MCU版本,PSN,VBat
  116. needFeedBackDevInfo=TRUE;
  117. //获取psn
  118. index=findByteFromStr(msg, cmd_len,',',2);
  119. if(index>=0){
  120. tmp=atoi(msg+index);
  121. if(tmp != sut_psn.psn){
  122. wlog_warn("psn error,setmcu:%d,%d",sut_psn.psn, tmp);
  123. break;
  124. }
  125. }
  126. //PSN匹配后
  127. //获取MCU版本号串
  128. index=findByteFromStr(msg, cmd_len,',',1);
  129. if(index>=0){
  130. ver=getMcuAppVer();
  131. if(0!=memcmp(msg+index, ver, strlen(ver))){
  132. //有新版本
  133. needUpdateMcu=TRUE;
  134. }
  135. }
  136. //获取BAT
  137. index=findByteFromStr(msg, cmd_len,',',3);
  138. if(index>=0){
  139. tmp=atoi(msg+index);
  140. app.bat=tmp;
  141. batSwitchNow();
  142. }
  143. //获取充电电压
  144. index=findByteFromStr(msg, cmd_len,',',4);
  145. if(index>=0){
  146. tmp=atoi(msg+index);
  147. app.vcharge=tmp;
  148. }
  149. wlog_info("DevInfo:%d,%d,%d",needUpdateMcu,app.bat,app.vcharge);
  150. if(needUpdateMcu==TRUE){
  151. apUpgradeMcu();
  152. McuIapStart();
  153. }
  154. break;
  155. case CMD_MCU_KEYPRESS://>>KeyPress,01,386A -->按键按下值:01/02/04或组合
  156. //获取键值
  157. index=findByteFromStr(msg, cmd_len,',',1);
  158. if(index>=0){
  159. if(0!=isBytesAreHex(msg+index, 2)){
  160. wlog_warn("KeyPress invalid1");
  161. break;
  162. }
  163. memcpy(temp, msg+index,2);
  164. if(0!=restoreDataFormatByHex(temp,2)){
  165. wlog_warn("KeyPress invalid2");
  166. break;
  167. }
  168. KeyPress=temp[0];
  169. KeyHandler(KeyPress,0);
  170. }
  171. break;
  172. case CMD_MCU_KEYFREE://>>KeyFree,01,386A -->按键放开值:01/02/04或组合
  173. //获取键值
  174. index=findByteFromStr(msg, cmd_len,',',1);
  175. if(index>=0){
  176. if(0!=isBytesAreHex(msg+index, 2)){
  177. wlog_warn("KeyFress invalid1");
  178. break;
  179. }
  180. memcpy(temp, msg+index,2);
  181. if(0!=restoreDataFormatByHex(temp,2)){
  182. wlog_warn("KeyFress invalid2");
  183. break;
  184. }
  185. KeyFree=temp[0];
  186. KeyHandler(KeyFree,1);
  187. }
  188. break;
  189. case CMD_MCU_MOTION://>>Motion,1234,89,511,1028,7902 -->运动传感器值:StepCount,Ax,Ay,Az
  190. //获取步数
  191. index=findByteFromStr(msg, cmd_len,',',1);
  192. if(index>=0){
  193. tmp=atoi(msg+index);
  194. gDevInfo->steps=tmp;
  195. }
  196. //获取Ax
  197. index=findByteFromStr(msg, cmd_len,',',2);
  198. if(index>=0){
  199. tmp=atoi(msg+index);
  200. gDevInfo->aspeed_x=(short)tmp;
  201. }
  202. //获取Ay
  203. index=findByteFromStr(msg, cmd_len,',',3);
  204. if(index>=0){
  205. tmp=atoi(msg+index);
  206. gDevInfo->aspeed_y=(short)tmp;
  207. }
  208. //获取Az
  209. index=findByteFromStr(msg, cmd_len,',',4);
  210. if(index>=0){
  211. tmp=atoi(msg+index);
  212. gDevInfo->aspeed_z=(short)tmp;
  213. }
  214. motionGetOk();
  215. wlog_info("GetMotion:%d,%d,%d,%d",gDevInfo->steps,gDevInfo->aspeed_x,gDevInfo->aspeed_y,gDevInfo->aspeed_z);
  216. break;
  217. case CMD_MCU_NEARDEV://>>NearDev,4,200510002,12,200510005,3C,200530004,0A,200510325,9E,13B3-->临近设备:PSN1,RSSI1,PSN2,RSSI2....
  218. #if 0
  219. //模拟NEAR数据上传
  220. gNearInfo->num=2;
  221. for(i=0;i<6;i++) gNearInfo->info[0].mac[i]=0x55;
  222. gNearInfo->info[0].rssi=0x55;
  223. for(i=0;i<6;i++) gNearInfo->info[1].mac[i]=0xAA;
  224. gNearInfo->info[1].rssi=0xAA;
  225. #else
  226. if(GetSubStrWithComma(msg,SubStr,sizeof(SubStr),1)){//获取个数
  227. wlog_warn("NearDev:Num error!\r\n");
  228. break;
  229. }
  230. int num=strtol(SubStr,NULL,16);
  231. wlog_warn("NearDev:Num=%d\r\n",num);
  232. if(GetCommaNum(msg)!=num*2+2){//统计逗号个数
  233. wlog_warn("NearDev:comma num error!\r\n");//逗号个数不对
  234. break;
  235. }
  236. if(num==0) break;
  237. memset((unsigned char *)gNearInfo, 0, sizeof(NEARINFO_DEF));
  238. for(i=0;i<num;i++){
  239. //get PSN
  240. GetSubStrWithComma(msg,SubStr,sizeof(SubStr),2+i*2);
  241. psn=strtol(SubStr,NULL,16);
  242. DecToBCD(psn, gNearInfo->info[i].mac,sizeof(gNearInfo->info[i].mac));
  243. //get RSSI
  244. GetSubStrWithComma(msg,SubStr,sizeof(SubStr),3+i*2);
  245. j=strtol(SubStr,NULL,16);
  246. gNearInfo->info[i].rssi=j;
  247. wlog_warn("PSN=%d RSSI=%02x\r\n",psn,j);
  248. }
  249. gNearInfo->num=num;
  250. #endif
  251. memcpy(gNearInfo->BCDTime,getBCDDateTime(),sizeof(gNearInfo->BCDTime));
  252. getNearOk();
  253. break;
  254. case CMD_MCU_SHUTDOWN://>>ShutDown,A657 -->控制关机
  255. #ifdef TAKE_NOTE_FOR_REBOOT
  256. saveRebootReason("CMD_MCU_SHUTDOWN\r\n");
  257. #endif
  258. outterInfo("ShutDown\r\n",10);
  259. vibraNow();
  260. if(getLoginStatus()==0){
  261. LSAPI_SYS_PowerOff();
  262. for(;;){LSAPI_OSI_ThreadSleep(100);}
  263. }else warnSendNow(WARN_PWROFF);
  264. break;
  265. case CMD_MCU_LOWPOWER://>>LowPower, -->低电关机
  266. #ifdef TAKE_NOTE_FOR_REBOOT
  267. saveRebootReason("CMD_MCU_LOWPOWER\r\n");
  268. #endif
  269. wlog_warn("LowPower ShutDown");
  270. if(getLoginStatus()==0){
  271. LSAPI_SYS_PowerOff(); //未登陆成功说明此时连接不行的
  272. for(;;){LSAPI_OSI_ThreadSleep(100);}
  273. }else warnSendNow(WARN_LOW_PWR_DOWN);
  274. break;
  275. default:break;
  276. }
  277. if(needFeedBackDevInfo==TRUE) setMcuPara(TRUE);
  278. }
  279. #define KEY_SOS 0x04
  280. #define KEY_REC 0x02
  281. //////////////////////////录音按键处理////////////////////////
  282. char recIsPress=0;
  283. static int64_t ltm=0;
  284. void clearLtm(void){ltm=LSAPI_OSI_UpTime();}
  285. void recHandler(keyType){
  286. int64_t dt;
  287. if(keyType==0){//按下
  288. recIsPress=1;
  289. wlog_info("rec is press");
  290. //检测dt
  291. dt=LSAPI_OSI_UpTime()-ltm;
  292. if(dt<600){//一定时间内按了两次,为双击
  293. stopRecTimer();
  294. wlog_info("Double key");
  295. TryvFileRePlay(LV_PLAYED);
  296. }else startRecTimer();//打开定时器检测单击
  297. clearLtm();
  298. }else{//放开
  299. recIsPress=0;
  300. wlog_info("rec is free");
  301. RecCloseNowApi();
  302. }
  303. }
  304. /*处理MCU发过来的按键值
  305. keyvalue:键值,低3位有效
  306. keyType:0 按下的键值 1 松开的键值
  307. */
  308. void KeyHandler(unsigned char keyvalue,unsigned char keyType){
  309. if(keyType==0) wlog_info("KeyPress:%02x",keyvalue);
  310. else wlog_info("KeyFress:%02x",keyvalue);
  311. switch(keyvalue){
  312. case KEY_SOS://SOS
  313. sosHandler(keyType);
  314. break;
  315. case KEY_REC://录音
  316. recHandler(keyType);
  317. break;
  318. default:
  319. wlog_info("keyvalue skip");
  320. break;
  321. }
  322. }
  323. typedef enum{
  324. LNET_NORMAL, //网络正常
  325. LNET_CONNTING, //正在找网
  326. LNET_HERROR //硬件故障
  327. }LNET_ENUM;
  328. typedef enum{
  329. LGPS_LOCATED, //已定位
  330. LGPS_LOCATING, //正在定位
  331. LGPS_HERROR //硬件故障
  332. }LGPS_ENUM;
  333. void triggerMcuAndSend(char *info){
  334. #if 1
  335. wlog_info("Send:%s",info);
  336. uartOutPut(info,strlen(info));//用于唤醒MCU
  337. LSAPI_OSI_ThreadSleep(1);
  338. uartOutPut(info,strlen(info));//发送消息给MCU
  339. #else
  340. const unsigned char buffer[1]={0};
  341. wlog_info("Send:%s",info);
  342. uartOutPut(buffer,sizeof(buffer));//用于唤醒MCU
  343. LSAPI_OSI_ThreadSleep(1);
  344. uartOutPut(info,strlen(info));//发送消息给MCU
  345. #endif
  346. }
  347. /*初始化MCU灯状态*/
  348. void setInitMcu(void){
  349. char info[100],tmp[10];
  350. unsigned short crc16;
  351. snprintf(info, sizeof(info), "<<SetMCU,%d,%d,%d",sut_psn.psn,LNET_HERROR,LGPS_HERROR);
  352. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  353. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  354. strcat(info, tmp);
  355. triggerMcuAndSend(info);
  356. }
  357. /*
  358. 设置MCU参数
  359. psn: 设备序列号
  360. led1:led1状态 网络状态 LNET_ENUM
  361. led2:led2状态 定位状态 LGPS_ENUM
  362. "<<SetMCU,psn,led1,led2,devinfotime,motiontime"
  363. */
  364. void setMcuPara(T_BOOL right_now){
  365. char info[100],tmp[10];
  366. unsigned short crc16;
  367. unsigned char led1=LNET_CONNTING;
  368. unsigned char led2=LGPS_LOCATING;
  369. static unsigned char lastLed1=LNET_HERROR;
  370. static unsigned char lastLed2=LGPS_HERROR;
  371. if(getServerAuth()==TRUE) led1=LNET_NORMAL;
  372. if(TRUE==isGpsLocated()) led2=LGPS_LOCATED;
  373. if(lastLed1==led1 && lastLed2==led2 && right_now==FALSE) return;
  374. lastLed1=led1;lastLed2=led2;
  375. snprintf(info, sizeof(info), "<<SetMCU,%d,%d,%d",sut_psn.psn,led1,led2);
  376. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  377. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  378. strcat(info, tmp);
  379. triggerMcuAndSend(info);
  380. }
  381. /*获取Near信息
  382. near为LTE主动定时向MCU请求获取
  383. "<<GetNear,CRC"
  384. */
  385. void getNearInfo(void){
  386. char info[100],tmp[10];
  387. unsigned short crc16;
  388. snprintf(info, sizeof(info),"<<GetNear");
  389. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  390. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  391. strcat(info, tmp);
  392. triggerMcuAndSend(info);
  393. }
  394. /*获取Motion信息
  395. motion为LTE主动定时向MCU请求获取
  396. "<<GetMotion,CRC"
  397. */
  398. void getMotionInfo(void){
  399. char info[100],tmp[10];
  400. unsigned short crc16;
  401. snprintf(info, sizeof(info),"<<GetMotion");
  402. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  403. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  404. strcat(info, tmp);
  405. triggerMcuAndSend(info);
  406. }
  407. /*AP控制MCU升级
  408. psn:目标设备序列号
  409. version:最新版本号
  410. "<<Upgrade,psn,version"
  411. */
  412. void apUpgradeMcu(void){
  413. char info[100],tmp[10];
  414. unsigned short crc16;
  415. snprintf(info, sizeof(info),"<<Upgrade");
  416. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  417. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  418. strcat(info, tmp);
  419. triggerMcuAndSend(info);
  420. }
  421. /*AP侧通知MCU复位整机*/
  422. void apRebootSys(void){
  423. char info[100],tmp[10];
  424. unsigned short crc16;
  425. snprintf(info, sizeof(info),"<<Reboot");
  426. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  427. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  428. strcat(info, tmp);
  429. triggerMcuAndSend(info);
  430. }
  431. /*AP侧通知MCU关机*/
  432. void apShutDownSys(void){
  433. char info[100],tmp[10];
  434. unsigned short crc16;
  435. snprintf(info, sizeof(info),"<<ShutDown");
  436. crc16=crc16Check(MCU_PRO_CRC16_INIT,info+2,strlen(info)-2);
  437. snprintf(tmp, sizeof(tmp),",%04x\r\n",crc16);
  438. strcat(info, tmp);
  439. triggerMcuAndSend(info);
  440. }
  441. /*服务器通知LTE重启/关机整机,每秒定时发信息给MCU*/
  442. void apCtlMcu(void){
  443. if(app.sysCtl==0) return;
  444. else if(app.sysCtl==1) apRebootSys();
  445. else if(app.sysCtl==2) apShutDownSys();
  446. }
  447. /*
  448. 在一个字符串里获取字串,指定从第几个逗号开始,到下一个逗号或非打印字符结束
  449. 参数:
  450. Str: 指定源串
  451. subStr: 获取到的字串存放在此
  452. subStrLen:限制字串长度
  453. StartComma:从第几个逗号开始。 如果是0 表示从源串第一个字节开始,如果是1表示从第一个逗号后一个字节开始,以此类推
  454. 返回: 0--已找到 -1--未找到 -2--字串存放区空间不够(实际获取的字串长度大于subStrLen)
  455. */
  456. int GetSubStrWithComma(const char *Str,char *subStr,int subStrLen,int StartComma)
  457. {
  458. const char *p;
  459. char *ss;
  460. p=Str;
  461. ss=subStr;
  462. if(subStrLen<1)return -1;
  463. subStrLen-=1;//预留一个'\0'
  464. if(StartComma>0){
  465. while(StartComma>0){
  466. if(*p==',')StartComma--;
  467. p++;
  468. if(*p<33 || *p>127)break;
  469. }
  470. if(StartComma!=0)return -1;
  471. }
  472. if(*p<33 || *p>127)return -1;
  473. //--拷贝
  474. while(subStrLen>0){
  475. *ss=*p;
  476. ss++;
  477. p++;
  478. if(*p<33 || *p>127 || *p==',')break;
  479. subStrLen--;
  480. }
  481. if(subStrLen==0)return -2;
  482. *ss=0;
  483. return 0;
  484. }
  485. /*
  486. 统计字符串中逗号个数,搜索到非可见字符结束
  487. */
  488. int GetCommaNum(const char *Str)
  489. {
  490. int i=0;
  491. char ch;
  492. const char *p;
  493. p=Str;
  494. ch=*p;
  495. while(ch>=33 && ch<=127){
  496. if(ch==',')i++;
  497. p++;
  498. ch=*p;
  499. }
  500. return i;
  501. }