gtk2 sam7fc telemetrie application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
9.4KB

  1. /***************************************************************************
  2. * Copyright (C) 04/2008 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  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 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU 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, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdint.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <errno.h>
  24. #include <glib.h>
  25. #include <gdk/gdk.h>
  26. #include "sockaddr.h"
  27. #include "tcpsocket.h"
  28. #include "tdc_parser.h"
  29. #include "tdc_proto.h"
  30. #include "tdc_store.h"
  31. #include "tdc_variable.h"
  32. static int socket_fd;
  33. static gint socket_tag;
  34. static void (*socket_status_cb)(int status);
  35. static GByteArray *socket_stream;
  36. static int tdcparser_send(struct tdc_pkt_header *pkt)
  37. {
  38. return write(socket_fd, pkt, pkt->size);
  39. }
  40. void tdcparser_send_hello(void)
  41. {
  42. int addr;
  43. for (addr = 1; addr < 8; addr++) {
  44. struct tdc_pkt_header pkt;
  45. pkt.cmd = (addr << 4) | TDC_HELLO;
  46. pkt.size = sizeof(pkt);
  47. tdcparser_send(&pkt);
  48. }
  49. }
  50. int tdcparser_send_getvars(int address)
  51. {
  52. struct tdc_pkt_header pkt;
  53. pkt.cmd = (address << 4) | TDC_GETVARS;
  54. pkt.size = sizeof(pkt);
  55. return tdcparser_send(&pkt);
  56. }
  57. int tdcparser_send_getvalue(int address, int id)
  58. {
  59. struct tdc_getvalue_request pkt;
  60. pkt.cmd = (address << 4) | TDC_GETVALUE;
  61. pkt.size = sizeof(pkt);
  62. pkt.id = (id & 0xFF);
  63. return tdcparser_send((struct tdc_pkt_header *)&pkt);
  64. }
  65. int tdcparser_send_setvalue(int address, int id)
  66. {
  67. struct tdc_var *var = tdcstore_get_var(address, id);
  68. if (var == NULL)
  69. return -1;
  70. int datasize = (var->flags & TDC_SIZEMASK);
  71. struct tdc_setvalue_request *pkt;
  72. pkt = g_malloc0(sizeof(*pkt) + datasize);
  73. pkt->cmd = (address << 4) | TDC_SETVALUE;
  74. pkt->size = sizeof(*pkt) + datasize;
  75. pkt->id = (id & 0xFF);
  76. memcpy(pkt->data, &var->data, datasize);
  77. int retval = tdcparser_send((struct tdc_pkt_header *)pkt);
  78. g_free(pkt);
  79. return retval;
  80. }
  81. int tdcparser_send_request(int address, int interval, uint32_t *bitmap)
  82. {
  83. struct tdc_reqvalues_request pkt;
  84. pkt.cmd = (address << 4) | TDC_REQVALUES;
  85. pkt.size = sizeof(pkt);
  86. pkt.interval = interval;
  87. memcpy(pkt.varmap, bitmap, sizeof(pkt.varmap));
  88. return tdcparser_send((struct tdc_pkt_header *)&pkt);
  89. }
  90. static int check_size_helper(int available,
  91. int packet_size,
  92. int expected_base_size,
  93. int packet_data_size,
  94. const char *name)
  95. {
  96. /* not enough data in buffer */
  97. if (available < expected_base_size) {
  98. // printf("received incomplete %s\n", name);
  99. return 0;
  100. }
  101. /* retest, after we know that packet_data_size is valid */
  102. if (available < (expected_base_size + packet_data_size)) {
  103. // printf("received incomplete %s\n", name);
  104. return 0;
  105. }
  106. /* packet has wrong size */
  107. if (packet_size != (expected_base_size + packet_data_size)) {
  108. // printf("received invalid %s\n", name);
  109. return -1;
  110. }
  111. // printf("received %s\n", name);
  112. return packet_size;
  113. }
  114. static int tdcparser_parse(void)
  115. {
  116. int address = (socket_stream->data[0] & TDC_ADDRMASK) >> 4;
  117. int remove = 1;
  118. switch (socket_stream->data[0] & (TDC_REPLY | TDC_OPCODEMASK)) {
  119. case TDC_HELLO: {
  120. struct tdc_pkt_header *pkt = (struct tdc_pkt_header *)socket_stream->data;
  121. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_HELLO");
  122. /* nothing to do */
  123. } break;
  124. case (TDC_HELLO | TDC_REPLY): {
  125. struct tdc_hello_reply *pkt = (struct tdc_hello_reply *)socket_stream->data;
  126. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_HELLO REPLY");
  127. if (remove <= 0)
  128. break;
  129. tdcstore_create_board(address, pkt->name);
  130. tdcstore_refresh_values(address, 250);
  131. tdcstore_graph_refresh(address, 20);
  132. tdcparser_send_getvars(address);
  133. } break;
  134. case TDC_GETVARS: {
  135. struct tdc_pkt_header *pkt = (struct tdc_pkt_header *)socket_stream->data;
  136. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_GETVARS");
  137. /* nothing to do */
  138. } break;
  139. case (TDC_GETVARS | TDC_REPLY): {
  140. struct tdc_getvars_reply *pkt = (struct tdc_getvars_reply *)socket_stream->data;
  141. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt),
  142. pkt->name_len, "TDC_GETVARS REPLY");
  143. if (remove <= 0)
  144. break;
  145. tdcstore_create_var(address, tdcvar_create(pkt->id, pkt->flags, pkt->name, pkt->name_len));
  146. } break;
  147. case TDC_GETVALUE: {
  148. struct tdc_getvalue_request *pkt = (struct tdc_getvalue_request *)socket_stream->data;
  149. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_GETVALUE");
  150. /* nothing to do */
  151. } break;
  152. case (TDC_GETVALUE | TDC_REPLY): {
  153. struct tdc_getvalue_reply *pkt = (struct tdc_getvalue_reply *)socket_stream->data;
  154. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_GETVALUE REPLY (1)");
  155. /* at this point: invalid packet */
  156. if (remove > 0)
  157. remove = 1;
  158. /* retry with more bytes */
  159. else if (remove == 0)
  160. break;
  161. /* base packet is complete, but exact size is wrong, get it from storage */
  162. struct tdc_var *var = tdcstore_get_var(address, pkt->id);
  163. if (var == NULL) {
  164. printf("unknown variable %d\n", pkt->id);
  165. remove = 1;
  166. break;
  167. }
  168. int varsize = (var->flags & TDC_SIZEMASK);
  169. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), varsize, "TDC_GETVALUE REPLY (2)");
  170. if (remove <= 0)
  171. break;
  172. tdcstore_update_var(address, pkt->id, pkt->data, varsize);
  173. } break;
  174. case TDC_SETVALUE: {
  175. struct tdc_setvalue_request *pkt = (struct tdc_setvalue_request *)socket_stream->data;
  176. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_SETVALUE REPLY (1)");
  177. /* at this point: invalid packet */
  178. if (remove > 0)
  179. remove = 1;
  180. /* retry with more bytes */
  181. else if (remove == 0)
  182. break;
  183. /* base packet is complete, but exact size is wrong, get it from storage */
  184. struct tdc_var *var = tdcstore_get_var(address, pkt->id);
  185. if (var == NULL) {
  186. printf("unknown variable %d\n", pkt->id);
  187. remove = 1;
  188. break;
  189. }
  190. int varsize = (var->flags & TDC_SIZEMASK);
  191. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), varsize, "TDC_SETVALUE REPLY (2)");
  192. if (remove <= 0)
  193. break;
  194. /* nothing to do */
  195. } break;
  196. case (TDC_SETVALUE | TDC_REPLY):
  197. break;
  198. case TDC_REQVALUES: {
  199. struct tdc_reqvalues_request *pkt = (struct tdc_reqvalues_request *)socket_stream->data;
  200. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_REQVALUES");
  201. /* nothing to do */
  202. } break;
  203. case (TDC_REQVALUES | TDC_REPLY): {
  204. struct tdc_reqvalues_reply *pkt = (struct tdc_reqvalues_reply *)socket_stream->data;
  205. remove = check_size_helper(socket_stream->len, pkt->size, sizeof(*pkt), 0, "TDC_REQVALUES");
  206. if (remove <= 0)
  207. break;
  208. // TODO: output pkt->timestamp, pkt->cnt
  209. } break;
  210. case TDC_TERMINAL:
  211. case (TDC_TERMINAL | TDC_REPLY):
  212. break;
  213. }
  214. if (remove != 0)
  215. g_byte_array_remove_range(socket_stream, 0, (remove > 0) ? remove : -remove);
  216. return remove;
  217. }
  218. static void tdcparser_read_cb(gpointer data,
  219. gint source,
  220. GdkInputCondition condition)
  221. {
  222. char buf[256];
  223. int len = read(socket_fd, buf, sizeof(buf));
  224. if (len > 0) {
  225. g_byte_array_append(socket_stream, (guint8 *)buf, len);
  226. while (socket_stream->len >= 2) {
  227. if (tdcparser_parse() == 0)
  228. break;
  229. }
  230. } else {
  231. g_warning("gtdc:tdcparser_read_cb:read:%s", g_strerror(errno));
  232. tdcparser_disconnect();
  233. }
  234. }
  235. static void tdcparser_connect_cb(gpointer data,
  236. gint source,
  237. GdkInputCondition condition)
  238. {
  239. gdk_input_remove(socket_tag);
  240. if (tcp_connect_error(source) < 0) {
  241. g_warning("gtdc:tdcparser_connect_cb:tcp_connect_error:%s", g_strerror(errno));
  242. socket_status_cb(STAT_DISCONNECTED);
  243. close(socket_fd);
  244. } else {
  245. socket_tag = gdk_input_add(socket_fd, GDK_INPUT_READ, tdcparser_read_cb, NULL);
  246. socket_status_cb(STAT_CONNECTED);
  247. if (socket_stream == NULL)
  248. socket_stream = g_byte_array_new();
  249. else if (socket_stream->len)
  250. g_byte_array_remove_range(socket_stream, 0, socket_stream->len);
  251. tdcstore_flush();
  252. tdcparser_send_hello();
  253. }
  254. }
  255. void tdcparser_connect(char *addr_str, void (*cb)(int status))
  256. {
  257. struct sockaddr_in sa;
  258. parse_sockaddr(addr_str, &sa);
  259. socket_status_cb = cb;
  260. socket_status_cb(STAT_CONNECTING);
  261. socket_fd = tcp_connect_nonblock(&sa);
  262. socket_tag = gdk_input_add(socket_fd, GDK_INPUT_WRITE, tdcparser_connect_cb, NULL);
  263. }
  264. void tdcparser_disconnect(void)
  265. {
  266. socket_status_cb(STAT_DISCONNECTED);
  267. gdk_input_remove(socket_tag);
  268. close(socket_fd);
  269. }