emu_server.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. MSP430 Emulator
  3. Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
  4. "MSP430 Emulator" is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. "MSP430 Emulator" is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include <string.h>
  16. #include "emu_server.h"
  17. #define TXIFG 0x02
  18. #define RXIFG 0x01
  19. #define HIGH 1
  20. #define LOW 0
  21. #define OUT 1
  22. #define IN 0
  23. //
  24. #define MAX_UPLOAD_FILENAME_SIZE 0xFFFF+1
  25. char UploadFileName[MAX_UPLOAD_FILENAME_SIZE] = {0};
  26. Emulator *emu = NULL;
  27. uint8_t *data;
  28. int lent;
  29. void *thrd (void *ctxt)
  30. {
  31. Usci *usci = (Usci *)ctxt;
  32. int i, j = 0;
  33. int len = lent;
  34. uint8_t *bytes = data;
  35. //printf("len is %d\nstr is %s\n", len, bytes);
  36. while (true) {
  37. usleep(333);
  38. while (*usci->IFG2 & RXIFG);
  39. uint8_t thing = *(bytes);
  40. if (thing == '\n') {
  41. thing = '\r';
  42. }
  43. //printf("Got 0x%02X '%c'\n", thing, thing);
  44. if (*bytes == '\\') {
  45. ++bytes;
  46. if (*bytes == 'h' || *bytes == 'H') {
  47. ++bytes;
  48. char buf[3] = {*((char*)bytes), *((char*)bytes+1), 0};
  49. //printf("%s - %s\n", buf, bytes);
  50. thing = (uint8_t) strtoul(buf, NULL, 16);
  51. ++bytes;
  52. }
  53. }
  54. *usci->UCA0RXBUF = thing;
  55. *usci->IFG2 |= RXIFG;
  56. //printf("\n0x%04X in UCA0RXBUF\n", (uint8_t)*usci->UCA0RXBUF);
  57. //puts("waiting..");
  58. while (*usci->IFG2 & RXIFG);
  59. //puts("done");
  60. //*usci->IFG2 |= RXIFG;
  61. if (*usci->UCA0RXBUF == '\r') break;
  62. ++bytes;
  63. }
  64. return NULL;
  65. }
  66. int callback_emu (struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
  67. {
  68. Cpu *cpu = emu->cpu;
  69. Port_1 *p1 = emu->cpu->p1;
  70. Debugger *deb = emu->debugger;
  71. switch (reason)
  72. {
  73. case LWS_CALLBACK_ESTABLISHED:
  74. {
  75. puts("connection established");
  76. // Flip ready flag for the emulator to begin
  77. deb->web_server_ready = true;
  78. // get the ball rolling
  79. //libwebsocket_callback_on_writable(this, wsi);
  80. lws_callback_on_writable(wsi);
  81. break;
  82. }
  83. case LWS_CALLBACK_SERVER_WRITEABLE:
  84. {
  85. if ( !packet_queue_empty(emu) )
  86. {
  87. Packet p = packet_dequeue(emu);
  88. void *msg = p.message;
  89. size_t msg_len = p.length;
  90. uint8_t op = p.opcode;
  91. //printf("[%s] of len %u, opcode: %u\n\n",
  92. //(char *)msg, (unsigned int)msg_len, op);
  93. // Leave room for websock header/trailer & opcode
  94. size_t pack_len = msg_len + sizeof(op) + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
  95. void *packet = malloc(pack_len);
  96. // Zero out our packet
  97. memset( ((uint8_t*)packet + LWS_SEND_BUFFER_PRE_PADDING), 0, msg_len + sizeof(op) );
  98. // Place opcode into packet
  99. *((uint8_t *)((uint8_t*)packet + LWS_SEND_BUFFER_PRE_PADDING)) = op;
  100. // Place message into packet
  101. memcpy( ((uint8_t*)packet + LWS_SEND_BUFFER_PRE_PADDING + sizeof(op)), (const void *)p.message, msg_len);
  102. /*
  103. int i;
  104. for (i = 0;i < pack_len;i++){
  105. printf( "%02X (%c) | ", *((uint8_t *)(packet+i)),
  106. *((char *)(packet+i)) );
  107. }
  108. puts("\n");
  109. */
  110. lws_write(wsi, ((unsigned char*)(packet))+LWS_SEND_BUFFER_PRE_PADDING, msg_len + sizeof(op), LWS_WRITE_BINARY);
  111. free(p.message);
  112. free(packet);
  113. }
  114. static bool p1_0_on = false;
  115. static bool p1_1_on = false;
  116. static bool p1_2_on = false;
  117. static bool p1_3_on = false;
  118. static bool p1_4_on = false;
  119. static bool p1_5_on = false;
  120. static bool p1_6_on = false;
  121. static bool p1_7_on = false;
  122. // P1.0 ON/OFF
  123. if (p1->DIR_0 == OUT)
  124. {
  125. if (p1->OUT_0 == HIGH)
  126. {
  127. if (p1_0_on == false)
  128. {
  129. send_control(emu, P1_0_ON_PACKET, NULL, 0);
  130. p1_0_on = true;
  131. }
  132. }
  133. else if (p1->OUT_0 == LOW)
  134. {
  135. if (p1_0_on == true)
  136. {
  137. send_control(emu, P1_0_OFF_PACKET, NULL, 0);
  138. p1_0_on = false;
  139. }
  140. }
  141. }
  142. // P1.1 ON/OFF
  143. if (p1->DIR_1 == OUT) {
  144. if (p1->OUT_1 == HIGH) {
  145. if (p1_1_on == false) {
  146. send_control(emu, P1_1_ON_PACKET, NULL, 0);
  147. p1_1_on = true;
  148. }
  149. }
  150. else if (p1->OUT_1 == LOW) {
  151. if (p1_1_on == true) {
  152. send_control(emu, P1_1_OFF_PACKET, NULL, 0);
  153. p1_1_on = false;
  154. }
  155. }
  156. }
  157. // P1.2 ON/OFF
  158. if (p1->DIR_2 == OUT) {
  159. if (p1->OUT_2 == HIGH) {
  160. if (p1_2_on == false) {
  161. send_control(emu, P1_2_ON_PACKET, NULL, 0);
  162. puts("p2 on");
  163. p1_2_on = true;
  164. }
  165. }
  166. else if (p1->OUT_2 == LOW) {
  167. if (p1_2_on == true) {
  168. send_control(emu, P1_2_OFF_PACKET, NULL, 0);
  169. p1_2_on = false;
  170. }
  171. }
  172. }
  173. // P1.3 ON/OFF
  174. if (p1->DIR_3 == OUT) {
  175. if (p1->OUT_3 == HIGH) {
  176. if (p1_3_on == false) {
  177. send_control(emu, P1_3_ON_PACKET, NULL, 0);
  178. p1_3_on = true;
  179. }
  180. }
  181. else if (p1->OUT_3 == LOW) {
  182. if (p1_3_on == true) {
  183. send_control(emu, P1_3_OFF_PACKET, NULL, 0);
  184. p1_3_on = false;
  185. }
  186. }
  187. }
  188. // P1.4 ON/OFF
  189. if (p1->DIR_4 == OUT) {
  190. if (p1->OUT_4 == HIGH) {
  191. if (p1_4_on == false) {
  192. send_control(emu, P1_4_ON_PACKET, NULL, 0);
  193. p1_4_on = true;
  194. }
  195. }
  196. else if (p1->OUT_4 == LOW) {
  197. if (p1_4_on == true) {
  198. send_control(emu, P1_4_OFF_PACKET, NULL, 0);
  199. p1_4_on = false;
  200. }
  201. }
  202. }
  203. // P1.5 ON/OFF
  204. if (p1->DIR_5 == OUT) {
  205. if (p1->OUT_5 == HIGH) {
  206. if (p1_5_on == false) {
  207. send_control(emu, P1_5_ON_PACKET, NULL, 0);
  208. p1_5_on = true;
  209. }
  210. }
  211. else if (p1->OUT_5 == LOW) {
  212. if (p1_5_on == true) {
  213. send_control(emu, P1_5_OFF_PACKET, NULL, 0);
  214. p1_5_on = false;
  215. }
  216. }
  217. }
  218. // P1.6 ON/OFF
  219. if (p1->DIR_6 == OUT) {
  220. if (p1->OUT_6 == HIGH) {
  221. if (p1_6_on == false) {
  222. send_control(emu, P1_6_ON_PACKET, NULL, 0);
  223. p1_6_on = true;
  224. }
  225. }
  226. else if (p1->OUT_6 == LOW) {
  227. if (p1_6_on == true) {
  228. send_control(emu, P1_6_OFF_PACKET, NULL, 0);
  229. p1_6_on = false;
  230. }
  231. }
  232. }
  233. // P1.7 ON/OFF
  234. if (p1->DIR_7 == OUT) {
  235. if (p1->OUT_7 == HIGH) {
  236. if (p1_7_on == false) {
  237. send_control(emu, P1_7_ON_PACKET, NULL, 0);
  238. p1_7_on = true;
  239. }
  240. }
  241. else if (p1->OUT_7 == LOW) {
  242. if (p1_7_on == true) {
  243. send_control(emu, P1_7_OFF_PACKET, NULL, 0);
  244. p1_7_on = false;
  245. }
  246. }
  247. }
  248. lws_callback_on_writable( wsi);
  249. break;
  250. }
  251. case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
  252. puts("Connection Error");
  253. break;
  254. }
  255. case LWS_CALLBACK_CLOSED: {
  256. puts("Connection Closed");
  257. exit(0);
  258. break;
  259. }
  260. case LWS_CALLBACK_CLIENT_WRITEABLE: {
  261. puts("cli writable");
  262. break;
  263. }
  264. case LWS_CALLBACK_RECEIVE:
  265. {
  266. static FILE *fp = NULL;
  267. static bool upload_in_progress = false;
  268. static uint32_t uploaded_bytes;
  269. static uint16_t FileSize = 0;
  270. char *buf = (char *)in;
  271. if (upload_in_progress)
  272. { // Continue transaction of upload
  273. int i;
  274. for (i = 0;i < len;i++)
  275. {
  276. fwrite(&buf[i], 1, 1, fp);
  277. uploaded_bytes++;
  278. if (uploaded_bytes >= FileSize)
  279. {
  280. puts("met bytes");
  281. fclose(fp);
  282. // system("msp430-objcopy -O binary tmp.elf tmp.bin");
  283. char cmdline[255] = "objcopy -I elf32-little -O binary \"";
  284. strcat(cmdline, UploadFileName);
  285. strcat(cmdline, "\" tmp.bin");
  286. system(cmdline);
  287. // std::string ObjCopyLine = "objcopy -I elf32-little -O binary \"" + std::string(UploadFileName) + "\" tmp.bin";
  288. // system(ObjCopyLine.c_str());
  289. deb->web_firmware_uploaded = true;
  290. upload_in_progress = false;
  291. return 0;
  292. }
  293. }
  294. return 0;
  295. }
  296. unsigned char opcode = buf[0];
  297. printf("opcode: %02X\n", *(uint8_t*)in);
  298. switch (opcode)
  299. {
  300. case 0x00: // Upload File
  301. {
  302. // Get the 32-bit length of the file
  303. FileSize = ntohs( *((uint16_t*)((uint8_t*)in + 1)) );
  304. // Get the 8-bit length of the ASCII filename
  305. uint16_t FileNameSize = ntohs(*((uint16_t*)((uint8_t*)in + 3)));
  306. printf(" Got file size %u, got data len %u for first callback.\n", (unsigned int)FileSize, (unsigned int)len);
  307. // Ensure that the file isn't too big, otherwise just quit on the user for now
  308. if (FileSize >= 0xFFFF)
  309. {
  310. print_console(emu, "File Size Not Supported. Quitting.\n");
  311. deb->quit = true;
  312. exit(1);
  313. }
  314. // for now assume the entire filename is uploaded, and has no 0 at the end so add one
  315. memset(UploadFileName, 0, MAX_UPLOAD_FILENAME_SIZE);
  316. memmove(&UploadFileName[0], &buf[5], FileNameSize);
  317. printf(" Got name size %u, name %s.\n", FileNameSize, UploadFileName);
  318. upload_in_progress = true;
  319. uploaded_bytes = 0;
  320. fp = fopen(UploadFileName, "wb");
  321. // Get Any Bytes that are in with this packet
  322. for (uint32_t i = 5+FileNameSize;i < len;i++)
  323. {
  324. fwrite(&buf[i], 1, 1, fp);
  325. uploaded_bytes++;
  326. if (uploaded_bytes >= FileSize)
  327. {
  328. puts("met bytes");
  329. fclose(fp);
  330. //system("msp430-objcopy -O binary tmp.elf tmp.bin");
  331. // std::string ObjCopyLine = "objcopy -I elf32-little -O binary \"" + std::string(UploadFileName) + "\" tmp.bin";
  332. // system(ObjCopyLine.c_str());
  333. char cmdline[255] = "objcopy -I elf32-little -O binary \"";
  334. strcat(cmdline, UploadFileName);
  335. strcat(cmdline, "\" tmp.bin");
  336. system(cmdline);
  337. deb->web_firmware_uploaded = true;
  338. upload_in_progress = false;
  339. return 0;
  340. }
  341. }
  342. break;
  343. }
  344. case 0x01: { // PLAY
  345. printf("Got play\n");
  346. cpu->running = true;
  347. deb->debug_mode = false;
  348. update_register_display(emu);
  349. return 0;
  350. }
  351. case 0x02: { // PAUSE
  352. printf("Got pause\n");
  353. if (cpu->running) {
  354. cpu->running = false;
  355. deb->debug_mode = true;
  356. // display first round of registers
  357. display_registers(emu);
  358. disassemble(emu, cpu->pc, 1);
  359. update_register_display(emu);
  360. }
  361. return 0;
  362. }
  363. case 0x03: { // SERIAL DATA
  364. if (len > 1000) exit(1);
  365. lent = len - 1;
  366. data = ((uint8_t*)in + 1);
  367. pthread_t t;
  368. if( pthread_create(&t, NULL, thrd, (void *)cpu->usci ) ) {
  369. fprintf(stderr, "Error creating thread\n");
  370. }
  371. //printf("Got serial data %s ... %d bytes long\n",
  372. //(char *)(in + 1), (unsigned int)len - 1);
  373. return 0;
  374. }
  375. case 0x04: { // Console Input Data
  376. if (len > 1000) exit(1);
  377. buf = buf + 1;
  378. printf("%s\n", buf);
  379. if (!cpu->running && deb->debug_mode) {
  380. exec_cmd(emu, buf, len);
  381. update_register_display(emu);
  382. }
  383. return 0;
  384. }
  385. default: break;
  386. }
  387. }
  388. default: {
  389. break;
  390. }
  391. }
  392. return 0;
  393. }
  394. void *web_server (void *ctxt)
  395. {
  396. emu = (Emulator *) ctxt;
  397. Debugger *deb = emu->debugger;
  398. int port = 9001;
  399. //struct libwebsocket_context *context;
  400. struct lws_context *context;
  401. struct lws_context_creation_info context_info = {0};
  402. context_info.port = deb->ws_port;
  403. context_info.iface = NULL;
  404. context_info.protocols = protocols;
  405. context_info.extensions = NULL;
  406. context_info.ssl_cert_filepath = NULL;
  407. context_info.ssl_private_key_filepath = NULL;
  408. context_info.ssl_ca_filepath = NULL;
  409. context_info.gid = -1;
  410. context_info.uid = -1;
  411. context_info.options = 0;
  412. context_info.ka_time = false;
  413. context_info.ka_probes = false;
  414. context_info.ka_interval = false;
  415. // Initialize packet queuing system
  416. init_packet_queue(emu);
  417. // create libwebsocket context representing this server
  418. context = lws_create_context(&context_info);
  419. if (context == NULL) {
  420. fprintf(stderr, "libwebsocket init failed\n");
  421. deb->quit = true;
  422. exit(1);
  423. }
  424. printf("starting server...\n");
  425. while (true) {
  426. lws_service(context, 10); // ms
  427. usleep(1000);
  428. }
  429. lws_context_destroy(context);
  430. return NULL;
  431. }
  432. void send_control(Emulator *emu, uint8_t opcode, void *data, size_t data_size)
  433. {
  434. const static uint8_t NUM_OPCODE_BYTES = 1;
  435. const static uint8_t NUM_DATA_LEN_BYTES = 1;
  436. if (data == NULL) { // Simple case
  437. packet_enqueue(emu, (void *)&opcode, 1, CONTROL_PACKET_OPCODE);
  438. }
  439. else { // data case ( OP DL DATADATADATA )
  440. uint8_t full_packet[NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES + data_size];
  441. // First part of packet is the opcode for specific control type
  442. memcpy(full_packet, (void *)&opcode, NUM_OPCODE_BYTES);
  443. // Second part is the data length field for following data
  444. memcpy(full_packet + NUM_OPCODE_BYTES, &data_size,
  445. NUM_DATA_LEN_BYTES);
  446. // Third part is the data itself.
  447. memcpy(full_packet + NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES,
  448. data, data_size);
  449. /*
  450. int i;
  451. for (i = 0;i < 1+size;i++) {
  452. printf("%02X ", *(uint8_t *)(full_packet + i));
  453. }
  454. puts(" .");
  455. */
  456. packet_enqueue(emu, (void *)&full_packet,
  457. NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES + data_size,
  458. CONTROL_PACKET_OPCODE);
  459. }
  460. }
  461. void print_serial (Emulator *emu, char *buf)
  462. {
  463. packet_enqueue(emu, buf, strlen(buf) + 1, SERIAL_PACKET_OPCODE);
  464. }
  465. void print_console (Emulator *emu, const char *buf)
  466. {
  467. packet_enqueue(emu, (void*)buf, strlen(buf) + 1, CONSOLE_PACKET_OPCODE);
  468. }
  469. int callback_http (
  470. struct lws *wsi,
  471. //enum libwebsocket_callback_reasons reason,
  472. enum lws_callback_reasons reason,
  473. void *user, void *in, size_t len)
  474. {
  475. return 0;
  476. }