Line data Source code
1 : /* 2 : * This file is free software: you can redistribute it and/or modify it 3 : * under the terms of the GNU General Public License as published by the 4 : * Free Software Foundation, either version 3 of the License, or 5 : * (at your option) any later version. 6 : * 7 : * This file is distributed in the hope that it will be useful, but 8 : * WITHOUT ANY WARRANTY; without even the implied warranty of 9 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 10 : * See the GNU General Public License for more details. 11 : * 12 : * You should have received a copy of the GNU General Public License along 13 : * with this program. If not, see <http://www.gnu.org/licenses/>. 14 : */ 15 : /* 16 : soft serial receive implementation, based on pulse width inputs 17 : */ 18 : 19 : #include "SoftSerial.h" 20 : #include <AP_Math/crc.h> 21 : #include <stdio.h> 22 : 23 20940 : SoftSerial::SoftSerial(uint32_t _baudrate, serial_config _config) : 24 20940 : baudrate(_baudrate), 25 20940 : half_bit((1000000U / baudrate)/2), 26 20940 : config(_config) 27 : { 28 20940 : switch (config) { 29 14658 : case SERIAL_CONFIG_8N1: 30 : case SERIAL_CONFIG_8N1I: 31 14658 : data_width = 8; 32 14658 : byte_width = 10; 33 14658 : stop_mask = 0x200; 34 14658 : break; 35 6282 : case SERIAL_CONFIG_8E2I: 36 6282 : data_width = 9; 37 6282 : byte_width = 12; 38 6282 : stop_mask = 0xC00; 39 6282 : break; 40 : } 41 20940 : } 42 : 43 : /* 44 : process a pulse made up of a width of values at high voltage 45 : followed by a width at low voltage 46 : */ 47 0 : bool SoftSerial::process_pulse(uint32_t width_high, uint32_t width_low, uint8_t &byte) 48 : { 49 : // convert to bit widths, allowing for a half bit error 50 0 : uint16_t bits_high = ((width_high+half_bit)*baudrate) / 1000000; 51 0 : uint16_t bits_low = ((width_low+half_bit)*baudrate) / 1000000; 52 : 53 0 : byte_timestamp_us = timestamp_us; 54 0 : timestamp_us += (width_high + width_low); 55 : 56 0 : if (bits_high == 0 || bits_low == 0) { 57 : // invalid data 58 0 : goto reset; 59 : } 60 : 61 0 : if (bits_high >= byte_width) { 62 : // if we have a start bit and a stop bit then we can have at 63 : // most 9 bits in high state for data. The rest must be idle 64 : // bits 65 0 : bits_high = byte_width-1; 66 : } 67 : 68 0 : if (state.bit_ofs == 0) { 69 : // we are in idle state, waiting for first low bit. swallow 70 : // the high bits 71 0 : bits_high = 0; 72 : } 73 : 74 0 : state.byte |= ((1U<<bits_high)-1) << state.bit_ofs; 75 : 76 0 : state.bit_ofs += bits_high + bits_low; 77 : 78 0 : if (state.bit_ofs >= byte_width) { 79 : // check start bit 80 0 : if ((state.byte & 1) != 0) { 81 0 : goto reset; 82 : } 83 : // check stop bits 84 0 : if ((state.byte & stop_mask) != stop_mask) { 85 0 : goto reset; 86 : } 87 0 : if (config == SERIAL_CONFIG_8E2I) { 88 : // check parity 89 0 : if (parity((state.byte>>1)&0xFF) != (state.byte&0x200)>>9) { 90 0 : goto reset; 91 : } 92 : } 93 : 94 0 : byte = ((state.byte>>1) & 0xFF); 95 0 : state.byte >>= byte_width; 96 0 : state.bit_ofs -= byte_width; 97 0 : if (state.bit_ofs > byte_width) { 98 0 : state.byte = 0; 99 0 : state.bit_ofs = bits_low; 100 : } 101 : // swallow idle bits 102 0 : while (state.bit_ofs > 0 && (state.byte & 1)) { 103 0 : state.bit_ofs--; 104 0 : state.byte >>= 1; 105 : } 106 0 : return true; 107 : } 108 0 : return false; 109 : 110 0 : reset: 111 0 : state.byte = 0; 112 0 : state.bit_ofs = 0; 113 : 114 0 : return false; 115 : } 116 :