/* Reflow Oven Controller * * Copyright (C) 2020 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * * The reflow oven controller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the reflow oven controller project. * If not, see . */ #include #include #include #include #define EEPROM_HEADER_MAGIC 0xC5 #define EEPROM_HEADER_COMP_VER 0x01 static const uint8_t expected_header[2] = {EEPROM_HEADER_MAGIC, EEPROM_HEADER_COMP_VER}; #define EEPROM_CALIBRATION_BASE_ADDR 0x2 struct eeprom_calibration_settings { uint32_t active; float offset; float sens_dev; uint32_t crc; }; #define EEPROM_OVER_TEMP_CONFIG_BASE_ADDR (EEPROM_CALIBRATION_BASE_ADDR + sizeof(struct eeprom_calibration_settings)) struct eeprom_over_temp_config { float over_temperature; uint32_t over_temp_crc; }; static bool check_eeprom_header(void) { uint8_t header[2] = {0}; /* Try to read the magic header and the compatible version */ spi_eeprom_read(0x0, header, 2); if (memcmp(header, expected_header, 2)) return false; else return true; } static void settings_eeprom_zero() { settings_eeprom_save_calibration(0.0f, 0.0f, false); settings_eeprom_save_overtemp_limit(0.0, false); } bool settings_eeprom_detect_and_prepare(void) { bool eeprom_ready = false;; int res; crc_unit_init(); res = spi_eeprom_init(); if (res) goto ret_deinit_crc; if (!spi_eeprom_check_connected()) goto ret_deinit_crc; if (check_eeprom_header() == false) { /* Try to write a new header and check it again */ spi_eeprom_write(0, expected_header, sizeof(expected_header)); while (spi_eeprom_write_in_progress()); if (check_eeprom_header() == false) { goto ret_deinit_crc; } else { /* Sucessfully written new header * Zero out the rest of the settings */ settings_eeprom_zero(); eeprom_ready = true; } } else { eeprom_ready = true; } goto exit; ret_deinit_crc: crc_unit_deinit(); exit: return eeprom_ready; } int settings_eeprom_save_calibration(float sens, float offset, bool active) { int res; struct eeprom_calibration_settings sett; sett.active = (active ? 0xAABBCCDD : 0); sett.offset = offset; sett.sens_dev = sens; crc_unit_reset(); crc_unit_input_array((const uint32_t *)&sett, (sizeof(sett) / 4)-1); sett.crc = crc_unit_get_crc(); res = spi_eeprom_write(EEPROM_CALIBRATION_BASE_ADDR, (uint8_t *)&sett, sizeof(sett)); if (res) return -2; else return 0; } int settings_eeprom_load_calibration(float *sens, float *offset, bool *active) { struct eeprom_calibration_settings sett; int res; res = spi_eeprom_read(EEPROM_CALIBRATION_BASE_ADDR, (uint8_t *)&sett, sizeof(sett)); if (res) return -2; crc_unit_reset(); crc_unit_input_array((const uint32_t *)&sett, sizeof(sett) / 4 - 1); if (crc_unit_get_crc() == sett.crc) { if (sens) *sens = sett.sens_dev; if (offset) *offset = sett.offset; if (active) *active = (sett.active ? true : false); return 0; } else { return -1; } } int settings_eeprom_save_overtemp_limit(float overtemp_limit, bool active) { int res; struct eeprom_over_temp_config over_temp_conf_entry; const uint8_t zero_vals[sizeof(over_temp_conf_entry)] = {0}; if (!active) { res = spi_eeprom_write(EEPROM_OVER_TEMP_CONFIG_BASE_ADDR, (const uint8_t *)zero_vals, sizeof(zero_vals)); return res ? -1 : 0; } over_temp_conf_entry.over_temperature = overtemp_limit; crc_unit_reset(); crc_unit_input_array((uint32_t *)&over_temp_conf_entry, 1); over_temp_conf_entry.over_temp_crc = crc_unit_get_crc(); res = spi_eeprom_write(EEPROM_OVER_TEMP_CONFIG_BASE_ADDR, (const uint8_t *)&over_temp_conf_entry, sizeof(over_temp_conf_entry)); return res ? -1 : 0; } int settings_eeprom_load_overtemp_limit(float *overtemp_limit) { int res; struct eeprom_over_temp_config over_temp_conf_entry; if (!overtemp_limit) return -1001; res = spi_eeprom_read(EEPROM_OVER_TEMP_CONFIG_BASE_ADDR, (uint8_t *)&over_temp_conf_entry, sizeof(struct eeprom_over_temp_config)); if (res) return -2; crc_unit_reset(); crc_unit_input_array((uint32_t *)&over_temp_conf_entry, 1); if (crc_unit_get_crc() != over_temp_conf_entry.over_temp_crc) return -1; *overtemp_limit = over_temp_conf_entry.over_temperature; return 0; }