Mercurial > repos > blastem
comparison megawifi.c @ 1516:aaab852803ac
Get enough of MegaWifi implemented so that basic commands from wflash CLI command work
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 22 Jan 2018 22:02:29 -0800 |
parents | 3fc129eb0653 |
children | 713b504dc577 |
comparison
equal
deleted
inserted
replaced
1515:3fc129eb0653 | 1516:aaab852803ac |
---|---|
1 #include <stdlib.h> | 1 #include <stdlib.h> |
2 #include <stdint.h> | 2 #include <stdint.h> |
3 #include <string.h> | 3 #include <string.h> |
4 #include <sys/types.h> | |
5 #include <sys/socket.h> | |
6 #include <unistd.h> | |
7 #include <netinet/in.h> | |
8 #include <errno.h> | |
9 #include <fcntl.h> | |
4 #include "genesis.h" | 10 #include "genesis.h" |
5 #include "net.h" | 11 #include "net.h" |
6 | 12 |
7 enum { | 13 enum { |
8 TX_IDLE, | 14 TX_IDLE, |
39 typedef struct { | 45 typedef struct { |
40 uint32_t transmit_bytes; | 46 uint32_t transmit_bytes; |
41 uint32_t expected_bytes; | 47 uint32_t expected_bytes; |
42 uint32_t receive_bytes; | 48 uint32_t receive_bytes; |
43 uint32_t receive_read; | 49 uint32_t receive_read; |
50 int sock_fds[15]; | |
44 uint16_t channel_flags; | 51 uint16_t channel_flags; |
52 uint8_t channel_state[15]; | |
45 uint8_t scratchpad; | 53 uint8_t scratchpad; |
46 uint8_t transmit_channel; | 54 uint8_t transmit_channel; |
47 uint8_t transmit_state; | 55 uint8_t transmit_state; |
48 uint8_t module_state; | 56 uint8_t module_state; |
49 uint8_t flags; | 57 uint8_t flags; |
55 { | 63 { |
56 m68k_context *m68k = context; | 64 m68k_context *m68k = context; |
57 genesis_context *gen = m68k->system; | 65 genesis_context *gen = m68k->system; |
58 if (!gen->extra) { | 66 if (!gen->extra) { |
59 gen->extra = calloc(1, sizeof(megawifi)); | 67 gen->extra = calloc(1, sizeof(megawifi)); |
60 ((megawifi *)gen->extra)->module_state = STATE_IDLE; | 68 megawifi *mw = gen->extra; |
69 mw->module_state = STATE_IDLE; | |
70 for (int i = 0; i < 15; i++) | |
71 { | |
72 mw->sock_fds[i] = -1; | |
73 } | |
61 } | 74 } |
62 return gen->extra; | 75 return gen->extra; |
63 } | 76 } |
64 | 77 |
65 static void mw_putc(megawifi *mw, uint8_t v) | 78 static void mw_putc(megawifi *mw, uint8_t v) |
94 if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) { | 107 if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) { |
95 return; | 108 return; |
96 } | 109 } |
97 memcpy(mw->receive_buffer + mw->receive_bytes, s, len); | 110 memcpy(mw->receive_buffer + mw->receive_bytes, s, len); |
98 mw->receive_bytes += len; | 111 mw->receive_bytes += len; |
112 } | |
113 | |
114 static void poll_socket(megawifi *mw, uint8_t channel) | |
115 { | |
116 if (mw->sock_fds[channel] < 0) { | |
117 return; | |
118 } | |
119 if (mw->channel_state[channel] == 1) { | |
120 int res = accept(mw->sock_fds[channel], NULL, NULL); | |
121 if (res >= 0) { | |
122 close(mw->sock_fds[channel]); | |
123 fcntl(res, F_SETFL, O_NONBLOCK); | |
124 mw->sock_fds[channel] = res; | |
125 mw->channel_state[channel] = 2; | |
126 mw->channel_flags |= 1 << (channel + 1); | |
127 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { | |
128 close(mw->sock_fds[channel]); | |
129 mw->channel_state[channel] = 0; | |
130 mw->channel_flags |= 1 << (channel + 1); | |
131 } | |
132 } else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) { | |
133 int bytes = recv( | |
134 mw->sock_fds[channel], | |
135 mw->receive_buffer + mw->receive_bytes + 3, | |
136 sizeof(mw->receive_buffer) - 4 - mw->receive_bytes, | |
137 0 | |
138 ); | |
139 if (bytes > 0) { | |
140 mw_putc(mw, STX); | |
141 mw_putc(mw, bytes >> 8 | (channel+1) << 4); | |
142 mw_putc(mw, bytes); | |
143 mw->receive_bytes += bytes; | |
144 mw_putc(mw, ETX); | |
145 //should this set the channel flag? | |
146 } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
147 close(mw->sock_fds[channel]); | |
148 mw->channel_state[channel] = 0; | |
149 mw->channel_flags |= 1 << (channel + 1); | |
150 } | |
151 } | |
152 } | |
153 | |
154 static void poll_all_sockets(megawifi *mw) | |
155 { | |
156 for (int i = 0; i < 15; i++) | |
157 { | |
158 poll_socket(mw, i); | |
159 } | |
99 } | 160 } |
100 | 161 |
101 static void start_reply(megawifi *mw, uint8_t cmd) | 162 static void start_reply(megawifi *mw, uint8_t cmd) |
102 { | 163 { |
103 mw_putc(mw, STX); | 164 mw_putc(mw, STX); |
129 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; | 190 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; |
130 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; | 191 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; |
131 if (size > mw->transmit_bytes - 4) { | 192 if (size > mw->transmit_bytes - 4) { |
132 size = mw->transmit_bytes - 4; | 193 size = mw->transmit_bytes - 4; |
133 } | 194 } |
134 mw->receive_read = mw->receive_bytes = 0; | 195 int orig_receive_bytes = mw->receive_bytes; |
135 switch (command) | 196 switch (command) |
136 { | 197 { |
137 case CMD_VERSION: | 198 case CMD_VERSION: |
138 start_reply(mw, CMD_OK); | 199 start_reply(mw, CMD_OK); |
139 mw_putc(mw, 1); | 200 mw_putc(mw, 1); |
142 end_reply(mw); | 203 end_reply(mw); |
143 break; | 204 break; |
144 case CMD_ECHO: | 205 case CMD_ECHO: |
145 mw->receive_bytes = mw->transmit_bytes; | 206 mw->receive_bytes = mw->transmit_bytes; |
146 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); | 207 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); |
147 break; | |
148 case CMD_AP_JOIN: | |
149 mw->module_state = STATE_READY; | |
150 start_reply(mw, CMD_OK); | |
151 end_reply(mw); | |
152 break; | |
153 case CMD_SYS_STAT: | |
154 start_reply(mw, CMD_OK); | |
155 mw_putc(mw, mw->module_state); | |
156 mw_putc(mw, mw->flags); | |
157 mw_putc(mw, mw->channel_flags >> 8); | |
158 mw_putc(mw, mw->channel_flags); | |
159 end_reply(mw); | |
160 break; | 208 break; |
161 case CMD_IP_CURRENT: { | 209 case CMD_IP_CURRENT: { |
162 iface_info i; | 210 iface_info i; |
163 if (get_host_address(&i)) { | 211 if (get_host_address(&i)) { |
164 start_reply(mw, CMD_OK); | 212 start_reply(mw, CMD_OK); |
182 start_reply(mw, CMD_ERROR); | 230 start_reply(mw, CMD_ERROR); |
183 } | 231 } |
184 end_reply(mw); | 232 end_reply(mw); |
185 break; | 233 break; |
186 } | 234 } |
235 case CMD_AP_JOIN: | |
236 mw->module_state = STATE_READY; | |
237 start_reply(mw, CMD_OK); | |
238 end_reply(mw); | |
239 break; | |
240 case CMD_TCP_BIND:{ | |
241 if (size < 7){ | |
242 start_reply(mw, CMD_ERROR); | |
243 end_reply(mw); | |
244 break; | |
245 } | |
246 uint8_t channel = mw->transmit_buffer[10]; | |
247 if (!channel || channel > 15) { | |
248 start_reply(mw, CMD_ERROR); | |
249 end_reply(mw); | |
250 break; | |
251 } | |
252 channel--; | |
253 if (mw->sock_fds[channel] >= 0) { | |
254 close(mw->sock_fds[channel]); | |
255 } | |
256 mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); | |
257 if (mw->sock_fds[channel] < 0) { | |
258 start_reply(mw, CMD_ERROR); | |
259 end_reply(mw); | |
260 break; | |
261 } | |
262 int value = 1; | |
263 setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); | |
264 struct sockaddr_in bind_addr; | |
265 memset(&bind_addr, 0, sizeof(bind_addr)); | |
266 bind_addr.sin_family = AF_INET; | |
267 bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]); | |
268 if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) { | |
269 close(mw->sock_fds[channel]); | |
270 mw->sock_fds[channel] = -1; | |
271 start_reply(mw, CMD_ERROR); | |
272 end_reply(mw); | |
273 break; | |
274 } | |
275 int res = listen(mw->sock_fds[channel], 2); | |
276 start_reply(mw, res ? CMD_ERROR : CMD_OK); | |
277 if (res) { | |
278 close(mw->sock_fds[channel]); | |
279 mw->sock_fds[channel] = -1; | |
280 } else { | |
281 mw->channel_flags |= 1 << (channel + 1); | |
282 mw->channel_state[channel] = 1; | |
283 fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK); | |
284 } | |
285 end_reply(mw); | |
286 break; | |
287 } | |
288 case CMD_SOCK_STAT: { | |
289 uint8_t channel = mw->transmit_buffer[4]; | |
290 if (!channel || channel > 15) { | |
291 start_reply(mw, CMD_ERROR); | |
292 end_reply(mw); | |
293 break; | |
294 } | |
295 mw->channel_flags &= ~(1 << channel); | |
296 channel--; | |
297 poll_socket(mw, channel); | |
298 start_reply(mw, CMD_OK); | |
299 mw_putc(mw, mw->channel_state[channel]); | |
300 end_reply(mw); | |
301 break; | |
302 } | |
303 case CMD_SYS_STAT: | |
304 poll_all_sockets(mw); | |
305 start_reply(mw, CMD_OK); | |
306 mw_putc(mw, mw->module_state); | |
307 mw_putc(mw, mw->flags); | |
308 mw_putc(mw, mw->channel_flags >> 8); | |
309 mw_putc(mw, mw->channel_flags); | |
310 end_reply(mw); | |
311 break; | |
187 default: | 312 default: |
188 printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); | 313 printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); |
189 break; | 314 break; |
315 } | |
316 } else if (mw->sock_fds[mw->transmit_channel - 1] >= 0 && mw->channel_state[mw->transmit_channel - 1] == 2) { | |
317 uint8_t channel = mw->transmit_channel - 1; | |
318 int sent = send(mw->sock_fds[channel], mw->transmit_buffer, mw->transmit_bytes, 0); | |
319 if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
320 close(mw->sock_fds[channel]); | |
321 mw->sock_fds[channel] = -1; | |
322 mw->channel_state[channel] = 0; | |
323 mw->channel_flags |= 1 << mw->transmit_channel; | |
324 } else if (sent < mw->transmit_bytes) { | |
325 //TODO: save this data somewhere so it can be sent in poll_socket | |
326 printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes); | |
190 } | 327 } |
191 } else { | 328 } else { |
192 printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); | 329 printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); |
193 } | 330 } |
194 mw->transmit_bytes = mw->expected_bytes = 0; | 331 mw->transmit_bytes = mw->expected_bytes = 0; |
257 megawifi *mw = get_megawifi(context); | 394 megawifi *mw = get_megawifi(context); |
258 address = address >> 1 & 7; | 395 address = address >> 1 & 7; |
259 switch (address) | 396 switch (address) |
260 { | 397 { |
261 case 0: | 398 case 0: |
399 poll_all_sockets(mw); | |
262 if (mw->receive_read < mw->receive_bytes) { | 400 if (mw->receive_read < mw->receive_bytes) { |
263 return mw->receive_buffer[mw->receive_read++]; | 401 uint8_t ret = mw->receive_buffer[mw->receive_read++]; |
402 if (mw->receive_read == mw->receive_bytes) { | |
403 mw->receive_read = mw->receive_bytes = 0; | |
404 } | |
405 return ret; | |
264 } | 406 } |
265 return 0xFF; | 407 return 0xFF; |
266 case 5: | 408 case 5: |
409 poll_all_sockets(mw); | |
267 //line status | 410 //line status |
268 return 0x60 | (mw->receive_read < mw->receive_bytes); | 411 return 0x60 | (mw->receive_read < mw->receive_bytes); |
269 case 7: | 412 case 7: |
270 return mw->scratchpad; | 413 return mw->scratchpad; |
271 default: | 414 default: |