// === Início de: components/peripherals/src/socket_lock.c === #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/timers.h" #include "esp_log.h" #include "driver/gpio.h" #include "nvs.h" #include "socket_lock.h" #include "board_config.h" #define NVS_NAMESPACE "socket_lock" #define NVS_OPERATING_TIME "op_time" #define NVS_BREAK_TIME "break_time" #define NVS_RETRY_COUNT "retry_count" #define NVS_DETECTION_HIGH "detect_hi" #define OPERATING_TIME_MIN 100 #define OPERATING_TIME_MAX 1000 #define LOCK_DELAY 500 #define LOCK_BIT BIT0 #define UNLOCK_BIT BIT1 #define REPEAT_LOCK_BIT BIT2 #define REPEAT_UNLOCK_BIT BIT3 static const char* TAG = "socket_lock"; static nvs_handle_t nvs; static uint16_t operating_time = 300; static uint16_t break_time = 1000; static bool detection_high; static uint8_t retry_count = 5; static socket_lock_status_t status; static TaskHandle_t socket_lock_task; static bool is_locked(void) { gpio_set_level(board_config.socket_lock_a_gpio, 1); gpio_set_level(board_config.socket_lock_b_gpio, 1); vTaskDelay(pdMS_TO_TICKS(board_config.socket_lock_detection_delay)); return gpio_get_level(board_config.socket_lock_detection_gpio) == detection_high; } bool socket_lock_is_locked_state(void) { return is_locked(); } static void socket_lock_task_func(void* param) { uint32_t notification; TickType_t previous_tick = 0; uint8_t attempt = 0; while (true) { if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) { if (notification & (LOCK_BIT | UNLOCK_BIT)) { attempt = retry_count; } if (notification & (UNLOCK_BIT | REPEAT_UNLOCK_BIT)) { gpio_set_level(board_config.socket_lock_a_gpio, 0); gpio_set_level(board_config.socket_lock_b_gpio, 1); vTaskDelay(pdMS_TO_TICKS(operating_time)); if (!is_locked()) { ESP_LOGI(TAG, "Unlock OK"); status = SOCKED_LOCK_STATUS_IDLE; } else { if (attempt > 1) { ESP_LOGW(TAG, "Not unlocked yet, repeating..."); attempt--; xTaskNotify(socket_lock_task, REPEAT_UNLOCK_BIT, eSetBits); } else { ESP_LOGE(TAG, "Not unlocked"); status = SOCKED_LOCK_STATUS_UNLOCKING_FAIL; } } gpio_set_level(board_config.socket_lock_a_gpio, 0); gpio_set_level(board_config.socket_lock_b_gpio, 0); } else if (notification & (LOCK_BIT | REPEAT_LOCK_BIT)) { if (notification & LOCK_BIT) { vTaskDelay(pdMS_TO_TICKS(LOCK_DELAY)); //delay before first lock attempt } gpio_set_level(board_config.socket_lock_a_gpio, 1); gpio_set_level(board_config.socket_lock_b_gpio, 0); vTaskDelay(pdMS_TO_TICKS(operating_time)); if (is_locked()) { ESP_LOGI(TAG, "Lock OK"); status = SOCKED_LOCK_STATUS_IDLE; } else { if (attempt > 1) { ESP_LOGW(TAG, "Not locked yet, repeating..."); attempt--; xTaskNotify(socket_lock_task, REPEAT_LOCK_BIT, eSetBits); } else { ESP_LOGE(TAG, "Not locked"); status = SOCKED_LOCK_STATUS_LOCKING_FAIL; } } gpio_set_level(board_config.socket_lock_a_gpio, 0); gpio_set_level(board_config.socket_lock_b_gpio, 0); } TickType_t delay_tick = xTaskGetTickCount() - previous_tick; if (delay_tick < pdMS_TO_TICKS(break_time)) { vTaskDelay(pdMS_TO_TICKS(break_time) - delay_tick); } previous_tick = xTaskGetTickCount(); } } } void socket_lock_init(void) { if (board_config.socket_lock) { ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs)); nvs_get_u16(nvs, NVS_OPERATING_TIME, &operating_time); nvs_get_u16(nvs, NVS_BREAK_TIME, &break_time); nvs_get_u8(nvs, NVS_RETRY_COUNT, &retry_count); uint8_t u8; if (nvs_get_u8(nvs, NVS_DETECTION_HIGH, &u8) == ESP_OK) { detection_high = u8; } gpio_config_t io_conf = {}; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pin_bit_mask = BIT64(board_config.socket_lock_a_gpio) | BIT64(board_config.socket_lock_b_gpio); ESP_ERROR_CHECK(gpio_config(&io_conf)); io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = BIT64(board_config.socket_lock_detection_gpio); ESP_ERROR_CHECK(gpio_config(&io_conf)); xTaskCreate(socket_lock_task_func, "socket_lock_task", 2 * 1024, NULL, 10, &socket_lock_task); } } bool socket_lock_is_detection_high(void) { return detection_high; } void socket_lock_set_detection_high(bool _detection_high) { detection_high = _detection_high; nvs_set_u8(nvs, NVS_DETECTION_HIGH, detection_high); nvs_commit(nvs); } uint16_t socket_lock_get_operating_time(void) { return operating_time; } esp_err_t socket_lock_set_operating_time(uint16_t _operating_time) { if (_operating_time < OPERATING_TIME_MIN || _operating_time > OPERATING_TIME_MAX) { ESP_LOGE(TAG, "Operating time out of range"); return ESP_ERR_INVALID_ARG; } operating_time = _operating_time; nvs_set_u16(nvs, NVS_OPERATING_TIME, operating_time); nvs_commit(nvs); return ESP_OK; } uint8_t socket_lock_get_retry_count(void) { return retry_count; } void socket_lock_set_retry_count(uint8_t _retry_count) { retry_count = _retry_count; nvs_set_u8(nvs, NVS_RETRY_COUNT, retry_count); nvs_commit(nvs); } uint16_t socket_lock_get_break_time(void) { return break_time; } esp_err_t socket_lock_set_break_time(uint16_t _break_time) { if (_break_time < board_config.socket_lock_min_break_time) { ESP_LOGE(TAG, "Operating time out of range"); return ESP_ERR_INVALID_ARG; } break_time = _break_time; nvs_set_u16(nvs, NVS_BREAK_TIME, break_time); nvs_commit(nvs); return ESP_OK; } void socket_lock_set_locked(bool locked) { ESP_LOGI(TAG, "Set locked %d", locked); xTaskNotify(socket_lock_task, locked ? LOCK_BIT : UNLOCK_BIT, eSetBits); status = SOCKED_LOCK_STATUS_OPERATING; } socket_lock_status_t socket_lock_get_status(void) { return status; } // === Fim de: components/peripherals/src/socket_lock.c === // === Início de: components/peripherals/src/temp_sensor.c === #include #include #include "freertos/task.h" #include "esp_log.h" #include "driver/gpio.h" #include "temp_sensor.h" #include "lm75a.h" #define MAX_SENSORS 5 #define MEASURE_PERIOD 10000 // 10s #define MEASURE_ERR_THRESHOLD 3 static const char *TAG = "temp_sensor"; static uint8_t sensor_count = 0; static int16_t low_temp = 0; static int high_temp = 0; static uint8_t measure_err_count = 0; static void temp_sensor_task_func(void *param) { while (true) { high_temp = lm75a_read_temperature(0); vTaskDelay(pdMS_TO_TICKS(MEASURE_PERIOD)); } } void temp_sensor_init(void) { ESP_LOGW(TAG, "temp_sensor_init"); lm75a_init(); xTaskCreate(temp_sensor_task_func, "temp_sensor_task", 5 * 1024, NULL, 5, NULL); } uint8_t temp_sensor_get_count(void) { return sensor_count; } int16_t temp_sensor_get_low(void) { return low_temp; } int temp_sensor_get_high(void) { return high_temp; } bool temp_sensor_is_error(void) { return sensor_count == 0 || measure_err_count > MEASURE_ERR_THRESHOLD; } // === Fim de: components/peripherals/src/temp_sensor.c === // === Início de: components/peripherals/src/aux_io.c === #include #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/task.h" #include "esp_log.h" #include "driver/gpio.h" #include "nvs.h" #include "aux_io.h" #include "board_config.h" #include "adc.h" #define MAX_AUX_IN 4 #define MAX_AUX_OUT 4 #define MAX_AUX_AIN 4 //static const char* TAG = "aux"; static int aux_in_count = 0; static int aux_out_count = 0; static int aux_ain_count = 0; static struct aux_gpio_s { gpio_num_t gpio; const char* name; } aux_in[MAX_AUX_IN], aux_out[MAX_AUX_OUT]; static struct aux_adc_s { adc_channel_t adc; const char* name; } aux_ain[MAX_AUX_AIN]; void aux_init(void) { // IN gpio_config_t io_conf = { .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLDOWN_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, .pin_bit_mask = 0 }; if (board_config.aux_in_1) { aux_in[aux_in_count].gpio = board_config.aux_in_1_gpio; aux_in[aux_in_count].name = board_config.aux_in_1_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_in_1_gpio); aux_in_count++; } if (board_config.aux_in_2) { aux_in[aux_in_count].gpio = board_config.aux_in_2_gpio; aux_in[aux_in_count].name = board_config.aux_in_2_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_in_2_gpio); aux_in_count++; } if (board_config.aux_in_3) { aux_in[aux_in_count].gpio = board_config.aux_in_3_gpio; aux_in[aux_in_count].name = board_config.aux_in_3_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_in_3_gpio); aux_in_count++; } if (board_config.aux_in_4) { aux_in[aux_in_count].gpio = board_config.aux_in_4_gpio; aux_in[aux_in_count].name = board_config.aux_in_4_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_in_4_gpio); aux_in_count++; } if (io_conf.pin_bit_mask > 0) { ESP_ERROR_CHECK(gpio_config(&io_conf)); } // OUT io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pin_bit_mask = 0; if (board_config.aux_out_1) { aux_out[aux_out_count].gpio = board_config.aux_out_1_gpio; aux_out[aux_out_count].name = board_config.aux_out_1_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_out_1_gpio); aux_out_count++; } if (board_config.aux_out_2) { aux_out[aux_out_count].gpio = board_config.aux_out_2_gpio; aux_out[aux_out_count].name = board_config.aux_out_2_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_out_2_gpio); aux_out_count++; } if (board_config.aux_out_3) { aux_out[aux_out_count].gpio = board_config.aux_out_3_gpio; aux_out[aux_out_count].name = board_config.aux_out_3_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_out_3_gpio); aux_out_count++; } if (board_config.aux_out_4) { aux_out[aux_out_count].gpio = board_config.aux_out_4_gpio; aux_out[aux_out_count].name = board_config.aux_out_4_name; io_conf.pin_bit_mask |= BIT64(board_config.aux_out_4_gpio); aux_out_count++; } if (io_conf.pin_bit_mask > 0) { ESP_ERROR_CHECK(gpio_config(&io_conf)); } // AIN adc_oneshot_chan_cfg_t config = { .bitwidth = ADC_BITWIDTH_DEFAULT, .atten = ADC_ATTEN_DB_12 }; if (board_config.aux_ain_1) { aux_ain[aux_ain_count].adc = board_config.aux_ain_1_adc_channel; aux_ain[aux_ain_count].name = board_config.aux_out_1_name; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.aux_ain_1_adc_channel, &config)); aux_ain_count++; } if (board_config.aux_ain_2) { aux_ain[aux_ain_count].adc = board_config.aux_ain_2_adc_channel; aux_ain[aux_ain_count].name = board_config.aux_out_2_name; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.aux_ain_2_adc_channel, &config)); aux_ain_count++; } } esp_err_t aux_read(const char* name, bool* value) { for (int i = 0; i < aux_in_count; i++) { if (strcmp(aux_in[i].name, name) == 0) { *value = gpio_get_level(aux_in[i].gpio) == 1; return ESP_OK; } } return ESP_ERR_NOT_FOUND; } esp_err_t aux_write(const char* name, bool value) { for (int i = 0; i < aux_out_count; i++) { if (strcmp(aux_out[i].name, name) == 0) { return gpio_set_level(aux_out[i].gpio, value); } } return ESP_ERR_NOT_FOUND; } esp_err_t aux_analog_read(const char* name, int* value) { for (int i = 0; i < aux_ain_count; i++) { if (strcmp(aux_ain[i].name, name) == 0) { int raw = 0; esp_err_t ret = adc_oneshot_read(adc_handle, aux_ain[i].adc, &raw); if (ret == ESP_OK) { return adc_cali_raw_to_voltage(adc_cali_handle, raw, value); } else { return ret; } } } return ESP_ERR_NOT_FOUND; } // === Fim de: components/peripherals/src/aux_io.c === // === Início de: components/peripherals/src/lm75a.c === #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "driver/gpio.h" #include "driver/i2c_master.h" #define I2C_MASTER_NUM I2C_NUM_1 #define I2C_MASTER_SCL_IO GPIO_NUM_22 // CONFIG_EXAMPLE_I2C_SCL /*!< gpio number for I2C master clock */ #define I2C_MASTER_SDA_IO GPIO_NUM_21 // CONFIG_EXAMPLE_I2C_SDA /*!< gpio number for I2C master data */ #define I2C_MASTER_FREQ_HZ 100000 // CONFIG_I2C_TRANS_SPEED /*!< I2C master clock frequency */ #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ #define LM75A_SLAVE_ADDR 0x48 // CONFIG_LM75A_SLAVE_ADDR /*!< LM75A slave address, you can set any 7bit value */ #define ACK_VAL 0x0 /*!< I2C ack value */ #define NACK_VAL 0x1 /*!< I2C nack value */ #define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ #define READ_BIT I2C_MASTER_READ /*!< I2C master read */ #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ /* #define GPIO_INPUT_IO_0 CONFIG_LM75A_OS_PIN #define GPIO_OUTPUT_IO_0 CONFIG_LM75A_VCC_PIN #define GPIO_OUTPUT_PIN_SEL (1ULL << GPIO_OUTPUT_IO_0) #define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO_0) #define ESP_INTR_FLAG_DEFAULT 0 */ // static xQueueHandle gpio_evt_queue = NULL; // static int gpio_int_task_enable = 0; // static TaskHandle_t gpio_int_task_handle = NULL; /** * @brief test code to read esp-i2c-slave * We need to fill the buffer of esp slave device, then master can read them out. * * _______________________________________________________________________________________ * | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop | * --------|--------------------------|----------------------|--------------------|------| * */ static esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t *data_rd, size_t size) { if (size == 0) { return ESP_OK; } i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (LM75A_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN); if (size > 1) { i2c_master_read(cmd, data_rd, size - 1, ACK_VAL); } i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL); i2c_master_stop(cmd); esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); return ret; } /** * @brief Test code to write esp-i2c-slave * Master device write data to slave(both esp32), * the data will be stored in slave buffer. * We can read them out from slave buffer. * * ___________________________________________________________________ * | start | slave_addr + wr_bit + ack | write n bytes + ack | stop | * --------|---------------------------|----------------------|------| * */ static esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t *data_wr, size_t size) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (LM75A_SLAVE_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN); i2c_master_stop(cmd); esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); return ret; } /** * @brief i2c master initialization */ static void i2c_master_init() { int i2c_master_port = I2C_MASTER_NUM; i2c_config_t conf; conf.mode = I2C_MODE_MASTER; conf.sda_io_num = I2C_MASTER_SDA_IO; conf.sda_pullup_en = GPIO_PULLUP_DISABLE; conf.scl_io_num = I2C_MASTER_SCL_IO; conf.scl_pullup_en = GPIO_PULLUP_DISABLE; conf.master.clk_speed = I2C_MASTER_FREQ_HZ; conf.clk_flags = 0; i2c_param_config(i2c_master_port, &conf); i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); } int lm75a_read_temperature(int show) { uint8_t buf[2]; float tmp; buf[0] = 0; i2c_master_write_slave(I2C_MASTER_NUM, buf, 1); i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); tmp = buf[0]; if (buf[1] & 128) tmp += 0.5; if (show) printf("lm75a_read_temperature=%.1f\n", tmp); return tmp; } /* static void IRAM_ATTR gpio_isr_handler(void *arg) { uint32_t gpio_num = (uint32_t)arg; xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); } static void gpio_int_task(void *arg) { uint32_t io_num; gpio_int_task_enable = 1; while (gpio_int_task_enable) { if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { // read temperature to clean int; if (io_num == GPIO_INPUT_IO_0) { printf("GPIO[%d] intr, val: %d\n\n", io_num, gpio_get_level(io_num)); lm75a_read_temperature(0); // read to clean interrupt. } } } printf("quit gpio_int_task\n"); if (gpio_evt_queue) { vQueueDelete(gpio_evt_queue); gpio_evt_queue = NULL; } gpio_int_task_handle = NULL; vTaskDelete(NULL); } void init_os_gpio() { printf("init_os_gpio!\n"); if (gpio_evt_queue == NULL) gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); if (gpio_int_task_handle == NULL) { xTaskCreate(gpio_int_task, "gpio_int_task", 2048, NULL, 10, &gpio_int_task_handle); // install gpio isr service gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); // hook isr handler for specific gpio pin again gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *)GPIO_INPUT_IO_0); } } static void deinit_os_gpio() { printf("deinit_os_gpio!\n"); if (gpio_int_task_handle) { gpio_isr_handler_remove(GPIO_INPUT_IO_0); gpio_uninstall_isr_service(); gpio_int_task_enable = 0; int io = 0; xQueueSend(gpio_evt_queue, &io, 0); // send a fake signal to quit task. } } static void lm75a_vcc_enable() { gpio_config_t io_conf; // enable output for vcc io_conf.intr_type = GPIO_PIN_INTR_DISABLE; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; io_conf.pull_down_en = 0; io_conf.pull_up_en = 0; gpio_config(&io_conf); // enable input for interrupt io_conf.intr_type = GPIO_PIN_INTR_NEGEDGE; // GPIO_PIN_INTR_ANYEDGE; io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; io_conf.mode = GPIO_MODE_INPUT; io_conf.pull_up_en = 1; gpio_set_pull_mode(GPIO_INPUT_IO_0, GPIO_FLOATING); gpio_config(&io_conf); gpio_set_level(GPIO_OUTPUT_IO_0, 1); } static void lm75a_vcc_disable() { gpio_set_level(GPIO_OUTPUT_IO_0, 0); } */ void lm75a_init() { // lm75a_vcc_enable(); i2c_master_init(); } void lm75a_deinit() { // deinit_os_gpio(); i2c_driver_delete(I2C_MASTER_NUM); // lm75a_vcc_disable(); } void lm75a_set_tos(int tos) { uint8_t buf[4]; printf("lm75a_set_tos: %d\n", tos); // set Tos: buf[0] = 0x3; buf[1] = (tos & 0xff); buf[2] = 0; i2c_master_write_slave(I2C_MASTER_NUM, buf, 3); } void lm75a_set_thys(int thys) { uint8_t buf[4]; printf("lm75a_set_thys: %d\n", thys); // set Thyst: buf[0] = 0x2; buf[1] = (thys & 0xff); buf[2] = 0; i2c_master_write_slave(I2C_MASTER_NUM, buf, 3); } void lm75a_get_tos() { uint8_t buf[4]; float tmp; buf[0] = 0x3; i2c_master_write_slave(I2C_MASTER_NUM, buf, 1); i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); tmp = buf[0]; if (buf[1] & 128) tmp += 0.5; printf("lm75a_get_tos: %.1f\n", tmp); } void lm75a_get_thys() { uint8_t buf[4]; float tmp; buf[0] = 0x2; i2c_master_write_slave(I2C_MASTER_NUM, buf, 1); i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); tmp = buf[0]; if (buf[1] & 128) tmp += 0.5; printf("lm75a_get_thys: %.1f\n", tmp); } void lm75a_set_int(int en) { uint8_t buf[2]; en = !!en; if (en) { printf("lm75a_set_int: %d\n", en); buf[0] = 0x1; buf[1] = (1 << 1); // D1 set to 1; i2c_master_write_slave(I2C_MASTER_NUM, buf, 2); i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); // do one time read to clean interrupt before enter interrupt mode. // gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_NEGEDGE); // init_os_gpio(); } else { printf("lm75a_set_int: %d\n", en); // deinit_os_gpio(); buf[0] = 0x1; buf[1] = 0; i2c_master_write_slave(I2C_MASTER_NUM, buf, 2); i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); // do one time read to clean interrupt before enter interrupt mode. } } void lm75a_get_osio() { // printf("os_io: %d\n", gpio_get_level(GPIO_INPUT_IO_0)); } // === Fim de: components/peripherals/src/lm75a.c ===