程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> mixer 結構分析[uavcan為例]

mixer 結構分析[uavcan為例]

編輯:JAVA綜合教程

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中的函數:
  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. floatnegative_scale;//負向縮放, MIX文件中 O: 後面的第1個整數/10000.0f
  4. floatpositive_scale;//正向縮放, MIX文件中 O: 後面的第2個整數/10000.0f
  5. floatoffset; //偏移 , MIX文件中 O: 後面的第3個整數/10000.0f
  6. floatmin_output;//最小輸出值 , MIX文件中 O: 後面的第4個整數/10000.0f
  7. floatmax_output;//最大輸出值 , MIX文件中 O: 後面的第5個整數/10000.0f
  8. };//該結構定義了單個控制量的結構

  9. /** mixer input */
  10. struct mixer_control_s {
  11. uint8_tcontrol_group;/**< group from which the input reads */
  12. uint8_tcontrol_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_tcontrol_count;/**< number of inputs */
  18. struct mixer_scaler_soutput_scaler;/**< scaling for the output */
  19. struct mixer_control_scontrols[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. }




  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved