reflow-oven-control-sw/stm-firmware/settings/settings-eeprom.c

195 lines
4.8 KiB
C

/* Reflow Oven Controller
*
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <reflow-controller/settings/settings-eeprom.h>
#include <reflow-controller/settings/spi-eeprom.h>
#include <stm-periph/crc-unit.h>
#include <string.h>
#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(void)
{
settings_eeprom_save_calibration(0.0f, 0.0f, false);
settings_eeprom_save_overtemp_limit(0.0f, 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;
}