37 #include <board_config.h> 48 #include <px4_arch/dshot.h> 49 #include <px4_platform_common/atomic.h> 50 #include <px4_platform_common/px4_config.h> 51 #include <px4_platform_common/getopt.h> 52 #include <px4_platform_common/log.h> 53 #include <px4_platform_common/module.h> 54 #include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> 91 #if !defined(BOARD_HAS_PWM) 92 # error "board_config.h needs to define BOARD_HAS_PWM" 122 static int task_spawn(
int argc,
char *argv[]);
125 static int custom_command(
int argc,
char *argv[]);
128 static int print_usage(
const char *reason =
nullptr);
136 static int module_new_mode(
PortMode new_mode);
138 virtual int ioctl(
file *filp,
int cmd,
unsigned long arg);
145 static void capture_trampoline(
void *context, uint32_t chan_index,
149 bool updateOutputs(
bool stop_motors, uint16_t outputs[MAX_ACTUATORS],
150 unsigned num_outputs,
unsigned num_control_groups_updated)
override;
152 void mixerChanged()
override;
163 void retrieveAndPrintESCInfoThreadSafe(
int motor_index);
168 static constexpr uint16_t DISARMED_VALUE = 0;
180 int num_repetitions{0};
181 uint8_t motor_mask{0xff};
183 bool valid()
const {
return num_repetitions > 0; }
184 void clear() { num_repetitions = 0; }
190 int last_motor_index{-1};
193 void updateTelemetryNumMotors();
194 void initTelemetry(
const char *
device);
197 int requestESCInfo();
202 static char _telemetry_device[20];
205 px4::atomic<DShotTelemetry::OutputBuffer *> _request_esc_info{
nullptr};
206 bool _waiting_for_esc_info{
false};
213 px4::atomic<Command *> _new_command{
nullptr};
215 unsigned _num_outputs{0};
216 int _class_instance{-1};
218 bool _outputs_on{
false};
219 uint32_t _output_mask{0};
220 bool _outputs_initialized{
false};
224 void capture_callback(uint32_t chan_index,
225 hrt_abstime edge_time, uint32_t edge_state, uint32_t overflow);
226 int pwm_ioctl(
file *filp,
int cmd,
unsigned long arg);
227 void update_dshot_out_state(
bool on);
231 int capture_ioctl(
file *filp,
int cmd,
unsigned long arg);
237 (ParamInt<px4::params::DSHOT_CONFIG>) _param_dshot_config,
238 (ParamFloat<px4::params::DSHOT_MIN>) _param_dshot_min,
239 (ParamInt<px4::params::MOT_POLE_COUNT>) _param_mot_pole_count
285 PX4_ERR(
"FAILED registering class device");
318 #if defined(BOARD_HAS_CAPTURE) 323 PX4_DEBUG(
"MODE_2PWM2CAP");
329 PX4_DEBUG(
"MODE_2PWM");
338 #if defined(BOARD_HAS_CAPTURE) 341 PX4_DEBUG(
"MODE_3PWM1CAP");
348 PX4_DEBUG(
"MODE_3PWM");
357 #if defined(BOARD_HAS_CAPTURE) 360 PX4_DEBUG(
"MODE_4PWM1CAP");
367 PX4_DEBUG(
"MODE_4PWM");
376 #if defined(BOARD_HAS_CAPTURE) 379 PX4_DEBUG(
"MODE_4PWM2CAP");
390 #if defined(BOARD_HAS_CAPTURE) 393 PX4_DEBUG(
"MODE_5PWM1CAP");
400 PX4_DEBUG(
"MODE_5PWM");
409 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 6 412 PX4_DEBUG(
"MODE_6PWM");
422 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 8 425 PX4_DEBUG(
"MODE_8PWM");
434 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 14 437 PX4_DEBUG(
"MODE_14PWM");
447 PX4_DEBUG(
"MODE_NONE");
473 _object.store(instance);
474 _task_id = task_id_is_work_queue;
476 if (instance->
init() == PX4_OK) {
481 PX4_ERR(
"alloc failed");
485 _object.store(
nullptr);
493 hrt_abstime edge_time, uint32_t edge_state, uint32_t overflow)
501 hrt_abstime edge_time, uint32_t edge_state, uint32_t overflow)
503 fprintf(stdout,
"DShot: Capture chan:%d time:%lld state:%d overflow:%d\n", chan_index, edge_time, edge_state, overflow);
511 unsigned dshot_frequency;
535 PX4_ERR(
"up_dshot_init failed (%i)", ret);
569 PX4_ERR(
"alloc failed");
577 PX4_ERR(
"telemetry init failed (%i)", ret);
588 if (motor_index < esc_status_s::CONNECTED_ESC_MAX) {
591 esc_status.
esc[motor_index].
esc_rpm = ((int)data.
erpm * 100) / (_param_mot_pole_count.get() / 2);
599 if (motor_index <= _telemetry->last_motor_index) {
622 if (motor_index == -1) {
661 if (output_buffer.
buf_pos == 0) {
662 PX4_ERR(
"No data received. If telemetry is setup correctly, try again");
674 _current_command.
motor_mask = 1 << motor_index;
677 PX4_DEBUG(
"Requesting ESC info for motor %i", motor_index);
687 unsigned num_outputs,
unsigned num_control_groups_updated)
693 int requested_telemetry_index = -1;
709 for (
int i = 0; i < (int)num_outputs; i++) {
710 if (_current_command.
valid() && (_current_command.
motor_mask & (1 << i))) {
719 if (_current_command.
valid()) {
724 for (
int i = 0; i < (int)num_outputs; i++) {
725 if (outputs[i] == DISARMED_VALUE) {
734 _current_command.
clear();
737 if (stop_motors || num_control_groups_updated > 0) {
771 if (telem_update != -1) {
776 }
else if (telem_update >= 0) {
786 if (_request_telemetry_init.load()) {
788 _request_telemetry_init.store(
false);
792 if (!_current_command.
valid()) {
796 _current_command = *new_command;
828 if (ret != -ENOTTY) {
844 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 6 847 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 8 850 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 14 857 PX4_DEBUG(
"not in a PWM mode");
862 if (ret == -ENOTTY) {
863 ret = CDev::ioctl(filp, cmd, arg);
874 PX4_DEBUG(
"dshot ioctl cmd: %d, arg: %ld", cmd, arg);
882 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 14 885 *(
unsigned *)arg = 14;
889 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 8 892 *(
unsigned *)arg = 8;
896 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 6 899 *(
unsigned *)arg = 6;
905 *(
unsigned *)arg = 5;
911 *(
unsigned *)arg = 4;
916 *(
unsigned *)arg = 3;
921 *(
unsigned *)arg = 2;
925 *(
unsigned *)arg = 1;
966 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >=6 973 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >=8 1067 const char *buf = (
const char *)arg;
1068 unsigned buflen = strlen(buf);
1089 #if defined(BOARD_HAS_CAPTURE) 1177 *(
unsigned *)arg = 1;
1182 *(
unsigned *)arg = 2;
1254 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM == 4 1258 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM == 6 1261 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM == 8 1264 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM == 14 1274 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 8 1281 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 6 1294 # if defined(BOARD_HAS_CAPTURE) 1309 # if defined(BOARD_HAS_CAPTURE) 1328 # if defined(BOARD_HAS_CAPTURE) 1341 # if defined(BOARD_HAS_CAPTURE) 1359 object->set_mode(mode);
1368 const char *verb = argv[0];
1370 if (!strcmp(verb,
"telemetry")) {
1373 strncpy(_telemetry_device, argv[1],
sizeof(_telemetry_device) - 1);
1375 _request_telemetry_init.store(
true);
1381 int motor_index = -1;
1384 const char *myoptarg =
nullptr;
1386 while ((ch = px4_getopt(argc, argv,
"m:", &myoptind, &myoptarg)) != EOF) {
1389 motor_index = strtol(myoptarg,
nullptr, 10) - 1;
1403 constexpr
Command commands[] = {
1416 for (
unsigned i = 0; i <
sizeof(commands) /
sizeof(commands[0]); ++i) {
1417 if (!strcmp(verb, commands[i].
name)) {
1419 PX4_ERR(
"module not running");
1423 return get_instance()->sendCommandThreadSafe(commands[i].command, commands[i].num_repetitions, motor_index);
1427 if (!strcmp(verb,
"esc_info")) {
1429 PX4_ERR(
"module not running");
1433 if (motor_index == -1) {
1434 PX4_ERR(
"No motor index specified");
1439 PX4_ERR(
"Telemetry is not enabled, but required to get ESC info");
1443 get_instance()->retrieveAndPrintESCInfoThreadSafe(motor_index);
1459 if (!strcmp(verb,
"mode_gpio")) {
1462 }
else if (!strcmp(verb,
"mode_pwm")) {
1466 #if defined(BOARD_HAS_PWM) 1468 }
else if (!strcmp(verb,
"mode_pwm1")) {
1472 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 6 1474 }
else if (!strcmp(verb,
"mode_pwm6")) {
1477 }
else if (!strcmp(verb,
"mode_pwm5")) {
1480 # if defined(BOARD_HAS_CAPTURE) 1482 }
else if (!strcmp(verb,
"mode_pwm5cap1")) {
1486 }
else if (!strcmp(verb,
"mode_pwm4")) {
1489 # if defined(BOARD_HAS_CAPTURE) 1491 }
else if (!strcmp(verb,
"mode_pwm4cap1")) {
1494 }
else if (!strcmp(verb,
"mode_pwm4cap2")) {
1498 }
else if (!strcmp(verb,
"mode_pwm3")) {
1501 # if defined(BOARD_HAS_CAPTURE) 1503 }
else if (!strcmp(verb,
"mode_pwm3cap1")) {
1507 }
else if (!strcmp(verb,
"mode_pwm2")) {
1510 # if defined(BOARD_HAS_CAPTURE) 1512 }
else if (!strcmp(verb,
"mode_pwm2cap2")) {
1516 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 8 1518 }
else if (!strcmp(verb,
"mode_pwm8")) {
1535 const char *mode_str =
nullptr;
1539 case MODE_NONE: mode_str =
"no outputs";
break;
1541 case MODE_1PWM: mode_str =
"outputs1";
break;
1543 case MODE_2PWM: mode_str =
"outputs2";
break;
1547 case MODE_3PWM: mode_str =
"outputs3";
break;
1551 case MODE_4PWM: mode_str =
"outputs4";
break;
1557 case MODE_5PWM: mode_str =
"outputs5";
break;
1561 case MODE_6PWM: mode_str =
"outputs6";
break;
1563 case MODE_8PWM: mode_str =
"outputs8";
break;
1565 case MODE_4CAP: mode_str =
"cap4";
break;
1567 case MODE_5CAP: mode_str =
"cap5";
break;
1569 case MODE_6CAP: mode_str =
"cap6";
break;
1576 PX4_INFO(
"Mode: %s", mode_str);
1580 PX4_INFO(
"Outputs on: %s",
_outputs_on ?
"yes" :
"no");
1585 PX4_INFO(
"telemetry on: %s", _telemetry_device);
1595 PX4_WARN(
"%s\n", reason);
1598 PRINT_MODULE_DESCRIPTION(
1601 This is the DShot output driver. It is similar to the fmu driver, and can be used as drop-in replacement 1602 to use DShot as ESC communication protocol instead of PWM. 1605 - DShot150, DShot300, DShot600, DShot1200 1606 - telemetry via separate UART and publishing as esc_status message 1607 - sending DShot commands via CLI 1610 Permanently reverse motor 1: 1611 $ dshot reverse -m 1 1613 After saving, the reversed direction will be regarded as the normal one. So to reverse again repeat the same commands. 1616 PRINT_MODULE_USAGE_NAME("dshot",
"driver");
1617 PRINT_MODULE_USAGE_COMMAND_DESCR(
"start",
"Start the task (without any mode set, use any of the mode_* cmds)");
1619 PRINT_MODULE_USAGE_PARAM_COMMENT(
"All of the mode_* commands will start the module if not running already");
1621 PRINT_MODULE_USAGE_COMMAND(
"mode_gpio");
1622 PRINT_MODULE_USAGE_COMMAND_DESCR(
"mode_pwm",
"Select all available pins as PWM");
1623 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 8 1624 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm8");
1626 #if defined(BOARD_HAS_PWM) && BOARD_HAS_PWM >= 6 1627 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm6");
1628 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm5");
1629 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm5cap1");
1630 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm4");
1631 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm4cap1");
1632 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm4cap2");
1633 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm3");
1634 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm3cap1");
1635 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm2");
1636 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm2cap2");
1638 #if defined(BOARD_HAS_PWM) 1639 PRINT_MODULE_USAGE_COMMAND(
"mode_pwm1");
1642 PRINT_MODULE_USAGE_COMMAND_DESCR(
"telemetry",
"Enable Telemetry on a UART");
1643 PRINT_MODULE_USAGE_ARG(
"<device>",
"UART device",
false);
1646 PRINT_MODULE_USAGE_COMMAND_DESCR(
"reverse",
"Reverse motor direction");
1647 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1648 PRINT_MODULE_USAGE_COMMAND_DESCR(
"normal",
"Normal motor direction");
1649 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1650 PRINT_MODULE_USAGE_COMMAND_DESCR(
"save",
"Save current settings");
1651 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1652 PRINT_MODULE_USAGE_COMMAND_DESCR(
"3d_on",
"Enable 3D mode");
1653 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1654 PRINT_MODULE_USAGE_COMMAND_DESCR(
"3d_off",
"Disable 3D mode");
1655 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1656 PRINT_MODULE_USAGE_COMMAND_DESCR(
"beep1",
"Send Beep pattern 1");
1657 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1658 PRINT_MODULE_USAGE_COMMAND_DESCR(
"beep2",
"Send Beep pattern 2");
1659 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1660 PRINT_MODULE_USAGE_COMMAND_DESCR(
"beep3",
"Send Beep pattern 3");
1661 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1662 PRINT_MODULE_USAGE_COMMAND_DESCR(
"beep4",
"Send Beep pattern 4");
1663 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1664 PRINT_MODULE_USAGE_COMMAND_DESCR(
"beep5",
"Send Beep pattern 5");
1665 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based, default=all)",
true);
1667 PRINT_MODULE_USAGE_COMMAND_DESCR(
"esc_info",
"Request ESC information");
1668 PRINT_MODULE_USAGE_PARAM_INT(
'm', -1, 0, 16,
"Motor index (1-based)",
false);
1670 PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
__EXPORT void up_dshot_trigger(void)
Trigger dshot data transfer.
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
#define PWM_SERVO_MODE_2PWM2CAP
struct esc_report_s esc[8]
perf_counter_t _cycle_perf
#define MIXERIOCLOADBUF
Add mixer(s) from the buffer in (const char *)arg.
px4::atomic< DShotTelemetry::OutputBuffer * > _request_esc_info
bool telemetryEnabled() const
const actuator_armed_s & armed() const
#define DSHOT1200
Dshot PWM frequency.
MixingOutput _mixing_output
static px4::atomic_bool _request_telemetry_init
void initTelemetry(const char *device)
#define PWM_SERVO_MODE_2PWM
measure the time elapsed performing an event
static int print_usage(const char *reason=nullptr)
#define PWM_SERVO_MODE_4PWM
#define PWM_SERVO_GET_COUNT
get the number of servos in *(unsigned *)arg
unsigned get_multirotor_count()
virtual int ioctl(file *filp, int cmd, unsigned long arg)
#define PWM_SERVO_MODE_8PWM
#define PWM_SERVO_MODE_5PWM1CAP
uORB::PublicationData< esc_status_s > esc_status_pub
virtual int register_class_devname(const char *class_devname)
Register a class device name, automatically adding device class instance suffix if need be...
int main(int argc, char **argv)
void lock()
Take the driver lock.
int pwm_ioctl(file *filp, int cmd, unsigned long arg)
uint8_t esc_connectiontype
static int task_spawn(int argc, char *argv[])
int getRequestMotorIndex()
Get the motor index for which telemetry should be requested.
void setNumMotors(int num_motors)
void retrieveAndPrintESCInfoThreadSafe(int motor_index)
#define PWM_SERVO_MODE_NONE
set auxillary output mode.
bool update()
Call this regularly from Run().
void mixerChanged() override
called whenever the mixer gets updated/reset
int sendCommandThreadSafe(dshot_command_t command, int num_repetitions, int motor_index)
Send a dshot command to one or all motors This is expected to be called from another thread...
static void print_usage()
int8_t temperature
[deg C]
int capture_ioctl(file *filp, int cmd, unsigned long arg)
#define PWM_SERVO_MODE_4PWM1CAP
Namespace encapsulating all device framework classes, functions and data.
bool updateSubscriptions(bool allow_wq_switch)
Check for subscription updates (e.g.
#define DSHOT_MAX_THROTTLE
High-resolution timer with callouts and timekeeping.
px4::atomic< Command * > _new_command
Global flash based parameter store.
static int custom_command(int argc, char *argv[])
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
#define PWM_SERVO_MODE_6PWM
#define PWM_SERVO_MODE_3PWM
__EXPORT int up_dshot_init(uint32_t channel_mask, unsigned dshot_pwm_freq)
Intialise the Dshot outputs using the specified configuration.
__EXPORT int up_dshot_arm(bool armed)
Arm or disarm dshot outputs (This will enable/disable complete timer for safety purpose.).
Abstract class for any character device.
Drive scheduling based on subscribed actuator controls topics (via uORB callbacks) ...
void perf_free(perf_counter_t handle)
Free a counter.
void init()
Activates/configures the hardware registers.
uORB::Subscription _param_sub
virtual int unregister_class_devname(const char *class_devname, unsigned class_instance)
Register a class device name, automatically adding device class instance suffix if need be...
#define PWM_SERVO_MODE_5PWM
int update()
Read telemetry from the UART (non-blocking) and handle timeouts.
#define PWM_SERVO_MODE_5CAP
const EscData & latestESCData() const
#define PWM_SERVO_MODE_4CAP
void resetMixerThreadSafe()
Reset (unload) the complete mixer, called from another thread.
bool updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS], unsigned num_outputs, unsigned num_control_groups_updated) override
Callback to update the (physical) actuator outputs in the driver.
static void capture_trampoline(void *context, uint32_t chan_index, hrt_abstime edge_time, uint32_t edge_state, uint32_t overflow)
PortMode
Mode given via CLI.
void perf_end(perf_counter_t handle)
End a performance event.
#define PWM_SERVO_MODE_6CAP
bool expectingData() const
Check whether we are currently expecting to read new data from an ESC.
int reorderedMotorIndex(int index) const
Get the motor index that maps from PX4 convention to the configured one.
bool updated()
Check if there is a new update.
Base class for an output module.
bool _waiting_for_esc_info
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
int loadMixerThreadSafe(const char *buf, unsigned len)
Load (append) a new mixer from a buffer, called from another thread.
__EXPORT void up_dshot_motor_command(unsigned channel, uint16_t command, bool telemetry)
Send DShot command to a channel (motor).
void handleNewTelemetryData(int motor_index, const DShotTelemetry::EscData &data)
#define PWM_SERVO_MODE_4PWM2CAP
constexpr _Tp min(_Tp a, _Tp b)
#define MIXERIOCRESET
reset (clear) the mixer configuration
static void update_params(ParameterHandles ¶m_handles, Parameters ¶ms, bool &got_changes)
__EXPORT int dshot_main(int argc, char *argv[])
void setAllMaxValues(uint16_t value)
#define PWM_SERVO_SET_MODE
static char _telemetry_device[20]
int redirectOutput(OutputBuffer &buffer)
Redirect everything that is read into a different buffer.
#define PWM_OUTPUT_BASE_DEVICE_PATH
Path for the default PWM output device.
__EXPORT void up_dshot_motor_data_set(unsigned channel, uint16_t throttle, bool telemetry)
Set the current dshot throttle value for a channel (motor).
struct @83::@85::@87 file
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
void setAllDisarmedValues(uint16_t value)
static int module_new_mode(PortMode new_mode)
change the mode of the running module
void setDriverInstance(uint8_t instance)
void updateTelemetryNumMotors()
int init(const char *uart_device)
static void decodeAndPrintEscInfoPacket(const OutputBuffer &buffer)
bool update(void *dst)
Update the struct.
MixerGroup * mixers() const
void unregister()
unregister uORB subscription callbacks
#define PWM_SERVO_MODE_1PWM
bool _outputs_initialized
int print_status() override
void unlock()
Release the driver lock.
#define PWM_SERVO_MODE_3PWM1CAP
void perf_begin(perf_counter_t handle)
Begin a performance event.
This handles the mixing, arming/disarming and all subscriptions required for that.
#define PWM_SERVO_SET_COUNT
set the number of servos in (unsigned)arg - allows change of split between servos and GPIO ...
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
void update_dshot_out_state(bool on)
Performance measuring tools.
void setAllMinValues(uint16_t value)
void capture_callback(uint32_t chan_index, hrt_abstime edge_time, uint32_t edge_state, uint32_t overflow)