jsonrtc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * This file is part of the jsonrtc.
  3. * written in 2018 by Helmut Pozimski.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, version 2.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <kore/kore.h>
  18. #include <kore/http.h>
  19. #include <fcntl.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <sys/ioctl.h>
  23. #include <linux/rtc.h>
  24. #include <cjson/cJSON.h>
  25. #define IOCTL_DS13307_ALRM _IOR('p', 0x15, unsigned char)
  26. int page(struct http_request *);
  27. int handle_time(struct http_request *);
  28. int handle_wkalrm(struct http_request *);
  29. int detect_device(struct http_request *);
  30. int handle_nvmem(struct http_request *);
  31. int
  32. page(struct http_request *req)
  33. {
  34. http_response(req, 200, NULL, 0);
  35. return (KORE_RESULT_OK);
  36. }
  37. static char * read_body(struct http_request *req) {
  38. int ret;
  39. struct kore_buf * buf;
  40. u_int8_t data[128];
  41. char * body;
  42. buf = kore_buf_alloc(128);
  43. while(1) {
  44. ret = http_body_read(req, data, sizeof(data));
  45. if (ret == -1) {
  46. kore_buf_free(buf);
  47. return NULL;
  48. } else if (ret == 0) {
  49. break;
  50. }
  51. kore_buf_append(buf,data,ret);
  52. }
  53. body = kore_buf_stringify(buf, NULL);
  54. kore_buf_free(buf);
  55. return body;
  56. }
  57. int handle_time(struct http_request *req) {
  58. int fdesc;
  59. struct rtc_time time;
  60. int ret;
  61. char *result_string;
  62. cJSON *time_json, *json_min, *json_hour, *json_mday,
  63. *json_mon, *json_year, *json_sec, *json_wday;
  64. if(req->method == HTTP_METHOD_GET) {
  65. time_json = cJSON_CreateObject();
  66. fdesc = open("/dev/rtc", O_RDONLY);
  67. ret = ioctl(fdesc, RTC_RD_TIME, &time);
  68. close(fdesc);
  69. if (!ret) {
  70. json_sec = cJSON_CreateNumber(time.tm_sec);
  71. json_min = cJSON_CreateNumber(time.tm_min);
  72. json_hour = cJSON_CreateNumber(time.tm_hour);
  73. json_mday = cJSON_CreateNumber(time.tm_mday);
  74. json_mon = cJSON_CreateNumber(time.tm_mon);
  75. json_year = cJSON_CreateNumber(time.tm_year);
  76. json_wday = cJSON_CreateNumber(time.tm_wday);
  77. cJSON_AddItemToObject(time_json, "seconds", json_sec);
  78. cJSON_AddItemToObject(time_json, "minutes", json_min);
  79. cJSON_AddItemToObject(time_json, "hour", json_hour);
  80. cJSON_AddItemToObject(time_json, "mday", json_mday);
  81. cJSON_AddItemToObject(time_json, "month", json_mon);
  82. cJSON_AddItemToObject(time_json, "year", json_year);
  83. cJSON_AddItemToObject(time_json, "wday", json_wday);
  84. result_string = cJSON_Print(time_json);
  85. cJSON_Delete(time_json);
  86. http_response_header(req, "Content-Type", "application/json");
  87. http_response_header(req, "Access-Control-Allow-Origin", "*");
  88. http_response(req, 200, result_string, strlen(result_string));
  89. return KORE_RESULT_OK;
  90. }
  91. cJSON_Delete(time_json);
  92. result_string = "Error: could not get time from /dev/rtc\n";
  93. http_response(req, 500, result_string, strlen(result_string));
  94. return KORE_RESULT_OK;
  95. } else if (req->method == HTTP_METHOD_POST) {
  96. char * body;
  97. body = read_body(req);
  98. if (body == NULL) {
  99. result_string = "Error: could not read request body\n";
  100. http_response(req, 500, result_string, strlen(result_string));
  101. return (KORE_RESULT_OK);
  102. }
  103. time_json = cJSON_Parse(body);
  104. if (time_json == NULL) {
  105. result_string = "Error: could not parse json\n";
  106. http_response(req, 500, result_string, strlen(result_string));
  107. return (KORE_RESULT_OK);
  108. }
  109. json_sec = cJSON_GetObjectItemCaseSensitive(time_json, "seconds");
  110. json_min = cJSON_GetObjectItemCaseSensitive(time_json, "minutes");
  111. json_hour = cJSON_GetObjectItemCaseSensitive(time_json, "hour");
  112. json_mday = cJSON_GetObjectItemCaseSensitive(time_json, "mday");
  113. json_mon = cJSON_GetObjectItemCaseSensitive(time_json, "month");
  114. json_year = cJSON_GetObjectItemCaseSensitive(time_json, "year");
  115. json_wday = cJSON_GetObjectItemCaseSensitive(time_json, "wday");
  116. if (cJSON_IsNumber(json_sec) && cJSON_IsNumber(json_min) && cJSON_IsNumber(json_hour) &&
  117. cJSON_IsNumber(json_mday) && cJSON_IsNumber(json_mon) &&
  118. cJSON_IsNumber(json_year) && cJSON_IsNumber(json_wday)) {
  119. time.tm_sec = json_sec->valueint;
  120. time.tm_min = json_min->valueint;
  121. time.tm_hour = json_hour->valueint;
  122. time.tm_mday = json_mday->valueint;
  123. time.tm_mon = json_mon->valueint;
  124. time.tm_year = json_year->valueint;
  125. time.tm_wday = json_wday->valueint;
  126. } else {
  127. cJSON_Delete(time_json);
  128. result_string = "Error: invalid or missing values in json object\n";
  129. http_response(req, 500, result_string, strlen(result_string));
  130. return (KORE_RESULT_OK);
  131. }
  132. cJSON_Delete(time_json);
  133. fdesc = open("/dev/rtc", O_WRONLY);
  134. ret = ioctl(fdesc, RTC_SET_TIME, &time);
  135. close(fdesc);
  136. if (ret) {
  137. result_string = "Error: Could not set time via /dev/rtc\n";
  138. http_response(req, 500, result_string, strlen(result_string));
  139. return (KORE_RESULT_OK);
  140. }
  141. http_response_header(req, "Access-Control-Allow-Origin", "*");
  142. http_response(req, 200, NULL, 0);
  143. return KORE_RESULT_OK;
  144. } else {
  145. http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0);
  146. return (KORE_RESULT_OK);
  147. }
  148. }
  149. int handle_wkalrm(struct http_request *req) {
  150. char *result_string;
  151. struct rtc_wkalrm alarm;
  152. int fdesc, ret;
  153. unsigned char alarm_bit;
  154. cJSON *alarm_json, *json_min, *json_hour, *json_mday,
  155. *json_mon, *json_year, *json_sec, *json_wday,
  156. *json_enabled, *json_pending;
  157. if(req->method == HTTP_METHOD_GET) {
  158. alarm_json = cJSON_CreateObject();
  159. fdesc = open("/dev/rtc", O_RDONLY);
  160. ret = ioctl(fdesc, RTC_WKALM_RD, &alarm);
  161. ret |= ioctl(fdesc, IOCTL_DS13307_ALRM, &alarm_bit);
  162. close(fdesc);
  163. if (!ret) {
  164. json_sec = cJSON_CreateNumber(alarm.time.tm_sec);
  165. json_min = cJSON_CreateNumber(alarm.time.tm_min);
  166. json_hour = cJSON_CreateNumber(alarm.time.tm_hour);
  167. json_mday = cJSON_CreateNumber(alarm.time.tm_mday);
  168. json_mon = cJSON_CreateNumber(alarm.time.tm_mon);
  169. json_year = cJSON_CreateNumber(alarm.time.tm_year);
  170. json_wday = cJSON_CreateNumber(alarm.time.tm_wday);
  171. json_enabled = cJSON_CreateNumber(alarm.enabled);
  172. json_pending = cJSON_CreateNumber(alarm_bit);
  173. cJSON_AddItemToObject(alarm_json, "seconds", json_sec);
  174. cJSON_AddItemToObject(alarm_json, "minutes", json_min);
  175. cJSON_AddItemToObject(alarm_json, "hour", json_hour);
  176. cJSON_AddItemToObject(alarm_json, "mday", json_mday);
  177. cJSON_AddItemToObject(alarm_json, "month", json_mon);
  178. cJSON_AddItemToObject(alarm_json, "year", json_year);
  179. cJSON_AddItemToObject(alarm_json, "wday", json_wday);
  180. cJSON_AddItemToObject(alarm_json, "enabled", json_enabled);
  181. cJSON_AddItemToObject(alarm_json, "pending", json_pending);
  182. result_string = cJSON_Print(alarm_json);
  183. cJSON_Delete(alarm_json);
  184. http_response_header(req, "Content-Type", "application/json");
  185. http_response_header(req, "Access-Control-Allow-Origin", "*");
  186. http_response(req, 200, result_string, strlen(result_string));
  187. return KORE_RESULT_OK;
  188. }
  189. cJSON_Delete(alarm_json);
  190. result_string = "Error: could not get alarm from /dev/rtc\n";
  191. http_response(req, 500, result_string, strlen(result_string));
  192. return KORE_RESULT_OK;
  193. } else if (req->method == HTTP_METHOD_POST) {
  194. char * body = read_body(req);
  195. if (body == NULL) {
  196. result_string = "Error: could not read request body\n";
  197. http_response(req, 500, result_string, strlen(result_string));
  198. return (KORE_RESULT_OK);
  199. }
  200. alarm_json = cJSON_Parse(body);
  201. if (alarm_json == NULL) {
  202. result_string = "Error: could not parse json\n";
  203. http_response(req, 500, result_string, strlen(result_string));
  204. return (KORE_RESULT_OK);
  205. }
  206. json_sec = cJSON_GetObjectItemCaseSensitive(alarm_json, "seconds");
  207. json_min = cJSON_GetObjectItemCaseSensitive(alarm_json, "minutes");
  208. json_hour = cJSON_GetObjectItemCaseSensitive(alarm_json, "hour");
  209. json_mday = cJSON_GetObjectItemCaseSensitive(alarm_json, "mday");
  210. json_mon = cJSON_GetObjectItemCaseSensitive(alarm_json, "month");
  211. json_year = cJSON_GetObjectItemCaseSensitive(alarm_json, "year");
  212. json_wday = cJSON_GetObjectItemCaseSensitive(alarm_json, "wday");
  213. json_enabled = cJSON_GetObjectItemCaseSensitive(alarm_json, "enabled");
  214. if (cJSON_IsNumber(json_sec) && cJSON_IsNumber(json_min) && cJSON_IsNumber(json_hour) &&
  215. cJSON_IsNumber(json_mday) && cJSON_IsNumber(json_mon) &&
  216. cJSON_IsNumber(json_year) && cJSON_IsNumber(json_wday) &&
  217. cJSON_IsNumber(json_enabled)) {
  218. alarm.time.tm_sec = json_sec->valueint;
  219. alarm.time.tm_min = json_min->valueint;
  220. alarm.time.tm_hour = json_hour->valueint;
  221. alarm.time.tm_mday = json_mday->valueint;
  222. alarm.time.tm_mon = json_mon->valueint;
  223. alarm.time.tm_year = json_year->valueint;
  224. alarm.time.tm_wday = json_wday->valueint;
  225. alarm.enabled = json_enabled->valueint;
  226. } else {
  227. cJSON_Delete(alarm_json);
  228. result_string = "Error: invalid or missing values in json object\n";
  229. http_response(req, 500, result_string, strlen(result_string));
  230. return (KORE_RESULT_OK);
  231. }
  232. cJSON_Delete(alarm_json);
  233. fdesc = open("/dev/rtc", O_WRONLY);
  234. ret = ioctl(fdesc, RTC_WKALM_SET, &alarm);
  235. close(fdesc);
  236. if (ret) {
  237. result_string = "Error: Could not set alarm via /dev/rtc\n";
  238. http_response(req, 500, result_string, strlen(result_string));
  239. return (KORE_RESULT_OK);
  240. }
  241. http_response_header(req, "Access-Control-Allow-Origin", "*");
  242. http_response(req, 200, NULL, 0);
  243. return KORE_RESULT_OK;
  244. } else {
  245. http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0);
  246. return (KORE_RESULT_OK);
  247. }
  248. }
  249. int detect_device(struct http_request *req) {
  250. if(req->method == HTTP_METHOD_GET) {
  251. http_response_header(req, "Access-Control-Allow-Origin", "*");
  252. if (access("/sys/bus/nvmem/devices/ds1307_nvram0/nvmem", F_OK) != -1) {
  253. http_response(req, 200, "DS1307", 6);
  254. } else {
  255. http_response(req, 200, "DS1337", 6);
  256. }
  257. return KORE_RESULT_OK;
  258. } else {
  259. http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0);
  260. return (KORE_RESULT_OK);
  261. }
  262. }
  263. int handle_nvmem(struct http_request *req) {
  264. int fdesc, bytes_read;
  265. unsigned char buf[56];
  266. char r_string[113];
  267. char buf2[3];
  268. char * result_object;
  269. char * result_string;
  270. cJSON *json_response, *json_string;
  271. if(req->method == HTTP_METHOD_GET) {
  272. fdesc = open("/sys/bus/nvmem/devices/ds1307_nvram0/nvmem", O_RDONLY);
  273. bytes_read = read(fdesc, &buf, 56);
  274. close(fdesc);
  275. if(bytes_read == 56) {
  276. r_string[112] = '\0';
  277. for(int i=0; i<56; i++) {
  278. if (buf[i] <= 15) {
  279. sprintf(buf2, "0%x", buf[i]);
  280. } else {
  281. sprintf(buf2, "%x", buf[i]);
  282. }
  283. strcpy(r_string + i*2, buf2);
  284. }
  285. json_response = cJSON_CreateObject();
  286. json_string = cJSON_CreateString(r_string);
  287. cJSON_AddItemToObject(json_response, "content", json_string);
  288. result_object = cJSON_Print(json_response);
  289. cJSON_Delete(json_response);
  290. http_response_header(req, "Content-Type", "application/json");
  291. http_response_header(req, "Access-Control-Allow-Origin", "*");
  292. http_response(req, 200, result_object, strlen(result_object));
  293. } else {
  294. result_string = "Error: could not read from nvmem\n";
  295. http_response(req, 500, result_string, strlen(result_string));
  296. }
  297. return KORE_RESULT_OK;
  298. } else if (req->method == HTTP_METHOD_POST) {
  299. unsigned char to_write[56];
  300. int buf3 = 0;
  301. int bytes_written;
  302. cJSON *body_json, *input_json;
  303. char * input_string;
  304. char * body = read_body(req);
  305. if (body == NULL) {
  306. result_string = "Error: could not read request body\n";
  307. http_response(req, 500, result_string, strlen(result_string));
  308. return (KORE_RESULT_OK);
  309. }
  310. body_json = cJSON_Parse(body);
  311. input_json = cJSON_GetObjectItemCaseSensitive(body_json, "content");
  312. if (cJSON_IsString(input_json)) {
  313. input_string = input_json->valuestring;
  314. } else {
  315. result_string = "Error: invalid value in json content\n";
  316. http_response(req, 500, result_string, strlen(result_string));
  317. return (KORE_RESULT_OK);
  318. }
  319. for (int i=0; i<112; i++) {
  320. if(i%2 == 0) {
  321. buf3 = 0;
  322. } else {
  323. buf3 = buf3 <<4;
  324. }
  325. if((input_string[i] >= '0') && (input_string[i] <= '9')) {
  326. buf3 += input_string[i] - '0';
  327. } else if ((input_string[i] >= 'A') && (input_string[i] <= 'Z')) {
  328. buf3 += input_string[i] - 55;
  329. }
  330. if (i%2 != 0) {
  331. to_write[i/2] = (unsigned char) buf3;
  332. }
  333. }
  334. cJSON_Delete(body_json);
  335. fdesc = open("/sys/bus/nvmem/devices/ds1307_nvram0/nvmem", O_WRONLY);
  336. bytes_written = write(fdesc, to_write, 56);
  337. close(fdesc);
  338. if (bytes_written == 56) {
  339. http_response_header(req, "Access-Control-Allow-Origin", "*");
  340. http_response(req, 200, NULL, 0);
  341. return (KORE_RESULT_OK);
  342. }
  343. result_string = "Error: could not write to nvmem\n";
  344. http_response(req, 500, result_string, strlen(result_string));
  345. return (KORE_RESULT_OK);
  346. } else {
  347. http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0);
  348. return (KORE_RESULT_OK);
  349. }
  350. }