drivers/timers: Add common include files, definitions and upper-half for DSHOT

DShot is a packet based serial protocol, used for controlling motor controllers
(ESCs), typically for drones.

This adds an upper-half driver for dshot protocol, along with common
configuration options and definitions definitions.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
Jukka Laitinen 2026-03-18 11:48:50 +02:00 committed by Xiang Xiao
parent c3e7c94d2f
commit b810cbe4d3
6 changed files with 986 additions and 0 deletions

View file

@ -86,6 +86,10 @@ if(CONFIG_PWM)
list(APPEND SRCS pwm.c)
endif()
if(CONFIG_DSHOT)
list(APPEND SRCS dshot.c)
endif()
if(CONFIG_CAPTURE)
list(APPEND SRCS capture.c)

View file

@ -112,6 +112,24 @@ config FAKE_CAPTURE
endif # CAPTURE
config DSHOT
bool "DShot Driver Support"
default n
---help---
This selection enables the DShot driver for ESC control.
if DSHOT
config DSHOT_NCHANNELS
int "Maximum DShot channels in API structs"
default 8
range 1 16
---help---
Specifies the number of output channels per timer. Each timer
may support fewer output channels than this value.
endif # DSHOT
config TIMER
bool "Timer Support"
default n

View file

@ -118,6 +118,12 @@ ifeq ($(CONFIG_PWM),y)
TMRVPATH = :timers
endif
ifeq ($(CONFIG_DSHOT),y)
CSRCS += dshot.c
TMRDEPPATH = --dep-path timers
TMRVPATH = :timers
endif
ifeq ($(CONFIG_CAPTURE),y)
CSRCS += capture.c

638
drivers/timers/dshot.c Normal file
View file

