zzz
OneWire.h@10:c89b9ad6097c, 2019-01-27 (annotated)
- Committer:
- hudakz
- Date:
- Sun Jan 27 14:11:28 2019 +0000
- Revision:
- 10:c89b9ad6097c
- Parent:
- 9:4af0015b0f47
- Child:
- 11:bc8ed7280966
Modified.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:acf75feb0947 | 1 | #ifndef OneWire_h |
hudakz | 0:acf75feb0947 | 2 | #define OneWire_h |
hudakz | 0:acf75feb0947 | 3 | |
hudakz | 0:acf75feb0947 | 4 | #include <inttypes.h> |
hudakz | 0:acf75feb0947 | 5 | #include <mbed.h> |
hudakz | 0:acf75feb0947 | 6 | |
hudakz | 10:c89b9ad6097c | 7 | #if defined(TARGET_STM) |
hudakz | 10:c89b9ad6097c | 8 | #define MODE(x) output(); \ |
hudakz | 10:c89b9ad6097c | 9 | mode(OpenDrain) |
hudakz | 10:c89b9ad6097c | 10 | #define INPUT() (*gpio.reg_set = gpio.mask) // write 1 to open drain |
hudakz | 10:c89b9ad6097c | 11 | #define OUTPUT() // configured as output in the constructor and stays output forever |
hudakz | 10:c89b9ad6097c | 12 | #define READ() ((*gpio.reg_in & gpio.mask) ? 1 : 0) |
hudakz | 10:c89b9ad6097c | 13 | #define WRITE(x) write(x) |
hudakz | 10:c89b9ad6097c | 14 | #else |
hudakz | 10:c89b9ad6097c | 15 | #define MODE() mode(PullUp) |
hudakz | 10:c89b9ad6097c | 16 | #define INPUT() input() |
hudakz | 10:c89b9ad6097c | 17 | #define OUTPUT() output() |
hudakz | 10:c89b9ad6097c | 18 | #define READ() read() |
hudakz | 10:c89b9ad6097c | 19 | #define WRITE(x) write(x) |
hudakz | 10:c89b9ad6097c | 20 | #endif |
hudakz | 10:c89b9ad6097c | 21 | |
hudakz | 0:acf75feb0947 | 22 | // You can exclude certain features from OneWire. In theory, this |
hudakz | 0:acf75feb0947 | 23 | // might save some space. In practice, the compiler automatically |
hudakz | 0:acf75feb0947 | 24 | // removes unused code (technically, the linker, using -fdata-sections |
hudakz | 0:acf75feb0947 | 25 | // and -ffunction-sections when compiling, and Wl,--gc-sections |
hudakz | 0:acf75feb0947 | 26 | // when linking), so most of these will not result in any code size |
hudakz | 0:acf75feb0947 | 27 | // reduction. Well, unless you try to use the missing features |
hudakz | 0:acf75feb0947 | 28 | // and redesign your program to not need them! ONEWIRE_CRC8_TABLE |
hudakz | 0:acf75feb0947 | 29 | // is the exception, because it selects a fast but large algorithm |
hudakz | 0:acf75feb0947 | 30 | // or a small but slow algorithm. |
hudakz | 0:acf75feb0947 | 31 | |
hudakz | 0:acf75feb0947 | 32 | // you can exclude onewire_search by defining that to 0 |
hudakz | 0:acf75feb0947 | 33 | #ifndef ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 34 | #define ONEWIRE_SEARCH 1 |
hudakz | 0:acf75feb0947 | 35 | #endif |
hudakz | 0:acf75feb0947 | 36 | |
hudakz | 0:acf75feb0947 | 37 | // You can exclude CRC checks altogether by defining this to 0 |
hudakz | 0:acf75feb0947 | 38 | #ifndef ONEWIRE_CRC |
hudakz | 0:acf75feb0947 | 39 | #define ONEWIRE_CRC 1 |
hudakz | 0:acf75feb0947 | 40 | #endif |
hudakz | 0:acf75feb0947 | 41 | |
hudakz | 9:4af0015b0f47 | 42 | class OneWire : public DigitalInOut |
hudakz | 0:acf75feb0947 | 43 | { |
hudakz | 9:4af0015b0f47 | 44 | Timer timer; |
hudakz | 0:acf75feb0947 | 45 | |
hudakz | 0:acf75feb0947 | 46 | #if ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 47 | // global search state |
hudakz | 0:acf75feb0947 | 48 | unsigned char ROM_NO[8]; |
hudakz | 0:acf75feb0947 | 49 | uint8_t LastDiscrepancy; |
hudakz | 0:acf75feb0947 | 50 | uint8_t LastFamilyDiscrepancy; |
hudakz | 0:acf75feb0947 | 51 | uint8_t LastDeviceFlag; |
hudakz | 0:acf75feb0947 | 52 | #endif |
hudakz | 0:acf75feb0947 | 53 | |
hudakz | 9:4af0015b0f47 | 54 | public: |
hudakz | 0:acf75feb0947 | 55 | OneWire(PinName pin); |
hudakz | 0:acf75feb0947 | 56 | |
hudakz | 0:acf75feb0947 | 57 | // Perform a 1-Wire reset cycle. Returns 1 if a device responds |
hudakz | 0:acf75feb0947 | 58 | // with a presence pulse. Returns 0 if there is no device or the |
hudakz | 0:acf75feb0947 | 59 | // bus is shorted or otherwise held low for more than 250uS |
hudakz | 0:acf75feb0947 | 60 | uint8_t reset(void); |
hudakz | 0:acf75feb0947 | 61 | |
hudakz | 0:acf75feb0947 | 62 | // Issue a 1-Wire rom select command, you do the reset first. |
hudakz | 0:acf75feb0947 | 63 | void select(const uint8_t rom[8]); |
hudakz | 0:acf75feb0947 | 64 | |
hudakz | 0:acf75feb0947 | 65 | // Issue a 1-Wire rom skip command, to address all on bus. |
hudakz | 0:acf75feb0947 | 66 | void skip(void); |
hudakz | 0:acf75feb0947 | 67 | |
hudakz | 0:acf75feb0947 | 68 | // Write a byte. If 'power' is one then the wire is held high at |
hudakz | 0:acf75feb0947 | 69 | // the end for parasitically powered devices. You are responsible |
hudakz | 0:acf75feb0947 | 70 | // for eventually depowering it by calling depower() or doing |
hudakz | 0:acf75feb0947 | 71 | // another read or write. |
hudakz | 9:4af0015b0f47 | 72 | void write_byte(uint8_t v, uint8_t power = 0); |
hudakz | 0:acf75feb0947 | 73 | |
hudakz | 0:acf75feb0947 | 74 | void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0); |
hudakz | 0:acf75feb0947 | 75 | |
hudakz | 0:acf75feb0947 | 76 | // Read a byte. |
hudakz | 9:4af0015b0f47 | 77 | uint8_t read_byte(void); |
hudakz | 0:acf75feb0947 | 78 | |
hudakz | 0:acf75feb0947 | 79 | void read_bytes(uint8_t *buf, uint16_t count); |
hudakz | 0:acf75feb0947 | 80 | |
hudakz | 0:acf75feb0947 | 81 | // Write a bit. The bus is always left powered at the end, see |
hudakz | 0:acf75feb0947 | 82 | // note in write() about that. |
hudakz | 0:acf75feb0947 | 83 | void write_bit(uint8_t v); |
hudakz | 0:acf75feb0947 | 84 | |
hudakz | 0:acf75feb0947 | 85 | // Read a bit. |
hudakz | 0:acf75feb0947 | 86 | uint8_t read_bit(void); |
hudakz | 0:acf75feb0947 | 87 | |
hudakz | 0:acf75feb0947 | 88 | // Stop forcing power onto the bus. You only need to do this if |
hudakz | 0:acf75feb0947 | 89 | // you used the 'power' flag to write() or used a write_bit() call |
hudakz | 0:acf75feb0947 | 90 | // and aren't about to do another read or write. You would rather |
hudakz | 0:acf75feb0947 | 91 | // not leave this powered if you don't have to, just in case |
hudakz | 0:acf75feb0947 | 92 | // someone shorts your bus. |
hudakz | 0:acf75feb0947 | 93 | void depower(void); |
hudakz | 0:acf75feb0947 | 94 | |
hudakz | 0:acf75feb0947 | 95 | #if ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 96 | // Clear the search state so that if will start from the beginning again. |
hudakz | 0:acf75feb0947 | 97 | void reset_search(); |
hudakz | 0:acf75feb0947 | 98 | |
hudakz | 0:acf75feb0947 | 99 | // Setup the search to find the device type 'family_code' on the next call |
hudakz | 0:acf75feb0947 | 100 | // to search(*newAddr) if it is present. |
hudakz | 0:acf75feb0947 | 101 | void target_search(uint8_t family_code); |
hudakz | 0:acf75feb0947 | 102 | |
hudakz | 0:acf75feb0947 | 103 | // Look for the next device. Returns 1 if a new address has been |
hudakz | 0:acf75feb0947 | 104 | // returned. A zero might mean that the bus is shorted, there are |
hudakz | 0:acf75feb0947 | 105 | // no devices, or you have already retrieved all of them. It |
hudakz | 0:acf75feb0947 | 106 | // might be a good idea to check the CRC to make sure you didn't |
hudakz | 0:acf75feb0947 | 107 | // get garbage. The order is deterministic. You will always get |
hudakz | 0:acf75feb0947 | 108 | // the same devices in the same order. |
hudakz | 0:acf75feb0947 | 109 | uint8_t search(uint8_t *newAddr); |
hudakz | 0:acf75feb0947 | 110 | #endif |
hudakz | 0:acf75feb0947 | 111 | |
hudakz | 0:acf75feb0947 | 112 | #if ONEWIRE_CRC |
hudakz | 0:acf75feb0947 | 113 | // Compute a Dallas Semiconductor 8 bit CRC, these are used in the |
hudakz | 0:acf75feb0947 | 114 | // ROM and scratchpad registers. |
hudakz | 0:acf75feb0947 | 115 | static uint8_t crc8(const uint8_t *addr, uint8_t len); |
hudakz | 0:acf75feb0947 | 116 | |
hudakz | 0:acf75feb0947 | 117 | #if ONEWIRE_CRC16 |
hudakz | 0:acf75feb0947 | 118 | // Compute the 1-Wire CRC16 and compare it against the received CRC. |
hudakz | 0:acf75feb0947 | 119 | // Example usage (reading a DS2408): |
hudakz | 0:acf75feb0947 | 120 | // // Put everything in a buffer so we can compute the CRC easily. |
hudakz | 0:acf75feb0947 | 121 | // uint8_t buf[13]; |
hudakz | 0:acf75feb0947 | 122 | // buf[0] = 0xF0; // Read PIO Registers |
hudakz | 0:acf75feb0947 | 123 | // buf[1] = 0x88; // LSB address |
hudakz | 0:acf75feb0947 | 124 | // buf[2] = 0x00; // MSB address |
hudakz | 0:acf75feb0947 | 125 | // WriteBytes(net, buf, 3); // Write 3 cmd bytes |
hudakz | 0:acf75feb0947 | 126 | // ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16 |
hudakz | 0:acf75feb0947 | 127 | // if (!CheckCRC16(buf, 11, &buf[11])) { |
hudakz | 0:acf75feb0947 | 128 | // // Handle error. |
hudakz | 0:acf75feb0947 | 129 | // } |
hudakz | 0:acf75feb0947 | 130 | // |
hudakz | 0:acf75feb0947 | 131 | // @param input - Array of bytes to checksum. |
hudakz | 0:acf75feb0947 | 132 | // @param len - How many bytes to use. |
hudakz | 0:acf75feb0947 | 133 | // @param inverted_crc - The two CRC16 bytes in the received data. |
hudakz | 0:acf75feb0947 | 134 | // This should just point into the received data, |
hudakz | 0:acf75feb0947 | 135 | // *not* at a 16-bit integer. |
hudakz | 0:acf75feb0947 | 136 | // @param crc - The crc starting value (optional) |
hudakz | 0:acf75feb0947 | 137 | // @return True, iff the CRC matches. |
hudakz | 0:acf75feb0947 | 138 | static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0); |
hudakz | 0:acf75feb0947 | 139 | |
hudakz | 0:acf75feb0947 | 140 | // Compute a Dallas Semiconductor 16 bit CRC. This is required to check |
hudakz | 0:acf75feb0947 | 141 | // the integrity of data received from many 1-Wire devices. Note that the |
hudakz | 0:acf75feb0947 | 142 | // CRC computed here is *not* what you'll get from the 1-Wire network, |
hudakz | 0:acf75feb0947 | 143 | // for two reasons: |
hudakz | 0:acf75feb0947 | 144 | // 1) The CRC is transmitted bitwise inverted. |
hudakz | 0:acf75feb0947 | 145 | // 2) Depending on the endian-ness of your processor, the binary |
hudakz | 0:acf75feb0947 | 146 | // representation of the two-byte return value may have a different |
hudakz | 0:acf75feb0947 | 147 | // byte order than the two bytes you get from 1-Wire. |
hudakz | 0:acf75feb0947 | 148 | // @param input - Array of bytes to checksum. |
hudakz | 0:acf75feb0947 | 149 | // @param len - How many bytes to use. |
hudakz | 0:acf75feb0947 | 150 | // @param crc - The crc starting value (optional) |
hudakz | 0:acf75feb0947 | 151 | // @return The CRC16, as defined by Dallas Semiconductor. |
hudakz | 0:acf75feb0947 | 152 | static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0); |
hudakz | 0:acf75feb0947 | 153 | #endif |
hudakz | 0:acf75feb0947 | 154 | #endif |
hudakz | 0:acf75feb0947 | 155 | }; |
hudakz | 0:acf75feb0947 | 156 | |
hudakz | 0:acf75feb0947 | 157 | #endif |