initial support for 2 players
[teensytas.git] / main.c
CommitLineData
c28a7c81 1/*
2 * TeensyTAS, TAS input player for MegaDrive
3 * Copyright (c) 2014 notaz
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
0c1e003e 26#include <stdint.h>
27#include <stdio.h>
28#include <string.h>
29#include "teensy3/core_pins.h"
30#include "teensy3/usb_seremu.h"
31#include "teensy3/usb_rawhid.h"
f20de073 32#include "pkts.h"
33
19560e5f 34#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
35
e8e66d02 36#define noinline __attribute__((noinline))
37
f20de073 38// use power of 2
39#define STREAM_BUF_SIZE 512
40#define STREAM_BUF_MASK (512 - 1)
0c1e003e 41
9c4f55f4 42/* ?0SA 00DU, ?1CB RLDU */
e8e66d02 43#define STREAM_EL_SZ 2
44
f20de073 45static struct {
19560e5f 46 uint8_t stream_to[2][STREAM_BUF_SIZE][STREAM_EL_SZ];
e8e66d02 47 uint8_t stream_from[STREAM_BUF_SIZE][STREAM_EL_SZ];
19560e5f 48 struct {
49 union {
50 uint8_t fixed_state[4];
51 uint32_t fixed_state32;
52 };
53 union {
54 uint8_t pending_state[4];
55 uint32_t pending_state32;
56 };
57 } pl[2];
e8e66d02 58 uint32_t stream_enable_to:1;
59 uint32_t stream_enable_from:1;
f20de073 60 uint32_t stream_started:1;
e8e66d02 61 uint32_t stream_ended:1;
19560e5f 62 uint32_t inc_mode:2;
72ef318c 63 uint32_t use_pending:1;
4af6d4e5 64 uint32_t frame_cnt;
f20de073 65 uint32_t edge_cnt;
19560e5f 66 struct {
67 uint32_t i;
68 uint32_t o;
69 } pos_to_p[2], pos_from;
f20de073 70} g;
71
0c1e003e 72ssize_t _write(int fd, const void *buf, size_t nbyte)
73{
74 char tbuf[64];
75 int ret;
76
77 if (fd != 1 && fd != 2) {
78 snprintf(tbuf, sizeof(tbuf), "write to fd %d\n", fd);
79 usb_seremu_write(tbuf, strlen(tbuf));
80 }
81
82 ret = usb_seremu_write(buf, nbyte);
83 return ret < 0 ? ret : nbyte;
84}
85
86void yield(void)
87{
88}
89
19560e5f 90static noinline void choose_isrs_idle(void);
91
92/* player1 TH */
93#define PL1_ISFR PORTD_ISFR
94#define PL1_TH() ((CORE_PIN21_PINREG >> CORE_PIN21_BIT) & 1)
95
96static void pl1th_isr_fixed(void)
9c4f55f4 97{
f20de073 98 uint32_t isfr, th;
9c4f55f4 99
19560e5f 100 isfr = PL1_ISFR;
101 PL1_ISFR = isfr;
102 th = PL1_TH();
4af6d4e5 103
19560e5f 104 GPIOD_PDOR = g.pl[0].fixed_state[th];
4af6d4e5 105 g.edge_cnt++;
106}
107
8e400118 108static noinline void do_to_step(void)
109{
110 g.frame_cnt++;
111
19560e5f 112 g.pos_to_p[0].o = (g.pos_to_p[0].o + 1) & STREAM_BUF_MASK;
113 if (g.pos_to_p[0].o == g.pos_to_p[0].i)
8e400118 114 // done
19560e5f 115 choose_isrs_idle();
8e400118 116}
117
19560e5f 118static void pl1th_isr_do_to_inc(void)
4af6d4e5 119{
120 uint32_t isfr, th;
9c4f55f4 121
19560e5f 122 isfr = PL1_ISFR;
123 PL1_ISFR = isfr;
124 th = PL1_TH();
f20de073 125
19560e5f 126 GPIOD_PDOR = g.stream_to[0][g.pos_to_p[0].o][th];
8e400118 127 if (th)
128 do_to_step();
f20de073 129}
130
19560e5f 131static void pl1th_isr_do_to(void)
4af6d4e5 132{
133 uint32_t isfr, th;
134
19560e5f 135 isfr = PL1_ISFR;
136 PL1_ISFR = isfr;
137 th = PL1_TH();
4af6d4e5 138
19560e5f 139 GPIOD_PDOR = g.stream_to[0][g.pos_to_p[0].o][th];
4af6d4e5 140 g.edge_cnt++;
141}
142
19560e5f 143/* player2 TH */
144#define PL2_ISFR PORTC_ISFR
145#define PL2_TH() ((CORE_PIN15_PINREG >> CORE_PIN15_BIT) & 1)
146#define PL2_ADJ(x) ((x) | ((x) << 12))
147
148static void pl2th_isr_fixed(void)
149{
150 uint32_t isfr, th, v;
151
152 isfr = PL2_ISFR;
153 PL2_ISFR = isfr;
154 th = PL2_TH();
155
156 v = g.pl[1].fixed_state[th];
157 GPIOB_PDOR = PL2_ADJ(v);
158}
159
160static void pl2th_isr_do_to(void)
161{
162 uint32_t isfr, th, v;
163
164 isfr = PL2_ISFR;
165 PL2_ISFR = isfr;
166 th = PL2_TH();
167
168 v = g.stream_to[1][g.pos_to_p[0].o][th];
169 GPIOB_PDOR = PL2_ADJ(v);
170
171 g.pos_to_p[1].o = g.pos_to_p[0].o;
172}
173
174static void pl2th_isr_do_to_inc_pl1(void)
175{
176 uint32_t isfr, th, v;
177
178 isfr = PL2_ISFR;
179 PL2_ISFR = isfr;
180 th = PL2_TH();
181
182 v = g.stream_to[1][g.pos_to_p[1].o][th];
183 GPIOB_PDOR = PL2_ADJ(v);
184 if (th) {
185 do_to_step();
186 g.pos_to_p[1].o = g.pos_to_p[0].o;
187 }
188}
189
190/* vsync handler */
191#define VSYNC_ISFR PORTC_ISFR
192
193static void vsync_isr_nop(void)
4af6d4e5 194{
195 uint32_t isfr;
196
19560e5f 197 isfr = VSYNC_ISFR;
198 VSYNC_ISFR = isfr;
4af6d4e5 199}
200
201// /vsync starts at line 235/259 (ntsc/pal), just as vcounter jumps back
202// we care when it comes out (/vsync goes high) after 3 lines at 238/262
19560e5f 203static void vsync_isr_frameinc(void)
4af6d4e5 204{
205 uint32_t isfr;
206
19560e5f 207 isfr = VSYNC_ISFR;
208 VSYNC_ISFR = isfr;
4af6d4e5 209
19560e5f 210 g.pos_to_p[0].o = (g.pos_to_p[0].o + 1) & STREAM_BUF_MASK;
211 g.pos_to_p[1].o = g.pos_to_p[0].o;
212
213 if (g.pos_to_p[0].o == g.pos_to_p[0].i)
214 choose_isrs_idle();
4af6d4e5 215 g.frame_cnt++;
216}
217
e8e66d02 218/* "recording" data */
219static noinline void do_from_step(void)
220{
221 uint32_t s;
222
223 // should hopefully give atomic fixed_state read..
19560e5f 224 s = g.pl[0].fixed_state32;
225 g.pl[0].fixed_state32 = g.pl[0].pending_state32;
226 g.stream_from[g.pos_from.i][0] = s;
227 g.stream_from[g.pos_from.i][1] = s >> 8;
228 g.pos_from.i = (g.pos_from.i + 1) & STREAM_BUF_MASK;
e8e66d02 229}
230
19560e5f 231static void pl1th_isr_fixed_do_from(void)
e8e66d02 232{
233 uint32_t isfr, th;
234
19560e5f 235 isfr = PL1_ISFR;
236 PL1_ISFR = isfr;
237 th = PL1_TH();
e8e66d02 238
19560e5f 239 GPIOD_PDOR = g.pl[0].fixed_state[th];
e8e66d02 240 if (th)
241 do_from_step();
242 g.edge_cnt++;
243}
244
19560e5f 245static void vsync_isr_frameinc_do_from(void)
e8e66d02 246{
247 uint32_t isfr;
248
19560e5f 249 isfr = VSYNC_ISFR;
250 VSYNC_ISFR = isfr;
e8e66d02 251
252 do_from_step();
253 g.frame_cnt++;
254}
255
19560e5f 256/* * */
6d4349fc 257static void choose_isrs(void)
258{
19560e5f 259 void (*pl1th_handler)(void) = pl1th_isr_fixed;
260 void (*pl2th_handler)(void) = pl2th_isr_fixed;
261 void (*vsync_handler)(void) = vsync_isr_nop;
262
6d4349fc 263 if (g.stream_enable_to) {
19560e5f 264 switch (g.inc_mode) {
265 case INC_MODE_VSYNC:
266 pl1th_handler = pl1th_isr_do_to;
267 pl2th_handler = pl2th_isr_do_to;
268 vsync_handler = vsync_isr_frameinc;
269 break;
270 case INC_MODE_SHARED_PL1:
271 pl1th_handler = pl1th_isr_do_to_inc;
272 pl2th_handler = pl2th_isr_do_to;
273 break;
274 case INC_MODE_SHARED_PL2:
275 pl1th_handler = pl1th_isr_do_to;
276 pl2th_handler = pl2th_isr_do_to_inc_pl1;
277 break;
6d4349fc 278 }
279 }
280 else if (g.stream_enable_from) {
281 g.use_pending = 1;
19560e5f 282 switch (g.inc_mode) {
283 case INC_MODE_VSYNC:
284 vsync_handler = vsync_isr_frameinc_do_from;
285 break;
286 case INC_MODE_SHARED_PL1:
287 pl1th_handler = pl1th_isr_fixed_do_from;
288 break;
289 case INC_MODE_SHARED_PL2:
290 /* TODO */
291 break;
6d4349fc 292 }
293 }
19560e5f 294
295 attachInterruptVector(IRQ_PORTD, pl1th_handler);
296 attachInterruptVector(IRQ_PORTC, pl2th_handler);
297 attachInterruptVector(IRQ_PORTA, vsync_handler);
298}
299
300static noinline void choose_isrs_idle(void)
301{
302 attachInterruptVector(IRQ_PORTD, pl1th_isr_fixed);
303 attachInterruptVector(IRQ_PORTC, pl2th_isr_fixed);
304 attachInterruptVector(IRQ_PORTA, vsync_isr_nop);
6d4349fc 305}
306
f20de073 307static void udelay(uint32_t us)
308{
309 uint32_t start = micros();
310
311 while ((micros() - start) < us) {
312 asm volatile("nop; nop; nop; nop");
313 yield();
314 }
315}
316
317static void do_start_seq(void)
318{
319 uint32_t edge_cnt_last;
320 uint32_t edge_cnt;
321 uint32_t start, t1, t2;
322 int tout;
323
324 start = micros();
325 edge_cnt = g.edge_cnt;
326
327 /* magic value */
19560e5f 328 g.pl[0].fixed_state[0] =
329 g.pl[0].fixed_state[1] = 0x25;
f20de073 330
331 for (tout = 10000; tout > 0; tout--) {
332 edge_cnt_last = edge_cnt;
333 udelay(100);
334 edge_cnt = g.edge_cnt;
335
336 if (edge_cnt != edge_cnt_last)
337 continue;
19560e5f 338 if (!PL1_TH())
f20de073 339 break;
340 }
341
19560e5f 342 g.pl[0].fixed_state[0] = 0x33;
343 g.pl[0].fixed_state[1] = 0x3f;
f20de073 344 GPIOD_PDOR = 0x33;
345
346 t1 = micros();
347 if (tout == 0) {
348 printf("start_seq timeout1, t=%u\n", t1 - start);
349 return;
350 }
351
352 for (tout = 100000; tout > 0; tout--) {
353 udelay(1);
354
19560e5f 355 if (PL1_TH())
f20de073 356 break;
357 }
358
359 t2 = micros();
360 if (tout == 0) {
361 printf("start_seq timeout2, t1=%u, t2=%u\n",
362 t1 - start, t2 - t1);
363 return;
364 }
365
366 //printf(" t1=%u, t2=%u\n", t1 - start, t2 - t1);
367
368 if (g.stream_started) {
369 printf("got start_seq when already started\n");
370 return;
371 }
372
e8e66d02 373 if (!g.stream_enable_to && !g.stream_enable_from) {
f20de073 374 printf("got start_seq, without enable from USB\n");
375 return;
376 }
377
19560e5f 378 if (g.stream_enable_to && g.pos_to_p[0].i == g.pos_to_p[0].o) {
e8e66d02 379 printf("got start_seq while stream_to is empty\n");
380 return;
381 }
382
19560e5f 383 if (g.stream_enable_from && g.pos_from.i != g.pos_from.o) {
e8e66d02 384 printf("got start_seq while stream_from is not empty\n");
f20de073 385 return;
386 }
387
4af6d4e5 388 __disable_irq();
6d4349fc 389 choose_isrs();
f20de073 390 g.stream_started = 1;
4af6d4e5 391 __enable_irq();
f20de073 392}
393
e8e66d02 394// callers must disable IRQs
395static void clear_state(void)
396{
19560e5f 397 int i;
398
e8e66d02 399 g.stream_enable_to = 0;
400 g.stream_enable_from = 0;
e8e66d02 401 g.stream_started = 0;
402 g.stream_ended = 0;
19560e5f 403 g.inc_mode = INC_MODE_VSYNC;
72ef318c 404 g.use_pending = 0;
19560e5f 405 for (i = 0; i < ARRAY_SIZE(g.pos_to_p); i++)
406 g.pos_to_p[i].i = g.pos_to_p[i].o = 0;
407 g.pos_from.i = g.pos_from.o = 0;
e8e66d02 408 g.frame_cnt = 0;
19560e5f 409 choose_isrs_idle();
e8e66d02 410}
411
19560e5f 412static int get_space_to(int p)
f20de073 413{
19560e5f 414 return STREAM_BUF_SIZE - ((g.pos_to_p[p].i - g.pos_to_p[p].o)
415 & STREAM_BUF_MASK);
e8e66d02 416}
417
418static int get_used_from(void)
419{
19560e5f 420 return (g.pos_from.i - g.pos_from.o) & STREAM_BUF_MASK;
f20de073 421}
422
423static void do_usb(void *buf)
424{
425 struct tas_pkt *pkt = buf;
19560e5f 426 uint32_t pos_to_i, i, p;
f20de073 427 int space;
428
429 switch (pkt->type) {
430 case PKT_FIXED_STATE:
72ef318c 431 memcpy(&i, pkt->data, sizeof(i));
432 if (g.use_pending)
19560e5f 433 g.pl[0].pending_state32 = i;
72ef318c 434 else
19560e5f 435 g.pl[0].fixed_state32 = i;
f20de073 436 break;
437 case PKT_STREAM_ENABLE:
4af6d4e5 438 __disable_irq();
e8e66d02 439 clear_state();
4af6d4e5 440 /* wait for start from MD */
e8e66d02 441 g.stream_enable_to = pkt->enable.stream_to;
442 g.stream_enable_from = pkt->enable.stream_from;
19560e5f 443 g.inc_mode = pkt->enable.inc_mode;
6d4349fc 444 if (pkt->enable.no_start_seq) {
445 GPIOD_PDOR = 0x3f;
446 choose_isrs();
447 g.stream_started = 1;
448 }
e8e66d02 449 __enable_irq();
450 break;
451 case PKT_STREAM_ABORT:
452 __disable_irq();
453 clear_state();
4af6d4e5 454 __enable_irq();
f20de073 455 break;
456 case PKT_STREAM_END:
e8e66d02 457 g.stream_ended = 1;
4af6d4e5 458 printf("end of stream\n");
f20de073 459 break;
19560e5f 460 case PKT_STREAM_DATA_TO_P1:
461 case PKT_STREAM_DATA_TO_P2:
462 p = pkt->type == PKT_STREAM_DATA_TO_P1 ? 0 : 1;
463 pos_to_i = g.pos_to_p[p].i;
464 space = get_space_to(p);
e8e66d02 465 if (space <= pkt->size / STREAM_EL_SZ) {
f20de073 466 printf("got data pkt while space=%d\n", space);
467 return;
468 }
e8e66d02 469 for (i = 0; i < pkt->size / STREAM_EL_SZ; i++) {
19560e5f 470 memcpy(&g.stream_to[p][pos_to_i++],
f20de073 471 pkt->data + i * STREAM_EL_SZ,
472 STREAM_EL_SZ);
19560e5f 473 pos_to_i &= STREAM_BUF_MASK;
f20de073 474 }
19560e5f 475 g.pos_to_p[p].i = pos_to_i;
f20de073 476 break;
477 default:
478 printf("got unknown pkt type: %04x\n", pkt->type);
479 break;
480 }
9c4f55f4 481}
482
19560e5f 483static void check_get_data(int p)
484{
485 struct tas_pkt pkt;
486 uint8_t buf[64];
487 int ret;
488
489 if (get_space_to(p) <= sizeof(pkt.data) / STREAM_EL_SZ)
490 return;
491
492 if (g.pos_to_p[p].i == g.pos_to_p[p].o && g.frame_cnt != 0) {
493 printf("underflow detected\n");
494 g.stream_enable_to = 0;
495 return;
496 }
497
498 pkt.type = PKT_STREAM_REQ;
499 pkt.req.frame = g.frame_cnt;
500 pkt.req.is_p2 = p;
501
502 ret = usb_rawhid_send(&pkt, 1000);
503 if (ret != sizeof(pkt)) {
504 printf("send STREAM_REQ/%d: %d\n", p, ret);
505 return;
506 }
507
508 ret = usb_rawhid_recv(buf, 1000);
509 if (ret != 64)
510 printf("usb_rawhid_recv/s: %d\n", ret);
511 else
512 do_usb(buf);
513}
514
0c1e003e 515int main(void)
516{
beaf6d89 517 uint32_t led_time = 0;
518 uint32_t scheck_time = 0;
f20de073 519 uint32_t edge_cnt_last;
520 uint32_t edge_cnt;
521 uint8_t buf[64];
19560e5f 522 int i, ret;
0c1e003e 523
524 delay(1000); // wait for usb..
525
f20de073 526 /* ?0SA 00DU, ?1CB RLDU */
19560e5f 527 for (i = 0; i < 2; i++) {
528 g.pl[i].fixed_state[0] = 0x33;
529 g.pl[i].fixed_state[1] = 0x3f;
530 }
f20de073 531
0c1e003e 532 printf("starting, rawhid: %d\n", usb_rawhid_available());
533
19560e5f 534 choose_isrs_idle();
535
536 // md pin th tr tl r l d u vsync th tr tl r l d u
537 // 7 9 6 4 3 2 1 7 9 6 4 3 2 1
538 // md bit* 6 5 4 3 2 1 0 6 5 4 3 2 1 0
539 // t bit d6 d5 d4 d3 d2 d1 d0 a12 c0 b17 b16 b3 b2 b1 b0
540 // t pin 21 20 6 8 7 14 2 3 15 1 0 18 19 17 16
9c4f55f4 541 // * - note: tl/tr mixed in most docs
19560e5f 542
543 // player1
544 pinMode(21, INPUT);
545 attachInterrupt(21, pl1th_isr_fixed, CHANGE);
546 NVIC_SET_PRIORITY(IRQ_PORTD, 0);
f20de073 547
9c4f55f4 548 pinMode( 2, OUTPUT);
549 pinMode(14, OUTPUT);
550 pinMode( 7, OUTPUT);
551 pinMode( 8, OUTPUT);
552 pinMode( 6, OUTPUT);
553 pinMode(20, OUTPUT);
554
19560e5f 555 // player2
556 pinMode(15, INPUT);
557 attachInterrupt(15, pl1th_isr_fixed, CHANGE);
558 NVIC_SET_PRIORITY(IRQ_PORTC, 0);
559
560 pinMode(16, OUTPUT);
561 pinMode(17, OUTPUT);
562 pinMode(19, OUTPUT);
563 pinMode(18, OUTPUT);
564 pinMode( 0, OUTPUT);
565 pinMode( 1, OUTPUT);
566
567 // vsync line
568 pinMode(3, INPUT);
569 attachInterrupt(3, vsync_isr_nop, RISING);
570 NVIC_SET_PRIORITY(IRQ_PORTA, 16);
571
9c4f55f4 572 // led
573 pinMode(13, OUTPUT);
9c4f55f4 574
19560e5f 575 // lower other priorities
576 SCB_SHPR1 = SCB_SHPR2 = SCB_SHPR3 = 0x10101010;
577
9c4f55f4 578 // CORE_PIN0_PORTSET CORE_PIN0_BITMASK PORTB_PCR16
4af6d4e5 579 printf("GPIOB PDDR, PDIR: %08x %08x\n", GPIOB_PDIR, GPIOB_PDDR);
9c4f55f4 580 printf("GPIOC PDDR, PDIR: %08x %08x\n", GPIOC_PDIR, GPIOC_PDDR);
581 printf("GPIOD PDDR, PDIR: %08x %08x\n", GPIOD_PDIR, GPIOD_PDDR);
582 printf("PORTB_PCR16: %08x\n", PORTB_PCR16);
4af6d4e5 583 printf("PORTC_PCR6: %08x\n", PORTC_PCR6);
8e400118 584 printf("PORTD_PCR0: %08x\n", PORTD_PCR0);
9c4f55f4 585
f20de073 586 asm("mrs %0, BASEPRI" : "=r"(ret));
8e400118 587 printf("BASEPRI: %d, SHPR: %08x %08x %08x\n",
588 ret, SCB_SHPR1, SCB_SHPR2, SCB_SHPR3);
0c1e003e 589
f20de073 590 edge_cnt_last = g.edge_cnt;
9c4f55f4 591
1cb2822f 592 while (1) {
f20de073 593 struct tas_pkt pkt;
beaf6d89 594 uint32_t now;
e8e66d02 595
19560e5f 596 if (g.stream_enable_to && !g.stream_ended) {
597 check_get_data(0);
598 if (g.inc_mode == INC_MODE_SHARED_PL2)
599 check_get_data(1);
f20de073 600 }
601
e8e66d02 602 while (g.stream_enable_from && !g.stream_ended
603 && get_used_from() >= sizeof(pkt.data) / STREAM_EL_SZ)
604 {
19560e5f 605 uint32_t o;
e8e66d02 606 int i;
607
19560e5f 608 o = g.pos_from.o;
e8e66d02 609 for (i = 0; i < sizeof(pkt.data); i += STREAM_EL_SZ) {
19560e5f 610 memcpy(pkt.data + i, &g.stream_from[o++],
e8e66d02 611 STREAM_EL_SZ);
19560e5f 612 o &= STREAM_BUF_MASK;
e8e66d02 613 }
19560e5f 614 g.pos_from.o = o;
e8e66d02 615
616 pkt.type = PKT_STREAM_DATA_FROM;
617 pkt.size = i;
618
619 ret = usb_rawhid_send(&pkt, 1000);
620 if (ret != sizeof(pkt)) {
621 printf("send DATA_FROM: %d\n", ret);
622 break;
623 }
624 }
625
beaf6d89 626 now = millis();
627
628 // start condition check
629 if (now - scheck_time > 1000) {
f20de073 630 edge_cnt = g.edge_cnt;
631 //printf("e: %d th: %d\n", edge_cnt - edge_cnt_last,
19560e5f 632 // PL1_TH());
beaf6d89 633 if ((g.stream_enable_to || g.stream_enable_from)
634 && !g.stream_started
635 && edge_cnt - edge_cnt_last > 10000)
636 {
f20de073 637 do_start_seq();
638 edge_cnt = g.edge_cnt;
639 }
640 edge_cnt_last = edge_cnt;
beaf6d89 641 scheck_time = now;
f20de073 642 }
643
beaf6d89 644 // led?
645 if (CORE_PIN13_PORTREG & CORE_PIN13_BITMASK) {
646 if ((int)(now - led_time) > 10)
647 CORE_PIN13_PORTCLEAR = CORE_PIN13_BITMASK;
1cb2822f 648 }
beaf6d89 649
650 // something on rawhid?
651 if (usb_rawhid_available() > 0)
652 {
653 ret = usb_rawhid_recv(buf, 20);
654 if (ret == 64) {
655 led_time = millis();
656 CORE_PIN13_PORTSET = CORE_PIN13_BITMASK;
657
658 do_usb(buf);
659 }
660 else {
661 printf("usb_rawhid_recv: %d\n", ret);
662 }
1cb2822f 663 }
0c1e003e 664 }
1cb2822f 665
666 return 0;
0c1e003e 667}