LCOV - code coverage report
Current view: top level - SITL - SIM_Temperature_TSYS01.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 106 129 82.2 %
Date: 2026-09-09 11:02:08 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "SIM_config.h"
       2             : 
       3             : #if AP_SIM_TEMPERATURE_TSYS01_ENABLED
       4             : 
       5             : #include "SIM_Temperature_TSYS01.h"
       6             : 
       7             : #include <stdio.h>
       8             : 
       9             : constexpr const int32_t SITL::TSYS01::_k[6];
      10             : 
      11      220642 : int SITL::TSYS01::rdwr(I2C::i2c_rdwr_ioctl_data *&data)
      12             : {
      13      220642 :     if (data->nmsgs == 2) {
      14             :         // something is expecting a response....
      15      111548 :         if (data->msgs[0].flags != 0) {
      16           0 :             AP_HAL::panic("Unexpected flags");
      17             :         }
      18      111548 :         if (data->msgs[1].flags != I2C_M_RD) {
      19           0 :             AP_HAL::panic("Unexpected flags");
      20             :         }
      21      111548 :         const uint8_t command = data->msgs[0].buf[0];
      22      111548 :         switch ((Command)command) {
      23           0 :         case Command::RESET:
      24           0 :             AP_HAL::panic("Bad RESET");
      25         892 :         case Command::READ_PROM0:
      26             :         case Command::READ_PROM1:
      27             :         case Command::READ_PROM2:
      28             :         case Command::READ_PROM3:
      29             :         case Command::READ_PROM4:
      30             :         case Command::READ_PROM5: {
      31         892 :             if (state != State::RESET) {
      32           0 :                 AP_HAL::panic("reading prom outside RESET state");
      33             :             }
      34         892 :             if (data->msgs[1].len != 2) {
      35           0 :                 AP_HAL::panic("Unexpected prom read length");
      36             :             }
      37         892 :             const uint8_t prom_idx = (uint8_t(command) - uint8_t(Command::READ_PROM0))/2;
      38         892 :             if (prom_idx == 0) {
      39             :                 // PROM0 is the unused CRC register; not requested by the driver
      40          82 :                 data->msgs[1].buf[0] = 0;
      41          82 :                 data->msgs[1].buf[1] = 0;
      42          82 :                 break;
      43             :             }
      44             :             // prom_idx 1..5 → _k[5].._k[1] (reversed to match driver's read_prom ordering)
      45         810 :             const uint16_t k = _k[ARRAY_SIZE(_k) - prom_idx];
      46         810 :             data->msgs[1].buf[0] = k >> 8;
      47         810 :             data->msgs[1].buf[1] = k & 0xFF;
      48         810 :             break;
      49             :         }
      50           0 :         case Command::CONVERT:
      51           0 :             AP_HAL::panic("Bad CONVERT");
      52      108852 :         case Command::READ_ADC: {
      53      108852 :             uint8_t registers[3] {};
      54      108852 :             if (data->msgs[1].len != sizeof(registers)) {
      55           0 :                 AP_HAL::panic("Unexpected prom read length");
      56             :             }
      57      108852 :             if (state == State::CONVERTING) {
      58             :                 // we've been asked for values while still converting.
      59             :                 // Return zeroes per data sheet
      60      108852 :             } else if (state == State::CONVERTED) {
      61      108852 :                 uint32_t value = adc;
      62      108852 :                 registers[2] = value & 0xff;
      63      108852 :                 value >>= 8;
      64      108852 :                 registers[1] = value & 0xff;
      65      108852 :                 value >>= 8;
      66      108852 :                 registers[0] = value & 0xff;
      67      108852 :                 set_state(State::IDLE);
      68             :             } else {
      69             :                 // AP_HAL::panic("READ_ADC in bad state");
      70             :                 // this happens at startup
      71           0 :                 return -1;
      72             :             }
      73      435408 :             for (uint8_t i=0; i<ARRAY_SIZE(registers); i++) {
      74      326556 :                 data->msgs[1].buf[i] = registers[i];
      75             :             }
      76      108852 :             break;
      77             :         }
      78        1804 :         default:
      79             :             // NAK commands we do not understand.  The MS5611 probe
      80             :             // sends us prom reads for words 6 and 7 (0xAC and 0xAE);
      81             :             // failing the transfer here ensures the response buffer
      82             :             // is not returned uninitialised.
      83        1804 :             return -1;
      84             :         }
      85      109744 :         return 0;
      86             :     }
      87             : 
      88      109094 :     if (data->nmsgs == 1) {
      89             :         // incoming write-only command
      90      109094 :         const auto &msg = data->msgs[0];
      91      109094 :         const uint8_t cmd = msg.buf[0];
      92             : 
      93      109094 :         switch ((Command)cmd) {
      94         162 :         case Command::RESET:
      95         162 :             set_state(State::RESET);
      96         162 :             break;
      97           0 :         case Command::READ_PROM0:
      98             :         case Command::READ_PROM1:
      99             :         case Command::READ_PROM2:
     100             :         case Command::READ_PROM3:
     101             :         case Command::READ_PROM4:
     102             :         case Command::READ_PROM5:
     103           0 :             AP_HAL::panic("bad prom read");
     104      108932 :         case Command::CONVERT:
     105      108932 :             if (state != State::RESET &&
     106      108852 :                 state != State::CONVERTING &&
     107      108852 :                 state != State::IDLE &&
     108           0 :                 state != State::READ_PROM) {
     109           0 :                 AP_HAL::panic("Convert outside reset/idle");
     110             :             }
     111      108932 :             set_state(State::CONVERTING);
     112      108932 :             break;
     113           0 :         case Command::READ_ADC:
     114           0 :             AP_HAL::panic("bad READ_ADC");
     115           0 :         default:
     116             :             // NAK commands we do not understand
     117           0 :             return -1;
     118             :         }
     119      109094 :         return 0;
     120             :     }
     121           0 :     return -1;
     122             : }
     123             : 
     124             : // swiped from the driver:
     125     1921525 : float SITL::TSYS01::temperature_for_adc(uint32_t _adc) const
     126             : {
     127     1921525 :     const float adc16 = _adc/256.0;
     128             :     // Note that the offsets used here start from 1 (PROM1), not like
     129             :     // in the main codebase where they start from 0 (PROM1)!  The main
     130             :     // code does not read PROM0 from the device (real or simulated),
     131             :     // but the array in the simulator here reserves a space for it.
     132             :     return
     133     1921525 :         -2   * _k[5] * powf(10, -21) * powf(adc16, 4) +
     134     1921525 :         4    * _k[4] * powf(10, -16) * powf(adc16, 3) +
     135     1921525 :         -2   * _k[3] * powf(10, -11) * powf(adc16, 2) +
     136     1921525 :         1    * _k[2] * powf(10, -6)  * adc16 +
     137     1921525 :         -1.5 * _k[1] * powf(10, -2);
     138             : }
     139             : 
     140      108773 : uint32_t SITL::TSYS01::calculate_adc(float temperature) const
     141             : {
     142             :     // bisect to find the adc24 value:
     143      108773 :     uint32_t min_adc = 0;
     144      108773 :     uint32_t max_adc = 1<<24;
     145      108773 :     uint32_t current_adc = (min_adc+(uint64_t)max_adc)/2;
     146      108773 :     float current_error = fabsf(temperature_for_adc(current_adc) - temperature);
     147      108773 :     bool bisect_down = false;
     148             : 
     149             :     // temperature_for_adc(9378708);  // should be 10.59
     150             : 
     151     1921525 :     while (labs(int32_t(max_adc - min_adc)) > 1 && current_error > 0.05) {
     152             :         uint32_t candidate_adc;
     153     1812752 :         if (bisect_down) {
     154      875549 :             candidate_adc = (min_adc+(uint64_t)current_adc)/2;
     155             :         } else {
     156      937203 :             candidate_adc = (max_adc+(uint64_t)current_adc)/2;
     157             :         }
     158     1812752 :         const float candidate_temp = temperature_for_adc(candidate_adc);
     159     1812752 :         const float candidate_error = fabsf(candidate_temp - temperature);
     160     1812752 :         if (candidate_error > current_error) {
     161             :             // worse result
     162     1258438 :             if (bisect_down) {
     163      629219 :                 min_adc = candidate_adc;
     164      629219 :                 bisect_down = false;
     165             :             } else {
     166      629219 :                 max_adc = candidate_adc;
     167      629219 :                 bisect_down = true;
     168             :             }
     169             :         } else {
     170             :             // better result
     171      554314 :             if (bisect_down) {
     172      246330 :                 max_adc = current_adc;
     173      246330 :                 bisect_down = false;
     174             :             } else {
     175      307984 :                 min_adc = current_adc;
     176      307984 :                 bisect_down = true;
     177             :             }
     178      554314 :             current_adc = candidate_adc;
     179      554314 :             current_error = candidate_error;
     180             :         }
     181             :     }
     182      108773 :     return current_adc;
     183             : }
     184             : 
     185   178759942 : void SITL::TSYS01::update(const class Aircraft &aircraft)
     186             : {
     187   178759942 :     switch (state) {
     188           0 :     case State::UNKNOWN:
     189           0 :         break;
     190       31536 :     case State::RESET:
     191       31536 :         if (time_in_state_ms() > 10) {
     192        2018 :             set_state(State::READ_PROM);
     193             :         }
     194       31536 :         break;
     195   172192317 :     case State::READ_PROM:
     196   172192317 :         break;
     197           0 :     case State::IDLE:
     198           0 :         break;
     199      889798 :     case State::CONVERTING:
     200      889798 :         if (time_in_state_ms() > 5) {
     201      108906 :             const float temperature = get_sim_temperature();
     202      108906 :             if (!is_equal(last_temperature, temperature)) {
     203      108773 :                 last_temperature = temperature;
     204      108773 :                 adc = calculate_adc(temperature);
     205             :             }
     206      108906 :             set_state(State::CONVERTED);
     207             :         }
     208      889798 :         break;
     209     5646291 :     case State::CONVERTED:
     210     5646291 :         break;
     211             :     }
     212   178759942 : }
     213             : 
     214      108906 : float SITL::TSYS01::get_sim_temperature() const
     215             : {
     216      108906 :     float sim_alt = AP::sitl()->state.altitude;
     217      108906 :     sim_alt += 2 * rand_float();
     218             : 
     219             :     // To Do: Add a sensor board temperature offset parameter
     220      108906 :     return AP_Baro::get_temperatureC_for_alt_amsl(sim_alt) + 25;
     221             : }
     222             : 
     223             : #endif  // AP_SIM_TEMPERATURE_TSYS01_ENABLED

Generated by: LCOV version 1.14