#include #include #include #include #include #include #define TIMER1_INTERVAL 1953 enum { TABBY_SEND_READING = 0, TABBY_SEND_BUFFERED = (1 << 0), TABBY_SEND_COMPLETE = (1 << 1) }; static volatile uint8_t bits = 0; static volatile uint8_t value_in = 0x00; /* Data coming in from Game Boy */ static volatile uint8_t value_out = 0x00; /* Data going out to Game Boy */ static volatile tabby_printer_packet header = { .type = 0, .compression = 0, .size = 0 }; static volatile uint8_t body[TABBY_PRINTER_MAX_PACKET_SIZE]; static volatile uint16_t sum = 0x0000; static volatile uint8_t device = 0x00, status = 0x00, flags = TABBY_SEND_READING; static volatile uint16_t i = 0, b = 0; static void spi_start() { /* * Configure MISO as input */ DDRB &= ~(1 << DDB4); /* * Configure MOSI as output */ DDRB |= (1 << DDB3); /* * Configure SCK pin as output */ DDRB |= (1 << DDB5); /* * Enable timer interrupt vector */ TIMSK0 = (1 << TOIE0); /* * Reset timer counter to zero */ TCNT1 = 0; /* * Set timer interval */ OCR1A = TIMER1_INTERVAL; /* * Set timer clock divider to 1/1 */ TCCR1B = (1 << CS10); } static void spi_end() { DDRB &= ~((1 << DDB5) | (1 << DDB4) | (1 << DDB3)); TIMSK0 &= ~(1 << TOIE0); TCNT1 = 0; OCR1A = TIMER1_INTERVAL; TCCR1B = (1 << CS10); } ISR(TIMER1_COMPA_vect) { value_in >>= 1; PORTB |= (1 << PORTB5); if (PORTB & (1 << PORTB4)) { value_in |= 0x80; } if (value_out & 0x80) { PORTB |= (1 << PORTB3); } else { PORTB &= ~(1 << PORTB3); } value_out <<= 1; if (--bits == 0) { if (i < sizeof(header)) { value_out = header.data[i++]; } else if (b < header.size) { value_out = body[b++]; } else if (b == header.size) { value_out = sum & 0x00ff; b++; } else if (b == header.size + 1) { value_out = (sum & 0xff00) >> 8; b++; } else if (b == header.size + 2) { device = value_in; value_out = 0x00; b++; } else if (b == header.size + 3) { status = value_in; value_out = 0x00; i = 0; b = 0; flags &= ~TABBY_SEND_BUFFERED; flags |= TABBY_SEND_COMPLETE; spi_end(); } bits = 8; } /* * Chill out for 60µsec, then ride out the rest of the time until the next * interrupt with a high as fuck SCK */ _delay_us(60); PORTB &= ~(1 << PORTB5); } static uint16_t checksum() { uint16_t sum = 0; size_t i; for (i=2; i<6; i++) { sum += header.data[i]; } for (i=0; i