diff options
Diffstat (limited to 'protocol/serial_soft.c')
| -rw-r--r-- | protocol/serial_soft.c | 119 |
1 files changed, 102 insertions, 17 deletions
diff --git a/protocol/serial_soft.c b/protocol/serial_soft.c index beddc353c..e8870bcd7 100644 --- a/protocol/serial_soft.c +++ b/protocol/serial_soft.c | |||
| @@ -43,15 +43,47 @@ POSSIBILITY OF SUCH DAMAGE. | |||
| 43 | 43 | ||
| 44 | /* | 44 | /* |
| 45 | * Stupid Inefficient Busy-wait Software Serial | 45 | * Stupid Inefficient Busy-wait Software Serial |
| 46 | * is still useful for negative logic signal like Sun protocol not supported by hardware USART. | 46 | * which is still useful for negative logic signal like Sun protocol |
| 47 | * if it is not supported by hardware UART. | ||
| 48 | * | ||
| 49 | * TODO: delay is not accurate enough. Instruction cycle should be counted and inline assemby is needed. | ||
| 47 | */ | 50 | */ |
| 48 | 51 | ||
| 49 | #define WAIT_US (1000000/SERIAL_BAUD) | 52 | #define WAIT_US (1000000L/SERIAL_SOFT_BAUD) |
| 53 | |||
| 54 | #ifdef SERIAL_SOFT_LOGIC_NEGATIVE | ||
| 55 | #define SERIAL_SOFT_RXD_IN() !(SERIAL_SOFT_RXD_READ()) | ||
| 56 | #define SERIAL_SOFT_TXD_ON() SERIAL_SOFT_TXD_LO() | ||
| 57 | #define SERIAL_SOFT_TXD_OFF() SERIAL_SOFT_TXD_HI() | ||
| 58 | #else | ||
| 59 | #define SERIAL_SOFT_RXD_IN() !!(SERIAL_SOFT_RXD_READ()) | ||
| 60 | #define SERIAL_SOFT_TXD_ON() SERIAL_SOFT_TXD_HI() | ||
| 61 | #define SERIAL_SOFT_TXD_OFF() SERIAL_SOFT_TXD_LO() | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #ifdef SERIAL_SOFT_PARITY_EVEN | ||
| 65 | #define SERIAL_SOFT_PARITY_VAL 0 | ||
| 66 | #elif defined(SERIAL_SOFT_PARITY_ODD) | ||
| 67 | #define SERIAL_SOFT_PARITY_VAL 1 | ||
| 68 | #endif | ||
| 69 | |||
| 70 | /* debug for signal timing, see debug pin with oscilloscope */ | ||
| 71 | #define SERIAL_SOFT_DEBUG | ||
| 72 | #ifdef SERIAL_SOFT_DEBUG | ||
| 73 | #define SERIAL_SOFT_DEBUG_INIT() (DDRD |= 1<<7) | ||
| 74 | #define SERIAL_SOFT_DEBUG_TGL() (PORTD ^= 1<<7) | ||
| 75 | #else | ||
| 76 | #define SERIAL_SOFT_DEBUG_INIT() | ||
| 77 | #define SERIAL_SOFT_DEBUG_TGL() | ||
| 78 | #endif | ||
| 79 | |||
| 50 | 80 | ||
| 51 | void serial_init(void) | 81 | void serial_init(void) |
| 52 | { | 82 | { |
| 53 | SERIAL_RXD_INIT(); | 83 | SERIAL_SOFT_DEBUG_INIT(); |
| 54 | SERIAL_TXD_INIT(); | 84 | |
| 85 | SERIAL_SOFT_RXD_INIT(); | ||
| 86 | SERIAL_SOFT_TXD_INIT(); | ||
| 55 | } | 87 | } |
| 56 | 88 | ||
| 57 | /* RX ring buffer */ | 89 | /* RX ring buffer */ |
| @@ -60,6 +92,7 @@ static uint8_t rbuf[RBUF_SIZE]; | |||
| 60 | static uint8_t rbuf_head = 0; | 92 | static uint8_t rbuf_head = 0; |
| 61 | static uint8_t rbuf_tail = 0; | 93 | static uint8_t rbuf_tail = 0; |
| 62 | 94 | ||
| 95 | |||
| 63 | uint8_t serial_recv(void) | 96 | uint8_t serial_recv(void) |
| 64 | { | 97 | { |
| 65 | uint8_t data = 0; | 98 | uint8_t data = 0; |
| @@ -72,68 +105,120 @@ uint8_t serial_recv(void) | |||
| 72 | return data; | 105 | return data; |
| 73 | } | 106 | } |
| 74 | 107 | ||
| 108 | int16_t serial_recv2(void) | ||
| 109 | { | ||
| 110 | uint8_t data = 0; | ||
| 111 | if (rbuf_head == rbuf_tail) { | ||
| 112 | return -1; | ||
| 113 | } | ||
| 114 | |||
| 115 | data = rbuf[rbuf_tail]; | ||
| 116 | rbuf_tail = (rbuf_tail + 1) % RBUF_SIZE; | ||
| 117 | return data; | ||
| 118 | } | ||
| 119 | |||
| 75 | void serial_send(uint8_t data) | 120 | void serial_send(uint8_t data) |
| 76 | { | 121 | { |
| 77 | /* signal state: IDLE: ON, START: OFF, STOP: ON, DATA0: OFF, DATA1: ON */ | 122 | /* signal state: IDLE: ON, START: OFF, STOP: ON, DATA0: OFF, DATA1: ON */ |
| 78 | /* start bit */ | ||
| 79 | SERIAL_TXD_OFF(); | ||
| 80 | _delay_us(WAIT_US); | ||
| 81 | 123 | ||
| 82 | #ifdef SERIAL_BIT_ORDER_MSB | 124 | #ifdef SERIAL_SOFT_BIT_ORDER_MSB |
| 83 | uint8_t mask = 0x80; | 125 | uint8_t mask = 0x80; |
| 84 | #else | 126 | #else |
| 85 | uint8_t mask = 0x01; | 127 | uint8_t mask = 0x01; |
| 86 | #endif | 128 | #endif |
| 129 | |||
| 130 | uint8_t parity = 0; | ||
| 131 | |||
| 132 | /* start bit */ | ||
| 133 | SERIAL_SOFT_TXD_OFF(); | ||
| 134 | _delay_us(WAIT_US); | ||
| 135 | |||
| 87 | while (mask) { | 136 | while (mask) { |
| 88 | if (data&mask) { SERIAL_TXD_ON(); } else { SERIAL_TXD_OFF(); } | 137 | if (data&mask) { |
| 138 | SERIAL_SOFT_TXD_ON(); | ||
| 139 | parity ^= 1; | ||
| 140 | } else { | ||
| 141 | SERIAL_SOFT_TXD_OFF(); | ||
| 142 | } | ||
| 89 | _delay_us(WAIT_US); | 143 | _delay_us(WAIT_US); |
| 90 | 144 | ||
| 91 | #ifdef SERIAL_BIT_ORDER_MSB | 145 | #ifdef SERIAL_SOFT_BIT_ORDER_MSB |
| 92 | mask >>= 1; | 146 | mask >>= 1; |
| 93 | #else | 147 | #else |
| 94 | mask <<= 1; | 148 | mask <<= 1; |
| 95 | #endif | 149 | #endif |
| 96 | } | 150 | } |
| 97 | 151 | ||
| 152 | #if defined(SERIAL_SOFT_PARITY_EVEN) || defined(SERIAL_SOFT_PARITY_ODD) | ||
| 153 | /* to center of parity bit */ | ||
| 154 | if (parity != SERIAL_SOFT_PARITY_VAL) { | ||
| 155 | SERIAL_SOFT_TXD_ON(); | ||
| 156 | } else { | ||
| 157 | SERIAL_SOFT_TXD_OFF(); | ||
| 158 | } | ||
| 159 | _delay_us(WAIT_US); | ||
| 160 | #endif | ||
| 161 | |||
| 98 | /* stop bit */ | 162 | /* stop bit */ |
| 99 | SERIAL_TXD_ON(); | 163 | SERIAL_SOFT_TXD_ON(); |
| 100 | _delay_us(WAIT_US); | 164 | _delay_us(WAIT_US); |
| 101 | } | 165 | } |
| 102 | 166 | ||
| 103 | /* detect edge of start bit */ | 167 | /* detect edge of start bit */ |
| 104 | ISR(SERIAL_RXD_VECT) | 168 | ISR(SERIAL_SOFT_RXD_VECT) |
| 105 | { | 169 | { |
| 106 | SERIAL_RXD_INT_ENTER() | 170 | SERIAL_SOFT_DEBUG_TGL(); |
| 171 | SERIAL_SOFT_RXD_INT_ENTER() | ||
| 107 | 172 | ||
| 108 | uint8_t data = 0; | 173 | uint8_t data = 0; |
| 109 | #ifdef SERIAL_BIT_ORDER_MSB | 174 | |
| 175 | #ifdef SERIAL_SOFT_BIT_ORDER_MSB | ||
| 110 | uint8_t mask = 0x80; | 176 | uint8_t mask = 0x80; |
| 111 | #else | 177 | #else |
| 112 | uint8_t mask = 0x01; | 178 | uint8_t mask = 0x01; |
| 113 | #endif | 179 | #endif |
| 180 | |||
| 181 | uint8_t parity = 0; | ||
| 182 | |||
| 114 | /* to center of start bit */ | 183 | /* to center of start bit */ |
| 115 | _delay_us(WAIT_US/2); | 184 | _delay_us(WAIT_US/2); |
| 185 | SERIAL_SOFT_DEBUG_TGL(); | ||
| 116 | do { | 186 | do { |
| 117 | /* to center of next bit */ | 187 | /* to center of next bit */ |
| 118 | _delay_us(WAIT_US); | 188 | _delay_us(WAIT_US); |
| 119 | 189 | ||
| 120 | if (SERIAL_RXD_READ()) { | 190 | SERIAL_SOFT_DEBUG_TGL(); |
| 191 | if (SERIAL_SOFT_RXD_IN()) { | ||
| 121 | data |= mask; | 192 | data |= mask; |
| 193 | parity ^= 1; | ||
| 122 | } | 194 | } |
| 123 | #ifdef SERIAL_BIT_ORDER_MSB | 195 | #ifdef SERIAL_SOFT_BIT_ORDER_MSB |
| 124 | mask >>= 1; | 196 | mask >>= 1; |
| 125 | #else | 197 | #else |
| 126 | mask <<= 1; | 198 | mask <<= 1; |
| 127 | #endif | 199 | #endif |
| 128 | } while (mask); | 200 | } while (mask); |
| 201 | |||
| 202 | #if defined(SERIAL_SOFT_PARITY_EVEN) || defined(SERIAL_SOFT_PARITY_ODD) | ||
| 203 | /* to center of parity bit */ | ||
| 204 | _delay_us(WAIT_US); | ||
| 205 | if (SERIAL_SOFT_RXD_IN()) { parity ^= 1; } | ||
| 206 | SERIAL_SOFT_DEBUG_TGL(); | ||
| 207 | #endif | ||
| 208 | |||
| 129 | /* to center of stop bit */ | 209 | /* to center of stop bit */ |
| 130 | _delay_us(WAIT_US); | 210 | _delay_us(WAIT_US); |
| 131 | 211 | ||
| 132 | uint8_t next = (rbuf_head + 1) % RBUF_SIZE; | 212 | uint8_t next = (rbuf_head + 1) % RBUF_SIZE; |
| 213 | #if defined(SERIAL_SOFT_PARITY_EVEN) || defined(SERIAL_SOFT_PARITY_ODD) | ||
| 214 | if ((parity == SERIAL_SOFT_PARITY_VAL) && next != rbuf_tail) { | ||
| 215 | #else | ||
| 133 | if (next != rbuf_tail) { | 216 | if (next != rbuf_tail) { |
| 217 | #endif | ||
| 134 | rbuf[rbuf_head] = data; | 218 | rbuf[rbuf_head] = data; |
| 135 | rbuf_head = next; | 219 | rbuf_head = next; |
| 136 | } | 220 | } |
| 137 | 221 | ||
| 138 | SERIAL_RXD_INT_EXIT(); | 222 | SERIAL_SOFT_RXD_INT_EXIT(); |
| 223 | SERIAL_SOFT_DEBUG_TGL(); | ||
| 139 | } | 224 | } |
