AP_Compass_UAVCAN.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. #include <AP_HAL/AP_HAL.h>
  14. #if HAL_WITH_UAVCAN
  15. #include "AP_Compass_UAVCAN.h"
  16. #include <AP_BoardConfig/AP_BoardConfig_CAN.h>
  17. #include <AP_UAVCAN/AP_UAVCAN.h>
  18. #include <uavcan/equipment/ahrs/MagneticFieldStrength.hpp>
  19. #include <uavcan/equipment/ahrs/MagneticFieldStrength2.hpp>
  20. extern const AP_HAL::HAL& hal;
  21. #define debug_mag_uavcan(level_debug, can_driver, fmt, args...) do { if ((level_debug) <= AP::can().get_debug_level_driver(can_driver)) { printf(fmt, ##args); }} while (0)
  22. // Frontend Registry Binders
  23. UC_REGISTRY_BINDER(MagCb, uavcan::equipment::ahrs::MagneticFieldStrength);
  24. UC_REGISTRY_BINDER(Mag2Cb, uavcan::equipment::ahrs::MagneticFieldStrength2);
  25. AP_Compass_UAVCAN::DetectedModules AP_Compass_UAVCAN::_detected_modules[] = {0};
  26. HAL_Semaphore AP_Compass_UAVCAN::_sem_registry;
  27. AP_Compass_UAVCAN::AP_Compass_UAVCAN(AP_UAVCAN* ap_uavcan, uint8_t node_id, uint8_t sensor_id)
  28. : _ap_uavcan(ap_uavcan)
  29. , _node_id(node_id)
  30. , _sensor_id(sensor_id)
  31. {
  32. }
  33. void AP_Compass_UAVCAN::subscribe_msgs(AP_UAVCAN* ap_uavcan)
  34. {
  35. if (ap_uavcan == nullptr) {
  36. return;
  37. }
  38. auto* node = ap_uavcan->get_node();
  39. uavcan::Subscriber<uavcan::equipment::ahrs::MagneticFieldStrength, MagCb> *mag_listener;
  40. mag_listener = new uavcan::Subscriber<uavcan::equipment::ahrs::MagneticFieldStrength, MagCb>(*node);
  41. const int mag_listener_res = mag_listener->start(MagCb(ap_uavcan, &handle_magnetic_field));
  42. if (mag_listener_res < 0) {
  43. AP_HAL::panic("UAVCAN Mag subscriber start problem\n\r");
  44. return;
  45. }
  46. uavcan::Subscriber<uavcan::equipment::ahrs::MagneticFieldStrength2, Mag2Cb> *mag2_listener;
  47. mag2_listener = new uavcan::Subscriber<uavcan::equipment::ahrs::MagneticFieldStrength2, Mag2Cb>(*node);
  48. const int mag2_listener_res = mag2_listener->start(Mag2Cb(ap_uavcan, &handle_magnetic_field_2));
  49. if (mag2_listener_res < 0) {
  50. AP_HAL::panic("UAVCAN Mag subscriber start problem\n\r");
  51. return;
  52. }
  53. }
  54. AP_Compass_Backend* AP_Compass_UAVCAN::probe()
  55. {
  56. WITH_SEMAPHORE(_sem_registry);
  57. AP_Compass_UAVCAN* driver = nullptr;
  58. for (uint8_t i = 0; i < COMPASS_MAX_BACKEND; i++) {
  59. if (!_detected_modules[i].driver && _detected_modules[i].ap_uavcan) {
  60. // Register new Compass mode to a backend
  61. driver = new AP_Compass_UAVCAN(_detected_modules[i].ap_uavcan, _detected_modules[i].node_id, _detected_modules[i].sensor_id);
  62. if (driver) {
  63. _detected_modules[i].driver = driver;
  64. driver->init();
  65. debug_mag_uavcan(2,
  66. _detected_modules[i].ap_uavcan->get_driver_index(),
  67. "Found Mag Node %d on Bus %d Sensor ID %d\n",
  68. _detected_modules[i].node_id,
  69. _detected_modules[i].ap_uavcan->get_driver_index(),
  70. _detected_modules[i].sensor_id);
  71. }
  72. break;
  73. }
  74. }
  75. return driver;
  76. }
  77. void AP_Compass_UAVCAN::init()
  78. {
  79. _instance = register_compass();
  80. uint32_t devid = AP_HAL::Device::make_bus_id(AP_HAL::Device::BUS_TYPE_UAVCAN,
  81. _ap_uavcan->get_driver_index(),
  82. _node_id,
  83. 1); // the 1 is arbitrary
  84. set_dev_id(_instance, devid);
  85. set_external(_instance, true);
  86. debug_mag_uavcan(2, _ap_uavcan->get_driver_index(), "AP_Compass_UAVCAN loaded\n\r");
  87. }
  88. AP_Compass_UAVCAN* AP_Compass_UAVCAN::get_uavcan_backend(AP_UAVCAN* ap_uavcan, uint8_t node_id, uint8_t sensor_id)
  89. {
  90. if (ap_uavcan == nullptr) {
  91. return nullptr;
  92. }
  93. for (uint8_t i=0; i<COMPASS_MAX_BACKEND; i++) {
  94. if (_detected_modules[i].driver &&
  95. _detected_modules[i].ap_uavcan == ap_uavcan &&
  96. _detected_modules[i].node_id == node_id &&
  97. _detected_modules[i].sensor_id == sensor_id) {
  98. return _detected_modules[i].driver;
  99. }
  100. }
  101. bool already_detected = false;
  102. // Check if there's an empty spot for possible registeration
  103. for (uint8_t i = 0; i < COMPASS_MAX_BACKEND; i++) {
  104. if (_detected_modules[i].ap_uavcan == ap_uavcan &&
  105. _detected_modules[i].node_id == node_id &&
  106. _detected_modules[i].sensor_id == sensor_id) {
  107. // Already Detected
  108. already_detected = true;
  109. break;
  110. }
  111. }
  112. if (!already_detected) {
  113. for (uint8_t i = 0; i < COMPASS_MAX_BACKEND; i++) {
  114. if (nullptr == _detected_modules[i].ap_uavcan) {
  115. _detected_modules[i].ap_uavcan = ap_uavcan;
  116. _detected_modules[i].node_id = node_id;
  117. _detected_modules[i].sensor_id = sensor_id;
  118. break;
  119. }
  120. }
  121. }
  122. return nullptr;
  123. }
  124. void AP_Compass_UAVCAN::handle_mag_msg(const Vector3f &mag)
  125. {
  126. Vector3f raw_field = mag * 1000.0;
  127. accumulate_sample(raw_field, _instance);
  128. }
  129. void AP_Compass_UAVCAN::handle_magnetic_field(AP_UAVCAN* ap_uavcan, uint8_t node_id, const MagCb &cb)
  130. {
  131. WITH_SEMAPHORE(_sem_registry);
  132. Vector3f mag_vector;
  133. AP_Compass_UAVCAN* driver = get_uavcan_backend(ap_uavcan, node_id, 0);
  134. if (driver != nullptr) {
  135. mag_vector[0] = cb.msg->magnetic_field_ga[0];
  136. mag_vector[1] = cb.msg->magnetic_field_ga[1];
  137. mag_vector[2] = cb.msg->magnetic_field_ga[2];
  138. driver->handle_mag_msg(mag_vector);
  139. }
  140. }
  141. void AP_Compass_UAVCAN::handle_magnetic_field_2(AP_UAVCAN* ap_uavcan, uint8_t node_id, const Mag2Cb &cb)
  142. {
  143. WITH_SEMAPHORE(_sem_registry);
  144. Vector3f mag_vector;
  145. uint8_t sensor_id = cb.msg->sensor_id;
  146. AP_Compass_UAVCAN* driver = get_uavcan_backend(ap_uavcan, node_id, sensor_id);
  147. if (driver != nullptr) {
  148. mag_vector[0] = cb.msg->magnetic_field_ga[0];
  149. mag_vector[1] = cb.msg->magnetic_field_ga[1];
  150. mag_vector[2] = cb.msg->magnetic_field_ga[2];
  151. driver->handle_mag_msg(mag_vector);
  152. }
  153. }
  154. void AP_Compass_UAVCAN::read(void)
  155. {
  156. drain_accumulated_samples(_instance);
  157. }
  158. #endif