Поиск устройств на шине 1-wire

Posted on February 20, 2016 with tags: rust.

Поиск устройств на шине 1-wire считается делом не простым и замысловатым. Причиной этого является 64-битный размер идентификатора (на самом деле 8-бит это CRC, но в данном случае это не играет роли) и опросить все возможные идентификаторы на предмет их присутствия на шине за вменяемое время не представляется возможным.

// Пишем функции — затычки для взаимодействия с несуществующей у нас переферией.
fn one_wire_reset(){}
fn is_presance() -> bool { true }
fn one_wire_write( c: u8 ){}
fn read_bit() -> u8 { 1 }
fn read_unbit() -> u8 { 0 }

struct SearchState {
    last_device_flag: u8,
    last_discrepancy: u8,
    search_direction: u8,
    rom_no: u64
}

enum SearchResult {
    NotFound,
    Rom( u64 )
}

fn search_rom( state: &mut SearchState ) -> SearchResult
{
    let mut last_zero: u8 = 0;
    let mut result        = SearchResult::NotFound;

// Сбрасываем шину.
    one_wire_reset();

    if is_presance() && state.last_device_flag != 1
    {

// Запускаем процесс поиска.
        one_wire_write( 0x0F );

        for id_bit_number in 1..64 {
            let id_bit     = read_bit();
            let cmp_id_bit = read_unbit();

            if id_bit == 1 && cmp_id_bit == 1
            {
                break;
            }

            state.search_direction =
                match id_bit_number {
                    _ if id_bit != cmp_id_bit                    => id_bit,
                    _ if id_bit_number == state.last_discrepancy => 1,
                    _ if id_bit_number > state.last_discrepancy  => 0,
                    _                                            =>
                        if state.rom_no & (1 << id_bit_number as u64) == 0 { 0 } else { 1 }
                };

            if state.search_direction == 0
            {
                last_zero = id_bit_number;
                state.rom_no &= !( 1 << id_bit_number as u64 );
            }
            else
            {
                state.rom_no |= 1 << id_bit_number as u64;
            }

// Отправляем устройствам бит выбранного направления обхода.
            one_wire_write( state.search_direction );

            if id_bit_number == 64
            {
                result = SearchResult::Rom( state.rom_no );
            }
        }
    }

    match result {
        SearchResult::Rom( _ ) =>
        {
            state.last_discrepancy = last_zero;

            if state.last_discrepancy == 0 { state.last_device_flag = 1 }
        }
        SearchResult::NotFound =>
        {
            state.last_discrepancy = 0;
            state.last_device_flag = 0;
        }
    }

    return result;
}

fn main()
{
// Создаём начальный стейт нашего поиска.
    let mut state =
                SearchState {
                    last_device_flag: 0,
                    last_discrepancy: 0,
                    search_direction: 0,
                    rom_no: 0
                };

// Ищем устройства до тех пор пока они находятся.
    loop {
        match search_rom( &mut state ) {
            SearchResult::Rom( w ) => println!( "{}", w ),
            SearchResult::NotFound => break
        }
    }
}