Heim >php教程 >php手册 >mixer 结构分析[uavcan为例]

mixer 结构分析[uavcan为例]

WBOY
WBOYOriginal
2016-06-13 08:42:341525Durchsuche

mixer 结构分析[uavcan为例]

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中的函数:
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>int load_mixer_file(const char *fname, char *buf, unsigned maxlen) </li></ol>
参数fname为mix文件在系统中的位置,buf为读取文件数据存放的缓冲区,maxlen为buf的最大长度。
该函数会剔除符合下面任何一条的行:
1.行长度小于2个字符的行
2.行的首字符不是大写字母的行
3.第二个字符不是':'的行
剔除这些非法内容的数据后,剩余的全部为格式化的内容,会被全部存入buf缓冲区中。
所以这要求在写mix文件时要遵循mix和格式。
这些格式化的mix内容被读取缓冲区后,就会通过函数
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>int ret = ioctl(dev, MIXERIOCLOADBUF, (unsigned long)buf); </li></ol>
来交给具体的设备处理。

相关结构的定义:


<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>/** simple channel scaler */<br /> </li><li>struct mixer_scaler_s {<br /></li><li>floatnegative_scale;//负向缩放, MIX文件中 O: 后面的第1个整数/10000.0f<br /></li><li>floatpositive_scale;//正向缩放, MIX文件中 O: 后面的第2个整数/10000.0f<br /></li><li>floatoffset; //偏移 , MIX文件中 O: 后面的第3个整数/10000.0f<br /></li><li>floatmin_output;//最小输出值 , MIX文件中 O: 后面的第4个整数/10000.0f<br /></li><li>floatmax_output;//最大输出值 , MIX文件中 O: 后面的第5个整数/10000.0f<br /></li><li>};//该结构定义了单个控制量的结构<br /></li><li><br /></li><li>/** mixer input */<br /></li><li>struct mixer_control_s {<br /></li><li>uint8_tcontrol_group;/**< group from which the input reads */<br /></li><li>uint8_tcontrol_index;/**< index within the control group */<br /></li><li>struct mixer_scaler_s scaler;/**< scaling applied to the input before use */<br /></li><li>};//定义输入量的结构<br /></li><li><br /></li><li>/** simple mixer */<br /></li><li>struct mixer_simple_s {<br /></li><li>uint8_tcontrol_count;/**< number of inputs */<br /></li><li>struct mixer_scaler_soutput_scaler;/**< scaling for the output */<br /></li><li>struct mixer_control_scontrols[0];/**< actual size of the array is set by control_count */<br /></li><li>};//定义了一个控制实体的控制体,包括输入的信号数量,输入信号控制集,输出信号控制。 </li><li>//因为一个mixer只有一个输出,可以有0到多个输入,所以control_count指明了这个mixer所需要的输入信号数量,而具体的信号都存放在数组controls[0]中。 </li><li>//输出则由output_scaler来控制. </li><li>//从这些结构体的定义,可以对照起来mix文件语法的定义.<br /> </li></ol>

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. }


