#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 512 #define TIMEX_INPUT_BANK GPIOB #define TIMEX_INPUT_GPIO GPIO9 #define TIMEX_OUTPUT_BANK GPIOB #define TIMEX_OUTPUT_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_OUTPUT_BANK, TIMEX_OUTPUT_GPIO); else gpio_clear (TIMEX_OUTPUT_BANK, TIMEX_OUTPUT_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 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, // DATA END 0x08, 0x31, 0x01, 0x15, 0x18, 0x17, 0xba, 0x26, //TIME ZONE LABEL 1 0x08, 0x31, 0x02, 0x11, 0x17, 0x10, 0x0d, 0x23, //TIME ZONE LABEL 2 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 }; 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_INPUT_BANK, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TIMEX_INPUT_GPIO); gpio_set_mode (TIMEX_OUTPUT_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIMEX_OUTPUT_GPIO); timex_led (1); }