5 #include <avr/interrupt.h>
6 #include <util/delay.h>
11 * IR decoding, connected to PD2
12 * enable/disable with switch on PCINT1
13 * some of the buttons multiplexed on ADC0
19 uint16_t evq[EVQ_SIZE];
20 volatile int evq_wr, evq_rd;
22 #define LOGNUM(x) EVLOG(EV_DEBUG, (x))
24 #define EVLOG(ev, data) \
26 if(ev != EV_DEBUG || dbgmode) { \
27 evq[evq_wr] = ((uint16_t)(ev) << 8) | (data); \
28 evq_wr = (evq_wr + 1) & (EVQ_SIZE - 1); \
29 if(evq_wr == evq_rd) { \
30 evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1); \
35 /* serial input buffer */
36 static char input[64];
37 static unsigned char inp_cidx;
39 static unsigned char data[16];
41 static uint16_t dump_addr;
42 static int dump_count;
45 static volatile unsigned char pending;
46 static volatile unsigned char enable, prev_enable;
47 static volatile uint16_t ir_input;
49 static void proc_cmd(char *input);
50 static void printstat(void);
51 static void printdump(void);
58 /* tri-state everything and disable pullups */
59 DDRB = 1; /* B0: activity LED */
60 DDRC = 0; /* I2C pins as inputs */
66 /* setup external interrupts */
67 EICRA = 0x6; /* INT0 falling edge, INT1 both */
68 EIMSK = 3; /* enable INT0 and INT1 */
70 /* we'll use the timer 0 compare interrupt for sampling the IR input pulses
71 * we need to sample every 889us or 1124.86 Hz
72 * interrupt frequency = F_CPU / (prescaler * (1 - OCRnx))
73 * 14745600 / (64.0 * (1.0 + 204)) -> 1123.9 Hz
75 TCCR0A = 2; /* clear on compare match */
76 TCCR0B = 3; /* clock select: ioclock / 64 <- prescaler */
77 OCR0A = 192; /* count top */
79 /* read initial enable switch state */
80 enable = (~PIND >> PD_ENSW) & 1;
87 printf("TV i2c hack\n");
97 printf("IR: %04x (%s)\n", (unsigned int)ir_input & 0x7fff, ir_input & 0x8000 ? "err" : "ok");
99 if(pend & 2 && enable != prev_enable) {
100 printf("enable: %d\n", enable);
101 prev_enable = enable;
108 if(c == '\r' || c == '\n') {
113 } else if(inp_cidx < sizeof input - 1) {
114 input[inp_cidx++] = c;
118 /* read from queue and send over the serial port */
123 if(evq_wr != evq_rd) {
125 evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1);
130 unsigned char ev = val >> 8;
131 printf("%02x: %02x\n", ev, val & 0xff);
138 static void proc_cmd(char *input)
142 if(strcmp(input, "dbg") == 0) {
146 } else if(strcmp(input, "nodbg") == 0) {
147 printf("OK nodbg\n");
150 } else if(strcmp(input, "av") == 0) {
153 /* AV switch (22): 0 0 SVO CMB1 CMB0 INA INB 0 */
155 i2c_write(0x8a, 0x22, data, 1);
158 } else if(strcmp(input, "rgb") == 0) {
161 /* Control 0 (2a): 0 IE2 RBL AKB CL3 CL2 CL1 CL0
162 * Control 1 (2b): 0 0 0 0 0 0 YUV HBL
166 i2c_write(0x8a, 0x2a, data, 1);
168 i2c_write(0x8a, 0x2b, data + 1, 1);
170 } else if(memcmp(input, "vol ", 4) == 0) {
171 int vol = atoi(input + 4);
172 if(vol < 1 || vol > 63) {
173 printf("ERR vol (%s)\n", input + 4);
176 i2c_write(0x8a, 0x1f, data, 1);
177 printf("OK volume: %d\n", vol);
180 } else if(memcmp(input, "sat", 3) == 0) {
182 data[0] = atoi(input + 3);
183 if(data[0] <= 0 || data[0] > 0x3f) {
186 i2c_write(0x8a, 0x1c, data, 1);
187 i2c_async(i2c_hold); /* hold I2C when done */
189 } else if(strcmp(input, "rel") == 0) {
190 printf("OK release\n");
193 } else if(strcmp(input, "status") == 0) {
194 i2c_read(0x8a, 0, data, 3);
195 i2c_async(printstat);
197 } else if(memcmp(input, "rd ", 3) == 0) {
198 dump_addr = strtol(input + 3, &endp, 16);
200 if(endp > input + 3 && dump_addr >= 0 && dump_addr < 2048) {
202 i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 1);
203 i2c_async(printdump);
205 printf("ERR address: %s\n", input + 3);
208 } else if(memcmp(input, "dump ", 5) == 0) {
209 dump_addr = strtol(input + 5, &endp, 16);
211 if(endp > input + 5 && dump_addr >= 0 && dump_addr < 2048) {
214 i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 16);
215 i2c_async(printdump);
217 printf("ERR address: %s\n", input + 5);
220 } else if(strcmp(input, "abort") == 0) {
225 printf("ERR command (%s)\n", input);
229 static void printstat(void)
231 printf("OK status: %02x %02x %02x\n", (unsigned int)data[0],
232 (unsigned int)data[1], (unsigned int)data[2]);
235 static void printdump(void)
238 while(dump_count > 0) {
239 printf("OK %03x:", dump_addr);
240 for(i=0; i<16; i++) {
241 if(i == 8) putchar(' ');
243 if(--dump_count >= 0) {
244 printf(" %02x", data[i]);
254 static unsigned char nsamples;
255 static uint32_t samples;
259 /* ignore interrupts while a previous input is pending */
260 if(pending & 1) return;
264 nsamples = 1; /* we're starting in the middle of the first bit which should be 01 (=1) */
266 EIMSK &= 0xfe; /* disable further interrupts while decoding IR code */
268 TCNT0 = 96; /* reset the counter to half the range so it'll trigger in the middle of the current pulse */
269 TIFR0 |= 1 << OCF0A; /* clear pending interrupts */
270 TIMSK0 = 1 << OCIE0A; /* enable output compare interrupt */
275 ISR(TIMER0_COMPA_vect)
277 static unsigned char err;
281 samples = (samples << 1) | (~(PIND >> PD_IR) & 1);
282 if((++nsamples & 1) == 0) {
283 if((samples & 3) == 0 || (samples & 3) == 3) {
284 /* 00 or 11 are invalid sequences, we lost sync */
289 ir_input = (ir_input << 1) | (samples & 1);
298 TIMSK0 &= ~(1 << OCIE0A); /* disable the sampling interrupt */
299 EIMSK |= 1; /* re-enable the edge-detect interrupt for the next input */
305 enable = (~PIND >> PD_ENSW) & 1;