<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>int MixerGroup::load_from_buf(const char *buf, unsigned &buflen)<br /></li><li>{<br /></li><li>int ret = -1;<br /></li><li>const char *end = buf + buflen;<br /></li><li><br /></li><li>/*<br /></li><li> * Loop until either we have emptied the buffer, or we have failed to<br /></li><li> * allocate something when we expected to.<br /></li><li> */<br /></li><li>while (buflen > 0) {<br /></li><li>Mixer *m = nullptr;<br /></li><li>const char *p = end - buflen;<br /></li><li>unsigned resid = buflen;<br /></li><li><br /></li><li>/*<br /></li><li> * Use the next character as a hint to decide which mixer class to construct.<br /></li><li> */<br /></li><li>switch (*p) {//首先看该行的第一个字母,来确定数据的类别.<br /></li><li>case 'Z':<br /></li><li>m = NullMixer::from_text(p, resid);<br /></li><li>break;<br /></li><li><br /></li><li>case 'M':<br /></li><li>m = SimpleMixer::from_text(_control_cb, _cb_handle, p, resid);<br /></li><li>break;<br /></li><li><br /></li><li>case 'R':<br /></li><li>m = MultirotorMixer::from_text(_control_cb, _cb_handle, p, resid);<br /></li><li>break;<br /></li><li><br /></li><li>default:<br /></li><li>/* it's probably junk or whitespace, skip a byte and retry */<br /></li><li>buflen--;<br /></li><li>continue;<br /></li><li>}<br /></li><li><br /></li><li>/*<br /></li><li> * If we constructed something, add it to the group.<br /></li><li> */<br /></li><li>if (m != nullptr) {<br /></li><li>add_mixer(m);<br /></li><li><br /></li><li>/* we constructed something */<br /></li><li>ret = 0;<br /></li><li><br /></li><li>/* only adjust buflen if parsing was successful */<br /></li><li>buflen = resid;<br /></li><li>debug("SUCCESS - buflen: %d", buflen);<br /></li><li><br /></li><li>} else {<br /></li><li><br /></li><li>/*<br /></li><li> * There is data in the buffer that we expected to parse, but it didn't,<br /></li><li> * so give up for now.<br /></li><li> */<br /></li><li>break;<br /></li><li>}<br /></li><li>}<br /></li><li><br /></li><li>/* nothing more in the buffer for us now */<br /></li><li>return ret;<br /></li><li>} </li></ol>

下面这个函数用来 处理 M: 开头的定义, 格式规定该字符后面只能有一个数字,用来指明input信号源的数量,即S类型数量的数量,联系到结构体的定义,则为 struct mixer_control_s 的数量.
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>SimpleMixer *<br /> </li><li>SimpleMixer::from_text(Mixer::ControlCallback control_cb, uintptr_t cb_handle, const char *buf, unsigned &buflen)<br /></li><li>{<br /></li><li>SimpleMixer *sm = nullptr;<br /></li><li>mixer_simple_s *mixinfo = nullptr;<br /></li><li>unsigned inputs;<br /></li><li>int used;<br /></li><li>const char *end = buf + buflen;<br /></li><li><br /></li><li>/* get the base info for the mixer */<br /></li><li>if (sscanf(buf, "M: %u%n", &inputs, &used) != 1) {<br /></li><li>debug("simple parse failed on '%s'", buf);<br /></li><li>goto out;<br /></li><li>}//复制M:后面第一个数值到无符号整型数据到变量inputs中,并将已经处理的字条数目赋值给used<br /></li><li><br /></li><li>buf = skipline(buf, buflen);//让buf指定下一行<br /></li><li><br /></li><li>if (buf == nullptr) {<br /></li><li>debug("no line ending, line is incomplete");<br /></li><li>goto out;<br /></li><li>}<br /></li><li><br /></li><li>mixinfo = (mixer_simple_s *)malloc(MIXER_SIMPLE_SIZE(inputs)); </li><li> //M:后面的数字为struct mixer_control_s 结构的数量.MIXER_SIMPLE_SIZE的字义为sizeof(mixer_simple_s) + inputs*sizeof(mixer_control_s), </li><li> //即一个完整的mixer_simple_s的定义,controls[0]一共有inputs个.<br /> </li><li><br /></li><li>if (mixinfo == nullptr) {<br /></li><li>debug("could not allocate memory for mixer info");<br /></li><li>goto out;<br /></li><li>}<br /></li><li><br /></li><li>mixinfo->control_count = inputs;//input 信号的数量<br /></li><li><br /></li><li>if (parse_output_scaler(end - buflen, buflen, mixinfo->output_scaler)) {<br /></li><li>debug("simple mixer parser failed parsing out scaler tag, ret: '%s'", buf);<br /></li><li>goto out;<br /></li><li>}//该函数解析输出域,并将期填充到mixinfo的output_scaler字段中.<br /><p></p><pre class="code"><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>int SimpleMixer::parse_output_scaler(const char *buf, unsigned &buflen, mixer_scaler_s &scaler)<br /></li><li>{<br /></li><li>int ret;<br /></li><li>int s[5];<br /></li><li>int n = -1;<br /></li><li><br /></li><li>buf = findtag(buf, buflen, 'O');//寻找"O:"这样的控制符,返回指针指向输出格式域定义的首字符'O'.<br /></li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>if ((buf == nullptr) || (buflen < 12)) {<br /></li><li>debug("output parser failed finding tag, ret: '%s'", buf);<br /></li><li>return -1;<br /></li><li>}//12,表示O:这行的定义至少有12个字符(O:和五个1位长的整数),例如最短的定义为: O: 0 0 0 0 0<br /></li><li><br /></li><li>if ((ret = sscanf(buf, "O: %d %d %d %d %d %n",//O:后面必须有5个整数,且整数间用至少一个空格分开,此处是取出O:后面的5个整数值.<br /></li><li> &s[0], &s[1], &s[2], &s[3], &s[4], &n)) != 5) {<br /></li><li>debug("out scaler parse failed on '%s' (got %d, consumed %d)", buf, ret, n);<br /></li><li>return -1;<br /></li><li>}<br /></li><li><br /></li><li>buf = skipline(buf, buflen);<br /></li><li><br /></li><li>if (buf == nullptr) {<br /></li><li>debug("no line ending, line is incomplete");<br /></li><li>return -1;<br /></li><li>}<br /></li><li> //从下面的赋值操作可以得出 O:后面5个数值的字义.,分别为 [negative_scale] [positive_scale] [offset] [min_output] [max_output] </li><li> //并且每个这都做了除10000的操作,所以MIX格式定义中说这些值都是被放大10000倍后的数值.<br /> </li><li>scaler.negative_scale= s[0] / 10000.0f;<br /></li><li>scaler.positive_scale= s[1] / 10000.0f;<br /></li><li>scaler.offset= s[2] / 10000.0f;<br /></li><li>scaler.min_output= s[3] / 10000.0f;<br /></li><li>scaler.max_output= s[4] / 10000.0f;<br /></li><li><br /></li><li>return 0;<br /></li><li>} </li></ol>

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

  • }

    <ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>int SimpleMixer::parse_control_scaler(const char *buf, unsigned &buflen, mixer_scaler_s &scaler, uint8_t &control_group,<br /></li><li>  uint8_t &control_index)<br /></li><li>{<br /></li><li>unsigned u[2];<br /></li><li>int s[5];<br /></li><li><br /></li><li>buf = findtag(buf, buflen, 'S');//找到剩余缓冲区中的第一个'S',并让buf指向该行的行首; </li><li> //<br /> </li><li> //16表示该S:行至少有16个字符,即至少有7个整数(因为整数间至少有1个空格分隔)<br /></li><li>if ((buf == nullptr) || (buflen < 16)) {<br /></li><li>debug("control parser failed finding tag, ret: '%s'", buf);<br /></li><li>return -1;<br /></li><li>}<br /></li><li> //读取S:后面的7个整数.<br /></li><li>if (sscanf(buf, "S: %u %u %d %d %d %d %d",<br /></li><li> &u[0], &u[1], &s[0], &s[1], &s[2], &s[3], &s[4]) != 7) {<br /></li><li>debug("control parse failed on '%s'", buf);<br /></li><li>return -1;<br /></li><li>}<br /></li><li><br /></li><li>buf = skipline(buf, buflen);<br /></li><li><br /></li><li>if (buf == nullptr) {<br /></li><li>debug("no line ending, line is incomplete");<br /></li><li>return -1;<br /></li><li>} </li><li><br /> </li><li> //从下面的赋值可以看出MIXER文件S:定义的格式,S:后面的整数分别为 </li><li>  // [control_group] [ontrol_index] [negative_scale] [positive_scale] [offset] [min_output] [max_output]<br /> </li><li> // 可以看出,输入信号的定义比输入出信号的定义多了两个整数,用来表示当前输入信号所在的组和组内的序号. 第1和第2个整就是用来 </li><li> // 说明组号和组内序号.而后面5个整数的定义和输入信号的定义一样,且也要除以10000.<br /> </li><li>control_group= u[0];<br /></li><li>control_index= u[1];<br /></li><li>scaler.negative_scale= s[0] / 10000.0f;<br /></li><li>scaler.positive_scale= s[1] / 10000.0f;<br /></li><li>scaler.offset= s[2] / 10000.0f;<br /></li><li>scaler.min_output= s[3] / 10000.0f;<br /></li><li>scaler.max_output= s[4] / 10000.0f;<br /></li><li><br /></li><li>return 0;<br /></li><li>} </li></ol>



  • sm = new SimpleMixer(control_cb, cb_handle, mixinfo);

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

  • } else {
  • debug("could not allocate memory for mixer");
  • }

  • out:

  • if (mixinfo != nullptr) {
  • free(mixinfo);
  • }

  • return sm;
  • }




  • Stellungnahme:
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn