comparison megawifi.c @ 1513:8f3b6a64b658

Initial work on MegaWiFi support
author Michael Pavone <pavone@retrodev.com>
date Mon, 15 Jan 2018 09:04:43 -0800
parents
children 4f94e0f90c83
comparison
equal deleted inserted replaced
1471:2e6320d261ff 1513:8f3b6a64b658
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include "genesis.h"
5
6 enum {
7 TX_IDLE,
8 TX_LEN1,
9 TX_LEN2,
10 TX_PAYLOAD,
11 TX_WAIT_ETX
12 };
13 #define STX 0x7E
14 #define ETX 0x7E
15
16 #define E(N) N
17 enum {
18 #include "mw_commands.c"
19 CMD_ERROR = 255
20 };
21 #undef E
22 #define E(N) #N
23 static const char *cmd_names[] = {
24 #include "mw_commands.c"
25 [255] = "CMD_ERROR"
26 };
27
28 enum {
29 STATE_IDLE=1,
30 STATE_AP_JOIN,
31 STATE_SCAN,
32 STATE_READY,
33 STATE_TRANSPARENT
34 };
35
36 #define FLAG_ONLINE
37
38 typedef struct {
39 uint32_t transmit_bytes;
40 uint32_t expected_bytes;
41 uint32_t receive_bytes;
42 uint32_t receive_read;
43 uint16_t channel_flags;
44 uint8_t scratchpad;
45 uint8_t transmit_channel;
46 uint8_t transmit_state;
47 uint8_t module_state;
48 uint8_t flags;
49 uint8_t transmit_buffer[4096];
50 uint8_t receive_buffer[4096];
51 } megawifi;
52
53 static megawifi *get_megawifi(void *context)
54 {
55 m68k_context *m68k = context;
56 genesis_context *gen = m68k->system;
57 if (!gen->extra) {
58 gen->extra = calloc(1, sizeof(megawifi));
59 ((megawifi *)gen->extra)->module_state = STATE_IDLE;
60 }
61 return gen->extra;
62 }
63
64 static void mw_putc(megawifi *mw, uint8_t v)
65 {
66 if (mw->receive_bytes == sizeof(mw->receive_buffer)) {
67 return;
68 }
69 mw->receive_buffer[mw->receive_bytes++] = v;
70 }
71
72 static void mw_puts(megawifi *mw, char *s)
73 {
74 uint32_t len = strlen(s);
75 if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) {
76 return;
77 }
78 memcpy(mw->receive_buffer + mw->receive_bytes, s, len);
79 mw->receive_bytes += len;
80 }
81
82 static void process_packet(megawifi *mw)
83 {
84 if (mw->transmit_channel == 0) {
85 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1];
86 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3];
87 if (size > mw->transmit_bytes - 4) {
88 size = mw->transmit_bytes - 4;
89 }
90 mw->receive_read = mw->receive_bytes = 0;
91 switch (command)
92 {
93 case CMD_VERSION:
94 //LSD header
95 mw_putc(mw, 0x7E);
96 mw_putc(mw, 0);
97 mw->receive_bytes += 1; //reserve space for LSB of len
98 //cmd
99 mw_putc(mw, 0);
100 mw_putc(mw, CMD_OK);
101 //length
102 mw_putc(mw, 0);
103 mw->receive_bytes += 1; //reserve space for LSB of len
104 mw_putc(mw, 1);
105 mw_putc(mw, 0);
106 mw_puts(mw, "blastem");
107 mw->receive_buffer[2] = mw->receive_bytes - 3;
108 mw->receive_buffer[6] = mw->receive_bytes - 7;
109 mw_putc(mw, 0x7E);
110 break;
111 case CMD_ECHO:
112 mw->receive_bytes = mw->transmit_bytes;
113 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes);
114 break;
115 case CMD_AP_JOIN:
116 mw->module_state = STATE_READY;
117 mw_putc(mw, 0x7E);
118 mw_putc(mw, 0);
119 mw_putc(mw, 4);
120 //cmd
121 mw_putc(mw, 0);
122 mw_putc(mw, CMD_OK);
123 //length
124 mw_putc(mw, 0);
125 mw_putc(mw, 0);
126 mw_putc(mw, 0x7E);
127 break;
128 case CMD_SYS_STAT:
129 //LSD header
130 mw_putc(mw, 0x7E);
131 mw_putc(mw, 0);
132 mw_putc(mw, 8);
133 //cmd
134 mw_putc(mw, 0);
135 mw_putc(mw, CMD_OK);
136 //length
137 mw_putc(mw, 0);
138 mw_putc(mw, 4);
139 mw_putc(mw, mw->module_state);
140 mw_putc(mw, mw->flags);
141 mw_putc(mw, mw->channel_flags >> 8);
142 mw_putc(mw, mw->channel_flags);
143 mw_putc(mw, 0x7E);
144 break;
145 default:
146 printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size);
147 break;
148 }
149 } else {
150 printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel);
151 }
152 mw->transmit_bytes = mw->expected_bytes = 0;
153 }
154
155 void *megawifi_write_b(uint32_t address, void *context, uint8_t value)
156 {
157 if (!(address & 1)) {
158 return context;
159 }
160 megawifi *mw = get_megawifi(context);
161 address = address >> 1 & 7;
162 switch (address)
163 {
164 case 0:
165 switch (mw->transmit_state)
166 {
167 case TX_IDLE:
168 if (value == STX) {
169 mw->transmit_state = TX_LEN1;
170 }
171 break;
172 case TX_LEN1:
173 mw->transmit_channel = value >> 4;
174 mw->expected_bytes = value << 8 & 0xF00;
175 mw->transmit_state = TX_LEN2;
176 break;
177 case TX_LEN2:
178 mw->expected_bytes |= value;
179 mw->transmit_state = TX_PAYLOAD;
180 break;
181 case TX_PAYLOAD:
182 mw->transmit_buffer[mw->transmit_bytes++] = value;
183 if (mw->transmit_bytes == mw->expected_bytes) {
184 mw->transmit_state = TX_WAIT_ETX;
185 }
186 break;
187 case TX_WAIT_ETX:
188 if (value == ETX) {
189 mw->transmit_state = TX_IDLE;
190 process_packet(mw);
191 }
192 break;
193 }
194 break;
195 case 7:
196 mw->scratchpad = value;
197 break;
198 default:
199 printf("Unhandled write to MegaWiFi UART register %X: %X\n", address, value);
200 }
201 return context;
202 }
203
204 void *megawifi_write_w(uint32_t address, void *context, uint16_t value)
205 {
206 return megawifi_write_b(address | 1, context, value);
207 }
208
209 uint8_t megawifi_read_b(uint32_t address, void *context)
210 {
211
212 if (!(address & 1)) {
213 return 0xFF;
214 }
215 megawifi *mw = get_megawifi(context);
216 address = address >> 1 & 7;
217 switch (address)
218 {
219 case 0:
220 if (mw->receive_read < mw->receive_bytes) {
221 return mw->receive_buffer[mw->receive_read++];
222 }
223 return 0xFF;
224 case 5:
225 //line status
226 return 0x60 | (mw->receive_read < mw->receive_bytes);
227 case 7:
228 return mw->scratchpad;
229 default:
230 printf("Unhandled read from MegaWiFi UART register %X\n", address);
231 return 0xFF;
232 }
233 }
234
235 uint16_t megawifi_read_w(uint32_t address, void *context)
236 {
237 return 0xFF00 | megawifi_read_b(address | 1, context);
238 }