From 809b234c2b9cd5fb3fe3bc6f7611cc30b9fe40c8 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 14 Jun 2017 09:10:58 +0100 Subject: initial commit --- serial_over_speaker.c | 572 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 572 insertions(+) create mode 100644 serial_over_speaker.c (limited to 'serial_over_speaker.c') diff --git a/serial_over_speaker.c b/serial_over_speaker.c new file mode 100644 index 0000000..9995123 --- /dev/null +++ b/serial_over_speaker.c @@ -0,0 +1,572 @@ +#include +#include +#include +#include + +#define BASE_CLK 1193180 +#define F 2200 + +#define DIVISOR (BASE_CLK /F) + +#define PIT_MCR_CH2 (2UL << 6) +#define PIT_MCR_AM_LOHI (3UL << 4) +#define PIT_MCR_MODE0 (0UL << 1) +#define PIT_MCR_MODE3 (3UL << 1) + +#define PIT_DATA_CH2 0x42 +#define PIT_MCR 0x43 + +#define PORTB 0x61 +#define PORTB_SP_GATE (1 << 1) +#define PORTB_SP_CH2_GATE (1 << 0) +#define PORTB_SP_STATUS (1 << 5) + +static inline uint64_t +rdtsc (void) +{ + uint32_t low, high; + __asm__ __volatile__ ("rdtsc":"=a" (low), "=d" (high)); + return ((uint64_t) high << 32) | low; +} + +static inline void +sti (void) +{ + __asm__ __volatile__ ("sti"); +} + +static inline void +cli (void) +{ + __asm__ __volatile__ ("cli"); +} + +static inline void +out_8 (uint16_t port, uint8_t value) +{ + asm volatile ("outb %b0,%w1"::"a" (value), "Nd" (port)); +} + + +static inline uint8_t +in_8 (uint16_t port) +{ + uint8_t ret; + asm volatile ("inb %w1,%b0":"=a" (ret):"Nd" (port)); + return ret; +} + + +static uint64_t t_f, t_b; +static int p = 0, f = 0; +static uint64_t tsc_baud, tsc_2f; +static unsigned baud; + +static const char *varicode_fsk[] = { + "1010101011", /* 0 - */ + "1011011011", /* 1 - */ + "1011101101", /* 2 - */ + "1101110111", /* 3 - */ + "1011101011", /* 4 - */ + "1101011111", /* 5 - */ + "1011101111", /* 6 - */ + "1011111101", /* 7 - */ + "1011111111", /* 8 - */ + "11101111", /* 9 - */ + "11101", /* 10 - */ + "1101101111", /* 11 - */ + "1011011101", /* 12 - */ + "11111", /* 13 - */ + "1101110101", /* 14 - */ + "1110101011", /* 15 - */ + "1011110111", /* 16 - */ + "1011110101", /* 17 - */ + "1110101101", /* 18 - */ + "1110101111", /* 19 - */ + "1101011011", /* 20 - */ + "1101101011", /* 21 - */ + "1101101101", /* 22 - */ + "1101010111", /* 23 - */ + "1101111011", /* 24 - */ + "1101111101", /* 25 - */ + "1110110111", /* 26 - */ + "1101010101", /* 27 - */ + "1101011101", /* 28 - */ + "1110111011", /* 29 - */ + "1011111011", /* 30 - */ + "1101111111", /* 31 - */ + "1", /* 32 - */ + "111111111", /* 33 - ! */ + "101011111", /* 34 - '"' */ + "111110101", /* 35 - # */ + "111011011", /* 36 - $ */ + "1011010101", /* 37 - % */ + "1010111011", /* 38 - & */ + "101111111", /* 39 - ' */ + "11111011", /* 40 - ( */ + "11110111", /* 41 - ) */ + "101101111", /* 42 - * */ + "111011111", /* 43 - + */ + "1110101", /* 44 - , */ + "110101", /* 45 - - */ + "1010111", /* 46 - . */ + "110101111", /* 47 - / */ + "10110111", /* 48 - 0 */ + "10111101", /* 49 - 1 */ + "11101101", /* 50 - 2 */ + "11111111", /* 51 - 3 */ + "101110111", /* 52 - 4 */ + "101011011", /* 53 - 5 */ + "101101011", /* 54 - 6 */ + "110101101", /* 55 - 7 */ + "110101011", /* 56 - 8 */ + "110110111", /* 57 - 9 */ + "11110101", /* 58 - : */ + "110111101", /* 59 - ; */ + "111101101", /* 60 - < */ + "1010101", /* 61 - = */ + "111010111", /* 62 - > */ + "1010101111", /* 63 - ? */ + "1010111101", /* 64 - @ */ + "1111101", /* 65 - A */ + "11101011", /* 66 - B */ + "10101101", /* 67 - C */ + "10110101", /* 68 - D */ + "1110111", /* 69 - E */ + "11011011", /* 70 - F */ + "11111101", /* 71 - G */ + "101010101", /* 72 - H */ + "1111111", /* 73 - I */ + "111111101", /* 74 - J */ + "101111101", /* 75 - K */ + "11010111", /* 76 - L */ + "10111011", /* 77 - M */ + "11011101", /* 78 - N */ + "10101011", /* 79 - O */ + "11010101", /* 80 - P */ + "111011101", /* 81 - Q */ + "10101111", /* 82 - R */ + "1101111", /* 83 - S */ + "1101101", /* 84 - T */ + "101010111", /* 85 - U */ + "110110101", /* 86 - V */ + "101011101", /* 87 - W */ + "101110101", /* 88 - X */ + "101111011", /* 89 - Y */ + "1010101101", /* 90 - Z */ + "111110111", /* 91 - [ */ + "111101111", /* 92 - \ */ + "111111011", /* 93 - ] */ + "1010111111", /* 94 - ^ */ + "101101101", /* 95 - _ */ + "1011011111", /* 96 - ` */ + "1011", /* 97 - a */ + "1011111", /* 98 - b */ + "101111", /* 99 - c */ + "101101", /* 100 - d */ + "11", /* 101 - e */ + "111101", /* 102 - f */ + "1011011", /* 103 - g */ + "101011", /* 104 - h */ + "1101", /* 105 - i */ + "111101011", /* 106 - j */ + "10111111", /* 107 - k */ + "11011", /* 108 - l */ + "111011", /* 109 - m */ + "1111", /* 110 - n */ + "111", /* 111 - o */ + "111111", /* 112 - p */ + "110111111", /* 113 - q */ + "10101", /* 114 - r */ + "10111", /* 115 - s */ + "101", /* 116 - t */ + "110111", /* 117 - u */ + "1111011", /* 118 - v */ + "1101011", /* 119 - w */ + "11011111", /* 120 - x */ + "1011101", /* 121 - y */ + "111010101", /* 122 - z */ + "1010110111", /* 123 - { */ + "110111011", /* 124 - | */ + "1010110101", /* 125 - } */ + "1011010111", /* 126 - ~ */ + "1110110101", /* 127 - */ + "1110111101", /* 128 - */ + "1110111111", /* 129 - */ + "1111010101", /* 130 - */ + "1111010111", /* 131 - */ + "1111011011", /* 132 - */ + "1111011101", /* 133 - */ + "1111011111", /* 134 - */ + "1111101011", /* 135 - */ + "1111101101", /* 136 - */ + "1111101111", /* 137 - */ + "1111110101", /* 138 - */ + "1111110111", /* 139 - */ + "1111111011", /* 140 - */ + "1111111101", /* 141 - */ + "1111111111", /* 142 - */ + "10101010101", /* 143 - */ + "10101010111", /* 144 - */ + "10101011011", /* 145 - */ + "10101011101", /* 146 - */ + "10101011111", /* 147 - */ + "10101101011", /* 148 - */ + "10101101101", /* 149 - */ + "10101101111", /* 150 - */ + "10101110101", /* 151 - */ + "10101110111", /* 152 - */ + "10101111011", /* 153 - */ + "10101111101", /* 154 - */ + "10101111111", /* 155 - */ + "10110101011", /* 156 - */ + "10110101101", /* 157 - */ + "10110101111", /* 158 - */ + "10110110101", /* 159 - */ + "10110110111", /* 160 - */ + "10110111011", /* 161 - */ + "10110111101", /* 162 - */ + "10110111111", /* 163 - */ + "10111010101", /* 164 - */ + "10111010111", /* 165 - */ + "10111011011", /* 166 - */ + "10111011101", /* 167 - */ + "10111011111", /* 168 - */ + "10111101011", /* 169 - */ + "10111101101", /* 170 - */ + "10111101111", /* 171 - */ + "10111110101", /* 172 - */ + "10111110111", /* 173 - */ + "10111111011", /* 174 - */ + "10111111101", /* 175 - */ + "10111111111", /* 176 - */ + "11010101011", /* 177 - */ + "11010101101", /* 178 - */ + "11010101111", /* 179 - */ + "11010110101", /* 180 - */ + "11010110111", /* 181 - */ + "11010111011", /* 182 - */ + "11010111101", /* 183 - */ + "11010111111", /* 184 - */ + "11011010101", /* 185 - */ + "11011010111", /* 186 - */ + "11011011011", /* 187 - */ + "11011011101", /* 188 - */ + "11011011111", /* 189 - */ + "11011101011", /* 190 - */ + "11011101101", /* 191 - */ + "11011101111", /* 192 - */ + "11011110101", /* 193 - */ + "11011110111", /* 194 - */ + "11011111011", /* 195 - */ + "11011111101", /* 196 - */ + "11011111111", /* 197 - */ + "11101010101", /* 198 - */ + "11101010111", /* 199 - */ + "11101011011", /* 200 - */ + "11101011101", /* 201 - */ + "11101011111", /* 202 - */ + "11101101011", /* 203 - */ + "11101101101", /* 204 - */ + "11101101111", /* 205 - */ + "11101110101", /* 206 - */ + "11101110111", /* 207 - */ + "11101111011", /* 208 - */ + "11101111101", /* 209 - */ + "11101111111", /* 210 - */ + "11110101011", /* 211 - */ + "11110101101", /* 212 - */ + "11110101111", /* 213 - */ + "11110110101", /* 214 - */ + "11110110111", /* 215 - */ + "11110111011", /* 216 - */ + "11110111101", /* 217 - */ + "11110111111", /* 218 - */ + "11111010101", /* 219 - */ + "11111010111", /* 220 - */ + "11111011011", /* 221 - */ + "11111011101", /* 222 - */ + "11111011111", /* 223 - */ + "11111101011", /* 224 - */ + "11111101101", /* 225 - */ + "11111101111", /* 226 - */ + "11111110101", /* 227 - */ + "11111110111", /* 228 - */ + "11111111011", /* 229 - */ + "11111111101", /* 230 - */ + "11111111111", /* 231 - */ + "101010101011", /* 232 - */ + "101010101101", /* 233 - */ + "101010101111", /* 234 - */ + "101010110101", /* 235 - */ + "101010110111", /* 236 - */ + "101010111011", /* 237 - */ + "101010111101", /* 238 - */ + "101010111111", /* 239 - */ + "101011010101", /* 240 - */ + "101011010111", /* 241 - */ + "101011011011", /* 242 - */ + "101011011101", /* 243 - */ + "101011011111", /* 244 - */ + "101011101011", /* 245 - */ + "101011101101", /* 246 - */ + "101011101111", /* 247 - */ + "101011110101", /* 248 - */ + "101011110111", /* 249 - */ + "101011111011", /* 250 - */ + "101011111101", /* 251 - */ + "101011111111", /* 252 - */ + "101101010101", /* 253 - */ + "101101010111", /* 254 - */ + "101101011011" /* 255 - */ +}; + +static void +program_pit_ch2 (uint32_t divisor, uint8_t mode) +{ + + out_8 (PIT_MCR, PIT_MCR_CH2 | PIT_MCR_AM_LOHI | mode); + + out_8 (PIT_DATA_CH2, divisor & 0xff); + out_8 (PIT_DATA_CH2, divisor >> 8); +} + + +static void +set_mask (int mask, uint8_t what) +{ + uint8_t v; + + v = in_8 (PORTB); + + if (mask) + v &= ~(what); + else + v |= what; + + out_8 (PORTB, v); +} + +static void +count_cycles (unsigned num) +{ + + while (num--) + { + while (!(in_8 (PORTB) & PORTB_SP_STATUS)); + while (in_8 (PORTB) & PORTB_SP_STATUS); + } + +} + + + +static void +give_to_pit (void) +{ + uint64_t t; + + set_mask (1, PORTB_SP_CH2_GATE); + program_pit_ch2 (DIVISOR, PIT_MCR_MODE3); + + + for (;;) + { + t = rdtsc (); + + if (t > t_f) + { + t_f += tsc_2f; + f = !f; + + if (f ^ p) + { + set_mask (1, PORTB_SP_GATE); + set_mask (0, PORTB_SP_CH2_GATE); + set_mask (0, PORTB_SP_GATE); + return; + } + else + { + set_mask (0, PORTB_SP_GATE); + } + } + } + +} + + +void +take_from_pit (void) +{ + uint64_t t; + + t = rdtsc (); + + while (t_b < t) + t_b += tsc_baud; + + while (!(in_8 (PORTB) & PORTB_SP_STATUS)); /*Low */ + while ((in_8 (PORTB) & PORTB_SP_STATUS)); /*High */ + t_f = rdtsc (); + set_mask (1, PORTB_SP_GATE | PORTB_SP_CH2_GATE); + + t_f += tsc_2f; + + while (t_b < t_f) + t_b += tsc_baud; +} + + +static void +start (void) +{ +/* This gets OUT2 from the 8254 high*/ + set_mask (1, PORTB_SP_CH2_GATE); + t_b = t_f = rdtsc (); +} + + + + +static void +send_bit_raw (int b) +{ + uint64_t t; + + if (!b) + p = !p; + + t_b += tsc_baud; + + while ((t = rdtsc ()) < t_b) + { + if (t > t_f) + { + t_f += tsc_2f; + f = !f; + set_mask (f ^ p, PORTB_SP_GATE); + } + } + +} + +static void +send_bit (int b) +{ + send_bit_raw (b); +} + + +static void +stop (void) +{ + set_mask (1, PORTB_SP_GATE | PORTB_SP_CH2_GATE); +} + + +static void +send_sync (int bits, int bit) +{ + + if (bit == 2) + { + bits >>= 1; + + while (bits--) + { + send_bit (1); + send_bit (0); + } + } + else + { + while (bits--) + send_bit (bit); + } +} + +static void +send_char (uint8_t c) +{ + const char *v = varicode_fsk[c]; + + if (!v) + return; + + while (*v) + send_bit (*(v++) - '0'); + + send_bit (0); + send_bit (0); +} + + +void +modem_xmit (void *_buf, size_t buf_len) +{ + uint8_t *buf = _buf; + take_from_pit (); + + send_sync (baud / 5, 0); + send_char (0); + + while (buf_len--) + send_char (*(buf++)); + + give_to_pit (); +} + + + +void +modem_on (unsigned _baud) +{ + uint64_t tsc, tsc_start; + + baud = _baud; + + program_pit_ch2 (DIVISOR, PIT_MCR_MODE3); + set_mask (0, PORTB_SP_GATE | PORTB_SP_CH2_GATE); + + count_cycles (10); + tsc_start = rdtsc (); + count_cycles (F); + tsc = rdtsc (); + + tsc -= tsc_start; + + tsc_baud = (tsc / baud); + tsc_2f = (tsc / (2 * F)); + + + start (); + send_sync (baud * 2, 0); + + give_to_pit (); +} + +void +modem_off (void) +{ + take_from_pit (); + send_sync (150, 1); + stop (); +} + +int +main (int argc, char *argv[]) +{ + char msg[] = "The quick brown fox jumps over the lazy dog\r\n"; + + iopl (3); + cli (); + + modem_on (125); + modem_xmit (msg, sizeof (msg)); + modem_off (); + + sti (); + + return 0; +} -- cgit v1.2.3