diff --git a/DS2482_HAL.c b/DS2482_HAL.c
new file mode 100644
index 0000000..10710e5
--- /dev/null
+++ b/DS2482_HAL.c
@@ -0,0 +1,472 @@
+#include "DS2482_HAL.h"
+#include "errors.h"
+#include <stdint.h>
+
+static I2C_HandleTypeDef* hi2c;
+
+HAL_StatusTypeDef ds2482_init(I2C_HandleTypeDef* handle) {
+    hi2c = handle;
+
+    HAL_StatusTypeDef status = ds2482_reset();
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    status = ds2482_write_config(DS2482_CONFIG_APU);
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    uint8_t config;
+    status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, &config, 1, DS2482_TIMEOUT_I2C);
+    if (status != HAL_OK) {
+        return status;
+    } else if (config != DS2482_CONFIG_APU) {
+        return HAL_ERROR;
+    }
+
+    return HAL_OK;
+}
+
+HAL_StatusTypeDef ds2482_reset() {
+    uint8_t data[1] = {DS2482_CMD_RESET};
+    return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+}
+
+HAL_StatusTypeDef ds2482_write_config(uint8_t config) {
+    uint8_t data[2] = {DS2482_CMD_WRITE_CONFIG, config | (~config << 4)};
+    return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+}
+
+HAL_StatusTypeDef ds2482_set_read_ptr(uint8_t read_ptr) {
+    uint8_t data[2] = {DS2482_CMD_SET_READ_PTR, read_ptr};
+    return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+}
+
+HAL_StatusTypeDef ds2482_1w_reset() {
+    uint8_t data[1] = {DS2482_CMD_1W_RESET};
+    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+    if (status != HAL_OK) {
+        return status;
+    }
+    DS2482_Status status_reg = {.BUSY = 1};
+    uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W;
+    do {
+        status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C);
+        if (status != HAL_OK) {
+            return status;
+        }
+        if (HAL_GetTick() > timeout) {
+            return HAL_TIMEOUT;
+        }
+    } while (status_reg.BUSY);
+
+    if (status_reg.SHORT) {
+        return HAL_ERROR;
+    }
+
+    return HAL_OK;
+}
+
+HAL_StatusTypeDef ds2482_1w_write_byte(uint8_t byte) {
+    uint8_t data[2] = {DS2482_CMD_1W_WRITE_BYTE, byte};
+    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    DS2482_Status status_reg = {.BUSY = 1};
+    uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W;
+    do {
+        status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C);
+        if (status != HAL_OK) {
+            return status;
+        }
+        if (HAL_GetTick() > timeout) {
+            return HAL_TIMEOUT;
+        }
+    } while (status_reg.BUSY);
+
+    return HAL_OK;
+}
+
+HAL_StatusTypeDef ds2482_1w_read_byte(uint8_t* byte) {
+    uint8_t data[1] = {DS2482_CMD_1W_READ_BYTE};
+    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    DS2482_Status status_reg = {.BUSY = 1};
+    uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W;
+    do {
+        status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C);
+        if (status != HAL_OK) {
+            return status;
+        }
+        if (HAL_GetTick() > timeout) {
+            return HAL_TIMEOUT;
+        }
+    } while (status_reg.BUSY);
+
+    status = ds2482_set_read_ptr(DS2482_READ_DATA);
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    return HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, byte, 1, DS2482_TIMEOUT_I2C);
+}
+
+HAL_StatusTypeDef ds2482_1w_triplet(uint8_t dir) {
+    uint8_t data[2] = {DS2482_CMD_1W_TRIPLET, dir ? 0xFF : 0x00};
+    return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+}
+
+static HAL_StatusTypeDef ds2482_1w_write_bit(bool bit) {
+    uint8_t data[2] = {DS2482_CMD_1W_SINGLE_BIT, bit ? 0xFF : 0x00};
+    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    DS2482_Status status_reg = {.BUSY = 1};
+    uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W;
+    do {
+        status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C);
+        if (status != HAL_OK) {
+            return status;
+        }
+        if (HAL_GetTick() > timeout) {
+            return HAL_TIMEOUT;
+        }
+    } while (status_reg.BUSY);
+
+    return HAL_OK;
+}
+
+static HAL_StatusTypeDef ds2482_1w_read_bit(bool* bit) {
+    uint8_t data[2] = {DS2482_CMD_1W_SINGLE_BIT, 0xFF};
+    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C);
+    if (status != HAL_OK) {
+        return status;
+    }
+
+    DS2482_Status status_reg = {.BUSY = 1};
+    uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W;
+    do {
+        status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C);
+        if (status != HAL_OK) {
+            return status;
+        }
+        if (HAL_GetTick() > timeout) {
+            return HAL_TIMEOUT;
+        }
+    } while (status_reg.BUSY);
+
+    *bit = status_reg.SBR;
+    return HAL_OK;
+}
+
+
+
+//
+// From https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html
+//
+
+
+
+// global search state
+static uint8_t ROM_NO[8];
+static int LastDiscrepancy;
+static int LastFamilyDiscrepancy;
+static bool LastDeviceFlag;
+static uint8_t crc8;
+
+//--------------------------------------------------------------------------
+// Setup the search to find the device type 'family_code' on the next call
+// to OWNext() if it is present.
+//
+static void OWTargetSetup(uint8_t family_code) {
+    int i;
+
+    // set the search state to find SearchFamily type devices
+    ROM_NO[0] = family_code;
+    for (i = 1; i < 8; i++)
+        ROM_NO[i] = 0;
+    LastDiscrepancy = 64;
+    LastFamilyDiscrepancy = 0;
+    LastDeviceFlag = false;
+}
+
+//--------------------------------------------------------------------------
+// Setup the search to skip the current device type on the next call
+// to OWNext().
+//
+static void OWFamilySkipSetup() {
+    // set the Last discrepancy to last family discrepancy
+    LastDiscrepancy = LastFamilyDiscrepancy;
+    LastFamilyDiscrepancy = 0;
+
+    // check for end of list
+    if (LastDiscrepancy == 0)
+        LastDeviceFlag = true;
+}
+
+//--------------------------------------------------------------------------
+// 1-Wire Functions to be implemented for a particular platform
+//--------------------------------------------------------------------------
+
+//--------------------------------------------------------------------------
+// Reset the 1-Wire bus and return the presence of any device
+// Return true  : device present
+//        false : no device present
+//
+static bool OWReset() {
+    ds2482_1w_reset();
+    DS2482_Status status_reg = {};
+    HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C);
+    return status_reg.PPD;
+}
+
+//--------------------------------------------------------------------------
+// Send 8 bits of data to the 1-Wire bus
+//
+static inline void OWWriteByte(uint8_t byte_value) { ds2482_1w_write_byte(byte_value); }
+
+//--------------------------------------------------------------------------
+// Send 1 bit of data to teh 1-Wire bus
+//
+static inline void OWWriteBit(uint8_t bit_value) { ds2482_1w_write_bit(bit_value); }
+
+//--------------------------------------------------------------------------
+// Read 1 bit of data from the 1-Wire bus
+// Return 1 : bit read is 1
+//        0 : bit read is 0
+//
+static inline uint8_t OWReadBit() {
+    bool bit;
+    ds2482_1w_read_bit(&bit);
+    return bit;
+}
+
+// TEST BUILD
+static uint8_t dscrc_table[] = {
+    0,   94,  188, 226, 97,  63,  221, 131, 194, 156, 126, 32,  163, 253, 31,  65,  157, 195, 33,  127, 252, 162,
+    64,  30,  95,  1,   227, 189, 62,  96,  130, 220, 35,  125, 159, 193, 66,  28,  254, 160, 225, 191, 93,  3,
+    128, 222, 60,  98,  190, 224, 2,   92,  223, 129, 99,  61,  124, 34,  192, 158, 29,  67,  161, 255, 70,  24,
+    250, 164, 39,  121, 155, 197, 132, 218, 56,  102, 229, 187, 89,  7,   219, 133, 103, 57,  186, 228, 6,   88,
+    25,  71,  165, 251, 120, 38,  196, 154, 101, 59,  217, 135, 4,   90,  184, 230, 167, 249, 27,  69,  198, 152,
+    122, 36,  248, 166, 68,  26,  153, 199, 37,  123, 58,  100, 134, 216, 91,  5,   231, 185, 140, 210, 48,  110,
+    237, 179, 81,  15,  78,  16,  242, 172, 47,  113, 147, 205, 17,  79,  173, 243, 112, 46,  204, 146, 211, 141,
+    111, 49,  178, 236, 14,  80,  175, 241, 19,  77,  206, 144, 114, 44,  109, 51,  209, 143, 12,  82,  176, 238,
+    50,  108, 142, 208, 83,  13,  239, 177, 240, 174, 76,  18,  145, 207, 45,  115, 202, 148, 118, 40,  171, 245,
+    23,  73,  8,   86,  180, 234, 105, 55,  213, 139, 87,  9,   235, 181, 54,  104, 138, 212, 149, 203, 41,  119,
+    244, 170, 72,  22,  233, 183, 85,  11,  136, 214, 52,  106, 43,  117, 151, 201, 74,  20,  246, 168, 116, 42,
+    200, 150, 21,  75,  169, 247, 182, 232, 10,  84,  215, 137, 107, 53};
+
+//--------------------------------------------------------------------------
+// Calculate the CRC8 of the byte value provided with the current
+// global 'crc8' value.
+// Returns current global crc8 value
+//
+static uint8_t docrc8(uint8_t value) {
+    crc8 = dscrc_table[crc8 ^ value];
+    return crc8;
+}
+
+//--------------------------------------------------------------------------
+// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
+// search state.
+// Return true  : device found, ROM number in ROM_NO buffer
+//        false : device not found, end of search
+//
+static bool OWSearch() {
+    int id_bit_number;
+    int last_zero, rom_byte_number, search_result;
+    int id_bit, cmp_id_bit;
+    uint8_t 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;
+    crc8 = 0;
+
+    // if the last call was not the last one
+    if (!LastDeviceFlag) {
+        // 1-Wire reset
+        if (!OWReset()) {
+            // reset the search
+            LastDiscrepancy = 0;
+            LastDeviceFlag = false;
+            LastFamilyDiscrepancy = 0;
+            return false;
+        }
+
+        // issue the search command
+        OWWriteByte(0xF0);
+
+        // loop to do the search
+        do {
+            // read a bit and its complement
+            id_bit = OWReadBit();
+            cmp_id_bit = OWReadBit();
+
+            // 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 < LastDiscrepancy)
+                        search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
+                    else
+                        // if equal to last pick 1, if not then pick 0
+                        search_direction = (id_bit_number == LastDiscrepancy);
+
+                    // 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)
+                            LastFamilyDiscrepancy = last_zero;
+                    }
+                }
+
+                // set or clear the bit in the ROM byte rom_byte_number
+                // with mask rom_byte_mask
+                if (search_direction == 1)
+                    ROM_NO[rom_byte_number] |= rom_byte_mask;
+                else
+                    ROM_NO[rom_byte_number] &= ~rom_byte_mask;
+
+                // serial number search direction write bit
+                OWWriteBit(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) {
+                    docrc8(ROM_NO[rom_byte_number]); // accumulate the CRC
+                    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) || (crc8 != 0))) {
+            // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
+            LastDiscrepancy = last_zero;
+
+            // check for last device
+            if (LastDiscrepancy == 0)
+                LastDeviceFlag = true;
+
+            search_result = true;
+        }
+    }
+
+    // if no device found then reset counters so next 'search' will be like a first
+    if (!search_result || !ROM_NO[0]) {
+        LastDiscrepancy = 0;
+        LastDeviceFlag = false;
+        LastFamilyDiscrepancy = 0;
+        search_result = false;
+    }
+
+    return search_result;
+}
+
+//--------------------------------------------------------------------------
+// Find the 'first' devices on the 1-Wire bus
+// Return true  : device found, ROM number in ROM_NO buffer
+//        false : no device present
+//
+static bool OWFirst() {
+    // reset the search state
+    LastDiscrepancy = 0;
+    LastDeviceFlag = false;
+    LastFamilyDiscrepancy = 0;
+
+    return OWSearch();
+}
+
+//--------------------------------------------------------------------------
+// Find the 'next' devices on the 1-Wire bus
+// Return true  : device found, ROM number in ROM_NO buffer
+//        false : device not found, end of search
+//
+static inline bool OWNext() {
+    // leave the search state alone
+    return OWSearch();
+}
+
+//--------------------------------------------------------------------------
+// Verify the device with the ROM number in ROM_NO buffer is present.
+// Return true  : device verified present
+//        false : device not present
+//
+static bool OWVerify() {
+    uint8_t rom_backup[8];
+    int i, rslt, ld_backup, ldf_backup, lfd_backup;
+
+    // keep a backup copy of the current state
+    for (i = 0; i < 8; i++)
+        rom_backup[i] = ROM_NO[i];
+    ld_backup = LastDiscrepancy;
+    ldf_backup = LastDeviceFlag;
+    lfd_backup = LastFamilyDiscrepancy;
+
+    // set search to find the same device
+    LastDiscrepancy = 64;
+    LastDeviceFlag = false;
+
+    if (OWSearch()) {
+        // check if same device found
+        rslt = true;
+        for (i = 0; i < 8; i++) {
+            if (rom_backup[i] != ROM_NO[i]) {
+                rslt = false;
+                break;
+            }
+        }
+    } else
+        rslt = false;
+
+    // restore the search state
+    for (i = 0; i < 8; i++)
+        ROM_NO[i] = rom_backup[i];
+    LastDiscrepancy = ld_backup;
+    LastDeviceFlag = ldf_backup;
+    LastFamilyDiscrepancy = lfd_backup;
+
+    // return the result of the verify
+    return rslt;
+}
+
+
+
+HAL_StatusTypeDef ds2482_1w_search(uint16_t max_devices, uint64_t devices[static max_devices]) {
+    OWFirst();
+    uint16_t count = 0;
+    do {
+        uint64_t device = 0;
+        for (int i = 0; i < 8; i++) {
+            device |= (uint64_t)ROM_NO[i] << (i * 8);
+        }
+        devices[count++] = device;
+    } while (OWNext() && count < max_devices);
+
+    return HAL_OK; 
+}
diff --git a/DS2482_HAL.h b/DS2482_HAL.h
new file mode 100644
index 0000000..13410c8
--- /dev/null
+++ b/DS2482_HAL.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#ifndef DS2482_HAL_H
+#define DS2482_HAL_H
+#include "stm32f3xx_hal.h"
+
+#define DS2482_I2C_ADDR 0x30 // TODO: change to actual address
+
+#define DS2482_CMD_RESET         0xF0
+#define DS2482_CMD_SET_READ_PTR  0xE1
+#define DS2482_CMD_WRITE_CONFIG  0xD2
+#define DS2482_CMD_1W_RESET      0xB4
+#define DS2482_CMD_1W_SINGLE_BIT 0x87
+#define DS2482_CMD_1W_WRITE_BYTE 0xA5
+#define DS2482_CMD_1W_READ_BYTE  0x96
+#define DS2482_CMD_1W_TRIPLET    0x78
+
+#define DS2482_STATUS 0xF0
+#define DS2482_READ_DATA 0xE1
+#define DS2482_CONFIG 0xC3
+
+#define DS2482_CONFIG_APU 1 << 0
+#define DS2482_CONFIG_SPU 1 << 2
+#define DS2482_CONFIG_1WS 1 << 3
+
+#define DS2482_TIMEOUT_1W 100
+#define DS2482_TIMEOUT_I2C 100
+
+typedef struct {
+    uint8_t BUSY : 1;
+    uint8_t PPD : 1;
+    uint8_t SHORT : 1;
+    uint8_t LL : 1;
+    uint8_t RST : 1;
+    uint8_t SBR : 1;
+    uint8_t TSB : 1;
+    uint8_t DIR : 1;
+} DS2482_Status;
+
+HAL_StatusTypeDef ds2482_init(I2C_HandleTypeDef* handle);
+HAL_StatusTypeDef ds2482_reset();
+HAL_StatusTypeDef ds2482_write_config(uint8_t config);
+HAL_StatusTypeDef ds2482_set_read_ptr(uint8_t read_ptr);
+HAL_StatusTypeDef ds2482_1w_reset();
+HAL_StatusTypeDef ds2482_1w_write_byte(uint8_t byte);
+HAL_StatusTypeDef ds2482_1w_read_byte(uint8_t* byte);
+HAL_StatusTypeDef ds2482_1w_triplet(uint8_t dir);
+
+HAL_StatusTypeDef ds2482_1w_search(uint16_t max_devices, uint64_t devices[static max_devices]);
+
+#endif // DS2482_HAL_H
\ No newline at end of file