#include "project.h" #define TWO_BYTES_PER_FRAME #undef SEND_EXAMPLE_DATA /* * VGA 640x480x4 mode timings are * * 48 640 16 96 * 10 480 33 2 * * at 25.175 MHz * * That gives horizontal sync of 25.175MHz/800 = 31.46875 kHz * */ /* * Two bytes are shown per video frame with RS232 8,n,1 framing * using the following scanlines * * 078 start * 093 +15 0 * 108 +15 1 * 124 +16 2 * 139 +15 3 * 155 +16 4 * 170 +15 5 * 186 +16 6 * 201 +15 7 * (216 +15) stop * * 263 +62 (+47) start * 279 +16 0 * 294 +15 1 * 310 +16 2 * 325 +15 3 * 340 +15 4 * 356 +16 5 * 371 +15 6 * 387 +16 7 * (402 +15) stop * * (25175000 / 800) *(8 / (201-78)) = 2046.75 * * That's supiciously close to 2048 baud * */ #define SL_BIT_0_0 78 #define SL_BIT_0_1 93 #define SL_BIT_0_2 108 #define SL_BIT_0_3 124 #define SL_BIT_0_4 139 #define SL_BIT_0_5 155 #define SL_BIT_0_6 170 #define SL_BIT_0_7 186 #define SL_BIT_0_8 201 #define SL_BIT_0_9 216 #define SL_BIT_1_0 263 #define SL_BIT_1_1 279 #define SL_BIT_1_2 294 #define SL_BIT_1_3 310 #define SL_BIT_1_4 325 #define SL_BIT_1_5 340 #define SL_BIT_1_6 356 #define SL_BIT_1_7 371 #define SL_BIT_1_8 387 #define SL_BIT_1_9 402 #define SL_ON(byte,bit) (SL_BIT_ ## byte ## _ ## bit) #define SL_OFF(byte,bit) (SL_ON(byte,bit) + 1) #define SL_PREPARE(byte) (SL_ON(byte,0) - 2) #define SEND_BIT(byte,bit,data) \ case SL_ON(byte,bit): \ timex_led((data) & 1); \ break; \ case SL_OFF(byte,bit): \ timex_led(1); \ break #define SEND_BIT_SHIFT(byte,bit,data) \ case SL_ON(byte,bit): \ timex_led((data) & 1); \ data>>=1; \ break; \ case SL_OFF(byte,bit): \ timex_led(1); \ break #define SEND_BYTE(byte, start, data) \ SEND_BIT(byte,0,start); \ SEND_BIT_SHIFT(byte,1,data); \ SEND_BIT_SHIFT(byte,2,data); \ SEND_BIT_SHIFT(byte,3,data); \ SEND_BIT_SHIFT(byte,4,data); \ SEND_BIT_SHIFT(byte,5,data); \ SEND_BIT_SHIFT(byte,6,data); \ SEND_BIT_SHIFT(byte,7,data); \ SEND_BIT_SHIFT(byte,8,data) /* * We ignore the horizontal front/back/sync and drive the system timer at * the horizontal sync frequency of 31.46875kHz or as close as we can manage */ #define BUFFER_SIZE 2048 #define TIMEX_INPUT1_BANK GPIOB #define TIMEX_INPUT1_GPIO GPIO7 #define TIMEX_OUTPUT1_BANK GPIOB #define TIMEX_OUTPUT1_GPIO GPIO6 #define TIMEX_INPUT2_BANK GPIOB #define TIMEX_INPUT2_GPIO GPIO9 #define TIMEX_OUTPUT2_BANK GPIOB #define TIMEX_OUTPUT2_GPIO GPIO8 ring_t timex_ring; static uint8_t timex_ring_buf[BUFFER_SIZE]; static inline void timex_led (int v) { if (v) { gpio_set (TIMEX_OUTPUT1_BANK, TIMEX_OUTPUT1_GPIO); gpio_set (TIMEX_OUTPUT2_BANK, TIMEX_OUTPUT2_GPIO); } else { gpio_clear (TIMEX_OUTPUT1_BANK, TIMEX_OUTPUT1_GPIO); gpio_clear (TIMEX_OUTPUT2_BANK, TIMEX_OUTPUT2_GPIO); } } #define SYNCS 200 typedef enum { STATE_MAGIC0, STATE_MAGIC1, STATE_MAGIC2, STATE_MAGIC3, STATE_MAGIC4, STATE_IDLE, STATE_SYNC1, STATE_SYNC2, STATE_PACKET_HEADER, STATE_PACKET_DATA, STATE_PACKET_TWO_BYTES_PER_FRAME, STATE_PACKET_RECOVERY, } Timex_state; static const uint8_t magic[5] = "Timex"; static int get_data (uint8_t *start, uint8_t *data) { static Timex_state state = STATE_MAGIC0; static unsigned len; static unsigned pad; *start = 0; switch (state) { case STATE_MAGIC0: case STATE_MAGIC1: case STATE_MAGIC2: case STATE_MAGIC3: case STATE_MAGIC4: if (ring_read_byte (&timex_ring, data)) { state = STATE_MAGIC0; return 1; } if (*data != magic [state - STATE_MAGIC0]) { state = STATE_MAGIC0; return 1; } state++; break; case STATE_IDLE: if (ring_empty (&timex_ring)) { state = STATE_MAGIC0; return 1; } state = STATE_SYNC1; len = SYNCS; break; case STATE_SYNC1: *data = 0x55; len--; if (!len) { len = 20; state = STATE_SYNC2; } break; case STATE_SYNC2: *data = 0xaa; len--; if (!len) state = STATE_PACKET_HEADER; break; case STATE_PACKET_HEADER: if (ring_read_byte (&timex_ring, data)) { /*No more data*/ state = STATE_MAGIC0; return 1; } len = *data - 1 ; state = STATE_PACKET_DATA; #ifdef TWO_BYTES_PER_FRAME pad = !! (*data & 1); #else pad = 0; #endif break; case STATE_PACKET_DATA: ring_read_byte (&timex_ring, data); len--; if (!len) { #ifdef TWO_BYTES_PER_FRAME len = 20; #else len = 10; #endif if (pad) state = STATE_PACKET_TWO_BYTES_PER_FRAME; else state = STATE_PACKET_RECOVERY; } break; case STATE_PACKET_TWO_BYTES_PER_FRAME: *data = 0x00; state = STATE_PACKET_RECOVERY; break; case STATE_PACKET_RECOVERY: *start = 1; *data = 0xff; len--; if (!len) state = STATE_PACKET_HEADER; break; } return 0; } void timex_tick (void) { static unsigned line = 0; static uint8_t data, start; switch (line) { case SL_PREPARE (0): if (get_data (&start, &data)) { line = 0; return; } break; SEND_BYTE (0, start, data); #ifdef TWO_BYTES_PER_FRAME case SL_PREPARE (1): if (get_data (&start, &data)) { line = 0; return; } break; SEND_BYTE (1, start, data); #endif } line++; if (line == 525) line = 0; } #ifdef SEND_EXAMPLE_DATA #if 0 uint8_t ex[] = { 0x07, 0x20, 0x00, 0x00, 0x01, 0xc0, 0x7f, // 0x00 // START 0x0d, 0x30, 0x02, 0x13, 0x11, 0x04, 0x1d, 0x13, 0x00, 0x2c, 0x01, 0x29, 0x56, // 0x00, //TIME ZONE 2 0x0d, 0x30, 0x01, 0x0b, 0x11, 0x04, 0x1d, 0x13, 0x00, 0x2c, 0x01, 0x73, 0x42, // 0x00, //TIME ZONE 1 0x05, 0x60, 0x03, 0x00, 0x78, // 0x00, // DATA START 0x20, 0x61, 0x01, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x26, 0x00, 0x39, 0x01, 0x01, 0x01, 0x01, 0x13, /**/ 0x03, 0x0d, 0x05, 0x05, 0x28, 0x9c, 0x62, 0x65, 0x95, 0x43, 0x2a, 0x59, 0xd6, 0xfd, 0x38, 0xc2, // DATA HEADER + DATA 0x20, 0x61, 0x02, 0x0b, 0x01, 0x9c, 0x62, 0x65, 0x95, 0x43, 0x76, 0x0a, 0x47, 0xfd, 0x13, 0x04, /**/ 0x54, 0x55, 0x55, 0x55, 0xcf, 0x8b, 0xb7, 0x35, 0x4e, 0x55, 0x91, 0x90, 0x83, 0x6d, 0xb6, 0x6a, //DATA 0x17, 0x61, 0x03, 0x90, 0xf3, 0x03, 0x0f, 0x05, 0x01, 0x9c, 0x62, 0x65, 0x95, 0x43, 0x2e, 0xd2, /**/ 0xd6, 0x45, 0x8d, 0x22, 0xfe, 0xd4, 0x6e, // 0x00, //DATA 0x04, 0x62, 0x29, 0x83, 0x08, 0x31, 0x01, 0x15, 0x18, 0x17, 0xba, 0x26, 0x08, 0x31, 0x02, 0x11, 0x17, 0x10, 0x0d, 0x23, 0x12, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x0a, 0x16, 0x19, 0x15, 0x0e, 0x24, 0x24, 0x01, /**/ 0x0e, 0x39, // ALARM 1 0x12, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x1b, 0x16, 0x24, 0x27, 0x02, 0x00, /**/ 0x73, 0x3b, // ALARM 2 0x07, 0x70, 0x00, 0x63, 0x00, 0xf0, 0x87, // 0x00, // SILENCE ALARM 2 0x12, 0x50, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x1b, 0x16, 0x24, 0x27, 0x03, 0x00, /**/ 0x22, 0x3a, // ALARM 3 0x07, 0x70, 0x00, 0x64, 0x00, 0xc0, 0x85, // 0x00, // SILENCE ALARM 3 0x12, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x1b, 0x16, 0x24, 0x27, 0x04, 0x00, /**/ 0xd5, 0x3e, // ALARM 4 0x07, 0x70, 0x00, 0x65, 0x00, 0x50, 0x84, // 0x00, // SILENCE ALARM 4 0x12, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x1b, 0x16, 0x24, 0x27, 0x05, 0x00, /**/ 0x84, 0x3f, // ALARM 5 0x07, 0x70, 0x00, 0x66, 0x00, 0xa0, 0x84, // 0x00, // SILENCE ALARM 5 0x04, 0x21, 0xd8, 0xc2, // END }; #endif #if 0 // Immediate reboot uint8_t ex[] = { 0x07, 0x20, 0x00, 0x00, 0x03, 0x01, 0xfe, /* 0x00, */ 0x09, 0x23, 0x04, 0x3e, 0x18, 0x94, 0x81, 0xdc, 0x4c }; #endif #if 1 // hello app uint8_t ex[] = { 0x07, 0x20, 0x00, 0x00, 0x03, 0x01, 0xfe, /* 0x00, */ 0x05, 0x93, 0x02, 0x30, 0xfd, /* 0x00, */ 0x07, 0x90, 0x02, 0x04, 0x01, 0x00, 0xfa, /* 0x00, */ 0x26, 0x91, 0x02, 0x01, 0xcc, 0x01, 0x6a, 0x81, 0x9d, 0x9d, 0x81, 0x9d, 0x9d, 0x81, 0x9d, /**/ 0x9d, 0x81, 0x9d, 0x9d, 0xd6, 0x01, 0x33, 0x81, 0xcc, 0x01, 0x41, 0x00, 0x11, 0x0e, 0x13, 0x13, /**/ 0x00, 0x1d, 0x1a, 0x00, 0x17, 0x14, 0x21, 0x26, 0x91, 0x02, 0x02, 0x13, 0x0d, 0x1d, 0x00, 0x1b, 0xff, 0x00, 0x1a, 0xff, 0x00, 0x80, /**/ 0xff, 0x00, 0x01, 0xff, 0xff, 0x1d, 0x12, 0x8f, 0xb6, 0x91, 0xa1, 0x80, 0x27, 0x1a, 0x11, 0x61, /**/ 0x01, 0x61, 0x03, 0xcc, 0x57, 0xe1, 0x07, 0x26, 0x91, 0x02, 0x03, 0x76, 0xcd, 0x57, 0x7a, 0xa6, 0x17, 0xcd, 0x58, 0x7e, 0xa6, 0x1d, /**/ 0xcd, 0x58, 0xa8, 0xa6, 0x48, 0xcc, 0x58, 0x4c, 0x00, 0x61, 0xe3, 0x10, 0x61, 0x20, 0xe1, 0xa6, /**/ 0xc0, 0xb7, 0x96, 0x3f, 0x61, 0x39, 0x50, 0x07, 0x91, 0x02, 0x04, 0x81, 0x5c, 0xfa, /* 0x00, */ 0x05, 0x92, 0x02, 0xa0, 0xfc, /* 0x00, */ 0x04, 0x21, 0xd8, 0xc2, }; #endif static void send_example_data (void) { ring_write (&timex_ring, magic, sizeof (magic)); ring_write (&timex_ring, ex, sizeof (ex)); } #endif void timex_init (void) { ring_init (&timex_ring, timex_ring_buf, sizeof (timex_ring_buf)); #ifdef SEND_EXAMPLE_DATA send_example_data(); #endif gpio_set_mode (TIMEX_INPUT1_BANK, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TIMEX_INPUT1_GPIO); gpio_set_mode (TIMEX_INPUT2_BANK, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TIMEX_INPUT2_GPIO); gpio_set_mode (TIMEX_OUTPUT1_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIMEX_OUTPUT1_GPIO); gpio_set_mode (TIMEX_OUTPUT2_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIMEX_OUTPUT2_GPIO); timex_led (1); }