#include "one_wire_master.h" #include "one_wire_timings.h" OneWireMaster::OneWireMaster(const GpioPin* one_wire_gpio) { gpio = one_wire_gpio; reset_search(); } OneWireMaster::~OneWireMaster() { stop(); } void OneWireMaster::start(void) { hal_gpio_init(gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); } void OneWireMaster::stop(void) { hal_gpio_init(gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } void OneWireMaster::reset_search() { // reset the search state last_discrepancy = 0; last_device_flag = false; last_family_discrepancy = 0; for(int i = 7;; i--) { saved_rom[i] = 0; if(i == 0) break; } } void OneWireMaster::target_search(uint8_t family_code) { // set the search state to find SearchFamily type devices saved_rom[0] = family_code; for(uint8_t i = 1; i < 8; i++) saved_rom[i] = 0; last_discrepancy = 64; last_family_discrepancy = 0; last_device_flag = false; } uint8_t OneWireMaster::search(uint8_t* newAddr, bool search_mode) { uint8_t id_bit_number; uint8_t last_zero, rom_byte_number, search_result; uint8_t id_bit, cmp_id_bit; unsigned char rom_byte_mask, search_direction; // initialize for search id_bit_number = 1; last_zero = 0; rom_byte_number = 0; rom_byte_mask = 1; search_result = 0; // if the last call was not the last one if(!last_device_flag) { // 1-Wire reset if(!reset()) { // reset the search last_discrepancy = 0; last_device_flag = false; last_family_discrepancy = 0; return false; } // issue the search command if(search_mode == true) { write(0xF0); // NORMAL SEARCH } else { write(0xEC); // CONDITIONAL SEARCH } // loop to do the search do { // read a bit and its complement id_bit = read_bit(); cmp_id_bit = read_bit(); // check for no devices on 1-wire if((id_bit == 1) && (cmp_id_bit == 1)) break; else { // all devices coupled have 0 or 1 if(id_bit != cmp_id_bit) search_direction = id_bit; // bit write value for search else { // if this discrepancy if before the Last Discrepancy // on a previous next then pick the same as last time if(id_bit_number < last_discrepancy) search_direction = ((saved_rom[rom_byte_number] & rom_byte_mask) > 0); else // if equal to last pick 1, if not then pick 0 search_direction = (id_bit_number == last_discrepancy); // if 0 was picked then record its position in LastZero if(search_direction == 0) { last_zero = id_bit_number; // check for Last discrepancy in family if(last_zero < 9) last_family_discrepancy = last_zero; } } // set or clear the bit in the ROM byte rom_byte_number // with mask rom_byte_mask if(search_direction == 1) saved_rom[rom_byte_number] |= rom_byte_mask; else saved_rom[rom_byte_number] &= ~rom_byte_mask; // serial number search direction write bit write_bit(search_direction); // increment the byte counter id_bit_number // and shift the mask rom_byte_mask id_bit_number++; rom_byte_mask <<= 1; // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask if(rom_byte_mask == 0) { rom_byte_number++; rom_byte_mask = 1; } } } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 // if the search was successful then if(!(id_bit_number < 65)) { // search successful so set last_Discrepancy, last_device_flag, search_result last_discrepancy = last_zero; // check for last device if(last_discrepancy == 0) last_device_flag = true; search_result = true; } } // if no device found then reset counters so next 'search' will be like a first if(!search_result || !saved_rom[0]) { last_discrepancy = 0; last_device_flag = false; last_family_discrepancy = 0; search_result = false; } else { for(int i = 0; i < 8; i++) newAddr[i] = saved_rom[i]; } return search_result; } bool OneWireMaster::reset(void) { uint8_t r; uint8_t retries = 125; // wait until the gpio is high hal_gpio_write(gpio, true); do { if(--retries == 0) return 0; delay_us(2); } while(!hal_gpio_read(gpio)); // pre delay delay_us(OneWireTiming::RESET_DELAY_PRE); // drive low hal_gpio_write(gpio, false); delay_us(OneWireTiming::RESET_DRIVE); // release hal_gpio_write(gpio, true); delay_us(OneWireTiming::RESET_RELEASE); // read and post delay r = !hal_gpio_read(gpio); delay_us(OneWireTiming::RESET_DELAY_POST); return r; } bool OneWireMaster::read_bit(void) { bool result; // drive low hal_gpio_write(gpio, false); delay_us(OneWireTiming::READ_DRIVE); // release hal_gpio_write(gpio, true); delay_us(OneWireTiming::READ_RELEASE); // read and post delay result = hal_gpio_read(gpio); delay_us(OneWireTiming::READ_DELAY_POST); return result; } void OneWireMaster::write_bit(bool value) { if(value) { // drive low hal_gpio_write(gpio, false); delay_us(OneWireTiming::WRITE_1_DRIVE); // release hal_gpio_write(gpio, true); delay_us(OneWireTiming::WRITE_1_RELEASE); } else { // drive low hal_gpio_write(gpio, false); delay_us(OneWireTiming::WRITE_0_DRIVE); // release hal_gpio_write(gpio, true); delay_us(OneWireTiming::WRITE_0_RELEASE); } } uint8_t OneWireMaster::read(void) { uint8_t result = 0; for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { if(read_bit()) { result |= bitMask; } } return result; } void OneWireMaster::read_bytes(uint8_t* buffer, uint16_t count) { for(uint16_t i = 0; i < count; i++) { buffer[i] = read(); } } void OneWireMaster::write(uint8_t value) { uint8_t bitMask; for(bitMask = 0x01; bitMask; bitMask <<= 1) { write_bit((bitMask & value) ? 1 : 0); } } void OneWireMaster::skip(void) { write(0xCC); }