code cleanup, dropped the sniffer
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 8 Mar 2021 09:14:57 +0000 (11:14 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 8 Mar 2021 09:14:57 +0000 (11:14 +0200)
.gitignore
Makefile
main.c [deleted file]
serial.c [deleted file]
serial.h [deleted file]
src/i2c.c [new file with mode: 0644]
src/i2c.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/serial.c [new file with mode: 0644]
src/serial.h [new file with mode: 0644]

index 3016d77..b890f1c 100644 (file)
@@ -1,7 +1,7 @@
 *.o
 *.d
 *.swp
-test
+tv_i2c_hack
 *.eep
 *.hex
 *.map
index 9d5bcf1..05efc87 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-src = $(wildcard *.c)
+src = $(wildcard src/*.c)
 obj = $(src:.c=.o)
-bin = test
+bin = tv_i2c_hack
 hex = $(bin).hex
 eep = $(bin).eep
 
@@ -12,7 +12,7 @@ OBJCOPY = avr-objcopy
 
 warn = -pedantic -Wall
 
-CFLAGS = -Os $(warn) -mmcu=$(mcu_gcc) -DF_CPU=20000000
+CFLAGS = -Os $(warn) -mmcu=$(mcu_gcc) -DF_CPU=14745600
 LDFLAGS = -Wl,-Map,$(bin).map -mmcu=$(mcu_gcc) -lprintf_min
 
 .PHONY: all
diff --git a/main.c b/main.c
deleted file mode 100644 (file)
index fa0be2f..0000000
--- a/main.c
+++ /dev/null
@@ -1,702 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <avr/io.h>
-#include <avr/interrupt.h>
-#include <util/delay.h>
-#include "serial.h"
-
-#undef USE_PCINT
-
-enum {
-       I2C_IDLE,
-       I2C_MASTER_WRITE,
-       I2C_MASTER_READ
-};
-
-enum {
-       ST_INVALID                      = 0,
-       ST_UNKNOWN                      = 0xf8,
-       ST_START                        = 0x08,
-       ST_REP_START            = 0x10,
-       ST_SLA_W_ACK            = 0x18,
-       ST_SLA_W_NACK           = 0x20,
-       ST_WR_ACK                       = 0x28,
-       ST_WR_NACK                      = 0x30,
-       ST_ARBLOST                      = 0x38,
-       ST_SLA_R_ACK            = 0x40,
-       ST_SLA_R_NACK           = 0x48,
-       ST_RD_ACK                       = 0x50,
-       ST_RD_NACK                      = 0x58,
-       ST_MATCH_W                      = 0x60,
-       ST_ARBLOST_MATCH        = 0x68,
-       ST_GENMATCH                     = 0x70,
-       ST_ARBLOST_GENMATCH = 0x78,
-       ST_SLAVE_RD_ACK         = 0x80,
-       ST_SLAVE_RD_NACK        = 0x88,
-       ST_SLAVE_GENRD_ACK      = 0x90,
-       ST_SLAVE_GENRD_NACK     = 0x98,
-       ST_SLAVE_STARTSTOP      = 0xa0,
-       ST_SLAVE_SLA_WR_ACK     = 0xa8,
-       ST_SLAVE_ARBLOST_WR_ACK = 0xb0,
-       ST_SLAVE_WR_ACK         = 0xb8,
-       ST_SLAVE_WR_NACK        = 0xc0,
-       ST_SLAVE_LAST_WR_ACK = 0xc8
-};
-
-enum {
-       EV_DEBUG,
-       EV_START,
-       EV_STOP,
-       EV_SLA_W,
-       EV_SLA_R,
-       EV_DATA
-};
-
-static const char *evname[] = {
-       "DBG",
-       "STA",
-       "STO",
-       "A+W",
-       "A+R",
-       "DAT"
-};
-
-#define TWINT_BIT      (1 << TWINT)
-#define TWEA_BIT       (1 << TWEA)
-#define TWSTA_BIT      (1 << TWSTA)
-#define TWSTO_BIT      (1 << TWSTO)
-#define TWEN_BIT       (1 << TWEN)
-#define TWIE_BIT       (1 << TWIE)
-
-#define I2C_START()    (TWCR = TWINT_BIT | TWSTA_BIT | TWEN_BIT | TWIE_BIT)
-#define I2C_STOP()     (TWCR = TWINT_BIT | TWSTO_BIT | TWEN_BIT | TWIE_BIT)
-#define I2C_WRITE()    (TWCR = TWINT_BIT | TWEN_BIT | TWIE_BIT)
-#define I2C_READ_ACK() (TWCR = TWINT_BIT | TWEA_BIT | TWEN_BIT | TWIE_BIT)
-#define I2C_READ_NACK()        (TWCR = TWINT_BIT | TWEN_BIT | TWIE_BIT)
-
-unsigned char i2c_addr, i2c_subaddr;
-volatile unsigned char i2c_mode;
-int i2c_seq, i2c_ndata;
-unsigned char *i2c_data;
-int i2c_retry_delay;
-
-#define EVQ_SIZE       64
-uint16_t evq[EVQ_SIZE];
-volatile int evq_wr, evq_rd;
-
-#define LOGNUM(x)      EVLOG(EV_DEBUG, (x))
-
-#define EVLOG(ev, data)        \
-       do { \
-               if(ev != EV_DEBUG || dbgmode) { \
-                       evq[evq_wr] = ((uint16_t)(ev) << 8) | (data); \
-                       evq_wr = (evq_wr + 1) & (EVQ_SIZE - 1); \
-                       if(evq_wr == evq_rd) { \
-                               evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1); \
-                       } \
-               } \
-       } while(0)
-
-/* serial input buffer */
-static char input[64];
-static unsigned char inp_cidx;
-
-static unsigned char data[16];
-
-static void (*async_func)(void);
-
-static uint16_t dump_addr;
-static int dump_count;
-static int dbgmode;
-static int snooping;
-
-static void proc_cmd(char *input);
-static void printstat(void);
-static void printdump(void);
-
-void i2c_write(unsigned char addr, unsigned char subaddr, unsigned char *data, int ndata);
-void i2c_read(unsigned char addr, unsigned char subaddr, unsigned char *buf, int size);
-void i2c_wait(void);
-void i2c_async(void (*donecb)(void));
-void i2c_check_async(void);
-void i2c_hold(void);
-void i2c_release(void);
-void i2c_snoop(int onoff);
-#ifndef USE_PCINT
-void snoop(void);
-#endif
-
-int main(void)
-{
-       uint16_t val;
-
-       /* tri-state everything and disable pullups */
-       DDRB = 1;       /* B0: activity LED */
-       DDRC = 0;       /* I2C pins as inputs */
-       DDRD = 0;
-       PORTB = 0;
-       PORTC = 0;
-       PORTD = 0;
-
-       TWBR = 10;              /* 10 with 1x prescaler should make it about 100khz */
-       TWSR = 0;               /* prescaler 1x */
-       TWAR = 0;
-       TWAMR = 0;
-       TWCR = 0;               /* I2C disabled by default */
-
-       i2c_mode = I2C_IDLE;
-       i2c_snoop(0);   /* disable snooping by default */
-
-       init_serial(38400);
-       sei();
-
-       printf("Starting i2c hack\n");
-
-       for(;;) {
-#ifndef USE_PCINT
-               if(snooping) {
-                       snoop();
-                       if(have_input()) {
-                               i2c_snoop(0);
-                       }
-                       continue;
-               }
-#endif
-
-               i2c_check_async();
-
-               if(have_input()) {
-                       int c = getchar();
-                       putchar(c);
-
-                       if(c == '\r' || c == '\n') {
-                               putchar('\n');
-                               input[inp_cidx] = 0;
-                               proc_cmd(input);
-                               inp_cidx = 0;
-                       } else if(inp_cidx < sizeof input - 1) {
-                               input[inp_cidx++] = c;
-                       }
-               }
-
-               /* read from queue and send over the serial port */
-               val = 0xffff;
-               cli();
-               if(evq_wr != evq_rd) {
-                       val = evq[evq_rd];
-                       evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1);
-               }
-               sei();
-
-               if(val != 0xffff) {
-                       unsigned char ev = val >> 8;
-                       if(ev > EV_DATA) {
-                               printf("%02x: %02x\n", ev, val & 0xff);
-                       } else {
-                               printf("%s: %02x\n", evname[ev], val & 0xff);
-                       }
-               }
-       }
-       return 0;
-}
-
-static void proc_cmd(char *input)
-{
-       char *endp;
-
-       if(strcmp(input, "dbg") == 0) {
-               printf("OK dbg\n");
-               dbgmode = 1;
-
-       } else if(strcmp(input, "nodbg") == 0) {
-               printf("OK nodbg\n");
-               dbgmode = 0;
-
-       } else if(strcmp(input, "start") == 0) {
-               printf("OK snooping\n");
-               i2c_snoop(1);
-
-       } else if(strcmp(input, "stop") == 0) {
-               i2c_snoop(0);
-               printf("OK stopped snooping\n");
-
-       } else if(strcmp(input, "av") == 0) {
-               printf("OK AV\n");
-
-               /* AV switch (22): 0 0 SVO CMB1 CMB0 INA INB 0 */
-               data[0] = 0x22;
-               i2c_write(0x8a, 0x22, data, 1);
-               i2c_async(i2c_hold);
-
-       } else if(strcmp(input, "rgb") == 0) {
-               printf("OK RGB\n");
-
-               /* Control 0 (2a): 0 IE2 RBL AKB  CL3 CL2 CL1 CL0
-                * Control 1 (2b): 0  0   0   0    0   0  YUV HBL
-                */
-               data[0] = 0x70;
-               data[1] = 0;
-               i2c_write(0x8a, 0x2a, data, 1);
-               while(i2c_mode);
-               i2c_write(0x8a, 0x2b, data + 1, 1);
-
-       } else if(memcmp(input, "vol ", 4) == 0) {
-               int vol = atoi(input + 4);
-               if(vol < 1 || vol > 63) {
-                       printf("ERR vol (%s)\n", input + 4);
-               } else {
-                       data[0] = vol;
-                       i2c_write(0x8a, 0x1f, data, 1);
-                       printf("OK volume: %d\n", vol);
-               }
-
-       } else if(memcmp(input, "sat", 3) == 0) {
-               printf("OK sat\n");
-               data[0] = atoi(input + 3);
-               if(data[0] <= 0 || data[0] > 0x3f) {
-                       data[0] = 0x1f;
-               }
-               i2c_write(0x8a, 0x1c, data, 1);
-               i2c_async(i2c_hold);    /* hold I2C when done */
-
-       } else if(strcmp(input, "rel") == 0) {
-               printf("OK release\n");
-               i2c_release();
-
-       } else if(strcmp(input, "status") == 0) {
-               i2c_read(0x8a, 0, data, 3);
-               i2c_async(printstat);
-
-       } else if(memcmp(input, "rd ", 3) == 0) {
-               dump_addr = strtol(input + 3, &endp, 16);
-
-               if(endp > input + 3 && dump_addr >= 0 && dump_addr < 2048) {
-                       dump_count = 1;
-                       i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 1);
-                       i2c_async(printdump);
-               } else {
-                       printf("ERR address: %s\n", input + 3);
-               }
-
-       } else if(memcmp(input, "dump ", 5) == 0) {
-               dump_addr = strtol(input + 5, &endp, 16);
-
-               if(endp > input + 5 && dump_addr >= 0 && dump_addr < 2048) {
-                       dump_count = 1;
-                       dump_addr &= 0xff0;
-                       i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 16);
-                       i2c_async(printdump);
-               } else {
-                       printf("ERR address: %s\n", input + 5);
-               }
-
-       } else if(strcmp(input, "abort") == 0) {
-               if(i2c_mode != I2C_IDLE) {
-                       i2c_mode = I2C_IDLE;
-                       I2C_STOP();
-                       printf("OK\n");
-               } else {
-                       printf("ERR i2c is idle\n");
-               }
-
-       } else {
-               printf("ERR command (%s)\n", input);
-       }
-}
-
-static void printstat(void)
-{
-       printf("OK status: %02x %02x %02x\n", (unsigned int)data[0],
-                       (unsigned int)data[1], (unsigned int)data[2]);
-}
-
-static void printdump(void)
-{
-       int i;
-       while(dump_count > 0) {
-               printf("OK %03x:", dump_addr);
-               for(i=0; i<16; i++) {
-                       if(i == 8) putchar(' ');
-
-                       if(--dump_count >= 0) {
-                               printf(" %02x", data[i]);
-                       } else {
-                               printf("   ");
-                       }
-                       dump_addr += 16;
-               }
-               putchar('\n');
-       }
-}
-
-void i2c_write(unsigned char addr, unsigned char subaddr, unsigned char *data, int ndata)
-{
-       i2c_addr = addr & 0xfe;
-       i2c_subaddr = subaddr;
-       i2c_mode = I2C_MASTER_WRITE;
-       i2c_ndata = ndata;
-       i2c_data = data;
-       i2c_seq = 0;
-       I2C_START();
-}
-
-void i2c_read(unsigned char addr, unsigned char subaddr, unsigned char *buf, int size)
-{
-       i2c_addr = addr & 0xfe;
-       i2c_subaddr = subaddr;
-       i2c_mode = I2C_MASTER_READ;
-       i2c_ndata = size;
-       i2c_data = buf;
-       i2c_seq = 0;
-       I2C_START();
-}
-
-void i2c_handle_send(void)
-{
-       unsigned char state = TWSR & 0xf8;
-
-       //printf("DBG i2c state (%x)\n", (unsigned int)state);
-       LOGNUM(state);
-
-       switch(state) {
-       case ST_REP_START:      /* 0x10 */
-               /* repeated start, same as start, but also increment i2c_seq */
-               i2c_seq++;
-       case ST_START:  /* 0x8 */
-               /* start initiated, write the slave address */
-               //printf("DBG i2c SLA: %x\n", (unsigned int)i2c_addr);
-               TWDR = i2c_addr;
-               I2C_WRITE();
-               break;
-
-       case ST_SLA_W_ACK:      /* 0x18 */
-               /* slave addr sent and ACKed, send subaddr or data */
-               if(i2c_seq == 0) {
-                       /* this is the first packet, send subaddr */
-                       i2c_seq++;
-                       TWDR = i2c_subaddr;
-                       I2C_WRITE();
-               } else {
-                       if(i2c_ndata--) {
-                               TWDR = *i2c_data++;
-                               I2C_WRITE();
-                       } else {
-                               /* done sending, send stop */
-                               i2c_mode = I2C_IDLE;
-                               I2C_STOP();
-                       }
-               }
-               break;
-
-       case ST_SLA_W_NACK:     /* 0x20 */
-               /* slave addr sent but not ACKed, abort */
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               printf("i2c: NACK after SLA+W\n");
-               break;
-
-       case ST_WR_ACK: /* 0x28 */
-               /* data (or subaddr) sent and ACKed, send more data (or restart) if available */
-#if 0
-               if(i2c_seq == 0) {
-                       /* subaddr was sent, send repeated start */
-                       I2C_START();
-               } else {
-#endif
-                       /* data was sent, send more data or stop */
-                       if(i2c_ndata--) {
-                               TWDR = *i2c_data++;
-                               I2C_WRITE();
-                       } else {
-                               i2c_mode = I2C_IDLE;
-                               I2C_STOP();
-                       }
-//             }
-               break;
-
-       case ST_WR_NACK:        /* 0x30 */
-               /* data (or subaddr) sent but not ACKed */
-               if(i2c_seq == 0) {
-                       /* NACK after subaddr, abort */
-                       printf("i2c: NACK after subaddr\n");
-               } else {
-                       /* NACK after data */
-                       if(i2c_ndata) {
-                               printf("i2c: NACK with %d pending\n", i2c_ndata);
-                       }
-               }
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               break;
-
-       case ST_ARBLOST:        /* 0x38 */
-               /* arbitration lost */
-               printf("i2c: arb lost\n");
-               I2C_START();
-               break;
-
-       case ST_INVALID:        /* 0 */
-               printf("i2c: invalid start/stop\n");
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               break;
-
-       default:
-               printf("i2c: unexpected state (W): 0x%x\n", state);
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-       }
-}
-
-void i2c_handle_recv(void)
-{
-       unsigned char state = TWSR & 0xf8;
-
-       LOGNUM(state);
-
-       switch(state) {
-       case ST_START:          /* 0x8 */
-               TWDR = i2c_addr;        /* start a *write* (we need to send the subaddress before reading) */
-               I2C_WRITE();
-               break;
-
-       case ST_REP_START:      /* 0x10 */
-               /* repeated start, now we can issue the actual read */
-               TWDR = i2c_addr | 1;
-               I2C_WRITE();
-               break;
-
-       case ST_SLA_W_ACK:      /* 0x18 */
-               /* SLA+W means we just started the write part, need to send the subaddress */
-               TWDR = i2c_subaddr;
-               I2C_WRITE();
-               break;
-
-       case ST_SLA_W_NACK:
-               /* slave addr sent but not ACKed, abort */
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               printf("i2c: NACK after SLA+W (R)\n");
-               break;
-
-       case ST_WR_ACK:         /* 0x28 */
-               /* the subaddress write was ACKed, rep-start to issue the read */
-               I2C_START();
-               break;
-
-       case ST_WR_NACK:
-               /* the subaddress write was not ACKed, abort */
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               printf("i2c: NACK after subaddr (R)\n");
-               break;
-
-       case ST_SLA_R_ACK:      /* 0x40 */
-               /* SLA+R was ACKed send ACK to start receiving */
-               I2C_READ_ACK();
-               break;
-
-       case ST_RD_ACK:         /* 0x50 */
-               /* ... or last read was ACKed, again read next and ACK for more */
-               *i2c_data++ = TWDR;
-               if(--i2c_ndata > 0) {
-                       I2C_READ_ACK();
-               } else {
-                       I2C_READ_NACK();
-               }
-               break;
-
-       case ST_SLA_R_NACK:     /* 0x48 */
-               /* SLA+R was sent but ACK was not received, abort */
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               printf("i2c: NACK after SLA+R\n");
-               break;
-
-       case ST_RD_NACK:        /* 0x58 */
-               /* read without ACK, we get this after we send a NACK, or this is the last byte (?) */
-               if(i2c_ndata > 0) {
-                       *i2c_data++ = TWDR;
-                       i2c_ndata--;
-               }
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               break;
-
-       case ST_ARBLOST:        /* 0x38 */
-               /* arbitration lost */
-               printf("i2c: arb lost\n");
-               I2C_START();
-               break;
-
-       case ST_INVALID:        /* 0 */
-               printf("i2c: invalid start/stop\n");
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-               break;
-
-       default:
-               printf("i2c: unexpected state (R): 0x%x\n", state);
-               i2c_mode = I2C_IDLE;
-               I2C_STOP();
-       }
-}
-
-ISR(TWI_vect)
-{
-       switch(i2c_mode) {
-       case I2C_MASTER_WRITE:
-               i2c_handle_send();
-               break;
-
-       case I2C_MASTER_READ:
-               i2c_handle_recv();
-               break;
-       }
-}
-
-void i2c_wait(void)
-{
-       while(i2c_mode);
-}
-
-void i2c_async(void (*donecb)(void))
-{
-       async_func = donecb;
-}
-
-void i2c_check_async(void)
-{
-       if(async_func && i2c_mode == I2C_IDLE) {
-               async_func();
-               async_func = 0;
-       }
-}
-
-void i2c_hold(void)
-{
-       TWCR = 0;               /* make sure the AVR i2c hardware is disabled */
-       DDRC = 0x20;    /* ... and drive SCL pin low */
-       PORTC = 0;
-}
-
-void i2c_release(void)
-{
-       DDRC = 0;
-}
-
-#define PC_SCL 5
-#define PC_SDA 4
-#define PC_SCL_BIT     (1 << PC_SCL)
-#define PC_SDA_BIT     (1 << PC_SDA)
-
-static unsigned char pcprev, state;
-static unsigned char value;
-static int nbits;
-
-/* use PCINT12,13 to snoop i2c traffic */
-void i2c_snoop(int onoff)
-{
-       snooping = onoff;
-
-       if(!onoff) {
-#ifdef USE_PCINT
-               /* to stop snooping just disable the interrupt */
-               cli();
-               PCMSK1 = 0;
-               PCICR &= ~(1 << PCIE1);
-               sei();
-#endif
-               return;
-       }
-
-       TWCR = 0;               /* make sure the i2c hw is disabled */
-       DDRC = 0;
-       PORTC = 0;
-
-#ifdef USE_PCINT
-       cli();
-       PCICR |= 1 << PCIE1;    /* enable the pin-change interrupt */
-       PCMSK1 = (1 << PCINT12) | (1 << PCINT13);
-#endif
-
-       pcprev = PINC;
-       state = 0;
-       value = 0;
-       nbits = 0;
-#ifdef USE_PCINT
-       sei();
-#endif
-}
-
-#ifdef USE_PCINT
-ISR(PCINT1_vect)
-#else
-void snoop(void)
-#endif
-{
-       unsigned char pinc, delta;
-
-       pinc = PINC;
-       delta = pinc ^ pcprev;
-       pcprev = pinc;
-
-       if(delta & PC_SDA_BIT) {
-               if(pinc & PC_SCL_BIT) {
-                       /* clock is high, so this is either a start or a stop */
-                       if(pinc & PC_SDA_BIT) {
-                               EVLOG(EV_STOP, 0);
-                               state = 0;
-                       } else {
-                               EVLOG(EV_START, 0);
-                               state = EV_START;
-                               value = 0;
-                               nbits = 0;
-                       }
-                       return;
-               }
-       }
-
-       if(!state) {
-               uint16_t val, ev;
-               if(evq_wr != evq_rd) {
-                       val = evq[evq_rd];
-                       evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1);
-                       ev = val >> 8;
-                       if(ev <= EV_STOP) {
-                               printf("%s\n", evname[ev]);
-                       } else {
-                               printf("%s: %02x\n", evname[ev], val & 0xff);
-                       }
-               }
-               return;
-       }
-
-       if(delta & PC_SCL_BIT) {
-               if(pinc & PC_SCL_BIT) {
-                       /* clock is going high, shift SDA */
-                       value = (value << 1) | ((pinc >> PC_SDA) & 1);
-                       if(++nbits >= 8) {
-                               switch(state) {
-                               case EV_START:
-                                       state = (value & 1) ? EV_SLA_R : EV_SLA_W;
-                                       EVLOG(state, value & 0xfe);
-                                       break;
-                               case EV_SLA_W:
-                               case EV_SLA_R:
-                                       state = EV_DATA;
-                                       EVLOG(state, value);
-                               case EV_DATA:
-                                       //EVLOG(state, value);
-                               default:
-                                       break;
-                               }
-                               nbits = 0;
-                               value = 0;
-                       }
-               }
-       }
-
-       PORTB ^= 1;
-}
diff --git a/serial.c b/serial.c
deleted file mode 100644 (file)
index 3ca641a..0000000
--- a/serial.c
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef F_CPU
-#ifdef XTAL
-#define F_CPU  XTAL
-#else
-#warning "compiled for 1mhz internal rc osc. serial comms won't work"
-#define F_CPU  1000000
-#endif
-#endif
-
-#include <stdio.h>
-#include <avr/io.h>
-#include <avr/interrupt.h>
-#include <util/delay.h>
-#include <avr/power.h>
-
-static int uart_send_char(char c, FILE *fp);
-static int uart_get_char(FILE *fp);
-
-#define BUF_SZ 16
-#define BUF_IDX_MASK   (BUF_SZ - 1)
-#define NEXT_IDX(x)    (((x) + 1) & BUF_IDX_MASK)
-static char outbuf[BUF_SZ];
-static volatile unsigned char out_rd, out_wr;
-static char inbuf[BUF_SZ];
-static volatile unsigned char in_rd, in_wr;
-
-static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW);
-
-
-
-void init_serial(long baud)
-{
-       unsigned int ubrr_val = F_CPU / 16 / baud - 1;
-
-       power_usart0_enable();
-
-       /* set baud generator timer reset value */
-       UBRR0H = (unsigned char)(ubrr_val >> 8);
-       UBRR0L = (unsigned char)ubrr_val;
-
-       /* enable rx/tx and recv interrupt */
-       UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
-       /* set frame format: 8n1 */
-       UCSR0C = 3 << UCSZ00;
-
-       stdin = stdout = stderr = &std_stream;
-}
-
-int have_input(void)
-{
-       return in_wr != in_rd;
-}
-
-static int uart_send_char(char c, FILE *fp)
-{
-       /*int next;*/
-       if(c == '\n') uart_send_char('\r', fp);
-
-       while((UCSR0A & (1 << UDRE0)) == 0);
-       UDR0 = (unsigned char)c;
-#if 0
-       next = NEXT_IDX(out_wr);
-       while(next == out_rd);
-
-       outbuf[out_wr] = c;
-       out_wr = next;
-
-       /* enable the Tx data register empty interrupt */
-       UCSR0B |= 1 << UDRIE0;
-#endif
-       return 0;
-}
-
-static int uart_get_char(FILE *fp)
-{
-       char c;
-
-       while(in_rd == in_wr);
-
-       c = inbuf[in_rd];
-       in_rd = NEXT_IDX(in_rd);
-       return c;
-}
-
-ISR(USART_RX_vect)
-{
-       char c = UDR0;
-
-       inbuf[in_wr] = c;
-       in_wr = NEXT_IDX(in_wr);
-}
-
-/* USART Tx data register empty (can send more data) */
-ISR(USART_UDRE_vect)
-{
-       if(out_rd != out_wr) {
-               UDR0 = outbuf[out_rd];
-               out_rd = NEXT_IDX(out_rd);
-       } else {
-               /* no more data to send for now, disable the interrupt */
-               UCSR0B &= ~(1 << UDRIE0);
-       }
-}
diff --git a/serial.h b/serial.h
deleted file mode 100644 (file)
index 615626e..0000000
--- a/serial.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef SERIAL_H_
-#define SERIAL_H_
-
-void init_serial(long baud);
-int have_input(void);
-
-#endif /* SERIAL_H_ */
diff --git a/src/i2c.c b/src/i2c.c
new file mode 100644 (file)
index 0000000..c7af41d
--- /dev/null
+++ b/src/i2c.c
@@ -0,0 +1,344 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include "i2c.h"
+
+enum {
+       I2C_IDLE,
+       I2C_MASTER_WRITE,
+       I2C_MASTER_READ
+};
+
+enum {
+       ST_INVALID                      = 0,
+       ST_UNKNOWN                      = 0xf8,
+       ST_START                        = 0x08,
+       ST_REP_START            = 0x10,
+       ST_SLA_W_ACK            = 0x18,
+       ST_SLA_W_NACK           = 0x20,
+       ST_WR_ACK                       = 0x28,
+       ST_WR_NACK                      = 0x30,
+       ST_ARBLOST                      = 0x38,
+       ST_SLA_R_ACK            = 0x40,
+       ST_SLA_R_NACK           = 0x48,
+       ST_RD_ACK                       = 0x50,
+       ST_RD_NACK                      = 0x58,
+       ST_MATCH_W                      = 0x60,
+       ST_ARBLOST_MATCH        = 0x68,
+       ST_GENMATCH                     = 0x70,
+       ST_ARBLOST_GENMATCH = 0x78,
+       ST_SLAVE_RD_ACK         = 0x80,
+       ST_SLAVE_RD_NACK        = 0x88,
+       ST_SLAVE_GENRD_ACK      = 0x90,
+       ST_SLAVE_GENRD_NACK     = 0x98,
+       ST_SLAVE_STARTSTOP      = 0xa0,
+       ST_SLAVE_SLA_WR_ACK     = 0xa8,
+       ST_SLAVE_ARBLOST_WR_ACK = 0xb0,
+       ST_SLAVE_WR_ACK         = 0xb8,
+       ST_SLAVE_WR_NACK        = 0xc0,
+       ST_SLAVE_LAST_WR_ACK = 0xc8
+};
+
+enum {
+       EV_DEBUG,
+       EV_START,
+       EV_STOP,
+       EV_SLA_W,
+       EV_SLA_R,
+       EV_DATA
+};
+
+#define TWINT_BIT      (1 << TWINT)
+#define TWEA_BIT       (1 << TWEA)
+#define TWSTA_BIT      (1 << TWSTA)
+#define TWSTO_BIT      (1 << TWSTO)
+#define TWEN_BIT       (1 << TWEN)
+#define TWIE_BIT       (1 << TWIE)
+
+#define I2C_START()    (TWCR = TWINT_BIT | TWSTA_BIT | TWEN_BIT | TWIE_BIT)
+#define I2C_STOP()     (TWCR = TWINT_BIT | TWSTO_BIT | TWEN_BIT | TWIE_BIT)
+#define I2C_WRITE()    (TWCR = TWINT_BIT | TWEN_BIT | TWIE_BIT)
+#define I2C_READ_ACK() (TWCR = TWINT_BIT | TWEA_BIT | TWEN_BIT | TWIE_BIT)
+#define I2C_READ_NACK()        (TWCR = TWINT_BIT | TWEN_BIT | TWIE_BIT)
+
+static unsigned char i2c_addr, i2c_subaddr;
+static volatile unsigned char i2c_mode;
+static int i2c_seq, i2c_ndata;
+static unsigned char *i2c_data;
+
+static void (*async_func)(void);
+
+void i2c_init(void)
+{
+       TWBR = 10;              /* 10 with 1x prescaler should make it about 100khz */
+       TWSR = 0;               /* prescaler 1x */
+       TWAR = 0;
+       TWAMR = 0;
+       TWCR = 0;               /* I2C disabled by default */
+
+       i2c_mode = I2C_IDLE;
+}
+
+
+void i2c_write(unsigned char addr, unsigned char subaddr, unsigned char *data, int ndata)
+{
+       i2c_addr = addr & 0xfe;
+       i2c_subaddr = subaddr;
+       i2c_mode = I2C_MASTER_WRITE;
+       i2c_ndata = ndata;
+       i2c_data = data;
+       i2c_seq = 0;
+       I2C_START();
+}
+
+void i2c_read(unsigned char addr, unsigned char subaddr, unsigned char *buf, int size)
+{
+       i2c_addr = addr & 0xfe;
+       i2c_subaddr = subaddr;
+       i2c_mode = I2C_MASTER_READ;
+       i2c_ndata = size;
+       i2c_data = buf;
+       i2c_seq = 0;
+       I2C_START();
+}
+
+void i2c_handle_send(void)
+{
+       unsigned char state = TWSR & 0xf8;
+
+       /*LOGNUM(state);*/
+
+       switch(state) {
+       case ST_REP_START:      /* 0x10 */
+               /* repeated start, same as start, but also increment i2c_seq */
+               i2c_seq++;
+       case ST_START:  /* 0x8 */
+               /* start initiated, write the slave address */
+               //printf("DBG i2c SLA: %x\n", (unsigned int)i2c_addr);
+               TWDR = i2c_addr;
+               I2C_WRITE();
+               break;
+
+       case ST_SLA_W_ACK:      /* 0x18 */
+               /* slave addr sent and ACKed, send subaddr or data */
+               if(i2c_seq == 0) {
+                       /* this is the first packet, send subaddr */
+                       i2c_seq++;
+                       TWDR = i2c_subaddr;
+                       I2C_WRITE();
+               } else {
+                       if(i2c_ndata--) {
+                               TWDR = *i2c_data++;
+                               I2C_WRITE();
+                       } else {
+                               /* done sending, send stop */
+                               i2c_mode = I2C_IDLE;
+                               I2C_STOP();
+                       }
+               }
+               break;
+
+       case ST_SLA_W_NACK:     /* 0x20 */
+               /* slave addr sent but not ACKed, abort */
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               printf("i2c: NACK after SLA+W\n");
+               break;
+
+       case ST_WR_ACK: /* 0x28 */
+               /* data (or subaddr) sent and ACKed, send more data (or restart) if available */
+#if 0
+               if(i2c_seq == 0) {
+                       /* subaddr was sent, send repeated start */
+                       I2C_START();
+               } else {
+#endif
+                       /* data was sent, send more data or stop */
+                       if(i2c_ndata--) {
+                               TWDR = *i2c_data++;
+                               I2C_WRITE();
+                       } else {
+                               i2c_mode = I2C_IDLE;
+                               I2C_STOP();
+                       }
+//             }
+               break;
+
+       case ST_WR_NACK:        /* 0x30 */
+               /* data (or subaddr) sent but not ACKed */
+               if(i2c_seq == 0) {
+                       /* NACK after subaddr, abort */
+                       printf("i2c: NACK after subaddr\n");
+               } else {
+                       /* NACK after data */
+                       if(i2c_ndata) {
+                               printf("i2c: NACK with %d pending\n", i2c_ndata);
+                       }
+               }
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               break;
+
+       case ST_ARBLOST:        /* 0x38 */
+               /* arbitration lost */
+               printf("i2c: arb lost\n");
+               I2C_START();
+               break;
+
+       case ST_INVALID:        /* 0 */
+               printf("i2c: invalid start/stop\n");
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               break;
+
+       default:
+               printf("i2c: unexpected state (W): 0x%x\n", state);
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+       }
+}
+
+void i2c_handle_recv(void)
+{
+       unsigned char state = TWSR & 0xf8;
+
+       /*LOGNUM(state);*/
+
+       switch(state) {
+       case ST_START:          /* 0x8 */
+               TWDR = i2c_addr;        /* start a *write* (we need to send the subaddress before reading) */
+               I2C_WRITE();
+               break;
+
+       case ST_REP_START:      /* 0x10 */
+               /* repeated start, now we can issue the actual read */
+               TWDR = i2c_addr | 1;
+               I2C_WRITE();
+               break;
+
+       case ST_SLA_W_ACK:      /* 0x18 */
+               /* SLA+W means we just started the write part, need to send the subaddress */
+               TWDR = i2c_subaddr;
+               I2C_WRITE();
+               break;
+
+       case ST_SLA_W_NACK:
+               /* slave addr sent but not ACKed, abort */
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               printf("i2c: NACK after SLA+W (R)\n");
+               break;
+
+       case ST_WR_ACK:         /* 0x28 */
+               /* the subaddress write was ACKed, rep-start to issue the read */
+               I2C_START();
+               break;
+
+       case ST_WR_NACK:
+               /* the subaddress write was not ACKed, abort */
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               printf("i2c: NACK after subaddr (R)\n");
+               break;
+
+       case ST_SLA_R_ACK:      /* 0x40 */
+               /* SLA+R was ACKed send ACK to start receiving */
+               I2C_READ_ACK();
+               break;
+
+       case ST_RD_ACK:         /* 0x50 */
+               /* ... or last read was ACKed, again read next and ACK for more */
+               *i2c_data++ = TWDR;
+               if(--i2c_ndata > 0) {
+                       I2C_READ_ACK();
+               } else {
+                       I2C_READ_NACK();
+               }
+               break;
+
+       case ST_SLA_R_NACK:     /* 0x48 */
+               /* SLA+R was sent but ACK was not received, abort */
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               printf("i2c: NACK after SLA+R\n");
+               break;
+
+       case ST_RD_NACK:        /* 0x58 */
+               /* read without ACK, we get this after we send a NACK, or this is the last byte (?) */
+               if(i2c_ndata > 0) {
+                       *i2c_data++ = TWDR;
+                       i2c_ndata--;
+               }
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               break;
+
+       case ST_ARBLOST:        /* 0x38 */
+               /* arbitration lost */
+               printf("i2c: arb lost\n");
+               I2C_START();
+               break;
+
+       case ST_INVALID:        /* 0 */
+               printf("i2c: invalid start/stop\n");
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+               break;
+
+       default:
+               printf("i2c: unexpected state (R): 0x%x\n", state);
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+       }
+}
+
+ISR(TWI_vect)
+{
+       switch(i2c_mode) {
+       case I2C_MASTER_WRITE:
+               i2c_handle_send();
+               break;
+
+       case I2C_MASTER_READ:
+               i2c_handle_recv();
+               break;
+       }
+}
+
+void i2c_wait(void)
+{
+       while(i2c_mode);
+}
+
+void i2c_async(void (*donecb)(void))
+{
+       async_func = donecb;
+}
+
+void i2c_check_async(void)
+{
+       if(async_func && i2c_mode == I2C_IDLE) {
+               async_func();
+               async_func = 0;
+       }
+}
+
+void i2c_hold(void)
+{
+       TWCR = 0;               /* make sure the AVR i2c hardware is disabled */
+       DDRC = 0x20;    /* ... and drive SCL pin low */
+       PORTC = 0;
+}
+
+void i2c_release(void)
+{
+       DDRC = 0;
+}
+
+void i2c_abort(void)
+{
+       if(i2c_mode != I2C_IDLE) {
+               i2c_mode = I2C_IDLE;
+               I2C_STOP();
+       }
+}
diff --git a/src/i2c.h b/src/i2c.h
new file mode 100644 (file)
index 0000000..e26e43d
--- /dev/null
+++ b/src/i2c.h
@@ -0,0 +1,15 @@
+#ifndef I2C_H_
+#define I2C_H_
+
+void i2c_init(void);
+void i2c_write(unsigned char addr, unsigned char subaddr, unsigned char *data, int ndata);
+void i2c_read(unsigned char addr, unsigned char subaddr, unsigned char *buf, int size);
+void i2c_wait(void);
+void i2c_async(void (*donecb)(void));
+void i2c_check_async(void);
+void i2c_hold(void);
+void i2c_release(void);
+void i2c_abort(void);
+
+
+#endif /* I2C_H_ */
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..2584292
--- /dev/null
@@ -0,0 +1,215 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include "serial.h"
+#include "i2c.h"
+
+/* TODO
+ * IR decoding, connected to PCINT0
+ * enable/disable with switch on PCINT1
+ * some of the buttons multiplexed on ADC0
+ */
+
+#define EVQ_SIZE       64
+uint16_t evq[EVQ_SIZE];
+volatile int evq_wr, evq_rd;
+
+#define LOGNUM(x)      EVLOG(EV_DEBUG, (x))
+
+#define EVLOG(ev, data)        \
+       do { \
+               if(ev != EV_DEBUG || dbgmode) { \
+                       evq[evq_wr] = ((uint16_t)(ev) << 8) | (data); \
+                       evq_wr = (evq_wr + 1) & (EVQ_SIZE - 1); \
+                       if(evq_wr == evq_rd) { \
+                               evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1); \
+                       } \
+               } \
+       } while(0)
+
+/* serial input buffer */
+static char input[64];
+static unsigned char inp_cidx;
+
+static unsigned char data[16];
+
+static uint16_t dump_addr;
+static int dump_count;
+static int dbgmode;
+
+static void proc_cmd(char *input);
+static void printstat(void);
+static void printdump(void);
+
+
+int main(void)
+{
+       uint16_t val;
+
+       /* tri-state everything and disable pullups */
+       DDRB = 1;       /* B0: activity LED */
+       DDRC = 0;       /* I2C pins as inputs */
+       DDRD = 0;
+       PORTB = 0;
+       PORTC = 0;
+       PORTD = 0;
+
+       i2c_init();
+
+       init_serial(38400);
+       sei();
+
+       printf("TV i2c hack\n");
+
+       for(;;) {
+               i2c_check_async();
+
+               if(have_input()) {
+                       int c = getchar();
+                       putchar(c);
+
+                       if(c == '\r' || c == '\n') {
+                               putchar('\n');
+                               input[inp_cidx] = 0;
+                               proc_cmd(input);
+                               inp_cidx = 0;
+                       } else if(inp_cidx < sizeof input - 1) {
+                               input[inp_cidx++] = c;
+                       }
+               }
+
+               /* read from queue and send over the serial port */
+               val = 0xffff;
+               cli();
+               if(evq_wr != evq_rd) {
+                       val = evq[evq_rd];
+                       evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1);
+               }
+               sei();
+
+               if(val != 0xffff) {
+                       unsigned char ev = val >> 8;
+                       printf("%02x: %02x\n", ev, val & 0xff);
+               }
+       }
+       return 0;
+}
+
+static void proc_cmd(char *input)
+{
+       char *endp;
+
+       if(strcmp(input, "dbg") == 0) {
+               printf("OK dbg\n");
+               dbgmode = 1;
+
+       } else if(strcmp(input, "nodbg") == 0) {
+               printf("OK nodbg\n");
+               dbgmode = 0;
+
+       } else if(strcmp(input, "av") == 0) {
+               printf("OK AV\n");
+
+               /* AV switch (22): 0 0 SVO CMB1 CMB0 INA INB 0 */
+               data[0] = 0x22;
+               i2c_write(0x8a, 0x22, data, 1);
+               i2c_async(i2c_hold);
+
+       } else if(strcmp(input, "rgb") == 0) {
+               printf("OK RGB\n");
+
+               /* Control 0 (2a): 0 IE2 RBL AKB  CL3 CL2 CL1 CL0
+                * Control 1 (2b): 0  0   0   0    0   0  YUV HBL
+                */
+               data[0] = 0x70;
+               data[1] = 0;
+               i2c_write(0x8a, 0x2a, data, 1);
+               i2c_wait();
+               i2c_write(0x8a, 0x2b, data + 1, 1);
+
+       } else if(memcmp(input, "vol ", 4) == 0) {
+               int vol = atoi(input + 4);
+               if(vol < 1 || vol > 63) {
+                       printf("ERR vol (%s)\n", input + 4);
+               } else {
+                       data[0] = vol;
+                       i2c_write(0x8a, 0x1f, data, 1);
+                       printf("OK volume: %d\n", vol);
+               }
+
+       } else if(memcmp(input, "sat", 3) == 0) {
+               printf("OK sat\n");
+               data[0] = atoi(input + 3);
+               if(data[0] <= 0 || data[0] > 0x3f) {
+                       data[0] = 0x1f;
+               }
+               i2c_write(0x8a, 0x1c, data, 1);
+               i2c_async(i2c_hold);    /* hold I2C when done */
+
+       } else if(strcmp(input, "rel") == 0) {
+               printf("OK release\n");
+               i2c_release();
+
+       } else if(strcmp(input, "status") == 0) {
+               i2c_read(0x8a, 0, data, 3);
+               i2c_async(printstat);
+
+       } else if(memcmp(input, "rd ", 3) == 0) {
+               dump_addr = strtol(input + 3, &endp, 16);
+
+               if(endp > input + 3 && dump_addr >= 0 && dump_addr < 2048) {
+                       dump_count = 1;
+                       i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 1);
+                       i2c_async(printdump);
+               } else {
+                       printf("ERR address: %s\n", input + 3);
+               }
+
+       } else if(memcmp(input, "dump ", 5) == 0) {
+               dump_addr = strtol(input + 5, &endp, 16);
+
+               if(endp > input + 5 && dump_addr >= 0 && dump_addr < 2048) {
+                       dump_count = 1;
+                       dump_addr &= 0xff0;
+                       i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 16);
+                       i2c_async(printdump);
+               } else {
+                       printf("ERR address: %s\n", input + 5);
+               }
+
+       } else if(strcmp(input, "abort") == 0) {
+               i2c_abort();
+               printf("OK\n");
+
+       } else {
+               printf("ERR command (%s)\n", input);
+       }
+}
+
+static void printstat(void)
+{
+       printf("OK status: %02x %02x %02x\n", (unsigned int)data[0],
+                       (unsigned int)data[1], (unsigned int)data[2]);
+}
+
+static void printdump(void)
+{
+       int i;
+       while(dump_count > 0) {
+               printf("OK %03x:", dump_addr);
+               for(i=0; i<16; i++) {
+                       if(i == 8) putchar(' ');
+
+                       if(--dump_count >= 0) {
+                               printf(" %02x", data[i]);
+                       } else {
+                               printf("   ");
+                       }
+                       dump_addr += 16;
+               }
+               putchar('\n');
+       }
+}
diff --git a/src/serial.c b/src/serial.c
new file mode 100644 (file)
index 0000000..3ca641a
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef F_CPU
+#ifdef XTAL
+#define F_CPU  XTAL
+#else
+#warning "compiled for 1mhz internal rc osc. serial comms won't work"
+#define F_CPU  1000000
+#endif
+#endif
+
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include <avr/power.h>
+
+static int uart_send_char(char c, FILE *fp);
+static int uart_get_char(FILE *fp);
+
+#define BUF_SZ 16
+#define BUF_IDX_MASK   (BUF_SZ - 1)
+#define NEXT_IDX(x)    (((x) + 1) & BUF_IDX_MASK)
+static char outbuf[BUF_SZ];
+static volatile unsigned char out_rd, out_wr;
+static char inbuf[BUF_SZ];
+static volatile unsigned char in_rd, in_wr;
+
+static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW);
+
+
+
+void init_serial(long baud)
+{
+       unsigned int ubrr_val = F_CPU / 16 / baud - 1;
+
+       power_usart0_enable();
+
+       /* set baud generator timer reset value */
+       UBRR0H = (unsigned char)(ubrr_val >> 8);
+       UBRR0L = (unsigned char)ubrr_val;
+
+       /* enable rx/tx and recv interrupt */
+       UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
+       /* set frame format: 8n1 */
+       UCSR0C = 3 << UCSZ00;
+
+       stdin = stdout = stderr = &std_stream;
+}
+
+int have_input(void)
+{
+       return in_wr != in_rd;
+}
+
+static int uart_send_char(char c, FILE *fp)
+{
+       /*int next;*/
+       if(c == '\n') uart_send_char('\r', fp);
+
+       while((UCSR0A & (1 << UDRE0)) == 0);
+       UDR0 = (unsigned char)c;
+#if 0
+       next = NEXT_IDX(out_wr);
+       while(next == out_rd);
+
+       outbuf[out_wr] = c;
+       out_wr = next;
+
+       /* enable the Tx data register empty interrupt */
+       UCSR0B |= 1 << UDRIE0;
+#endif
+       return 0;
+}
+
+static int uart_get_char(FILE *fp)
+{
+       char c;
+
+       while(in_rd == in_wr);
+
+       c = inbuf[in_rd];
+       in_rd = NEXT_IDX(in_rd);
+       return c;
+}
+
+ISR(USART_RX_vect)
+{
+       char c = UDR0;
+
+       inbuf[in_wr] = c;
+       in_wr = NEXT_IDX(in_wr);
+}
+
+/* USART Tx data register empty (can send more data) */
+ISR(USART_UDRE_vect)
+{
+       if(out_rd != out_wr) {
+               UDR0 = outbuf[out_rd];
+               out_rd = NEXT_IDX(out_rd);
+       } else {
+               /* no more data to send for now, disable the interrupt */
+               UCSR0B &= ~(1 << UDRIE0);
+       }
+}
diff --git a/src/serial.h b/src/serial.h
new file mode 100644 (file)
index 0000000..615626e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef SERIAL_H_
+#define SERIAL_H_
+
+void init_serial(long baud);
+int have_input(void);
+
+#endif /* SERIAL_H_ */