changeset 1517:9136b7ea1ccb

Merge
author Michael Pavone <pavone@retrodev.com>
date Mon, 22 Jan 2018 22:03:55 -0800
parents aaab852803ac (diff) 8158c2757605 (current diff)
children 713b504dc577
files Makefile
diffstat 8 files changed, 547 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Thu Jan 04 21:37:34 2018 -0800
+++ b/Makefile	Mon Jan 22 22:03:55 2018 -0800
@@ -127,7 +127,7 @@
 AUDIOOBJS=ym2612.o psg.o wave.o
 CONFIGOBJS=config.o tern.o util.o
 
-MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o ppm.o io.o romdb.o hash.o menu.o xband.o realtec.o i2c.o nor.o sega_mapper.o multi_game.o serialize.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
+MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o ppm.o io.o romdb.o hash.o menu.o xband.o realtec.o i2c.o nor.o sega_mapper.o multi_game.o megawifi.o net.o serialize.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
 
 ifeq ($(CPU),x86_64)
 CFLAGS+=-DX86_64 -m64
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/megawifi.c	Mon Jan 22 22:03:55 2018 -0800
@@ -0,0 +1,423 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "genesis.h"
+#include "net.h"
+
+enum {
+	TX_IDLE,
+	TX_LEN1,
+	TX_LEN2,
+	TX_PAYLOAD,
+	TX_WAIT_ETX
+};
+#define STX 0x7E
+#define ETX 0x7E
+
+#define E(N) N
+enum {
+#include "mw_commands.c"
+	CMD_ERROR = 255
+};
+#undef E
+#define E(N) #N
+static const char *cmd_names[] = {
+#include "mw_commands.c"
+	[255] = "CMD_ERROR"
+};
+
+enum {
+	STATE_IDLE=1,
+	STATE_AP_JOIN,
+	STATE_SCAN,
+	STATE_READY,
+	STATE_TRANSPARENT
+};
+
+#define FLAG_ONLINE 
+
+typedef struct {
+	uint32_t transmit_bytes;
+	uint32_t expected_bytes;
+	uint32_t receive_bytes;
+	uint32_t receive_read;
+	int      sock_fds[15];
+	uint16_t channel_flags;
+	uint8_t  channel_state[15];
+	uint8_t  scratchpad;
+	uint8_t  transmit_channel;
+	uint8_t  transmit_state;
+	uint8_t  module_state;
+	uint8_t  flags;
+	uint8_t  transmit_buffer[4096];
+	uint8_t  receive_buffer[4096];
+} megawifi;
+
+static megawifi *get_megawifi(void *context)
+{
+	m68k_context *m68k = context;
+	genesis_context *gen = m68k->system;
+	if (!gen->extra) {
+		gen->extra = calloc(1, sizeof(megawifi));
+		megawifi *mw = gen->extra;
+		mw->module_state = STATE_IDLE;
+		for (int i = 0; i < 15; i++)
+		{
+			mw->sock_fds[i] = -1;
+		}
+	}
+	return gen->extra;
+}
+
+static void mw_putc(megawifi *mw, uint8_t v)
+{
+	if (mw->receive_bytes == sizeof(mw->receive_buffer)) {
+		return;
+	}
+	mw->receive_buffer[mw->receive_bytes++] = v;
+}
+
+static void mw_set(megawifi *mw, uint8_t val, uint32_t count)
+{
+	if (count + mw->receive_bytes > sizeof(mw->receive_buffer)) {
+		count = sizeof(mw->receive_buffer) - mw->receive_bytes;
+	}
+	memset(mw->receive_buffer + mw->receive_bytes, val, count);
+	mw->receive_bytes += count;
+}
+
+static void mw_copy(megawifi *mw, const uint8_t *src, uint32_t count)
+{
+	if (count + mw->receive_bytes > sizeof(mw->receive_buffer)) {
+		count = sizeof(mw->receive_buffer) - mw->receive_bytes;
+	}
+	memcpy(mw->receive_buffer + mw->receive_bytes, src, count);
+	mw->receive_bytes += count;
+}
+
+static void mw_puts(megawifi *mw, char *s)
+{
+	uint32_t len = strlen(s);
+	if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) {
+		return;
+	}
+	memcpy(mw->receive_buffer + mw->receive_bytes, s, len);
+	mw->receive_bytes += len;
+}
+
+static void poll_socket(megawifi *mw, uint8_t channel)
+{
+	if (mw->sock_fds[channel] < 0) {
+		return;
+	}
+	if (mw->channel_state[channel] == 1) {
+		int res = accept(mw->sock_fds[channel], NULL, NULL);
+		if (res >= 0) {
+			close(mw->sock_fds[channel]);
+			fcntl(res, F_SETFL, O_NONBLOCK);
+			mw->sock_fds[channel] = res;
+			mw->channel_state[channel] = 2;
+			mw->channel_flags |= 1 << (channel + 1);
+		} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
+			close(mw->sock_fds[channel]);
+			mw->channel_state[channel] = 0;
+			mw->channel_flags |= 1 << (channel + 1);
+		}
+	} else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) {
+		int bytes = recv(
+			mw->sock_fds[channel],
+			mw->receive_buffer + mw->receive_bytes + 3,
+			sizeof(mw->receive_buffer) - 4 - mw->receive_bytes,
+			0
+		);
+		if (bytes > 0) {
+			mw_putc(mw, STX);
+			mw_putc(mw, bytes >> 8 | (channel+1) << 4);
+			mw_putc(mw, bytes);
+			mw->receive_bytes += bytes;
+			mw_putc(mw, ETX);
+			//should this set the channel flag?
+		} else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
+			close(mw->sock_fds[channel]);
+			mw->channel_state[channel] = 0;
+			mw->channel_flags |= 1 << (channel + 1);
+		}
+	}
+}
+
+static void poll_all_sockets(megawifi *mw)
+{
+	for (int i = 0; i < 15; i++)
+	{
+		poll_socket(mw, i);
+	}
+}
+
+static void start_reply(megawifi *mw, uint8_t cmd)
+{
+	mw_putc(mw, STX);
+	//reserve space for length
+	mw->receive_bytes += 2;
+	//cmd
+	mw_putc(mw, 0);
+	mw_putc(mw, cmd);
+	//reserve space for length
+	mw->receive_bytes += 2;
+}
+
+static void end_reply(megawifi *mw)
+{
+	uint32_t len = mw->receive_bytes - 3;
+	//LSD packet length
+	mw->receive_buffer[1] = len >> 8;
+	mw->receive_buffer[2] = len;
+	//command length
+	len -= 4;
+	mw->receive_buffer[5] = len >> 8;
+	mw->receive_buffer[6] = len;
+	mw_putc(mw, ETX);
+}
+
+static void process_packet(megawifi *mw)
+{
+	if (mw->transmit_channel == 0) {
+		uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1];
+		uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3];
+		if (size > mw->transmit_bytes - 4) {
+			size = mw->transmit_bytes - 4;
+		}
+		int orig_receive_bytes = mw->receive_bytes;
+		switch (command)
+		{
+		case CMD_VERSION:
+			start_reply(mw, CMD_OK);
+			mw_putc(mw, 1);
+			mw_putc(mw, 0);
+			mw_puts(mw, "blastem");
+			end_reply(mw);
+			break;
+		case CMD_ECHO:
+			mw->receive_bytes = mw->transmit_bytes;
+			memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes);
+			break;
+		case CMD_IP_CURRENT: {
+			iface_info i;
+			if (get_host_address(&i)) {
+				start_reply(mw, CMD_OK);
+				//config number and reserved bytes
+				mw_set(mw, 0, 4);
+				//ip
+				mw_copy(mw, i.ip, sizeof(i.ip));
+				//net mask
+				mw_copy(mw, i.net_mask, sizeof(i.net_mask));
+				//gateway guess
+				mw_putc(mw, i.ip[0] & i.net_mask[0]);
+				mw_putc(mw, i.ip[1] & i.net_mask[1]);
+				mw_putc(mw, i.ip[2] & i.net_mask[2]);
+				mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1);
+				//dns
+				static const uint8_t localhost[] = {127,0,0,1};
+				mw_copy(mw, localhost, sizeof(localhost));
+				mw_copy(mw, localhost, sizeof(localhost));
+				
+			} else {
+				start_reply(mw, CMD_ERROR);
+			}
+			end_reply(mw);
+			break;
+		}
+		case CMD_AP_JOIN:
+			mw->module_state = STATE_READY;
+			start_reply(mw, CMD_OK);
+			end_reply(mw);
+			break;
+		case CMD_TCP_BIND:{
+			if (size < 7){
+				start_reply(mw, CMD_ERROR);
+				end_reply(mw);
+				break;
+			}
+			uint8_t channel = mw->transmit_buffer[10];
+			if (!channel || channel > 15) {
+				start_reply(mw, CMD_ERROR);
+				end_reply(mw);
+				break;
+			}
+			channel--;
+			if (mw->sock_fds[channel] >= 0) {
+				close(mw->sock_fds[channel]);
+			}
+			mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0);
+			if (mw->sock_fds[channel] < 0) {
+				start_reply(mw, CMD_ERROR);
+				end_reply(mw);
+				break;
+			}
+			int value = 1;
+			setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
+			struct sockaddr_in bind_addr;
+			memset(&bind_addr, 0, sizeof(bind_addr));
+			bind_addr.sin_family = AF_INET;
+			bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]);
+			if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) {
+				close(mw->sock_fds[channel]);
+				mw->sock_fds[channel] = -1;
+				start_reply(mw, CMD_ERROR);
+				end_reply(mw);
+				break;
+			}
+			int res = listen(mw->sock_fds[channel], 2);
+			start_reply(mw, res ? CMD_ERROR : CMD_OK);
+			if (res) {
+				close(mw->sock_fds[channel]);
+				mw->sock_fds[channel] = -1;
+			} else {
+				mw->channel_flags |= 1 << (channel + 1);
+				mw->channel_state[channel] = 1;
+				fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK);
+			}
+			end_reply(mw);
+			break;
+		}
+		case CMD_SOCK_STAT: {
+			uint8_t channel = mw->transmit_buffer[4];
+			if (!channel || channel > 15) {
+				start_reply(mw, CMD_ERROR);
+				end_reply(mw);
+				break;
+			}
+			mw->channel_flags &= ~(1 << channel);
+			channel--;
+			poll_socket(mw, channel);
+			start_reply(mw, CMD_OK);
+			mw_putc(mw, mw->channel_state[channel]);
+			end_reply(mw);
+			break;
+		}
+		case CMD_SYS_STAT:
+			poll_all_sockets(mw);
+			start_reply(mw, CMD_OK);
+			mw_putc(mw, mw->module_state);
+			mw_putc(mw, mw->flags);
+			mw_putc(mw, mw->channel_flags >> 8);
+			mw_putc(mw, mw->channel_flags);
+			end_reply(mw);
+			break;
+		default:
+			printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size);
+			break;
+		}
+	} else if (mw->sock_fds[mw->transmit_channel - 1] >= 0 && mw->channel_state[mw->transmit_channel - 1] == 2) {
+		uint8_t channel = mw->transmit_channel - 1;
+		int sent = send(mw->sock_fds[channel], mw->transmit_buffer, mw->transmit_bytes, 0);
+		if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
+			close(mw->sock_fds[channel]);
+			mw->sock_fds[channel] = -1;
+			mw->channel_state[channel] = 0;
+			mw->channel_flags |= 1 << mw->transmit_channel;
+		} else if (sent < mw->transmit_bytes) {
+			//TODO: save this data somewhere so it can be sent in poll_socket
+			printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes);
+		}
+	} else {
+		printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel);
+	}
+	mw->transmit_bytes = mw->expected_bytes = 0;
+}
+
+void *megawifi_write_b(uint32_t address, void *context, uint8_t value)
+{
+	if (!(address & 1)) {
+		return context;
+	}
+	megawifi *mw = get_megawifi(context);
+	address = address >> 1 & 7;
+	switch (address)
+	{
+	case 0:
+		switch (mw->transmit_state)
+		{
+		case TX_IDLE:
+			if (value == STX) {
+				mw->transmit_state = TX_LEN1;
+			}
+			break;
+		case TX_LEN1:
+			mw->transmit_channel = value >> 4;
+			mw->expected_bytes = value << 8 & 0xF00;
+			mw->transmit_state = TX_LEN2;
+			break;
+		case TX_LEN2:
+			mw->expected_bytes |= value;
+			mw->transmit_state = TX_PAYLOAD;
+			break;
+		case TX_PAYLOAD:
+			mw->transmit_buffer[mw->transmit_bytes++] = value;
+			if (mw->transmit_bytes == mw->expected_bytes) {
+				mw->transmit_state = TX_WAIT_ETX;
+			}
+			break;
+		case TX_WAIT_ETX:
+			if (value == ETX) {
+				mw->transmit_state = TX_IDLE;
+				process_packet(mw);
+			}
+			break;
+		}
+		break;
+	case 7:
+		mw->scratchpad = value;
+		break;
+	default:
+		printf("Unhandled write to MegaWiFi UART register %X: %X\n", address, value);
+	}
+	return context;
+}
+
+void *megawifi_write_w(uint32_t address, void *context, uint16_t value)
+{
+	return megawifi_write_b(address | 1, context, value);
+}
+
+uint8_t megawifi_read_b(uint32_t address, void *context)
+{
+	
+	if (!(address & 1)) {
+		return 0xFF;
+	}
+	megawifi *mw = get_megawifi(context);
+	address = address >> 1 & 7;
+	switch (address)
+	{
+	case 0:
+		poll_all_sockets(mw);
+		if (mw->receive_read < mw->receive_bytes) {
+			uint8_t ret = mw->receive_buffer[mw->receive_read++];
+			if (mw->receive_read == mw->receive_bytes) {
+				mw->receive_read = mw->receive_bytes = 0;
+			}
+			return ret;
+		}
+		return 0xFF;
+	case 5:
+		poll_all_sockets(mw);
+		//line status
+		return 0x60 | (mw->receive_read < mw->receive_bytes);
+	case 7:
+		return mw->scratchpad;
+	default:
+		printf("Unhandled read from MegaWiFi UART register %X\n", address);
+		return 0xFF;
+	}
+}
+
+uint16_t megawifi_read_w(uint32_t address, void *context)
+{
+	return 0xFF00 | megawifi_read_b(address | 1, context);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/megawifi.h	Mon Jan 22 22:03:55 2018 -0800
@@ -0,0 +1,9 @@
+#ifndef MEGAWIFI_H_
+#define MEGAWIFI_H_
+
+void *megawifi_write_w(uint32_t address, void *context, uint16_t value);
+void *megawifi_write_b(uint32_t address, void *context, uint8_t value);
+uint16_t megawifi_read_w(uint32_t address, void *context);
+uint8_t megawifi_read_b(uint32_t address, void *context);
+
+#endif //MEGAWIFI_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mw_commands.c	Mon Jan 22 22:03:55 2018 -0800
@@ -0,0 +1,33 @@
+	E(CMD_OK),
+	E(CMD_VERSION),
+	E(CMD_ECHO),
+	E(CMD_AP_SCAN),
+	E(CMD_AP_CFG),
+	E(CMD_AP_CFG_GET),
+	E(CMD_IP_CURRENT),
+	E(CMD_RESERVED),
+	E(CMD_IP_CFG),
+	E(CMD_IP_CFG_GET),
+	E(CMD_DEF_AP_CFG),
+	E(CMD_DEF_AP_CFG_GET),
+	E(CMD_AP_JOIN),
+	E(CMD_AP_LEAVE),
+	E(CMD_TCP_CON),
+	E(CMD_TCP_BIND),
+	E(CMD_TCP_ACCEPT),
+	E(CMD_TCP_DISC),
+	E(CMD_UDP_SET),
+	E(CMD_UDP_CLR),
+	E(CMD_SOCK_STAT),
+	E(CMD_PING),
+	E(CMD_SNTP_CFG),
+	E(CMD_SNTP_CFG_GET),
+	E(CMD_DATETIME),
+	E(CMD_DT_SET),
+	E(CMD_FLASH_WRITE),
+	E(CMD_FLASH_READ),
+	E(CMD_FLASH_ERASE),
+	E(CMD_FLASH_ID),
+	E(CMD_SYS_STAT),
+	E(CMD_DEF_CFG_SET),
+	E(CMD_HRNG_GET),
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/net.c	Mon Jan 22 22:03:55 2018 -0800
@@ -0,0 +1,49 @@
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <netinet/in.h>
+#include "net.h"
+
+static uint8_t is_loopback(struct sockaddr_in *addr)
+{
+	return (addr->sin_addr.s_addr & 0xFF) == 127;
+}
+
+static void format_address(uint8_t *dst, struct sockaddr_in *addr)
+{
+	long ip = addr->sin_addr.s_addr;
+	dst[0] = ip;
+	dst[1] = ip >> 8;
+	dst[2] = ip >> 16;
+	dst[3] = ip >> 24;
+}
+
+uint8_t get_host_address(iface_info *out)
+{
+	struct ifaddrs *entries, *current, *localhost;
+	if (getifaddrs(&entries)) {
+		return 0;
+	}
+	
+	for (current = entries; current; current = current->ifa_next)
+	{
+		if (current->ifa_addr && current->ifa_addr->sa_family == AF_INET) {
+			struct sockaddr_in *addr = (struct sockaddr_in *)current->ifa_addr;
+			if (is_loopback(addr)) {
+				localhost = current;
+			} else {
+				break;
+			}
+		}
+	}
+	if (!current && localhost) {
+		current = localhost;
+	}
+	uint8_t ret = 0;
+	if (current) {
+		ret = 1;
+		format_address(out->ip, (struct sockaddr_in *)current->ifa_addr);
+		format_address(out->net_mask, (struct sockaddr_in *)current->ifa_netmask);
+	}
+	freeifaddrs(entries);
+	return ret;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/net.h	Mon Jan 22 22:03:55 2018 -0800
@@ -0,0 +1,12 @@
+#ifndef NET_H_
+#define NET_H_
+#include <stdint.h>
+
+typedef struct {
+	uint8_t ip[4];
+	uint8_t net_mask[4];
+} iface_info;
+
+uint8_t get_host_address(iface_info *out);
+
+#endif //NET_H_
--- a/rom.db	Thu Jan 04 21:37:34 2018 -0800
+++ b/rom.db	Mon Jan 22 22:03:55 2018 -0800
@@ -1299,3 +1299,16 @@
 		}
 	}
 }
