Chinaunix首页 | 论坛 | 博客
  • 博客访问: 387674
  • 博文数量: 61
  • 博客积分: 4650
  • 博客等级: 上校
  • 技术积分: 786
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-11 21:07
个人简介

少抱怨,多实干;

文章分类

全部博文(61)

文章存档

2017年(1)

2016年(13)

2015年(1)

2013年(2)

2011年(1)

2010年(3)

2009年(23)

2008年(17)

我的朋友

分类: 嵌入式

2016-04-06 11:32:46

mixer指令为系统的app命令,位置在Firmware/src/systemcmds/mixer目录下面,其功能是装载mix文件中的有效内容到具体的设备中,然后由具体的设备中的MixerGroups来解析这些定义.
本例是以uvacan为例, 系统运行后,设备的名称为:/dev/uavcan/esc.
uavcan的定义中有MixerGroup实例,Output实例.

MIXER的种类一共有三个:NullMixer, SimpleMixer 和MultirotorMixer.
NullMixer:用来为未分组的输出通道点位;
SimpleMixer:0或多个输入融合成一个输出;
MultirotorMixer:将输入量(ROLL,PITCH,RAW,Thrusttle)融合成一组基于 预先定义的geometry的输出量.



读取mix文件的函数位于Firmware/src/modules/systemlib/mixwr/mixer_load.c中的函数:
  1. int load_mixer_file(const char *fname, char *buf, unsigned maxlen)
参数fname为mix文件在系统中的位置,buf为读取文件数据存放的缓冲区,maxlen为buf的最大长度。
该函数会剔除符合下面任何一条的行:
1.行长度小于2个字符的行
2.行的首字符不是大写字母的行
3.第二个字符不是':'的行
剔除这些非法内容的数据后,剩余的全部为格式化的内容,会被全部存入buf缓冲区中。
所以这要求在写mix文件时要遵循mix和格式。
这些格式化的mix内容被读取缓冲区后,就会通过函数

点击(此处)折叠或打开

  1. int ret = ioctl(dev, MIXERIOCLOADBUF, (unsigned long)buf);
来交给具体的设备处理。

相关结构的定义:


点击(此处)折叠或打开

  1. /** simple channel scaler */
  2. struct mixer_scaler_s {
  3.     float            negative_scale;//负向缩放, MIX文件中 O: 后面的第1个整数/10000.0f
  4.     float            positive_scale;//正向缩放, MIX文件中 O: 后面的第2个整数/10000.0f
  5.     float            offset;        //偏移   , MIX文件中 O: 后面的第3个整数/10000.0f
  6.     float            min_output;//最小输出值  , MIX文件中 O: 后面的第4个整数/10000.0f
  7.     float            max_output;//最大输出值  , MIX文件中 O: 后面的第5个整数/10000.0f
  8. };//该结构定义了单个控制量的结构

  9. /** mixer input */
  10. struct mixer_control_s {
  11.     uint8_t            control_group;    /**< group from which the input reads */
  12.     uint8_t            control_index;    /**< index within the control group */
  13.     struct mixer_scaler_s     scaler;        /**< scaling applied to the input before use */
  14. };//定义输入量的结构

  15. /** simple mixer */
  16. struct mixer_simple_s {
  17.     uint8_t            control_count;    /**< number of inputs */
  18.     struct mixer_scaler_s    output_scaler;    /**< scaling for the output */
  19.     struct mixer_control_s    controls[0];    /**< actual size of the array is set by control_count */
  20. };//定义了一个控制实体的控制体,包括输入的信号数量,输入信号控制集,输出信号控制。
  21. //因为一个mixer只有一个输出,可以有0到多个输入,所以control_count指明了这个mixer所需要的输入信号数量,而具体的信号都存放在数组controls[0]中。
  22. //输出则由output_scaler来控制.
  23. //从这些结构体的定义,可以对照起来mix文件语法的定义.

uavcan_main.cpp:
该文件中有解析上面提到的缓冲数据
  1. int UavcanNode::ioctl(file *filp, int cmd, unsigned long arg)
  2. {
  3. ...
  4.             case MIXERIOCLOADBUF: {
                const char *buf = (const char *)arg;
                unsigned buflen = strnlen(buf, 1024);

                if (_mixers == nullptr) {
                    _mixers = new MixerGroup(control_callback, (uintptr_t)_controls);
                }

                if (_mixers == nullptr) {
                    _groups_required = 0;
                    ret = -ENOMEM;

                } else {

                    ret = _mixers->load_from_buf(buf, buflen);//这里开始解析数据

                    if (ret != 0) {
                        warnx("mixer load failed with %d", ret);
                        delete _mixers;
                        _mixers = nullptr;
                        _groups_required = 0;
                        ret = -EINVAL;

                    } else {

                        _mixers->groups_required(_groups_required);
                    }
                }

                break;
            }
    ...
  5. }


