app_nb.c 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833
  1. #include "board.h"
  2. #include "app_nb.h"
  3. #include "prj_com.h"
  4. #include "param.h"
  5. #include "rtc_run.h"
  6. #include "board.h"
  7. #include "tdc_tof.h"
  8. #include "bill.h"
  9. #include "alarm.h"
  10. #include "stat.h"
  11. #include "ymodem.h"
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <stdint.h>
  15. #include <string.h>
  16. Nb_Run_t NbRun;
  17. uint8_t NB_CHECK_TDC_COMPLETE_FLAG = 0;
  18. uint8_t NbIntStep = 0xFFu;
  19. rt_sem_t Nb_thread_run_sem = RT_NULL; // NB线程运行信号量
  20. // 补报相关信息
  21. NbAppFrame_t __attribute__((aligned(4))) NbAppFrame;
  22. uint8_t Nb_rx_data(void);
  23. void nb_run_init(void)
  24. {
  25. nb_power_off();
  26. lpuart0_set_rx_itf(NbRxCh); // nb串口中断
  27. // NbRun.rx_flag = FALSE;
  28. NbRun.rx_over_time = 0;
  29. NbRun.rx_idx = 0;
  30. memset(NbRun.rx_buf, 0, sizeof(NbRun.rx_buf));
  31. memset(NbRun.tx_buf, 0, sizeof(NbRun.tx_buf));
  32. NbRun.cur_at = at_end;
  33. NbRun.rsrp = 0;
  34. NbRun.rsrq = 0;
  35. NbRun.rssi = 0;
  36. NbRun.snr = 0;
  37. memset(NbRun.imei, 0, sizeof(NbRun.imei));
  38. memset(NbRun.imsi, 0, sizeof(NbRun.imsi));
  39. memset(NbRun.ccid, 0, sizeof(NbRun.ccid));
  40. NbRun.task.count = 0;
  41. // NbRun.open_time_out = 0;
  42. memset(&NbAppFrame, 0, sizeof(NbAppFrame));
  43. NbRun.status = 0;
  44. Nb_thread_run_sem = rt_sem_create("nb_thread_run", 0, RT_IPC_FLAG_FIFO); // 创建nb运行信号量
  45. NbRun.get_imei_flag = 0;
  46. NbRun.get_imsi_flag = 0;
  47. NbRun.get_ccid_flag = 0;
  48. }
  49. static void NbBuildDataHeader(uint16_t data_len)
  50. {
  51. Param_t *param;
  52. GetParam(&param);
  53. NbAppFrame.prefix[0] = 0xFE;
  54. NbAppFrame.prefix[1] = 0xFE;
  55. NbAppFrame.head = 0x68;
  56. NbAppFrame.type = 0x10;
  57. // memcpy(NbAppFrame.addr, param->dev_id, sizeof(param->dev_id));
  58. NbAppFrame.addr[0] = param->dev_id[5];
  59. NbAppFrame.addr[1] = param->dev_id[4];
  60. NbAppFrame.addr[2] = param->dev_id[3];
  61. NbAppFrame.addr[3] = param->dev_id[2];
  62. NbAppFrame.addr[4] = param->dev_id[1];
  63. NbAppFrame.addr[5] = param->dev_id[0];
  64. // NbAppFrame.addr[6] = param->dev_id[0];
  65. NbAppFrame.addr[6] = 0x00;
  66. NbAppFrame.ctrl = 0xA0;
  67. NbAppFrame.len[0] = (unsigned char)(data_len);
  68. NbAppFrame.len[1] = (unsigned char)(data_len >> 8);
  69. }
  70. static void NbBuildDataTail(uint16_t data_len)
  71. {
  72. uint8_t cs = 0;
  73. // cs
  74. cs = check_sum((uint8_t *)&NbAppFrame.head, 12);
  75. cs += check_sum(NbAppFrame.data, data_len);
  76. NbAppFrame.data[data_len] = cs; // 8位累加和
  77. NbAppFrame.data[data_len + 1] = 0x16; // 结束位 //450个字节
  78. }
  79. /**
  80. * @brief 查找16进制数据帧的首地址
  81. * @param buf 待查找的数据缓冲区起始地址
  82. * @param len 可用于查找的数据长度
  83. * @return 找到则返回数据帧起始地址,没有找到则返回 NULL
  84. */
  85. char *get_frame_start(char *buf, uint16_t len)
  86. {
  87. if (buf == NULL || len < 2)
  88. {
  89. return NULL;
  90. }
  91. for (uint16_t i = 0; i <= len - 2; i++)
  92. {
  93. if ((uint8_t)buf[i] == 0x68 && (uint8_t)buf[i + 1] == 0x10)
  94. {
  95. return &buf[i];
  96. }
  97. }
  98. return NULL;
  99. }
  100. int NbRcvDataValid(void)
  101. {
  102. char *p_comma = NULL;
  103. char *p_start = NULL;
  104. char len_str[8] = {0};
  105. uint32_t total_frame_len = 0;
  106. uint8_t cs;
  107. uint8_t head_len = 0;
  108. uint16_t data_len;
  109. // 1. 检查是否有数据接收完成标志
  110. if (Nb_rx_data() == 0)
  111. return 0; // 无数据,继续等待
  112. // 2. 接收数据关键字
  113. uint8_t pos = 0;
  114. while (pos < NbRun.rx_idx)
  115. {
  116. p_comma = strstr((char *)NbRun.rx_buf + pos, "+QIRD: ");
  117. if (p_comma == NULL)
  118. {
  119. // 没有逗号,检查是否全是空白或OK,如果是则清除
  120. if (strstr((char *)NbRun.rx_buf, "OK") != NULL || NbRun.rx_idx > 50)
  121. {
  122. NbClrRxBuf();
  123. }
  124. return 0; // 数据可能不完整,继续等待
  125. }
  126. p_start = p_comma + 7; //+QIRD:后的数据开始位置
  127. while (*p_start >= '0' && *p_start <= '9')
  128. {
  129. len_str[head_len++] = *p_start++;
  130. }
  131. len_str[head_len] = '\0';
  132. total_frame_len = atoi(len_str); // 数据总长度
  133. if (total_frame_len < 14)
  134. {
  135. // NbClrRxBuf();
  136. // return 4;
  137. pos = p_start - (char *)NbRun.rx_buf;
  138. continue;
  139. }
  140. else
  141. break;
  142. }
  143. // 6. 检查 Hex 数据完整性
  144. // char *p_hex_start = p_start + head_len + 2; // 包含关键字+ 长度域+ 回车换行符
  145. char *p_hex_start = get_frame_start(p_start + 2, NbRun.rx_idx - (p_start + 2 - (char *)NbRun.rx_buf));
  146. if (p_hex_start == NULL)
  147. {
  148. return 0; // 数据不完整,继续等待
  149. }
  150. // 6.2 检查校验和
  151. cs = 0;
  152. uint16_t available_chars = NbRun.rx_idx - (p_hex_start - (char *)NbRun.rx_buf);
  153. if (available_chars < total_frame_len) // 这里可能要改为接收二进制数据,(去掉*2)
  154. {
  155. return 0; // 数据不完整,继续等待
  156. }
  157. // 7. Hex 转 Binary
  158. // StrToHexBuf((char *)&NbAppFrame.head, p_hex_start, total_frame_len);//如果是二进制数据,则不需要转换
  159. memcpy((char *)&NbAppFrame.head, p_hex_start, total_frame_len);
  160. NbClrRxBuf();
  161. // 8. 校验帧头
  162. if (NbAppFrame.head != 0x68)
  163. return 5;
  164. // 9. 校验长度一致性
  165. data_len = (NbAppFrame.len[1] << 8) | NbAppFrame.len[0];
  166. if (total_frame_len != (14 + data_len))
  167. return 6;
  168. // 10. 校验 Check Sum
  169. cs = check_sum((uint8_t *)&NbAppFrame.head, total_frame_len - 2);
  170. if (cs != NbAppFrame.data[data_len])
  171. return 7;
  172. // 11. 校验帧尾
  173. if (NbAppFrame.data[data_len + 1] != 0x16)
  174. return 8;
  175. return 1; // 验证成功
  176. }
  177. void GetNbRun(Nb_Run_t **nb_run)
  178. {
  179. *nb_run = &NbRun;
  180. }
  181. void NbRxCh(uint8_t ch)
  182. {
  183. if (NbRun.rx_idx >= NB_RXLEN_MAX - 1)
  184. {
  185. return;
  186. }
  187. NbRun.rx_buf[NbRun.rx_idx++] = ch;
  188. NbRun.rx_over_time = 4;
  189. #ifdef DEBUG_NB
  190. // LOG("%c",ch);
  191. #endif
  192. }
  193. // void NbRxTimeout(void)
  194. //{
  195. // if (NbRun.rx_over_time >= 2) {
  196. // NbRun.rx_over_time--;
  197. // } else if (NbRun.rx_over_time == 1) {
  198. // NbRun.rx_flag = TRUE;
  199. // NbRun.rx_over_time--;
  200. // }
  201. // }
  202. uint8_t Nb_rx_data(void)
  203. {
  204. if (NbRun.rx_over_time != 0)
  205. {
  206. NbRun.rx_over_time--;
  207. }
  208. if (NbRun.rx_over_time == 1)
  209. {
  210. #ifdef DEBUG_NB
  211. /////////////////////
  212. unsigned short i;
  213. for (i = 0; i < NbRun.rx_idx; i++)
  214. LOG("%c", NbRun.rx_buf[i]);
  215. // LOG("%s\r\n",NbRun.rx_buf);
  216. ///////////////////
  217. #endif
  218. return 1; // 已收到数据
  219. // }
  220. }
  221. return 0;
  222. }
  223. void NbClrRxBuf(void)
  224. {
  225. NbRun.rx_idx = 0;
  226. memset(NbRun.rx_buf, 0, sizeof(NbRun.rx_buf));
  227. }
  228. int8_t get_nb_imsi_code(void)
  229. {
  230. char *p = NULL;
  231. char *q = NULL;
  232. uint8_t i, flag;
  233. p = strstr((char *)NbRun.rx_buf, "OK");
  234. if (p == NULL)
  235. {
  236. return -1;
  237. }
  238. p = strstr((char *)NbRun.rx_buf, "\r\n"); // 找到第一个回车符
  239. if (p != NULL && strlen(p) > 2)
  240. {
  241. q = strstr(p + 2, "\r\n"); // 第二个回车符,id在两个回车符之间
  242. if (q != NULL && (q - p - 2) > 0 && (q - p - 2) < 16)
  243. { // 长度大于2小于15
  244. *q = 0;
  245. strcpy(NbRun.imsi, p + 2);
  246. /// LOG("imsi = %s\n", NbRun.imsi);
  247. }
  248. }
  249. flag = 0;
  250. for (i = 0; NbRun.imsi[i] != 0; i++)
  251. {
  252. if (NbRun.imsi[i] < '0' || NbRun.imsi[i] > '9')
  253. {
  254. flag = 1;
  255. break;
  256. }
  257. }
  258. if (flag == 1 || i != 15)
  259. return -1;
  260. NbRun.get_imsi_flag = 1; // 已获取IMEI号标志
  261. return 0;
  262. }
  263. int8_t get_nb_imei_code(void)
  264. {
  265. char *p = NULL;
  266. char *q = NULL;
  267. uint8_t i, flag;
  268. p = strstr((char *)NbRun.rx_buf, "OK");
  269. if (p == NULL)
  270. {
  271. return -1;
  272. }
  273. p = strstr((char *)NbRun.rx_buf, "+CGSN:");
  274. if (p != NULL)
  275. {
  276. p = strstr((char *)NbRun.rx_buf, "\""); // 找到第一个"所在位置
  277. if (p != NULL && strlen(p + 1) > 1)
  278. {
  279. q = strstr(p + 1, "\"\r\n"); // 回车换行符所在位置
  280. if (q != NULL && (q - p - 1) > 0 && (q - p - 1) < 16)
  281. { // 存在回车换行符,且:到换行符之间有信息,且长度小于16
  282. *q = 0; // 把第二个"置0,作为字符串结束位置
  283. strcpy(NbRun.imei, p + 1);
  284. }
  285. }
  286. }
  287. flag = 0;
  288. for (i = 0; NbRun.imei[i] != 0; i++)
  289. {
  290. if (NbRun.imei[i] < '0' || NbRun.imei[i] > '9')
  291. {
  292. flag = 1;
  293. break;
  294. }
  295. }
  296. if (flag == 1 || i != 15)
  297. return -1;
  298. NbRun.get_imei_flag = 1; // 已获取IMEI号标志
  299. #ifdef APP_DEBUG_PRINT
  300. LOG("imei=%s\r\n", NbRun.imei);
  301. #endif
  302. return 0;
  303. }
  304. int8_t get_nb_ccid_code(void)
  305. {
  306. char *p = NULL;
  307. char *q = NULL;
  308. uint8_t i, flag;
  309. p = strstr((char *)NbRun.rx_buf, "OK");
  310. if (p == NULL)
  311. {
  312. return -1;
  313. }
  314. p = strstr((char *)NbRun.rx_buf, ":");
  315. p++;
  316. if (p != NULL && strlen(p) > 1)
  317. {
  318. q = strstr(p + 1, "\r\n");
  319. if (q != NULL && (q - p - 1) > 0 && (q - p - 1) < 21)
  320. {
  321. *q = 0;
  322. strcpy(NbRun.ccid, p + 1);
  323. }
  324. }
  325. flag = 0;
  326. for (i = 0; NbRun.ccid[i] != 0; i++)
  327. {
  328. if (NbRun.ccid[i] < '0' || NbRun.ccid[i] > '9')
  329. {
  330. flag = 1;
  331. break;
  332. }
  333. }
  334. if (flag == 1 || i != 20)
  335. return -1;
  336. NbRun.get_ccid_flag = 1; // 已获取IMEI号标志
  337. #ifdef APP_DEBUG_PRINT
  338. LOG("iccid=%s\r\n", NbRun.ccid);
  339. #endif
  340. return 0;
  341. }
  342. // NUESTATS:CELL,<earfcn>,<physical_cell_id>,<primarycell>,<RSRP>,<RSRQ>,<RSSI>,<SNR>
  343. // NUESTATS:CELL,2401,476,1,-920,-41,-879,144
  344. // 在 app_nb.c 中找到 NbSetUploadMode 函数并替换
  345. void NbSetUploadMode(uint8_t mode)
  346. {
  347. // 【修改点】:始终更新 mode,使用 |= 确保不覆盖已有的触发原因
  348. // 例如:如果之前是定时上报(0x02),现在发生了错误报警(0x10),mode 将变为 0x12
  349. NbRun.upload.mode |= mode;
  350. // 只有在尚未标记上传任务时,才设置 flag 并唤醒线程
  351. if (NbRun.upload.flag == FALSE)
  352. {
  353. NbRun.upload.flag = TRUE;
  354. NbRun.task.flag = 1;
  355. NbRun.cur_afn = 0x0010;
  356. rt_sem_release(Nb_thread_run_sem); // 触发nb线程
  357. }
  358. }
  359. /////////////////等待接收指定的回复///////////////////////
  360. // ack:回复的字符串
  361. // timeout:等待超时时间 秒单位
  362. //: 返回0:成功, -1:等待超时
  363. /////////////////////////////////////
  364. int8_t Nb_check_rec_valid(uint8_t state, char *ack)
  365. {
  366. // if(state == COAP_WAIT_REG){
  367. // if(strstr((const char *)NbRun.rx_buf, ack) != NULL )
  368. // }
  369. // else
  370. if (strstr((const char *)NbRun.rx_buf, ack) != NULL)
  371. { // 收到要求的回复
  372. return 1; // 收到正确回复,进行下一步
  373. }
  374. // if (strstr((char *)&NbRun.rx_buf[0], "\r\nOK\r\n") != NULL || strstr((char *)&NbRun.rx_buf[0], "\r\nERROR\r\n") != NULL)
  375. if (strstr((char *)&NbRun.rx_buf[0], "\r\nERROR\r\n") != NULL)
  376. {
  377. return -1; // 错误回复,重新发送
  378. }
  379. return 0; // 其他需要继续等待
  380. }
  381. void nb_send_data_route(unsigned char *data, uint16_t len) // 发送数据 TCP
  382. {
  383. char tmp[16] = {0};
  384. memset(NbRun.tx_buf, 0, sizeof(NbRun.tx_buf));
  385. strcpy((char *)NbRun.tx_buf, "AT+QISENDEX=0,"); // at指令 发送数据
  386. // int2str(len, tmp); // 转换成字符串
  387. strcat((char *)NbRun.tx_buf, "\"");
  388. HexBufToStr((char *)NbRun.tx_buf + strlen((char *)NbRun.tx_buf), data, len); // 不加前面的指令部分,只发送数据部分
  389. strcat((char *)NbRun.tx_buf, "\"");
  390. strcat((char *)NbRun.tx_buf, "\r\n\0"); // 末尾回车换行符
  391. // NbRoutineEventPro((char *)NbRun.tx_buf, (char *)NB_NMGS_ACK, 3, 60);
  392. }
  393. UPLOAD_DEF upload_dat;
  394. const uint8_t monthday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  395. ///////////////////////////////////////////
  396. /////////////////////////////////main.c中运行,判断是否应该触发nb线程//////////////////////////////////////////////
  397. // 参数 无
  398. // 返回 无
  399. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  400. uint8_t settlement_day_upload_check(void)
  401. { // 结算日上报
  402. if (Paramx.settlement_day == 0)
  403. return 0;
  404. rtc_run_t *rr;
  405. get_rtc_run(&rr);
  406. uint8_t days, setday;
  407. days = monthday[rr->month - 1];
  408. if (rr->year % 4 == 0 && rr->month == 2)
  409. {
  410. days++;
  411. } // 计算当月天数
  412. //////////////////////确定当天上报是否是结算日上报/////////////////////////////////////
  413. int32_t now, start;
  414. now = (int32_t)(3600 * rr->hour + 60 * rr->minute + rr->second);
  415. start = (int32_t)(Paramx.report_base_hour * 3600 + Paramx.report_base_min * 60 + (Paramx.report_base_sec & 0xfc));
  416. if (Paramx.settlement_day == 0)
  417. {
  418. return 0;
  419. }
  420. if (Paramx.settlement_day > days)
  421. {
  422. setday = days;
  423. }
  424. else
  425. {
  426. setday = Paramx.settlement_day;
  427. }
  428. if (now < start)
  429. return 0;
  430. if (setday == rr->day && now - start <= 5)
  431. {
  432. return NB_UPLOAD_SETTLE_DAY;
  433. }
  434. return 0;
  435. }
  436. uint8_t regular_upload_check(void)
  437. { // 定时上报
  438. uint32_t *alarmbit;
  439. all_alarm_status(&alarmbit);
  440. if ((*alarmbit & ERR_LOW_POWER) != 0)
  441. return 0; // 低电压不上报
  442. uint8_t i;
  443. rtc_run_t *rr;
  444. get_rtc_run(&rr);
  445. int32_t now, start;
  446. now = (int32_t)(3600 * rr->hour + 60 * rr->minute + rr->second);
  447. start = (int32_t)(Paramx.report_base_hour * 3600 + Paramx.report_base_min * 60 + (Paramx.report_base_sec & 0xfc));
  448. if (now < start)
  449. return 0; // 未到上报时间
  450. if (((now - start) % (Paramx.report_interval * 60)) <= 5)
  451. return NB_UPLOAD_TIMER;
  452. return 0;
  453. }
  454. uint8_t dma_upload_check(void)
  455. {
  456. uint32_t *alarmbit;
  457. all_alarm_status(&alarmbit);
  458. if ((*alarmbit & ERR_LOW_POWER) != 0)
  459. return 0; // 低电压DMA不上报
  460. if (Paramx.dma_interval == 0)
  461. return 0; // 无dma上报
  462. int32_t start_sec, end_sec, now_sec;
  463. rtc_run_t *rr;
  464. get_rtc_run(&rr);
  465. start_sec = (int32_t)(3600 * Paramx.dma_report_start[0] + 60 * Paramx.dma_report_start[1] + (Paramx.dma_report_start[2] & 0xfc));
  466. end_sec = (int32_t)(3600 * Paramx.dma_report_end[0] + 60 * Paramx.dma_report_end[1] + (Paramx.dma_report_end[2] & 0xfc));
  467. now_sec = (int32_t)(3600 * rr->hour + 60 * rr->minute + rr->second);
  468. if (now_sec < start_sec || now_sec > end_sec + 3)
  469. return 0; // 不在dma时间范围内
  470. if (((now_sec - start_sec) % (Paramx.dma_interval * 60)) <= 5)
  471. {
  472. return NB_UPLOAD_DMA;
  473. }
  474. return 0;
  475. }
  476. ////////////////故障上报监测///////////////////////
  477. // 参数:无
  478. // 返回:有故障NB_UPLOAD_ERR 无故障:0
  479. ///////////////////////////////////////////////
  480. uint8_t err_upload_check(void)
  481. {
  482. uint32_t *alarmbit;
  483. uint32_t temp;
  484. if (StartUp < 15)
  485. return 0;
  486. all_alarm_status(&alarmbit);
  487. temp = (upload_dat.err_mem_dat & (*alarmbit)) ^ (*alarmbit); // 检查是否有异常bit被置位
  488. if (temp != 0)
  489. {
  490. upload_dat.err_mem_dat = *alarmbit;
  491. return NB_UPLOAD_ERR;
  492. }
  493. return 0;
  494. }
  495. uint8_t rept_upload_check(void)
  496. { // 重复上报监测
  497. uint8_t i;
  498. rtc_run_t *rr;
  499. get_rtc_run(&rr);
  500. tm_t now_time;
  501. now_time.year = rr->year;
  502. now_time.month = rr->month;
  503. now_time.day = rr->day;
  504. now_time.hour = rr->hour;
  505. now_time.min = rr->minute;
  506. now_time.sec = rr->second;
  507. uint32_t now_sec = (uint32_t)(now_time.hour * 3600 + now_time.min * 60 + now_time.sec);
  508. uint32_t start_sec = (uint32_t)(upload_dat.rept_time.hour * 3600 + upload_dat.rept_time.min * 60 + (upload_dat.rept_time.sec & 0xfc));
  509. uint8_t ret = 0;
  510. if (upload_dat.rept_runflag != 0)
  511. {
  512. // if (datecmp(now_time, upload_dat.rept_time) >= 0)
  513. if (now_sec >= start_sec && now_sec <= start_sec + 3)
  514. {
  515. upload_dat.rept_runflag = 0;
  516. return NB_UPLOAD_REPT;
  517. }
  518. }
  519. return 0;
  520. }
  521. // 手动上报
  522. uint8_t manual_upload_check(void)
  523. {
  524. if (upload_dat.manual_runflag == 1)
  525. {
  526. upload_dat.manual_runflag = 0;
  527. return NB_UPLOAD_MANUAL;
  528. }
  529. return 0;
  530. }
  531. short up_signal_cnt = -100; // 用于上报过程中动态显示信号强度
  532. /////////////////////////////////main.c中运行,判断是否应该触发nb线程,1秒1一次//////////////////////////////////////////////
  533. // 参数 无
  534. // 返回 无
  535. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  536. // 在 app_nb.c 中找到 nb_task_run_check 函数并替换
  537. void nb_task_run_check(void)
  538. {
  539. uint8_t trik_flag = 0;
  540. extern const int16_t rsrp_level[5];
  541. // 信号强度动态显示逻辑保持不变
  542. if (NbRun.upload.flag != 0)
  543. {
  544. up_signal_cnt = (up_signal_cnt + 1) % 5;
  545. NbRun.rsrp = rsrp_level[up_signal_cnt];
  546. }
  547. else
  548. NbRun.rsrp = NbRun.rsrp_bak;
  549. #ifdef debug_dog
  550. if (StartUp == 5)
  551. {
  552. rt_enter_critical();
  553. McuFlash_EraseSegment(DIFF_PATCH_PACKET_START, DIFF_PATCH_PACKET_SIZE);
  554. rt_exit_critical();
  555. rt_enter_critical();
  556. uint8_t i;
  557. for (i = 0; i < 16; i++)
  558. xx[i] = i + 1;
  559. write_flash_memory(xx, DIFF_PATCH_PACKET_START, 16);
  560. rt_exit_critical();
  561. while (1)
  562. ;
  563. }
  564. #endif
  565. if (NbRun.reset_mcu_cnt != 0)
  566. {
  567. NbRun.reset_mcu_cnt--;
  568. if (NbRun.reset_mcu_cnt == 2)
  569. LOG("ready to reset mcu\r\n");
  570. if (NbRun.reset_mcu_cnt == 1)
  571. {
  572. // watchdog_init(WdtResetEn, WdtT3s28);
  573. // feed_dog();
  574. NVIC_SystemReset();
  575. // while (1);
  576. // {
  577. // }
  578. }
  579. // NVIC_SystemReset();
  580. }
  581. // 【修改点】:不再因为 NbRun.upload.flag 为真而直接 return
  582. // 即使正在上传,我们也要检查是否有新的触发原因(如错误报警),并将其加入 mode
  583. trik_flag = settlement_day_upload_check();
  584. trik_flag |= regular_upload_check();
  585. trik_flag |= dma_upload_check();
  586. trik_flag |= err_upload_check(); // 错误报警通常优先级最高,但也作为位之一
  587. trik_flag |= rept_upload_check();
  588. trik_flag |= manual_upload_check();
  589. if (trik_flag != 0)
  590. {
  591. // 调用 NbSetUploadMode,它内部会处理 |= 逻辑和线程唤醒逻辑
  592. NbSetUploadMode(trik_flag);
  593. }
  594. // 注意:如果上传已经完成或失败,NbRun.upload.flag 会在 NbTread 末尾清零
  595. // 此时下一次 nb_task_run_check 运行时会正常触发新的上传任务
  596. }
  597. // 上报数据准备,在tx_buf中
  598. void nb_upload_data_ready(void)
  599. {
  600. NbBuildDataReport(); // 组织上报数据,在NbAppFrame中
  601. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16; // 数据总长度
  602. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  603. }
  604. void nb_set_ip_para_ack(void)
  605. {
  606. // NbBuildSetIpAndPortRsp();
  607. nb_set_para_rept(5, 0x20, 1);
  608. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  609. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  610. }
  611. void nb_set_regular_report_para_ack(int8_t ret)
  612. {
  613. // NbBuildSetReportPointRsp(ret);
  614. nb_set_para_rept(5, 0x21, ret);
  615. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  616. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  617. }
  618. void nb_set_dma_report_para_ack(int8_t ret)
  619. {
  620. /// NbBuildSetDmaReportPointRsp(ret);
  621. nb_set_para_rept(5, 0x22, ret);
  622. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  623. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  624. }
  625. void nb_set_rtc_data_ack(int8_t ret)
  626. {
  627. // NbBuildSetDateTimeRsp(ret);
  628. nb_set_para_rept(5, 0x23, ret);
  629. }
  630. void nb_set_flow_alarm_para_ack(int8_t ret)
  631. {
  632. // NbBuildSetFlowAlarmThresRsp(ret);
  633. nb_set_para_rept(5, 0x24, ret);
  634. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  635. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  636. }
  637. void nb_set_pressure_alarm_para_ack(int8_t ret)
  638. {
  639. // NbBuildSetPressureAlarmThresRsp(ret);
  640. nb_set_para_rept(5, 0x25, ret);
  641. }
  642. void nb_set_temp_alarm_para_ack(int8_t ret)
  643. {
  644. // NbBuildSetTempAlarmThresRsp(ret);
  645. nb_set_para_rept(5, 0x26, ret);
  646. }
  647. void nb_set_settlment_day_para_ack(int8_t ret)
  648. {
  649. // NbBuildSetSettleRsp(ret);
  650. nb_set_para_rept(5, 0x27, ret);
  651. }
  652. void nb_set_meter_bottom_data_ack(int8_t ret)
  653. {
  654. // NbBuildSetBaseReadingRsp(ret);
  655. nb_set_para_rept(5, 0x28, ret);
  656. }
  657. void nb_read_month_record_ack(void)
  658. {
  659. NbBuildReportMonthRecord();
  660. }
  661. void nb_read_day_record_ack(void)
  662. {
  663. NbBuildReportDayRecord();
  664. }
  665. int8_t nb_read_hour_record_ack(void)
  666. {
  667. uint32_t start, end, ndate;
  668. uint8_t loop_count = 0; // 用于限制循环次数
  669. start = (NbAppFrame.data[5] << 16) | (NbAppFrame.data[6] << 8) | NbAppFrame.data[7];
  670. end = (NbAppFrame.data[9] << 16) | (NbAppFrame.data[10] << 8) | NbAppFrame.data[11];
  671. rtc_run_t *rr;
  672. get_rtc_run(&rr); // 获取当前时间
  673. ndate = (rr->year << 16) | (rr->month << 8) | rr->day;
  674. // 计算30天前的日期边界
  675. uint32_t b30date = ndate;
  676. for (uint8_t i = 0; i < 30; i++)
  677. b30date = prev_day(b30date);
  678. // --- 修改部分开始 ---
  679. // 原逻辑:如果时间不合法,直接返回 -1
  680. // 新逻辑:如果时间不合法,构建一个长度为248且数据全为0的帧发送一次
  681. // 检查合法性
  682. uint8_t is_invalid = 0;
  683. if (start > ndate || end < b30date || start > end) // 允许读取当天数据
  684. {
  685. is_invalid = 1;
  686. }
  687. // 校正 start
  688. if (start < b30date)
  689. start = b30date;
  690. // 校正 end
  691. if (end > ndate)
  692. end = ndate;
  693. // 再次检查校正后是否合法
  694. if (start > end)
  695. {
  696. is_invalid = 1;
  697. }
  698. if (is_invalid)
  699. {
  700. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  701. // 定义正常的数据长度 (参考 NbBuildReportHourRecord)
  702. uint16_t data_len = 248;
  703. // 构建帧头
  704. NbBuildDataHeader(data_len);
  705. // 设置 AFN 为 0x34 (Read Hour Record Response)
  706. NbAppFrame.data[0] = 0x34;
  707. NbAppFrame.data[1] = 0x00;
  708. // 设置 MID
  709. NbAppFrame.data[2] = (uint8_t)(mid);
  710. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  711. // 将数据区域全部清零 (NbBuildDataHeader 不会自动清零 data 区域,需手动处理)
  712. // 注意:NbAppFrame.data 的大小通常足够容纳 248 字节
  713. memset(&NbAppFrame.data[4], 0, data_len);
  714. // 构建帧尾 (包含校验和)
  715. NbBuildDataTail(data_len);
  716. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  717. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  718. // 发送 AT 命令
  719. if (at_cmd_send(COAP_QLWDATASEND, (char *)NbRun.tx_buf, NB_AT_ACK, 3, 60) == -1)
  720. return -1;
  721. return 0; // 返回成功,表示已处理本次请求
  722. }
  723. // --- 修改部分结束 ---
  724. ndate = start;
  725. uint16_t len;
  726. // 无限循环处理所有有效日期,但限制 loop_count < 12 以防死循环或数据过多
  727. while (ndate <= end && loop_count < 12)
  728. {
  729. NbBuildReportHourRecord((uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate));
  730. len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  731. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  732. if (at_cmd_send(COAP_QLWDATASEND, (char *)NbRun.tx_buf, NB_AT_ACK, 3, 60) == -1)
  733. return -1;
  734. ndate = next_day(ndate);
  735. loop_count++; // 增加计数器
  736. }
  737. return 0;
  738. }
  739. int8_t nb_read_5min_record_ack(void)
  740. {
  741. // 将大型局部变量改为静态变量,以减少栈使用
  742. static tm_t start, end, cur;
  743. static tm_t now_tm, limit_start_tm;
  744. uint16_t len;
  745. uint8_t loop_count = 0; // ?
  746. // 1. е????
  747. start.year = NbAppFrame.data[5];
  748. start.month = NbAppFrame.data[6];
  749. start.day = NbAppFrame.data[7];
  750. start.hour = NbAppFrame.data[8];
  751. start.min = NbAppFrame.data[9];
  752. start.sec = 0;
  753. end.year = NbAppFrame.data[11];
  754. end.month = NbAppFrame.data[12];
  755. end.day = NbAppFrame.data[13];
  756. end.hour = NbAppFrame.data[14];
  757. end.min = NbAppFrame.data[15];
  758. end.sec = 0;
  759. // 2. ????15??
  760. rtc_run_t *rr;
  761. get_rtc_run(&rr);
  762. // ?? tm_t (??)
  763. now_tm.year = rr->year;
  764. now_tm.month = rr->month;
  765. now_tm.day = rr->day;
  766. now_tm.hour = rr->hour;
  767. now_tm.min = rr->minute;
  768. now_tm.sec = rr->second;
  769. // 15???
  770. uint32_t date32 = (rr->year << 16) | (rr->month << 8) | rr->day;
  771. for (uint8_t i = 0; i < 15; i++)
  772. {
  773. date32 = prev_day(date32);
  774. }
  775. limit_start_tm.year = (date32 >> 16) & 0xFF;
  776. limit_start_tm.month = (date32 >> 8) & 0xFF;
  777. limit_start_tm.day = date32 & 0xFF;
  778. limit_start_tm.hour = 0;
  779. limit_start_tm.min = 0;
  780. limit_start_tm.sec = 0;
  781. // 3. ??: start ? end
  782. uint8_t is_invalid = 0;
  783. if (datecmp(start, end) > 0)
  784. {
  785. is_invalid = 1;
  786. }
  787. // 4. ?Ч??Χ
  788. // ЧΧ: [limit_start_tm, now_tm]
  789. if (datecmp(end, limit_start_tm) < 0) // ?15?
  790. {
  791. is_invalid = 1;
  792. }
  793. if (datecmp(start, now_tm) > 0) // ?????
  794. {
  795. is_invalid = 1;
  796. }
  797. // 5. У start end ЧΧ
  798. if (datecmp(start, limit_start_tm) < 0)
  799. {
  800. start = limit_start_tm;
  801. }
  802. // if (datecmp(end, now_tm) > 0)//允许终止时间大于当前时间
  803. //{
  804. // end = now_tm;
  805. // }
  806. // ?μУ?
  807. if (datecmp(start, end) > 0)
  808. {
  809. is_invalid = 1;
  810. }
  811. // --- ???? ---
  812. // ????388??0??
  813. if (is_invalid)
  814. {
  815. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  816. //
  817. uint16_t data_len = 388;
  818. // ??
  819. NbBuildDataHeader(data_len);
  820. // AFN ? 0x37 (Read 5Min Record Response)
  821. NbAppFrame.data[0] = 0x37;
  822. NbAppFrame.data[1] = 0x00;
  823. // MID
  824. NbAppFrame.data[2] = (uint8_t)(mid);
  825. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  826. // ? (NbBuildDataHeader ? data ?)
  827. // ??NbAppFrame.data ?С? 388 ?
  828. memset(&NbAppFrame.data[4], 0, data_len);
  829. // ?β (У)
  830. NbBuildDataTail(data_len);
  831. len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  832. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  833. // AT
  834. if (at_cmd_send(COAP_QLWDATASEND, (char *)NbRun.tx_buf, NB_AT_ACK, 3, 60) == -1)
  835. return -1;
  836. return 0; // ????
  837. }
  838. // --- ??? ---
  839. // 6. ??12
  840. cur = start; // 初始化 cur
  841. while (datecmp(cur, end) < 0) // ? while ???м
  842. {
  843. // ?
  844. if (loop_count >= 12)
  845. {
  846. break;
  847. }
  848. NbBuildReport5MinRecord(&cur);
  849. len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  850. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  851. if (at_cmd_send(COAP_QLWDATASEND, (char *)NbRun.tx_buf, NB_AT_ACK, 3, 60) == -1)
  852. return -1;
  853. // 2С?
  854. time_add_secs(&cur, &cur, 2 * 60 * 60);
  855. loop_count++; // ?
  856. }
  857. return 0;
  858. }
  859. void nb_read_log_record_ack(void)
  860. {
  861. NbBuildReportLogRecord();
  862. }
  863. /////// 设置开始升级信息/////////////////////
  864. /// 返回 1:成功 2:版本号不对 3:长度超限
  865. int8_t nb_set_patch_info(void)
  866. {
  867. PATCH_INFO_DEF dat;
  868. uint8_t *src = &NbAppFrame.data[4];
  869. memcpy(dat.cur_ver, src, 5);
  870. memcpy(dat.new_ver, src + 5, 5);
  871. dat.patch_len = src[10] + ((uint16_t)src[11] << 8) + ((uint32_t)src[12] << 16) + ((uint32_t)src[13] << 24);
  872. dat.per_packet_len = src[14] + 256 * src[15];
  873. dat.packet_crc = src[16] + 256 * src[17];
  874. uint8_t ret = set_patch_info(&dat); // 返回1,2,3 //1成功
  875. // if(ret != 0)return -1;
  876. // else return 0;
  877. return ret;
  878. }
  879. ////////////////////////////////////
  880. // 1.升级成功结束
  881. // 2:升级失败,crc校验失败
  882. // 3.升级失败,多次尝试未获得升级包
  883. // 4.失败,未能成功运行
  884. // 5.失败版本不匹配
  885. // 0x10:重新读取本包数据
  886. // 0x20:获取下一包
  887. ///////////////////////////////////
  888. void nb_set_patch_info_ack(int8_t stat)
  889. {
  890. // if(stat>=1 && stat <= 6 ){
  891. if (stat <= 3)
  892. NbBuildReportUpdateStatus(stat);
  893. //}
  894. else // if(stat == 0x10){
  895. NbBuildGetPackage();
  896. //}
  897. // else if(stat == 0x20){
  898. // NbBuildGetPackage();
  899. // }
  900. }
  901. /////////////在采样中断结束,刚好允许进入低功耗时发送指令,避免接收失败//////////////////////
  902. // dat:要发送的数据
  903. ////////////////////////////////////
  904. // uint8_t NB_CHECK_TDC_COMPLETE_FLAG
  905. // check G_TDC_CAN_DEEP_SLEEP 0->1
  906. uint8_t delay_send_cmd_cnt = 0;
  907. void send_nb_data_after_sample(char *dat)
  908. {
  909. delay_send_cmd_cnt++;
  910. if (NB_CHECK_TDC_COMPLETE_FLAG == 1 && delay_send_cmd_cnt > 3 ||delay_send_cmd_cnt > 12)
  911. {
  912. nb_tx_str(dat);
  913. delay_send_cmd_cnt = 0;
  914. }
  915. NB_CHECK_TDC_COMPLETE_FLAG = 0;
  916. }
  917. int8_t rec_data_check(void)
  918. {
  919. // 1. 主动请求数据
  920. send_nb_data_after_sample("AT+QIRD=0,1500\r\n"); // 读取数据,最长1500 tcp限制
  921. // 2. 尝试解析数据
  922. uint8_t result = NbRcvDataValid();
  923. // --- 情况 A: 没有收到完整数据或正在等待 ---
  924. if (result == 0)
  925. {
  926. // 如果是 OTA 过程,允许较长的等待时间
  927. if (NbRun.cur_afn == 0x50 || NbRun.cur_afn == 0x51)
  928. {
  929. NbRun.get_patch_time_out++;
  930. if (NbRun.get_patch_time_out < 120) // 约 5-10秒
  931. return 1; // 继续等待
  932. else
  933. return -1; // OTA 超时
  934. }
  935. return 1; // 普通命令继续等待
  936. }
  937. // --- 情况 B: 数据校验失败 (格式错误、CS错误等) ---
  938. if (result > 1)
  939. {
  940. #ifdef DEBUG_NB
  941. LOG("Rcv Err: %d\r\n", result);
  942. #endif
  943. // 收到垃圾数据,清除状态,让上层循环重试 AT+NMGR
  944. // 返回 1 表示“本次尝试失败,请重试”,而不是“继续等待当前缓冲”
  945. return 1;
  946. }
  947. // --- 情况 C: 数据校验成功 (result == 1) ---
  948. NbRun.get_patch_time_out = 0; // 重置 OTA 超时计数
  949. uint16_t afn = (NbAppFrame.data[1] << 8) | NbAppFrame.data[0];
  950. uint16_t data_len = (NbAppFrame.len[1] << 8) | NbAppFrame.len[0];
  951. // 更新当前 AFN 状态,用于后续多包交互(如 OTA)
  952. if (afn != 0x51)
  953. { // 数据包通常不改变 cur_afn,除非是第一个包
  954. NbRun.cur_afn = afn;
  955. }
  956. int8_t ret = 0;
  957. uint8_t need_reply = 0; // 标记是否需要发送应用层回复
  958. uint8_t update_status = 0;
  959. #ifdef DEBUG_NB
  960. LOG("Rec OK, AFN=0x%04X, Len=%d\r\n", afn, data_len);
  961. #endif
  962. // --- 业务逻辑分发 ---
  963. switch (afn)
  964. {
  965. case 0x20: // Set IP/Port
  966. if (data_len != 16)
  967. return 1;
  968. ret = set_server_ip_port_para((SERVER_IP_PORT_DEF *)&NbAppFrame.data[4]);
  969. nb_set_ip_para_ack();
  970. need_reply = 1;
  971. break;
  972. case 0x21: // Set Regular Report
  973. if (data_len != 9)
  974. return 1;
  975. {
  976. REGULAR_REPORT_DEF dat;
  977. dat.report_base_hour = NbAppFrame.data[4];
  978. dat.report_base_min = NbAppFrame.data[5];
  979. dat.report_base_sec = NbAppFrame.data[6];
  980. dat.report_interval = NbAppFrame.data[7] + 256 * NbAppFrame.data[8];
  981. ret = set_regular_report_para(&dat);
  982. }
  983. nb_set_regular_report_para_ack(ret == 0 ? 1 : ret);
  984. need_reply = 1;
  985. break;
  986. case 0x22: // Set DMA Report
  987. if (data_len != 11)
  988. return 1;
  989. {
  990. DMA_REGULAR_REPORT_DEF dat;
  991. dat.dma_report_start_hour = NbAppFrame.data[4];
  992. dat.dma_report_start_min = NbAppFrame.data[5];
  993. dat.dma_report_start_sec = NbAppFrame.data[6];
  994. dat.dma_report_end_hour = NbAppFrame.data[7];
  995. dat.dma_report_end_min = NbAppFrame.data[8];
  996. dat.dma_report_end_sec = NbAppFrame.data[9];
  997. dat.dma_interval = NbAppFrame.data[10];
  998. ret = set_dma_regular_report_para(&dat);
  999. }
  1000. nb_set_dma_report_para_ack(ret == 0 ? 1 : ret);
  1001. need_reply = 1;
  1002. break;
  1003. case 0x23: // Set RTC
  1004. if (data_len != 11)
  1005. return 1;
  1006. {
  1007. tm_t tm;
  1008. // tm.year = ((NbAppFrame.data[4] << 8) | NbAppFrame.data[5]) % 2000;
  1009. tm.year = NbAppFrame.data[5];
  1010. tm.month = NbAppFrame.data[6];
  1011. tm.day = NbAppFrame.data[7];
  1012. tm.hour = NbAppFrame.data[8];
  1013. tm.min = NbAppFrame.data[9];
  1014. tm.sec = NbAppFrame.data[10];
  1015. ret = SetRtcTime(&tm);
  1016. }
  1017. save_cur_flow_flag = 1;
  1018. nb_set_rtc_data_ack(ret);
  1019. need_reply = 1;
  1020. break;
  1021. case 0x24: // Set Flow Alarm
  1022. if (data_len != 18)
  1023. return 1;
  1024. {
  1025. FLOW_ALARM_PARA_DEF flow_alarm_para;
  1026. flow_alarm_para.large_flow_alarm_thres = (NbAppFrame.data[7] << 24) | (NbAppFrame.data[6] << 16) | (NbAppFrame.data[5] << 8) | NbAppFrame.data[4];
  1027. flow_alarm_para.large_flow_cnti_moni_time = (NbAppFrame.data[9] << 8) | NbAppFrame.data[8];
  1028. flow_alarm_para.cnti_flow_cnti_moni_time = (NbAppFrame.data[11] << 8) | NbAppFrame.data[10];
  1029. flow_alarm_para.leak_flow_alarm_thres = (NbAppFrame.data[15] << 24) | (NbAppFrame.data[14] << 16) | (NbAppFrame.data[13] << 8) | NbAppFrame.data[12];
  1030. flow_alarm_para.leak_flow_cnti_moni_time = (NbAppFrame.data[17] << 8) | NbAppFrame.data[16];
  1031. ret = set_flow_alarm_para(&flow_alarm_para);
  1032. }
  1033. nb_set_flow_alarm_para_ack(ret == 0 ? 1 : ret);
  1034. need_reply = 1;
  1035. break;
  1036. case 0x25: // Set Press Alarm
  1037. if (data_len != 6)
  1038. return 1;
  1039. ret = set_press_alarm_para((PRESS_ALARM_PARA_DEF *)&NbAppFrame.data[4]);
  1040. nb_set_pressure_alarm_para_ack(ret == 0 ? 1 : ret);
  1041. need_reply = 1;
  1042. break;
  1043. case 0x26: // Set Temp Alarm
  1044. if (data_len != 8)
  1045. return 1;
  1046. ret = set_temp_alarm_para((TEMP_ALARM_PARA_DEF *)&NbAppFrame.data[4]);
  1047. nb_set_temp_alarm_para_ack(ret == 0 ? 1 : ret);
  1048. need_reply = 1;
  1049. break;
  1050. case 0x27: // Set Settlement Day
  1051. if (data_len != 5)
  1052. return 1;
  1053. ret = set_settlement_day_para((SETTLEMENT_DAY_DEF *)&NbAppFrame.data[4]);
  1054. nb_set_settlment_day_para_ack(ret == 0 ? 1 : ret);
  1055. need_reply = 1;
  1056. break;
  1057. case 0x28: // Set Bottom Data
  1058. if (data_len != 12)
  1059. return 1;
  1060. ret = set_meter_bottom_data((METER_BOTTOM_DEF *)&NbAppFrame.data[4]);
  1061. nb_set_meter_bottom_data_ack(ret == 0 ? 1 : ret);
  1062. need_reply = 1;
  1063. break;
  1064. case 0x30: // Read Month Record
  1065. nb_read_month_record_ack();
  1066. need_reply = 1;
  1067. break;
  1068. case 0x32: // Read Day Record
  1069. nb_read_day_record_ack();
  1070. need_reply = 1;
  1071. break;
  1072. case 0x34: // Read Hour Record
  1073. // 注意:nb_read_hour_record_ack 内部已经完成了所有分包发送和 AT 交互
  1074. ret = nb_read_hour_record_ack();
  1075. if (ret == -1)
  1076. {
  1077. LOG("Read Hour Err\r\n");
  1078. return -1; // 严重错误,退出上传会话
  1079. }
  1080. // 内部已处理完毕,不需要再执行底部的通用回复逻辑
  1081. return 0;
  1082. case 0x36: // Read 5Min Record
  1083. ret = nb_read_5min_record_ack();
  1084. if (ret == -1)
  1085. {
  1086. LOG("Read 5Min Err\r\n");
  1087. return -1;
  1088. }
  1089. // 内部已处理完毕
  1090. return 0;
  1091. case 0x38: // Read Log
  1092. nb_read_log_record_ack();
  1093. need_reply = 1;
  1094. break;
  1095. case 0x40: // Close Link
  1096. LOG("Close Link\r\n");
  1097. return 2; // 特殊返回码,指示关闭链接
  1098. case 0x50: // OTA Start
  1099. if (data_len != 22)
  1100. return 1;
  1101. ret = nb_set_patch_info();
  1102. if (ret != 1)
  1103. {
  1104. nb_set_patch_info_ack(ret);
  1105. need_reply = 1;
  1106. }
  1107. else
  1108. {
  1109. NbRun.mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  1110. nb_set_patch_info_ack(0x10); // Request first package
  1111. need_reply = 1;
  1112. }
  1113. NbRun.get_patch_retry_cnt = 0;
  1114. break;
  1115. case 0x51: // OTA Data Package
  1116. // 检查数据长度是否匹配预期
  1117. if (data_len != (8 + PatchInfo.per_packet_len))
  1118. {
  1119. update_status = 0x20; // Resend request
  1120. }
  1121. else
  1122. {
  1123. DIFF_PACKET_DEF *dat = (DIFF_PACKET_DEF *)&NbAppFrame.data[4];
  1124. ret = write_diff_patch_to_flash(dat);
  1125. if (ret == 1)
  1126. { // Success
  1127. NbRun.get_patch_retry_cnt = 0;
  1128. if (PatchInfo.update_status == 1)
  1129. {
  1130. update_status = 0x10; // Request next
  1131. }
  1132. else
  1133. {
  1134. update_status = 1; // Finish
  1135. }
  1136. }
  1137. else
  1138. {
  1139. update_status = ret; // Error code
  1140. }
  1141. }
  1142. // 重试计数逻辑
  1143. if (update_status == 0x10 || update_status == 1)
  1144. {
  1145. NbRun.get_patch_retry_cnt = 0;
  1146. }
  1147. else
  1148. {
  1149. NbRun.get_patch_retry_cnt++;
  1150. }
  1151. if (NbRun.get_patch_retry_cnt > 20)
  1152. {
  1153. update_status = 3; // Fail
  1154. }
  1155. if (update_status <= 3)
  1156. {
  1157. NbRun.cur_afn = 0; // Reset AFN after handling packet
  1158. }
  1159. nb_set_patch_info_ack(update_status);
  1160. need_reply = 1;
  1161. if (update_status >= 1 && update_status <= 6)
  1162. {
  1163. // OTA finished or failed, will return 2 later
  1164. }
  1165. break;
  1166. default:
  1167. LOG("Unknown AFN: 0x%04X\r\n", afn);
  1168. return 1; // Ignore unknown, wait for next
  1169. }
  1170. // --- 发送应用层回复 ---
  1171. if (need_reply == 1)
  1172. {
  1173. uint16_t len = ((NbAppFrame.len[1] << 8) | NbAppFrame.len[0]) + 16;
  1174. nb_send_data_route((uint8_t *)&NbAppFrame, len);
  1175. // 发送 AT 指令并将数据发往网络
  1176. ret = at_cmd_send(55, (char *)NbRun.tx_buf, NB_AT_ACK, 6, 5);
  1177. if (ret == -1)
  1178. {
  1179. return -1; // Send failed
  1180. }
  1181. // 如果是 OTA 结束状态,返回 2 以退出循环
  1182. if (afn == 0x51 && (update_status >= 1 && update_status <= 6))
  1183. {
  1184. return 2;
  1185. }
  1186. return 0; // Success
  1187. }
  1188. return 1; // Should not reach here if logic is correct
  1189. }
  1190. void rtc_add_secs(TIME_DEF *dest, rtc_run_t *src, unsigned short secs)
  1191. {
  1192. unsigned short dat;
  1193. // dat=secs;
  1194. dest->second = (src->second + dat) % 60;
  1195. dat = (src->second + dat) / 60;
  1196. dest->minute = (src->minute + dat) % 60;
  1197. dat = (src->minute + dat) / 60;
  1198. dest->hour = (dat + src->hour) % 24;
  1199. }
  1200. uint8_t connected_flag;
  1201. void NbTread(void)
  1202. {
  1203. uint32_t retry_time;
  1204. uint8_t vflag = 0;
  1205. uint16_t len;
  1206. uint8_t ncnt;
  1207. uint8_t npos;
  1208. //////////////读取ID等初始化流程/////////////////////////////////////////
  1209. G_NB_CAN_DEEP_SLEEP = 0; // 允许休眠
  1210. nb_power_on(0);
  1211. rt_thread_mdelay(2000);
  1212. do
  1213. {
  1214. npos = 0;
  1215. if (at_cmd_send(npos++, NB_AT, NB_AT_ACK, 10, 2) == -1)
  1216. break; //
  1217. if (at_cmd_send(npos++, NB_ATE0, NB_ATE0_ACK, 3, 2) == -1) // 关闭回显
  1218. break;
  1219. /////////////设置频段//////////////////////////
  1220. ncnt = Paramx.nb_band_flag;
  1221. /////////////设置频段//////////////////////////
  1222. if (ncnt != 1)
  1223. {
  1224. set_nb_band(1);
  1225. if (at_cmd_send(npos++, "AT+GMM\r\n", NB_AT_ACK, 3, 5) == -1)
  1226. break;
  1227. ncnt = get_ta_id();
  1228. if (ncnt == TA_ID_EC800Z_CN)
  1229. {
  1230. if (at_cmd_send(npos++, NB_CFUN0, NB_AT_ACK, 3, 3) == -1)
  1231. break;
  1232. rt_thread_mdelay(1500);
  1233. if (at_cmd_send(npos++, "AT+QCFG=\"band\",0,0x90,0,1\r\n", NB_AT_ACK, 3, 5) == -1) // 使用B1,B3,B5,B8,B39
  1234. break;
  1235. if (at_cmd_send(1, NB_CFUN1, NB_AT_ACK, 3, 3) == -1)
  1236. break;
  1237. rt_thread_mdelay(1200);
  1238. }
  1239. else if (ncnt == TA_ID_EG800Z_EU) // 保持出厂默认全频段
  1240. {
  1241. // if (at_cmd_send(npos++, NB_CFUN0, NB_AT_ACK, 3, 3) == -1)
  1242. // break;
  1243. // rt_thread_mdelay(1000);
  1244. // if (at_cmd_send(npos++, "AT+QCFG=\"band\",0,0x8080095,0,1\r\n", NB_AT_ACK, 3, 5) == -1)
  1245. // break;
  1246. // if (at_cmd_send(1, NB_CFUN1, NB_AT_ACK, 3, 3) == -1)
  1247. // break;
  1248. // rt_thread_mdelay(1200);
  1249. }
  1250. }
  1251. //////////////////////////////////////////
  1252. if (at_cmd_send(npos++, NB_CGSN, NB_CGSN_ACK, 3, 2) == -1)
  1253. break;
  1254. get_nb_imei_code();
  1255. if (at_cmd_send(npos++, NB_CIMI, NB_AT_ACK, 3, 2) == -1)
  1256. break;
  1257. get_nb_imsi_code();
  1258. if (at_cmd_send(npos++, NB_NCCID, NB_NCCID_ACK, 3, 2) == -1) // different from BC28
  1259. break;
  1260. get_nb_ccid_code();
  1261. } while (0);
  1262. nb_power_off();
  1263. //////////////////////////////////////////////////////////////////
  1264. G_NB_CAN_DEEP_SLEEP = 1; // 允许休眠
  1265. while (1)
  1266. {
  1267. G_NB_CAN_DEEP_SLEEP = 1; // 允许休眠
  1268. rt_sem_take(Nb_thread_run_sem, RT_WAITING_FOREVER); // 等信号量
  1269. npos = 0;
  1270. NbRun.rsrp_bak = 0;
  1271. #ifdef DEBUG_NB
  1272. // #ifdef APP_DEBUG_PRINT
  1273. LOG("upload_begin type: %s\r\n", get_upload_type_str(NbRun.upload.mode));
  1274. if (NbRun.upload.mode & 0x10)
  1275. LOG("error_code = %X\r\n", upload_dat.err_mem_dat);
  1276. #endif
  1277. // #endif
  1278. // 既不是定时上报,也不是重复上报,并且没有子服务,也没有主服务,则跳过
  1279. if (check_sub_service_flag() == 0 && check_main_service_flag() == 0)
  1280. {
  1281. NbRun.upload.flag = 0;
  1282. NbRun.upload.mode = 0; // 本次上传结束后清零
  1283. LOG("no service upload!\r\n");
  1284. continue;
  1285. }
  1286. G_NB_CAN_DEEP_SLEEP = 0; // 不允许休眠
  1287. // #ifdef DEBUG_NB
  1288. // rtc_run_t *rr;
  1289. // get_rtc_run(&rr);
  1290. // LOG("run_time:20%2d-%2d-%2d:%2d:%2d:%2d fw=%f,bw=%f\r\n", rr->year, rr->month, rr->day, rr->hour, rr->minute, rr->second, BillRun.fw_cum_flow, BillRun.bw_cum_flow); // 锟斤拷示时锟斤拷
  1291. // #endif
  1292. nb_power_on(0);
  1293. rt_thread_mdelay(500);
  1294. do
  1295. {
  1296. if (at_cmd_send(npos++, NB_AT, NB_AT_ACK, 10, 2) == -1) // at测试
  1297. break;
  1298. if (at_cmd_send(npos++, NB_ATE0, NB_ATE0_ACK, 3, 2) == -1) // 关闭回显
  1299. break;
  1300. if (at_cmd_send(npos++, "AT+IPR=9600\r\n", NB_AT_ACK, 3, 2) == -1) // 设置波特率
  1301. break;
  1302. nb_power_on(3);
  1303. rt_thread_mdelay(500);
  1304. if (NbRun.get_imei_flag == 0 || NbRun.get_ccid_flag == 0 || NbRun.get_imsi_flag == 0)
  1305. {
  1306. if (at_cmd_send(npos++, NB_CFUN0, NB_AT_ACK, 3, 3) == -1)
  1307. break;
  1308. rt_thread_mdelay(1000);
  1309. if (at_cmd_send(1, NB_CFUN1, NB_AT_ACK, 3, 3) == -1)
  1310. break;
  1311. rt_thread_mdelay(1200);
  1312. }
  1313. if (NbRun.get_imei_flag == 0) // 读取imei号
  1314. {
  1315. // 读取IMEI号
  1316. if (at_cmd_send(npos++, NB_CGSN, NB_CGSN_ACK, 3, 2) == -1)
  1317. break;
  1318. get_nb_imei_code();
  1319. }
  1320. npos = 5;
  1321. if (at_cmd_send(npos++, NB_CMEE1, NB_CMEE_ACK, 3, 2) == -1) // 错误上报方式 BC800需要
  1322. break;
  1323. retry_time = 0;
  1324. vflag = 1;
  1325. if (NbRun.get_ccid_flag == 0 || NbRun.get_imsi_flag == 0)
  1326. {
  1327. while (at_cmd_send(npos, "AT+CPIN?\r\n", "+CPIN: READY", 3, 3) == -1)
  1328. {
  1329. retry_time++;
  1330. if (retry_time > 3)
  1331. {
  1332. vflag = 0;
  1333. break;
  1334. }
  1335. if (at_cmd_send(npos + 1, NB_CFUN0, NB_AT_ACK, 3, 2) == -1)
  1336. {
  1337. vflag = 0;
  1338. break;
  1339. } // FUN0格式
  1340. rt_thread_mdelay(1000);
  1341. if (at_cmd_send(npos + 2, NB_CFUN1, NB_AT_ACK, 3, 3) == -1) // 设置最大模式,开始搜网
  1342. {
  1343. vflag = 0;
  1344. break;
  1345. }
  1346. rt_thread_mdelay(1200);
  1347. }
  1348. npos += 3;
  1349. if (vflag == 0)
  1350. break;
  1351. if (NbRun.get_ccid_flag == 0) // 读取ccid号
  1352. { // 读取ccid号
  1353. ncnt = 0;
  1354. if (at_cmd_send(npos, NB_NCCID, NB_NCCID_ACK, 3, 2) == -1)
  1355. {
  1356. break;
  1357. }
  1358. get_nb_ccid_code();
  1359. }
  1360. npos++;
  1361. if (NbRun.get_imsi_flag == 0) // 读取imsi号
  1362. { // 读取imsi号
  1363. if (at_cmd_send(npos, NB_CIMI, NB_AT_ACK, 3, 2) == -1)
  1364. break;
  1365. get_nb_imsi_code();
  1366. }
  1367. npos++;
  1368. }
  1369. vflag = 0;
  1370. do
  1371. {
  1372. if (at_cmd_send2(npos, "AT+CEREG?\r\n", "+CEREG: 0,1", "+CREG: 0,5", NB_CREG_WAIT_TIME, 2) != -1) // 首次成功
  1373. // if (at_cmd_send(npos + 2, "AT+CEREG?\r\n", "+CEREG: 0", 20, 2) != -1) // 首次成功
  1374. {
  1375. vflag = 1;
  1376. break;
  1377. }
  1378. if (at_cmd_send(npos + 1, "AT+COPS=2\r\n", NB_AT_ACK, 3, 2) == -1) // 自动选择网络
  1379. break;
  1380. rt_thread_mdelay(1200);
  1381. if (at_cmd_send(npos + 2, "AT+COPS=0\r\n", NB_AT_ACK, 3, 2) == -1) // 自动选择网络
  1382. break;
  1383. rt_thread_mdelay(1000);
  1384. if (at_cmd_send2(npos + 3, "AT+CEREG?\r\n", "+CEREG: 0,1", "+CREG: 0,5", NB_CREG_WAIT_TIME, 2) != -1)
  1385. // if (at_cmd_send(npos + 2, "AT+CEREG?\r\n", "+CEREG: 0", 20, 2) != -1)
  1386. {
  1387. vflag = 1;
  1388. break;
  1389. }
  1390. if (at_cmd_send(npos + 4, NB_CFUN0, NB_AT_ACK, 3, 2) == -1)
  1391. break; // FUN0格式
  1392. rt_thread_mdelay(1000);
  1393. if (at_cmd_send(npos + 5, NB_CFUN1, NB_AT_ACK, 3, 3) == -1) // 设置最大模式,开始搜网
  1394. break;
  1395. rt_thread_mdelay(1200);
  1396. if (at_cmd_send2(npos + 6, "AT+CEREG?\r\n", "+CEREG: 0,1", "+CREG: 0,5", NB_CREG_WAIT_TIME, 2) != -1)
  1397. // if (at_cmd_send(npos + 2, "AT+CEREG?\r\n", "+CEREG: 0", 20, 2) != -1)
  1398. {
  1399. vflag = 1;
  1400. }
  1401. } while (0);
  1402. npos += 7;
  1403. if (vflag == 0)
  1404. break; // 失败后退出的循环
  1405. vflag = 0;
  1406. ncnt = 5;
  1407. vflag = 1;
  1408. while (ncnt--) // 查询无线信号强度 BC800有
  1409. {
  1410. if (at_cmd_send(npos++, "AT+QENG=\"servingcell\"\r\n", "+QENG: \"servingcell\"", 3, 2) == -1)
  1411. {
  1412. vflag = 0;
  1413. break;
  1414. }
  1415. if (get_nb_signal(NbRun.rx_buf, NbRun.rx_idx) == 1)
  1416. break;
  1417. rt_thread_mdelay(1000);
  1418. }
  1419. if (vflag == 0)
  1420. break;
  1421. vflag = 0;
  1422. if (at_cmd_send(npos++, "AT+QICSGP=1,1,\"CTNET\",\"\",\"\",1\r\n", NB_AT_ACK, 3, 2) == -1) // 配置场景
  1423. break;
  1424. if (at_cmd_send(npos++, "AT+QIACT=1\r\n", NB_AT_ACK, 3, 3) == -1) // 激活场景
  1425. break;
  1426. if (at_cmd_send(npos++, "AT+QIACT?\r\n", "+QIACT: 1,1", 3, 3) == -1) // 查询场景激活状态
  1427. break;
  1428. #ifdef NB_AUTO_GET_NET_TIME // 自动获取网络时间
  1429. if ((NbRun.upload.mode & NB_UPLOAD_TIMER) != 0)
  1430. {
  1431. if (at_cmd_send(npos, "AT+QNTP=1,\"202.112.10.36\",123\r\n", "+QNTP: 0,", 1, 15) == 0)
  1432. {
  1433. save_datetime_from_at(NbRun.rx_buf, NbRun.rx_idx);
  1434. LOG("get net time!\t\n");
  1435. }
  1436. }
  1437. #endif
  1438. npos++;
  1439. vflag = 0x80;
  1440. //////////////////////////////////tcp主连接与发送数据////////////////////////////////////////
  1441. if (check_main_service_flag() == 1)
  1442. {
  1443. rec_cmd_handler(npos, PORT_MAIN, &vflag);
  1444. }
  1445. npos += 3;
  1446. ////////////////////////////备用连接/////////////////////////////////////////////////////
  1447. if (check_sub_service_flag() == 1)
  1448. {
  1449. rec_cmd_handler(npos, PORT_SUB, &vflag);
  1450. }
  1451. } while (0); // 主循环
  1452. // NB_RUN_UPDATE_FLAG = 0;
  1453. nb_power_off();
  1454. // #ifdef DEBUG_NB
  1455. // get_rtc_run(&rr);
  1456. // LOG("run_time:20%2d-%2d-%2d:%2d:%2d:%2d fw=%f,bw=%f\r\n", rr->year, rr->month, rr->day, rr->hour, rr->minute, rr->second, BillRun.fw_cum_flow, BillRun.bw_cum_flow); // 锟斤拷示时锟斤拷
  1457. // #endif
  1458. if (vflag & 0x80)
  1459. LOG("no service upload!\r\n");
  1460. else if ((vflag & 3) != 0)
  1461. {
  1462. if ((vflag & BIT0) != 0)
  1463. LOG("MAIN upload ok!\r\n");
  1464. if ((vflag & BIT1) != 0)
  1465. LOG("SUB upload ok!\r\n");
  1466. }
  1467. else if (vflag == 0)
  1468. LOG("upload fail\r\n");
  1469. if ((vflag & 3) != 3 && vflag != 0x80) // 有失败的情况
  1470. { // 上报失败,补报判别
  1471. if (NbRun.upload.mode & ~(NB_UPLOAD_REPT | NB_UPLOAD_DMA | NB_UPLOAD_MANUAL))
  1472. { // 除补报,DMA,手动上报之外,其他需要补报
  1473. upload_dat.rept_runflag = ((~vflag) & 0x3); // 补报
  1474. upload_dat.rept_addr = upload_dat.rept_runflag;
  1475. rtc_run_t *rr;
  1476. get_rtc_run(&rr);
  1477. tm_t ntm;
  1478. ntm.year = rr->year;
  1479. ntm.month = rr->month;
  1480. ntm.day = rr->day;
  1481. ntm.hour = rr->hour;
  1482. ntm.min = rr->minute;
  1483. ntm.sec = rr->second;
  1484. time_add_secs(&upload_dat.rept_time, &ntm, 3600);
  1485. }
  1486. }
  1487. // NbRun.void_load_timout = NB_VOID_UPLOAD_TIME;//这段时间不能上报60s
  1488. NbRun.upload.flag = 0;
  1489. NbRun.upload.mode = 0; // 本次上传结束后清零
  1490. } // while(1)
  1491. }
  1492. /////////////添加上报过程中动态显示信号/////////////////////
  1493. ////////////////////发送at指令并等待处理接收数据//////////////////////////////////////////////////////
  1494. // stat:当前所在流程位置,和每个指令一一对应
  1495. // cmd_str:at指令字符串
  1496. // ack:要求本次回复的字符串
  1497. // retry_time: 重试次数
  1498. // time_out: 超时时间 秒单位
  1499. // 成功:返回0 失败返回-1
  1500. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  1501. int8_t at_cmd_send(uint8_t stat, char *cmd_str, char *ack, uint16_t retry_time, uint8_t time_out)
  1502. {
  1503. uint16_t retry = retry_time;
  1504. uint16_t time_cnt;
  1505. int8_t ret = 0;
  1506. NbRun.cur_state = stat;
  1507. NbRun.ack = ack;
  1508. if (time_out > 250)
  1509. time_out = 250; // 最大不超过25秒
  1510. time_cnt = time_out * 10;
  1511. ////////////
  1512. // retry=250;
  1513. //////////////
  1514. // LOG("nbstat=%d\r\n",stat);
  1515. while (retry--)
  1516. {
  1517. NbClrRxBuf();
  1518. time_cnt = time_out * 10;
  1519. nb_tx_str(cmd_str);
  1520. while (--time_cnt)
  1521. {
  1522. if (Nb_rx_data() == 1)
  1523. {
  1524. // if (stat > COAP_CGATT_QUERY && stat < COAP_WAIT_REG)//EC800 不再需要了
  1525. // {
  1526. // if (memstr_exist(NbRun.rx_buf, NbRun.rx_idx, "+QLWEVTIND:3", 12) == 1)
  1527. // {
  1528. // connected_flag = 1;
  1529. // }
  1530. // }
  1531. //////////////////////////////////////////////
  1532. ret = Nb_check_rec_valid(stat, ack);
  1533. if (ret == 1)
  1534. {
  1535. LOG(".");
  1536. return 0;
  1537. } // 收到正确的回复}
  1538. else if (ret == -1)
  1539. break;
  1540. // else if(ret == 0)continue;
  1541. }
  1542. rt_thread_mdelay(NB_REC_DELAY_TICK); // 等100ms
  1543. }
  1544. if (time_cnt == 0)
  1545. { // 超时未收到数据
  1546. continue;
  1547. }
  1548. if (Nb_check_rec_valid(stat, ack) == TRUE)
  1549. { // 检查是否收到正确回复
  1550. return 0;
  1551. }
  1552. }
  1553. return -1;
  1554. }
  1555. int8_t at_cmd_send2(uint8_t stat, char *cmd_str, char *ack1, char *ack2, uint16_t retry_time, uint8_t time_out)
  1556. {
  1557. uint16_t retry = retry_time;
  1558. uint16_t time_cnt;
  1559. int8_t ret1, ret2;
  1560. NbRun.cur_state = stat;
  1561. NbRun.ack = ack1;
  1562. if (time_out > 250)
  1563. time_out = 250; // 最大不超过25秒
  1564. time_cnt = time_out * 10;
  1565. ////////////
  1566. // retry=250;
  1567. //////////////
  1568. // LOG("nbstat=%d\r\n",stat);
  1569. while (retry--)
  1570. {
  1571. NbClrRxBuf();
  1572. time_cnt = time_out * 10;
  1573. nb_tx_str(cmd_str);
  1574. while (--time_cnt)
  1575. {
  1576. if (Nb_rx_data() == 1)
  1577. {
  1578. ret1 = Nb_check_rec_valid(stat, ack1);
  1579. if (ret1 == 1)
  1580. {
  1581. LOG(".");
  1582. return 0;
  1583. } // 收到正确的回复}
  1584. ret2 = Nb_check_rec_valid(stat, ack2);
  1585. if (ret2 == 1)
  1586. {
  1587. LOG(".");
  1588. return 0;
  1589. } // 收到正确的回复
  1590. if (ret1 == -1 || ret2 == -1)
  1591. break;
  1592. // else if(ret == 0)continue;
  1593. }
  1594. rt_thread_mdelay(NB_REC_DELAY_TICK); // 等100ms
  1595. }
  1596. if (time_cnt == 0)
  1597. { // 超时未收到数据
  1598. continue;
  1599. }
  1600. if (Nb_check_rec_valid(stat, ack1) == TRUE)
  1601. { // 检查是否收到正确回复
  1602. return 0;
  1603. }
  1604. if (Nb_check_rec_valid(stat, ack2) == TRUE)
  1605. { // 检查是否收到正确回复
  1606. return 0;
  1607. }
  1608. }
  1609. return -1;
  1610. }
  1611. static void BuildDataReportMeter(rtc_run_t *rr, uint8_t *data)
  1612. {
  1613. rtc_run_t *max_fr_rr;
  1614. // total positive water
  1615. uint32_t temp = (uint32_t)(FwCumFlow * 0.0001 + 0.5); // unit: 0.01m^3
  1616. data[0] = (uint8_t)temp;
  1617. data[1] = (uint8_t)(temp >> 8);
  1618. data[2] = (uint8_t)(temp >> 16);
  1619. data[3] = (uint8_t)(temp >> 24);
  1620. // total reverse water
  1621. temp = (uint32_t)(BwCumFlow * 0.0001 + 0.5); // unit: 0.01m^3
  1622. data[4] = (uint8_t)temp;
  1623. data[5] = (uint8_t)(temp >> 8);
  1624. data[6] = (uint8_t)(temp >> 16);
  1625. data[7] = (uint8_t)(temp >> 24);
  1626. // Daily maximum flow rate
  1627. temp = (uint32_t)(get_max_flow_rate() * 1000); // 3位小数点
  1628. #ifdef DEBUG_4G_DATA
  1629. temp = 12345;
  1630. #endif
  1631. data[8] = (uint8_t)(temp);
  1632. data[9] = (uint8_t)(temp >> 8);
  1633. data[10] = (uint8_t)(temp >> 16);
  1634. data[11] = (uint8_t)(temp >> 24);
  1635. // Daily maximum flow rate time
  1636. get_max_flow_rate_time(&max_fr_rr);
  1637. if (max_fr_rr == NULL || max_fr_rr->year == 0 || max_fr_rr->month == 0 || max_fr_rr->day == 0)
  1638. memset(&data[12], 0, 7);
  1639. else
  1640. {
  1641. data[12] = 0x14;
  1642. data[13] = max_fr_rr->year;
  1643. data[14] = max_fr_rr->month;
  1644. data[15] = max_fr_rr->day;
  1645. data[16] = max_fr_rr->hour;
  1646. data[17] = max_fr_rr->minute;
  1647. data[18] = max_fr_rr->second;
  1648. }
  1649. #ifdef DEBUG_4G_DATA
  1650. data[12] = 0x14;
  1651. data[13] = 26;
  1652. data[14] = 3;
  1653. data[15] = 31;
  1654. data[16] = 9;
  1655. data[17] = 30;
  1656. data[18] = 45;
  1657. #endif
  1658. // water temperature
  1659. if (WaterTemp > 100.0f || WaterTemp < 0.0f)
  1660. temp = 0x8000; // wxl 2026-5-22
  1661. else
  1662. temp = (uint32_t)(WaterTemp * 10 + 0.5);
  1663. #ifdef DEBUG_4G_DATA
  1664. // temp = -300;
  1665. #endif
  1666. data[19] = (uint8_t)(temp);
  1667. data[20] = (uint8_t)(temp >> 8);
  1668. // water pressure
  1669. if (Paramx.pressure_sensor == 1)
  1670. {
  1671. data[21] = (uint8_t)(WaterPressure * 100);
  1672. }
  1673. else
  1674. data[21] = 0;
  1675. #ifdef DEBUG_NB
  1676. // data[21]=213;
  1677. #endif
  1678. // battery voltage unit: 0.1V
  1679. #if VER_MODULE == 3
  1680. if (McuVbat > McuVTxbat)
  1681. { // 判断哪个电池低就上传哪个数据
  1682. temp = McuVTxbat / 100;
  1683. }
  1684. else
  1685. temp = McuVbat / 100;
  1686. #else
  1687. temp = McuVbat / 100;
  1688. #endif
  1689. data[22] = (unsigned char)temp;
  1690. data[23] = 0x14;
  1691. data[24] = rr->year;
  1692. data[25] = rr->month;
  1693. data[26] = rr->day;
  1694. data[27] = rr->hour;
  1695. data[28] = rr->minute;
  1696. data[29] = rr->second;
  1697. }
  1698. static void BuildDataReportParam(uint8_t *data)
  1699. {
  1700. Param_t *param;
  1701. Nb_Run_t *nb_run;
  1702. GetParam(&param);
  1703. GetNbRun(&nb_run);
  1704. // version
  1705. data[0] = 'V';
  1706. data[1] = VER_TYPE;
  1707. data[2] = VER_OPERATOR;
  1708. data[3] = VER_MODULE;
  1709. data[4] = VER_FIRMWARE;
  1710. // diameter
  1711. data[5] = (unsigned char)(param->diameter);
  1712. data[6] = (unsigned char)(param->diameter >> 8);
  1713. // channel number
  1714. data[7] = param->chan_num;
  1715. // main server ip
  1716. data[8] = param->main_server_ip[0];
  1717. data[9] = param->main_server_ip[1];
  1718. data[10] = param->main_server_ip[2];
  1719. data[11] = param->main_server_ip[3];
  1720. // main server port
  1721. data[12] = (unsigned char)(param->main_server_port);
  1722. data[13] = (unsigned char)(param->main_server_port >> 8);
  1723. // sub server ip
  1724. data[14] = param->sub_server_ip[0];
  1725. data[15] = param->sub_server_ip[1];
  1726. data[16] = param->sub_server_ip[2];
  1727. data[17] = param->sub_server_ip[3];
  1728. // sub server port
  1729. data[18] = (unsigned char)(param->sub_server_port);
  1730. data[19] = (unsigned char)(param->sub_server_port >> 8);
  1731. // report base time
  1732. data[20] = param->report_base_hour;
  1733. data[21] = param->report_base_min;
  1734. data[22] = param->report_base_sec;
  1735. // report interval minutes
  1736. data[23] = (unsigned char)(param->report_interval);
  1737. data[24] = (unsigned char)(param->report_interval >> 8);
  1738. // DMA report start time
  1739. data[25] = param->dma_report_start[0];
  1740. data[26] = param->dma_report_start[1];
  1741. data[27] = param->dma_report_start[2];
  1742. // DMA report end time
  1743. data[28] = param->dma_report_end[0];
  1744. data[29] = param->dma_report_end[1];
  1745. data[30] = param->dma_report_end[2];
  1746. // DMA report interval time
  1747. data[31] = param->dma_interval;
  1748. // settlement day
  1749. data[32] = param->settlement_day;
  1750. // high temperature alarm threshold
  1751. data[33] = (unsigned char)(param->high_temp_alarm_thres);
  1752. data[34] = (unsigned char)(param->high_temp_alarm_thres >> 8);
  1753. // low temperature alarm threshold
  1754. data[35] = (unsigned char)(param->low_temp_alarm_thres);
  1755. data[36] = (unsigned char)(param->low_temp_alarm_thres >> 8);
  1756. // large flow alarm threshold
  1757. data[37] = (unsigned char)(param->large_flow_alarm_thres);
  1758. data[38] = (unsigned char)(param->large_flow_alarm_thres >> 8);
  1759. data[39] = (unsigned char)(param->large_flow_alarm_thres >> 16);
  1760. data[40] = (unsigned char)(param->large_flow_alarm_thres >> 24);
  1761. // large flow continue monitor time
  1762. data[41] = (unsigned char)(param->large_flow_cnti_moni_time);
  1763. data[42] = (unsigned char)(param->large_flow_cnti_moni_time >> 8);
  1764. // continue flow continue monitor time
  1765. data[43] = (unsigned char)(param->cnti_flow_cnti_moni_time);
  1766. data[44] = (unsigned char)(param->cnti_flow_cnti_moni_time >> 8);
  1767. // leak flow alarm threshold
  1768. data[45] = (unsigned char)(param->leak_flow_alarm_thres);
  1769. data[46] = (unsigned char)(param->leak_flow_alarm_thres >> 8);
  1770. data[47] = (unsigned char)(param->leak_flow_alarm_thres >> 16);
  1771. data[48] = (unsigned char)(param->leak_flow_alarm_thres >> 24);
  1772. // leak flow continue monitor time
  1773. data[49] = (unsigned char)(param->leak_flow_cnti_moni_time);
  1774. data[50] = (unsigned char)(param->leak_flow_cnti_moni_time >> 8);
  1775. // high press alarm threshold
  1776. data[51] = (unsigned char)(param->high_press_alarm_thres);
  1777. // low press alarm threshold
  1778. data[52] = (unsigned char)(param->low_press_alarm_thres);
  1779. // pressure sensor
  1780. data[53] = param->pressure_sensor;
  1781. }
  1782. static void BuildDataReportNb(uint8_t *data)
  1783. {
  1784. Nb_Run_t *nb_run;
  1785. char tmp[3];
  1786. uint16_t i;
  1787. GetNbRun(&nb_run);
  1788. // IMEI len = 8
  1789. if (strlen(nb_run->imei) == 15)
  1790. {
  1791. tmp[0] = '0';
  1792. tmp[1] = nb_run->imei[0];
  1793. tmp[2] = 0;
  1794. StrToHexBuf((char *)&data[0], tmp, 2);
  1795. StrToHexBuf((char *)&data[1], &(nb_run->imei[1]), 14);
  1796. }
  1797. else
  1798. {
  1799. StrToHexBuf((char *)&data[0], tmp, 16);
  1800. }
  1801. // cell id in AT+NUESTATS response
  1802. data[8] = (unsigned char)(nb_run->bts_id);
  1803. data[9] = (unsigned char)(nb_run->bts_id >> 8);
  1804. data[10] = (unsigned char)(nb_run->bts_id >> 16);
  1805. data[11] = (unsigned char)(nb_run->bts_id >> 24);
  1806. // physical cell id
  1807. data[12] = (unsigned char)(nb_run->physical_cell_id);
  1808. data[13] = (unsigned char)(nb_run->physical_cell_id >> 8);
  1809. // rsrp
  1810. data[14] = (unsigned char)(nb_run->rsrp_bak);
  1811. data[15] = (unsigned char)(nb_run->rsrp_bak >> 8);
  1812. // snr
  1813. data[16] = (unsigned char)(nb_run->snr);
  1814. data[17] = (unsigned char)(nb_run->snr >> 8);
  1815. // csq
  1816. data[18] = nb_run->rssi;
  1817. // iccid len = 10
  1818. for (i = 0; i < 10; i++)
  1819. { // 这里是不是错了
  1820. data[19 + i] = (unsigned char)(((nb_run->ccid[2 * i] - '0') << 4) | (nb_run->ccid[2 * i + 1] - '0'));
  1821. }
  1822. }
  1823. static void BuildMonthRecord(rtc_run_t *rr, uint8_t *data)
  1824. {
  1825. uint32_t date = ((rr->year << 16) | (rr->month << 8));
  1826. uint16_t i;
  1827. bill_t bill;
  1828. uint8_t vflag;
  1829. for (i = 0; i < 2; i++)
  1830. {
  1831. date = prev_month(date);
  1832. vflag = get_month_used_bill((uint8_t)(date >> 16), (uint8_t)(date >> 8), &bill);
  1833. if (vflag != 0)
  1834. continue; // no data
  1835. data[i * 11] = 0x14;
  1836. data[i * 11 + 1] = bill.date[0];
  1837. data[i * 11 + 2] = bill.date[1];
  1838. data[i * 11 + 3] = (unsigned char)(bill.fw_used);
  1839. data[i * 11 + 4] = (unsigned char)(bill.fw_used >> 8);
  1840. data[i * 11 + 5] = (unsigned char)(bill.fw_used >> 16);
  1841. data[i * 11 + 6] = (unsigned char)(bill.fw_used >> 24);
  1842. data[i * 11 + 7] = (unsigned char)(bill.bw_used);
  1843. data[i * 11 + 8] = (unsigned char)(bill.bw_used >> 8);
  1844. data[i * 11 + 9] = (unsigned char)(bill.bw_used >> 16);
  1845. data[i * 11 + 10] = (unsigned char)(bill.bw_used >> 24);
  1846. }
  1847. }
  1848. static void BuildDayRecord(rtc_run_t *rr, uint8_t *data)
  1849. {
  1850. uint16_t i;
  1851. bill_t bill;
  1852. uint32_t date = ((rr->year << 16) | (rr->month << 8) | rr->day);
  1853. uint8_t vflag;
  1854. for (i = 0; i < 5; i++)
  1855. {
  1856. date = prev_day(date);
  1857. vflag = get_day_used_bill((uint8_t)(date >> 16), (uint8_t)(date >> 8), (uint8_t)date, &bill);
  1858. if (vflag != 0)
  1859. continue; // no data
  1860. // if (bill.date[0] != (uint8_t)(date >> 16) || bill.date[1] != (uint8_t)(date >> 8) || bill.date[2] != (uint8_t)date)
  1861. // continue; // 不是当天的数据
  1862. data[i * 12] = 0x14;
  1863. data[i * 12 + 1] = bill.date[0];
  1864. data[i * 12 + 2] = bill.date[1];
  1865. data[i * 12 + 3] = bill.date[2];
  1866. data[i * 12 + 4] = (unsigned char)(bill.fw_used);
  1867. data[i * 12 + 5] = (unsigned char)(bill.fw_used >> 8);
  1868. data[i * 12 + 6] = (unsigned char)(bill.fw_used >> 16);
  1869. data[i * 12 + 7] = (unsigned char)(bill.fw_used >> 24);
  1870. data[i * 12 + 8] = (unsigned char)(bill.bw_used);
  1871. data[i * 12 + 9] = (unsigned char)(bill.bw_used >> 8);
  1872. data[i * 12 + 10] = (unsigned char)(bill.bw_used >> 16);
  1873. data[i * 12 + 11] = (unsigned char)(bill.bw_used >> 24);
  1874. }
  1875. }
  1876. static void BuildHourRecord(rtc_run_t *rr, uint8_t *data)
  1877. {
  1878. uint8_t i;
  1879. hour_bill_t bill;
  1880. uint8_t vflag;
  1881. uint32_t date = ((rr->year << 16) | (rr->month << 8) | rr->day);
  1882. date = prev_day(date);
  1883. data[0] = 0x14;
  1884. data[1] = (unsigned char)(date >> 16);
  1885. data[2] = (unsigned char)(date >> 8);
  1886. data[3] = (unsigned char)(date);
  1887. for (i = 0; i < 24; i++)
  1888. {
  1889. vflag = get_hour_used_bill(data[1], data[2], data[3], i, &bill);
  1890. if (vflag != 0) // 数据不合法,放弃
  1891. continue;
  1892. memcpy(&data[4 + i * 3], bill.fw_used, 3);
  1893. memcpy(&data[4 + 72 + i * 3], bill.bw_used, 3);
  1894. #ifdef DEBUG_4G_DATA
  1895. bill.pressure = 102;
  1896. *(uint16_t *)bill.flow_rate = 12345;
  1897. bill.flow_rate[2] = 0;
  1898. #endif
  1899. data[4 + 144 + i] = bill.pressure;
  1900. memcpy(&data[4 + 168 + i * 3], bill.flow_rate, 3);
  1901. }
  1902. }
  1903. void NbBuildDataReport(void)
  1904. {
  1905. rtc_run_t *rr;
  1906. Nb_Run_t *nb_run;
  1907. uint16_t data_len = 448;
  1908. uint32_t *err_no;
  1909. // current date time
  1910. get_rtc_run(&rr);
  1911. GetNbRun(&nb_run);
  1912. NbBuildDataHeader(data_len);
  1913. // AFN
  1914. NbAppFrame.data[0] = 0x10;
  1915. NbAppFrame.data[1] = 0x00;
  1916. // MID
  1917. NbAppFrame.data[2] = 0x00;
  1918. NbAppFrame.data[3] = 0x00;
  1919. // DC
  1920. // report trigger mode
  1921. NbAppFrame.data[4] = nb_run->upload.mode;
  1922. BuildDataReportMeter(rr, &NbAppFrame.data[5]); // meter part len 30
  1923. BuildDataReportParam(&NbAppFrame.data[35]); // param part len 54
  1924. BuildDataReportNb(&NbAppFrame.data[89]); // nb part len 29
  1925. BuildMonthRecord(rr, &NbAppFrame.data[118]); // month record part len 22
  1926. BuildDayRecord(rr, &NbAppFrame.data[140]); // day record part len 60
  1927. BuildHourRecord(rr, &NbAppFrame.data[200]); // day record part len 244
  1928. // error no
  1929. all_alarm_status(&err_no);
  1930. //(*err_no) &= 0xffff0fff;
  1931. NbAppFrame.data[444] = (uint8_t)(*err_no);
  1932. NbAppFrame.data[445] = (uint8_t)(*err_no >> 8);
  1933. NbAppFrame.data[446] = (uint8_t)(*err_no >> 16);
  1934. NbAppFrame.data[447] = (uint8_t)(*err_no >> 24);
  1935. NbBuildDataTail(data_len);
  1936. }
  1937. void nb_set_para_rept(uint16_t dat_len, uint16_t afn, int8_t ret)
  1938. {
  1939. // uint16_t data_len = 5;
  1940. // uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  1941. NbBuildDataHeader(dat_len);
  1942. // AFN
  1943. NbAppFrame.data[0] = (uint8_t)afn;
  1944. NbAppFrame.data[1] = (uint8_t)(afn >> 8);
  1945. // MID
  1946. // NbAppFrame.data[2] = (uint8_t)(mid);
  1947. // NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  1948. NbAppFrame.data[4] = ret; // set success
  1949. NbBuildDataTail(dat_len);
  1950. }
  1951. void NbBuildReportMonthRecord(void)
  1952. {
  1953. uint16_t data_len = 202;
  1954. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  1955. uint8_t ret;
  1956. // rtc_run_t *rr;
  1957. // get_rtc_run(&rr);
  1958. NbBuildDataHeader(data_len);
  1959. // AFN
  1960. NbAppFrame.data[0] = 0x31;
  1961. NbAppFrame.data[1] = 0x00;
  1962. // MID
  1963. NbAppFrame.data[2] = (uint8_t)(mid);
  1964. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  1965. uint8_t *data = &NbAppFrame.data[4];
  1966. get_18month_record_data(data);
  1967. NbBuildDataTail(data_len);
  1968. }
  1969. void NbBuildReportDayRecord(void)
  1970. {
  1971. uint16_t data_len = 364;
  1972. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  1973. uint8_t ret;
  1974. NbBuildDataHeader(data_len);
  1975. // AFN
  1976. NbAppFrame.data[0] = 0x33;
  1977. NbAppFrame.data[1] = 0x00;
  1978. // MID
  1979. NbAppFrame.data[2] = (uint8_t)(mid);
  1980. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  1981. uint8_t *data = &NbAppFrame.data[4];
  1982. get_30day_record_data(data);
  1983. NbBuildDataTail(data_len);
  1984. }
  1985. void NbBuildReportHourRecord(uint8_t year, uint8_t month, uint8_t day)
  1986. {
  1987. uint16_t data_len = 248;
  1988. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  1989. // rtc_run_t *rr;
  1990. // get_rtc_run(&rr);
  1991. NbBuildDataHeader(data_len);
  1992. // AFN
  1993. NbAppFrame.data[0] = 0x35;
  1994. NbAppFrame.data[1] = 0x00;
  1995. // MID
  1996. NbAppFrame.data[2] = (uint8_t)(mid);
  1997. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  1998. uint8_t *data = &NbAppFrame.data[4];
  1999. get_hour_record_data(year, month, day, data);
  2000. NbBuildDataTail(data_len);
  2001. }
  2002. void NbBuildReport5MinRecord(tm_t *date)
  2003. { // 年月日时分
  2004. uint16_t data_len = 388;
  2005. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  2006. uint32_t i = 0;
  2007. uint8_t ret;
  2008. hour_bill_t bill;
  2009. tm_t src;
  2010. tm_t dest;
  2011. NbBuildDataHeader(data_len);
  2012. memset(NbAppFrame.data, 0, sizeof(NbAppFrame.data));
  2013. // AFN
  2014. NbAppFrame.data[0] = 0x37;
  2015. NbAppFrame.data[1] = 0x00;
  2016. // MID
  2017. NbAppFrame.data[2] = (uint8_t)(mid);
  2018. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  2019. uint8_t *data = &NbAppFrame.data[4];
  2020. GET_5MIN_REOCORD_DEF mdate;
  2021. mdate.start_time[0] = date->year;
  2022. mdate.start_time[1] = date->month;
  2023. mdate.start_time[2] = date->day;
  2024. mdate.start_time[3] = date->hour;
  2025. mdate.start_time[4] = date->min;
  2026. mdate.start_time[5] = date->sec;
  2027. time_add_secs(&dest, date, 2 * 3600);
  2028. mdate.end_time[0] = dest.year;
  2029. mdate.end_time[1] = dest.month;
  2030. mdate.end_time[2] = dest.day;
  2031. mdate.end_time[3] = dest.hour;
  2032. mdate.end_time[4] = dest.min;
  2033. mdate.end_time[5] = dest.sec;
  2034. get_5min_record_data(&mdate, 0, data);
  2035. NbBuildDataTail(data_len);
  2036. }
  2037. void NbBuildReportLogRecord(void)
  2038. {
  2039. uint16_t data_len = 394;
  2040. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  2041. uint8_t i;
  2042. int8_t j;
  2043. uint8_t num = 0;
  2044. alarm_t alarm;
  2045. uint8_t rec_len = 13;
  2046. NbBuildDataHeader(data_len);
  2047. // AFN
  2048. NbAppFrame.data[0] = 0x39;
  2049. NbAppFrame.data[1] = 0x00;
  2050. // MID
  2051. NbAppFrame.data[2] = (uint8_t)(mid);
  2052. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  2053. uint8_t *data = &NbAppFrame.data[4];
  2054. num = get_alarm_num();
  2055. if (num > 30)
  2056. {
  2057. num = 30;
  2058. }
  2059. get_log_record(0, num, data);
  2060. NbBuildDataTail(data_len);
  2061. }
  2062. void NbBuildGetPackage(void)
  2063. {
  2064. uint16_t data_len = 21;
  2065. uint16_t mid = (NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  2066. Param_t *param;
  2067. NbBuildDataHeader(data_len);
  2068. // AFN
  2069. NbAppFrame.data[0] = 0x51;
  2070. NbAppFrame.data[1] = 0x00;
  2071. // MID
  2072. NbAppFrame.data[2] = (uint8_t)(mid);
  2073. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  2074. GetParam(&param);
  2075. uint8_t *data = &NbAppFrame.data[4];
  2076. data[0] = 'V';
  2077. data[1] = VER_TYPE;
  2078. data[2] = VER_OPERATOR;
  2079. data[3] = VER_MODULE;
  2080. data[4] = VER_FIRMWARE;
  2081. data[5] = 'V';
  2082. data[6] = VER_TYPE;
  2083. data[7] = VER_OPERATOR;
  2084. data[8] = VER_MODULE;
  2085. data[9] = VER_FIRMWARE + 1;
  2086. data[10] = (uint8_t)(PatchInfo.per_packet_len);
  2087. data[11] = (uint8_t)(PatchInfo.per_packet_len >> 8);
  2088. data[12] = (uint8_t)(PatchInfo.cur_num);
  2089. data[13] = (uint8_t)(PatchInfo.cur_num >> 8);
  2090. data[14] = (uint8_t)(PatchInfo.packet_crc);
  2091. data[15] = (uint8_t)(PatchInfo.packet_crc >> 8);
  2092. data[16] = 1;
  2093. NbBuildDataTail(data_len);
  2094. }
  2095. void NbBuildReportUpdateStatus(int8_t stat)
  2096. {
  2097. uint16_t data_len = 5;
  2098. uint16_t mid = NbRun.mid; //(NbAppFrame.data[3] << 8) | NbAppFrame.data[2];
  2099. Param_t *param;
  2100. NbBuildDataHeader(data_len);
  2101. // AFN
  2102. NbAppFrame.data[0] = 0x52;
  2103. NbAppFrame.data[1] = 0x00;
  2104. // MID
  2105. NbAppFrame.data[2] = (uint8_t)(mid);
  2106. NbAppFrame.data[3] = (uint8_t)(mid >> 8);
  2107. NbAppFrame.data[4] = stat;
  2108. NbBuildDataTail(data_len);
  2109. }
  2110. #ifdef DEBUG_LOG_WARM
  2111. void Debug_log(void)
  2112. {
  2113. // #ifdef DEBUG_NB
  2114. uint8_t i;
  2115. for (i = 0; i < 32; i++)
  2116. {
  2117. write_alarm(i / 2, i % 2, i * 10 + 10);
  2118. }
  2119. // #endif
  2120. }
  2121. #endif
  2122. #ifdef APP_DEBUG_PRINT
  2123. static char str[50];
  2124. char *get_upload_type_str(uint8_t type)
  2125. {
  2126. char cnt = 0;
  2127. memset(str, 0, 50);
  2128. if (type & 0x1)
  2129. strcat(str, "manual,");
  2130. if (type & 0x2)
  2131. strcat(str, "regular,");
  2132. if (type & 0x4)
  2133. strcat(str, "rept,");
  2134. if (type & 0x8)
  2135. strcat(str, "settlement,");
  2136. if (type & 0x10)
  2137. strcat(str, "error,");
  2138. if (type & 0x20)
  2139. strcat(str, "dma");
  2140. return str;
  2141. }
  2142. #endif
  2143. uint8_t memstr_exist(uint8_t *hay, size_t hay_len, const char *sub, size_t sub_len)
  2144. {
  2145. if (sub_len == 0)
  2146. return 1;
  2147. if (sub_len > hay_len)
  2148. return 0;
  2149. for (size_t i = 0; i <= hay_len - sub_len; i++)
  2150. {
  2151. if (memcmp(hay + i, sub, sub_len) == 0)
  2152. {
  2153. return 1;
  2154. }
  2155. }
  2156. return 0;
  2157. }
  2158. int8_t get_code(uint8_t *buf, const char *keyword, uint16_t dat_len, int16_t *ret)
  2159. {
  2160. char *pos;
  2161. buf[dat_len] = 0;
  2162. pos = strstr((char *)buf, keyword);
  2163. if (pos == NULL)
  2164. return -1;
  2165. uint16_t dat = 0;
  2166. uint16_t i;
  2167. char vflag;
  2168. pos = pos + strlen(keyword);
  2169. vflag = 0;
  2170. uint8_t flag = 0;
  2171. if (*pos == '+' || *pos == '-')
  2172. {
  2173. if (*pos == '-')
  2174. flag = 1;
  2175. pos++;
  2176. }
  2177. while (*pos >= '0' && *pos <= '9')
  2178. {
  2179. dat *= 10;
  2180. dat += *pos - '0';
  2181. pos++;
  2182. vflag = 1;
  2183. }
  2184. if (vflag == 0)
  2185. return -1;
  2186. if (flag == 1)
  2187. dat = -dat;
  2188. *ret = dat;
  2189. return 1;
  2190. }
  2191. #ifdef NB_AUTO_GET_NET_TIME // 自动获取网络时间
  2192. //+QNTP: 0,"2019/09/09,01:32:42+32"
  2193. void save_datetime_from_at(uint8_t *buf, uint16_t dat_len)
  2194. {
  2195. tm_t tm;
  2196. int16_t zone = 0;
  2197. char *p;
  2198. buf[dat_len] = 0; // 确保字符串终止
  2199. p = strstr((char *)buf, "\""); // 定位到双引号开始处
  2200. if (p == NULL)
  2201. return;
  2202. // 利用 sscanf 直接格式化提取年月日时分秒和时区
  2203. // 格式: 2019/09/09,01:32:42+32
  2204. if (sscanf(p + 1, "%hu/%hu/%hu,%u:%u:%u%hd",
  2205. &tm.year, &tm.month, &tm.day,
  2206. &tm.hour, &tm.min, &tm.sec, &zone) != 7)
  2207. {
  2208. return; // 解析失败或格式不匹配
  2209. }
  2210. // 合法性检查
  2211. if (tm.year < 26 || tm.month == 0 || tm.month > 12 ||
  2212. tm.day == 0 || tm.day > 31 || tm.hour > 23 || tm.min > 59 || tm.sec > 59)
  2213. return;
  2214. // 时区转换 (保留原逻辑:正负时区分别调用不同的时间计算函数)
  2215. if (zone > 0)
  2216. {
  2217. time_add_secs(&tm, &tm, zone * 15 * 60);
  2218. }
  2219. else if (zone < 0) // 增加非零判断,避免对0进行无意义的减法
  2220. {
  2221. time_sub_secs(&tm, &tm, -zone * 15 * 60); // 传入正数
  2222. }
  2223. tm.year %= 100;
  2224. SetRtcTime(&tm);
  2225. save_cur_flow_flag = 1;
  2226. }
  2227. #endif
  2228. //+QENG: "servingcell","NOCONN","LTE","FDD",460,11,EA6CE03,77,100,1,5,5,EA15,-94,-8,-66,24,26
  2229. // rsrp rwrq rssi sinr
  2230. uint8_t get_nb_signal(uint8_t *buf, uint16_t dat_len)
  2231. {
  2232. // 确保数据包含预期的关键字
  2233. if (buf == NULL || strstr((char *)buf, "+QENG: \"servingcell\"") == NULL)
  2234. {
  2235. return 0;
  2236. }
  2237. if (dat_len > 200)
  2238. return 0;
  2239. char temp[200] = {0};
  2240. memcpy(temp, buf, dat_len);
  2241. char *token = NULL;
  2242. char *tokens[20]; // 足足够容纳所有分割的子字符串
  2243. int count = 0;
  2244. // 使用 strtok 按逗号分割字符串
  2245. token = strtok(temp, ",");
  2246. while (token != NULL && count < 20)
  2247. {
  2248. tokens[count++] = token;
  2249. token = strtok(NULL, ",");
  2250. }
  2251. // 根据您提供的格式,各字段在分割后的索引如下:
  2252. // [0] +QENG: "servingcell"
  2253. // [1] "NOCONN"
  2254. // [2] "LTE"
  2255. // [3] "FDD"
  2256. // [4] 460
  2257. // [5] 11
  2258. // [6] 9C8C712 -> 基站id (需转为uint32_t)
  2259. // [7] 119 -> 物理小区id
  2260. // [8] 2452
  2261. // [9] 5
  2262. // [10] 3
  2263. // [11] 3
  2264. // [12] EA15
  2265. // [13] -85 -> 参考信号接收功率
  2266. // [14] -15 -> 参考信号接收质量
  2267. // [15] -53 -> 接收信号强度指示
  2268. // [16] 0 -> SINR (有效范围 -20~40)
  2269. // 确保分割出的字段数量足够
  2270. if (count > 16)
  2271. {
  2272. // 基站id是16进制字符串,使用 strtoul 转换为 32位无符号数
  2273. NbRun.bts_id = (uint32_t)strtoul(tokens[6], NULL, 16);
  2274. // 物理小区id是10进制数
  2275. NbRun.physical_cell_id = (uint32_t)atoi(tokens[7]);
  2276. // 参考信号接收功率
  2277. NbRun.rsrp_bak = atoi(tokens[13]);
  2278. // 参考信号接收质量
  2279. NbRun.rsrq = atoi(tokens[14]);
  2280. // 接收信号强度指示
  2281. NbRun.rssi = atoi(tokens[15]);
  2282. // SINR
  2283. NbRun.snr = atoi(tokens[16]);
  2284. return 1;
  2285. }
  2286. return 0;
  2287. }
  2288. uint8_t check_sub_service_flag(void)
  2289. {
  2290. uint8_t vflag;
  2291. vflag = 1;
  2292. if (Paramx.main_server_ip[0] == Paramx.sub_server_ip[0] && Paramx.main_server_ip[1] == Paramx.sub_server_ip[1] && Paramx.main_server_ip[2] == Paramx.sub_server_ip[2] && Paramx.main_server_ip[3] == Paramx.sub_server_ip[3] && Paramx.main_server_port == Paramx.sub_server_port)
  2293. {
  2294. vflag = 0;
  2295. } // 主从ip相同,端口号相同
  2296. if (Paramx.sub_server_ip[0] == 0 || Paramx.sub_server_port == 0) // 从ip为空,端口号为空
  2297. {
  2298. vflag = 0;
  2299. }
  2300. return vflag;
  2301. }
  2302. uint8_t check_main_service_flag(void)
  2303. {
  2304. uint8_t vflag;
  2305. vflag = 1;
  2306. if (Paramx.main_server_ip[0] == 0 || Paramx.main_server_port == 0) // 从ip为空,端口号为空
  2307. {
  2308. vflag = 0;
  2309. }
  2310. return vflag;
  2311. }
  2312. /**
  2313. * @brief 极简的无符号整型转字符串函数 (替代 itoa,减少对 stdlib 的依赖)
  2314. * @param value 待转换的数值
  2315. * @param str 转换后的字符串缓冲区 (需保证至少6字节空间)
  2316. * @return 指向字符串缓冲区的指针
  2317. */
  2318. static char *uint_to_str(uint16_t value, char *str)
  2319. {
  2320. char buf[6];
  2321. uint8_t i = 0;
  2322. if (value == 0)
  2323. {
  2324. str[0] = '0';
  2325. str[1] = '\0';
  2326. return str;
  2327. }
  2328. while (value > 0)
  2329. {
  2330. buf[i++] = (value % 10) + '0';
  2331. value /= 10;
  2332. }
  2333. uint8_t len = i;
  2334. for (uint8_t j = 0; j < len; j++)
  2335. {
  2336. str[j] = buf[len - 1 - j];
  2337. }
  2338. str[len] = '\0';
  2339. return str;
  2340. }
  2341. /**
  2342. * @brief 构建 NB-IoT TCP 连接的 AT 指令 (替代 sprintf,大幅减少代码量)
  2343. * @param out_str 输出的指令字符串缓冲区
  2344. * @param ip 4字节IP地址数组
  2345. * @param port 端口号
  2346. */
  2347. void build_tcp_open_cmd(char *out_str, uint8_t *ip, uint16_t port)
  2348. {
  2349. char num_buf[6];
  2350. strcpy(out_str, "AT+QIOPEN=1,0,\"TCP\",\"");
  2351. uint_to_str(ip[0], num_buf);
  2352. strcat(out_str, num_buf);
  2353. strcat(out_str, ".");
  2354. uint_to_str(ip[1], num_buf);
  2355. strcat(out_str, num_buf);
  2356. strcat(out_str, ".");
  2357. uint_to_str(ip[2], num_buf);
  2358. strcat(out_str, num_buf);
  2359. strcat(out_str, ".");
  2360. uint_to_str(ip[3], num_buf);
  2361. strcat(out_str, num_buf);
  2362. strcat(out_str, "\",");
  2363. uint_to_str(port, num_buf);
  2364. strcat(out_str, num_buf);
  2365. strcat(out_str, ",0,0\r\n");
  2366. }
  2367. int8_t get_ta_id(void)
  2368. {
  2369. NbRun.rx_buf[NbRun.rx_idx] = 0;
  2370. if (strstr((char *)NbRun.rx_buf, "EC800Z") != NULL)
  2371. return TA_ID_EC800Z_CN;
  2372. else if (strstr((char *)NbRun.rx_buf, "EG800Z") != NULL)
  2373. return TA_ID_EG800Z_EU;
  2374. return -1;
  2375. }
  2376. // port ==0 main
  2377. // port ==1 sub
  2378. void rec_cmd_handler(uint8_t npos, uint8_t mport, uint8_t *vflag)
  2379. {
  2380. uint8_t *ip;
  2381. uint16_t port_num;
  2382. int16_t link_code;
  2383. char ncdp_str[64];
  2384. int8_t ret, retry_time;
  2385. *vflag &= 0x0f; // 已启动上报,清除BIT7
  2386. #ifdef APP_DEBUG_PRINT
  2387. if (mport == PORT_MAIN)
  2388. LOG("main service upload\r\n");
  2389. else
  2390. LOG("sub service upload\r\n");
  2391. #endif
  2392. do
  2393. {
  2394. if (mport == PORT_MAIN)
  2395. {
  2396. ip = Paramx.main_server_ip;
  2397. port_num = Paramx.main_server_port;
  2398. }
  2399. else
  2400. {
  2401. ip = Paramx.sub_server_ip;
  2402. port_num = Paramx.sub_server_port;
  2403. }
  2404. build_tcp_open_cmd(ncdp_str, ip, port_num); // 字符串生成
  2405. if (at_cmd_send(npos, ncdp_str, "+QIOPEN: 0,", 2, 10) == -1) // 建立TCP连接,等待连接成功
  2406. break;
  2407. if (get_code(NbRun.rx_buf, "+QIOPEN: 0,", NbRun.rx_idx, &link_code) == -1)
  2408. break;
  2409. if (link_code != 0) // 连接失败
  2410. break;
  2411. nb_upload_data_ready(); // 准备上报数据
  2412. rt_thread_mdelay(100); // 准备上报数据
  2413. if (at_cmd_send(npos + 1, (char *)NbRun.tx_buf, "SEND OK", 3, 3) == -1) // 发送上报数据
  2414. break;
  2415. *vflag |= mport; // 上报成功标志
  2416. retry_time = WAIT_CMD_DELAY_TIME * 10; // 12秒
  2417. NbRun.cur_afn = 0;
  2418. //////////////////////////////////////
  2419. while (retry_time--)
  2420. {
  2421. ret = rec_data_check();
  2422. rt_thread_mdelay(100);
  2423. if (ret == 0)
  2424. retry_time = WAIT_CMD_DELAY_TIME * 10; // 判断接收数据是否合法,以及读取协议层afn和长度,并回复
  2425. else if (ret == 2)
  2426. break;
  2427. }
  2428. } while (0);
  2429. at_cmd_send(npos + 2, "AT+QICLOSE=0\r\n", NB_AT_ACK, 3, 3); // 关闭tcpLINK
  2430. }