settings.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * settings.c
  3. *
  4. * Created on: Jan 12, 2021
  5. * Author: David Original work by Jose (PTDreamer), 2017
  6. */
  7. #include "settings.h"
  8. #include "pid.h"
  9. #include "iron.h"
  10. #include "gui.h"
  11. #include "ssd1306.h"
  12. #include "tempsensors.h"
  13. systemSettings_t systemSettings;
  14. flashSettings_t* flashSettings = (flashSettings_t*)FLASH_ADDR;
  15. void settingsChkErr(void);
  16. void ProfileChkErr(void);
  17. void Flash_error(void);
  18. void Button_reset(void);
  19. void Diag_init(void);
  20. void ErrCountDown(uint8_t Start,uint8_t xpos, uint8_t ypos);
  21. // Check for changes in system settings.
  22. void checkSettings(void){
  23. static uint32_t prevSysChecksum=0, newSysChecksum=0, prevTipChecksum=0, newTipChecksum=0, checksumtime=0;
  24. uint32_t CurrentTime = HAL_GetTick();
  25. // Don't check if in: Calibration mode, Setup mode, Save delay==0, failure error active
  26. if( (systemSettings.setupMode==setup_On) || (Iron.calibrating==calibration_On) || (systemSettings.settings.saveSettingsDelay==0) || (Iron.Error.failState!=noError) || (CurrentTime-checksumtime<999)){
  27. return;
  28. }
  29. checksumtime=CurrentTime; // Store current time
  30. newSysChecksum=ChecksumSettings(&systemSettings.settings); // Calculate system checksum
  31. newTipChecksum=ChecksumProfile(&systemSettings.Profile); // Calculate tip profile checksum
  32. if((systemSettings.settingsChecksum!=newSysChecksum)||(systemSettings.ProfileChecksum!=newTipChecksum)){ // If anything was changed (Checksum mismatch)
  33. if((prevSysChecksum!=newSysChecksum)||(prevTipChecksum!=newTipChecksum)){ // If different from the previous calculated checksum (settings are being changed quickly, don't save every time).
  34. prevSysChecksum=newSysChecksum; // Store last computed checksum
  35. prevTipChecksum=newTipChecksum;
  36. Iron.LastSysChangeTime=CurrentTime; // Reset timer (we don't save anything until we pass a certain time without changes)
  37. }
  38. else if((CurrentTime-Iron.LastSysChangeTime)>((uint32_t)systemSettings.settings.saveSettingsDelay*1000)){ // If different from the previous calculated checksum, and timer expired (No changes for enough time)
  39. saveSettings(saveKeepingProfiles); // Data was saved (so any pending interrupt knows this)
  40. }
  41. }
  42. }
  43. void saveSettings(bool wipeAllProfileData) {
  44. uint32_t error=0;
  45. //Read stored data, as everything will be erased and we don't store data for all iron tips in ram (only the current tip type)
  46. flashSettings_t flashBuffer=*flashSettings;
  47. // Check init flags
  48. if( (systemSettings.settings.NotInitialized!=initialized) || (systemSettings.Profile.NotInitialized!=initialized) ){
  49. Error_Handler();
  50. }
  51. // Compute checksum of current system settings
  52. systemSettings.settingsChecksum = ChecksumSettings(&systemSettings.settings);
  53. // Transfer system settings to flash buffer
  54. flashBuffer.settingsChecksum=systemSettings.settingsChecksum;
  55. flashBuffer.settings=systemSettings.settings;
  56. if(!wipeAllProfileData){ // If wipe all tips is not set
  57. if(systemSettings.settings.currentProfile!=profile_None){ // If current tip is initialized
  58. if((systemSettings.settings.currentProfile<=profile_C210) && // Check valid Profile
  59. (systemSettings.Profile.ID == systemSettings.settings.currentProfile )){ // Ensure profile ID is correct
  60. systemSettings.ProfileChecksum = ChecksumProfile(&systemSettings.Profile); // Compute checksum
  61. flashBuffer.ProfileChecksum[systemSettings.settings.currentProfile]=systemSettings.ProfileChecksum;
  62. memcpy(&flashBuffer.Profile[systemSettings.settings.currentProfile],&systemSettings.Profile,sizeof(profile_t)); // Transfer system profile to flash buffer
  63. }
  64. else{
  65. Error_Handler(); // Invalid tip (uncontrolled state)
  66. }
  67. }
  68. }
  69. else{ // Wipe all tip data
  70. for(uint8_t x=0;x<ProfileSize;x++){
  71. flashBuffer.Profile[x].NotInitialized=0xFF;
  72. flashBuffer.ProfileChecksum[x]=0xFF;
  73. memset(&flashBuffer.Profile[x],0xFF,sizeof(profile_t));
  74. }
  75. }
  76. __disable_irq();
  77. HAL_FLASH_Unlock();
  78. __enable_irq();
  79. FLASH_EraseInitTypeDef erase;
  80. erase.NbPages = (1024*StoreSize)/FLASH_PAGE_SIZE;
  81. erase.PageAddress = FLASH_ADDR;
  82. erase.TypeErase = FLASH_TYPEERASE_PAGES;
  83. //Erase flash page
  84. __disable_irq();
  85. HAL_IWDG_Refresh(&hiwdg);
  86. if((HAL_FLASHEx_Erase(&erase, &error)!=HAL_OK) || (error!=0xFFFFFFFF)){
  87. Flash_error();
  88. }
  89. __enable_irq();
  90. __disable_irq();
  91. HAL_FLASH_Lock();
  92. __enable_irq();
  93. // Ensure flash was erased
  94. for (uint16_t i = 0; i < sizeof(flashSettings_t)/2; i++) {
  95. if( *(uint16_t*)(FLASH_ADDR+(i*2)) != 0xFFFF){
  96. Flash_error();
  97. }
  98. }
  99. __disable_irq();
  100. HAL_FLASH_Unlock();
  101. __enable_irq();
  102. uint32_t dest = (uint32_t)flashSettings;
  103. uint16_t *data = (uint16_t*)&flashBuffer;
  104. // Store settings
  105. // written = number of 16-bit values written
  106. for(uint16_t written=0; written < (sizeof(flashSettings_t)/2); written++){
  107. __disable_irq();
  108. if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, dest, *data ) != HAL_OK){
  109. Flash_error();
  110. }
  111. dest += 2; // address +2 because we write 16 bit data
  112. data++; // +1 because it's 16Bit pointer
  113. __enable_irq();
  114. }
  115. __disable_irq();
  116. HAL_FLASH_Lock();
  117. __enable_irq();
  118. if(!wipeAllProfileData){
  119. uint32_t ProfileFlash = ChecksumProfile(&flashSettings->Profile[systemSettings.settings.currentProfile]);
  120. uint32_t ProfileRam = ChecksumProfile(&systemSettings.Profile);
  121. // Check flash and system tip profile have same checksum and profile type
  122. if((ProfileFlash != ProfileRam) || (flashSettings->settings.currentProfile != systemSettings.settings.currentProfile)){
  123. Flash_error(); // Error if data mismatchº
  124. }
  125. }
  126. // Check flash and system settings have same checksum
  127. uint32_t SettingsFlash = ChecksumSettings(&flashSettings->settings);
  128. uint32_t SettingsRam = ChecksumSettings(&systemSettings.settings);
  129. if(SettingsFlash != SettingsRam){ // Check flash and system settings have same checksum
  130. Flash_error(); // Error if data mismatch
  131. }
  132. }
  133. void restoreSettings() {
  134. #ifdef NOSAVESETTINGS // Stop erasing the flash every time while in debug mode
  135. resetSystemSettings(); // TODO not tested with the new profile system
  136. setupPID(systemSettings.Profile.tip[systemSettings.settings.currentTip[systemSettings.settings.currentProfile]].PID);
  137. return;
  138. #endif
  139. if(flashSettings->settings.NotInitialized!=initialized){ // If flash not initialized (Erased flash is always read "1")
  140. resetSystemSettings();
  141. saveSettings(saveWipingProfiles);
  142. }
  143. else{
  144. Button_reset(); // Check for button reset
  145. }
  146. systemSettings.settings=flashSettings->settings; // Load system settings from flash
  147. systemSettings.settingsChecksum=flashSettings->settingsChecksum; // Load stored checksum
  148. loadProfile(systemSettings.settings.currentProfile); // Load current tip data into system memory
  149. // Compare loaded checksum with calculated checksum
  150. if( (systemSettings.settings.version != SETTINGS_VERSION) || (ChecksumSettings(&systemSettings.settings)!=systemSettings.settingsChecksum) ){
  151. settingsChkErr();
  152. }
  153. setContrast(systemSettings.settings.contrast);
  154. }
  155. uint32_t ChecksumSettings(settings_t* settings){
  156. uint32_t checksum;
  157. checksum = HAL_CRC_Calculate(&hcrc, (uint32_t*)settings, sizeof(settings_t)/sizeof(uint32_t) );
  158. return checksum;
  159. }
  160. uint32_t ChecksumProfile(profile_t* profile){
  161. uint32_t checksum;
  162. checksum = HAL_CRC_Calculate(&hcrc, (uint32_t*)profile, sizeof(profile_t)/sizeof(uint32_t));
  163. return checksum;
  164. }
  165. void resetSystemSettings(void) {
  166. systemSettings.settings.version = SETTINGS_VERSION;
  167. systemSettings.settings.contrast = 255;
  168. systemSettings.settings.screenDimming = true;
  169. systemSettings.settings.OledOffset = 2;
  170. systemSettings.settings.errorDelay = 100;
  171. systemSettings.settings.guiUpdateDelay = 200;
  172. systemSettings.settings.tempUnit = mode_Celsius;
  173. systemSettings.settings.tempStep = 10; // 10º steps
  174. systemSettings.settings.activeDetection = true;
  175. systemSettings.settings.saveSettingsDelay = 5; // 5s
  176. systemSettings.settings.lvp = 110; // 11.0V Low voltage
  177. systemSettings.settings.currentProfile = profile_None;
  178. systemSettings.settings.initMode = mode_run;
  179. systemSettings.settings.buzzerMode = buzzer_Off;
  180. systemSettings.settings.wakeOnButton = wakeButton_On;
  181. systemSettings.settings.wakeOnShake = wakeShake_On;
  182. systemSettings.settings.WakeInputMode = wakeInputmode_shake;
  183. systemSettings.settings.StandMode = mode_sleep;
  184. systemSettings.settings.EncoderMode = RE_Mode_One;
  185. systemSettings.settings.NotInitialized = initialized;
  186. }
  187. void resetCurrentProfile(void){
  188. #ifdef NOSAVESETTINGS
  189. systemSettings.settings.currentProfile=profile_T12; /// Force T12 when debugging. TODO this is not tested with the profiles update!
  190. #endif
  191. char str[TipCharSize];
  192. for(uint8_t x=0;x<TipCharSize;x++){
  193. str[x] = ' ';
  194. }
  195. str[TipCharSize-1] = 0;
  196. if(systemSettings.settings.currentProfile==profile_T12){
  197. systemSettings.Profile.ID = profile_T12;
  198. for(uint8_t x = 0; x < TipSize; x++) {
  199. systemSettings.Profile.tip[x].calADC_At_250 = T12_Cal250;
  200. systemSettings.Profile.tip[x].calADC_At_350 = T12_Cal350; // These values are way lower, but better to be safe than sorry
  201. systemSettings.Profile.tip[x].calADC_At_450 = T12_Cal450; // User needs to calibrate its station
  202. systemSettings.Profile.tip[x].PID.Kp = 7500; // val = /1.000.000
  203. systemSettings.Profile.tip[x].PID.Ki = 4000; // val = /1.000.000
  204. systemSettings.Profile.tip[x].PID.Kd = 1000; // val = /1.000.000
  205. systemSettings.Profile.tip[x].PID.maxI = 40; // val = /100
  206. systemSettings.Profile.tip[x].PID.minI = 0; // val = /100
  207. strcpy(systemSettings.Profile.tip[x].name, str); // Empty name
  208. }
  209. strcpy(systemSettings.Profile.tip[0].name, "BC3 "); // Put some generic name
  210. systemSettings.Profile.currentNumberOfTips = 1;
  211. systemSettings.Profile.currentTip = 0;
  212. systemSettings.Profile.impedance = 80; // 8.0 Ohms
  213. systemSettings.Profile.power = 80; // 80W
  214. systemSettings.Profile.noIronValue = 4000;
  215. systemSettings.Profile.Cal250_default = T12_Cal250;
  216. systemSettings.Profile.Cal350_default = T12_Cal350;
  217. systemSettings.Profile.Cal450_default = T12_Cal450;
  218. }
  219. else if(systemSettings.settings.currentProfile==profile_C245){
  220. systemSettings.Profile.ID = profile_C245;
  221. for(uint8_t x = 0; x < TipSize; x++) {
  222. systemSettings.Profile.tip[x].calADC_At_250 = C245_Cal250;
  223. systemSettings.Profile.tip[x].calADC_At_350 = C245_Cal350;
  224. systemSettings.Profile.tip[x].calADC_At_450 = C245_Cal450;
  225. systemSettings.Profile.tip[x].PID.Kp = 7500; // val = /1.000.000
  226. systemSettings.Profile.tip[x].PID.Ki = 4000; // val = /1.000.000
  227. systemSettings.Profile.tip[x].PID.Kd = 1000; // val = /1.000.000
  228. systemSettings.Profile.tip[x].PID.maxI = 40; // val = /100
  229. systemSettings.Profile.tip[x].PID.minI = 0; // val = /100
  230. strcpy(systemSettings.Profile.tip[x].name, str); // Empty name
  231. }
  232. strcpy(systemSettings.Profile.tip[0].name, "C245");
  233. systemSettings.Profile.currentNumberOfTips = 1;
  234. systemSettings.Profile.currentTip = 0;
  235. systemSettings.Profile.impedance = 26;
  236. systemSettings.Profile.power = 150;
  237. systemSettings.Profile.noIronValue = 4000;
  238. systemSettings.Profile.Cal250_default = C245_Cal250;
  239. systemSettings.Profile.Cal350_default = C245_Cal350;
  240. systemSettings.Profile.Cal450_default = C245_Cal450;
  241. }
  242. else if(systemSettings.settings.currentProfile==profile_C210){
  243. systemSettings.Profile.ID = profile_C210;
  244. for(uint8_t x = 0; x < TipSize; x++) {
  245. systemSettings.Profile.tip[x].calADC_At_250 = C210_Cal250;
  246. systemSettings.Profile.tip[x].calADC_At_350 = C210_Cal350;
  247. systemSettings.Profile.tip[x].calADC_At_450 = C210_Cal450;
  248. systemSettings.Profile.tip[x].PID.Kp = 7500; // val = /1.000.000
  249. systemSettings.Profile.tip[x].PID.Ki = 4000; // val = /1.000.000
  250. systemSettings.Profile.tip[x].PID.Kd = 1000; // val = /1.000.000
  251. systemSettings.Profile.tip[x].PID.maxI = 40; // val = /100
  252. systemSettings.Profile.tip[x].PID.minI = 0; // val = /100
  253. strcpy(systemSettings.Profile.tip[x].name, str); // Empty name
  254. }
  255. strcpy(systemSettings.Profile.tip[0].name, "C210");
  256. systemSettings.Profile.currentNumberOfTips = 1;
  257. systemSettings.Profile.currentTip = 0;
  258. systemSettings.Profile.power = 80;
  259. systemSettings.Profile.impedance = 21;
  260. systemSettings.Profile.noIronValue = 1200;
  261. systemSettings.Profile.Cal250_default = C210_Cal250;
  262. systemSettings.Profile.Cal350_default = C210_Cal350;
  263. systemSettings.Profile.Cal450_default = C210_Cal450;
  264. }
  265. else{
  266. Error_Handler(); // We shouldn't get here!
  267. }
  268. systemSettings.Profile.CalNTC = 25;
  269. systemSettings.Profile.sleepTimeout = 5;
  270. systemSettings.Profile.standbyTimeout = 5;
  271. systemSettings.Profile.standbyTemperature = 180;
  272. systemSettings.Profile.UserSetTemperature = 180;
  273. systemSettings.Profile.MaxSetTemperature = 450;
  274. systemSettings.Profile.MinSetTemperature = 180;
  275. systemSettings.Profile.pwmPeriod = 19999;
  276. systemSettings.Profile.pwmDelay = 1999;
  277. systemSettings.Profile.filterFactor = 2;
  278. systemSettings.Profile.tempUnit = mode_Celsius;
  279. systemSettings.Profile.NotInitialized = initialized;
  280. }
  281. void loadProfile(uint8_t profile){
  282. systemSettings.settings.currentProfile=profile; // Update system profile
  283. if(profile<=profile_C210){ // If current tip type is valid
  284. systemSettings.Profile = flashSettings->Profile[profile]; // Load stored tip data
  285. systemSettings.ProfileChecksum = flashSettings->ProfileChecksum[profile]; // Load stored checksum
  286. if(systemSettings.Profile.NotInitialized!=initialized){ // Check if initialized
  287. resetCurrentProfile(); // Load defaults if not
  288. systemSettings.ProfileChecksum = ChecksumProfile(&systemSettings.Profile); // Compute checksum
  289. }
  290. // Calculate data checksum and compare with stored checksum, also ensure the stored ID is the same as the requested profile
  291. if( (profile!=systemSettings.Profile.ID) || (systemSettings.ProfileChecksum != ChecksumProfile(&systemSettings.Profile)) ){
  292. ProfileChkErr(); // Checksum mismatch, reset current tip data
  293. }
  294. setUserTemperature(systemSettings.Profile.UserSetTemperature); // Load user set temperature
  295. setCurrentTip(systemSettings.Profile.currentTip); // Load TIP data
  296. Iron.updatePwm=needs_update; // Apply profile PWM settings
  297. }
  298. else if(profile==profile_None){
  299. return; // Profiles not initialized, load nothing
  300. }
  301. else{ // Unknown profile
  302. Error_Handler();
  303. }
  304. if(systemSettings.settings.tempUnit != systemSettings.Profile.tempUnit){ // If stored temps are in different units
  305. setSystemTempUnit(systemSettings.settings.tempUnit); // Convert temperatures
  306. systemSettings.Profile.tempUnit = systemSettings.settings.tempUnit; // Store unit in profile
  307. }
  308. }
  309. void Diag_init(void){
  310. setContrast(255);
  311. FillBuffer(BLACK,fill_soft);
  312. u8g2_SetFont(&u8g2,default_font );
  313. u8g2_SetDrawColor(&u8g2, WHITE);
  314. }
  315. void Flash_error(void){
  316. __disable_irq();
  317. HAL_FLASH_Lock();
  318. __enable_irq();
  319. Diag_init();
  320. putStrAligned("FLASH ERROR!", 16, align_center);
  321. putStrAligned("HALTING SYSTEM", 32, align_center);
  322. update_display();
  323. while(1){
  324. HAL_IWDG_Refresh(&hiwdg);
  325. }
  326. }
  327. void settingsChkErr(void){
  328. Diag_init();
  329. systemSettings.settings.OledOffset = 2; // Set default value
  330. putStrAligned("SETTING ERR!", 10, align_center);
  331. putStrAligned("RESTORING", 26, align_center);
  332. putStrAligned("DEFAULTS...", 42, align_center);
  333. update_display();
  334. ErrCountDown(3,117,50);
  335. if(systemSettings.settings.currentProfile<=profile_C210){ // If current tip type is valid
  336. if(systemSettings.ProfileChecksum==ChecksumProfile(&systemSettings.Profile)){ // If current profile checksum is correct
  337. uint8_t tip = systemSettings.settings.currentProfile; // save current tip
  338. resetSystemSettings(); // reset settings
  339. systemSettings.settings.currentProfile=tip; // Restore tip type
  340. saveSettings(saveKeepingProfiles); // Save settings preserving tip data
  341. }
  342. else{ // If checksum wrong
  343. resetSystemSettings(); // reset settings
  344. saveSettings(saveWipingProfiles); // Save settings erasing tip data
  345. }
  346. }
  347. else{ // If current tip not valid
  348. resetSystemSettings(); // Assume something went wrong, reset settings
  349. saveSettings(saveKeepingProfiles); // Save keeping tip data
  350. }
  351. }
  352. void ProfileChkErr(void){
  353. Diag_init();
  354. putStrAligned("PROFILE ERR!", 10, align_center);
  355. putStrAligned("RESTORING", 26, align_center);
  356. putStrAligned("DEFAULTS...", 42, align_center);
  357. update_display();
  358. ErrCountDown(3,117,50);
  359. resetCurrentProfile(); // Reset current tip type data only
  360. }
  361. void Button_reset(void){
  362. uint16_t ResetTimer= HAL_GetTick();
  363. if(!BUTTON_input()){
  364. Diag_init();
  365. putStrAligned("HOLD BUTTON", 10, align_center);
  366. putStrAligned("TO RESTORE", 26, align_center);
  367. putStrAligned("DEFAULTS", 42, align_center);
  368. update_display();
  369. while(!BUTTON_input()){
  370. HAL_IWDG_Refresh(&hiwdg);
  371. if((HAL_GetTick()-ResetTimer)>5000){
  372. FillBuffer(BLACK,fill_dma);
  373. putStrAligned("RELEASE", 16, align_center);
  374. putStrAligned("BUTTON NOW", 32, align_center);
  375. update_display();
  376. while(!BUTTON_input()){
  377. HAL_IWDG_Refresh(&hiwdg);
  378. }
  379. resetSystemSettings();
  380. saveSettings(saveWipingProfiles);
  381. }
  382. }
  383. }
  384. }
  385. //Max 99 seconds countdown.
  386. void ErrCountDown(uint8_t Start,uint8_t xpos, uint8_t ypos){
  387. uint32_t timErr = 0;
  388. char str[4];
  389. uint8_t length;
  390. if(Start>99){Start=99;}
  391. if(Start>9){
  392. length=2;
  393. }
  394. else{
  395. length=1;
  396. }
  397. HAL_IWDG_Refresh(&hiwdg);
  398. while(oled.status!=oled_idle); // Wait for the screen to be idle (few mS at most). Hanging here will cause a watchdog reset.
  399. while(Start){
  400. timErr=HAL_GetTick();
  401. u8g2_SetDrawColor(&u8g2, BLACK);
  402. u8g2_DrawBox(&u8g2,xpos,ypos,u8g2_GetStrWidth(&u8g2,str),u8g2_GetMaxCharHeight(&u8g2));
  403. u8g2_SetDrawColor(&u8g2, WHITE);
  404. sprintf(&str[0],"%*u",length-1,Start--);
  405. u8g2_DrawStr(&u8g2,xpos,ypos,str);
  406. update_display();
  407. while( (HAL_GetTick()-timErr)<999 ){
  408. HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
  409. }
  410. }
  411. }