点击(此处)折叠或打开

  1. int MixerGroup::load_from_buf(const char *buf, unsigned &buflen)
  2. {
  3.     int ret = -1;
  4.     const char *end = buf + buflen;

  5.     /*
  6.      * Loop until either we have emptied the buffer, or we have failed to
  7.      * allocate something when we expected to.
  8.      */
  9.     while (buflen > 0) {
  10.         Mixer *m = nullptr;
  11.         const char *p = end - buflen;
  12.         unsigned resid = buflen;

  13.         /*
  14.          * Use the next character as a hint to decide which mixer class to construct.
  15.          */
  16.         switch (*p) {//首先看该行的第一个字母,来确定数据的类别.
  17.         case 'Z':
  18.             m = NullMixer::from_text(p, resid);
  19.             break;

  20.         case 'M':
  21.             m = SimpleMixer::from_text(_control_cb, _cb_handle, p, resid);
  22.             break;

  23.         case 'R':
  24.             m = MultirotorMixer::from_text(_control_cb, _cb_handle, p, resid);
  25.             break;

  26.         default:
  27.             /* it's probably junk or whitespace, skip a byte and retry */
  28.             buflen--;
  29.             continue;
  30.         }

  31.         /*
  32.          * If we constructed something, add it to the group.
  33.          */
  34.         if (m != nullptr) {
  35.             add_mixer(m);

  36.             /* we constructed something */
  37.             ret = 0;

  38.             /* only adjust buflen if parsing was successful */
  39.             buflen = resid;
  40.             debug("SUCCESS - buflen: %d", buflen);

  41.         } else {

  42.             /*
  43.              * There is data in the buffer that we expected to parse, but it didn't,
  44.              * so give up for now.
  45.              */
  46.             break;
  47.         }
  48.     }

  49.     /* nothing more in the buffer for us now */
  50.     return ret;
  51. }

下面这个函数用来 处理 M: 开头的定义, 格式规定该字符后面只能有一个数字,用来指明input信号源的数量,即S类型数量的数量,联系到结构体的定义,则为 struct mixer_control_s 的数量.

