/* * geany_encoding=koi8-r * sensors_manage.c * * Copyright 2018 Edward V. Emelianov * * This program 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 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "sensors_manage.h" #include "can_process.h" #include "i2c.h" #include "usart.h" extern volatile uint32_t Tms; uint8_t sensors_scan_mode = 0; // infinite scan mode static uint32_t lastSensT = 0; static SensorsState Sstate = SENS_OFF; // turn on sensors only by request static uint8_t curr_mul_addr = 0; // current sensors pair address @ multiplexer static uint8_t overcurnt_ctr = 0; // if this counter > 32 go to OFF state uint8_t sens_present[2] = {0,0}; // bit flag: Nth bit == 1 if sensor[s] on given channel found static uint8_t Nsens_present = 0; // total amount of sensors found static uint8_t Ntemp_measured = 0; // total amount of themperatures measured // 8 - amount of pairs, 2 - amount in pair, 5 - amount of Coef. static uint16_t coefficients[MUL_MAX_ADDRESS+1][2][5]; // Coefficients for given sensors // measured temperatures * 100 int16_t Temperatures[MUL_MAX_ADDRESS+1][2]; // pair addresses static const uint8_t Taddr[2] = {TSYS01_ADDR0, TSYS01_ADDR1}; SensorsState sensors_get_state(){return Sstate;} /** * Get temperature & calculate it by polinome * T = (-2) * k4 * 10^{-21} * ADC16^4 * + 4 * k3 * 10^{-16} * ADC16^3 * + (-2) * k2 * 10^{-11} * ADC16^2 * + 1 * k1 * 10^{-6} * ADC16 * +(-1.5)* k0 * 10^{-2} * k0*(-1.5e-2) + 1e-6*val*(k1 + 1e-5*val*(-2*k2 + 1e-5*val*(4*k3 + -2e-5*k4*val))) * * @param t - value from sensor * @param i - number of sensor in pair * @return -30000 if something wrong or T*100 if all OK */ static uint16_t calc_t(uint32_t t, int i){ uint16_t *coeff = coefficients[curr_mul_addr][i]; if(coeff[0] == 0) return BAD_TEMPERATURE; // what is with coeffs? if(t < 600000 || t > 30000000) return BAD_TEMPERATURE; // wrong value - too small or too large int j; double d = (double)t/256., tmp = 0.; // k0*(-1.5e-2) + 0.1*1e-5*val*(1*k1 + 1e-5*val*(-2.*k2 + 1e-5*val*(4*k3 + 1e-5*val*(-2*k4)))) const double mul[5] = {-1.5e-2, 1., -2., 4., -2.}; for(j = 4; j > 0; --j){ tmp += mul[j] * (double)coeff[j]; tmp *= 1e-5*d; } tmp = tmp * 10. + 100. * mul[0] * coeff[0]; return (uint16_t)tmp; } // turn off sensors' power void sensors_off(){ MUL_OFF(); // turn off multiplexers SENSORS_OFF(); // turn off sensors' power Sstate = SENS_OFF; } /** * if all OK with current, turn ON sensors' power and change state to "initing" */ void sensors_on(){ sens_present[0] = sens_present[1] = 0; curr_mul_addr = 0; Nsens_present = 0; MUL_OFF(); if(SENSORS_OVERCURNT()){ SENSORS_OFF(); Sstate = (++overcurnt_ctr > 32) ? SENS_OVERCURNT_OFF : SENS_OVERCURNT; }else{ SENSORS_ON(); Sstate = SENS_INITING; } } /** * start measurement if sensors are sleeping, * turn ON if they were OFF * do nothing if measurement processing */ void sensors_start(){ if(sensors_scan_mode) return; switch(Sstate){ case SENS_SLEEPING: Sstate = SENS_START_MSRMNT; break; case SENS_OFF: sensors_on(); break; default: break; } } // count 1 bits in sens_present & set `Nsens_present` to this value static void count_sensors(){ Nsens_present = 0; uint16_t B = sens_present[0]<<8 | sens_present[1]; while(B){ ++Nsens_present; B &= (B - 1); } } /** * All procedures return 1 if they change current state due to error & 0 if all OK */ // procedure call each time @ resetting static uint8_t resetproc(){ uint8_t i, ctr = 0; SEND("pair "); printu(curr_mul_addr); SEND(" : "); for(i = 0; i < 2; ++i){ if(write_i2c(Taddr[i], TSYS01_RESET)){ usart_putchar('0' + i); ++ctr; sens_present[i] |= 1< MUL_MAX_ADDRESS){ // scan is over curr_mul_addr = 0; return 1; } } return 0; } // print coefficients @debug console void showcoeffs(){ int a, p, k; if(Nsens_present == 0){ SEND("No sensors found\n"); return; } for(a = 0; a <= MUL_MAX_ADDRESS; ++a){ for(p = 0; p < 2; ++p){ if(!(sens_present[p] & (1< 32) ? SENS_OVERCURNT_OFF : SENS_OVERCURNT; return; } switch (Sstate){ case SENS_INITING: // initialisation (restart I2C) //MSG("init->reset\n"); i2c_setup(CURRENT_SPEED); Sstate = SENS_RESETING; lastSensT = Tms; overcurnt_ctr = 0; break; case SENS_RESETING: // reset & discovery procedure if(Tms - lastSensT > POWERUP_TIME){ overcurnt_ctr = 0; if(sensors_scan(resetproc)){ count_sensors(); // get total amount of sensors if(Nsens_present){ //MSG("reset->getcoeff\n"); Sstate = SENS_GET_COEFFS; }else{ // no sensors found //MSG("reset->off\n"); sensors_off(); } } } break; case SENS_GET_COEFFS: // get coefficients if(sensors_scan(getcoefsproc)){ //MSG("got coeffs for "); #if 0 printu(Nsens_present); SEND(" sensors ->start\n"); #endif Sstate = SENS_START_MSRMNT; } break; case SENS_START_MSRMNT: // send all sensors command to start measurements if(sensors_scan(msrtempproc)){ lastSensT = Tms; //MSG("->wait\n"); Sstate = SENS_WAITING; Ntemp_measured = 0; // reset value of good measurements } break; case SENS_WAITING: // wait for end of conversion if(Tms - lastSensT > CONV_TIME){ //MSG("->gather\n"); Sstate = SENS_GATHERING; } break; case SENS_GATHERING: // scan all sensors, get thermal data & calculate temperature if(sensors_scan(gettempproc)){ lastSensT = Tms; NsentOverCAN = 0; Sstate = SENS_SLEEPING; //MSG("->sleep\n"); /* if(Nsens_present == Ntemp_measured){ // All OK, amount of T == amount of sensors MSG("->sleep\n"); Sstate = SENS_SLEEPING; }else{ // reinit I2C & try to start measurements again MSG("gather error ->start\n"); i2c_setup(CURRENT_SPEED); Sstate = SENS_START_MSRMNT; }*/ } break; case SENS_SLEEPING: // wait for `SLEEP_TIME` till next measurements NsentOverCAN = send_temperatures(NsentOverCAN); // call sending T process if(NsentOverCAN == -1){ if(Nsens_present != Ntemp_measured){ // restart sensors only after measurements sent i2c_setup(CURRENT_SPEED); sensors_on(); } if(sensors_scan_mode){ // sleep until next measurement start if(Tms - lastSensT > SLEEP_TIME){ //MSG("sleep->start\n"); Sstate = SENS_START_MSRMNT; } } } break; case SENS_OVERCURNT: // try to reinit all after overcurrent //MSG("try to turn on after overcurrent\n"); sensors_on(); break; default: // do nothing break; } }