Sat, 04 May 2024 15:18:02 +0200
Log pid of each started thread so we can see which uses the most cpu time.
/***************************************************************************** * Copyright (C) 2014-2024 * * Michiel Broek <mbroek at mbse dot eu> * * This file is part of the mbsePi-apps * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * mbsePi-apps 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 ThermFerm; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ extern int debug; #include "thermferm.h" #include "statetbl.h" #include "delay.h" #include "xutil.h" #include "websocket.h" #include "simulator.h" int my_simulator_state = THREAD_OFF; int my_simulator_command = THREAD_OFF; #ifdef USE_SIMULATOR extern sys_config Config; extern const char DEVPRESENT[4][6]; static int simulate(void); /* * Return json data for one simulator */ char *simulator_json(simulator_list *simulator) { char *payload, buf[64]; payload = xstrcpy((char *)"{\"uuid\":\""); payload = xstrcat(payload, simulator->uuid); payload = xstrcat(payload, (char *)"\",\"name\":\""); payload = xstrcat(payload, simulator->name); payload = xstrcat(payload, (char *)"\",\"simno\":"); sprintf(buf, "%d", simulator->simno); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"volume_air\":"); sprintf(buf, "%d", simulator->volume_air); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"volume_beer\":"); sprintf(buf, "%d", simulator->volume_beer); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"room\":{\"tempaddress\":\""); payload = xstrcat(payload, simulator->room_tempaddress); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.1f", simulator->room_temperature); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"humaddress\":\""); payload = xstrcat(payload, simulator->room_humaddress); payload = xstrcat(payload, (char *)"\",\"humidity\":"); sprintf(buf, "%.1f", simulator->room_humidity); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"air\":{\"address\":\""); payload = xstrcat(payload, simulator->air_address); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.4f", simulator->air_temperature); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->air_present]); payload = xstrcat(payload, (char *)"\"},\"beer\":{\"address\":\""); payload = xstrcat(payload, simulator->beer_address); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.4f", simulator->beer_temperature); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->beer_present]); payload = xstrcat(payload, (char *)"\"},\"beer2\":{\"address\":\""); payload = xstrcat(payload, simulator->beer_address2); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.4f", simulator->beer_temperature2); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->beer_present2]); payload = xstrcat(payload, (char *)"\"},\"chiller\":{\"address\":\""); payload = xstrcat(payload, simulator->chiller_address); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.4f", simulator->chiller_temperature); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->chiller_present]); payload = xstrcat(payload, (char *)"\"},\"cooler\":{\"address\":\""); payload = xstrcat(payload, simulator->cooler_address); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.4f", simulator->cooler_temp); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"time\":"); sprintf(buf, "%d", simulator->cooler_time); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"size\":"); sprintf(buf, "%.4f", simulator->cooler_size); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->cooler_present]); payload = xstrcat(payload, (char *)"\",\"power\":"); sprintf(buf, "%d", simulator->cooler_power); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"heater\":{\"address\":\""); payload = xstrcat(payload, simulator->heater_address); payload = xstrcat(payload, (char *)"\",\"temperature\":"); sprintf(buf, "%.4f", simulator->heater_temp); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"time\":"); sprintf(buf, "%d", simulator->heater_time); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"size\":"); sprintf(buf, "%.4f", simulator->heater_size); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->heater_present]); payload = xstrcat(payload, (char *)"\",\"power\":"); sprintf(buf, "%d", simulator->heater_power); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"fan\":{\"address\":\""); payload = xstrcat(payload, simulator->fan_address); payload = xstrcat(payload, (char *)"\",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->fan_present]); payload = xstrcat(payload, (char *)"\",\"power\":"); sprintf(buf, "%d", simulator->fan_power); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"light\":{\"address\":\""); payload = xstrcat(payload, simulator->light_address); payload = xstrcat(payload, (char *)"\",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->light_present]); payload = xstrcat(payload, (char *)"\",\"power\":"); sprintf(buf, "%d", simulator->light_power); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"door\":{\"address\":\""); payload = xstrcat(payload, simulator->door_address); payload = xstrcat(payload, (char *)"\",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->door_present]); payload = xstrcat(payload, (char *)"\",\"value\":"); sprintf(buf, "%d", simulator->door_value); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"psu\":{\"address\":\""); payload = xstrcat(payload, simulator->psu_address); payload = xstrcat(payload, (char *)"\",\"present\":\""); payload = xstrcat(payload, (char *)DEVPRESENT[simulator->psu_present]); payload = xstrcat(payload, (char *)"\",\"value\":"); sprintf(buf, "%d", simulator->psu_value); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"frigo_isolation\":"); sprintf(buf, "%.4f", simulator->frigo_isolation); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"timestamp\":"); sprintf(buf, "%ld", (long)simulator->timestamp); payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"}"); return payload; } void simulator_ws(void) { bool comma = false; char *payload = NULL, *payloadu = NULL; simulator_list *simulator; payload = xstrcpy((char *)"{\"type\":\"simulator\",\"metric\":["); for (simulator = Config.simulators; simulator; simulator = simulator->next) { if (comma) payload = xstrcat(payload, (char *)","); payloadu = simulator_json(simulator); payload = xstrcat(payload, payloadu); comma = true; free(payloadu); payloadu = NULL; } payload = xstrcat(payload, (char *)"]}"); ws_broadcast(payload); free(payload); payload = NULL; } void *my_simulator_loop(void *threadid) { pid_t pid = gettid(); my_simulator_command = THREAD_RUN; syslog(LOG_NOTICE, "Thread my_simulator_loop started, pid=%d", pid); /* * Run the state machine */ simulate(); syslog(LOG_NOTICE, "Thread my_simulator_loop stopped"); return 0; } SM_DECL(simulate, (char *)"simulator") SM_STATES Init, Pause, Waiting, Run, Websocket SM_NAMES (char *)"Init", (char *)"Pause", (char *)"Waiting", (char *)"run", (char *)"Websocket" SM_EDECL simulator_list *simulator; time_t now, last = (time_t)0; int seconds = 0; double k_room_air, sqm_room_air, thick_room_air, air_heat_transfer; double air_change, vhc_air = 0.00121; double air_temp, beer_temp, chiller_temp; bool changed = false; SM_START(Init) SM_STATE(Init) for (simulator = Config.simulators; simulator; simulator = simulator->next) { /* * Heater and cooler have the air temperature */ simulator->s_heat_temp = simulator->s_cool_temp = simulator->room_temperature; } my_simulator_state = THREAD_RUN; SM_PROCEED(Waiting); SM_STATE(Pause) my_simulator_state = THREAD_PAUSE; if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; } else if (my_simulator_command == THREAD_RUN) { my_simulator_state = THREAD_RUN; SM_PROCEED(Waiting); } mDelay(50); SM_STATE(Waiting) if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; } else if (my_simulator_command == THREAD_PAUSE) { SM_PROCEED(Pause); } now = time(NULL); if (now != last) { last = now; seconds++; SM_PROCEED(Run); } mDelay(50L); SM_STATE(Run) changed = false; for (simulator = Config.simulators; simulator; simulator = simulator->next) { if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; } else if (my_simulator_command == THREAD_PAUSE) { SM_PROCEED(Pause); } /* * Copy to duplicates */ air_temp = simulator->air_temperature; beer_temp = simulator->beer_temperature; chiller_temp = simulator->chiller_temperature; /* * First, calculate temperature difference between the room and the air in the * fridge. We use the volume air to roughly calculate the total area between * the in and outside. Calculate the effect and shift the air temperature towards * the room temperature. */ sqm_room_air = (cbrtl(simulator->volume_air) * cbrtl(simulator->volume_air) * 6) / 100; /* square meters all fridge sides */ thick_room_air = 0.04; /* 4 cm walls */ k_room_air = 0.03; /* Polystrene */ air_heat_transfer=(k_room_air * sqm_room_air * (simulator->room_temperature - air_temp)) / thick_room_air; air_change = (air_heat_transfer / (vhc_air * ((simulator->volume_air - simulator->volume_beer) * 1000))) / 60.0; air_temp += air_change; /* * If heating, calculate temperature of the heating plate. If heating is off but * the plate is warmer then the air, calculate the cooling down temperature. * Finally, calculate the new air and plate temperature. */ if (simulator->heater_present == DEVPRESENT_YES && simulator->heater_power >= 50) { if (simulator->s_heat_temp < simulator->heater_temp) { simulator->s_heat_temp += 0.05; if (simulator->s_heat_temp > simulator->air_temperature) air_temp += ((simulator->s_heat_temp - air_temp) / 100.0); } } else { /* * Follow the air temperature */ simulator->s_heat_temp -= (simulator->s_heat_temp - air_temp) / 25.0; } /* * If cooling, calculate temperature of the cooling plate. If cooling is off but * the plate is colder then the air, calculate the warming up temperature. * Finsally, calculate the new air and plate temperature. */ if (simulator->cooler_present == DEVPRESENT_YES && simulator->cooler_power >= 50) { if (simulator->s_cool_temp > simulator->cooler_temp) { simulator->s_cool_temp -= 0.05; if (simulator->s_cool_temp < air_temp) air_temp -= ((air_temp - simulator->s_cool_temp) / 100.0); } } else { simulator->s_cool_temp -= (simulator->s_cool_temp - air_temp) / 25.0; } /* * Calculate final temperature of the beer and the air. */ // Cheap trick, just follow slowly the air temp. beer_temp += ((air_temp - beer_temp) / 500.0); air_temp += ((beer_temp - air_temp) / 2500.0); chiller_temp = simulator->cooler_temp; // Link these /* * Finally update simulated sensors with the new values. * The devices_loop will pickup the values and sets the resolution. */ if (air_temp != simulator->air_temperature) { // syslog(LOG_NOTICE, "SIM %d: air %f to %f", simulator->simno, simulator->air_temperature, air_temp); simulator->air_temperature = air_temp; changed = true; } if (beer_temp != simulator->beer_temperature) { // syslog(LOG_NOTICE, "SIM %d: beer %f to %f", simulator->simno, simulator->beer_temperature, beer_temp); simulator->beer_temperature = beer_temp; changed = true; } if (chiller_temp != simulator->chiller_temperature) { // syslog(LOG_NOTICE, "SIM %d: chiller %f to %f", simulator->simno, simulator->chiller_temperature, chiller_temp); simulator->chiller_temperature = chiller_temp; changed = true; } } SM_PROCEED(Websocket); SM_STATE(Websocket) if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; } else if (my_simulator_command == THREAD_PAUSE) { SM_PROCEED(Pause); } if (changed) { simulator_ws(); changed = false; } SM_PROCEED(Waiting); SM_END my_simulator_state = THREAD_OFF; SM_RETURN #endif