cra.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <syslog.h>
  6. #include <stdint.h>
  7. #include <math.h>
  8. #include <curl/curl.h>
  9. #include <confuse.h>
  10. #include "libyuarel/yuarel.h"
  11. #include "json-c/json.h"
  12. #include "sensob/sensob.h"
  13. #include "aes.h"
  14. //#include "../../status.h"
  15. #include "../../feeder.h"
  16. #define RECVD_HISTORY_SIZE 32//must be dividable by 8
  17. typedef struct unit_t
  18. {
  19. uint32_t id;
  20. uint8_t recvd[RECVD_HISTORY_SIZE];
  21. uint8_t pos, recvd_size;
  22. uint32_t seq;
  23. uint8_t ack;
  24. struct unit_t * next;
  25. } unit_t;
  26. static struct unit_t * units, * unit_now;
  27. static uint64_t jid = 0;
  28. //static uint32_t seq;
  29. static uint8_t ack;
  30. static cfg_t * cfg;
  31. static void (* feederLog)(int priority, const char * fmt, ...);
  32. int setLog(void * func)
  33. {
  34. feederLog = (void(*)(int, const char * , ...))func;
  35. return 0;
  36. }
  37. int init(void * param)
  38. {
  39. (void)param;
  40. // seq = 0;
  41. units = unit_now = NULL;
  42. ack = 0;
  43. cfg_opt_t cfg_opts[] =
  44. {
  45. CFG_STR((char *)"url", 0, CFGF_NONE),
  46. CFG_STR((char *)"user", 0, CFGF_NONE),
  47. CFG_STR((char *)"pass", 0, CFGF_NONE),
  48. CFG_END()
  49. };
  50. cfg = cfg_init(cfg_opts, CFGF_NONE);
  51. if (cfg_parse(cfg, "cra.conf") != CFG_SUCCESS)
  52. {
  53. return -1;
  54. }
  55. curl_global_init(CURL_GLOBAL_DEFAULT);
  56. return 0;
  57. }
  58. struct unit_t * unitFind(struct unit_t * unit, uint32_t id)
  59. {
  60. while (unit != NULL)
  61. {
  62. if (unit->id == id)
  63. return unit;
  64. unit = unit->next;
  65. }
  66. return NULL;
  67. }
  68. struct unit_t * unitCreate(uint32_t id)
  69. {
  70. struct unit_t * unit;
  71. unit = (struct unit_t *)malloc(sizeof(struct unit_t));
  72. unit->id = id;
  73. memset(unit->recvd, 0, RECVD_HISTORY_SIZE);
  74. unit->seq = 0;
  75. unit->pos = 0;
  76. unit->next = NULL;
  77. return unit;
  78. }
  79. void unitUpdateRecvd(struct unit_t * unit, uint8_t flag)
  80. {
  81. unit->recvd[unit->pos++] = flag;
  82. if (unit->pos > RECVD_HISTORY_SIZE)
  83. unit->pos = 0;
  84. }
  85. void stringToArrayn(uint8_t * data, char * str, uint16_t len)
  86. {
  87. uint16_t i;
  88. uint8_t j;
  89. char c;
  90. for (i = 0; i < len; i++)
  91. {
  92. data[i] = 0;
  93. for (j = 0; j < 2; j++)
  94. {
  95. c = str[i * 2 + j];
  96. if (c >= 'a') //to high case
  97. c -= 0x20;
  98. data[i] += (c - ((c < 'A')?'0':'7')) << ((j == 0)?4:0);
  99. }
  100. }
  101. }
  102. void arraynToString(char * str, uint8_t * data, uint16_t len)
  103. {
  104. uint16_t i;
  105. uint8_t j;
  106. char c;
  107. for (i = 0; i < len; i++)
  108. {
  109. for (j = 0; j < 2; j++)
  110. {
  111. c = (data[i] >> ((j == 0)?4:0)) & 0x0F;
  112. str[i * 2 + j] = c + ((c < 0x0A)?'0':'7');
  113. }
  114. }
  115. str[len * 2] = '\0';
  116. }
  117. #define CMD_DATETIME_REQ 0xD0
  118. #define CMD_DATETIME_SYNC 0xD1
  119. #define CMD_DATETIME_RESPONSE 0xD2
  120. #define CMD_VARVAL 0xD3
  121. #define CMD_NONE 0xCF
  122. typedef struct cmd_datetimereq_t
  123. {
  124. uint32_t tm;
  125. } __attribute__((packed)) cmd_datetimereq_t;
  126. typedef struct cmd_datetimeresponse_t
  127. {
  128. int32_t diff;
  129. } __attribute__((packed)) cmd_datetimeresponse_t;
  130. typedef struct cmd_datetimesync_t
  131. {
  132. } __attribute__((packed)) cmd_datetimesync_t;
  133. typedef struct cmd_header_t
  134. {
  135. // uint8_t delimiter;
  136. // uint64_t id;
  137. uint8_t cmd;
  138. } __attribute__((packed)) cmd_header_t;
  139. typedef struct cmd_footer_t
  140. {
  141. // uint16_t crc;
  142. } __attribute__((packed)) cmd_footer_t;
  143. int curlDebug(CURL * curl, curl_infotype info, char * string, size_t size, void * data)
  144. {
  145. (void)curl;
  146. (void)data;
  147. if (feederLog != NULL)
  148. {
  149. if (info == CURLINFO_TEXT)
  150. {
  151. string[size] = 0;
  152. feederLog(LOG_DEBUG, "cra: curl debug: %s", string);
  153. }
  154. }
  155. return 0;
  156. }
  157. typedef struct cb_t
  158. {
  159. uint8_t cmd;
  160. } cb_t;
  161. size_t curlWriteCB(void *contents, size_t size, size_t nmemb, void *userp)
  162. {
  163. size_t realsize;
  164. char * fetch = (char *)userp;
  165. realsize = size * nmemb;
  166. feederLog(LOG_DEBUG, "cra: Fetched %s\n", (char *)contents);
  167. memcpy(fetch, contents, realsize);
  168. fetch[realsize] = 0;
  169. /* return size */
  170. return realsize;
  171. }
  172. void craApi(char * method, char * header_id, char * req_body, char * fetch)
  173. {
  174. CURL *ch;
  175. CURLcode res;
  176. char url[1024];
  177. char post[2048];
  178. char header[256];
  179. int info;
  180. struct curl_slist * headers = NULL;
  181. ch = curl_easy_init();
  182. if (ch)
  183. {
  184. curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, curlDebug);
  185. curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
  186. // strcpy(url, "http://82.99.180.180/Message");
  187. // strcpy(url, "https://api.iot.cra.cz/cxf/IOTServices/v2/");
  188. strcpy(url, cfg_getstr(cfg, "url"));
  189. strcpy(url + strlen(url), method);
  190. curl_easy_setopt(ch, CURLOPT_URL, url);
  191. curl_easy_setopt(ch, CURLOPT_POST, 1L);
  192. headers = curl_slist_append(headers, "Accept: application/json");
  193. headers = curl_slist_append(headers, "Content-Type: application/json");
  194. if (header_id != NULL)
  195. {
  196. strcpy(header, "SessionId: ");
  197. strcpy(header + strlen(header), header_id);
  198. headers = curl_slist_append(headers, header);
  199. }
  200. curl_easy_setopt(ch, CURLOPT_HTTPHEADER, headers);
  201. // curl_easy_setopt(ch, CURLOPT_HEADER, 0);
  202. // curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0);
  203. /* sprintf((char *)post,
  204. "{\r\n\t\"EUI\": \"%s\",\r\n\t\"data\": \"{\\\"cmd\\\":\\\"tx\\\",\\\"port\\\":1,\\\"data\\\":\\\"%s\\\",\\\"EUI\\\":\\\"%s\\\"}\"\r\n}\r\n",
  205. "0004A30B0022088F", "2C","0004A30B0022088F");
  206. */
  207. strcpy(post, req_body);
  208. curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, "POST");
  209. curl_easy_setopt(ch, CURLOPT_POSTFIELDS, post);
  210. curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, strlen(post));
  211. // cf.payload = (char *)calloc(1, sizeof(cf.payload));
  212. // cf.size = 0;
  213. // curl_easy_setopt(ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); //!!!!!!!!!!!!
  214. if (fetch != NULL)
  215. {
  216. curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, curlWriteCB);
  217. curl_easy_setopt(ch, CURLOPT_WRITEDATA, (void *)fetch);
  218. }
  219. // res = curl_fetch_url(curl_g, path, &cf);
  220. feederLog(LOG_INFO, "cra: %s %s\n", url, post);
  221. res = curl_easy_perform(ch);
  222. curl_easy_cleanup(ch);
  223. curl_easy_getinfo(ch, CURLINFO_HTTP_CODE, &info);
  224. if (res != CURLE_OK)
  225. {
  226. feederLog(LOG_ERR, "cra: curl POST error %d\n", res);
  227. return;
  228. }
  229. if (info != 200)
  230. {
  231. feederLog(LOG_ERR, "cra: curl page error %d\n", info);
  232. return;
  233. }
  234. }
  235. }
  236. char * craLogin(void)
  237. {
  238. char fetch[2048];
  239. char req[1024];
  240. json_object * json;
  241. enum json_tokener_error jerr = json_tokener_success;
  242. char * id = NULL;
  243. // craApi((char *)"Login", NULL, (char *)"{\r\n\t\"username\": \"krivanek@lesprojekt.cz\",\r\n\t\"password\": \"#LESPloRa2020@\"\r\n}\r\n", fetch);//todo: conf
  244. sprintf(req, (char *)"{\r\n\t\"username\": \"%s\",\r\n\t\"password\": \"%s\"\r\n}\r\n", cfg_getstr(cfg, "user"), cfg_getstr(cfg, "pass"));
  245. craApi((char *)"Login", NULL, req, fetch);//todo: conf
  246. json = json_tokener_parse_verbose(fetch, &jerr);
  247. if (jerr != json_tokener_success)
  248. {
  249. feederLog(LOG_ERR, "cra: Failed to parse json err %s\n", json_tokener_error_desc(jerr));
  250. json_object_put(json);
  251. return NULL;
  252. }
  253. id = (char *)json_object_get_string(json_object_object_get(json, "sessionId"));
  254. feederLog(LOG_INFO, "cra: Session id %s\n", id);
  255. return id;
  256. }
  257. void cmdMessage(uint8_t * d, uint64_t id, uint8_t cmd)
  258. {
  259. struct cmd_header_t * header;
  260. // struct cmd_footer_t * footer;
  261. (void)id;
  262. header = (struct cmd_header_t *)(d);
  263. // footer = (struct cmd_footer_t *)(d + sizeof(struct cmd_header_t) + cmd_tyope_size);//todo: footer
  264. // header->delimiter = '.';
  265. // header->id = id;
  266. header->cmd = cmd;
  267. }
  268. void cmdFooter(uint8_t * d, uint16_t len)
  269. {
  270. struct cmd_footer_t * footer;
  271. footer = (struct cmd_footer_t *)(d + len);
  272. // footer->crc = 0;//todo: spocitat
  273. }
  274. void cmdDateTimeReq(struct cmd_datetimereq_t * req, uint64_t id)
  275. {
  276. char body[2048];
  277. char message[256];
  278. uint8_t data[32];
  279. struct cmd_datetimeresponse_t * response;
  280. char * sid;
  281. time_t tm;
  282. int32_t diff;
  283. uint16_t len;
  284. tm = time(NULL);
  285. diff = tm - byteSwap32(req->tm);
  286. feederLog(LOG_INFO, "cra: device time %lld, system time %lld, difference %lld\n", byteSwap32(req->tm), tm, diff);
  287. cmdMessage(data, 0, CMD_DATETIME_RESPONSE);
  288. response = (struct cmd_datetimeresponse_t *)(data + sizeof(struct cmd_header_t));
  289. response->diff = byteSwap32(diff);
  290. cmdFooter(data, sizeof(struct cmd_header_t) + sizeof(struct cmd_datetimeresponse_t));
  291. len = sizeof(struct cmd_header_t) + sizeof(struct cmd_datetimeresponse_t) + sizeof(struct cmd_footer_t);
  292. sid = craLogin();
  293. if (sid != NULL)
  294. {
  295. arraynToString(message, data, len);
  296. /* sprintf((char *)body,
  297. "{\r\n\t\"EUI\": \"%s\",\r\n\t\"data\": \"{\\\"cmd\\\":\\\"tx\\\",\\\"port\\\":1,\\\"data\\\":\\\"%s\\\",\\\"EUI\\\":\\\"%s\\\"}\"\r\n}\r\n",
  298. "0004A30B0022088F", message,"0004A30B0022088F");*/
  299. sprintf((char *)body,
  300. "{\r\n\t\"EUI\": \"%016llX\",\r\n\t\"data\": \"{\\\"cmd\\\":\\\"tx\\\",\\\"port\\\":1,\\\"data\\\":\\\"%s\\\",\\\"EUI\\\":\\\"%016llX\\\"}\"\r\n}\r\n",
  301. id, message, id);
  302. craApi((char *)"Message", sid, body, NULL);
  303. }
  304. }
  305. void cmdParse(uint8_t * data, uint16_t len, uint64_t id)
  306. {
  307. struct cmd_header_t * header = (struct cmd_header_t *)data;
  308. (void)len;
  309. switch (header->cmd)
  310. {
  311. case CMD_DATETIME_REQ:
  312. feederLog(LOG_DEBUG, "cra: Cmd datetimereq\n");
  313. cmdDateTimeReq((struct cmd_datetimereq_t *)(data + sizeof(struct cmd_header_t)), id);
  314. break;
  315. case CMD_DATETIME_SYNC:
  316. feederLog(LOG_DEBUG, "cra: Cmd datetimesync\n");
  317. break;
  318. default:
  319. feederLog(LOG_ERR, "cra: Unknowen command %d\n", header->cmd);
  320. break;
  321. }
  322. }
  323. #define LW_KEY_LEN (16)
  324. unsigned int
  325. process(void *lib_data, int sock, unsigned char *data,
  326. unsigned int length, unsigned long long int *id, time_t * tm,
  327. double *result_array, uint64_t * sensors, unsigned int *type)
  328. {
  329. uint32_t seq;
  330. json_object *json, *json_data, * jdata;
  331. enum json_tokener_error jerr = json_tokener_success;
  332. char * data_json, * json_data_data_str;
  333. uint8_t json_data_data_bin[255];
  334. uint32_t json_data_ts_int;
  335. uint8_t json_data_bat_int;
  336. unsigned int res;
  337. (void)lib_data;
  338. (void)sock;
  339. if ((data == NULL) || (length == 0))
  340. {
  341. res = sensob_parse(NULL, 0, (uint64_t *)id, tm, result_array, sensors, type);
  342. *id = jid;
  343. // feederLog(LOG_DEBUG, "cra: item sensor %lu, value %f, type %d\n", sensors[0], result_array[0], *type);
  344. return res;
  345. }
  346. while (data[length - 1] < ' ')
  347. length--;
  348. data[length] = 0;
  349. feederLog(LOG_DEBUG, "cra: raw data in:\n%s\n", (char *)data);
  350. seq = 0;
  351. *id = 0;
  352. feederLog(LOG_DEBUG, "cra:1\n");
  353. data_json = strchr((char *)data, '{');//todo: proparsit i hlavicku
  354. if (data_json == NULL)
  355. {
  356. feederLog(LOG_ERR, "cra: Json not found\n");
  357. return -1;
  358. }
  359. json = json_tokener_parse_verbose(data_json, &jerr);
  360. if (jerr != json_tokener_success)
  361. {
  362. feederLog(LOG_ERR, "cra: Failed to parse json err %s\n", json_tokener_error_desc(jerr));
  363. json_object_put(json);
  364. return -1;
  365. }
  366. jdata = json_object_object_get(json, "data");
  367. // todo: check
  368. // feederLog(LOG_DEBUG, "cra: %s\n", json_object_get_string(jdata));
  369. json_data = json_tokener_parse_verbose(json_object_get_string(jdata), &jerr);
  370. jid = strtol(json_object_get_string(json_object_object_get(json_data, "EUI")), NULL, 16);
  371. feederLog(LOG_DEBUG, "cra: id %lld\n", *id);
  372. json_data_data_str = (char *)json_object_get_string(json_object_object_get(json_data, "data"));
  373. json_data_ts_int = json_object_get_int64(json_object_object_get(json_data, "ts")) / 1000;
  374. json_data_bat_int = json_object_get_int64(json_object_object_get(json_data, "bat"));
  375. if ((json_data_data_str == NULL) || (strlen(json_data_data_str) == 0))
  376. {
  377. /* json_data_data_str = (char *)json_object_get_string(json_object_object_get(json_data, "encdata"));
  378. feederLog(LOG_DEBUG, "cra: encdata %s\n", json_data_data_str);
  379. stringToArrayn(json_data_data_bin, json_data_data_str, strlen(json_data_data_str) / 2);
  380. aes_context aesContext;
  381. uint8_t aeskey[] = {0x45, 0xf3, 0x22, 0x67, 0x98, 0x95, 0x6f, 0xcd, 0x46, 0x67, 0x0b, 0x8c, 0x13, 0xb8, 0x23, 0x15};
  382. aes_set_key(aeskey, LW_KEY_LEN, &aesContext);
  383. aes_encrypt(json_data_data_bin, json_data_data_bin, &aesContext);
  384. */
  385. // feederLog(LOG_ERR, "cra: Encoded data not yet supported\n");
  386. feederLog(LOG_ERR, "cra: Data shape not yet supported\n");
  387. json_object_put(json);
  388. return -1;
  389. }
  390. else
  391. {
  392. feederLog(LOG_DEBUG, "cra: data %s\n", json_data_data_str);
  393. stringToArrayn(json_data_data_bin, json_data_data_str, strlen(json_data_data_str) / 2);
  394. }
  395. feederLog(LOG_DEBUG, "cra: binary data: ");
  396. uint16_t i;
  397. for (i = 0; i < (strlen(json_data_data_str) / 2); i++)
  398. feederLog(LOG_DEBUG, "%02X ", json_data_data_bin[i]);
  399. feederLog(LOG_DEBUG, "\n");
  400. if (json_data_data_bin[0] == 0xFF)//this is sensob message
  401. {
  402. feederLog(LOG_DEBUG, "cra: sensob detected\n");
  403. res = sensob_parse(json_data_data_bin, strlen(json_data_data_str) / 2, (uint64_t *)id, tm, result_array, sensors, type);
  404. feederLog(LOG_DEBUG, "cra: item sensor %lu, value %f, type %d\n", sensors[0], result_array[0], *type);
  405. *id = jid;
  406. }
  407. // else if (json_data_data_bin[0] == 0xFE)//this is command todo: nebo rozlisit podle portu
  408. else if (json_data_data_bin[0] > 0xC0)//this is command todo: nebo rozlisit podle portu
  409. {
  410. feederLog(LOG_DEBUG, "cra: cmd detected\n");
  411. cmdParse(json_data_data_bin, strlen(json_data_data_str) / 2, jid);
  412. }
  413. else if (json_data_data_bin[0] >= 0xA0) //this is sensob tiny message
  414. {
  415. feederLog(LOG_DEBUG, "cra: sensob tiny detected\n");
  416. res = sensobtiny_parse(json_data_data_bin, strlen(json_data_data_str) / 2, json_data_ts_int, tm, result_array, sensors, type);
  417. *id = jid;
  418. }
  419. else //this is sensob lite message
  420. {
  421. feederLog(LOG_DEBUG, "cra: sensob lite detected\n");
  422. res = sensoblite_parse(json_data_data_bin, strlen(json_data_data_str) / 2, tm, result_array, sensors, type);
  423. *id = jid;
  424. }
  425. result_array[res] = (double)json_data_bat_int; //get lora battery status as sensor measurement
  426. sensors[res] = 560030000;
  427. res++;
  428. return res;
  429. }
  430. int reply(void * lib_data, int sock, unsigned char *data)
  431. {
  432. struct unit_t * unit;
  433. char * buf;
  434. (void)lib_data;
  435. (void)sock;
  436. unit = unit_now;
  437. if (unit == NULL)
  438. {
  439. //todo: odpovededet nejakym chybou
  440. return 0;
  441. }
  442. if (unit->seq == 0)
  443. return 0;
  444. time((time_t *)data);
  445. /*todo
  446. memset(data + 4, 0, 4);
  447. for (i = 0; i < RECVD_HISTORY_SIZE; i++)
  448. {
  449. j = unit->pos - (RECVD_HISTORY_SIZE + i);
  450. if (j > RECVD_HISTORY_SIZE) //rotated (less then zero)
  451. j += RECVD_HISTORY_SIZE;
  452. data[4 + i / 8] |= unit->recvd[j] << (i % 8);
  453. }
  454. */
  455. buf = (char *)data;
  456. time_t now = time(0);
  457. struct tm tm = *gmtime(&now);
  458. sprintf(buf, "HTTP/1.0 204 NO CONTENT\r\nServer: feeder\r\nContent-Length: %d\r\nDate: ", 0);
  459. strftime(buf + strlen(buf), 1000, "%a, %d %b %Y %H:%M:%S %Z", &tm);
  460. sprintf(buf + strlen(buf), "\r\n\r\n");
  461. feederLog(LOG_DEBUG, "cra: raw data out: \n%s\n", (char *)data);
  462. feederLog(LOG_DEBUG, "cra: replying\n");
  463. unit->seq = 0;
  464. return strlen((char *)data);
  465. }