Cellular.c 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748
  1. #include <time.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <termios.h>
  8. #include <errno.h>
  9. #include "cJSON.h"
  10. #include "json_handle.h"
  11. #include "websocket_handle.h"
  12. #include "common.h"
  13. #include "sys.h"
  14. #include "Cellular.h"
  15. #include <pthread.h>
  16. #include "thread.h"
  17. #include "paras.h"
  18. #include "lock.h"
  19. #include "elog.h"
  20. #include "cfg.h"
  21. #include "sqlite_handle.h"
  22. #if 0
  23. #define LOGE log_e
  24. #define LOGW log_w
  25. #define LOGD log_d
  26. #else
  27. #define LOGD printf
  28. #define LOGW printf
  29. #define LOGE printf
  30. #endif
  31. #define RETRY_TIMES 1
  32. #define BUF_LEN 2000
  33. #define AT_PORT "/dev/ttyUSB1"
  34. #define BAUD_RATE B115200
  35. #define QUERY_INTERVAL 1000 // 查询间隔,毫秒
  36. #define RSSI_DBM_MIN1 -113 // LTE、HSDPA网络最小信号值,对应RSSI值范围0-57
  37. #define RSSI_DBM_MIN2 -116 // TD-SCDMA网络最小信号值,对应RSSI值范围100-199
  38. #define CONTEXT_ID "1" //1~15
  39. #define CONNECT_ID "0" //0~11
  40. #define CONNECT_TIMEOUT "5"
  41. #define CHUNCK_SIZE 1460
  42. #define MQTT_VER 4 //3: v3.1 4: v3.1.1
  43. #define MQTT_WILL 0
  44. #define MQTT_RETAIN 0
  45. #define MQTT_MAX 6
  46. #define MQTT_QOS 2
  47. #define MQTT_CHUNCK_SIZE 1500
  48. #define SMS_SEND_MAX 500
  49. #define UNLINK_MAX 3
  50. #define MAX_CONNECTIONS 6 // EC200N最多支持6个连接
  51. int UnLinkCount=0;
  52. enum {
  53. AT_OK=0,
  54. AT_ERR,
  55. AT_TOUT,
  56. };
  57. enum {
  58. AT_STAT_UNINIT=0,
  59. AT_STAT_INITED,
  60. };
  61. enum {
  62. SOCK_TCP=0,
  63. SOCK_UDP,
  64. };
  65. enum {
  66. URC_SOCK=0,
  67. URC_MQTT,
  68. URC_GNSS,
  69. URC_NTP,
  70. URC_SMS,
  71. URC_CALL,
  72. URC_ERR,
  73. };
  74. typedef int (*urc_fn_t)(int urc, void *data, int len);
  75. typedef struct {
  76. int cmd;
  77. char para[100];
  78. }at_para_t;
  79. typedef struct {
  80. char *cmd;
  81. char *ok;
  82. char *err;
  83. int timeout; //ms
  84. }at_cmd_t;
  85. typedef struct {
  86. int cmd;
  87. char *buf;
  88. int dlen;
  89. int blen;
  90. }at_buf_t;
  91. typedef struct {
  92. at_buf_t rx;
  93. at_buf_t tx;
  94. }at_data_t;
  95. typedef struct {
  96. void *h;
  97. int sock;
  98. int cont_id; //1~15
  99. int cont_type; //1:ipv4 2:ipv6 3:ipv4+ipv6
  100. int conn_id;
  101. char apn[64];
  102. char username[128];
  103. char password[128];
  104. int authentication; //0:none 1:PAP 2:CHAP 3:PAP OR CHAP
  105. int cdma_pwd; //0:no save 1:save
  106. }sock_conn_t;
  107. typedef struct {
  108. char host[100];
  109. uint16_t port;
  110. char username[64];
  111. char password[64];
  112. }mqtt_para_t;
  113. typedef struct {
  114. int flag;
  115. int qos;
  116. int retain;
  117. char topic[256];
  118. char message[256];
  119. int message_len;
  120. }mqtt_will_t;
  121. typedef struct {
  122. char product_key[64]; //aliyun used
  123. char device_name[64]; //aliyun used
  124. char device_secret[64]; //aliyun/ used
  125. char product_id[64]; //onenet used
  126. char access_key[64]; //onenet used
  127. int hw_time_enable; //huawei used
  128. char product_secret[64]; //huawei used
  129. char node_id[64];
  130. }mqtt_plat_t;
  131. typedef struct {
  132. void *h;
  133. int ver; //3:v3.1 4:v3.1.1
  134. int pdpId; //1~15
  135. int cliId;
  136. uint16_t msgId;
  137. int qos;
  138. int retain;
  139. mqtt_will_t will;
  140. int timeout; //1~60, default:5
  141. int retry_times;
  142. int timeout_notice;
  143. int clean_session;
  144. int keep_alive_time; //0~3600 seconds default:120, 0:do not disconnect
  145. int ssl_enable;
  146. int ssl_ctx_id;
  147. int msg_recv_mode; //0: urc, 1: not urc
  148. int msg_len_enable;
  149. int ping_interval; //5~60, default:5
  150. int proto_chk_enable; //0:no check 1:check
  151. int send_mode; //0:string 1:hex
  152. int recv_mode; //0:string 1:hex
  153. int view_mode; //0:no echo 1:echo
  154. int edit_mode; //0:timeout not quit 1:timeout quit
  155. int edit_time; //1~120 seconds
  156. mqtt_plat_t plat;
  157. }mqtt_conn_t;
  158. typedef struct {
  159. int fd;
  160. CellInfo_t *pcell;
  161. //lock_t lck;
  162. char prod_id[32];
  163. int stat;
  164. cell_all_t all;
  165. int curcmd; //current cmd
  166. mqtt_conn_t mq_conn[MQTT_MAX];
  167. at_data_t data[AT_CMD_MAX];
  168. GlobalDeviceManager *dm;
  169. }cell_handle_t;
  170. static cell_handle_t ceHandle={0};
  171. static at_cmd_t all_cmd[AT_CMD_MAX]={
  172. //genernal cmd
  173. {"AT", "OK", "ERROR", 300}, //测试命令
  174. {"ATI", "OK", "ERROR", 300}, //显示MT的ID信息
  175. {"AT+GMI", "OK", "ERROR", 300}, //请求制造商信息
  176. {"AT+GMM", "OK", "ERROR", 300}, //请求TA型号ID
  177. {"AT+GMR", "OK", "ERROR", 300}, //请求TA固件版本ID
  178. {"AT+CGMI", "OK", "ERROR", 300}, //同GMI
  179. {"AT+CGMM", "OK", "ERROR", 300}, //同GMM
  180. {"AT+CGMR", "OK", "ERROR", 300}, //同GMR
  181. {"AT+GSN", "OK", "ERROR", 300}, //请求国际移动设备识别码(IMEI)
  182. {"AT+CGSN", "OK", "ERROR", 300}, //同GSN
  183. {"AT&F", "OK", "ERROR", 300}, //重置AT命令设置为出厂设置
  184. {"AT&V", "OK", "ERROR", 300}, //显示当前配置
  185. {"AT&W", "OK", "ERROR", 300}, //存储当前设置到用户自定义配置文件
  186. {"ATZ", "OK", "ERROR", 300}, //从用户定义配置文件还原所有AT命令设置
  187. {"ATQ", "OK", "ERROR", 300}, //设置结果码回显模式
  188. {"ATV", "OK", "ERROR", 300}, //TA响应格式
  189. {"ATE0", "OK", "ERROR", 300}, //设置命令回显模式
  190. {"ATS3", "OK", "ERROR", 300}, //设置命令行终止符
  191. {"ATS4", "OK", "ERROR", 300}, //设置响应格式字符
  192. {"ATS5", "OK", "ERROR", 300}, //设置命令行编辑字符
  193. {"ATX", "OK", "ERROR", 300}, //设置CONNECT结果码格式和检测呼叫进程
  194. {"AT+CFUN", "OK", "ERROR", 15000}, //设置功能模式
  195. {"AT+CMEE", "OK", "ERROR", 300}, //设置错误讯息格式
  196. {"AT+CSCS", "OK", "ERROR", 300}, //选择TE字符集
  197. {"AT+QURCCFG", "OK", "ERROR", 300}, //配置URC指示选项
  198. {"AT+QPPPDROP", "OK", "ERROR", 300}, //终止PPP连接
  199. //serial cmd
  200. {"AT&C", "OK", "ERROR", 300}, //设置DCD信号模式
  201. {"AT&D", "OK", "ERROR", 300}, //设置DTR信号模式
  202. {"AT+IFC", "OK", "ERROR", 300}, //设置串口的流控方式
  203. {"AT+IPR", "OK", "ERROR", 300}, //设置固定的串口通信波特率
  204. //status cmd
  205. {"AT+CPAS", "OK", "ERROR", 300}, //查询ME活动状态
  206. {"AT+CEER", "OK", "ERROR", 300}, //上报扩展错误
  207. {"AT+QCFG", "OK", "ERROR", 300}, //扩展命令, 较多子命令
  208. {"AT+QINDCFG", "OK", "ERROR", 300}, //控制URC上报
  209. //sim cmd
  210. {"AT+CIMI", "OK", "ERROR", 300}, //查询IMSI
  211. {"AT+CLCK", "OK", "ERROR", 5000}, //功能锁定
  212. {"AT+CPIN", "OK", "ERROR", 5000}, //PIN管理
  213. {"AT+CPWD", "OK", "ERROR", 5000}, //修改密码
  214. {"AT+CSIM", "OK", "ERROR", 300}, //通用(U)SIM卡访问
  215. {"AT+CRSM", "OK", "ERROR", 300}, //(U)SIM卡受限访问
  216. {"AT+QCCID", "OK", "ERROR", 300}, //查询ICCID
  217. {"AT+QPINC", "OK", "ERROR", 300}, //获取PIN剩余重试次数
  218. {"AT+QINISTAT", "OK", "ERROR", 300}, //查询(U)SIM卡初始化状态
  219. {"AT+QSIMDET", "OK", "ERROR", 300}, //(U)SIM卡检测
  220. {"AT+QSIMSTAT", "OK", "ERROR", 300}, //(U)SIM卡插拔状态上报
  221. {"AT+QDSIM", "OK", "ERROR", 50000}, //选择(U)SIM卡
  222. //network service cmd
  223. {"AT+COPS", "OK", "ERROR", 300000}, //选择运营商
  224. {"AT+CREG", "OK", "ERROR", 300}, //CS域网络注册状态
  225. {"AT+CSQ", "OK", "ERROR", 300}, //查询信号强度
  226. {"AT+CPOL", "OK", "ERROR", 300}, //配置首选运营商列表
  227. {"AT+COPN", "OK", "ERROR", 300}, //查询运营商名称列表
  228. {"AT+CTZU", "OK", "ERROR", 300}, //自动更新时区
  229. {"AT+CTZR", "OK", "ERROR", 300}, //上报时区变化
  230. {"AT+QLTS", "OK", "ERROR", 500}, //获取通过网络同步的最新时间
  231. {"AT+QNWINFO", "OK", "ERROR", 300}, //查询网络信息
  232. //call cmd
  233. {"ATA", "OK", "ERROR", 90000}, //呼叫应答
  234. {"ATD", "OK", "ERROR", 5000}, //发起呼叫
  235. {"AT+COLP", "OK", "ERROR", 15000}, //被叫线路识别显示
  236. {"AT+ATH", "OK", "ERROR", 90000}, //挂断现有连接
  237. {"AT+CHUP", "OK", "ERROR", 90000}, //挂断语音通话
  238. {"+++", "OK", "ERROR", 300}, //从数据模式切换至命令模式
  239. {"AT+ATO", "OK", "ERROR", 300}, //从命令模式切换至数据模式
  240. {"AT+ATSO", "OK", "ERROR", 300}, //设置自动应答前振铃次数
  241. {"AT+CLCC", "OK", "ERROR", 300}, //查询当前 ME 呼叫
  242. {"AT^DSCI", "OK", "ERROR", 300}, //指示呼叫状态
  243. //phonebook cmd
  244. {"AT+CNUM", "OK", "ERROR", 300}, //查询本机号码
  245. {"AT+CPBF", "OK", "ERROR", 300}, //搜索电话本
  246. {"AT+CPBR", "OK", "ERROR", 300}, //读取电话本条目
  247. {"AT+CPBS", "OK", "ERROR", 300}, //设置电话本存储器
  248. {"AT+CPBW", "OK", "ERROR", 300}, //写入电话本
  249. //sms cmd
  250. {"AT+CSMS", "OK", "ERROR", 300}, //选择短消息服务类型
  251. {"AT+CMGF", "OK", "ERROR", 300}, //配置短消息模式
  252. {"AT+CSCA", "OK", "ERROR", 300}, //设置短消息服务中心地址
  253. {"AT+CPMS", "OK", "ERROR", 300}, //配置短消息首选存储位置
  254. {"AT+CMGD", "OK", "ERROR", 300}, //删除短消息
  255. {"AT+CMGL", "OK", "ERROR", 300}, //按状态读取短消息
  256. {"AT+CMGR", "OK", "ERROR", 300}, //按照索引读取短消息
  257. {"AT+CMGS", ">", "ERROR", 120000}, //发送短消息
  258. {"AT+CMMS", "OK", "ERROR", 300}, //发送多条短消息
  259. {"AT+CMGW", "OK", "ERROR", 300}, //存储短消息
  260. {"AT+CMSS", "OK", "ERROR", 300}, //从存储器发送短消息
  261. {"AT+CNMA", "OK", "ERROR", 300}, //新短消息确认
  262. {"AT+CNMI", "OK", "ERROR", 300}, //设置短消息上报方式
  263. {"AT+CSCB", "OK", "ERROR", 300}, //选择小区广播消息类型
  264. {"AT+CSDH", "OK", "ERROR", 300}, //设置文本模式下参数显示
  265. {"AT+CSMP", "OK", "ERROR", 300}, //设置短消息文本模式参数
  266. {"AT+QCMGS", "OK", "ERROR", 120000}, //发送级联短消息
  267. {"AT+QCMGR", "OK", "ERROR", 300}, //读取级联短消息
  268. //gps cmd
  269. {"AT+QGPSCFG", "OK", "ERROR", 300}, //配置GNSS
  270. {"AT+QGPSDEL", "OK", "ERROR", 300}, //删除辅助数据
  271. {"AT+QGPS", "OK", "ERROR", 300}, //打开GNSS
  272. {"AT+QGPSEND", "OK", "ERROR", 300}, //关闭GNSS
  273. {"AT+QGPSLOC", "OK", "ERROR", 300}, //获取定位信息
  274. {"AT+QGPSNMEA", "OK", "ERROR", 300}, //获取指定的NMEA语句
  275. {"AT+QAGPS", "OK", "ERROR", 300}, //启用/禁用AGPS
  276. //tcp/udp cmd
  277. {"AT+QICFG", "OK", "ERROR", 300}, //配置可选参数
  278. {"AT+QICSGP", "OK", "ERROR", 300}, //配置TCP/IP场景参数
  279. {"AT+QIACT", "OK", "ERROR", 10000}, //激活PDP场景
  280. {"AT+QIDEACT", "OK", "ERROR", 10000}, //去激活PDP场景
  281. {"AT+QIOPEN", "OK", "ERROR", 300}, //打开Socket服务
  282. {"AT+QICLOSE", "OK", "ERROR", 300}, //关闭Socket服务
  283. {"AT+QISTATE", "OK", "ERROR", 300}, //查询Socket服务状态
  284. {"AT+QISEND", ">", "ERROR", 300}, //发送数据
  285. {"AT+QIRD", "OK", "ERROR", 300}, //读取收到的TCP/IP数据
  286. {"AT+QISENDEX", "OK", "ERROR", 300}, //发送16进制字符串数据
  287. {"AT+QISWTMD", "OK", "ERROR", 300}, //切换数据访问模式
  288. {"AT+QNTP", "OK", "ERROR", 300}, //进行远程服务器Ping操作
  289. {"AT+QPING", "+QPING", "ERROR", 3000}, //使用NTP服务器同步本地时间
  290. {"AT+QIDNSCFG", "OK", "ERROR", 300}, //配置DNS服务器地址
  291. {"AT+QIDNSGIP", "OK", "ERROR", 300}, //用域名获取IP地址
  292. {"AT+QISDE", "OK", "ERROR", 300}, //控制是否回显AT+QISEND要发送的
  293. {"AT+QIGETERROR", "OK", "ERROR", 300}, //查询上一个AT命令错误代码
  294. //mqtt cmd
  295. {"AT+QMTCFG", "OK", "ERROR", 300}, //配置MQTT可选参数
  296. {"AT+QMTOPEN", "OK", "ERROR", 300}, //打开MQTT客户端网络
  297. {"AT+QMTCLOSE", "OK", "ERROR", 300}, //关闭MQTT客户端网络
  298. {"AT+QMTCONN", "OK", "ERROR", 300}, //连接客户端到MQTT服务器
  299. {"AT+QMTDISC", "OK", "ERROR", 300}, //客户端断开与MQTT服务器的连接
  300. {"AT+QMTSUB", "OK", "ERROR", 300}, //订阅主题
  301. {"AT+QMTUNS", "OK", "ERROR", 300}, //退订主题
  302. {"AT+QMTPUBEX", ">", "ERROR", 300}, //发布消息
  303. {"AT+QMTRECV", "OK", "ERROR", 300}, //从缓存中读取消息
  304. //domain cmd
  305. {"AT+CGATT", "OK", "ERROR", 140000}, //PS域附着或去附着
  306. {"AT+CGDCONT", "OK", "ERROR", 3000}, //定义PDP上下文
  307. {"AT+CGQREQ", "OK", "ERROR", 300}, //服务质量参数请求
  308. {"AT+CGQMIN", "OK", "ERROR", 300}, //服务质量参数(最低可接受的)
  309. {"AT+CGEQREQ", "OK", "ERROR", 300}, //3G服务质量参数(请求的)
  310. {"AT+CGEQMIN", "OK", "ERROR", 300}, //3G 服务质量参数(最低可接受的)
  311. {"AT+CGACT", "OK", "ERROR", 150000}, //PDP上下文激活/去激活
  312. {"AT+CGDATA", "OK", "ERROR", 300}, //进入数据传输状态
  313. {"AT+CGPADDR", "OK", "ERROR", 300}, //显示PDP地址
  314. {"AT+CGCLASS", "OK", "ERROR", 300}, //GPRS移动站点等级
  315. {"AT+CGEREG", "OK", "ERROR", 300}, //PS域网络注册状态
  316. {"AT+CGEREP", "OK", "ERROR", 300}, //分组域事件上报
  317. {"AT+CGSMS", "OK", "ERROR", 300}, //选择MO短消息服务
  318. {"AT+CEREG", "OK", "ERROR", 300}, //EPS网络注册状态
  319. {"AT+QGDCNT", "OK", "ERROR", 300}, //流量统计
  320. {"AT+QAUGDCNT", "OK", "ERROR", 300}, //自动保存流量统计
  321. {"AT+QNETDEVCTL", "OK", "ERROR", 2000}, //连接USB网卡
  322. {"AT+QCEERCATCFG", "OK", "ERROR", 300}, //配置2G/4G下AT+CEER返回格式
  323. //hardware cmd
  324. {"AT+QPOWD", "OK", "ERROR", 300}, //关闭模块
  325. {"AT+CCLK", "OK", "ERROR", 300}, //实时时钟
  326. {"AT+QSCLK", "OK", "ERROR", 300}, //禁用/启用睡眠模式
  327. };
  328. at_para_t init_para[]={
  329. {AT_CMD_AT, ""},
  330. {AT_CMD_ATE, "0"},
  331. {AT_CMD_QSIMDET, "=1,1"},
  332. {AT_CMD_CPIN, "?"},
  333. {AT_CMD_CREG, "?"},
  334. //{AT_CMD_CGDCONT, ""},
  335. {AT_CMD_QICSGP, ""},
  336. {AT_CMD_QIDEACT, "="CONTEXT_ID},
  337. {AT_CMD_QIACT, "="CONTEXT_ID},
  338. {AT_CMD_QCFG, "=\"usbnet\",1"}, //set module to ecm mode
  339. {AT_CMD_QNETDEVCTL, "=3,"CONTEXT_ID",0"},
  340. {AT_CMD_CMGF, "=1"},
  341. {AT_CMD_CSCS, "=GSM"},
  342. #ifdef GNSS_ENABLE
  343. {AT_CMD_QGPS, "=1"},
  344. {AT_CMD_QGPSCFG, "=\"gnssconfig\",5"},
  345. {AT_CMD_QGPSCFG, "=\"gpsnmeatype\",1"},
  346. #endif
  347. {-1, ""},
  348. };
  349. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  350. static at_cmd_t* data_of(int cmd)
  351. {
  352. return &all_cmd[cmd];
  353. }
  354. static int rssi_to_dbm(int rssi)
  355. {
  356. int dbm=0;
  357. if(rssi>=0 && rssi<57) {
  358. dbm = RSSI_DBM_MIN1+rssi*2;
  359. }
  360. else if(rssi>=100 && rssi<199) {
  361. dbm = RSSI_DBM_MIN2+rssi-100;
  362. }
  363. return dbm;
  364. }
  365. static char* str_get(char *buf, char c)
  366. {
  367. int i,len=strlen(buf);
  368. for(i=0; i<len; i++) {
  369. if(buf[i]==c) return buf+i;
  370. }
  371. return buf;
  372. }
  373. static int mem_find(char *buf, int len, char *str)
  374. {
  375. int i,slen=strlen(str);
  376. for(i=0; i<=len-slen; i++) {
  377. if(memcmp(buf+i, str, slen)==0) {
  378. return 0;
  379. }
  380. }
  381. return -1;
  382. }
  383. static void mem_print(char *buf, int len)
  384. {
  385. int i;
  386. for(i=0; i<len; i++) {
  387. LOGD("%d, ", buf[i]);
  388. if((i+1)%16==0) LOGD("\n");
  389. }
  390. LOGD("\n");
  391. }
  392. static int nic_set(int nic, int on)
  393. {
  394. char tmp[200],path[100];
  395. const char *ifname=sys_get_ifname(nic);
  396. sprintf(path, "/var/run/udhcpc_%s.pid", ifname);
  397. sprintf(tmp, "kill $(cat %s)", path);
  398. system(tmp);
  399. sprintf(tmp, "ip link set dev %s %s", ifname, on?"up":"down");
  400. system(tmp);
  401. if(on) {
  402. sprintf(tmp, "udhcpc -R -b -i %s -p %s ", ifname, path);
  403. system(tmp);
  404. }
  405. return 0;
  406. }
  407. static int cell_reset(cell_handle_t *h);
  408. static int cell_sock_init(cell_handle_t *h);
  409. static int cell_get_info(cell_handle_t *h, cell_info_t *info);
  410. static int cell_get_stat(cell_handle_t *h, cell_stat_t *stat);
  411. static void conn_init(cell_handle_t *h, mqtt_conn_t *conn);
  412. //////////////////////////////////////////////////////////////////////////////////
  413. static int port_setup(cell_handle_t *h, int speed);
  414. static void msleep(int ms)
  415. {
  416. usleep(ms*1000);
  417. }
  418. static void reset_var( cell_handle_t *h)
  419. {
  420. h->stat=AT_STAT_UNINIT;
  421. h->all.stat.dbm = 0;
  422. h->all.stat.ber = 0;
  423. h->all.stat.nsta = 0;
  424. h->all.stat.altitude = 0;
  425. sprintf(h->all.stat.latitude, "-");
  426. sprintf(h->all.stat.longitude, "-");
  427. h->all.stat.utctime = 0;
  428. h->all.stat.linked = 0;
  429. sprintf(h->all.stat.ipv4, "-");
  430. sprintf(h->all.stat.ipv6, "-");
  431. sprintf(h->all.info.apn, "-");
  432. sprintf(h->all.info.cnum, "-");
  433. sprintf(h->all.info.imsi, "-");
  434. sprintf(h->all.info.imei, "-");
  435. sprintf(h->all.info.isp, "-");
  436. }
  437. static int port_init(cell_handle_t *h)
  438. {
  439. h->fd = open(AT_PORT, O_RDWR | O_NOCTTY | O_NONBLOCK);
  440. if(h->fd<0) {
  441. return -1;
  442. }
  443. port_setup(h, BAUD_RATE);
  444. return 0;
  445. }
  446. static int port_deinit(cell_handle_t *h)
  447. {
  448. if(h->fd<0) {
  449. return -1;
  450. }
  451. int r=close(h->fd);
  452. h->fd=-1;
  453. sleep(2);
  454. return r;
  455. }
  456. static int port_read(cell_handle_t *h, void *data, int len)
  457. {
  458. return read(h->fd, data, len);
  459. }
  460. static int port_write(cell_handle_t *h, void *data, int len)
  461. {
  462. return write(h->fd, data, len);
  463. }
  464. static int port_setup(cell_handle_t *h, int speed)
  465. {
  466. struct termios tty;
  467. if (tcgetattr(h->fd, &tty) != 0) {
  468. LOGE("Read 4G Module tcgetattr!!!\n");
  469. return -1;
  470. }
  471. cfsetospeed(&tty, speed);
  472. cfsetispeed(&tty, speed);
  473. tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
  474. tty.c_iflag &= ~IGNBRK; // disable break processing
  475. tty.c_lflag = 0; // no signaling chars, no echo,
  476. // no canonical processing
  477. tty.c_oflag = 0; // no remapping, no delays
  478. tty.c_cc[VMIN] = 0; // read doesn't block
  479. tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
  480. tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
  481. tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
  482. // enable reading
  483. tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
  484. tty.c_cflag |= 0;
  485. tty.c_cflag &= ~CSTOPB;
  486. tty.c_cflag &= ~CRTSCTS;
  487. if (tcsetattr(h->fd, TCSANOW, &tty) != 0) {
  488. LOGE("Read 4G Module tcsetattr!!!\n");
  489. return -1;
  490. }
  491. return 0;
  492. }
  493. static int port_wait(cell_handle_t *h, int timeout)
  494. {
  495. int r;
  496. char buf[100];
  497. fd_set fset;
  498. struct timeval tv;
  499. tv.tv_sec = timeout/1000;
  500. tv.tv_usec = (timeout%1000)*1000;
  501. if(h->fd < 0)
  502. return -1;
  503. FD_ZERO(&fset); FD_SET(h->fd, &fset);
  504. r = select(h->fd + 1, &fset, NULL, NULL, &tv);
  505. if (r<=0) {
  506. if(r<0) {
  507. //LOGE("port_wait error %s\n", strerror(errno));
  508. }
  509. else {
  510. //LOGE("port_wait timeout\n");
  511. }
  512. }
  513. return r;
  514. }
  515. static int port_recv(cell_handle_t *h, char *buf, int buflen, int timeout)
  516. {
  517. int r;
  518. r = port_wait(h, timeout);
  519. if(r<0) {
  520. return -1;
  521. }
  522. r = port_read(h, buf, buflen);
  523. if(r<=0) {
  524. return -1;
  525. }
  526. return r;
  527. }
  528. static int send_cmd(cell_handle_t *h, int cmd, char *para, char *rcv, int rcvlen)
  529. {
  530. int i,r,l,tout,finish=0;
  531. int tlen=0,buflen,wait_step=10;
  532. char buf[BUF_LEN],*pbuf;
  533. at_cmd_t *pcmd=data_of(cmd);
  534. sprintf(buf, "%s%s\r", pcmd->cmd, para?para:"");
  535. LOGD("[tx]: %s\n", buf);
  536. for (i = 0; i < RETRY_TIMES; i++)
  537. {
  538. tout = 0;
  539. port_write(h, buf, strlen(buf));
  540. while (tout < pcmd->timeout)
  541. {
  542. l = port_wait(h, wait_step);
  543. if (l > 0)
  544. {
  545. if (rcv && rcvlen > 0)
  546. {
  547. pbuf = rcv;
  548. buflen = rcvlen;
  549. }
  550. else
  551. {
  552. pbuf = buf;
  553. buflen = sizeof(buf);
  554. }
  555. l = port_read(h, pbuf + tlen, buflen);
  556. if (l > 0)
  557. {
  558. tlen += l;
  559. pbuf[tlen] = 0;
  560. LOGD("[rx]: %s\n", pbuf);
  561. if (pcmd->ok && strlen(pcmd->ok) && strstr(pbuf, pcmd->ok))
  562. {
  563. return AT_OK;
  564. }
  565. if (pcmd->err && strlen(pcmd->err) && strstr(pbuf, pcmd->err))
  566. {
  567. // 指令不通则重置模块
  568. // if (cmd != AT_CMD_CFUN && cmd != AT_CMD_QIDEACT )
  569. // {
  570. // cell_reset(h);
  571. // }
  572. return AT_ERR;
  573. }
  574. }
  575. }
  576. tout += wait_step;
  577. usleep(1000);
  578. }
  579. }
  580. //AT不通重启串口
  581. // if (cmd != AT_CMD_QIDEACT && cmd != AT_CMD_CFUN )
  582. // {
  583. // port_deinit(h);
  584. // port_init(h);
  585. // }
  586. return AT_TOUT;
  587. }
  588. static int send_data(cell_handle_t *h, void *data, int len, int timeout)
  589. {
  590. char buf[100];
  591. int l,tlen=0,tout=0,wait_step=10;
  592. l = port_write(h, data, len);
  593. if(l==len) {
  594. while(tout<timeout) {
  595. l = port_wait(h, wait_step);
  596. if(l>0) {
  597. l = port_read(h, buf, sizeof(buf));
  598. if(l>0) {
  599. tlen += l; buf[tlen] = 0;
  600. if(strstr(buf, "OK")) {
  601. return AT_OK;
  602. }
  603. else if(strstr(buf, "ERROR")) {
  604. return AT_ERR;
  605. }
  606. }
  607. }
  608. tout += wait_step;
  609. }
  610. }
  611. return AT_TOUT;
  612. }
  613. ////////////////////////////////////////////////////////////////////////////
  614. static int cell_reset(cell_handle_t *h)
  615. {
  616. int r=AT_OK;
  617. // r = send_cmd(h, AT_CMD_CFUN, "=1,1", NULL, 0);
  618. // if(r==AT_OK) {
  619. // h->stat = AT_STAT_UNINIT;
  620. //}
  621. //sleep(5);//等待模块复位完成
  622. // if (r == AT_OK)
  623. // {
  624. // port_deinit(h);
  625. // port_init(h);
  626. // }
  627. return (r==AT_OK)?0:-1;
  628. }
  629. static int cell_init(cell_handle_t *h)
  630. {
  631. int i,r;
  632. at_para_t *p=init_para;
  633. if(h->stat==AT_STAT_INITED) {
  634. return 0;
  635. }
  636. for(i=0;; i++) {
  637. if(p[i].cmd==-1) {
  638. break;
  639. }
  640. if(p[i].cmd==AT_CMD_CGDCONT) {
  641. sprintf(p[i].para, "=%s,\"IPV4V6\",\"%s\"", CONTEXT_ID, h->pcell->apn);
  642. }
  643. else if(p[i].cmd==AT_CMD_QICSGP) {
  644. sprintf(p[i].para, "=%s,3,\"%s\",\"%s\",\"%s\"", CONTEXT_ID, h->pcell->apn,h->pcell->username,h->pcell->password);
  645. }
  646. r = send_cmd(h, p[i].cmd, p[i].para, NULL, 0);
  647. if(r!=AT_OK) {
  648. if (p[i].cmd==AT_CMD_AT)
  649. {
  650. port_deinit(h);
  651. port_init(h);
  652. }
  653. break;
  654. }
  655. }
  656. if(r==0) {
  657. h->stat = AT_STAT_INITED;
  658. nic_set(NIC_USB, 1);
  659. cell_get_info(h, &h->all.info);
  660. }
  661. return r?-1:0;
  662. }
  663. static int cell_deinit(cell_handle_t *h)
  664. {
  665. int r=-1;
  666. char buf[400];
  667. r = send_cmd(h, AT_CMD_QIDEACT, "="CONTEXT_ID, buf, sizeof(buf));
  668. if(r==AT_OK) {
  669. return r;
  670. }
  671. return r;
  672. }
  673. static int cell_get_ip(cell_handle_t *h, cell_stat_t *stat)
  674. {
  675. char buf[200];
  676. int r=-1;
  677. memset(stat->ipv4, 0, sizeof(stat->ipv4));
  678. memset(stat->ipv6, 0, sizeof(stat->ipv6));
  679. if(h->stat==AT_STAT_UNINIT) {
  680. return -1;
  681. }
  682. r = send_cmd(h, AT_CMD_QIACT, "?", buf, sizeof(buf));
  683. if (r != AT_OK)
  684. {
  685. return -1;
  686. }
  687. r = sscanf(str_get(buf, '+'), "+QIACT: %*d,%*d,%*d,\"%15[^\"]\",\"%63[^\"]\"", stat->ipv4, stat->ipv6);
  688. LOGD("Cellular IPV4: %s\n",stat->ipv4);
  689. LOGD("Cellular IPV6:%s\n", stat->ipv6);
  690. return 0;
  691. }
  692. static int cell_get_info(cell_handle_t *h, cell_info_t *info)
  693. {
  694. int r;
  695. char buf[400];
  696. if(h->stat==AT_STAT_UNINIT) {
  697. return -1;
  698. }
  699. memset(info, 0, sizeof(cell_info_t));
  700. // r = send_cmd(h, AT_CMD_CNUM, NULL, buf, sizeof(buf));
  701. // if(r==AT_OK) {
  702. // r = sscanf(str_get(buf,'+'), "+CNUM: %*s,%s,%*d", info->cnum);
  703. // }
  704. r = send_cmd(h, AT_CMD_GSN, NULL, buf, sizeof(buf));
  705. if(r==AT_OK) {
  706. r = sscanf(str_get(buf,'+'), "%s", info->imei);
  707. }
  708. r = send_cmd(h, AT_CMD_CIMI, NULL, buf, sizeof(buf));
  709. if(r==AT_OK) {
  710. r = sscanf(str_get(buf,'+'), "%s", info->imsi);
  711. }
  712. r = send_cmd(h, AT_CMD_CGDCONT, "?", buf, sizeof(buf));
  713. if(r==AT_OK) {
  714. r = sscanf(str_get(buf,'+'), "+CGDCONT: %*d,\"%*[^\"]\",\"%[^\"]", info->apn);
  715. }
  716. r = send_cmd(h, AT_CMD_COPS, "?", buf, sizeof(buf));
  717. if(r==AT_OK) {
  718. r = sscanf(str_get(buf,'+'), "+COPS: %*d,%*d,\"%[^\"]", info->isp);
  719. }
  720. //cell_get_ip(h, &h->all.stat);
  721. LOGD("___info->apn: %s\n", info->apn);
  722. LOGD("___info->isp: %s\n", info->isp);
  723. LOGD("___info->imei: %s\n", info->imei);
  724. LOGD("___info->imsi: %s\n", info->imsi);
  725. LOGD("___info->cnum: %s\n", info->cnum);
  726. return 0;
  727. }
  728. static int cell_get_sig(cell_handle_t *h, cell_stat_t *stat)
  729. {
  730. char buf[200];
  731. int rssi,ber,r=-1;
  732. if(h->stat==AT_STAT_UNINIT) {
  733. return -1;
  734. }
  735. r = send_cmd(h, AT_CMD_CSQ, NULL, buf, sizeof(buf));
  736. if (r != AT_OK)
  737. {
  738. return -1;
  739. }
  740. r = sscanf(str_get(buf, '+'), "%*s %d,%d", &rssi, &ber);
  741. if (r < 2)
  742. {
  743. return -1;
  744. }
  745. stat->dbm = rssi_to_dbm(rssi);
  746. stat->ber = ber;
  747. return 0;
  748. }
  749. static int cell_get_gnss(cell_handle_t *h, cell_stat_t *stat)
  750. {
  751. int r;
  752. char buf[200],utc[32],date[32];
  753. #ifdef GNSS_ENABLE
  754. if(h->stat==AT_STAT_UNINIT) {
  755. return -1;
  756. }
  757. r = send_cmd(h, AT_CMD_QGPSLOC, "=0", buf, sizeof(buf));
  758. if(r!=AT_OK) {
  759. return -1;
  760. }
  761. r = sscanf(str_get(buf,'+'), "+QGPSLOC: %s,%s,%s,%*d,%d,%*d,%*d,%*d,%*d,%s,%d", utc, stat->latitude, stat->longitude, &stat->altitude, date, &stat->nsta);
  762. if(r<6) {
  763. return -1;
  764. }
  765. //
  766. #endif
  767. return 0;
  768. }
  769. static int cell_get_ping(cell_handle_t *h, cell_stat_t *stat)
  770. {
  771. int r,ret;
  772. char buf[200],utc[32],date[32];
  773. if(h->stat==AT_STAT_UNINIT) {
  774. stat->linked = 0;
  775. return -1;
  776. }
  777. /*
  778. r = send_cmd(h, AT_CMD_QPING, "=1,\"www.baidu.com\",3,2,", buf, sizeof(buf));
  779. if(r!=AT_OK) {
  780. stat->linked = 0;
  781. return -1;
  782. }
  783. r = sscanf(str_get(buf,'+'), "+QPING: %d", &ret);
  784. if(r<1) {
  785. stat->linked = 0;
  786. return -1;
  787. }
  788. if(ret==0) {
  789. stat->linked = 1;
  790. }
  791. else {
  792. stat->linked = 0;
  793. }
  794. */
  795. r = send_cmd(h, AT_CMD_CGATT, "?", buf, sizeof(buf));
  796. if(r!=AT_OK) {
  797. stat->linked = 0;
  798. return -1;
  799. }
  800. r = sscanf(str_get(buf,'+'), "+CGATT: %d", &ret);
  801. if(r<1) {
  802. stat->linked = 0;
  803. return -1;
  804. }
  805. if(ret==1) {
  806. stat->linked = 1;
  807. }
  808. else {
  809. stat->linked = 0;
  810. }
  811. return 0;
  812. }
  813. static int cell_get_time(cell_handle_t *h, cell_stat_t *stat)
  814. {
  815. int r,offset;
  816. char opr,buf[200],date[24],time[24];
  817. struct tm utc_tm;
  818. if(h->stat==AT_STAT_UNINIT) {
  819. return -1;
  820. }
  821. r = send_cmd(h, AT_CMD_QLTS, "=1", buf, sizeof(buf));
  822. if(r!=AT_OK) {
  823. return -1;
  824. }
  825. r = sscanf(str_get(buf,'+'), "+QLTS: \"%d/%d/%d,%d:%d:%d",&utc_tm.tm_year,&utc_tm.tm_mon,&utc_tm.tm_mday,&utc_tm.tm_hour,&utc_tm.tm_min,&utc_tm.tm_sec);
  826. if(r<6) {
  827. return -1;
  828. }
  829. stat->utctime = mktime2(&utc_tm, 0);
  830. //print_time("999", &utc_tm);
  831. return 0;
  832. }
  833. static int cell_get_stat(cell_handle_t *h, cell_stat_t *stat)
  834. {
  835. if(h->stat==AT_STAT_UNINIT) {
  836. return -1;
  837. }
  838. cell_get_sig(h, stat);
  839. cell_get_gnss(h, stat);
  840. cell_get_ping(h, stat);
  841. cell_get_time(h, stat);
  842. cell_get_ip(h, stat);
  843. return 0;
  844. }
  845. static int cell_sock_conn(cell_handle_t *h, int sock, char *host, uint16_t port, sock_conn_t *conn)
  846. {
  847. int r;
  848. char buf[200];
  849. if(h->stat==AT_STAT_UNINIT) {
  850. return -1;
  851. }
  852. sprintf(buf, "=%s,%s,%s,“%s”,%d,0,1", CONTEXT_ID, CONNECT_ID, (sock==SOCK_TCP)?"TCP":"UDP", host, port);
  853. r = send_cmd(h, AT_CMD_QIOPEN, buf, NULL, 0);
  854. if(r!=AT_OK) {
  855. return -1;
  856. }
  857. conn->h = h;
  858. conn->sock = sock;
  859. conn->cont_id = atoi(CONTEXT_ID);
  860. conn->conn_id = atoi(CONNECT_ID);
  861. return 0;
  862. }
  863. static int cell_sock_disconn(sock_conn_t *conn)
  864. {
  865. int r;
  866. char buf[200];
  867. cell_handle_t *h=(cell_handle_t*)conn->h;
  868. if(h->stat==AT_STAT_UNINIT) {
  869. return -1;
  870. }
  871. sprintf(buf, "=%s,%s", CONNECT_ID, CONNECT_TIMEOUT);
  872. r = send_cmd(h, AT_CMD_QICLOSE, buf, NULL, 0);
  873. if(r!=AT_OK) {
  874. return -1;
  875. }
  876. conn->h = NULL;
  877. conn->sock = -1;
  878. conn->cont_id = -1;
  879. conn->conn_id = -1;
  880. return 0;
  881. }
  882. static int cell_sock_send(sock_conn_t *conn, void *data, int len)
  883. {
  884. int r=0,rt,offset=0,remain_len,send_len;
  885. char buf[100],*pd=(char*)data;
  886. cell_handle_t *h=(cell_handle_t*)conn->h;
  887. if(h->stat==AT_STAT_UNINIT) {
  888. return -1;
  889. }
  890. sprintf(buf, "=%d,%d", conn->conn_id, len);
  891. rt = send_cmd(h, AT_CMD_QISEND, buf, NULL, 0);
  892. if(rt!=AT_OK) {
  893. return -1;
  894. }
  895. while(offset<len) {
  896. remain_len = len - offset;
  897. send_len = (remain_len>CHUNCK_SIZE)?CHUNCK_SIZE:remain_len;
  898. rt = send_data(h, data+offset, send_len, 500);
  899. if(rt!=AT_OK) {
  900. r = -1; break;
  901. }
  902. offset += send_len;
  903. }
  904. return r;
  905. }
  906. static int cell_sock_disconn_all(cell_handle_t *h)
  907. {
  908. int r;
  909. char buf[100];
  910. if(h->stat==AT_STAT_UNINIT) {
  911. return -1;
  912. }
  913. int count = 0;
  914. uint8_t conn_ids[MAX_CONNECTIONS];
  915. memset(conn_ids, 0, sizeof(conn_ids));
  916. r = send_cmd(h, AT_CMD_QISTATE, NULL, buf, sizeof(buf));
  917. if(r!=AT_OK) {
  918. return -1;
  919. }
  920. char *ptr = buf;
  921. while ((ptr = strstr(ptr, "+QISTATE: ")) != NULL && count < MAX_CONNECTIONS) {
  922. int conn_id;
  923. char conn_type[100];
  924. char conn_IP[100];
  925. if (sscanf(ptr, "+QISTATE: %d,%s,%s,", &conn_id,conn_type,conn_IP) == 1) {
  926. conn_ids[count++] = (uint8_t)conn_id;
  927. log_i("4G Cellular Found active connection: ID=%d, Type=%s, IP=%s", conn_id,conn_type,conn_IP);
  928. ptr += 10; // 跳过已解析的部分
  929. }
  930. else break;
  931. }
  932. char closebuf[200];
  933. for (int i = 0; i < count; i++)
  934. {
  935. char ids[10] = { 0 };
  936. sprintf(ids, "%d", conn_ids[i]);
  937. sprintf(closebuf, "=%s,%s", ids, CONNECT_TIMEOUT);
  938. r = send_cmd(h, AT_CMD_QICLOSE, closebuf, NULL, 0);
  939. if (r != AT_OK)
  940. {
  941. log_e("4G Cellular active connection: ID=%d close Failed!!!!", conn_ids[i]);
  942. }
  943. else
  944. log_i("4G Cellular active connection: ID=%d close Successful!!!!", conn_ids[i]);
  945. }
  946. return 0;
  947. }
  948. static int cell_sock_connected(cell_handle_t *h)
  949. {
  950. return 0;
  951. }
  952. static mqtt_conn_t* get_mqtt_conn_free(cell_handle_t *h)
  953. {
  954. int i;
  955. for(i=0; i<MQTT_MAX; i++) {
  956. if(h->mq_conn[i].h==NULL) {
  957. return &h->mq_conn[i];
  958. }
  959. }
  960. return NULL;
  961. }
  962. static int cell_mqtt_init(cell_handle_t *h)
  963. {
  964. int i;
  965. at_cmd_t *pcmd=NULL;
  966. for(i=0; i<MQTT_MAX; i++) {
  967. h->mq_conn[i].cliId = i;
  968. }
  969. return 0;
  970. }
  971. static int cell_mqtt_conn(cell_handle_t *h, mqtt_para_t *para)
  972. {
  973. int r;
  974. char tmp[200],buf[100];
  975. mqtt_conn_t *conn=NULL;
  976. conn = get_mqtt_conn_free(h);
  977. if(!conn) {
  978. return -1;
  979. }
  980. conn_init(h, conn);
  981. sprintf(tmp, "=%d,\"%s\",%d", conn->cliId, para->host, para->port);
  982. r = send_cmd(h, AT_CMD_QMTOPEN, tmp, buf, sizeof(buf));
  983. if(r!=AT_OK) {
  984. return -1;
  985. }
  986. sprintf(tmp, "=%d,\"mqtt%d\",\"%s\",\"%s\"", conn->cliId, conn->cliId, para->username, para->password);
  987. r = send_cmd(h, AT_CMD_QMTCONN, tmp, buf, sizeof(buf));
  988. if(r!=AT_OK) {
  989. return -1;
  990. }
  991. conn->h = h;
  992. conn->qos = 2;
  993. conn->retain = 0;
  994. return 0;
  995. }
  996. static int cell_mqtt_disconn(mqtt_conn_t *conn)
  997. {
  998. int r;
  999. char tmp[100],buf[100];
  1000. at_cmd_t *pcmd=NULL;
  1001. sprintf(tmp, "=%d", conn->cliId);
  1002. r = send_cmd(conn->h, AT_CMD_QMTDISC, tmp, buf, sizeof(buf));
  1003. if(r!=AT_OK) {
  1004. return -1;
  1005. }
  1006. r = send_cmd(conn->h, AT_CMD_QMTCLOSE, tmp, buf, sizeof(buf));
  1007. if(r!=AT_OK) {
  1008. return -1;
  1009. }
  1010. conn->msgId = 0;
  1011. conn->h = NULL;
  1012. return 0;
  1013. }
  1014. static int cell_mqtt_sub(mqtt_conn_t *conn, char *topic)
  1015. {
  1016. int r;
  1017. char buf[500];
  1018. at_cmd_t *pcmd=NULL;
  1019. sprintf(buf, "=%d, %d, \"%s\",%d", conn->cliId, conn->msgId, topic, conn->qos);
  1020. r = send_cmd(conn->h, AT_CMD_QMTSUB, buf, NULL, 0);
  1021. if(r!=AT_OK) {
  1022. return -1;
  1023. }
  1024. return 0;
  1025. }
  1026. static int cell_mqtt_pub(mqtt_conn_t *conn, char *topic, void *data, int len)
  1027. {
  1028. char buf[200],*pd=(char*)data;
  1029. int r=0,rt,offset=0,remain_len,send_len;
  1030. sprintf(buf, "=%d,%d,%d,%d,\"%s\",%d", conn->cliId, conn->msgId, conn->qos, conn->retain, topic, len);
  1031. rt = send_cmd(conn->h, AT_CMD_QMTPUB, NULL, buf, sizeof(buf));
  1032. if(rt!=AT_OK) {
  1033. return -1;
  1034. }
  1035. while(offset<len) {
  1036. remain_len = len - offset;
  1037. send_len = (remain_len>CHUNCK_SIZE)?CHUNCK_SIZE:remain_len;
  1038. rt = send_data(conn->h, data+offset, send_len, 500);
  1039. if(rt!=AT_OK) {
  1040. r = -1; break;
  1041. }
  1042. offset += send_len;
  1043. }
  1044. return 0;
  1045. }
  1046. static int cell_send_sms(cell_handle_t *h, char *number, char *txt)
  1047. {
  1048. int r=-1,rt;
  1049. char tmp[100],buf[300];
  1050. if(h->stat==AT_STAT_UNINIT) {
  1051. return -1;
  1052. }
  1053. // char* unicode_str=utf8_to_unicode_string(txt);
  1054. //if (!unicode_str) return -1;
  1055. //log_i("unicode_str,%s\n", unicode_str);
  1056. log_i("chinese,%s\n", txt);
  1057. char ucs2_sms[256];
  1058. int ss=chinese_to_ucs2(txt, ucs2_sms,sizeof(ucs2_sms)); // 转换为 UCS2 编码
  1059. if (ss!=0) return -1;
  1060. log_i("ucs2_sms,%s\n", ucs2_sms);
  1061. sprintf(tmp, "=\"%s\"", "UCS2");
  1062. r = send_cmd(h, AT_CMD_CSCS, tmp, buf, sizeof(buf));
  1063. if (r != AT_OK)
  1064. {
  1065. return -1;
  1066. }
  1067. sprintf(tmp, "=17,71,0,8");
  1068. r = send_cmd(h, AT_CMD_CSMP, tmp, buf, sizeof(buf));
  1069. if (r != AT_OK)
  1070. {
  1071. return -1;
  1072. }
  1073. sprintf(tmp, "=\"%s\"", number);
  1074. r = send_cmd(h, AT_CMD_CMGS, tmp, buf, sizeof(buf));
  1075. if (r != AT_OK)
  1076. {
  1077. return -1;
  1078. }
  1079. snprintf(buf, sizeof(buf), "%s\x1a", ucs2_sms);
  1080. r = send_data(h, buf, strlen(buf), 5000);
  1081. SMS_SEND_COUNT++;
  1082. return r;
  1083. }
  1084. int cell_send_sms_all(int type, int subtype, int alarm_type,char *txt)
  1085. {
  1086. cell_handle_t *h=&ceHandle;
  1087. if (!__globalDeviceManage._globalDevInfo.cell.Cellular_enable || __globalDeviceManage._globalDevInfo.cell.mode==0 || SMS_SEND_COUNT >= SMS_SEND_MAX)
  1088. {
  1089. return -1;
  1090. }
  1091. char temp[128];
  1092. char *prod_name = h->dm->_globalDevInfo.product.name;
  1093. char prod_id[32];
  1094. strcpy( prod_id,h->dm->_globalDevInfo.product.number);
  1095. int langID = h->dm->_globalDevInfo.product.language;
  1096. switch (type)
  1097. {
  1098. case ALARM_TYPE_POWER:
  1099. {
  1100. if (subtype)
  1101. {
  1102. switch (alarm_type)
  1103. {
  1104. case ENABLE_TAC_V_UP:
  1105. case ENABLE_TAC_V_DOWN:
  1106. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_V[langID], language_exceed[langID], language_alarm[langID]);
  1107. break;
  1108. case ENABLE_TAC_A_UP:
  1109. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_A[langID], language_exceed[langID], language_alarm[langID]);
  1110. break;
  1111. case ENABLE_TAC_W_UP:
  1112. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_W[langID], language_exceed[langID], language_alarm[langID]);
  1113. break;
  1114. case ENABLE_TAC_P_UP:
  1115. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_P[langID], language_exceed[langID], language_alarm[langID]);
  1116. break;
  1117. case ENABLE_TAC_STIME:
  1118. case ENABLE_TAC_ETIME:
  1119. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_alarm_phase_lose[langID], language_alarm[langID]);
  1120. break;
  1121. default:
  1122. return -1;
  1123. }
  1124. }
  1125. else
  1126. {
  1127. switch (alarm_type)
  1128. {
  1129. case WARNING_V_UP:
  1130. case WARNING_V_DOWN:
  1131. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_V[langID], language_exceed[langID], language_alarm[langID]);
  1132. break;
  1133. case WARNING_A_UP:
  1134. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_A[langID], language_exceed[langID], language_alarm[langID]);
  1135. break;
  1136. case WARNING_W_UP:
  1137. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_W[langID], language_exceed[langID], language_alarm[langID]);
  1138. break;
  1139. case WARNING_P_UP:
  1140. snprintf(temp, sizeof(temp), "%s %s %s %s %s", prod_name, prod_id, language_alarm_P[langID], language_exceed[langID], language_alarm[langID]);
  1141. break;
  1142. case 0 ... 2:
  1143. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_alarm_phase_lose[langID], language_alarm[langID]);
  1144. break;
  1145. default:
  1146. return -1;
  1147. }
  1148. }
  1149. }
  1150. break;
  1151. case ALARM_TYPE_SENSOR:
  1152. {
  1153. switch (subtype)
  1154. {
  1155. case SENSOR_TYPE_TEMP_DOUBLE:
  1156. case SENSOR_TYPE_TEMP_HUMI:
  1157. case SENSOR_TYPE_TEMP:
  1158. snprintf(temp, sizeof(temp), "%s %s %s/%s %s", prod_name, prod_id, language_temperature[langID], language_humidity[langID], language_alarm[langID]);
  1159. break;
  1160. case SENSOR_TYPE_SMOKE:
  1161. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_sensor_smoke[langID], language_alarm[langID]);
  1162. break;
  1163. case SENSOR_TYPE_WATER:
  1164. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_humidity[langID], language_alarm[langID]);
  1165. break;
  1166. case SENSOR_TYPE_ACCESS:
  1167. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_sensor_access[langID], language_alarm[langID]);
  1168. break;
  1169. case SENSOR_TYPE_GAS:
  1170. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_atmosphere_gas[langID], language_alarm[langID]);
  1171. break;
  1172. case SENSOR_TYPE_AIR_PRESS:
  1173. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_atmosphere_pressure[langID], language_alarm[langID]);
  1174. break;
  1175. case SENSOR_TYPE_LEAK:
  1176. snprintf(temp, sizeof(temp), "%s %s %s %s", prod_name, prod_id, language_sensor_leak[langID], language_alarm[langID]);
  1177. break;
  1178. default:
  1179. return -1;
  1180. }
  1181. }
  1182. break;
  1183. case ALARM_TYPE_NETWORK:
  1184. {
  1185. snprintf(temp, sizeof(temp), "%s %s %s", prod_name, prod_id, language_alarm_Type_Network[langID]);
  1186. }
  1187. break;
  1188. default:
  1189. return -1;
  1190. }
  1191. char result[256];
  1192. snprintf(result, sizeof(result), "%s, %s", temp, txt);
  1193. for (int i = 0; i < MAIL_RECV_MAX; i++)
  1194. {
  1195. if (strcmp(__globalDeviceManage._globalDevInfo.cell.sms_recv[i].account, "") != 0)
  1196. {
  1197. cell_send_sms(h, __globalDeviceManage._globalDevInfo.cell.sms_recv[i].account, result);
  1198. sleep(1);
  1199. }
  1200. }
  1201. return 1;
  1202. }
  1203. static int cell_send_call(cell_handle_t *h, char *number, void *data, int len)
  1204. {
  1205. int r;
  1206. char buf[100];
  1207. if(h->stat==AT_STAT_UNINIT) {
  1208. return -1;
  1209. }
  1210. sprintf(buf, "%s", number);
  1211. r = send_cmd(h, AT_CMD_ATD, NULL, buf, sizeof(buf));
  1212. if(r!=AT_OK) {
  1213. return -1;
  1214. }
  1215. return 0;
  1216. }
  1217. /////////////////////////////////////////////////////////////////////////
  1218. static int conn_cfg(mqtt_conn_t *conn, char *item, char *value)
  1219. {
  1220. int r;
  1221. char tmp[100],buf[200];
  1222. cell_handle_t *h=(cell_handle_t*)conn->h;
  1223. if(h->stat==AT_STAT_UNINIT) {
  1224. return -1;
  1225. }
  1226. sprintf(tmp, "=\"%s\",%s", item, value);
  1227. r = send_cmd(h, AT_CMD_QMTCFG, NULL, buf, sizeof(buf));
  1228. if(r!=AT_OK) {
  1229. return -1;
  1230. }
  1231. return 0;
  1232. }
  1233. static void conn_init(cell_handle_t *h, mqtt_conn_t *conn)
  1234. {
  1235. char buf[100];
  1236. conn->h = h;
  1237. conn->ver = MQTT_VER;
  1238. conn->pdpId = conn->cliId+1; //1~15
  1239. conn->msgId = 0;
  1240. conn->qos = MQTT_QOS;
  1241. conn->retain = 1;
  1242. conn->will.flag = MQTT_WILL;
  1243. conn->will.qos = MQTT_QOS;
  1244. conn->will.retain = MQTT_RETAIN;
  1245. strcpy(conn->will.topic, "");
  1246. strcpy(conn->will.message, "");
  1247. conn->will.message_len = strlen(conn->will.message);
  1248. conn->timeout = 10; //1~60, default:5
  1249. conn->retry_times = 3;
  1250. conn->timeout_notice = 1;
  1251. conn->clean_session = 1;
  1252. conn->ssl_enable = 0;
  1253. conn->ssl_ctx_id = 0;
  1254. conn->msg_recv_mode = 0; //0: urc, 1: not urc
  1255. conn->msg_len_enable = 1;
  1256. conn->ping_interval = 5; //5~60, default:5
  1257. conn->proto_chk_enable = 0; //0:no check 1:check
  1258. conn->send_mode = 0; //0:string 1:hex
  1259. conn->recv_mode = 0; //0:string 1:hex
  1260. conn->view_mode = 0; //0:no echo 1:echo
  1261. conn->edit_mode = 0; //0:timeout not quit 1:timeout quit
  1262. conn->edit_time = 5; //1~120 seconds
  1263. //conn->plat.product_key[64]; //aliyun used
  1264. //conn->plat.device_name[64]; //aliyun used
  1265. //conn->plat.device_secret[64]; //aliyun/ used
  1266. //conn->plat.hw_time_enable; //huawei used
  1267. //conn->plat.product_secret[64]; //huawei used
  1268. //conn->plat.node_id[64];
  1269. //conn->plat.product_id[64]; //onenet used
  1270. //conn->plat.access_key[64]; //onenet used
  1271. sprintf(buf, "%d,%d", conn->cliId, conn->ver);
  1272. conn_cfg(conn, "version", buf);
  1273. sprintf(buf, "%d,%d", conn->cliId, conn->pdpId);
  1274. conn_cfg(conn, "pdpcid", buf);
  1275. sprintf(buf, "%d,%d", conn->cliId, conn->keep_alive_time);
  1276. conn_cfg(conn, "keepalive", buf);
  1277. sprintf(buf, "%d,%d", conn->cliId, conn->clean_session);
  1278. conn_cfg(conn, "session", buf);
  1279. sprintf(buf, "%d,%d,%d,%d", conn->cliId, conn->timeout, conn->retry_times, conn->timeout_notice);
  1280. conn_cfg(conn, "timeout", buf);
  1281. sprintf(buf, "%d,%d,%d", conn->cliId, conn->ssl_enable, conn->ssl_ctx_id);
  1282. conn_cfg(conn, "ssl", buf);
  1283. sprintf(buf, "%d,%d", conn->cliId, conn->ping_interval);
  1284. conn_cfg(conn, "qmtping", buf);
  1285. //sprintf(buf, "%d,%d,%d,%d,\"%s\",\"%s\"", conn->cliId, conn->will.flag, conn->will.qos, conn->will.retain, conn->will.topic, conn->will.message);
  1286. //conn_cfg(conn, "will", buf);
  1287. //sprintf(buf, "%d,%d,%d,%d,\"%s\",%d", conn->cliId, conn->will.flag, conn->will.qos, conn->will.retain, conn->will.topic, conn->will.message_len);
  1288. //conn_cfg(conn, "willex", buf);
  1289. sprintf(buf, "%d,%d", conn->cliId, conn->send_mode);
  1290. conn_cfg(conn, "send/mode", buf);
  1291. sprintf(buf, "%d,%d,%d", conn->cliId, conn->msg_recv_mode, conn->msg_len_enable);
  1292. conn_cfg(conn, "recv/mode", buf);
  1293. sprintf(buf, "%d,%d", conn->cliId, conn->view_mode);
  1294. conn_cfg(conn, "view/mode", buf);
  1295. sprintf(buf, "%d,%d,%d", conn->cliId, conn->edit_mode, conn->edit_time);
  1296. conn_cfg(conn, "edit/timeout", buf);
  1297. sprintf(buf, "%d,%d", conn->cliId, conn->proto_chk_enable);
  1298. conn_cfg(conn, "protocol/check", buf);
  1299. sprintf(buf, "%d,%d,%d", conn->cliId, conn->send_mode, conn->recv_mode);
  1300. conn_cfg(conn, "dataformat", buf);
  1301. #if 0 //aliyun
  1302. sprintf(buf, "%d,\"%s\",\"%s\",\"%s\"", conn->cliId, conn->plat.product_key, conn->plat.device_name, conn->plat.device_secret);
  1303. conn_cfg(conn, "aliauth", buf);
  1304. #endif
  1305. #if 0 //huawei
  1306. sprintf(buf, "%d,\"%s\",\"%s\"", conn->cliId, conn->plat.product_id, conn->plat.device_secret);
  1307. conn_cfg(conn, "hwauth", buf);
  1308. sprintf(buf, "%d,\"%s\",\"%s\",\"%s\"", conn->cliId, conn->plat.product_id, conn->plat.product_secret, conn->plat.node_id);
  1309. conn_cfg(conn, "hwprodid", buf);
  1310. #endif
  1311. #if 0 //onenet
  1312. sprintf(buf, "%d,\"%s\",\"%s\"", conn->cliId, conn->plat.product_id, conn->plat.access_key);
  1313. conn_cfg(conn, "onenet", buf);
  1314. #endif
  1315. }
  1316. static int cell_test(cell_handle_t *h)
  1317. {
  1318. int r;
  1319. cell_info_t info;
  1320. cell_stat_t stat;
  1321. cell_get_info(h, &info);
  1322. while(1) {
  1323. r = cell_get_stat(h, &stat);
  1324. if(r==0) {
  1325. LOGD("___dbm: %d ber: %d\n", stat.dbm, stat.ber);
  1326. }
  1327. else {
  1328. LOGE("___ get stat failed\n");
  1329. }
  1330. sleep(3);
  1331. }
  1332. return 0;
  1333. }
  1334. /////////////////////////////////////////////////////////////////////////
  1335. static int urc_handle(char *data, int len)
  1336. {
  1337. char *key=NULL;
  1338. key = "+QIURC: ";
  1339. if(strstr(data, key)) {
  1340. }
  1341. key = "+QMT";
  1342. if(strstr(data, key)) {
  1343. }
  1344. return 0;
  1345. }
  1346. static void* cellular_thread(void *arg)
  1347. {
  1348. int r;
  1349. uint32_t cnt=0,prelinkcnt=0;
  1350. char rxbuf[BUF_LEN];
  1351. thread_handle_t *th=(thread_handle_t*)arg;
  1352. cell_handle_t *h=(cell_handle_t*)th->arg;
  1353. int nlinkedflag=0;
  1354. port_init(h);
  1355. while (th->quit==0) {
  1356. cnt++;
  1357. if(h->pcell->mode) {
  1358. if (h->fd<0)
  1359. {
  1360. port_init(h);
  1361. }
  1362. if(cnt%5==0) {
  1363. cell_init(h);
  1364. }
  1365. if (cnt % 5 == 0)
  1366. {
  1367. // cell_get_info(h, &h->all.info);
  1368. cell_get_stat(h, &h->all.stat);
  1369. }
  1370. if (h->all.stat.linked == 1)
  1371. {
  1372. prelinkcnt = cnt;
  1373. }
  1374. else
  1375. {
  1376. if (nlinkedflag == 1)
  1377. {
  1378. nic_set(NIC_USB, 0);
  1379. }
  1380. reset_var(h);
  1381. if (cnt - prelinkcnt >= 60)
  1382. {
  1383. prelinkcnt = cnt;
  1384. cell_reset(h);
  1385. }
  1386. }
  1387. nlinkedflag=h->all.stat.linked;
  1388. }
  1389. else
  1390. {
  1391. if( h->fd>=0)
  1392. {
  1393. //cell_sock_disconn_all(h);
  1394. cell_deinit(h);
  1395. port_deinit(h);
  1396. }
  1397. reset_var(h);
  1398. }
  1399. UpdateCellularManager(&h->all);
  1400. sleep(1);
  1401. }
  1402. //cell_sock_disconn_all(h);
  1403. reset_var(h);
  1404. UpdateCellularManager(&h->all);
  1405. cell_deinit(h);
  1406. port_deinit(h);
  1407. pthread_exit(NULL);
  1408. }
  1409. int cellular_reset(void)
  1410. {
  1411. int r=-1;
  1412. cell_handle_t *h=&ceHandle;
  1413. r = cell_reset(h);
  1414. return r;
  1415. }
  1416. int cellular_init(void)
  1417. {
  1418. int r;
  1419. cell_handle_t *h=&ceHandle;
  1420. if (__globalDeviceManage._globalDevInfo.cell.Cellular_enable && __globalDeviceManage._globalDevInfo.cell.mode && !thread_is_running(THREAD_ID_CELLULAR))
  1421. {
  1422. memset(h, 0, sizeof(cell_handle_t));
  1423. h->dm = &__globalDeviceManage;
  1424. h->pcell = &h->dm->_globalDevInfo.cell;
  1425. strcpy( h->prod_id,h->dm->_globalDevInfo.product.number);
  1426. // h->lck = lock_d_init();
  1427. //nic_set(NIC_USB, 1);
  1428. dev_SMS_get(h->dm->db, h->pcell);
  1429. thread_start(THREAD_ID_CELLULAR, cellular_thread, h);
  1430. }
  1431. else return -1;
  1432. return 0;
  1433. }
  1434. int cellular_deinit(void)
  1435. {
  1436. cell_handle_t *h=&ceHandle;
  1437. if (__globalDeviceManage._globalDevInfo.cell.Cellular_enable && !__globalDeviceManage._globalDevInfo.cell.mode)
  1438. {
  1439. thread_stop(THREAD_ID_CELLULAR);
  1440. nic_set(NIC_USB, 0);
  1441. }
  1442. return 0;
  1443. }
  1444. int cellular_get_all(cell_all_t *all)
  1445. {
  1446. int r=-1;
  1447. cell_handle_t *h=&ceHandle;
  1448. if(all) {
  1449. *all = h->all;
  1450. r = 0;
  1451. }
  1452. return r;
  1453. }
  1454. int cellular_is_connected(void)
  1455. {
  1456. int r=0;
  1457. cell_handle_t *h=&ceHandle;
  1458. if (__globalDeviceManage._globalDevInfo.cell.Cellular_enable)
  1459. {
  1460. r = h->all.stat.linked;
  1461. }
  1462. return r;
  1463. }
  1464. int UpdateCellularManager( cell_all_t *all)
  1465. {
  1466. int r = -1;
  1467. if (all)
  1468. {
  1469. __globalDeviceManage._globalDevInfo.cell.Link_status = all->stat.linked;
  1470. __globalDeviceManage._globalDevInfo.cell.Signal_strength = all->stat.dbm;
  1471. strcpy( __globalDeviceManage._globalDevInfo.cell.apn , all->info.apn);
  1472. strcpy( __globalDeviceManage._globalDevInfo.cell.Cellular_name , all->info.isp);
  1473. strcpy( __globalDeviceManage._globalDevInfo.cell.Cellular_Num , all->info.imei);
  1474. strcpy(__globalDeviceManage._globalDevInfo.cell.ipv4, all->stat.ipv4);
  1475. strcpy(__globalDeviceManage._globalDevInfo.cell.ipv6, all->stat.ipv6);
  1476. r = 0;
  1477. }
  1478. return r;
  1479. }
  1480. int cellular_test(void)
  1481. {
  1482. cell_handle_t *h=&ceHandle;
  1483. cell_test(h);
  1484. return 0;
  1485. }