@ -0,0 +1,638 @@
/****************************************************************************
* drivers/timers/dshot.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/fs/fs.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/timers/dshot.h>
#ifdef CONFIG_DSHOT
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define DSHOT_GCR_MASK 0x000fffffu
#define DSHOT_ERPMSCALE_NUM 600000u
/****************************************************************************
* Private Types
****************************************************************************/
struct dshot_upperhalf_s
{
uint8_t crefs;
mutex_t lock;
FAR struct dshot_lowerhalf_s *dev;
struct dshot_ch_telemetry_s telemetry[DSHOT_NCHANNELS];
bool bidir;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int dshot_open(FAR struct file *filep);
static int dshot_close(FAR struct file *filep);
static ssize_t dshot_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t dshot_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
static int dshot_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_dshotops =
{
dshot_open, /* open */
dshot_close, /* close */
dshot_read, /* read */
dshot_write, /* write */
NULL, /* seek */
dshot_ioctl, /* ioctl */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: dshot_crc
*
* Description:
* Calculate the 4-bit CRC for a DShot packet.
*
* Input Parameters:
* packet - The DShot packet to calculate CRC for.
* bidir - Boolean indicating if bidirectional DShot is enabled.
*
* Returned Value:
* The calculated 4-bit CRC value.
*
****************************************************************************/
static uint16_t dshot_crc(uint16_t packet, bool bidir)
{
uint16_t crc;
crc = packet >> 4;
crc = crc ^ (crc >> 4) ^ (crc >> 8);
if (bidir)
{
crc = ~crc;
}
return crc & 0xf;
}
/****************************************************************************
* Name: dshot_build_packet
*
* Description:
* Build a complete DShot packet from throttle, telemetry, and bidir
* values.
*
* Input Parameters:
* throttle - Throttle value (0-2047).
* telemetry - Boolean indicating if telemetry request is enabled.
* bidir - Boolean indicating if bidirectional DShot is enabled.
*
* Returned Value:
* The constructed 16-bit DShot packet.
*
****************************************************************************/
static uint16_t dshot_build_packet(uint16_t throttle, bool telemetry,
bool bidir)
{
uint16_t packet = 0;
packet |= throttle << 5;
packet |= (telemetry ? 1 << 4 : 0);
packet |= dshot_crc(packet, bidir);
return packet;
}
/****************************************************************************
* Name: dshot_parse_raw_packet
*
* Description:
* Parse raw pattern from the line into a 16-bit packet and verify CRC.
* Steps:
* 1. Extract GCR20 value from the raw value
* 2. Extract the 16-bit packet from the GCR20
* 3. Check the packet CRC
*
* Input Parameters:
* raw - The raw encoded packet value to parse.
*
* Returned Value:
* On success, returns the 12-bit payload as a positive integer.
* On error, returns a negative error code.
*
****************************************************************************/
static int dshot_parse_raw_packet(uint32_t raw)
{
static const int8_t gcr_decode[32] =
{
-1, -1, -1, -1, -1, -1, -1, -1,
-1, 9, 10, 11, -1, 13, 14, 15,
-1, -1, 2, 3, -1, 5, 6, 7,
-1, 0, 8, 1, -1, 4, 12, -1
};
uint32_t gcr20 = (raw ^ (raw >> 1)) & DSHOT_GCR_MASK;
uint16_t packet = 0;
int i;
for (i = 0; i < 4; i++)
{
int16_t nibble = gcr_decode[gcr20 & 0x1f];
if (nibble < 0)
{
return -EINVAL;
}
packet |= nibble << (4 * i);
gcr20 >>= 5;
}
if (dshot_crc(packet, true) != (packet & 0xf))
{
return -EINVAL;
}
return packet >> 4;
}
/****************************************************************************
* Name: dshot_copy_telemetry
*
* Description:
* Copy telemetry data for selected channels from upper-half to output.
*
* Input Parameters:
* upper - Pointer to the upper-half driver state.
* out - Pointer to output telemetry array.
* ch_mask - Bitmask indicating which channels to copy.
*
* Returned Value:
* None.
*
****************************************************************************/
static void dshot_copy_telemetry(FAR struct dshot_upperhalf_s *upper,
FAR struct dshot_ch_telemetry_s *out,
uint16_t ch_mask)
{
int i;
for (i = 0; i < DSHOT_NCHANNELS; i++)
{
if ((ch_mask & (1u << i)) != 0)
{
out[i] = upper->telemetry[i];
}
}
}
/****************************************************************************
* Name: dshot_update_telemetry
*
* Description:
* Update telemetry data from lower-half driver for selected channels.
* Parses raw telemetry data and extracts EDT or eRPM information.
*
* Input Parameters:
* upper - Pointer to the upper-half driver state.
* ch_mask - Bitmask indicating which channels to update.
*
* Returned Value:
* OK on success; a negated errno value on failure.
*
****************************************************************************/
static int dshot_update_telemetry(FAR struct dshot_upperhalf_s *upper,
uint16_t ch_mask)
{
FAR struct dshot_lowerhalf_s *lower = upper->dev;
struct dshot_raw_telemetry_s raw[DSHOT_NCHANNELS];
int i;
int ret;
memset(raw, 0, sizeof(raw));
DEBUGASSERT(lower->ops->get_raw_telemetry != NULL);
ret = lower->ops->get_raw_telemetry(lower, raw, ch_mask);
if (ret < 0)
{
return ret;
}
for (i = 0; i < DSHOT_NCHANNELS; i++)
{
if ((ch_mask & (1u << i)) != 0)
{
int value = dshot_parse_raw_packet(raw[i].raw);
if (value > 0)
{
uint16_t telem = (uint16_t)value & 0x0fff;
uint8_t exponent = telem >> 9;
if ((exponent & 1) == 0)
{
upper->telemetry[i].edt_type = (uint8_t)(telem >> 8);
upper->telemetry[i].edt_value = (uint8_t)(telem & 0xff);
upper->telemetry[i].timestamp = raw[i].timestamp;
}
else
{
uint32_t mantissa = telem & 0x1ff;
uint32_t period = mantissa << exponent;
if (period != 0)
{
uint32_t rpm = DSHOT_ERPMSCALE_NUM / period;
upper->telemetry[i].erpm =
(uint16_t)((rpm > 0xffff) ? 0xffff : rpm);
upper->telemetry[i].timestamp = raw[i].timestamp;
}
}
}
}
}
return OK;
}
/****************************************************************************
* Name: dshot_open
*
* Description:
* This function is called whenever the DShot device is opened.
*
* Input Parameters:
* filep - A pointer to the file structure instance.
*
* Returned Value:
* OK on success; a negated errno value on failure.
*
****************************************************************************/
static int dshot_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct dshot_upperhalf_s *upper = inode->i_private;
uint8_t tmp;
int ret;
ret = nxmutex_lock(&upper->lock);
if (ret < 0)
{
return ret;
}
tmp = upper->crefs + 1;
if (tmp == 0)
{
nxmutex_unlock(&upper->lock);
return -EMFILE;
}
if (tmp == 1)
{
DEBUGASSERT(upper->dev->ops->setup != NULL);
ret = upper->dev->ops->setup(upper->dev);
if (ret < 0)
{
nxmutex_unlock(&upper->lock);
return ret;
}
}
upper->crefs = tmp;
nxmutex_unlock(&upper->lock);
return OK;
}
/****************************************************************************
* Name: dshot_close
*
* Description:
* This function is called when the DShot device is closed.
*
* Input Parameters:
* filep - A pointer to the file structure instance.
*
* Returned Value:
* OK on success; a negated errno value on failure.
*
****************************************************************************/
static int dshot_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct dshot_upperhalf_s *upper = inode->i_private;
int ret;
ret = nxmutex_lock(&upper->lock);
if (ret < 0)
{
return ret;
}
if (upper->crefs > 1)
{
upper->crefs--;
}
else
{
upper->crefs = 0;
DEBUGASSERT(upper->dev->ops->shutdown != NULL);
upper->dev->ops->shutdown(upper->dev);
}
nxmutex_unlock(&upper->lock);
return OK;
}
/****************************************************************************
* Name: dshot_read
*
* Description:
* A dummy read method. This is provided only to satisfy the VFS layer.
*
* Input Parameters:
* filep - A pointer to the file structure instance.
* buffer - The user-provided buffer into which data will be returned.
* buflen - The size of the buffer in bytes.
*
* Returned Value:
* Always returns 0 (end-of-file).
*
****************************************************************************/
static ssize_t dshot_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
return 0;
}
/****************************************************************************
* Name: dshot_write
*
* Description:
* A dummy write method. This is provided only to satisfy the VFS layer.
*
* Input Parameters:
* filep - A pointer to the file structure instance.
* buffer - The user-provided buffer from which data will be written.
* buflen - The number of bytes to be written.
*
* Returned Value:
* Always returns -EPERM (operation not permitted).
*
****************************************************************************/
static ssize_t dshot_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen)
{
return -EPERM;
}
/****************************************************************************
* Name: dshot_ioctl
*
* Description:
* The standard ioctl method. This is used to perform DShot-specific
* operations including setting throttle, configuring channels, and
* retrieving telemetry data.
*
* Input Parameters:
* filep - A pointer to the file structure instance.
* cmd - The ioctl command code.
* arg - The argument provided with the ioctl command.
*
* Returned Value:
* OK on success; a negated errno value on failure.
*
****************************************************************************/
static int dshot_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode = filep->f_inode;
FAR struct dshot_upperhalf_s *upper = inode->i_private;
FAR struct dshot_lowerhalf_s *lower = upper->dev;
int ret;
ret = nxmutex_lock(&upper->lock);
if (ret < 0)
{
return ret;
}
switch (cmd)
{
case DSHOTIOC_CONFIGURE:
{
FAR struct dshot_config_s *cfg =
(FAR struct dshot_config_s *)((uintptr_t)arg);
if (cfg == NULL)
{
ret = -EINVAL;
break;
}
DEBUGASSERT(lower->ops->configure);
ret = lower->ops->configure(lower, cfg);
upper->bidir = cfg->bidir;
}
break;
case DSHOTIOC_SET_THROTTLE:
{
FAR struct dshot_throttle_s *req =
(FAR struct dshot_throttle_s *)((uintptr_t)arg);
uint16_t packets[DSHOT_NCHANNELS];
int i;
if (req == NULL)
{
ret = -EINVAL;
break;
}
/* Retrieve the latest telemetry */
if (req->telemetry_req != 0)
{
ret = dshot_update_telemetry(upper, req->telemetry_req);
if (ret < 0)
{
break;
}
dshot_copy_telemetry(upper, req->ch_telemetry,
req->telemetry_req);
}
/* Build DShot packets for each channel */
for (i = 0; i < DSHOT_NCHANNELS; i++)
{
if ((req->ch_mask & (1u << i)) != 0)
{
bool telemetry = (req->telemetry_req & (1u << i)) != 0;
packets[i] =
dshot_build_packet(req->throttle[i], telemetry,
upper->bidir);
}
}
/* Send the packets */
DEBUGASSERT(lower->ops->send_command);
ret = lower->ops->send_command(lower, packets, req->ch_mask);
}
break;
case DSHOTIOC_GET_TELEMETRY:
{
FAR struct dshot_telemetry_s *tlm =
(FAR struct dshot_telemetry_s *)((uintptr_t)arg);
if (tlm == NULL)
{
ret = -EINVAL;
break;
}
ret = dshot_update_telemetry(upper, tlm->ch_mask);
if (ret < 0)
{
break;
}
dshot_copy_telemetry(upper, tlm->ch_telemetry, tlm->ch_mask);
ret = OK;
}
break;
default:
{
if (lower->ops->ioctl != NULL)
{
ret = lower->ops->ioctl(lower, cmd, arg);
}
else
{
ret = -ENOTTY;
}
}
break;
}
nxmutex_unlock(&upper->lock);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: dshot_register
*
* Description:
* This function binds an instance of a "lower half" DShot driver with the
* "upper half" DShot device and registers that device so that it can be
* used by application code.
*
* When this function is called, the "lower half" driver should be in the
* reset state (as if the shutdown() method had already been called).
*
* Input Parameters:
* path - The full path to the driver to be registered in the NuttX pseudo-
* filesystem. The recommended convention is to name all DShot drivers
* as "/dev/dshot0", "/dev/dshot1", etc., where the driver path differs
* only in the "minor" number at the end of the device name.
* dev - A pointer to an instance of lower half DShot driver. This
* instance is bound to the DShot driver and must persist as long as the
* driver persists.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
int dshot_register(FAR const char *path, FAR struct dshot_lowerhalf_s *dev)
{
FAR struct dshot_upperhalf_s *upper;
int ret;
if (dev == NULL || dev->ops == NULL)
{
return -EINVAL;
}
upper = kmm_zalloc(sizeof(struct dshot_upperhalf_s));
if (upper == NULL)
{
return -ENOMEM;
}
nxmutex_init(&upper->lock);
upper->dev = dev;
ret = register_driver(path, &g_dshotops, 0666, upper);
if (ret < 0)
{
nxmutex_destroy(&upper->lock);
kmm_free(upper);
return ret;
}
return OK;
}
#endif /* CONFIG_DSHOT */

