Device.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /*
  2. * This file is free software: you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License as published by the
  4. * Free Software Foundation, either version 3 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This file is distributed in the hope that it will be useful, but
  8. * WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. * See the GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License along
  13. * with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "Device.h"
  16. #include <stdio.h>
  17. /*
  18. using checked registers allows a device check that a set of critical
  19. register values don't change at runtime. This is useful on key
  20. sensors (such as IMUs) which may experience brownouts or other
  21. issues in flight
  22. To use register checking call setup_checked_registers() once to
  23. allocate the space for the checked register values. The set the
  24. checked flag on any write_register() calls that you want protected.
  25. Periodically (say at 50Hz) you should then call
  26. check_next_register(). If that returns false then the sensor has had
  27. a corrupted register value. Marking the sensor as unhealthy is
  28. approriate. The bad value will be corrected
  29. */
  30. /*
  31. setup nregs checked registers
  32. */
  33. bool AP_HAL::Device::setup_checked_registers(uint8_t nregs, uint8_t frequency)
  34. {
  35. if (_checked.regs != nullptr) {
  36. delete[] _checked.regs;
  37. _checked.n_allocated = 0;
  38. _checked.n_set = 0;
  39. _checked.next = 0;
  40. }
  41. _checked.regs = new struct checkreg[nregs];
  42. if (_checked.regs == nullptr) {
  43. return false;
  44. }
  45. _checked.n_allocated = nregs;
  46. _checked.frequency = frequency;
  47. _checked.counter = 0;
  48. return true;
  49. }
  50. /*
  51. set value of one checked register
  52. */
  53. void AP_HAL::Device::set_checked_register(uint8_t reg, uint8_t val)
  54. {
  55. if (_checked.regs == nullptr) {
  56. return;
  57. }
  58. struct checkreg *regs = _checked.regs;
  59. for (uint8_t i=0; i<_checked.n_set; i++) {
  60. if (regs[i].regnum == reg) {
  61. regs[i].value = val;
  62. return;
  63. }
  64. }
  65. if (_checked.n_set == _checked.n_allocated) {
  66. printf("Not enough checked registers for reg 0x%02x on device 0x%x\n",
  67. (unsigned)reg, (unsigned)get_bus_id());
  68. return;
  69. }
  70. regs[_checked.n_set].regnum = reg;
  71. regs[_checked.n_set].value = val;
  72. _checked.n_set++;
  73. }
  74. /*
  75. check one register value
  76. */
  77. bool AP_HAL::Device::check_next_register(void)
  78. {
  79. if (_checked.n_set == 0) {
  80. return true;
  81. }
  82. if (++_checked.counter < _checked.frequency) {
  83. return true;
  84. }
  85. _checked.counter = 0;
  86. struct checkreg &reg = _checked.regs[_checked.next];
  87. uint8_t v;
  88. if (!read_registers(reg.regnum, &v, 1) || v != reg.value) {
  89. // a register has changed value unexpectedly. Try changing it back
  90. // and re-check it next time
  91. #if 0
  92. printf("Device 0x%x fixing 0x%02x 0x%02x -> 0x%02x\n",
  93. (unsigned)get_bus_id(),
  94. (unsigned)reg.regnum, (unsigned)v, (unsigned)reg.value);
  95. #endif
  96. write_register(reg.regnum, reg.value);
  97. return false;
  98. }
  99. _checked.next = (_checked.next+1) % _checked.n_set;
  100. return true;
  101. }