45 #include <px4_platform_common/px4_config.h>    61                    uint8_t control_group,
    62                    uint8_t control_index,
    70 #define MIXER_DIFFERENCE_THRESHOLD 30    72 #define MIXER_DIFFERENCE_THRESHOLD 2    83 #if defined(CONFIG_ARCH_BOARD_PX4_SITL)    84 #define MIXER_PATH(_file)  "etc/mixers/"#_file    85 #define MIXER_ONBOARD_PATH "etc/mixers"    87 #define MIXER_ONBOARD_PATH "/etc/mixers"    88 #define MIXER_PATH(_file) MIXER_ONBOARD_PATH"/"#_file   108     bool load_mixer(
const char *filename, 
unsigned expected_count, 
bool verbose = 
false);
   109     bool load_mixer(
const char *filename, 
const char *buf, 
unsigned loaded, 
unsigned expected_count,
   110             const unsigned chunk_size, 
bool verbose);
   162         PX4_ERR(
"File open failed");
   166     struct dirent *result = 
nullptr;
   170         result = readdir(dp);
   173         if (result == 
nullptr) {
   175                 PX4_ERR(
"readdir failed");
   186         switch (result->d_type) {
   193             if (strncmp(result->d_name, 
".", 1) != 0) {
   198                     PX4_ERR(
"mixer path too long %s", result->d_name);
   206                     PX4_ERR(
"Error testing mixer %s", buf);
   229     unsigned loaded = strlen(buf);
   232         PX4_INFO(
"loaded: \n\"%s\"\n (file: %s, %d chars)", &buf[0], filename, loaded);
   237         bool ret = 
load_mixer(filename, buf, loaded, expected_count, chunk_size, verbose);
   240             PX4_ERR(
"Mixer load failed with chunk size %u", chunk_size);
   249                const unsigned chunk_size, 
bool verbose)
   257     unsigned xx = loaded;
   261     if (expected_count > 0) {
   265     unsigned empty_load = 2;
   273         PX4_INFO(
"empty buffer load: loaded %u mixers, used: %u", 
mixer_group.
count(), empty_load);
   276     ut_compare(
"empty buffer load", empty_load, 0);
   283     unsigned transmitted = 0;
   286     while (transmitted < loaded) {
   288         unsigned text_length = (loaded - transmitted > chunk_size) ? chunk_size : loaded - transmitted;
   291         if ((mixer_text_length + text_length + 1) > 
sizeof(
mixer_text)) {
   292             PX4_ERR(
"Mixer text length overflow for file: %s. Is PX4IO_MAX_MIXER_LENGTH too small? (curr len: %d)", filename,
   298         memcpy(&mixer_text[mixer_text_length], &buf[transmitted], text_length);
   299         mixer_text_length += text_length;
   308         if (resid != mixer_text_length) {
   313                 memmove(&mixer_text[0], &mixer_text[mixer_text_length - resid], resid);
   315                 mixer_text[resid] = 
'\0';
   318             mixer_text_length = resid;
   321         transmitted += text_length;
   324             PX4_INFO(
"transmitted: %d, loaded: %d", transmitted, loaded);
   333         PX4_ERR(
"Load of mixer failed, last chunk: %s, transmitted: %u, text length: %u, resid: %u", mixer_text, transmitted,
   334             mixer_text_length, resid);
   353     int16_t reverse_pwm_mask = 0;
   384               r_page_servo_control_max, outputs, r_page_servos, &output_limit);
   388     for (
unsigned i = 0; i < mixed; i++) {
   391         if (i != actuator_controls_s::INDEX_THROTTLE) {
   392             if (r_page_servos[i] < r_page_servo_control_min[i]) {
   393                 PX4_ERR(
"active servo < min");
   398             if (r_page_servos[i] != r_page_servo_disarmed[i]) {
   399                 PX4_ERR(
"throttle output != 0 (this check assumed the IO pass mixer!)");
   414     unsigned sleep_quantum_us = 10000;
   417     unsigned sleepcount = 0;
   425                   r_page_servo_control_max, outputs, r_page_servos, &output_limit);
   428         for (
unsigned i = 0; i < mixed; i++) {
   434                 r_page_servos[i] != r_page_servo_disarmed[i]) {
   435                 PX4_ERR(
"disarmed servo value mismatch: %d vs %d", r_page_servos[i], r_page_servo_disarmed[i]);
   440                 r_page_servos[i] + 1 <= r_page_servo_disarmed[i]) {
   441                 PX4_ERR(
"ramp servo value mismatch");
   446         px4_usleep(sleep_quantum_us);
   449         if (sleepcount % 10 == 0) {
   456     for (
int j = -jmax; j <= jmax; j++) {
   469                   r_page_servo_control_max, outputs, r_page_servos, &output_limit);
   473         for (
unsigned i = 0; i < mixed; i++) {
   474             servo_predicted[i] = 1500 + outputs[i] * (r_page_servo_control_max[i] - r_page_servo_control_min[i]) / 2.0
f;
   477                 fprintf(stderr, 
"\t %d: %8.4f predicted: %d, servo: %d\n", i, (
double)outputs[i], servo_predicted[i],
   478                     (
int)r_page_servos[i]);
   479                 PX4_ERR(
"mixer violated predicted value");
   497                   r_page_servo_control_max, outputs, r_page_servos, &output_limit);
   500         for (
unsigned i = 0; i < mixed; i++) {
   505             if (r_page_servos[i] != r_page_servo_disarmed[i]) {
   506                 PX4_ERR(
"disarmed servo value mismatch");
   511         px4_usleep(sleep_quantum_us);
   514         if (sleepcount % 10 == 0) {
   534                   r_page_servo_control_max, outputs, r_page_servos, &output_limit);
   537         for (
unsigned i = 0; i < mixed; i++) {
   539             servo_predicted[i] = 1500 + outputs[i] * (r_page_servo_control_max[i] - r_page_servo_control_min[i]) / 2.0
f;
   546                 (r_page_servos[i] + 1 <= r_page_servo_disarmed[i] ||
   547                  r_page_servos[i] > servo_predicted[i])) {
   548                 PX4_ERR(
"ramp servo value mismatch");
   554                 abs(servo_predicted[i] - r_page_servos[i]) > 2) {
   555                 printf(
"\t %d: %8.4f predicted: %d, servo: %d\n", i, (
double)outputs[i], servo_predicted[i], (
int)r_page_servos[i]);
   556                 PX4_ERR(
"mixer violated predicted value");
   561         px4_usleep(sleep_quantum_us);
   564         if (sleepcount % 10 == 0) {
   578     if (control_group != 0) {
   588     if (
should_prearm && control_group == actuator_controls_s::GROUP_INDEX_ATTITUDE &&
   589         control_index == actuator_controls_s::INDEX_THROTTLE) {
 #define PWM_DEFAULT_MAX
Default maximum PWM in us. 
int load_from_buf(Mixer::ControlCallback control_cb, uintptr_t cb_handle, const char *buf, unsigned &buflen)
Adds mixers to the group based on a text description in a buffer. 
bool load_mixer(const char *filename, unsigned expected_count, bool verbose=false)
static unsigned mixer_text_length
void reset()
Remove all the mixers from the group. 
void output_limit_calc(const bool armed, const bool pre_armed, const unsigned num_channels, const uint16_t reverse_mask, const uint16_t *disarmed_output, const uint16_t *min_output, const uint16_t *max_output, const float *output, uint16_t *effective_output, output_limit_t *limit)
int test_mixer(int argc, char *argv[])
static char mixer_text[PX4IO_MAX_MIXER_LENGTH]
static volatile bool should_arm
unsigned count() const
Count the mixers in the group. 
Base class to be used for unit tests. 
ut_declare_test_c(test_mixer, MixerTest) bool MixerTest
PX4IO interface protocol. 
High-resolution timer with callouts and timekeeping. 
static int mixer_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &control)
int _tests_failed
The number of unit tests which failed. 
uint16_t r_page_servo_control_max[]
PAGE 107. 
#define MIXER_DIFFERENCE_THRESHOLD
static bool should_prearm
#define MIXER_PATH(_file)
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now. 
virtual bool run_tests()
Override to run your unit tests. 
uint16_t r_page_servo_disarmed[]
PAGE 109. 
int load_mixer_file(const char *fname, char *buf, unsigned maxlen)
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units. 
#define PX4IO_MAX_TRANSFER_LEN
#define PX4IO_MAX_MIXER_LENGTH
uint16_t r_page_servo_control_min[]
PAGE 106. 
#define MIXER_ONBOARD_PATH
static const unsigned output_max
uint16_t r_page_servos[]
PAGE 3. 
void output_limit_init(output_limit_t *limit)
#define ut_compare(message, v1, v2)
Used to compare two integer values within a unit test. 
static float actuator_controls[output_max]
unsigned mix(float *outputs, unsigned space)
#define PWM_MOTOR_OFF
Default value for a shutdown motor. 
#define ut_run_test(test)
Runs a single unit test. 
Group of mixers, built up from single mixers and processed in order when mixing. 
Dual< Scalar, N > abs(const Dual< Scalar, N > &a)
#define PWM_DEFAULT_MIN
Default minimum PWM in us. 
Library for output limiting (PWM for example) 
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap). 
#define PWM_LOWEST_MIN
Lowest minimum PWM in us.