View file

@ -113,6 +113,7 @@
#define _1WIREBASE (0x4500) /* 1WIRE ioctl commands */
#define _EEPIOCBASE (0x4600) /* EEPROM driver ioctl commands */
#define _PTPBASE (0x4700) /* PTP ioctl commands */
#define _DSHOTIOCBASE (0x4800) /* Dshot device ioctl commands */
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
/* boardctl() commands share the same number space */
@ -807,6 +808,13 @@
#define _PTPIOCVALID(c) (_IOC_TYPE(c)==_PTPBASE)
#define _PTPIOC(nr) _IOC(_PTPBASE,nr)
/* DSHOT ioctl definitions (see nuttx/timers/dshot.h) ***********************/
/* see nuttx/include/timers/dshot.h */
#define _DSHOTIOCVALID(c) (_IOC_TYPE(c)==_DSHOTIOCBASE)
#define _DSHOTIOC(nr) _IOC(_DSHOTIOCBASE,nr)
/****************************************************************************
* Public Type Definitions
****************************************************************************/

View file

@ -0,0 +1,312 @@
/****************************************************************************
* include/nuttx/timers/dshot.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_TIMERS_DSHOT_H
#define __INCLUDE_NUTTX_TIMERS_DSHOT_H
/* Common definitions for DShot drivers */
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <nuttx/fs/ioctl.h>
#include <time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_DSHOT_NCHANNELS
# if CONFIG_DSHOT_NCHANNELS > 16
# error "max 16 channels supported"
# endif
# define DSHOT_NCHANNELS CONFIG_DSHOT_NCHANNELS
#else
# define DSHOT_NCHANNELS 1
#endif
/* IOCTL Commands ***********************************************************/
/* Configure the DShot instance; speed, bidirectional mode, active channels */
#define DSHOTIOC_CONFIGURE _DSHOTIOC(0x01)
/* Write throttle data or special command for one or more channels */
#define DSHOTIOC_SET_THROTTLE _DSHOTIOC(0x02)
/* Retrieve telemetry from the last successful bidirectional RX */
#define DSHOTIOC_GET_TELEMETRY _DSHOTIOC(0x03)
/* DSHOT Speeds *************************************************************/
#define DSHOT_SPEED_150 150000u
#define DSHOT_SPEED_300 300000u
#define DSHOT_SPEED_600 600000u
#define DSHOT_SPEED_1200 1200000u
#define DSHOT_SPEED_2400 2400000u
#define DSHOT_SPEED_3600 3600000u
/* DSHOT special commands (throttle values 0-47)*****************************/
#define DSHOT_CMD_MOTOR_STOP 0
#define DSHOT_CMD_BEEP1 1
#define DSHOT_CMD_BEEP2 2
#define DSHOT_CMD_BEEP3 3
#define DSHOT_CMD_BEEP4 4
#define DSHOT_CMD_BEEP5 5
#define DSHOT_CMD_ESC_INFO 6
#define DSHOT_CMD_SPIN_DIRECTION_1 7
#define DSHOT_CMD_SPIN_DIRECTION_2 8
#define DSHOT_CMD_3D_MODE_OFF 9
#define DSHOT_CMD_3D_MODE_ON 10
#define DSHOT_CMD_SETTINGS_REQUEST 11
#define DSHOT_CMD_SAVE_SETTINGS 12
#define DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE 13
#define DSHOT_CMD_EXTENDED_TELEMETRY_DISABLE 14
/* 15 - 19 Unassigned */
#define DSHOT_CMD_SPIN_DIRECTION_NORMAL 20
#define DSHOT_CMD_SPIN_DIRECTION_REVERSED 21
#define DSHOT_CMD_LED0_ON 22
#define DSHOT_CMD_LED1_ON 23
#define DSHOT_CMD_LED2_ON 24
#define DSHOT_CMD_LED3_ON 25
#define DSHOT_CMD_LED0_OFF 26
#define DSHOT_CMD_LED1_OFF 27
#define DSHOT_CMD_LED2_OFF 28
#define DSHOT_CMD_LED3_OFF 29
#define DSHOT_CMD_AUDIO_STREAM_MODE 30
#define DSHOT_CMD_SILENT_MODE 31
#define DSHOT_CMD_SIGNAL_LINE_TELEMETRY_DISABLE 32
#define DSHOT_CMD_SIGNAL_LINE_TELEMETRY_ENABLE 33
#define DSHOT_CMD_SIGNAL_LINE_CONTINUOUS_ERPM_TELEMETRY 34
#define DSHOT_CMD_SIGNAL_LINE_CONTINUOUS_ERPM_PERIOD_TELEMETRY 35
/* 36 - 41 Unassigned */
#define DSHOT_CMD_SIGNAL_LINE_TEMPERATURE_TELEMETRY 42
#define DSHOT_CMD_SIGNAL_LINE_VOLTAGE_TELEMETRY 43
#define DSHOT_CMD_SIGNAL_LINE_CURRENT_TELEMETRY 44
#define DSHOT_CMD_SIGNAL_LINE_CONSUMPTION_TELEMETRY 45
#define DSHOT_CMD_SIGNAL_LINE_ERPM_TELEMETRY 46
#define DSHOT_CMD_SIGNAL_LINE_ERPM_PERIOD_TELEMETRY 47
/* Extended telemetry types *************************************************/
#define DSHOT_EDT_TYPE_TEMP 0x02 /* Temperature in C */
#define DSHOT_EDT_TYPE_V 0x04 /* Voltage: 0.25V per step */
#define DSHOT_EDT_TYPE_A 0x06 /* Current in Amp */
#define DSHOT_EDT_TYPE_DBG1 0x08 /* Debug value 1 */
#define DSHOT_EDT_TYPE_DBG2 0x0A /* Debug value 2 */
#define DSHOT_EDT_TYPE_DBG3 0x0C /* Debug value 3 */
#define DSHOT_EDT_TYPE_STATE 0x0E /* State/Event */
/****************************************************************************
* Public Types
****************************************************************************/
/* Configuration argument for DSHOTIOC_CONFIGURE
*
* freq - Bit rate in Hz: DSHOT_SPEED_150/300/600/1200/2400/3600
* telem_freq - Telemetry frequency. Use 1.25 * freq for standard speed
* (e.g., 750kHz for DShot600). Some ESCs may require
* different values (e.g., 1.15 * freq for T-motor F55A).
* active_mask - Bitmask of active channels (bit0=ch0, bit1=ch1, etc.)
* bidir - Enable bidirectional DShot (inverted command data,
* response on same line).
*/
struct dshot_config_s
{
uint32_t freq;
uint32_t telem_freq;
uint16_t active_mask;
bool bidir;
};
/* Telemetry data for a single DShot channel. Contains eRPM, extended
* telemetry type/value, and timestamp of the last valid response.
*
* erpm - eRPM value from telemetry response.
* edt_type - Extended telemetry type (if supported).
* edt_value - Extended telemetry value (if supported).
* timestamp - Timestamp of the last valid response.
*/
struct dshot_ch_telemetry_s
{
uint16_t erpm;
uint8_t edt_type;
uint8_t edt_value;
struct timespec timestamp;
};
/* Telemetry result for DSHOTIOC_GET_TELEMETRY ioctl command.
* Contains bitmask of channels to read and telemetry data for each.
*
* ch_mask - Bitmask of logical channels to read telemetry from.
* ch_telemetry - Telemetry data array for each channel.
*/
struct dshot_telemetry_s
{
uint16_t ch_mask;
struct dshot_ch_telemetry_s ch_telemetry[DSHOT_NCHANNELS];
};
/* Per-channel throttle value for DSHOTIOC_SET_THROTTLE ioctl command.
* Specifies throttle values, channel mask, and optional telemetry
* request for efficient batching of operations.
*
* throttle - Throttle value array (0 = disarm, 48-2047 = armed range,
* or special command values).
* ch_mask - Bitmask of logical channels to set.
* telemetry_req - Bitmask: bit N requests telemetry from channel N.
* ch_telemetry - Telemetry data from previous request. Allows reading
* previous telemetry response without separate ioctl.
*/
struct dshot_throttle_s
{
uint16_t throttle[DSHOT_NCHANNELS];
uint16_t ch_mask;
uint16_t telemetry_req;
struct dshot_ch_telemetry_s ch_telemetry[DSHOT_NCHANNELS];
};
/* Raw telemetry frame captured from the DShot signal line.
* Contains the raw GCR-encoded packet and capture timestamp.
*
* raw - Raw 20-bit GCR encoded packet data.
* timestamp - Capture timestamp of the raw packet.
*/
struct dshot_raw_telemetry_s
{
uint32_t raw;
struct timespec timestamp;
};
/* Lower-half driver operations table. Provides callback functions for
* the upper-half driver to control DShot hardware. All methods except
* ioctl are mandatory.
*
* setup - Called when driver is opened. Configure and initialize
* device for use.
* shutdown - Called when driver is closed. Stop output and free
* hardware resources.
* configure - Configure speed, active channels, and bidirectional
* mode according to dshot_config_s.
* send_command - Send DShot command packets to specified channels.
* get_raw_telemetry - Fetch raw telemetry packets from specified channels.
* ioctl - Optional platform-specific ioctl handler.
*/
struct dshot_lowerhalf_s;
struct dshot_ops_s
{
CODE int (*setup)(FAR struct dshot_lowerhalf_s *dev);
CODE int (*shutdown)(FAR struct dshot_lowerhalf_s *dev);
CODE int (*configure)(FAR struct dshot_lowerhalf_s *dev,
FAR const struct dshot_config_s *cfg);
CODE int (*send_command)(FAR struct dshot_lowerhalf_s *dev,
FAR const uint16_t *packets,
uint16_t ch_mask);
CODE int (*get_raw_telemetry)(FAR struct dshot_lowerhalf_s *dev,
FAR struct dshot_raw_telemetry_s *raw,
uint16_t ch_mask);
CODE int (*ioctl)(FAR struct dshot_lowerhalf_s *dev,
int cmd, unsigned long arg);
};
/* Public representation of lower-half state. */
struct dshot_lowerhalf_s
{
FAR const struct dshot_ops_s *ops;
};
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* "Upper-Half" DShot Driver Interfaces
****************************************************************************/
/****************************************************************************
* Name: dshot_register
*
* Description:
* This function binds an instance of a "lower half" timer driver with the
* "upper half" DSHOT device and registers that device so that can be used
* by application code.
*
* When this function is called, the "lower half" driver should be in the
* reset state (as if the shutdown() method had already been called).
*
* Input Parameters:
* path - The full path to the driver to be registered in the NuttX pseudo-
* filesystem.
* dev - A pointer to an instance of lower half DShot driver. This instance
* is bound to the DShot driver and must persist as long as the driver
* persists.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
int dshot_register(FAR const char *path, FAR struct dshot_lowerhalf_s *dev);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __INCLUDE_NUTTX_TIMERS_DSHOT_H */