+cda73e4caf53cbc8f0750b69e5e7f394ad3735d1 {
+	name MegaWiFi Bootloader
+	map {
+		0 {
+			device ROM
+			last 3FFFFF
+		}
+		A130C0 {
+			device megawifi
+			last A130CF
+		}
+	}
+}
--- a/romdb.c	Thu Jan 04 21:37:34 2018 -0800
+++ b/romdb.c	Mon Jan 22 22:03:55 2018 -0800
@@ -11,6 +11,7 @@
 #include "nor.h"
 #include "sega_mapper.h"
 #include "multi_game.h"
+#include "megawifi.h"
 
 #define DOM_TITLE_START 0x120
 #define DOM_TITLE_END 0x150
@@ -778,6 +779,12 @@
 		map->mask = 0xFF;
 		map->write_16 = write_multi_game_w;
 		map->write_8 = write_multi_game_b;
+	} else if (!strcmp(dtype, "megawifi")) {
+		map->write_16 = megawifi_write_w;
+		map->write_8 = megawifi_write_b;
+		map->read_16 = megawifi_read_w;
+		map->read_8 = megawifi_read_b;
+		map->mask = 0xFFFFFF;
 	} else {
 		fatal_error("Invalid device type %s for ROM DB map entry %d with address %s\n", dtype, state->index, key);
 	}