#include "one_wire.h"

#define OW_SLOT_A     6
#define OW_SLOT_B    64
#define OW_SLOT_C    60
#define OW_SLOT_D    10
#define OW_SLOT_E     9
#define OW_SLOT_F    55
#define OW_SLOT_G    10
#define OW_SLOT_H   480
#define OW_SLOT_I    70
#define OW_SLOT_J   410

#define DRIVE_DQ(x) ow->cb.drive_dq(ow->user_data, x)
#define DELAY_US(x) ow->cb.delay_usec(ow->user_data, x)
#define READ_DQ()   ow->cb.read_dq(ow->user_data)

static inline uint8_t onewire_op_reset(onewire_t *ow) {
    uint8_t sample_result;

    // Delay G
    DRIVE_DQ(1);
    DELAY_US(OW_SLOT_G);

    // Drive bus low, delay H
    DRIVE_DQ(0);
    DELAY_US(OW_SLOT_H);

    // Release bus, delay I
    DRIVE_DQ(1);
    DELAY_US(OW_SLOT_I);

    // Sample bus, delay J
    sample_result = READ_DQ();
    DELAY_US(OW_SLOT_J);

    return sample_result;
}

static inline onewire_ret_t onewire_op_write_one_bit(onewire_t *ow) {

    // Drive bus low, delay A
    DRIVE_DQ(0);
    DELAY_US(OW_SLOT_A);

    // Release bus, delay B
    DRIVE_DQ(1);
    DELAY_US(OW_SLOT_B);

    return OW_OK;
}

static inline onewire_ret_t onewire_op_write_zero_bit(onewire_t *ow) {

    // Drive bus low, delay C
    DRIVE_DQ(0);
    DELAY_US(OW_SLOT_C);

    // Release bus, delay D
    DRIVE_DQ(1);
    DELAY_US(OW_SLOT_D);

    return OW_OK;
}

static inline uint8_t onewire_op_read_bit(onewire_t *ow) {
    uint8_t sample_value;

    // Drive bus low, delay A
    DRIVE_DQ(0);
    DELAY_US(OW_SLOT_A);

    // Release bus, delay E
    DRIVE_DQ(1);
    DELAY_US(OW_SLOT_E);

    // Sample bus to read bit from slave, delay F
    sample_value = READ_DQ();
    DELAY_US(OW_SLOT_F);

    return sample_value;
}

uint8_t onewire_bus_reset(onewire_t *ow) {
    uint8_t device_response = onewire_op_reset(ow);

    return device_response ? 0 : 1;
}

onewire_ret_t onewire_bus_write_byte(onewire_t *ow, uint8_t byte) {
    for(uint8_t i = 0; i < 8; i++) {
        if(byte & 0x01) {
            onewire_op_write_one_bit(ow);
        }
        else {
            onewire_op_write_zero_bit(ow);
        }

        byte >>= 1U;
    }

    return OW_OK;
}

uint8_t onewire_bus_read_byte(onewire_t *ow) {
    uint8_t result = 0x00;

    for(uint8_t i = 0; i < 8; i++) {
        result >>= 1U;
        if(onewire_op_read_bit(ow)) {
            result |= 0x80U;
        }
    }

    return result;
}

onewire_ret_t onewire_bus_search_devices(onewire_t *ow) {
    onewire_bus_write_byte(ow, 0xF0); // Search ROM command.

    // Perform a binary search on the bus

    return OW_OK;
}