点击(此处)折叠或打开

  1. SimpleMixer *
  2. SimpleMixer::from_text(Mixer::ControlCallback control_cb, uintptr_t cb_handle, const char *buf, unsigned &buflen)
  3. {
  4.     SimpleMixer *sm = nullptr;
  5.     mixer_simple_s *mixinfo = nullptr;
  6.     unsigned inputs;
  7.     int used;
  8.     const char *end = buf + buflen;

  9.     /* get the base info for the mixer */
  10.     if (sscanf(buf, "M: %u%n", &inputs, &used) != 1) {
  11.         debug("simple parse failed on '%s'", buf);
  12.         goto out;
  13.     }//复制M:后面第一个数值到无符号整型数据到变量inputs中,并将已经处理的字条数目赋值给used

  14.     buf = skipline(buf, buflen);//让buf指定下一行

  15.     if (buf == nullptr) {
  16.         debug("no line ending, line is incomplete");
  17.         goto out;
  18.     }

  19.     mixinfo = (mixer_simple_s *)malloc(MIXER_SIMPLE_SIZE(inputs));
  20.     //M:后面的数字为struct mixer_control_s 结构的数量.MIXER_SIMPLE_SIZE的字义为sizeof(mixer_simple_s) + inputs*sizeof(mixer_control_s),
  21.     //即一个完整的mixer_simple_s的定义,controls[0]一共有inputs个.

  22.     if (mixinfo == nullptr) {
  23.         debug("could not allocate memory for mixer info");
  24.         goto out;
  25.     }

  26.     mixinfo->control_count = inputs;//input 信号的数量

  27.     if (parse_output_scaler(end - buflen, buflen, mixinfo->output_scaler)) {
  28.         debug("simple mixer parser failed parsing out scaler tag, ret: '%s'", buf);
  29.         goto out;
  30.     }//该函数解析输出域,并将期填充到mixinfo的output_scaler字段中.

    点击(此处)折叠或打开

    1. int SimpleMixer::parse_output_scaler(const char *buf, unsigned &buflen, mixer_scaler_s &scaler)
    2. {
    3.     int ret;
    4.     int s[5];
    5.     int n = -1;

    6.     buf = findtag(buf, buflen, 'O');//寻找"O:"这样的控制符,返回指针指向输出格式域定义的首字符'O'.
    1.     if ((buf == nullptr) || (buflen < 12)) {
    2.         debug("output parser failed finding tag, ret: '%s'", buf);
    3.         return -1;
    4.     }//12,表示O:这行的定义至少有12个字符(O:和五个1位长的整数),例如最短的定义为: O: 0 0 0 0 0

    5.     if ((ret = sscanf(buf, "O: %d %d %d %d %d %n",//O:后面必须有5个整数,且整数间用至少一个空格分开,此处是取出O:后面的5个整数值.
    6.              &s[0], &s[1], &s[2], &s[3], &s[4], &n)) != 5) {
    7.         debug("out scaler parse failed on '%s' (got %d, consumed %d)", buf, ret, n);
    8.         return -1;
    9.     }

    10.     buf = skipline(buf, buflen);

    11.     if (buf == nullptr) {
    12.         debug("no line ending, line is incomplete");
    13.         return -1;
    14.     }
    15.     //从下面的赋值操作可以得出 O:后面5个数值的字义.,分别为 [negative_scale] [positive_scale] [offset] [min_output] [max_output]
    16.     //并且每个这都做了除10000的操作,所以MIX格式定义中说这些值都是被放大10000倍后的数值.
    17.     scaler.negative_scale    = s[0] / 10000.0f;
    18.     scaler.positive_scale    = s[1] / 10000.0f;
    19.     scaler.offset        = s[2] / 10000.0f;
    20.     scaler.min_output    = s[3] / 10000.0f;
    21.     scaler.max_output    = s[4] / 10000.0f;

    22.     return 0;
    23. }

       //上面解析了MIXER的输出量,下面开始解析输入量,因为我们已经读取了输入信号的数量("M: n"中n定义的数值),所以要循环n次.
  31.    //首先记住parse_control_scaler函数输入的参数
  32.     for (unsigned i = 0; i < inputs; i++) {
  33.         if (parse_control_scaler(end - buflen, buflen,
  34.                      mixinfo->controls[i].scaler,
  35.                      mixinfo->controls[i].control_group,
  36.                      mixinfo->controls[i].control_index)) {
  37.             debug("simple mixer parser failed parsing ctrl scaler tag, ret: '%s'", buf);
  38.             goto out;
  39.         }

  40.     }

    点击(此处)折叠或打开

    1. int SimpleMixer::parse_control_scaler(const char *buf, unsigned &buflen, mixer_scaler_s &scaler, uint8_t &control_group,
    2.                  uint8_t &control_index)
    3. {
    4.     unsigned u[2];
    5.     int s[5];

    6.     buf = findtag(buf, buflen, 'S');//找到剩余缓冲区中的第一个'S',并让buf指向该行的行首;
    7.     //
    8.     //16表示该S:行至少有16个字符,即至少有7个整数(因为整数间至少有1个空格分隔)
    9.     if ((buf == nullptr) || (buflen < 16)) {
    10.         debug("control parser failed finding tag, ret: '%s'", buf);
    11.         return -1;
    12.     }
    13.     //读取S:后面的7个整数.
    14.     if (sscanf(buf, "S: %u %u %d %d %d %d %d",
    15.          &u[0], &u[1], &s[0], &s[1], &s[2], &s[3], &s[4]) != 7) {
    16.         debug("control parse failed on '%s'", buf);
    17.         return -1;
    18.     }

    19.     buf = skipline(buf, buflen);

    20.     if (buf == nullptr) {
    21.         debug("no line ending, line is incomplete");
    22.         return -1;
    23.     }

    24.     //从下面的赋值可以看出MIXER文件S:定义的格式,S:后面的整数分别为
    25.     // [control_group] [ontrol_index] [negative_scale] [positive_scale] [offset] [min_output] [max_output]
    26.     // 可以看出,输入信号的定义比输入出信号的定义多了两个整数,用来表示当前输入信号所在的组和组内的序号. 第1和第2个整就是用来
    27.     // 说明组号和组内序号.而后面5个整数的定义和输入信号的定义一样,且也要除以10000.
    28.     control_group        = u[0];
    29.     control_index        = u[1];
    30.     scaler.negative_scale= s[0] / 10000.0f;
    31.     scaler.positive_scale= s[1] / 10000.0f;
    32.     scaler.offset        = s[2] / 10000.0f;
    33.     scaler.min_output    = s[3] / 10000.0f;
    34.     scaler.max_output    = s[4] / 10000.0f;

    35.     return 0;
    36. }



  41.     sm = new SimpleMixer(control_cb, cb_handle, mixinfo);

  42.     if (sm != nullptr) {
  43.         mixinfo = nullptr;
  44.         debug("loaded mixer with %d input(s)", inputs);

  45.     } else {
  46.         debug("could not allocate memory for mixer");
  47.     }

  48. out:

  49.     if (mixinfo != nullptr) {
  50.         free(mixinfo);
  51.     }

  52.     return sm;
  53. }




阅读(31466) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~