PageRenderTime 72ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/plugins/mscommon/mtxsocket.c

https://gitlab.com/libreems-suite/megatunix
C | 2160 lines | 1721 code | 139 blank | 300 comment | 282 complexity | 98af72fea9af2ac6dd02993f35debc5a MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2002-2012 by Dave J. Andruczyk <djandruczyk at yahoo dot com>
  3. *
  4. * Linux Megasquirt tuning software
  5. *
  6. *
  7. * This software comes under the GPL (GNU Public License)
  8. * You may freely copy,distribute etc. this as long as the source code
  9. * is made available for FREE.
  10. *
  11. * No warranty is made or implied. You use this program at your own risk.
  12. */
  13. /*!
  14. \file src/plugins/mscommon/mtxsocket.c
  15. \ingroup MSCommonPlugin,Plugins
  16. \brief MS personality specific remote network mode functionality
  17. \author David Andruczyk
  18. */
  19. /* Current GSocket Implementation */
  20. #include <api-versions.h>
  21. #include <args.h>
  22. #include <config.h>
  23. #include <configfile.h>
  24. #include <datamgmt.h>
  25. #include <defines.h>
  26. #include <enums.h>
  27. #include <errno.h>
  28. #include <fcntl.h>
  29. #include <firmware.h>
  30. #include <glib.h>
  31. #include <gtk/gtk.h>
  32. #include <gio/gio.h>
  33. #include <init.h>
  34. #include <mscommon_comms.h>
  35. #include <mscommon_plugin.h>
  36. #include <mtxsocket.h>
  37. #include <rtv_map_loader.h>
  38. #include <serialio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #ifndef __WIN32__
  42. #include <poll.h>
  43. #include <arpa/inet.h>
  44. #include <sys/select.h>
  45. #include <sys/types.h>
  46. #include <sys/socket.h>
  47. #endif
  48. #ifdef __WIN32__
  49. #include <winsock2.h>
  50. #endif
  51. #include <unistd.h>
  52. #define ERR_MSG "Bad Request: "
  53. static GPtrArray *slave_list = NULL;
  54. static const guint8 SLAVE_MEMORY_UPDATE=0xBE;
  55. static const guint8 SLAVE_STATUS_UPDATE=0xBF;
  56. GThread *ascii_socket_id = NULL;
  57. GThread *binary_socket_id = NULL;
  58. GThread *control_socket_id = NULL;
  59. GThread *notify_slaves_id = NULL;
  60. extern gconstpointer *global_data;
  61. /*!
  62. *\brief open_tcpip_sockets opens up the TCP sockets to handle the connection
  63. of slave isntances, Opens 3 ports, one for ASCII, one for binary, and the
  64. third is the callback socket that clients connect to to get the changes
  65. fed back made by the master or other slave instances.
  66. */
  67. G_MODULE_EXPORT void open_tcpip_sockets(void)
  68. {
  69. MtxSocket *mtxsock = NULL;
  70. gboolean fail1,fail2,fail3;
  71. ENTER();
  72. /* Open The three sockets, ASCII interface, binary interface
  73. * and control socket for telling other instances to update
  74. * stuff..
  75. */
  76. mtxsock = g_new0(MtxSocket,1);
  77. mtxsock->socket = setup_socket(MTX_SOCKET_ASCII_PORT);
  78. mtxsock->fd = g_socket_get_fd(mtxsock->socket);
  79. mtxsock->type = MTX_SOCKET_ASCII;
  80. if (mtxsock->fd)
  81. {
  82. ascii_socket_id = g_thread_new("ASCII TCP socketthread",socket_thread_manager,
  83. (gpointer)mtxsock); /* Thread args */
  84. DATA_SET(global_data,"ascii_socket",mtxsock);
  85. fail1 = FALSE;
  86. }
  87. else
  88. {
  89. fail1 = TRUE;
  90. g_free(mtxsock);
  91. MTXDBG(CRITICAL,_("ERROR setting up ASCII TCP socket\n"));
  92. }
  93. mtxsock = g_new0(MtxSocket,1);
  94. mtxsock->socket = setup_socket(MTX_SOCKET_BINARY_PORT);
  95. mtxsock->fd = g_socket_get_fd(mtxsock->socket);
  96. mtxsock->type = MTX_SOCKET_BINARY;
  97. if (mtxsock->fd)
  98. {
  99. binary_socket_id = g_thread_new("Binary TCP Socket Thread",
  100. socket_thread_manager,
  101. (gpointer)mtxsock); /* Thread args */
  102. DATA_SET(global_data,"binary_socket",mtxsock);
  103. fail2 = FALSE;
  104. }
  105. else
  106. {
  107. fail2 = TRUE;
  108. g_free(mtxsock);
  109. MTXDBG(CRITICAL,_("ERROR setting up BINARY TCP socket\n"));
  110. }
  111. mtxsock = g_new0(MtxSocket,1);
  112. mtxsock->socket = setup_socket(MTX_SOCKET_CONTROL_PORT);
  113. mtxsock->fd = g_socket_get_fd(mtxsock->socket);
  114. mtxsock->type = MTX_SOCKET_CONTROL;
  115. if (mtxsock->fd)
  116. {
  117. control_socket_id = g_thread_new("Binary TCP Control Socket Thread",
  118. socket_thread_manager,
  119. (gpointer)mtxsock); /* Thread args */
  120. DATA_SET(global_data,"control_socket",mtxsock);
  121. fail3 = FALSE;
  122. }
  123. else
  124. {
  125. fail3 = TRUE;
  126. g_free(mtxsock);
  127. MTXDBG(CRITICAL,_("ERROR setting up TCP control socket\n"));
  128. }
  129. if ((!fail1) && (!fail2) &&(!fail3))
  130. {
  131. notify_slaves_id = g_thread_new("Slave Notifier Thread",
  132. notify_slaves_thread,
  133. NULL); /* Thread args */
  134. DATA_SET(global_data,"notify_slaves_id",GINT_TO_POINTER(notify_slaves_id));
  135. }
  136. EXIT();
  137. return;
  138. }
  139. /*!
  140. \brief Sets up incoming sockets (master mode only)
  141. \param port if the port number to setup
  142. \returns a pointer to a GSocket structure
  143. */
  144. G_MODULE_EXPORT GSocket *setup_socket(gint port)
  145. {
  146. GSocket *sock = NULL;
  147. GError *error = NULL;
  148. GInetAddress *inetaddr = NULL;
  149. GSocketAddress *sockaddr = NULL;
  150. ENTER();
  151. sock = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &error);
  152. if (!sock)
  153. {
  154. MTXDBG(CRITICAL|SERIAL_RD|SERIAL_WR,_("Socket creation error: %s\n"),error->message);
  155. g_error_free(error);
  156. error = NULL;
  157. EXIT();
  158. return NULL;
  159. }
  160. g_socket_set_blocking(sock,TRUE);
  161. inetaddr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
  162. sockaddr = g_inet_socket_address_new(inetaddr,port);
  163. if(!g_socket_bind(sock,sockaddr,TRUE,&error))
  164. {
  165. MTXDBG(CRITICAL|SERIAL_RD|SERIAL_WR,_("Socket bind error: %s\n"),error->message);
  166. g_error_free(error);
  167. error = NULL;
  168. g_socket_close(sock,NULL);
  169. EXIT();
  170. return NULL;
  171. }
  172. g_object_unref(sockaddr);
  173. g_object_unref(inetaddr);
  174. /* Max 5 clients outstanding */
  175. g_socket_set_listen_backlog (sock,5);
  176. if (!g_socket_listen(sock,&error))
  177. {
  178. MTXDBG(CRITICAL|SERIAL_RD|SERIAL_WR,_("Socket listen error: %s\n"),error->message);
  179. g_error_free(error);
  180. error = NULL;
  181. g_socket_close(sock,NULL);
  182. EXIT();
  183. return NULL;
  184. }
  185. /* printf("\nTCP/IP Socket ready: %s:%d\n\n",inet_ntoa(server_address.sin_addr),ntohs(server_address.sin_port));*/
  186. EXIT();
  187. return (sock);
  188. }
  189. /*!
  190. \brief socket_thread_manager()'s sole purpose in life is to wait for socket
  191. connections and spawn threads to handle their I/O. These sockets are for
  192. remote megatunix management (logging, dashboards, and other cool things)
  193. \param data is a pointer to the socket descriptor for the open TCP socket.
  194. \see MtxSocket
  195. \see MtxSocketClient
  196. **/
  197. G_MODULE_EXPORT void *socket_thread_manager(gpointer data)
  198. {
  199. GtkWidget *widget = NULL;
  200. gchar * tmpbuf = NULL;
  201. fd_set rd;
  202. gint res = 0;
  203. gint i = 0;
  204. GSocket *socket = NULL;
  205. GError *error = NULL;
  206. MtxSocket *mtxsock = (MtxSocket *)data;
  207. MtxSocketClient * cli_data = NULL;
  208. GTimeVal cur;
  209. GSocketAddress *sockaddr = NULL;
  210. static MtxSocketClient *last_bin_client = NULL;
  211. Firmware_Details *firmware = NULL;
  212. ENTER();
  213. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  214. MTXDBG(MTXSOCKET|THREADS|CRITICAL,_("Thread created!\n"));
  215. while (TRUE)
  216. {
  217. if (DATA_GET(global_data,"leaving")) /* MTX shutting down */
  218. {
  219. g_socket_close(mtxsock->socket,NULL);
  220. g_free(mtxsock);
  221. g_thread_exit(0);
  222. }
  223. if (!(GBOOLEAN)DATA_GET(global_data,"network_access"))
  224. {
  225. g_socket_close(mtxsock->socket,NULL);
  226. g_free(mtxsock);
  227. g_thread_exit(0);
  228. }
  229. cur.tv_sec = 1;
  230. cur.tv_usec = 0;
  231. FD_ZERO(&rd);
  232. FD_SET(mtxsock->fd,&rd);
  233. res = select(mtxsock->fd+1,&rd,NULL,NULL,(struct timeval *)&cur);
  234. if (res < 0) /* Error, FD closed, abort */
  235. {
  236. /*printf("poll error, closing socket!\n");*/
  237. g_socket_close(mtxsock->socket,NULL);
  238. g_free(mtxsock);
  239. g_thread_exit(0);
  240. }
  241. if (res == 0) /* Timeout, loop around */
  242. {
  243. /*printf("poll timeout, looping...\n");*/
  244. continue;
  245. }
  246. socket = g_socket_accept(mtxsock->socket,NULL,&error);
  247. if (((mtxsock->type == MTX_SOCKET_ASCII) || (mtxsock->type == MTX_SOCKET_BINARY)) && (firmware))
  248. {
  249. sockaddr = g_socket_get_remote_address(socket,NULL);
  250. cli_data = g_new0(MtxSocketClient, 1);
  251. cli_data->ip = g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress *)sockaddr));
  252. cli_data->socket = socket;
  253. cli_data->fd = g_socket_get_fd(socket);
  254. cli_data->type = mtxsock->type;
  255. cli_data->ecu_data = g_new0(guint8 *, firmware->total_pages);
  256. g_object_unref(sockaddr);
  257. /*printf ("created slave %p, ecu_data %p\n",cli_data,cli_data->ecu_data);*/
  258. for (i=0;i<firmware->total_pages;i++)
  259. {
  260. cli_data->ecu_data[i] = g_new0(guint8, firmware->page_params[i]->length);
  261. /*printf ("created slave %p, ecu_data[%i] %p\n",cli_data,i,cli_data->ecu_data[i]);*/
  262. if (firmware->ecu_data[i])
  263. memcpy (cli_data->ecu_data[i],firmware->ecu_data[i],firmware->page_params[i]->length);
  264. }
  265. }
  266. if (mtxsock->type == MTX_SOCKET_ASCII)
  267. {
  268. g_thread_new("ASCII Socket Server",
  269. ascii_socket_server,
  270. cli_data); /* Thread args */
  271. }
  272. if (mtxsock->type == MTX_SOCKET_BINARY)
  273. {
  274. last_bin_client = cli_data;
  275. g_thread_new("BINARY Socket Server",
  276. binary_socket_server,
  277. cli_data); /* Thread args */
  278. }
  279. if (mtxsock->type == MTX_SOCKET_CONTROL)
  280. {
  281. /* printf("Connected slave pointer is %p\n",last_bin_client);*/
  282. if (!slave_list)
  283. slave_list = g_ptr_array_new();
  284. last_bin_client->control_socket = socket;
  285. last_bin_client->container = (gpointer)slave_list;
  286. g_ptr_array_add(slave_list,last_bin_client);
  287. last_bin_client = NULL; /* to prevent adding it to multiple clients by mistake. The next binary client will regenerated it */
  288. widget = lookup_widget_f("connected_clients_entry");
  289. tmpbuf = g_strdup_printf("%i",slave_list->len);
  290. gtk_entry_set_text(GTK_ENTRY(widget),tmpbuf);
  291. g_free(tmpbuf);
  292. }
  293. }
  294. EXIT();
  295. return NULL;
  296. }
  297. /*!
  298. \brief ascii_socket_server, answers simple requests for data on the
  299. ASCII communications port 12764 (for telnet/other simple low speed apps)
  300. \param data gpointer representation of the socket filedescriptor
  301. */
  302. G_MODULE_EXPORT void *ascii_socket_server(gpointer data)
  303. {
  304. MtxSocketClient *client = (MtxSocketClient *) data;
  305. GTimeVal cur;
  306. gint fd = client->fd;
  307. gchar buf[4096];
  308. gchar * cbuf = NULL; /* Client buffer */
  309. gchar * tmpbuf = NULL;
  310. fd_set rd;
  311. gint res = 0;
  312. GError *error = NULL;
  313. ENTER();
  314. MTXDBG(THREADS|CRITICAL,_("Thread created!\n"));
  315. tmpbuf = g_strdup_printf(_("Welcome to MegaTunix %s, ASCII mode enabled\nEnter 'help' for assistance\n"),VERSION);
  316. net_send(client->socket,(guint8 *)tmpbuf,strlen(tmpbuf));
  317. g_free(tmpbuf);
  318. while (TRUE)
  319. {
  320. if (DATA_GET(global_data,"leaving"))
  321. goto close_ascii;
  322. if (!(GBOOLEAN)DATA_GET(global_data,"network_access"))
  323. goto close_ascii;
  324. FD_ZERO(&rd);
  325. FD_SET(fd,&rd);
  326. cur.tv_sec = 1;
  327. cur.tv_usec = 0;
  328. res = select(fd+1,&rd,NULL,NULL,(struct timeval *)&cur);
  329. if (res < 0) /* Error, socket closed, abort */
  330. {
  331. close_ascii:
  332. g_socket_close(client->socket,NULL);
  333. g_object_unref(client->socket);
  334. dealloc_client_data(client);
  335. g_thread_exit(0);
  336. }
  337. if (res > 0) /* Data Arrived */
  338. {
  339. res = g_socket_receive(client->socket,buf,4096,NULL,&error);
  340. if (res < 0)
  341. {
  342. MTXDBG(THREADS|CRITICAL,_("Receive error \"%s\"\n"),error->message);
  343. g_error_free(error);
  344. error = NULL;
  345. g_socket_close(client->socket,NULL);
  346. g_object_unref(client->socket);
  347. dealloc_client_data(client);
  348. g_thread_exit(0);
  349. }
  350. /* If command validator returns false, the connection
  351. * was quit, thus close and exit nicely
  352. */
  353. cbuf = g_new0(gchar, 4096);
  354. memcpy (cbuf,buf,res);
  355. if (client->type == MTX_SOCKET_ASCII)
  356. res = validate_remote_ascii_cmd(client,cbuf,res);
  357. g_free(cbuf);
  358. if (!res)
  359. {
  360. g_socket_close(client->socket,NULL);
  361. g_object_unref(client->socket);
  362. dealloc_client_data(client);
  363. g_thread_exit(0);
  364. }
  365. }
  366. }
  367. EXIT();
  368. return NULL;
  369. }
  370. /*!
  371. \brief This thread handles the binary socket port (port 12765), and
  372. acts as a MegaSquirt state machine, thus a remote client uses the same
  373. API as if it was talking to a MS on a serial port. It emulates most of the
  374. MS features, thus allowing non-megatunix clients, however MS doesn't have any
  375. sort of notification of changes, which is why another port (12766) is used
  376. to pass messages from the MASTER (the one connected directly to the MS via
  377. serial) to all connected slaves to keep them in sync.
  378. \param data is a pointer to the MtxSocketClient structure
  379. \see MtxSocketClient
  380. */
  381. G_MODULE_EXPORT void *binary_socket_server(gpointer data)
  382. {
  383. GtkWidget *widget = NULL;
  384. MtxSocketClient *client = (MtxSocketClient *) data;
  385. gchar buf;
  386. gchar *tmpbuf = NULL;
  387. gint res = 0;
  388. gint canID = 0;
  389. gint tableID = 0;
  390. gint mtx_page = 0;
  391. gint offset = 0;
  392. guint8 offset_h = 0;
  393. guint8 offset_l = 0;
  394. gint count = 0;
  395. guint8 count_h = 0;
  396. guint8 count_l = 0;
  397. gint index = 0;
  398. guint8 *buffer = NULL;
  399. guint8 byte = 0;
  400. gfloat tmpf = 0.0;
  401. gint tmpi = 0;
  402. OutputData *output = NULL;
  403. State state;
  404. State next_state;
  405. State substate;
  406. GError *error = NULL;
  407. Firmware_Details *firmware;
  408. ENTER();
  409. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  410. state = WAITING_FOR_CMD;
  411. next_state = WAITING_FOR_CMD;
  412. substate = UNDEFINED_SUBSTATE;
  413. MTXDBG(THREADS|CRITICAL,_("Thread created!\n"));
  414. while(TRUE)
  415. {
  416. /* Condition handling */
  417. if (DATA_GET(global_data,"leaving"))
  418. goto close_binary;
  419. if (!(GBOOLEAN)DATA_GET(global_data,"network_access"))
  420. goto close_binary;
  421. if (res < 0)
  422. goto close_binary2;
  423. res = g_socket_receive(client->socket,&buf,1,NULL,&error);
  424. if (res < 0)
  425. {
  426. close_binary:
  427. if (error)
  428. {
  429. MTXDBG(THREADS|CRITICAL,_("Receive error \"%s\"\n"),error->message);
  430. g_error_free(error);
  431. }
  432. error = NULL;
  433. close_binary2:
  434. g_socket_close(client->socket,NULL);
  435. g_object_unref(client->socket);
  436. if (slave_list)
  437. {
  438. g_ptr_array_remove(slave_list,client);
  439. dealloc_client_data(client);
  440. client = NULL;
  441. widget = lookup_widget_f("connected_clients_entry");
  442. tmpbuf = g_strdup_printf("%i",slave_list->len);
  443. gtk_entry_set_text(GTK_ENTRY(widget),tmpbuf);
  444. g_free(tmpbuf);
  445. }
  446. g_thread_exit(0);
  447. }
  448. /* State machine... */
  449. switch (state)
  450. {
  451. case WAITING_FOR_CMD:
  452. switch (buf)
  453. {
  454. case '!': /* Potential reinit/reboot */
  455. if ((firmware->capabilities & MS2) || (firmware->capabilities & MS1_E))
  456. state = GET_REINIT_OR_REBOOT;
  457. continue;
  458. case 'a':/* MS2 table full table read */
  459. if (firmware->capabilities & MS2)
  460. {
  461. /*printf("'a' received\n");*/
  462. state = GET_CAN_ID;
  463. next_state = WAITING_FOR_CMD;
  464. substate = SEND_FULL_TABLE;
  465. }
  466. continue;;
  467. case 't':/* MS2 Lookuptable update */
  468. /*printf("'t' received\n");*/
  469. if (firmware->capabilities & MS2)
  470. {
  471. state = GET_TABLE_ID;
  472. next_state = GET_DATABLOCK;
  473. substate = RECV_LOOKUPTABLE;
  474. }
  475. continue;
  476. case 'A':/* MS1 RTvars */
  477. /* printf("'A' received\n");*/
  478. if (firmware->capabilities & MS1_E)
  479. res = net_send (client->socket,(guint8 *)firmware->rt_data,22);
  480. else
  481. res = net_send (client->socket,(guint8 *)firmware->rt_data,firmware->rtvars_size);
  482. /* printf("MS1 rtvars sent, %i bytes delivered\n",res);*/
  483. continue;
  484. case 'b':/* MS2 burn */
  485. if (firmware->capabilities & MS2)
  486. {
  487. /* printf("'b' received\n");*/
  488. state = GET_CAN_ID;
  489. next_state = WAITING_FOR_CMD;
  490. substate = BURN_MS2_FLASH;
  491. }
  492. continue;
  493. case 'B':/* MS1 burn */
  494. /* printf("'B' received\n");*/
  495. if (firmware->capabilities & MS1)
  496. io_cmd_f(firmware->burn_all_command,NULL);
  497. continue;
  498. case 'r':/* MS2 partial table read */
  499. if (firmware->capabilities & MS2)
  500. {
  501. /* printf("'r' received\n");*/
  502. state = GET_CAN_ID;
  503. next_state = GET_HIGH_OFFSET;
  504. substate = SEND_PARTIAL_TABLE;
  505. }
  506. continue;
  507. case 'w':/* MS2 chunk write */
  508. if (firmware->capabilities & MS2)
  509. {
  510. /* printf("'w' received\n");*/
  511. state = GET_CAN_ID;
  512. next_state = GET_HIGH_OFFSET;
  513. substate = GET_VAR_DATA;
  514. }
  515. continue;
  516. case 'c':/* MS2 Clock read */
  517. if (firmware->capabilities & MS2)
  518. {
  519. /* printf("'c' received\n");*/
  520. state = WAITING_FOR_CMD;
  521. lookup_current_value_f("raw_secl",&tmpf);
  522. tmpi = (guint16)tmpf;
  523. res = net_send(client->socket,(guint8 *)&tmpi,2);
  524. /* printf("MS2 clock sent, %i bytes delivered\n",res);*/
  525. }
  526. continue;
  527. case 'C':/* MS1 Clock read */
  528. if (firmware->capabilities & MS1)
  529. {
  530. /* printf("'C' received\n");*/
  531. lookup_current_value_f("raw_secl",&tmpf);
  532. tmpi = (guint8)tmpf;
  533. res = net_send(client->socket,(guint8 *)&tmpi,1);
  534. /* printf("MS1 clock sent, %i bytes delivered\n",res);*/
  535. }
  536. continue;
  537. case 'P':/* MS1 Page change */
  538. /* printf ("'P' (MS1 Page change)\n");*/
  539. if (firmware->capabilities & MS1)
  540. {
  541. state = GET_MS1_PAGE;
  542. next_state = WAITING_FOR_CMD;
  543. }
  544. continue;
  545. case 'Q':/* MS1 Numeric Revision read
  546. * MS2 Text revision, API clash!
  547. */
  548. if (!firmware)
  549. continue;
  550. else
  551. {
  552. /* printf ("'Q' (MS1 ecu revision, or ms2 text rev)\n");*/
  553. if ((firmware->capabilities & MS1) && (!(firmware->capabilities & JIMSTIM)))
  554. res = net_send(client->socket,(guint8 *)&(firmware->ecu_revision),1);
  555. else
  556. if (firmware->text_revision)
  557. res = net_send(client->socket,(guint8 *)firmware->text_revision,firmware->txt_rev_len);
  558. else
  559. printf(_("text_revision undefined!\n"));
  560. }
  561. /* printf("numeric/text revision sent, %i bytes delivered\n",res);*/
  562. continue;
  563. case 'R':/* MSnS Extra (MS1) RTvars */
  564. if (firmware->capabilities & MS1_E)
  565. {
  566. /* printf ("'R' (MS1 extra RTvars)\n");*/
  567. res = net_send (client->socket,(guint8 *)firmware->rt_data,firmware->rtvars_size);
  568. /* printf("MSnS-E rtvars, %i bytes delivered\n",res);*/
  569. }
  570. continue;
  571. case 'T':/* MS1 Text Revision */
  572. if (firmware->capabilities & MS1)
  573. {
  574. /* printf ("'T' (MS1 text revision)\n");*/
  575. if (firmware->text_revision)
  576. {
  577. res = net_send(client->socket,(guint8 *)firmware->text_revision,strlen(firmware->text_revision));
  578. /* printf("MS1 textrev, %i bytes delivered\n",res);*/
  579. }
  580. }
  581. continue;
  582. case 'S':/* MS1/2 Signature Read */
  583. /* printf("'S' received\n");*/
  584. state = WAITING_FOR_CMD;
  585. if (firmware)
  586. {
  587. if (firmware->actual_signature)
  588. res = net_send(client->socket,(guint8 *)firmware->actual_signature,firmware->signature_len);
  589. /*printf("MS signature, %i bytes delivered\n",res);*/
  590. }
  591. continue;
  592. case 'V':/* MS1 VE/data read */
  593. if (firmware->capabilities & MS1)
  594. {
  595. /* printf("'V' received (MS1 VEtable)\n");*/
  596. if ((GINT)DATA_GET(global_data,"last_page") < 0)
  597. DATA_SET(global_data,"last_page",GINT_TO_POINTER(0));
  598. res = net_send (client->socket,(guint8 *)firmware->ecu_data[(GINT)DATA_GET(global_data,"last_page")],firmware->page_params[(GINT)DATA_GET(global_data,"last_page")]->length);
  599. /* printf("MS1 VEtable, %i bytes delivered\n",res);*/
  600. }
  601. continue;
  602. case 'W':/* MS1 Simple write */
  603. if (firmware->capabilities & MS1)
  604. {
  605. /* printf("'W' received (MS1 Write)\n");*/
  606. state = GET_MS1_OFFSET;
  607. next_state = GET_MS1_BYTE;
  608. }
  609. continue;
  610. case 'X':/* MS1 Chunk write */
  611. if (firmware->capabilities & MS1)
  612. {
  613. /* printf("'X' received (MS1 Chunk Write)\n");*/
  614. state = GET_MS1_OFFSET;
  615. next_state = GET_MS1_COUNT;
  616. }
  617. continue;
  618. default:
  619. continue;
  620. }
  621. case GET_REINIT_OR_REBOOT:
  622. if ((buf == '!') && (firmware->capabilities & MS2))
  623. state = GET_MS2_REBOOT;
  624. else if ((buf == '!') && (firmware->capabilities & MS1_E))
  625. state = GET_MS1_EXTRA_REBOOT;
  626. if (buf == 'x')
  627. {
  628. io_cmd_f("ms2_reinit",NULL);
  629. state = WAITING_FOR_CMD;
  630. }
  631. continue;
  632. case GET_MS1_EXTRA_REBOOT:
  633. if (buf == 'X')
  634. {
  635. io_cmd_f("ms1_extra_reboot_get_error",NULL);
  636. state = WAITING_FOR_CMD;
  637. }
  638. continue;
  639. case GET_MS2_REBOOT:
  640. if (buf == 'x')
  641. {
  642. io_cmd_f("ms2_reboot",NULL);
  643. state = WAITING_FOR_CMD;
  644. }
  645. continue;
  646. case GET_CAN_ID:
  647. /* printf("get_can_id block\n");*/
  648. canID = (guint8)buf;
  649. /* printf("canID received is %i\n",canID);*/
  650. if ((canID < 0) || (canID > 8))
  651. {
  652. /* printf( "canID is out of range!\n");*/
  653. state = WAITING_FOR_CMD;
  654. }
  655. else
  656. state = GET_TABLE_ID;
  657. continue;
  658. case GET_TABLE_ID:
  659. /* printf("get_table_id block\n"); */
  660. tableID = (guint8)buf;
  661. /* printf("tableID received is %i\n",tableID); */
  662. if (tableID > firmware->total_tables)
  663. {
  664. state = WAITING_FOR_CMD;
  665. break;
  666. }
  667. state = next_state;
  668. if (substate == SEND_FULL_TABLE)
  669. {
  670. if (ms_find_mtx_page(tableID,&mtx_page))
  671. {
  672. if (firmware->ecu_data[mtx_page])
  673. {
  674. res = net_send(client->socket,(guint8 *)firmware->ecu_data[mtx_page],firmware->page_params[mtx_page]->length);
  675. /* printf("Full table sent, %i bytes\n",res);*/
  676. }
  677. }
  678. }
  679. else if (substate == RECV_LOOKUPTABLE)
  680. {
  681. /* printf("lookuptable tableID\n");*/
  682. if ((tableID < 0) || (tableID > 3)) /* Limit check */
  683. break;
  684. if (tableID == 2) /* EGO is 1024 bytes, others are 2048 */
  685. count = 1024;
  686. else
  687. count = 2048;
  688. buffer = g_new0(guint8, count);
  689. index = 0;
  690. /* printf("Count to be received is %i\n",count);*/
  691. }
  692. else if (substate == BURN_MS2_FLASH)
  693. {
  694. if (ms_find_mtx_page(tableID,&mtx_page))
  695. {
  696. /* printf("MS2 burn: Can ID is %i, tableID %i mtx_page %i\n",canID,tableID,mtx_page);*/
  697. output = initialize_outputdata_f();
  698. DATA_SET(output->data,"page",GINT_TO_POINTER(mtx_page));
  699. DATA_SET(output->data,"phys_ecu_page",GINT_TO_POINTER(tableID));
  700. DATA_SET(output->data,"canID",GINT_TO_POINTER(canID));
  701. DATA_SET(output->data,"mode", GINT_TO_POINTER(MTX_CMD_WRITE));
  702. io_cmd_f(firmware->burn_command,output);
  703. }
  704. }
  705. else
  706. next_state = WAITING_FOR_CMD;
  707. continue;
  708. case GET_HIGH_OFFSET:
  709. /* printf("get_high_offset block\n");*/
  710. offset_h = (guint8)buf;
  711. /* printf("high offset received is %i\n",offset_h);*/
  712. state = GET_LOW_OFFSET;
  713. continue;
  714. case GET_LOW_OFFSET:
  715. /* printf("get_low_offset block\n");*/
  716. offset_l = (guint8)buf;
  717. /* printf("low offset received is %i\n",offset_l);*/
  718. offset = offset_l + (offset_h << 8);
  719. state = GET_HIGH_COUNT;
  720. continue;
  721. case GET_HIGH_COUNT:
  722. /* printf("get_high_count block\n");*/
  723. count_h = (guint8)buf;
  724. /* printf("high count received is %i\n",count_h);*/
  725. state = GET_LOW_COUNT;
  726. continue;
  727. case GET_LOW_COUNT:
  728. /* printf("get_low_count block\n");*/
  729. count_l = (guint8)buf;
  730. /* printf("low count received is %i\n",count_l);*/
  731. count = count_l + (count_h << 8);
  732. state = next_state;
  733. if (substate == GET_VAR_DATA)
  734. {
  735. state = GET_DATABLOCK;
  736. buffer = g_new0(guint8, count);
  737. index = 0;
  738. }
  739. if (substate == SEND_PARTIAL_TABLE)
  740. {
  741. if (ms_find_mtx_page(tableID,&mtx_page))
  742. {
  743. if (firmware->ecu_data[mtx_page])
  744. res = net_send(client->socket,(guint8 *)firmware->ecu_data[mtx_page]+offset,count);
  745. /* printf("MS2 partial table, %i bytes delivered\n",res);*/
  746. }
  747. }
  748. continue;
  749. case GET_DATABLOCK:
  750. /* printf("get_datablock\n");*/
  751. buffer[index] = (guint8)buf;
  752. index++;
  753. /* printf ("Datablock index %i of %i\n",index,count);*/
  754. if (index >= count)
  755. {
  756. if (firmware->capabilities & MS2)
  757. {
  758. if (substate == RECV_LOOKUPTABLE)
  759. {
  760. /* printf("Received lookuptable from slave, sending to ECU\n");*/
  761. if (ms_find_mtx_page(tableID,&mtx_page))
  762. ms_table_write(mtx_page,count,(guint8 *) buffer);
  763. }
  764. else
  765. {
  766. if (ms_find_mtx_page(tableID,&mtx_page))
  767. {
  768. memcpy (client->ecu_data[mtx_page]+offset,buffer,count);
  769. ms_chunk_write(canID,mtx_page,offset,count,buffer);
  770. }
  771. }
  772. }
  773. else
  774. {
  775. /*printf("updating local ms1 chunk buffer\n");*/
  776. memcpy (client->ecu_data[(GINT)DATA_GET(global_data,"last_page")]+offset,buffer,count);
  777. ms_chunk_write(0,(GINT)DATA_GET(global_data,"last_page"),offset,count,buffer);
  778. }
  779. state = WAITING_FOR_CMD;
  780. }
  781. else
  782. state = GET_DATABLOCK;
  783. continue;
  784. case GET_MS1_PAGE:
  785. /* printf("get_ms1_page\n");*/
  786. tableID = (guint8)buf;
  787. /* printf ("Passed page %i\n",tableID);*/
  788. ms_handle_page_change(tableID,(GINT)DATA_GET(global_data,"last_page"));
  789. state = WAITING_FOR_CMD;
  790. continue;
  791. case GET_MS1_OFFSET:
  792. /* printf("get_ms1_offset\n");*/
  793. offset = (guint8)buf;
  794. /* printf ("Passed offset %i\n",offset);*/
  795. state = next_state;
  796. continue;
  797. case GET_MS1_COUNT:
  798. /* printf("get_ms1_count\n");*/
  799. count = (guint8)buf;
  800. index = 0;
  801. buffer = g_new0(guint8, count);
  802. /* printf ("Passed count %i\n",count);*/
  803. state = GET_DATABLOCK;
  804. continue;
  805. case GET_MS1_BYTE:
  806. /* printf("get_ms1_byte\n");*/
  807. byte = (guint8)buf;
  808. /* printf ("Passed byte %i\n",byte);*/
  809. _set_sized_data_f(client->ecu_data[(GINT)DATA_GET(global_data,"last_page")],offset,MTX_U08,byte,firmware->bigendian);
  810. ms_send_to_ecu(0,(GINT)DATA_GET(global_data,"last_page"),offset,MTX_U08,byte,TRUE);
  811. /* printf("Writing byte %i to ecu on page %i, offset %i\n",byte,(GINT)DATA_GET(global_data,"last_page"),offset);*/
  812. state = WAITING_FOR_CMD;
  813. continue;
  814. default:
  815. printf("case not handled in state machine, BUG!\n");
  816. continue;
  817. }
  818. }
  819. EXIT();
  820. return NULL;
  821. }
  822. /*!
  823. \brief This function validates incoming commands from the TCP socket
  824. thread(s). Commands need to be comma separated, ASCII text, minimum of two
  825. arguments (more are allowed)
  826. \param client is a pointer to an active MtxSocketClient structure
  827. \param buf is the pointer to the input buffer
  828. \param len is the length of input buffer
  829. \returns TRUE on valid command, FALSE otherwise
  830. */
  831. G_MODULE_EXPORT gboolean validate_remote_ascii_cmd(MtxSocketClient *client, gchar * buf, gint len)
  832. {
  833. gchar ** vector = NULL;
  834. gchar * arg2 = NULL;
  835. gint args = 0;
  836. gsize res = 0;
  837. gint cmd = 0;
  838. gboolean retval = TRUE;
  839. gboolean send_rescode = TRUE;
  840. gchar *tmpbuf = NULL;
  841. Firmware_Details *firmware = NULL;
  842. ENTER();
  843. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  844. tmpbuf = g_strchomp(g_strdelimit(g_strndup(buf,len),"\n\r\t",' '));
  845. if (!tmpbuf)
  846. {
  847. EXIT();
  848. return TRUE;
  849. }
  850. vector = g_strsplit(tmpbuf,",",2);
  851. g_free(tmpbuf);
  852. args = g_strv_length(vector);
  853. if (!vector[0])
  854. {
  855. g_strfreev(vector);
  856. EXIT();
  857. return TRUE;
  858. }
  859. tmpbuf = g_ascii_strup(vector[0],-1);
  860. arg2 = g_strdup(vector[1]);
  861. g_strfreev(vector);
  862. cmd = translate_string_f(tmpbuf);
  863. g_free(tmpbuf);
  864. switch (cmd)
  865. {
  866. case GET_RT_VARS:
  867. if (args != 2)
  868. return_socket_error(client->socket);
  869. else
  870. socket_get_rt_vars(client->socket, arg2);
  871. break;
  872. case GET_RTV_LIST:
  873. socket_get_rtv_list(client->socket);
  874. break;
  875. case GET_ECU_PAGE:
  876. if (args != 2)
  877. return_socket_error(client->socket);
  878. else
  879. socket_get_ecu_page(client,arg2);
  880. break;
  881. case GET_ECU_VAR_U08:
  882. if (args != 2)
  883. return_socket_error(client->socket);
  884. else
  885. socket_get_ecu_var(client,arg2,MTX_U08);
  886. break;
  887. case GET_ECU_VAR_S08:
  888. if (args != 2)
  889. return_socket_error(client->socket);
  890. else
  891. socket_get_ecu_var(client,arg2,MTX_S08);
  892. break;
  893. case GET_ECU_VAR_U16:
  894. if (args != 2)
  895. return_socket_error(client->socket);
  896. else
  897. socket_get_ecu_var(client,arg2,MTX_U16);
  898. break;
  899. case GET_ECU_VAR_S16:
  900. if (args != 2)
  901. return_socket_error(client->socket);
  902. else
  903. socket_get_ecu_var(client,arg2,MTX_S16);
  904. break;
  905. case GET_ECU_VAR_U32:
  906. if (args != 2)
  907. return_socket_error(client->socket);
  908. else
  909. socket_get_ecu_var(client,arg2,MTX_U32);
  910. break;
  911. case GET_ECU_VAR_S32:
  912. if (args != 2)
  913. return_socket_error(client->socket);
  914. else
  915. socket_get_ecu_var(client,arg2,MTX_S32);
  916. break;
  917. case SET_ECU_VAR_U08:
  918. if (args != 2)
  919. return_socket_error(client->socket);
  920. else
  921. socket_set_ecu_var(client,arg2,MTX_U08);
  922. break;
  923. case SET_ECU_VAR_S08:
  924. if (args != 2)
  925. return_socket_error(client->socket);
  926. else
  927. socket_set_ecu_var(client,arg2,MTX_S08);
  928. break;
  929. case SET_ECU_VAR_U16:
  930. if (args != 2)
  931. return_socket_error(client->socket);
  932. else
  933. socket_set_ecu_var(client,arg2,MTX_U16);
  934. break;
  935. case SET_ECU_VAR_S16:
  936. if (args != 2)
  937. return_socket_error(client->socket);
  938. else
  939. socket_set_ecu_var(client,arg2,MTX_S16);
  940. break;
  941. case SET_ECU_VAR_U32:
  942. if (args != 2)
  943. return_socket_error(client->socket);
  944. else
  945. socket_set_ecu_var(client,arg2,MTX_U32);
  946. break;
  947. case SET_ECU_VAR_S32:
  948. if (args != 2)
  949. return_socket_error(client->socket);
  950. else
  951. socket_set_ecu_var(client,arg2,MTX_S32);
  952. break;
  953. case GO_BURN_FLASH:
  954. io_cmd_f(firmware->burn_all_command,NULL);
  955. break;
  956. case GET_SIGNATURE:
  957. if (!firmware)
  958. net_send(client->socket,(guint8 *)_("Not Connected yet"),strlen(_("Not Connected yet")));
  959. else
  960. {
  961. if (firmware->actual_signature)
  962. net_send(client->socket,(guint8 *)firmware->actual_signature,strlen(firmware->actual_signature));
  963. else
  964. net_send(client->socket,(guint8 *)_("Offline mode, no signature"),strlen(_("Offline mode, no signature")));
  965. }
  966. res = net_send(client->socket,(guint8 *)"\n\r",strlen("\n\r"));
  967. break;
  968. case GET_REVISION:
  969. if (!firmware)
  970. net_send(client->socket,(guint8 *)_("Not Connected yet"),strlen(_("Not Connected yet")));
  971. else
  972. {
  973. if (firmware->text_revision)
  974. net_send(client->socket,(guint8 *)firmware->text_revision,strlen(firmware->text_revision));
  975. else
  976. net_send(client->socket,(guint8 *)_("Offline mode, no revision"),strlen(_("Offline mode, no revision")));
  977. }
  978. res = net_send(client->socket,(guint8 *)"\n\r",strlen("\n\r"));
  979. break;
  980. case HELP:
  981. tmpbuf = g_strdup("\n\
  982. Supported Calls:\n\r\
  983. help\n\r\
  984. quit\n\r\
  985. get_signature <-- Returns ECU Signature\n\r\
  986. get_revision <-- Returns ECU Textual Revision\n\r\
  987. get_rtv_list <-- returns runtime variable listing\n\r\
  988. get_rt_vars,[*|<var1>,<var2>,...] <-- returns values of specified variables\n\r\tor all variables if '*' is specified\n\r\
  989. get_ecu_var_[u08|s08|u16|s16|u32|s32],<canID>,<page>,<offset> <-- returns the\n\r\tecu variable at the spcified location, if firmware\n\r\tis not CAN capable, use 0 for canID, likewise for non-paged\n\r\tfirmwares use 0 for page...\n\r\
  990. set_ecu_var_[u08|s08|u16|s16|u32|s32],<canID>,<page>,<offset>,<data> <-- Sets\n\r\tthe ecu variable at the spcified location, if firmware\n\r\tis not CAN capable, use 0 for canID, likewise for non-paged\n\r\tfirmwares use 0 for page...\n\r\
  991. get_ecu_page,<canID>,<page> <-- returns the whole ECU page at canID,page\n\r\
  992. burn_flash <-- Burns contents of ecu ram for current page to flash\n\r\n\r");
  993. net_send(client->socket,(guint8 *)tmpbuf,strlen(tmpbuf));
  994. g_free(tmpbuf);
  995. send_rescode = TRUE;
  996. break;
  997. case QUIT:
  998. tmpbuf = g_strdup("\rBuh Bye...\n\r");
  999. net_send(client->socket,(guint8 *)tmpbuf,strlen(tmpbuf));
  1000. g_free(tmpbuf);
  1001. retval = FALSE;
  1002. send_rescode = FALSE;
  1003. break;
  1004. default:
  1005. return_socket_error(client->socket);
  1006. break;
  1007. }
  1008. /* Send result code*/
  1009. if (send_rescode)
  1010. {
  1011. if (!DATA_GET(global_data,"connected"))
  1012. net_send(client->socket,(guint8 *)"NOT CONNECTED,",strlen("NOT CONNECTED,"));
  1013. if (check_for_changes(client))
  1014. net_send(client->socket,(guint8 *)"ECU_DATA_CHANGED,",strlen("ECU_DATA_CHANGED,"));
  1015. net_send(client->socket,(guint8 *)"OK",strlen("OK"));
  1016. net_send(client->socket,(guint8 *)"\n\r",strlen("\n\r"));
  1017. }
  1018. g_free(arg2);
  1019. EXIT();
  1020. return retval;
  1021. }
  1022. /*!
  1023. \brief simple wrapper function to spit back a generic error to a client
  1024. \param socket is a pointer to the network socket
  1025. */
  1026. G_MODULE_EXPORT void return_socket_error(GSocket *socket)
  1027. {
  1028. ENTER();
  1029. net_send(socket,(guint8 *)ERR_MSG,strlen(ERR_MSG));
  1030. net_send(socket,(guint8 *)"\n\r",strlen("\n\r"));
  1031. EXIT();
  1032. return;
  1033. }
  1034. /*!
  1035. \brief This returns the RTV vars requested by the comma separated string,
  1036. arg2
  1037. \param socket is the pointer to the open GSocket structure
  1038. \param arg2 is a command separated list of internal names of runtime
  1039. variables the remote end is interested in.
  1040. */
  1041. G_MODULE_EXPORT void socket_get_rt_vars(GSocket *socket, gchar *arg2)
  1042. {
  1043. gint res = 0;
  1044. gchar **vars = NULL;
  1045. guint i = 0;
  1046. guint j = 0;
  1047. gconstpointer * object = NULL;
  1048. gint tmpi = 0;
  1049. gfloat tmpf = 0.0;
  1050. GString *output;
  1051. Rtv_Map *rtv_map = NULL;
  1052. ENTER();
  1053. rtv_map = (Rtv_Map *)DATA_GET(global_data,"rtv_map");
  1054. vars = g_strsplit(arg2,",",-1);
  1055. output = g_string_sized_new(8);
  1056. for (i=0;i<g_strv_length(vars);i++)
  1057. {
  1058. if (g_ascii_strcasecmp(vars[i],"*")==0)
  1059. {
  1060. for (j=0;j<rtv_map->rtv_list->len;j++)
  1061. {
  1062. object = (gconstpointer *)g_ptr_array_index(rtv_map->rtv_list,j);
  1063. lookup_current_value_f((gchar *)DATA_GET(object,"internal_names"),&tmpf);
  1064. lookup_precision_f((gchar *)DATA_GET(object,"internal_names"),&tmpi);
  1065. if (j < (rtv_map->rtv_list->len-1))
  1066. g_string_append_printf(output,"%1$.*2$f ",tmpf,tmpi);
  1067. else
  1068. g_string_append_printf(output,"%1$.*2$f\n\r",tmpf,tmpi);
  1069. }
  1070. }
  1071. else
  1072. {
  1073. lookup_current_value_f(vars[i],&tmpf);
  1074. lookup_precision_f(vars[i],&tmpi);
  1075. if (i < (g_strv_length(vars)-1))
  1076. g_string_append_printf(output,"%1$.*2$f ",tmpf,tmpi);
  1077. else
  1078. g_string_append_printf(output,"%1$.*2$f\n\r",tmpf,tmpi);
  1079. }
  1080. }
  1081. res = net_send(socket,(guint8 *)output->str,output->len);
  1082. g_string_free(output,TRUE);
  1083. g_strfreev(vars);
  1084. EXIT();
  1085. return;
  1086. }
  1087. /*!
  1088. \brief Echos back to the client a list of all avaialble runtime variables
  1089. \param socket is a pointer to the active GSocket structure
  1090. */
  1091. G_MODULE_EXPORT void socket_get_rtv_list(GSocket *socket)
  1092. {
  1093. guint i = 0;
  1094. gint res = 0;
  1095. gint len = 0;
  1096. gchar * tmpbuf = NULL;
  1097. gconstpointer * object = NULL;
  1098. Rtv_Map *rtv_map = NULL;
  1099. ENTER();
  1100. rtv_map = (Rtv_Map *)DATA_GET(global_data,"rtv_map");
  1101. for (i=0;i<rtv_map->rtv_list->len;i++)
  1102. {
  1103. object = (gconstpointer *)g_ptr_array_index(rtv_map->rtv_list,i);
  1104. if (i < rtv_map->rtv_list->len-1)
  1105. tmpbuf = g_strdup_printf("%s ",(gchar *)DATA_GET(object,"internal_names"));
  1106. else
  1107. tmpbuf = g_strdup_printf("%s",(gchar *)DATA_GET(object,"internal_names"));
  1108. if (tmpbuf)
  1109. {
  1110. len = strlen(tmpbuf);
  1111. res = net_send(socket,(guint8 *)tmpbuf,len);
  1112. if (res != len)
  1113. printf(_("SHORT WRITE!\n"));
  1114. g_free(tmpbuf);
  1115. }
  1116. }
  1117. tmpbuf = g_strdup("\r\n");
  1118. len = strlen(tmpbuf);
  1119. res = net_send(socket,(guint8 *)tmpbuf,len);
  1120. if (len != res)
  1121. printf(_("SHORT WRITE!\n"));
  1122. g_free(tmpbuf);
  1123. EXIT();
  1124. return;
  1125. }
  1126. /*!
  1127. \brief The client requested an ECU variable, validate its request and return
  1128. the value back to the client
  1129. \param client is a pointer to the active MtxSocketclient structure
  1130. \param arg2 is a comma separated list of coordinates, i.e. canID,page,
  1131. and offset. All three are required,
  1132. \param size is the size enumeration of the data to retrieve
  1133. */
  1134. G_MODULE_EXPORT void socket_get_ecu_var(MtxSocketClient *client, gchar *arg2, DataSize size)
  1135. {
  1136. gchar ** vars = NULL;
  1137. gchar * tmpbuf = NULL;
  1138. Firmware_Details *firmware = NULL;
  1139. ENTER();
  1140. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  1141. /* We want canID, page, offset
  1142. * If firmware in use doesn't have canBUS capability
  1143. * just use zero for the option, likewise for page
  1144. */
  1145. vars = g_strsplit(arg2,",",-1);
  1146. if (g_strv_length(vars) != 3)
  1147. {
  1148. return_socket_error(client->socket);
  1149. g_strfreev(vars);
  1150. }
  1151. else
  1152. {
  1153. gint canID = atoi(vars[0]);
  1154. gint page = atoi(vars[1]);
  1155. gint offset = atoi(vars[2]);
  1156. gint tmpi = ms_get_ecu_data(canID,page,offset,size);
  1157. _set_sized_data_f(client->ecu_data[page],offset,size,tmpi,firmware->bigendian);
  1158. tmpbuf = g_strdup_printf("%i\r\n",tmpi);
  1159. gint len = strlen(tmpbuf);
  1160. gint res = net_send(client->socket,(guint8 *)tmpbuf,len);
  1161. if (len != res)
  1162. printf(_("SHORT WRITE!\n"));
  1163. g_free(tmpbuf);
  1164. g_strfreev(vars);
  1165. }
  1166. EXIT();
  1167. return;
  1168. }
  1169. /*!
  1170. \brief The client requested multiple ECU variables, validate its request
  1171. and return the values back to the client
  1172. \param client is a pointer to the active MtxSocketclient structure
  1173. \param arg2 is a 2 value comma separated list of coordinates,
  1174. i.e. canID and page, This fucntion returns the WHOLE PAGE
  1175. */
  1176. G_MODULE_EXPORT void socket_get_ecu_page(MtxSocketClient *client, gchar *arg2)
  1177. {
  1178. gchar ** vars = NULL;
  1179. GString * output = NULL;
  1180. Firmware_Details *firmware = NULL;
  1181. ENTER();
  1182. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  1183. /* We want canID, page
  1184. * If firmware in use doesn't have canBUS capability
  1185. * just use zero for the option, likewise for page
  1186. */
  1187. vars = g_strsplit(arg2,",",-1);
  1188. if (g_strv_length(vars) != 2)
  1189. {
  1190. return_socket_error(client->socket);
  1191. g_strfreev(vars);
  1192. }
  1193. else
  1194. {
  1195. gint canID = atoi(vars[0]);
  1196. gint page = atoi(vars[1]);
  1197. gint len = firmware->page_params[page]->length;
  1198. gint tmpi = 0;
  1199. output = g_string_sized_new(8);
  1200. for (gint i=0;i<len;i++)
  1201. {
  1202. tmpi = ms_get_ecu_data(canID,page,i,MTX_U08);
  1203. _set_sized_data_f(client->ecu_data[page],i,MTX_U08,tmpi,firmware->bigendian);
  1204. if (i < (len -1))
  1205. g_string_append_printf(output,"%i,",tmpi);
  1206. else
  1207. g_string_append_printf(output,"%i\n\r",tmpi);
  1208. }
  1209. g_strfreev(vars);
  1210. net_send(client->socket,(guint8 *)output->str,output->len);
  1211. g_string_free(output,TRUE);
  1212. }
  1213. EXIT();
  1214. return;
  1215. }
  1216. /*!
  1217. \brief The slave is updating an ECU location in memory, validate it, update
  1218. which will trigger the master Gui and all slave gui's to update accordingly
  1219. \param client is a pointer to the MtxSocketClient structure
  1220. \param args is the coordinates (4 values required), canID, page, offset,
  1221. and the new data
  1222. \param size is hte size to store.
  1223. \bug this function works properly only for 8 bit values....
  1224. */
  1225. G_MODULE_EXPORT void socket_set_ecu_var(MtxSocketClient *client, gchar *arg2, DataSize size)
  1226. {
  1227. gchar ** vars = NULL;
  1228. Firmware_Details *firmware = NULL;
  1229. ENTER();
  1230. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  1231. /* We want canID, page, offset, data
  1232. * If firmware in use doesn't have canBUS capability
  1233. * just use zero for the option, likewise for page
  1234. */
  1235. vars = g_strsplit(arg2,",",-1);
  1236. if (g_strv_length(vars) != 4)
  1237. {
  1238. return_socket_error(client->socket);
  1239. g_strfreev(vars);
  1240. }
  1241. else
  1242. {
  1243. gint canID = atoi(vars[0]);
  1244. gint page = atoi(vars[1]);
  1245. gint offset = atoi(vars[2]);
  1246. gint data = atoi(vars[3]);
  1247. _set_sized_data_f(client->ecu_data[page],offset,size,data,firmware->bigendian);
  1248. ms_send_to_ecu(canID,page,offset,size,data,TRUE);
  1249. g_strfreev(vars);
  1250. }
  1251. EXIT();
  1252. return;
  1253. }
  1254. /*!
  1255. \brief compares the content of the master's representation of ECU memory with
  1256. the slave's, if they match return FALSE, if not, return TRUE
  1257. \param client is a pointer to the active socket client
  1258. */
  1259. G_MODULE_EXPORT gboolean check_for_changes(MtxSocketClient *client)
  1260. {
  1261. gint i = 0;
  1262. Firmware_Details *firmware = NULL;
  1263. ENTER();
  1264. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  1265. if (!firmware)
  1266. {
  1267. EXIT();
  1268. return FALSE;
  1269. }
  1270. for (i=0;i<firmware->total_pages;i++)
  1271. {
  1272. if (!firmware->page_params[i]->dl_by_default)
  1273. continue;
  1274. if (!firmware->ecu_data[i])
  1275. continue;
  1276. if(memcmp(client->ecu_data[i],firmware->ecu_data[i],firmware->page_params[i]->length) != 0)
  1277. {
  1278. EXIT();
  1279. return TRUE;
  1280. }
  1281. }
  1282. EXIT();
  1283. return FALSE;
  1284. }
  1285. /*!
  1286. \brief this is analagous to the serial_repair_thread and goes through the
  1287. motions of trying to reconnect to the target if the connection is lost
  1288. \param data is unused
  1289. \see serial_repair_thread
  1290. */
  1291. G_MODULE_EXPORT void *network_repair_thread(gpointer data)
  1292. {
  1293. /* - DEV code for setting up connection to a network socket
  1294. * in place of a serial port, useful for chaining instances of
  1295. * megatunix to a master, allows "group mind" tuning, or a complete
  1296. * disaster...
  1297. */
  1298. static gboolean network_is_open = FALSE; /* Assume never opened */
  1299. static GAsyncQueue *io_repair_queue;
  1300. void (*setup_serial_params_f)(void) = NULL;
  1301. volatile gboolean autodetect = TRUE;
  1302. gchar * host = NULL;
  1303. gint port = 0;
  1304. gchar ** vector = NULL;
  1305. CmdLineArgs *args = NULL;
  1306. ENTER();
  1307. get_symbol_f("setup_serial_params",(void **)&setup_serial_params_f);
  1308. args = (CmdLineArgs *)DATA_GET(global_data,"args");
  1309. g_return_val_if_fail(args,NULL);
  1310. g_return_val_if_fail(setup_serial_params_f,NULL);
  1311. MTXDBG(THREADS|CRITICAL,_("Thread created!\n"));
  1312. if (DATA_GET(global_data,"offline"))
  1313. {
  1314. g_timeout_add(100,(gboolean (*)(void*))queue_function_f,(gpointer)"kill_conn_warning");
  1315. g_thread_exit(0);
  1316. }
  1317. if (!io_repair_queue)
  1318. io_repair_queue = (GAsyncQueue *)DATA_GET(global_data,"io_repair_queue");
  1319. /* IF network_is_open is true, then the port was ALREADY opened
  1320. * previously but some error occurred that sent us down here. Thus
  1321. * first do a simple comms test, if that succeeds, then just cleanup
  1322. * and return, if not, close the port and essentially start over.
  1323. */
  1324. if (network_is_open == TRUE)
  1325. {
  1326. MTXDBG(SERIAL_RD|SERIAL_WR,_("Port considered open, but throwing errors\n"));
  1327. gint i = 0;
  1328. while (i <= 5)
  1329. {
  1330. MTXDBG(SERIAL_RD|SERIAL_WR,_("Calling comms_test, attempt %i\n"),i);
  1331. if (comms_test())
  1332. {
  1333. g_thread_exit(0);
  1334. }
  1335. i++;
  1336. }
  1337. close_network();
  1338. close_control_socket();
  1339. network_is_open = FALSE;
  1340. /* Fall through */
  1341. }
  1342. /* App just started, no connection yet*/
  1343. while (network_is_open == FALSE)
  1344. {
  1345. /* Message queue used to exit immediately */
  1346. if (g_async_queue_try_pop(io_repair_queue))
  1347. {
  1348. g_timeout_add(100,(gboolean (*)(void*))queue_function_f,(gpointer)"kill_conn_warning");
  1349. g_thread_exit(0);
  1350. }
  1351. autodetect = (GBOOLEAN) DATA_GET(global_data,"autodetect_port");
  1352. if (!autodetect)
  1353. {
  1354. vector = g_strsplit((gchar *)DATA_GET(global_data, "override_port"),":",2);
  1355. if (g_strv_length(vector) == 2)
  1356. {
  1357. host = vector[0];
  1358. port = strtol(vector[1],NULL,10);
  1359. }
  1360. else
  1361. {
  1362. host = args->network_host;
  1363. port = args->network_port;
  1364. }
  1365. }
  1366. else
  1367. {
  1368. host = args->network_host;
  1369. port = args->network_port;
  1370. }
  1371. thread_update_logbar_f("comms_view",NULL,g_strdup_printf(_("Attempting to open connection to %s:%i\n"),host,port),FALSE,FALSE);
  1372. if (open_network(host,port))
  1373. {
  1374. setup_serial_params_f();
  1375. thread_update_logbar_f("comms_view",NULL,g_strdup_printf(_("Network Connection established to %s:%i\n"),host,port),FALSE,FALSE);
  1376. if (comms_test())
  1377. {
  1378. network_is_open = TRUE;
  1379. thread_update_logbar_f("comms_view","info",g_strdup_printf(_("Comms Test Success!, Opening Control Socket\n")),FALSE,FALSE);
  1380. open_control_socket(host,MTX_SOCKET_CONTROL_PORT);
  1381. g_free(vector);
  1382. break;
  1383. }
  1384. else
  1385. {
  1386. thread_update_logbar_f("comms_view","warning",g_strdup_printf(_("Comms Test failed, closing port\n")),FALSE,FALSE);
  1387. close_network();
  1388. close_control_socket();
  1389. g_free(vector);
  1390. g_usleep(200000); /* Sleep 200ms */
  1391. continue;
  1392. }
  1393. }
  1394. else
  1395. {
  1396. thread_update_logbar_f("comms_view","warning",g_strdup_printf(_("Failed to open network connection to %s:%i, sleeping...\n"),host,port),FALSE,FALSE);
  1397. g_usleep(500000); /* Sleep 500ms */
  1398. }
  1399. }
  1400. if (network_is_open)
  1401. {
  1402. thread_update_widget_f("active_port_entry",MTX_ENTRY,g_strdup_printf("%s:%i",host,port));
  1403. }
  1404. g_thread_exit(0);
  1405. EXIT();
  1406. return NULL;
  1407. }
  1408. /*!
  1409. \brief Opens a network connection to a remote machine, sets up the global
  1410. Serial_Params structure on success
  1411. \param host is the name of the remote host
  1412. \param port is the port on the target to attempt to open
  1413. \returns TRUE on success, FALSE otherwise
  1414. */
  1415. G_MODULE_EXPORT gboolean open_network(gchar * host, gint port)
  1416. {
  1417. GSocket *clientsocket = NULL;
  1418. gint status = 0;
  1419. GSocketAddress *sockaddr = NULL;
  1420. GError *error = NULL;
  1421. GResolver *resolver = NULL;
  1422. GList *list = NULL;
  1423. Serial_Params *serial_params;
  1424. serial_params = (Serial_Params *)DATA_GET(global_data,"serial_params");
  1425. ENTER();
  1426. clientsocket = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &error);
  1427. if (!clientsocket)
  1428. {
  1429. MTXDBG(CRITICAL|SERIAL_RD|SERIAL_WR,_("Socket open error: %s\n"),error->message);
  1430. g_error_free(error);
  1431. error = NULL;
  1432. EXIT();
  1433. return FALSE;
  1434. }
  1435. resolver = g_resolver_get_default();
  1436. list = g_resolver_lookup_by_name(resolver,host,NULL,NULL);
  1437. sockaddr = g_inet_socket_address_new((GInetAddress *)g_list_nth_data(list,0),port);
  1438. status = g_socket_connect(clientsocket,sockaddr,NULL,&error);
  1439. if (!status)
  1440. {
  1441. MTXDBG(SERIAL_RD|SERIAL_WR,_("Socket connect error: %s\n"),error->message);
  1442. g_error_free(error);
  1443. error = NULL;
  1444. EXIT();
  1445. return FALSE;
  1446. }
  1447. g_resolver_free_addresses(list);
  1448. g_object_unref(resolver);
  1449. g_object_unref(sockaddr);
  1450. /* printf("connected!!\n");*/
  1451. serial_params->fd = g_socket_get_fd(clientsocket);
  1452. serial_params->socket = clientsocket;
  1453. serial_params->net_mode = TRUE;
  1454. serial_params->open = TRUE;
  1455. EXIT();
  1456. return TRUE;
  1457. }
  1458. /*!
  1459. \brief closes the binary socket
  1460. */
  1461. G_MODULE_EXPORT gboolean close_network(void)
  1462. {
  1463. Serial_Params *serial_params;
  1464. ENTER();
  1465. serial_params = (Serial_Params *)DATA_GET(global_data,"serial_params");
  1466. /* printf("Closing network port!\n");*/
  1467. g_socket_shutdown(serial_params->socket,TRUE,TRUE,NULL);
  1468. g_socket_close(serial_params->socket,NULL);
  1469. serial_params->open = FALSE;
  1470. serial_params->fd = -1;
  1471. DATA_SET(global_data,"connected",GINT_TO_POINTER(FALSE));
  1472. EXIT();
  1473. return TRUE;
  1474. }
  1475. /*!
  1476. \brief closes the control socket
  1477. */
  1478. G_MODULE_EXPORT gboolean close_control_socket(void)
  1479. {
  1480. Serial_Params *serial_params;
  1481. ENTER();
  1482. serial_params = (Serial_Params *)DATA_GET(global_data,"serial_params");
  1483. g_socket_shutdown(serial_params->ctrl_socket,TRUE,TRUE,NULL);
  1484. g_socket_close(serial_params->ctrl_socket,NULL);
  1485. serial_params->ctrl_socket = NULL;
  1486. EXIT();
  1487. return TRUE;
  1488. }
  1489. /*!
  1490. \brief notify_slaves_thread()'s sole purpose in life is to listen for
  1491. messages on the async queue from the IO core for messages to send to slaves
  1492. and dispatch them out. It should check if a slave disconected and in that
  1493. case delete their entry from the slave list.
  1494. \param data (gpointer) unused.
  1495. */
  1496. G_MODULE_EXPORT void *notify_slaves_thread(gpointer data)
  1497. {
  1498. static GAsyncQueue *slave_msg_queue = NULL;
  1499. static Firmware_Details *firmware = NULL;
  1500. GtkWidget *widget = NULL;
  1501. gchar * tmpbuf = NULL;
  1502. SlaveMessage *msg = NULL;
  1503. MtxSocketClient * cli_data = NULL;
  1504. fd_set wr;
  1505. gboolean *to_be_closed = NULL;
  1506. guint i = 0;
  1507. gint fd = 0;
  1508. gint res = 0;
  1509. gint len = 0;
  1510. guint8 *buffer = NULL;
  1511. ENTER();
  1512. if (!firmware)
  1513. firmware = (Firmware_Details *)DATA_GET(global_data,"firmware");
  1514. if (!slave_msg_queue)
  1515. slave_msg_queue = (GAsyncQueue *)DATA_GET(global_data,"slave_msg_queue");
  1516. g_return_val_if_fail(firmware,NULL);
  1517. g_return_val_if_fail(slave_msg_queue,NULL);
  1518. MTXDBG(THREADS|CRITICAL,_("Thread created!\n"));
  1519. while(TRUE) /* endless loop */
  1520. {
  1521. if ((DATA_GET(global_data,"leaving")) || (!(GBOOLEAN)DATA_GET(global_data,"network_access")))
  1522. {
  1523. /* drain queue and exit thread */
  1524. while (g_async_queue_try_pop(slave_msg_queue) != NULL)
  1525. {}
  1526. /* Deallocate and exit! */
  1527. if (slave_list)
  1528. {
  1529. for (gint i=0;i<slave_list->len;i++)
  1530. {
  1531. cli_data = (MtxSocketClient *)g_ptr_array_index(slave_list,i);
  1532. g_socket_close(cli_data->control_socket,NULL);
  1533. g_ptr_array_remove(slave_list,cli_data);
  1534. dealloc_client_data(cli_data);
  1535. }
  1536. }
  1537. g_thread_exit(0);
  1538. }
  1539. msg = (SlaveMessage *)g_async_queue_timeout_pop(slave_msg_queue,100000);
  1540. if (!slave_list) /* List not created yet.. */
  1541. continue;
  1542. if (!msg) /* Null message)*/
  1543. continue;
  1544. /*printf("There are %i clients in the slave pointer array\n",slave_list->len);
  1545. */
  1546. to_be_closed = g_new0(gboolean, slave_list->len);
  1547. for (gint i=0;i<slave_list->len;i++)
  1548. {
  1549. cli_data = (MtxSocketClient *)g_ptr_array_index(slave_list,i);
  1550. if ((!cli_data) || (!cli_data->ecu_data[0]))
  1551. {
  1552. to_be_closed[i] = TRUE;
  1553. continue;
  1554. }
  1555. fd = g_socket_get_fd(cli_data->control_socket);
  1556. FD_ZERO(&wr);
  1557. FD_SET(fd,&wr);
  1558. res = select(fd+1,NULL,&wr,NULL,NULL);
  1559. if (res <= 0)
  1560. {
  1561. /* printf("Select error!, closing this socket\n");*/
  1562. to_be_closed[i] = TRUE;
  1563. continue;
  1564. }
  1565. /*
  1566. printf("sending chunk update\n");
  1567. printf("notify slaves, slave %p, ecu_data %p\n",cli_data,cli_data->ecu_data);
  1568. */
  1569. /* We need to check if this slave sent the update,
  1570. * if so, DO NOT send the same thing back to that
  1571. * slave as he already knows....
  1572. */
  1573. if (msg->type == MTX_DATA_CHANGED)
  1574. {
  1575. if (msg->mode == MTX_SIMPLE_WRITE)
  1576. {
  1577. if (_get_sized_data_f(cli_data->ecu_data[msg->page],msg->offset,MTX_U08,firmware->bigendian) == ms_get_ecu_data(0,msg->page,msg->offset,MTX_U08))
  1578. continue;
  1579. }
  1580. if (msg->mode == MTX_CHUNK_WRITE)
  1581. {
  1582. if (memcmp (cli_data->ecu_data[msg->page]+msg->offset,firmware->ecu_data[msg->page]+msg->offset,msg->length) == 0)
  1583. continue;
  1584. }
  1585. buffer = build_netmsg(SLAVE_MEMORY_UPDATE,msg,&len);
  1586. res = net_send(cli_data->control_socket,(guint8 *)buffer,len);
  1587. if (res == len)
  1588. {
  1589. if (msg->mode == MTX_SIMPLE_WRITE)
  1590. _set_sized_data_f(cli_data->ecu_data[msg->page],msg->offset,msg->size,msg->value,firmware->bigendian);
  1591. else if (msg->mode == MTX_CHUNK_WRITE)
  1592. memcpy (cli_data->ecu_data[msg->page],&msg->value,msg->length);
  1593. }
  1594. else
  1595. printf(_("Peer update WRITE ERROR!\n"));
  1596. g_free(buffer);
  1597. }
  1598. if (msg->type == MTX_STATUS_CHANGED)
  1599. {
  1600. buffer = build_status_update(SLAVE_STATUS_UPDATE,msg,&len);
  1601. res = net_send(cli_data->control_socket,(guint8 *)buffer,len);
  1602. if (res != len)
  1603. printf(_("Peer update WRITE ERROR!\n"));
  1604. g_free(buffer);
  1605. }
  1606. if (res == -1)
  1607. to_be_closed[i] = TRUE;
  1608. }
  1609. for (i=0;i<slave_list->len;i++)
  1610. {
  1611. if (to_be_closed[i])
  1612. {
  1613. cli_data = (MtxSocketClient *)g_ptr_array_index(slave_list,i);
  1614. g_socket_close(cli_data->control_socket,NULL);

Large files files are truncated, but you can click here to view the full file