Вставка ассемблерного кода в скетч

Тема в разделе "Arduino & Shields", создана пользователем avt34, 22 июн 2017.

  1. avt34

    avt34 Нерд

    Завтра напишу контрольный пример под x86 и проверю. Правда, только ява под рукой, надеюсь asm там тоже можно использовать. Но с++ если понадобится - найду.

    Код (C++):
    "=r" заменить на "+r"
    Учту, спасибо.

    Если будут результаты, то выложу пример.
     
  2. Igor68

    Igor68 Гуру

    Не бейте только... это было давно... где-то в 2012 году. Был контроллер на Linux IA241LX... и описание протокола для весового терминала. Там пример подсчёта контрольной суммы был на ассемблере для x86. Думать не стал... взял книгу с "микропроцессор i486" с описанием системы команд и "перепилил" на Си. И вот, что получилось:
    Код (C++):

    /***************************
    * computing Crack for  *
    * receive and tranceive  *
    * blocks data of tenzo-m  *
    ***************************/

    BYTE  TENZO_CRCMaker(BYTE b_input, BYTE b_CRC)
    {
      BOOL tmp;
      struct registers  _reg;
      //=== simulator x86 ===
      _reg.al = b_input;
      _reg.ah = b_CRC;
      _reg.cx = 0x08;
      //==== rol al,1 ===
    mod1:  if(_reg.al & 0x80)
      _reg.CF = TRUE;
      else
      _reg.CF = FALSE;
      _reg.al = _reg.al << 1;
      if(_reg.CF)
      _reg.al |= 0x01;
      else
      _reg.al &= 0xFE;
      //=== rcl ah,1 ===
      if(_reg.ah & 0x80)
      tmp = TRUE;
      else
      tmp = FALSE;
      _reg.ah = _reg.ah << 1;
      if(_reg.CF)
      _reg.ah |= 0x01;
      else
      _reg.ah &= 0xFE;
      _reg.CF = tmp;
      //=== jnc mod2 ===
      if(!(_reg.CF))
      goto mod2;
      _reg.ah ^= 0x69;
    mod2:  _reg.cx--;
      //=== jnz mod1 ===
      if(_reg.cx != 0)
      goto mod1;
      b_CRC = _reg.ah;
      return b_CRC;
    }

     
    Хоть и по бычьи... но работает с весами до сих пор.

    Все регистры в стуктуру не пихал... а только те, что использовались в примере
    Код (C++):

    struct registers
    {
      BOOL  CF;
      //
      BYTE  al;
      BYTE  ah;
      ushort  cx;
    };
     
     
    avt34 и mcureenab нравится это.
  3. avt34

    avt34 Нерд

    Вот что в итоге получилось.
    Код (C++):
    #include <stdio.h>

    void setup()
    {
      Serial.begin(9600);
    }

    void loop()
    {
      unsigned char packet[10] = {0xff, 0x01, 0x03, 0x01, 0x02, 0x00, 0x11, 0x00, 0xff, 0xff};
      for (int i = 0; i < 7; i++)
      {
        packet[7] = CRCMaker(packet[i], packet[7]);
      }
      char hexstr[(sizeof(packet)) * 5];
      getHexStr(packet, hexstr, sizeof(packet));
      Serial.println(hexstr);
      delay(1000);
    }


    //  посчитать контрольную сумму
    byte CRCMaker(byte b_input, byte b_CRC)
    {
      asm volatile
      (
        "    ldi  r21,0x69"        "\n\t"
        "    ldi  r20,8"           "\n\t"
        "a:  rol  %1"              "\n\t"
        "    rol  %0"              "\n\t"
        "    brcc b"               "\n\t"
        "    eor  %0,r21"          "\n\t"
        "b:  dec  r20"             "\n\t"
        "    brne a"               "\n\t"
        :"+r"(b_CRC)
        :"r" (b_input)
        :"r20", "r21"
      );
      return b_CRC;
    }

    // получить массив байт в виде строки
    void getHexStr(unsigned char *data, char* str, int len)
    {
      for (int i = 0; i < len; ++i)
      {
        sprintf(str + i * 5, "0x%02x ", data[i]);
      }
    }

    Код (C++):
    #include <stdio.h>

    /*
    BYTE CRCMaker(BYTE b_input, BYTE b_CRC)
    {
       __asm
       {
           mov al,b_input
           mov ah,b_CRC
           mov cx,8
       mod1:   rol al,1
           rcl ah,1
           jnc mod2
           xor ah,0x69
       mod2:   dec cx
           jnz mod1
           mov b_CRC,ah
       }
       return b_CRC;
    }
    */


    unsigned char CRCMaker(unsigned char b_input, unsigned char b_CRC)
    {
        asm volatile
        (
         "        mov     %1,%%al"        "\n\t"
         "        mov     %0,%%ah"        "\n\t"
         "        mov     $8,%%cx"        "\n\t"
         "m1:     rol     $1,%%al"        "\n\t"
         "        rcl     $1,%%ah"        "\n\t"
         "        jnc     m2"             "\n\t"
         "        xor     $0x69,%%ah"     "\n\t"
         "m2:     dec     %%cx"           "\n\t"
         "        jnz     m1"             "\n\t"
         "        mov     %%ah,%0"        "\n\t"
         :"+r"(b_CRC)
         :"r" (b_input)
         :"al", "ah", "cx"
         );
        return b_CRC;
    }

    // получить массив байт в виде строки
    void getHexStr(unsigned char *data, char* str, int len)
    {
        for(int i=0; i< len; ++i)
        {
          sprintf(str+i*5, "0x%02x ", data[i]);
        }
    }


    int main()
    {
        // тестовые данные
        unsigned char packet[10] = {0xff, 0x01, 0x03, 0x01, 0x02, 0x00, 0x11, 0x00, 0xff, 0xff};

        char hexstr[(sizeof(packet))*5];
        getHexStr(packet, hexstr, sizeof(packet));
        printf("Оригинал:\t%s\n", hexstr);

        for(int i = 0; i < 7; i++)
            packet[7] = CRCMaker(packet[i], packet[7]);

        getHexStr(packet, hexstr, sizeof(packet));
        printf("Результат:\t%s\n", hexstr);
    }

    Комментарий: считаю первые 7 байт и пишу в 8-й.
    Результат получается одинаковый:
    Ардуино - 0xff 0x01 0x03 0x01 0x02 0x00 0x11 0xa6 0xff 0xff
    Программа - 0xff 0x01 0x03 0x01 0x02 0x00 0x11 0xa6 0xff 0xff
     
    Последнее редактирование: 23 июн 2017
    mcureenab и Igor68 нравится это.
  4. Igor68

    Igor68 Гуру

    В моём случае в IA241LX процессор не имеет 8 битных регистров... все 32 битные. Ни на какие регистровые пары не разделяются в этом ARM9. Потому и бит переноса сработает очень не скоро, а в алгоритм я не вдавался... действовал "силовым" методом - тупо.
     
  5. avt34

    avt34 Нерд

    Да я тоже... Ассемблер вообще впервые увидел. :)
    Основное происходящее в целом понятно, но надо было максимально точно сымитировать ардуинкой выдаваемые данные весами.
    Сейчас весы найдём, раскурочим, будем смотреть что же реально они передают :)
     
  6. Igor68

    Igor68 Гуру

    В моём случае 2 весовых терминала ТВ009 и один ТВ011. Скажу честно ТВ009 управляется удобнее... включая обнуление весов, сброс веса, пуск, стоп, получение данных и состояний. Можно ещё задавать параметры... и всё по RS485. С ТВ011 хуже... половина функций блокирована... пришлось задействовать порт ввода-вывода МК110-8Д.4Р от ОВЕН... ну и соответственно по Modbus RTU к онечно на другом RS485... благо в IA241LX их четыре. Для весов выделен отдельный порт RS485 - на нём все три весовых терминала. На остальные все устройства автоматизакии по Modbus RTU
     
    avt34 нравится это.
  7. Igor68

    Igor68 Гуру

    Да... кстати вот ещё кусочки:
    Код (C++):

    /************************
     * full comuting CRC of *
     * data for transeiving *
     ************************/

    BYTE TENZO_OutCRC(BYTE* DataOut, ushort size)
    {
      BYTE crc = 0;
      ushort count = 0;
      if(size < 1)
      return crc;
      do{
      crc = TENZO_CRCMaker(DataOut[count],crc);
      count++;
      }while(count < size);
      DataOut[count -1] = crc;
      return crc;
    }

    //=== create the data blocks for tranceive ===
    ushort TENZO_CreateSendPKT(BYTE* DatOut, BYTE* TxDat, ushort size)
    {
      ushort count_out = 0;
      ushort count_dat = 0;
      BYTE bt;
      TxDat[count_out] = 0xFF;
      count_out++;
      while(count_dat < size)
      {
      bt = DatOut[count_dat];
      TxDat[count_out] = bt;
      count_out++;
      if(bt == 0xFF)
      {
      TxDat[count_out] =0xFE;
      count_out++;
      };
      count_dat++;
      };
      TxDat[count_out] = 0xFF;
      count_out++;
      TxDat[count_out] = 0xFF;
      count_out++;
      //
      return count_out;
    }

    //=== dissection the data blocks of receiving ===
    ushort TENZO_DissectionRecvPKT(BYTE* DataIn, BYTE* RxDat)
    {
      ushort size = 0;
      ushort count = 0;
      BYTE bt;
      if(RxDat[count] != 0xFF)
      return size;
      count++;
      while(count < 256)
      {
      bt = RxDat[count];
      if(bt == 0xFF)
      {
      count++;
      if(RxDat[count] != 0xFE)
      break;
      }
      DataIn[size] = bt;
      size++;
      count++;
      }
      return size;
    }

    //==== BCD to FLOAT ===
    float TENZO_BCDtoFLOAT(uint _bcd)
    {
      float _float, mn;
      uint p = 0;
      p += (uint)(_bcd & 0x0F);
      p += (uint)(((_bcd >> 4) & 0x0F) * 10);
      p += (uint)(((_bcd >> 8) & 0x0F) * 100);
      p += (uint)(((_bcd >> 12) & 0x0F) * 1000);
      p += (uint)(((_bcd >> 16) & 0x0F) * 10000);
      p += (uint)(((_bcd >> 20) & 0x0F) * 100000);
      _float = (float)(p);
      p = (uint)((_bcd >> 24) & 0x07);
      mn = pow(10.0, (float)(p));
      _float = _float / mn;
      if((_bcd >> 24) & 0x80)
      _float *= -1.0;
      return _float;
    }

    //==== FLOAT to BCD ===
    uint TENZO_FLOATtoBCD(float _float)
    {
      uint p, _bcd = 0;
      p = (uint)(_float / 100000.0);
      _bcd |= (p << 20);
      _float -= (float)(p * 100000);
      p = (uint)(_float / 10000.0);
      _bcd |= (p << 16);
      _float -= (float)(p * 10000);
      p = (uint)(_float / 1000.0);
      _bcd |= (p << 12);
      _float -= (float)(p * 1000);
      p = (uint)(_float / 100.0);
      _bcd |= (p << 8);
      _float -= (float)(p * 100);
      p = (uint)(_float / 10.0);
      _bcd |= (p << 4);
      _float -= (float)(p * 10);
      p = (uint)(_float);
      _bcd |= p ;
      return _bcd;
    }

     
    Там ещё толпа функций для выполнения команд... как в инструкции. А вот преобразование данных в/из BCD реализовал добольно не сразу.
     
    avt34 нравится это.
  8. avt34

    avt34 Нерд

    Это перевод веса в их формат?
     
  9. Igor68

    Igor68 Гуру

    Простите за назойливость... но это в довесок (вырвал из проекта)
    tenzo-m.zip
    Может сгодиться... и упростит задачу.
    Простите за русскую кодировку!
     

    Вложения:

    • tenzo-m.zip
      Размер файла:
      10,4 КБ
      Просмотров:
      415
  10. Igor68

    Igor68 Гуру

    Да в этом формате они и передают.
     
  11. avt34

    avt34 Нерд

    Спасибо, наверняка пригодится!