├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── api └── one_wire.h ├── source └── one_wire.cpp └── test ├── CMakeLists.txt ├── pico_pi_mocks.cpp ├── pico_pi_mocks.h └── test_one_wire.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignOperands: true 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: true 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: ForContinuationAndIndentation 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .idea/ 3 | test/cmake-build-debug/ 4 | cmake-build-debug/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(pico_one_wire INTERFACE) 2 | 3 | target_sources(pico_one_wire INTERFACE 4 | ${CMAKE_CURRENT_LIST_DIR}/source/one_wire.cpp 5 | ) 6 | 7 | target_include_directories(pico_one_wire INTERFACE ${CMAKE_CURRENT_LIST_DIR}/api) 8 | target_link_libraries(pico_one_wire INTERFACE pico_stdlib hardware_gpio) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2010, Michael Hagberg 4 | Copyright (c) 2013, David Pairman 5 | Copyright (c) 2015, Florian P 6 | Copyright (c) 2014-7, Eric Olieman 7 | Copyright (c) 2019,2021, Adam Boardman 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Pico One Wire Library 2 | 3 | This library allows you to talk to one wire devices such as Temperature sensors Dallas DS18S20, DS18B20 and DS1822, Maxim MAX31820 and MAX31826. 4 | 5 | It should also be easy to extend it to also support RTC's DS2404 and DS2417, Current measurement devices DS2740 and 1k EEPROM's DS2502. 6 | 7 | Based upon Erik Olieman's mbed DS1820 lib 8 | 9 | https://developer.mbed.org/components/DS1820/ 10 | 11 | Modified timings so that it works when used on the Pi Pico 12 | 13 | Added off device test code with mocks and its own cmake configuration. 14 | 15 | Modified API's for two stage workflow: 16 | 1. Listing of devices with addresses to be stored elsewhere 17 | 2. Returning temperatures for each device by address 18 | 19 | # Usage - Temperature reading 20 | 21 | ## Include library 22 | 23 | Check the module out as a submodule of your project to say: modules/pico-onewire then 24 | add the sub directory and link the library in your CMakeLists.txt: 25 | ``` 26 | add_subdirectory(modules/pico-onewire) 27 | 28 | target_link_libraries( ... pico_one_wire) 29 | ``` 30 | 31 | ## Single sensor 32 | 33 | An example main that will check for attached devices once per second, print the address and temperature. 34 | ``` 35 | #include 36 | #include "pico/stdlib.h" 37 | #include "hardware/gpio.h" 38 | #include "modules/pico-onewire/api/one_wire.h" 39 | 40 | int main() { 41 | stdio_init_all(); 42 | One_wire one_wire(15); //GP15 - Pin 20 on Pi Pico 43 | one_wire.init(); 44 | rom_address_t address{}; 45 | while (true) { 46 | one_wire.single_device_read_rom(address); 47 | printf("Device Address: %02x%02x%02x%02x%02x%02x%02x%02x\n", address.rom[0], address.rom[1], address.rom[2], address.rom[3], address.rom[4], address.rom[5], address.rom[6], address.rom[7]); 48 | one_wire.convert_temperature(address, true, false); 49 | printf("Temperature: %3.1foC\n", one_wire.temperature(address)); 50 | sleep_ms(1000); 51 | } 52 | return 0; 53 | } 54 | ``` 55 | 56 | ## Multiple sensors 57 | 58 | A more complicated example to print all the available devices. 59 | Additionally pin 22 is used to exit the main loop and return to the USB Flashing mode. 60 | A push button switch between pins 28&29 (GND+GP22) will do nicely. 61 | Also we are converting the address to uint64 for future use. 62 | 63 | Add to the CMakeLists.txt in your project config: 64 | ``` 65 | add_definitions(-DPICO_ENTER_USB_BOOT_ON_EXIT) 66 | ``` 67 | main.cpp: 68 | ``` 69 | #include 70 | #include "pico/stdlib.h" 71 | #include "hardware/gpio.h" 72 | #include "modules/pico-onewire/api/one_wire.h" 73 | 74 | #define TEMP_SENSE_GPIO_PIN 15 75 | #define EXIT_GPIO_PIN 22 76 | 77 | int main() { 78 | stdio_init_all(); 79 | One_wire one_wire(TEMP_SENSE_GPIO_PIN); 80 | one_wire.init(); 81 | gpio_init(EXIT_GPIO_PIN); 82 | gpio_set_dir(EXIT_GPIO_PIN, GPIO_IN); 83 | gpio_pull_up(EXIT_GPIO_PIN); 84 | sleep_ms(1); 85 | while (gpio_get(EXIT_GPIO_PIN)) { 86 | int count = one_wire.find_and_count_devices_on_bus(); 87 | rom_address_t null_address{}; 88 | one_wire.convert_temperature(null_address, true, true); 89 | for (int i = 0; i < count; i++) { 90 | auto address = One_wire::get_address(i); 91 | printf("%016llX\t%3.1f*C\r\n", One_wire::to_uint64(address), one_wire.temperature(address)); 92 | } 93 | sleep_ms(1000); 94 | } 95 | return 0; 96 | } 97 | ``` 98 | 99 | # Running the test code on a desktop 100 | 101 | If your just using the library you don't need to worry about the test code. 102 | If you plan on fixing bugs or extending the library then you must. 103 | 104 | Install Catch2 version 3, it might be available on your desktop linux distro, 105 | though possibly only an older version. Or you can download, build and install it: 106 | ``` 107 | git clone https://github.com/catchorg/Catch2.git 108 | cd Catch2 109 | cmake -Bbuild -H. -DBUILD_TESTING=OFF 110 | cmake --build build/ 111 | sudo cmake --build build/ --target install 112 | ``` 113 | 114 | Build and run the test code: 115 | ``` 116 | cd test 117 | mkdir build 118 | cd build 119 | cmake .. 120 | make 121 | ./tests 122 | ``` 123 | 124 | You should then see 'All tests passed' 125 | -------------------------------------------------------------------------------- /api/one_wire.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-pi-one-wire Library, derived from the mbed DS1820 Library, for the 3 | * Dallas (Maxim) 1-Wire Devices 4 | * Copyright (c) 2010, Michael Hagberg 5 | * 6 | * This version uses a single instance to talk to multiple one wire devices. 7 | * During configuration the devices will be listed and the addresses 8 | * then stored within the system they are associated with. 9 | * 10 | * Then previously stored addresses are used to query devices. 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | */ 30 | 31 | #ifndef PICO_PI_ONEWIRE_H 32 | #define PICO_PI_ONEWIRE_H 33 | 34 | #ifdef MOCK_PICO_PI 35 | 36 | #include "../test/pico_pi_mocks.h" 37 | 38 | #else 39 | 40 | #include "hardware/gpio.h" 41 | #include "pico/time.h" 42 | 43 | #endif 44 | 45 | #define FAMILY_CODE address.rom[0] 46 | #define FAMILY_CODE_DS18S20 0x10 //9bit temp 47 | #define FAMILY_CODE_DS18B20 0x28 //9-12bit temp also known as MAX31820 48 | #define FAMILY_CODE_DS1822 0x22 //9-12bit temp 49 | #define FAMILY_CODE_MAX31826 0x3B//12bit temp + 1k EEPROM 50 | #define FAMILY_CODE_DS2404 0x04 //RTC 51 | #define FAMILY_CODE_DS2417 0x27 //RTC 52 | #define FAMILY_CODE_DS2740 0x36 //Current measurement 53 | #define FAMILY_CODE_DS2502 0x09 //1k EEPROM 54 | 55 | static const int ReadScratchPadCommand = 0xBE; 56 | static const int ReadPowerSupplyCommand = 0xB4; 57 | static const int ConvertTempCommand = 0x44; 58 | static const int MatchROMCommand = 0x55; 59 | static const int ReadROMCommand = 0x33; 60 | static const int SearchROMCommand = 0xF0; 61 | static const int SkipROMCommand = 0xCC; 62 | static const int WriteScratchPadCommand = 0x4E; 63 | static const int ROMSize = 8; 64 | struct rom_address_t { 65 | uint8_t rom[ROMSize]; 66 | }; 67 | 68 | /** 69 | * OneWire with DS1820 Dallas 1-Wire Temperature Probe 70 | * 71 | * Example: 72 | * @code 73 | * #include "one_wire.h" 74 | * 75 | * One_wire one_wire(15); //GP15 - Pin 20 on Pi Pico 76 | * 77 | * int main() { 78 | * one_wire.init(); 79 | * rom_address_t address{}; 80 | * while (true) { 81 | * one_wire.single_device_read_rom(address); 82 | * one_wire.convert_temperature(address, true, true); 83 | * printf("It is %3.1foC\n", one_wire.temperature(address)); 84 | * sleep_ms(1000); 85 | * } 86 | * } 87 | * @endcode 88 | */ 89 | class One_wire { 90 | public: 91 | enum { 92 | invalid_conversion = -1000, 93 | not_controllable = 0xFFFFFFFF 94 | }; 95 | 96 | /** Create a one wire bus object connected to the specified pins 97 | * 98 | * The bus might either by regular powered or parasite powered. If it is parasite 99 | * powered and power_pin is set, that pin will be used to switch an external mosfet 100 | * connecting data to Vdd. If it is parasite powered and the pin is not set, the 101 | * regular data pin is used to supply extra power when required. This will be 102 | * sufficient as long as the number of devices is limited. 103 | * 104 | * @param data_pin pin for the data bus 105 | * @param power_pin (optional) pin to control the power MOSFET 106 | * @param power_polarity (optional) which sets active state (false for active low (default), true for active high) 107 | */ 108 | One_wire(uint data_pin, uint power_pin = not_controllable, bool power_polarity = false); 109 | ~One_wire(); 110 | 111 | /** 112 | * Initialise and determine if any devices are using parasitic power 113 | */ 114 | void init(); 115 | 116 | /** 117 | * Finds all one wire devices and returns the count 118 | * 119 | * @return - number of devices found 120 | */ 121 | int find_and_count_devices_on_bus(); 122 | 123 | /** 124 | * Get address of devices previously found 125 | * 126 | * @param index the index into found devices 127 | * @return the address of 128 | */ 129 | static rom_address_t &get_address(int index); 130 | 131 | /** 132 | * This routine will initiate the temperature conversion within 133 | * one or all temperature devices. 134 | * 135 | * @param wait if true or parasitic power is used, waits up to 750 ms for 136 | * conversion otherwise returns immediately. 137 | * @param address allows the function to apply to a specific device or 138 | * to all devices on the 1-Wire bus. 139 | * @returns milliseconds until conversion will complete. 140 | */ 141 | int convert_temperature(rom_address_t &address, bool wait, bool all); 142 | 143 | /** 144 | * Changes the "endianness" of the unique device ID in supplied address 145 | * so that it can be conveniently printed out and manipulated as a number. 146 | * 147 | * @param address the address you received from OneWire::get_address(i). 148 | * @returns device ID as unsigned 64-bit integer. 149 | */ 150 | static uint64_t to_uint64(rom_address_t &address); 151 | 152 | /** 153 | * This function will return the temperature measured by the specific device. 154 | * 155 | * @param convert_to_fahrenheit whether to convert the degC to Fahrenheit 156 | * @returns temperature for that scale, or OneWire::invalid_conversion (-1000) if CRC error detected. 157 | */ 158 | float temperature(rom_address_t &address, bool convert_to_fahrenheit = false); 159 | 160 | /** 161 | * This function sets the temperature resolution for supported devices 162 | * in the configuration register. 163 | * 164 | * @param resolution number between 9 and 12 to specify resolution 165 | * @returns true if successful 166 | */ 167 | bool set_resolution(rom_address_t &address, unsigned int resolution); 168 | 169 | /** 170 | * Assuming a single device is attached, do a Read ROM 171 | * 172 | * @param rom_address the address will be filled into this parameter 173 | */ 174 | void single_device_read_rom(rom_address_t &rom_address); 175 | 176 | /** 177 | * Static utility method for easy conversion from previously stored addresses 178 | * 179 | * @param hex_address the address as a human readable hex string 180 | * @return the rom address 181 | */ 182 | static rom_address_t address_from_hex(const char *hex_address); 183 | 184 | private: 185 | uint _data_pin; 186 | uint _parasite_pin; 187 | bool _parasite_power{}; 188 | bool _power_mosfet; 189 | bool _power_polarity; 190 | uint8_t _search_ROM[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 191 | uint8_t ram[9]{}; 192 | 193 | int _last_discrepancy; // search state 194 | bool _last_device; // search state 195 | 196 | static uint8_t crc_byte(uint8_t crc, uint8_t byte); 197 | 198 | static void bit_write(uint8_t &value, int bit, bool set); 199 | 200 | [[nodiscard]] bool reset_check_for_device() const; 201 | 202 | void match_rom(rom_address_t &address); 203 | 204 | void skip_rom(); 205 | 206 | void onewire_bit_out(bool bit_data) const; 207 | 208 | void onewire_byte_out(uint8_t data); 209 | 210 | [[nodiscard]] bool onewire_bit_in() const; 211 | 212 | uint8_t onewire_byte_in(); 213 | 214 | static bool rom_checksum_error(uint8_t *address); 215 | 216 | bool ram_checksum_error(); 217 | 218 | bool search_rom_find_next(); 219 | 220 | void read_scratch_pad(rom_address_t &address); 221 | 222 | void write_scratch_pad(rom_address_t &address, int data); 223 | 224 | bool power_supply_available(rom_address_t &address, bool all); 225 | }; 226 | 227 | 228 | #endif// PICO_PI_ONEWIRE_H -------------------------------------------------------------------------------- /source/one_wire.cpp: -------------------------------------------------------------------------------- 1 | #include "../api/one_wire.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef MOCK_PICO_PI 9 | 10 | #include "../test/pico_pi_mocks.h" 11 | 12 | #else 13 | 14 | #include "hardware/gpio.h" 15 | 16 | #endif 17 | 18 | std::vector found_addresses; 19 | 20 | One_wire::One_wire(uint data_pin, uint power_pin, bool power_polarity) 21 | : _data_pin(data_pin), 22 | _parasite_pin(power_pin), 23 | _power_polarity(power_polarity), 24 | _power_mosfet(power_pin != not_controllable) { 25 | } 26 | 27 | void One_wire::init() { 28 | gpio_init(_data_pin); 29 | if (_parasite_pin != not_controllable) { 30 | gpio_init(_parasite_pin); 31 | } 32 | for (uint8_t &byte_counter : ram) { 33 | byte_counter = 0x00; 34 | } 35 | 36 | rom_address_t address{}; 37 | _parasite_power = !power_supply_available(address, true); 38 | } 39 | 40 | One_wire::~One_wire() { 41 | found_addresses.clear(); 42 | } 43 | 44 | bool One_wire::reset_check_for_device() const { 45 | // This will return false if no devices are present on the data bus 46 | bool presence = false; 47 | gpio_init(_data_pin); 48 | gpio_set_dir(_data_pin, GPIO_OUT); 49 | gpio_put(_data_pin, false); // bring low for 480us 50 | sleep_us(480); 51 | gpio_set_dir(_data_pin, GPIO_IN); // let the data line float high 52 | sleep_us(70); // wait 70us 53 | if (!gpio_get(_data_pin)) { 54 | // see if any devices are pulling the data line low 55 | presence = true; 56 | } 57 | sleep_us(410); 58 | return presence; 59 | } 60 | 61 | void One_wire::onewire_bit_out(bool bit_data) const { 62 | gpio_set_dir(_data_pin, GPIO_OUT); 63 | gpio_put(_data_pin, false); 64 | sleep_us(3);// (spec 1-15us) 65 | if (bit_data) { 66 | gpio_put(_data_pin, true); 67 | sleep_us(55); 68 | } else { 69 | sleep_us(60);// (spec 60-120us) 70 | gpio_put(_data_pin, true); 71 | sleep_us(5);// allow bus to float high before next bit_out 72 | } 73 | } 74 | 75 | void One_wire::onewire_byte_out(uint8_t data) { 76 | int n; 77 | for (n = 0; n < 8; n++) { 78 | onewire_bit_out((bool) (data & 0x01)); 79 | data = data >> 1;// now the next bit is in the least sig bit position. 80 | } 81 | } 82 | 83 | bool One_wire::onewire_bit_in() const { 84 | bool answer; 85 | gpio_set_dir(_data_pin, GPIO_OUT); 86 | gpio_put(_data_pin, false); 87 | sleep_us(3);// (spec 1-15us) 88 | gpio_set_dir(_data_pin, GPIO_IN); 89 | sleep_us(3);// (spec read within 15us) 90 | answer = gpio_get(_data_pin); 91 | sleep_us(45); 92 | return answer; 93 | } 94 | 95 | uint8_t One_wire::onewire_byte_in() { 96 | uint8_t answer = 0x00; 97 | int i; 98 | for (i = 0; i < 8; i++) { 99 | answer = answer >> 1;// shift over to make room for the next bit 100 | if (onewire_bit_in()) 101 | answer = (uint8_t) (answer | 0x80);// if the data port is high, make this bit a 1 102 | } 103 | return answer; 104 | } 105 | 106 | int One_wire::find_and_count_devices_on_bus() { 107 | found_addresses.clear(); 108 | _last_discrepancy = 0; // start search from begining 109 | _last_device = 0; 110 | while (search_rom_find_next()) { 111 | } 112 | return (int) found_addresses.size(); 113 | } 114 | 115 | rom_address_t One_wire::address_from_hex(const char *hex_address) { 116 | rom_address_t address = rom_address_t(); 117 | for (uint8_t i = 0; i < ROMSize; i++) { 118 | char buffer[3]; 119 | strncpy(buffer, &hex_address[i * 2], 2); 120 | buffer[2] = '\0'; 121 | address.rom[i] = (uint8_t) strtol(buffer, nullptr, 16); 122 | } 123 | return address; 124 | } 125 | 126 | rom_address_t &One_wire::get_address(int index) { 127 | return found_addresses[index]; 128 | } 129 | 130 | void One_wire::bit_write(uint8_t &value, int bit, bool set) { 131 | if (bit <= 7 && bit >= 0) { 132 | if (set) { 133 | value |= (1 << bit); 134 | } else { 135 | value &= ~(1 << bit); 136 | } 137 | } 138 | } 139 | 140 | void One_wire::single_device_read_rom(rom_address_t &rom_address) { 141 | if (!reset_check_for_device()) { 142 | return; 143 | } else { 144 | onewire_byte_out(ReadROMCommand); 145 | for (int bit_index = 0; bit_index < 64; bit_index++) { 146 | bool bit = onewire_bit_in(); 147 | bit_write((uint8_t &) rom_address.rom[bit_index / 8], (bit_index % 8), bit); 148 | } 149 | } 150 | } 151 | 152 | bool One_wire::search_rom_find_next() { 153 | 154 | 155 | int discrepancy_marker, rom_bit_index; 156 | bool bitA, bitB; 157 | uint8_t byte_counter, bit_mask; 158 | 159 | if (!reset_check_for_device()) { 160 | printf("Failed to reset one wire bus\n"); 161 | return false; 162 | } else { 163 | if (_last_device) { 164 | return false; // all devices found 165 | } 166 | rom_bit_index = 1; 167 | discrepancy_marker = 0; 168 | onewire_byte_out(SearchROMCommand); 169 | byte_counter = 0; 170 | bit_mask = 0x01; 171 | while (rom_bit_index <= 64) { 172 | bitA = onewire_bit_in(); 173 | bitB = onewire_bit_in(); 174 | if (bitA & bitB) { 175 | discrepancy_marker = 0;// data read error, this should never happen 176 | rom_bit_index = 0xFF; 177 | printf("Data read error - no devices on bus?\r\n"); 178 | } else { 179 | if (bitA | bitB) { 180 | // Set ROM bit to Bit_A 181 | if (bitA) { 182 | _search_ROM[byte_counter] = 183 | _search_ROM[byte_counter] | bit_mask;// Set ROM bit to one 184 | } else { 185 | _search_ROM[byte_counter] = 186 | _search_ROM[byte_counter] & ~bit_mask;// Set ROM bit to zero 187 | } 188 | } else { 189 | // both bits A and B are low, so there are two or more devices present 190 | if (rom_bit_index == _last_discrepancy) { 191 | _search_ROM[byte_counter] = 192 | _search_ROM[byte_counter] | bit_mask;// Set ROM bit to one 193 | } else { 194 | if (rom_bit_index > _last_discrepancy) { 195 | _search_ROM[byte_counter] = 196 | _search_ROM[byte_counter] & ~bit_mask;// Set ROM bit to zero 197 | discrepancy_marker = rom_bit_index; 198 | } else { 199 | if ((_search_ROM[byte_counter] & bit_mask) == 0x00) 200 | discrepancy_marker = rom_bit_index; 201 | } 202 | } 203 | } 204 | onewire_bit_out(_search_ROM[byte_counter] & bit_mask); 205 | rom_bit_index++; 206 | if (bit_mask & 0x80) { 207 | byte_counter++; 208 | bit_mask = 0x01; 209 | } else { 210 | bit_mask = bit_mask << 1; 211 | } 212 | } 213 | } 214 | _last_discrepancy = discrepancy_marker; 215 | if (rom_bit_index != 0xFF) { 216 | #ifdef _LIST_ROMS 217 | printf ("Found %02x%02x%02x%02x%02x%02x%02x%02x\n", 218 | _search_ROM[0], _search_ROM[1], _search_ROM[2], _search_ROM[3], 219 | _search_ROM[4], _search_ROM[5], _search_ROM[6], _search_ROM[7] 220 | ); 221 | #endif 222 | 223 | if (rom_checksum_error(_search_ROM)) {// Check the CRC 224 | printf("failed crc\r\n"); 225 | return false; 226 | } 227 | rom_address_t address{}; 228 | for (byte_counter = 0; byte_counter < 8; byte_counter++) { 229 | address.rom[byte_counter] = _search_ROM[byte_counter]; 230 | } 231 | found_addresses.push_back(address); 232 | _last_device = _last_discrepancy == 0; 233 | return true; 234 | } else { 235 | return false; 236 | } 237 | } 238 | } 239 | 240 | void One_wire::match_rom(rom_address_t &address) { 241 | int i; 242 | if (reset_check_for_device()) { 243 | onewire_byte_out(MatchROMCommand); 244 | for (i = 0; i < 8; i++) { 245 | onewire_byte_out(address.rom[i]); 246 | } 247 | } else { 248 | printf("match_rom failed\n"); 249 | } 250 | } 251 | 252 | void One_wire::skip_rom() { 253 | if (reset_check_for_device()) { 254 | onewire_byte_out(SkipROMCommand); 255 | } else { 256 | printf("skip_rom failed\n"); 257 | } 258 | } 259 | 260 | bool One_wire::rom_checksum_error(uint8_t *address) { 261 | uint8_t crc = 0x00; 262 | int i; 263 | for (i = 0; i < 7; i++) {// Only going to shift the lower 7 bytes 264 | crc = crc_byte(crc, address[i]); 265 | } 266 | // After 7 bytes CRC should equal the 8th byte (ROM CRC) 267 | return (crc != address[7]);// will return true if there is a CRC checksum mis-match 268 | } 269 | 270 | bool One_wire::ram_checksum_error() { 271 | uint8_t crc = 0x00; 272 | int i; 273 | for (i = 0; i < 8; i++) {// Only going to shift the lower 8 bytes 274 | crc = crc_byte(crc, ram[i]); 275 | } 276 | // After 8 bytes CRC should equal the 9th byte (RAM CRC) 277 | return (crc != ram[8]);// will return true if there is a CRC checksum mis-match 278 | } 279 | 280 | uint8_t One_wire::crc_byte(uint8_t crc, uint8_t byte) { 281 | int j; 282 | for (j = 0; j < 8; j++) { 283 | if ((byte & 0x01) ^ (crc & 0x01)) { 284 | // DATA ^ LSB CRC = 1 285 | crc = crc >> 1; 286 | // Set the MSB to 1 287 | crc = (uint8_t) (crc | 0x80); 288 | // Check bit 3 289 | if (crc & 0x04) { 290 | crc = (uint8_t) (crc & 0xFB);// Bit 3 is set, so clear it 291 | } else { 292 | crc = (uint8_t) (crc | 0x04);// Bit 3 is clear, so set it 293 | } 294 | // Check bit 4 295 | if (crc & 0x08) { 296 | crc = (uint8_t) (crc & 0xF7);// Bit 4 is set, so clear it 297 | } else { 298 | crc = (uint8_t) (crc | 0x08);// Bit 4 is clear, so set it 299 | } 300 | } else { 301 | // DATA ^ LSB CRC = 0 302 | crc = crc >> 1; 303 | // clear MSB 304 | crc = (uint8_t) (crc & 0x7F); 305 | // No need to check bits, with DATA ^ LSB CRC = 0, they will remain unchanged 306 | } 307 | byte = byte >> 1; 308 | } 309 | return crc; 310 | } 311 | 312 | int One_wire::convert_temperature(rom_address_t &address, bool wait, bool all) { 313 | int delay_time = 750;// Default delay time 314 | uint8_t resolution; 315 | if (all) 316 | skip_rom();// Skip ROM command, will convert for ALL devices, wait maximum time 317 | else { 318 | match_rom(address); 319 | if ((FAMILY_CODE == FAMILY_CODE_DS18B20) || (FAMILY_CODE == FAMILY_CODE_DS1822)) { 320 | resolution = (uint8_t) (ram[4] & 0x60); 321 | if (resolution == 0x00) // 9 bits 322 | delay_time = 94; 323 | if (resolution == 0x20) // 10 bits 324 | delay_time = 188; 325 | if (resolution == 0x40) // 11 bits. 326 | delay_time = 375; 327 | //Note 12bits uses the 750ms default 328 | } 329 | if (FAMILY_CODE == FAMILY_CODE_MAX31826) { 330 | delay_time = 150;// 12bit conversion 331 | } 332 | } 333 | 334 | onewire_byte_out(ConvertTempCommand);// perform temperature conversion 335 | if (_parasite_power) { 336 | if (_power_mosfet) { 337 | gpio_put(_parasite_pin, _power_polarity);// Parasite power strong pull up 338 | sleep_ms(delay_time); 339 | gpio_put(_parasite_pin, !_power_polarity); 340 | delay_time = 0; 341 | } else { 342 | gpio_set_dir(_data_pin, GPIO_OUT); 343 | gpio_put(_data_pin, true); 344 | sleep_ms(delay_time); 345 | gpio_set_dir(_data_pin, GPIO_IN); 346 | } 347 | } else { 348 | if (wait) { 349 | sleep_ms(delay_time); 350 | delay_time = 0; 351 | } 352 | } 353 | return delay_time; 354 | } 355 | 356 | void One_wire::read_scratch_pad(rom_address_t &address) { 357 | int i; 358 | match_rom(address); 359 | onewire_byte_out(ReadScratchPadCommand); 360 | for (i = 0; i < 9; i++) { 361 | ram[i] = onewire_byte_in(); 362 | } 363 | } 364 | 365 | bool One_wire::set_resolution(rom_address_t &address, unsigned int resolution) { 366 | bool answer = false; 367 | switch (FAMILY_CODE) { 368 | case FAMILY_CODE_DS18B20: 369 | case FAMILY_CODE_DS18S20: 370 | case FAMILY_CODE_DS1822: 371 | resolution = resolution - 9; 372 | if (resolution < 4) { 373 | resolution = resolution << 5; // align the bits 374 | ram[4] = (uint8_t) ((ram[4] & 0x60) | resolution);// mask out old data, insert new 375 | write_scratch_pad(address, (ram[2] << 8) + ram[3]); 376 | answer = true; 377 | } 378 | break; 379 | default: 380 | break; 381 | } 382 | return answer; 383 | } 384 | 385 | void One_wire::write_scratch_pad(rom_address_t &address, int data) { 386 | ram[3] = (uint8_t) data; 387 | ram[2] = (uint8_t) (data >> 8); 388 | match_rom(address); 389 | onewire_byte_out(WriteScratchPadCommand); 390 | onewire_byte_out(ram[2]);// T(H) 391 | onewire_byte_out(ram[3]);// T(L) 392 | if ((FAMILY_CODE == FAMILY_CODE_DS18S20) || (FAMILY_CODE == FAMILY_CODE_DS18B20) || 393 | (FAMILY_CODE == FAMILY_CODE_DS1822)) { 394 | onewire_byte_out(ram[4]);// Configuration register 395 | } 396 | } 397 | 398 | uint64_t One_wire::to_uint64(rom_address_t &address) { 399 | return ((uint64_t)address.rom[7]) | 400 | (((uint64_t)address.rom[6]) << 8 ) | 401 | (((uint64_t)address.rom[5]) << 16) | 402 | (((uint64_t)address.rom[4]) << 24) | 403 | (((uint64_t)address.rom[3]) << 32) | 404 | (((uint64_t)address.rom[2]) << 40) | 405 | (((uint64_t)address.rom[1]) << 48) | 406 | (((uint64_t)address.rom[0]) << 56); 407 | } 408 | 409 | float One_wire::temperature(rom_address_t &address, bool convert_to_fahrenheit) { 410 | float answer, remaining_count, count_per_degree; 411 | int reading; 412 | read_scratch_pad(address); 413 | if (ram_checksum_error()) 414 | // Indicate we got a CRC error 415 | answer = invalid_conversion; 416 | else { 417 | reading = (ram[1] << 8) + ram[0]; 418 | if (reading & 0x8000) { // negative degrees C 419 | reading = 0 - ((reading ^ 0xffff) + 1);// 2's comp then convert to signed int 420 | } 421 | 422 | answer = (float) reading; 423 | 424 | switch (FAMILY_CODE) { 425 | case FAMILY_CODE_MAX31826: 426 | case FAMILY_CODE_DS18B20: 427 | case FAMILY_CODE_DS1822: 428 | answer = answer / 16.0f; 429 | break; 430 | case FAMILY_CODE_DS18S20: 431 | remaining_count = ram[6]; 432 | count_per_degree = ram[7]; 433 | answer = (float) (std::floor(answer / 2.0f) - 0.25f + 434 | (count_per_degree - remaining_count) / count_per_degree); 435 | break; 436 | default: 437 | printf("Unsupported device family\n"); 438 | break; 439 | } 440 | 441 | if (convert_to_fahrenheit) { 442 | answer = answer * 9.0f / 5.0f + 32.0f; 443 | } 444 | } 445 | return answer; 446 | } 447 | 448 | bool One_wire::power_supply_available(rom_address_t &address, bool all) { 449 | if (all) { 450 | skip_rom(); 451 | } else { 452 | match_rom(address); 453 | } 454 | onewire_byte_out(ReadPowerSupplyCommand); 455 | return onewire_bit_in(); 456 | } 457 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | add_definitions(-DMOCK_PICO_PI) 4 | 5 | project(tests) 6 | 7 | set(CMAKE_CXX_STANDARD 20) 8 | 9 | find_package(Catch2 REQUIRED) 10 | 11 | include_directories(../api) 12 | 13 | add_executable(tests test_one_wire.cpp pico_pi_mocks.cpp ../source/one_wire.cpp) 14 | target_link_libraries(tests PRIVATE Catch2::Catch2WithMain) 15 | 16 | include(CTest) 17 | include(Catch) 18 | catch_discover_tests(tests) -------------------------------------------------------------------------------- /test/pico_pi_mocks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "pico_pi_mocks.h" 7 | 8 | #define STRING_STACK_LIMIT 100 9 | 10 | std::vector mockLastCommands; 11 | uint8_t mockLastCommand;//Stores the last 8 bits written to the bus 12 | int mockReadBitPos; 13 | size_t mockReadBitsLength; 14 | const char *mockReadBits; 15 | int waitTime; 16 | int writeCount; 17 | bool gpio_out_direction[30]; 18 | bool gpio_initialised[30]{false}; 19 | 20 | void gpio_init(uint gpio) { 21 | gpio_initialised[gpio] = true; 22 | } 23 | 24 | void gpio_put(uint gpio, bool value) { 25 | REQUIRE(gpio_initialised[gpio] == true); 26 | REQUIRE(gpio_out_direction[gpio] == true); 27 | if (value == 0) { 28 | waitTime = 0; 29 | } else { 30 | if ((writeCount > 0) && (writeCount % 8 == 0)) { 31 | mockLastCommands.push_back(mockLastCommand); 32 | mockLastCommand = 0; 33 | } 34 | if (waitTime > 1 && waitTime <= 15) {//Spec for write bit 1 35 | mockLastCommand >>= 1; 36 | mockLastCommand |= (1 << 7); 37 | } 38 | if (waitTime >= 10 && waitTime <= 120) {//Spec for write bit 0 39 | mockLastCommand >>= 1; 40 | mockLastCommand &= ~(1 << 7); 41 | } 42 | if (waitTime > 480) {//Spec for reset 43 | mockLastCommands.push_back(mockLastCommand); 44 | mockLastCommand = 0; 45 | writeCount = 0; 46 | } 47 | writeCount++; 48 | } 49 | } 50 | 51 | bool gpio_get(uint gpio) { 52 | int ret = 1; 53 | REQUIRE(gpio_initialised[gpio] == true); 54 | REQUIRE(gpio_out_direction[gpio] == false); 55 | if (mockReadBitPos < mockReadBitsLength) { 56 | if (mockReadBits[mockReadBitPos] == '0') { 57 | ret = 0; 58 | } 59 | mockReadBitPos++; 60 | } else { 61 | printf("Ran out of mock data\n"); 62 | } 63 | return ret; 64 | } 65 | 66 | void gpio_set_dir(uint gpio, bool out) { 67 | REQUIRE(gpio_initialised[gpio] == true); 68 | gpio_out_direction[gpio] = out; 69 | } 70 | 71 | void sleep_us(int us) { 72 | waitTime += us; 73 | } 74 | 75 | void sleep_ms(int ms) { 76 | waitTime += ms * 1000; 77 | } 78 | -------------------------------------------------------------------------------- /test/pico_pi_mocks.h: -------------------------------------------------------------------------------- 1 | #ifndef PICO_PI_MOCKS_H 2 | #define PICO_PI_MOCKS_H 3 | 4 | #include 5 | #include 6 | 7 | #define GPIO_OUT 1 8 | #define GPIO_IN 0 9 | 10 | typedef unsigned int uint; 11 | 12 | extern std::vector mockLastCommands; 13 | extern uint8_t mockLastCommand; 14 | extern int mockReadBitPos; 15 | extern size_t mockReadBitsLength; 16 | extern const char *mockReadBits; 17 | extern int writeCount; 18 | 19 | void sleep_us(int us); 20 | 21 | void sleep_ms(int ms); 22 | 23 | void gpio_init(uint gpio); 24 | 25 | void gpio_set_dir(uint gpio, bool out); 26 | 27 | bool gpio_get(uint gpio); 28 | 29 | void gpio_put(uint gpio, bool value); 30 | 31 | #endif // PICO_PI_MOCKS_H 32 | -------------------------------------------------------------------------------- /test/test_one_wire.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "one_wire.h" 7 | 8 | extern std::vector found_addresses; 9 | 10 | One_wire one_wire(0); //NOLINT 11 | 12 | void resetLastCommands() { 13 | mockLastCommand = 0; 14 | mockLastCommands.clear(); 15 | writeCount = 0; 16 | } 17 | 18 | void initialiseModule() { 19 | mockReadBitPos = 0; 20 | mockReadBits = "01"; 21 | mockReadBitsLength = strlen(mockReadBits); 22 | 23 | one_wire.init(); 24 | } 25 | 26 | void test_resolution(unsigned int resolution, uint8_t expected) { 27 | initialiseModule(); 28 | resetLastCommands(); 29 | 30 | mockReadBitPos = 0; 31 | //28 62 24 C7 03 00 00 0F 32 | mockReadBits = "0" 33 | "00010100" 34 | "01000110" 35 | "00100100" 36 | "11100011" 37 | "11000000" 38 | "00000000" 39 | "00000000" 40 | "11110000"; 41 | mockReadBitsLength = strlen(mockReadBits); 42 | 43 | rom_address_t address = One_wire::address_from_hex("286224C70300000F"); 44 | one_wire.set_resolution(address, resolution); 45 | 46 | REQUIRE(mockLastCommands[0] == MatchROMCommand); 47 | REQUIRE(mockLastCommands[1] == 0x28);//address 48 | REQUIRE(mockLastCommands[2] == 0x62);//address 49 | REQUIRE(mockLastCommands[3] == 0x24);//address 50 | REQUIRE(mockLastCommands[4] == 0xC7);//address 51 | REQUIRE(mockLastCommands[5] == 0x03);//address 52 | REQUIRE(mockLastCommands[6] == 0x00);//address 53 | REQUIRE(mockLastCommands[7] == 0x00);//address 54 | REQUIRE(mockLastCommands[8] == 0x0F);//address 55 | REQUIRE(mockLastCommands[9] == WriteScratchPadCommand); 56 | REQUIRE(mockLastCommands[10] == 0x0); 57 | REQUIRE(mockLastCommands[11] == 0x0); 58 | REQUIRE(mockLastCommand == expected); 59 | } 60 | 61 | TEST_CASE("Init", "[one_wire]") { 62 | resetLastCommands(); 63 | initialiseModule(); 64 | 65 | REQUIRE(mockLastCommand == ReadPowerSupplyCommand); 66 | } 67 | 68 | TEST_CASE("Set Resolution 9", "[one_wire]") { 69 | test_resolution(9, 0x0); 70 | } 71 | 72 | TEST_CASE("Set Resolution 10", "[one_wire]") { 73 | test_resolution(10, 0x20); 74 | } 75 | 76 | TEST_CASE("Set Resolution 11", "[one_wire]") { 77 | test_resolution(11, 0x40); 78 | } 79 | 80 | TEST_CASE("Set Resolution 12", "[one_wire]") { 81 | test_resolution(12, 0x60); 82 | } 83 | 84 | TEST_CASE("Read ROM", "[one_wire]") { 85 | resetLastCommands(); 86 | mockReadBitPos = 0; 87 | //28 62 24 C7 03 00 00 0F 88 | mockReadBits = "0" 89 | "00010100" 90 | "01000110" 91 | "00100100" 92 | "11100011" 93 | "11000000" 94 | "00000000" 95 | "00000000" 96 | "11110000"; 97 | mockReadBitsLength = strlen(mockReadBits); 98 | rom_address_t address{}; 99 | one_wire.single_device_read_rom(address); 100 | REQUIRE(address.rom[0] == 0x28); 101 | REQUIRE(address.rom[1] == 0x62); 102 | REQUIRE(address.rom[2] == 0x24); 103 | REQUIRE(address.rom[3] == 0xC7); 104 | REQUIRE(address.rom[4] == 0x03); 105 | REQUIRE(address.rom[5] == 0x00); 106 | REQUIRE(address.rom[6] == 0x00); 107 | REQUIRE(address.rom[7] == 0x0F); 108 | REQUIRE(mockLastCommand == ReadROMCommand); 109 | } 110 | 111 | TEST_CASE("Convert Temperature", "[one_wire]") { 112 | initialiseModule(); 113 | resetLastCommands(); 114 | mockReadBitPos = 0; 115 | mockReadBits = "0"; 116 | mockReadBitsLength = strlen(mockReadBits); 117 | rom_address_t address{}; 118 | one_wire.convert_temperature(address, false, true); 119 | REQUIRE(mockLastCommand == ConvertTempCommand); 120 | REQUIRE(mockLastCommands[0] == SkipROMCommand); 121 | } 122 | 123 | TEST_CASE("ReadTemperature", "[one_wire]") { 124 | initialiseModule(); 125 | resetLastCommands(); 126 | mockReadBitPos = 0; 127 | mockReadBits = "0" 128 | "10100000"//0x05 129 | "10000000"//0x01 130 | "11010010"//0x4B 131 | "01100010"//0x46 132 | "11111110"//0x7F 133 | "11111111"//0xFF 134 | "11010000"//0x0B 135 | "00001000"//0x10 136 | "10110011"//0xCD 137 | ; 138 | mockReadBitsLength = strlen(mockReadBits); 139 | 140 | rom_address_t address = One_wire::address_from_hex("286224C70300000F"); 141 | float temperature = one_wire.temperature(address); 142 | REQUIRE(temperature == 16.3125); 143 | REQUIRE(mockLastCommand == ReadScratchPadCommand); 144 | REQUIRE(mockLastCommands[0] == MatchROMCommand); 145 | REQUIRE(mockLastCommands[1] == 0x28); 146 | REQUIRE(mockLastCommands[2] == 0x62); 147 | REQUIRE(mockLastCommands[3] == 0x24); 148 | REQUIRE(mockLastCommands[4] == 0xC7); 149 | REQUIRE(mockLastCommands[5] == 0x03); 150 | REQUIRE(mockLastCommands[6] == 0x00); 151 | REQUIRE(mockLastCommands[7] == 0x00); 152 | REQUIRE(mockLastCommands[8] == 0x0F); 153 | } 154 | 155 | TEST_CASE("ReadTemperature125", "[one_wire]") { 156 | initialiseModule(); 157 | resetLastCommands(); 158 | mockReadBitPos = 0; 159 | mockReadBits = "0" 160 | "00001011"//0xD0 161 | "11100000"//0x07 162 | "11010010"//0x4B 163 | "01100010"//0x46 164 | "11111110"//0x7F 165 | "11111111"//0xFF 166 | "11010000"//0x0B 167 | "00001000"//0x10 168 | "01011001"//0x9A 169 | ; 170 | mockReadBitsLength = strlen(mockReadBits); 171 | 172 | rom_address_t address = One_wire::address_from_hex("286224C70300000F"); 173 | float temperature = one_wire.temperature(address, false); 174 | REQUIRE(temperature == 125.0); 175 | REQUIRE(mockLastCommands[0] == MatchROMCommand); 176 | REQUIRE(mockLastCommands[1] == 0x28); 177 | REQUIRE(mockLastCommands[2] == 0x62); 178 | REQUIRE(mockLastCommands[3] == 0x24); 179 | REQUIRE(mockLastCommands[4] == 0xC7); 180 | REQUIRE(mockLastCommands[5] == 0x03); 181 | REQUIRE(mockLastCommands[6] == 0x00); 182 | REQUIRE(mockLastCommands[7] == 0x00); 183 | REQUIRE(mockLastCommands[8] == 0x0F); 184 | REQUIRE(mockLastCommand == ReadScratchPadCommand); 185 | } 186 | 187 | TEST_CASE("SearchROMSingleDevice", "[one_wire]") { 188 | /** 189 | * Search ROM command causes all 1-wire devices to respond simultaneously with their addresses 190 | * as pairs of bits for each bit of the address, first the true bit then the inversion. 191 | * As each bit is read back if all devices have the same value we just move to the next bit. 192 | * When there is a difference each device will hold the line down at different times to indicate 193 | * a zero bit for the true case (device A) and for the inversion case (device B). 194 | * As we are reading each bit of the address we are also writing them back to the bus, only 195 | * devices that match that address keep responding, so each time we have conflicting devices 196 | * we pick one and carry on. 197 | */ 198 | found_addresses.clear(); 199 | initialiseModule(); 200 | resetLastCommands(); 201 | mockReadBitPos = 0; 202 | mockReadBits = "0" 203 | "0101011001100101" 204 | "0110010101101001" 205 | "0101100101100101" 206 | "1010100101011010" 207 | "1010010101010101" 208 | "0101010101010101" 209 | "0101010101010101" 210 | "1010101001010101" 211 | "0" 212 | "0101011001100101" 213 | "0110010101101001" 214 | "0101100101100101" 215 | "1010100101011010" 216 | "1010010101010101" 217 | "0101010101010101" 218 | "0101010101010101" 219 | "1010101001010101"; 220 | mockReadBitsLength = strlen(mockReadBits); 221 | int found = one_wire.find_and_count_devices_on_bus(); 222 | REQUIRE(found == 1); 223 | REQUIRE(mockLastCommands[0] == SearchROMCommand); 224 | REQUIRE(mockLastCommands[1] == 0x28); 225 | REQUIRE(mockLastCommands[2] == 0x62); 226 | REQUIRE(mockLastCommands[3] == 0x24); 227 | REQUIRE(mockLastCommands[4] == 0xC7); 228 | REQUIRE(mockLastCommands[5] == 0x03); 229 | REQUIRE(mockLastCommands[6] == 0x00); 230 | REQUIRE(mockLastCommands[7] == 0x00); 231 | REQUIRE(mockLastCommand == 0x0F); 232 | 233 | rom_address_t ROM_address = One_wire::get_address(0); 234 | REQUIRE(ROM_address.rom[0] == 0x28); 235 | REQUIRE(ROM_address.rom[1] == 0x62); 236 | REQUIRE(ROM_address.rom[2] == 0x24); 237 | REQUIRE(ROM_address.rom[3] == 0xC7); 238 | REQUIRE(ROM_address.rom[4] == 0x03); 239 | REQUIRE(ROM_address.rom[5] == 0x00); 240 | REQUIRE(ROM_address.rom[6] == 0x00); 241 | REQUIRE(ROM_address.rom[7] == 0x0F); 242 | } 243 | 244 | TEST_CASE("SearchROMSecondDevice", "[one_wire]") { 245 | found_addresses.clear(); 246 | initialiseModule(); 247 | resetLastCommands(); 248 | mockReadBitPos = 0; 249 | //28 08 81 FB 07 00 00 26 - first 250 | //28 62 24 C7 03 00 00 0F - second 251 | mockReadBits = "0" 252 | "0101011001100101" 253 | "0100011001010101"// Second bit is first difference, indicated with double zero's 254 | "1001010101010110" 255 | "1010011010101010" 256 | "1010100101010101" 257 | "0101010101010101" 258 | "0101010101010101" 259 | "0110100101100101" 260 | "0" 261 | "0101011001100101" 262 | "0100010101101001"// Second bit is first difference, indicated with double zero's 263 | "0101100101100101" 264 | "1010100101011010" 265 | "1010010101010101" 266 | "0101010101010101" 267 | "0101010101010101" 268 | "1010101001010101" 269 | "0" 270 | "0101011001100101" 271 | "0110010101101001" 272 | "0101100101100101" 273 | "1010100101011010" 274 | "1010010101010101" 275 | "0101010101010101" 276 | "0101010101010101" 277 | "1010101001010101"; 278 | mockReadBitsLength = strlen(mockReadBits); 279 | 280 | int found = one_wire.find_and_count_devices_on_bus(); 281 | REQUIRE(found == 2); 282 | REQUIRE(mockLastCommands[0] == SearchROMCommand); 283 | REQUIRE(mockLastCommands[1] == 0x28); 284 | REQUIRE(mockLastCommands[2] == 0x08); 285 | REQUIRE(mockLastCommands[3] == 0x81); 286 | REQUIRE(mockLastCommands[4] == 0xFB); 287 | REQUIRE(mockLastCommands[5] == 0x07); 288 | REQUIRE(mockLastCommands[6] == 0x00); 289 | REQUIRE(mockLastCommands[7] == 0x00); 290 | REQUIRE(mockLastCommands[8] == 0x26); 291 | REQUIRE(mockLastCommands[9] == SearchROMCommand); 292 | REQUIRE(mockLastCommands[10] == 0x28); 293 | REQUIRE(mockLastCommands[11] == 0x62); 294 | REQUIRE(mockLastCommands[12] == 0x24); 295 | REQUIRE(mockLastCommands[13] == 0xC7); 296 | REQUIRE(mockLastCommands[14] == 0x03); 297 | REQUIRE(mockLastCommands[15] == 0x00); 298 | REQUIRE(mockLastCommands[16] == 0x00); 299 | REQUIRE(mockLastCommand == 0x0F); 300 | 301 | rom_address_t ROM_address = One_wire::get_address(0); 302 | REQUIRE(ROM_address.rom[0] == 0x28); 303 | REQUIRE(ROM_address.rom[1] == 0x08); 304 | REQUIRE(ROM_address.rom[2] == 0x81); 305 | REQUIRE(ROM_address.rom[3] == 0xFB); 306 | REQUIRE(ROM_address.rom[4] == 0x07); 307 | REQUIRE(ROM_address.rom[5] == 0x00); 308 | REQUIRE(ROM_address.rom[6] == 0x00); 309 | REQUIRE(ROM_address.rom[7] == 0x26); 310 | 311 | ROM_address = One_wire::get_address(1); 312 | REQUIRE(ROM_address.rom[0] == 0x28); 313 | REQUIRE(ROM_address.rom[1] == 0x62); 314 | REQUIRE(ROM_address.rom[2] == 0x24); 315 | REQUIRE(ROM_address.rom[3] == 0xC7); 316 | REQUIRE(ROM_address.rom[4] == 0x03); 317 | REQUIRE(ROM_address.rom[5] == 0x00); 318 | REQUIRE(ROM_address.rom[6] == 0x00); 319 | REQUIRE(ROM_address.rom[7] == 0x0F); 320 | } 321 | 322 | 323 | TEST_CASE("ListAllAttachedDevices", "[one_wire]") { 324 | found_addresses.clear(); 325 | resetLastCommands(); 326 | mockReadBitPos = 0; 327 | //28 08 81 FB 07 00 00 26 - first 328 | //28 62 24 C7 03 00 00 0F - second 329 | mockReadBits = "0" 330 | "0101011001100101" 331 | "0100011001010101"// Second bit is first difference, indicated with double zero's 332 | "1001010101010110" 333 | "1010011010101010" 334 | "1010100101010101" 335 | "0101010101010101" 336 | "0101010101010101" 337 | "0110100101100101" 338 | "0" 339 | "0101011001100101" 340 | "0100010101101001"// Second bit is first difference, indicated with double zero's 341 | "0101100101100101" 342 | "1010100101011010" 343 | "1010010101010101" 344 | "0101010101010101" 345 | "0101010101010101" 346 | "1010101001010101" 347 | "0" 348 | "0101011001100101" 349 | "0110010101101001" 350 | "0101100101100101" 351 | "1010100101011010" 352 | "1010010101010101" 353 | "0101010101010101" 354 | "0101010101010101" 355 | "1010101001010101"; 356 | mockReadBitsLength = strlen(mockReadBits); 357 | 358 | one_wire.find_and_count_devices_on_bus(); 359 | 360 | rom_address_t ROM_address = One_wire::get_address(0); 361 | REQUIRE(ROM_address.rom[0] == 0x28); 362 | REQUIRE(ROM_address.rom[1] == 0x08); 363 | REQUIRE(ROM_address.rom[2] == 0x81); 364 | REQUIRE(ROM_address.rom[3] == 0xFB); 365 | REQUIRE(ROM_address.rom[4] == 0x07); 366 | REQUIRE(ROM_address.rom[5] == 0x00); 367 | REQUIRE(ROM_address.rom[6] == 0x00); 368 | REQUIRE(ROM_address.rom[7] == 0x26); 369 | 370 | ROM_address = One_wire::get_address(1); 371 | REQUIRE(ROM_address.rom[0] == 0x28); 372 | REQUIRE(ROM_address.rom[1] == 0x62); 373 | REQUIRE(ROM_address.rom[2] == 0x24); 374 | REQUIRE(ROM_address.rom[3] == 0xC7); 375 | REQUIRE(ROM_address.rom[4] == 0x03); 376 | REQUIRE(ROM_address.rom[5] == 0x00); 377 | REQUIRE(ROM_address.rom[6] == 0x00); 378 | REQUIRE(ROM_address.rom[7] == 0x0F); 379 | } --------------------------------------------------------------------------------