Mercurial > repos > blastem
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 } |