emu_server.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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>
  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. std::string ObjCopyLine = "objcopy -I elf32-little -O binary \"" + std::string(UploadFileName) + "\" tmp.bin";
  284. system(ObjCopyLine.c_str());
  285. deb->web_firmware_uploaded = true;
  286. upload_in_progress = false;
  287. return 0;
  288. }
  289. }
  290. return 0;
  291. }
  292. unsigned char opcode = buf[0];
  293. printf("opcode: %02X\n", *(uint8_t*)in);
  294. switch (opcode)
  295. {
  296. case 0x00: // Upload File
  297. {
  298. // Get the 32-bit length of the file
  299. FileSize = ntohs( *((uint16_t*)((uint8_t*)in + 1)) );
  300. // Get the 8-bit length of the ASCII filename
  301. uint16_t FileNameSize = ntohs(*((uint16_t*)((uint8_t*)in + 3)));
  302. printf(" Got file size %u, got data len %u for first callback.\n", (unsigned int)FileSize, (unsigned int)len);
  303. // Ensure that the file isn't too big, otherwise just quit on the user for now
  304. if (FileSize >= 0xFFFF)
  305. {
  306. print_console(emu, "File Size Not Supported. Quitting.\n");
  307. deb->quit = true;
  308. exit(1);
  309. }
  310. // for now assume the entire filename is uploaded, and has no 0 at the end so add one
  311. memset(UploadFileName, 0, MAX_UPLOAD_FILENAME_SIZE);
  312. memmove(&UploadFileName[0], &buf[5], FileNameSize);
  313. printf(" Got name size %u, name %s.\n", FileNameSize, UploadFileName);
  314. upload_in_progress = true;
  315. uploaded_bytes = 0;
  316. fp = fopen(UploadFileName, "wb");
  317. // Get Any Bytes that are in with this packet
  318. for (uint32_t i = 5+FileNameSize;i < len;i++)
  319. {
  320. fwrite(&buf[i], 1, 1, fp);
  321. uploaded_bytes++;
  322. if (uploaded_bytes >= FileSize)
  323. {
  324. puts("met bytes");
  325. fclose(fp);
  326. //system("msp430-objcopy -O binary tmp.elf tmp.bin");
  327. std::string ObjCopyLine = "objcopy -I elf32-little -O binary \"" + std::string(UploadFileName) + "\" tmp.bin";
  328. system(ObjCopyLine.c_str());
  329. deb->web_firmware_uploaded = true;
  330. upload_in_progress = false;
  331. return 0;
  332. }
  333. }
  334. break;
  335. }
  336. case 0x01: { // PLAY
  337. printf("Got play\n");
  338. cpu->running = true;
  339. deb->debug_mode = false;
  340. update_register_display(emu);
  341. return 0;
  342. }
  343. case 0x02: { // PAUSE
  344. printf("Got pause\n");
  345. if (cpu->running) {
  346. cpu->running = false;
  347. deb->debug_mode = true;
  348. // display first round of registers
  349. display_registers(emu);
  350. disassemble(emu, cpu->pc, 1);
  351. update_register_display(emu);
  352. }
  353. return 0;
  354. }
  355. case 0x03: { // SERIAL DATA
  356. if (len > 1000) exit(1);
  357. lent = len - 1;
  358. data = ((uint8_t*)in + 1);
  359. pthread_t t;
  360. if( pthread_create(&t, NULL, thrd, (void *)cpu->usci ) ) {
  361. fprintf(stderr, "Error creating thread\n");
  362. }
  363. //printf("Got serial data %s ... %d bytes long\n",
  364. //(char *)(in + 1), (unsigned int)len - 1);
  365. return 0;
  366. }
  367. case 0x04: { // Console Input Data
  368. if (len > 1000) exit(1);
  369. buf = buf + 1;
  370. printf("%s\n", buf);
  371. if (!cpu->running && deb->debug_mode) {
  372. exec_cmd(emu, buf, len);
  373. update_register_display(emu);
  374. }
  375. return 0;
  376. }
  377. default: break;
  378. }
  379. }
  380. default: {
  381. break;
  382. }
  383. }
  384. return 0;
  385. }
  386. void *web_server (void *ctxt)
  387. {
  388. emu = (Emulator *) ctxt;
  389. Debugger *deb = emu->debugger;
  390. int port = 9001;
  391. //struct libwebsocket_context *context;
  392. struct lws_context *context;
  393. struct lws_context_creation_info context_info = {0};
  394. context_info.port = deb->ws_port;
  395. context_info.iface = NULL;
  396. context_info.protocols = protocols;
  397. context_info.extensions = NULL;
  398. context_info.ssl_cert_filepath = NULL;
  399. context_info.ssl_private_key_filepath = NULL;
  400. context_info.ssl_ca_filepath = NULL;
  401. context_info.gid = -1;
  402. context_info.uid = -1;
  403. context_info.options = 0;
  404. context_info.ka_time = false;
  405. context_info.ka_probes = false;
  406. context_info.ka_interval = false;
  407. // Initialize packet queuing system
  408. init_packet_queue(emu);
  409. // create libwebsocket context representing this server
  410. context = lws_create_context(&context_info);
  411. if (context == NULL) {
  412. fprintf(stderr, "libwebsocket init failed\n");
  413. deb->quit = true;
  414. exit(1);
  415. }
  416. printf("starting server...\n");
  417. while (true) {
  418. lws_service(context, 10); // ms
  419. usleep(1000);
  420. }
  421. lws_context_destroy(context);
  422. return NULL;
  423. }
  424. void send_control(Emulator *emu, uint8_t opcode, void *data, size_t data_size)
  425. {
  426. const static uint8_t NUM_OPCODE_BYTES = 1;
  427. const static uint8_t NUM_DATA_LEN_BYTES = 1;
  428. if (data == NULL) { // Simple case
  429. packet_enqueue(emu, (void *)&opcode, 1, CONTROL_PACKET_OPCODE);
  430. }
  431. else { // data case ( OP DL DATADATADATA )
  432. uint8_t full_packet[NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES + data_size];
  433. // First part of packet is the opcode for specific control type
  434. memcpy(full_packet, (void *)&opcode, NUM_OPCODE_BYTES);
  435. // Second part is the data length field for following data
  436. memcpy(full_packet + NUM_OPCODE_BYTES, &data_size,
  437. NUM_DATA_LEN_BYTES);
  438. // Third part is the data itself.
  439. memcpy(full_packet + NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES,
  440. data, data_size);
  441. /*
  442. int i;
  443. for (i = 0;i < 1+size;i++) {
  444. printf("%02X ", *(uint8_t *)(full_packet + i));
  445. }
  446. puts(" .");
  447. */
  448. packet_enqueue(emu, (void *)&full_packet,
  449. NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES + data_size,
  450. CONTROL_PACKET_OPCODE);
  451. }
  452. }
  453. void print_serial (Emulator *emu, char *buf)
  454. {
  455. packet_enqueue(emu, buf, strlen(buf) + 1, SERIAL_PACKET_OPCODE);
  456. }
  457. void print_console (Emulator *emu, const char *buf)
  458. {
  459. packet_enqueue(emu, (void*)buf, strlen(buf) + 1, CONSOLE_PACKET_OPCODE);
  460. }
  461. int callback_http (
  462. struct lws *wsi,
  463. //enum libwebsocket_callback_reasons reason,
  464. enum lws_callback_reasons reason,
  465. void *user, void *in, size_t len)
  466. {
  467. return 0;
  468. }