| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- /*
- MSP430 Emulator
- Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
- "MSP430 Emulator" is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- "MSP430 Emulator" is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include <string>
- #include "emu_server.h"
- #define TXIFG 0x02
- #define RXIFG 0x01
- #define HIGH 1
- #define LOW 0
- #define OUT 1
- #define IN 0
- //
- #define MAX_UPLOAD_FILENAME_SIZE 0xFFFF+1
- char UploadFileName[MAX_UPLOAD_FILENAME_SIZE] = {0};
- Emulator *emu = NULL;
- uint8_t *data;
- int lent;
- void *thrd (void *ctxt)
- {
- Usci *usci = (Usci *)ctxt;
- int i, j = 0;
- int len = lent;
- uint8_t *bytes = data;
- //printf("len is %d\nstr is %s\n", len, bytes);
- while (true) {
- usleep(333);
- while (*usci->IFG2 & RXIFG);
- uint8_t thing = *(bytes);
- if (thing == '\n') {
- thing = '\r';
- }
-
- //printf("Got 0x%02X '%c'\n", thing, thing);
-
- if (*bytes == '\\') {
- ++bytes;
- if (*bytes == 'h' || *bytes == 'H') {
- ++bytes;
-
- char buf[3] = {*((char*)bytes), *((char*)bytes+1), 0};
- //printf("%s - %s\n", buf, bytes);
- thing = (uint8_t) strtoul(buf, NULL, 16);
- ++bytes;
- }
- }
- *usci->UCA0RXBUF = thing;
- *usci->IFG2 |= RXIFG;
-
- //printf("\n0x%04X in UCA0RXBUF\n", (uint8_t)*usci->UCA0RXBUF);
- //puts("waiting..");
- while (*usci->IFG2 & RXIFG);
- //puts("done");
- //*usci->IFG2 |= RXIFG;
-
- if (*usci->UCA0RXBUF == '\r') break;
- ++bytes;
- }
- return NULL;
- }
- int callback_emu (struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
- {
- Cpu *cpu = emu->cpu;
- Port_1 *p1 = emu->cpu->p1;
- Debugger *deb = emu->debugger;
- switch (reason)
- {
- case LWS_CALLBACK_ESTABLISHED:
- {
- puts("connection established");
-
- // Flip ready flag for the emulator to begin
- deb->web_server_ready = true;
- // get the ball rolling
- //libwebsocket_callback_on_writable(this, wsi);
- lws_callback_on_writable(wsi);
-
- break;
- }
-
- case LWS_CALLBACK_SERVER_WRITEABLE:
- {
- if ( !packet_queue_empty(emu) )
- {
- Packet p = packet_dequeue(emu);
-
- void *msg = p.message;
- size_t msg_len = p.length;
- uint8_t op = p.opcode;
-
- //printf("[%s] of len %u, opcode: %u\n\n",
- //(char *)msg, (unsigned int)msg_len, op);
-
- // Leave room for websock header/trailer & opcode
- size_t pack_len = msg_len + sizeof(op) + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
-
- void *packet = malloc(pack_len);
-
- // Zero out our packet
- memset( ((uint8_t*)packet + LWS_SEND_BUFFER_PRE_PADDING), 0, msg_len + sizeof(op) );
- // Place opcode into packet
- *((uint8_t *)((uint8_t*)packet + LWS_SEND_BUFFER_PRE_PADDING)) = op;
-
- // Place message into packet
- memcpy( ((uint8_t*)packet + LWS_SEND_BUFFER_PRE_PADDING + sizeof(op)), (const void *)p.message, msg_len);
- /*
- int i;
- for (i = 0;i < pack_len;i++){
- printf( "%02X (%c) | ", *((uint8_t *)(packet+i)),
- *((char *)(packet+i)) );
- }
- puts("\n");
- */
- lws_write(wsi, ((unsigned char*)(packet))+LWS_SEND_BUFFER_PRE_PADDING, msg_len + sizeof(op), LWS_WRITE_BINARY);
-
- free(p.message);
- free(packet);
- }
- static bool p1_0_on = false;
- static bool p1_1_on = false;
- static bool p1_2_on = false;
- static bool p1_3_on = false;
- static bool p1_4_on = false;
- static bool p1_5_on = false;
- static bool p1_6_on = false;
- static bool p1_7_on = false;
-
- // P1.0 ON/OFF
- if (p1->DIR_0 == OUT)
- {
- if (p1->OUT_0 == HIGH)
- {
- if (p1_0_on == false)
- {
- send_control(emu, P1_0_ON_PACKET, NULL, 0);
- p1_0_on = true;
- }
- }
- else if (p1->OUT_0 == LOW)
- {
- if (p1_0_on == true)
- {
- send_control(emu, P1_0_OFF_PACKET, NULL, 0);
- p1_0_on = false;
- }
- }
- }
- // P1.1 ON/OFF
- if (p1->DIR_1 == OUT) {
- if (p1->OUT_1 == HIGH) {
- if (p1_1_on == false) {
- send_control(emu, P1_1_ON_PACKET, NULL, 0);
- p1_1_on = true;
- }
- }
- else if (p1->OUT_1 == LOW) {
- if (p1_1_on == true) {
- send_control(emu, P1_1_OFF_PACKET, NULL, 0);
- p1_1_on = false;
- }
- }
- }
- // P1.2 ON/OFF
- if (p1->DIR_2 == OUT) {
- if (p1->OUT_2 == HIGH) {
- if (p1_2_on == false) {
- send_control(emu, P1_2_ON_PACKET, NULL, 0);
- puts("p2 on");
- p1_2_on = true;
- }
- }
- else if (p1->OUT_2 == LOW) {
- if (p1_2_on == true) {
- send_control(emu, P1_2_OFF_PACKET, NULL, 0);
- p1_2_on = false;
- }
- }
- }
- // P1.3 ON/OFF
- if (p1->DIR_3 == OUT) {
- if (p1->OUT_3 == HIGH) {
- if (p1_3_on == false) {
- send_control(emu, P1_3_ON_PACKET, NULL, 0);
- p1_3_on = true;
- }
- }
- else if (p1->OUT_3 == LOW) {
- if (p1_3_on == true) {
- send_control(emu, P1_3_OFF_PACKET, NULL, 0);
- p1_3_on = false;
- }
- }
- }
- // P1.4 ON/OFF
- if (p1->DIR_4 == OUT) {
- if (p1->OUT_4 == HIGH) {
- if (p1_4_on == false) {
- send_control(emu, P1_4_ON_PACKET, NULL, 0);
- p1_4_on = true;
- }
- }
- else if (p1->OUT_4 == LOW) {
- if (p1_4_on == true) {
- send_control(emu, P1_4_OFF_PACKET, NULL, 0);
- p1_4_on = false;
- }
- }
- }
- // P1.5 ON/OFF
- if (p1->DIR_5 == OUT) {
- if (p1->OUT_5 == HIGH) {
- if (p1_5_on == false) {
- send_control(emu, P1_5_ON_PACKET, NULL, 0);
- p1_5_on = true;
- }
- }
- else if (p1->OUT_5 == LOW) {
- if (p1_5_on == true) {
- send_control(emu, P1_5_OFF_PACKET, NULL, 0);
- p1_5_on = false;
- }
- }
- }
-
- // P1.6 ON/OFF
- if (p1->DIR_6 == OUT) {
- if (p1->OUT_6 == HIGH) {
- if (p1_6_on == false) {
- send_control(emu, P1_6_ON_PACKET, NULL, 0);
- p1_6_on = true;
- }
- }
- else if (p1->OUT_6 == LOW) {
- if (p1_6_on == true) {
- send_control(emu, P1_6_OFF_PACKET, NULL, 0);
- p1_6_on = false;
- }
- }
- }
- // P1.7 ON/OFF
- if (p1->DIR_7 == OUT) {
- if (p1->OUT_7 == HIGH) {
- if (p1_7_on == false) {
- send_control(emu, P1_7_ON_PACKET, NULL, 0);
- p1_7_on = true;
- }
- }
- else if (p1->OUT_7 == LOW) {
- if (p1_7_on == true) {
- send_control(emu, P1_7_OFF_PACKET, NULL, 0);
- p1_7_on = false;
- }
- }
- }
- lws_callback_on_writable( wsi);
- break;
- }
- case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
- puts("Connection Error");
- break;
- }
- case LWS_CALLBACK_CLOSED: {
- puts("Connection Closed");
- exit(0);
- break;
- }
- case LWS_CALLBACK_CLIENT_WRITEABLE: {
- puts("cli writable");
- break;
- }
- case LWS_CALLBACK_RECEIVE:
- {
- static FILE *fp = NULL;
- static bool upload_in_progress = false;
- static uint32_t uploaded_bytes;
- static uint16_t FileSize = 0;
- char *buf = (char *)in;
-
- if (upload_in_progress)
- { // Continue transaction of upload
- int i;
- for (i = 0;i < len;i++)
- {
- fwrite(&buf[i], 1, 1, fp);
- uploaded_bytes++;
- if (uploaded_bytes >= FileSize)
- {
- puts("met bytes");
- fclose(fp);
- // system("msp430-objcopy -O binary tmp.elf tmp.bin");
- std::string ObjCopyLine = "objcopy -I elf32-little -O binary \"" + std::string(UploadFileName) + "\" tmp.bin";
- system(ObjCopyLine.c_str());
- deb->web_firmware_uploaded = true;
- upload_in_progress = false;
- return 0;
- }
- }
-
- return 0;
- }
-
- unsigned char opcode = buf[0];
- printf("opcode: %02X\n", *(uint8_t*)in);
-
- switch (opcode)
- {
- case 0x00: // Upload File
- {
- // Get the 32-bit length of the file
- FileSize = ntohs( *((uint16_t*)((uint8_t*)in + 1)) );
- // Get the 8-bit length of the ASCII filename
- uint16_t FileNameSize = ntohs(*((uint16_t*)((uint8_t*)in + 3)));
- printf(" Got file size %u, got data len %u for first callback.\n", (unsigned int)FileSize, (unsigned int)len);
- // Ensure that the file isn't too big, otherwise just quit on the user for now
- if (FileSize >= 0xFFFF)
- {
- print_console(emu, "File Size Not Supported. Quitting.\n");
- deb->quit = true;
- exit(1);
- }
- // for now assume the entire filename is uploaded, and has no 0 at the end so add one
- memset(UploadFileName, 0, MAX_UPLOAD_FILENAME_SIZE);
- memmove(&UploadFileName[0], &buf[5], FileNameSize);
- printf(" Got name size %u, name %s.\n", FileNameSize, UploadFileName);
- upload_in_progress = true;
- uploaded_bytes = 0;
- fp = fopen(UploadFileName, "wb");
- // Get Any Bytes that are in with this packet
- for (uint32_t i = 5+FileNameSize;i < len;i++)
- {
- fwrite(&buf[i], 1, 1, fp);
- uploaded_bytes++;
- if (uploaded_bytes >= FileSize)
- {
- puts("met bytes");
- fclose(fp);
- //system("msp430-objcopy -O binary tmp.elf tmp.bin");
- std::string ObjCopyLine = "objcopy -I elf32-little -O binary \"" + std::string(UploadFileName) + "\" tmp.bin";
- system(ObjCopyLine.c_str());
- deb->web_firmware_uploaded = true;
- upload_in_progress = false;
- return 0;
- }
- }
- break;
- }
- case 0x01: { // PLAY
- printf("Got play\n");
- cpu->running = true;
- deb->debug_mode = false;
- update_register_display(emu);
- return 0;
- }
-
- case 0x02: { // PAUSE
- printf("Got pause\n");
- if (cpu->running) {
- cpu->running = false;
- deb->debug_mode = true;
- // display first round of registers
- display_registers(emu);
- disassemble(emu, cpu->pc, 1);
- update_register_display(emu);
- }
-
- return 0;
- }
- case 0x03: { // SERIAL DATA
- if (len > 1000) exit(1);
- lent = len - 1;
- data = ((uint8_t*)in + 1);
-
- pthread_t t;
- if( pthread_create(&t, NULL, thrd, (void *)cpu->usci ) ) {
- fprintf(stderr, "Error creating thread\n");
- }
-
- //printf("Got serial data %s ... %d bytes long\n",
- //(char *)(in + 1), (unsigned int)len - 1);
-
- return 0;
- }
- case 0x04: { // Console Input Data
- if (len > 1000) exit(1);
- buf = buf + 1;
- printf("%s\n", buf);
- if (!cpu->running && deb->debug_mode) {
- exec_cmd(emu, buf, len);
- update_register_display(emu);
- }
- return 0;
- }
-
- default: break;
- }
- }
-
- default: {
- break;
- }
- }
-
- return 0;
- }
- void *web_server (void *ctxt)
- {
- emu = (Emulator *) ctxt;
- Debugger *deb = emu->debugger;
- int port = 9001;
- //struct libwebsocket_context *context;
- struct lws_context *context;
- struct lws_context_creation_info context_info = {0};
- context_info.port = deb->ws_port;
- context_info.iface = NULL;
- context_info.protocols = protocols;
- context_info.extensions = NULL;
- context_info.ssl_cert_filepath = NULL;
- context_info.ssl_private_key_filepath = NULL;
- context_info.ssl_ca_filepath = NULL;
- context_info.gid = -1;
- context_info.uid = -1;
- context_info.options = 0;
- context_info.ka_time = false;
- context_info.ka_probes = false;
- context_info.ka_interval = false;
- // Initialize packet queuing system
- init_packet_queue(emu);
-
- // create libwebsocket context representing this server
- context = lws_create_context(&context_info);
- if (context == NULL) {
- fprintf(stderr, "libwebsocket init failed\n");
- deb->quit = true;
- exit(1);
- }
-
- printf("starting server...\n");
-
- while (true) {
- lws_service(context, 10); // ms
- usleep(1000);
- }
- lws_context_destroy(context);
- return NULL;
- }
- void send_control(Emulator *emu, uint8_t opcode, void *data, size_t data_size)
- {
- const static uint8_t NUM_OPCODE_BYTES = 1;
- const static uint8_t NUM_DATA_LEN_BYTES = 1;
- if (data == NULL) { // Simple case
- packet_enqueue(emu, (void *)&opcode, 1, CONTROL_PACKET_OPCODE);
- }
- else { // data case ( OP DL DATADATADATA )
- uint8_t full_packet[NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES + data_size];
- // First part of packet is the opcode for specific control type
- memcpy(full_packet, (void *)&opcode, NUM_OPCODE_BYTES);
- // Second part is the data length field for following data
- memcpy(full_packet + NUM_OPCODE_BYTES, &data_size,
- NUM_DATA_LEN_BYTES);
- // Third part is the data itself.
- memcpy(full_packet + NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES,
- data, data_size);
-
- /*
- int i;
- for (i = 0;i < 1+size;i++) {
- printf("%02X ", *(uint8_t *)(full_packet + i));
- }
- puts(" .");
- */
- packet_enqueue(emu, (void *)&full_packet,
- NUM_OPCODE_BYTES + NUM_DATA_LEN_BYTES + data_size,
- CONTROL_PACKET_OPCODE);
-
- }
- }
- void print_serial (Emulator *emu, char *buf)
- {
- packet_enqueue(emu, buf, strlen(buf) + 1, SERIAL_PACKET_OPCODE);
- }
- void print_console (Emulator *emu, const char *buf)
- {
- packet_enqueue(emu, (void*)buf, strlen(buf) + 1, CONSOLE_PACKET_OPCODE);
- }
- int callback_http (
- struct lws *wsi,
- //enum libwebsocket_callback_reasons reason,
- enum lws_callback_reasons reason,
- void *user, void *in, size_t len)
- {
- return 0;
- }
|