CAN skripty, díl 3

V tomto díle seriálu o CAN bus skriptech v programu PP2CAN si ukážeme jak simulovat data z joysticku s CAN sběrnicí, který používá protokol SAE J1939. Zároveň si ukážeme funkce pro snadné nastavení dat do CAN zprávy, pokud data nejsou zarovnána na jednotlivé bajty a jejich délka není násobkem 8 bitů.

Aby byl tento příklad funkční, je třeba použít překladač CAN bus skriptů verze 1.90. Tato verze překladače je součástí programu PP2CAN verze 3.041. Novinkou je v ní kromě podpory funkcí pro snadné dekódování dat z CAN zprávy i opačná funkce snadného vkládání dat do CAN zprávy a také obsahuje počáteční podporu formátu dat unsigned64 a int64. Poslední verzi software najdete ke stažení vždy zde.

Pokud si chcete skript otestovat, ale nemáte po ruce joystick, je možné použít softwarový emulátor - virtuální joystick. Jeden takový který bez problému se skriptem funguje najdete zde.

Norma SAE J1939 popisuje zprávu kterou použijeme takto:

PGN 64982 Basic Joystick Message 1

Parameter Group Number: 64982 (0x00FDD6)

  • Start Position / Length / Parameter Name SPN
  • 1.1 - 2 bits Joystick 1 X-Axis Neutral Position Status 2675
  • 1.3 - 2 bits Joystick 1 X-Axis Lever Left Negative Position Status 2670
  • 1.5 - 2 bits Joystick 1 X-Axis Lever Right Positive Position Status 2665
  • 1.7 - 2 10 bits Joystick 1 X-Axis Position 2660
  • 3.1 - 2 bits Joystick 1 Y-Axis Neutral Position Status 2676
  • 3.3 - 2 bits Joystick 1 Y-Axis Lever Back Negative Position Status 2671
  • 3.5 - 2 bits Joystick 1 Y-Axis Lever Forward Positive Position Status 2666
  • 3.7 - 4 10 bits Joystick 1 Y-Axis Position 2661
  • 5.5 - 2 bits Joystick 1 Y-Axis Detent Position Status 2681
  • 5.7 - 2 bits Joystick 1 X-Axis Detent Position Status 2680
  • 6.1 - 2 bits Joystick 1 Button 4 Pressed Status 2688
  • 6.3 - 2 bits Joystick 1 Button 3 Pressed Status 2687
  • 6.5 - 2 bits Joystick 1 Button 2 Pressed Status 2686
  • 6.7 - 2 bits Joystick 1 Button 1 Pressed Status 2685
  • 7.1 - 2 bits Joystick 1 Button 8 Pressed Status 2692
  • 7.3 - 2 bits Joystick 1 Button 7 Pressed Status 2691
  • 7.5 - 2 bits Joystick 1 Button 6 Pressed Status 2690
  • 7.7 - 2 bits Joystick 1 Button 5 Pressed Status 2689
  • 8.1 - 2 bits Joystick 1 Button 12 Pressed Status 2696
  • 8.3 - 2 bits Joystick 1 Button 11 Pressed Status 2695
  • 8.5 - 2 bits Joystick 1 Button 10 Pressed Status 2694
  • 8.7 - 2 bits Joystick 1 Button 9 Pressed Status 2693

Naším skriptem si budeme simulovat zvýrazněné položky.  Celý skript je ke stažení v archivu zip zde. Archiv obsahuje i soubor EYE, který můžeme použít pro zobrazení dat generovaných skriptem na CAN (nebo simulovaných přes virtuální CAN - V2CAN) v nástroji Signal receiver nebo Data view. Při použití nástroje Signál receiver je dle potřeby nutno upravit položku TX - směr dat. Pokud odesíláme data na skutečný CAN, je třeba dekódovat pro zobrazení hodnot směr TX. V režimu V2CAN pak směr RX - data čteme v režimu V2CAN zpět. Nástroj Data view zobrazuje oba směry.

Skript je uveden níže a obsahuje komentáře, které podrobně vysvětlují jeho funkci. Pokud se Vám výpis skriptu nezobrazuje, najeďte na jeho pole myší.

script:
    //Typ skriptu
    //Chci data generovat periodicky - tedy periodicky typ skriptu.
    type = TIMER_SCRIPT;
end

// Definice promenych
variables:
    unsigned x_neutral;
    unsigned x_left;
    unsigned x_right;
    unsigned y_neutral;
    unsigned y_back;
    unsigned y_forward;

    unsigned64 value;
    double x;
    double y;
    bool button_1;
    bool button_2;
end

// Definice objektu
// Je definovan jeden objekt a to objekt CAN zpravy.
objects:
    obj_can_msg can_msg;
end

// Init sekce - tato sekce je volana jednou po spusteni skriptu.
// Sekce se pouziva na inicializaci dat.
init:
    logs("Simulace joysticku dle SAE J1939");
    log_endl();
    //Nastavuji datove bajty na FF, tedy nevyuzite polozky budou signalizovat neznama data.
    can_msg.set_all(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF);
    //Rozsireny - 29 bitovy identifikator.
    can_msg.stext=true;
    //Nejedna se o RTR, ale o datovou zpravu.
    can_msg.rtr=false;
    //8 datovych bajtu
    can_msg.size = 8; 
    //29 bitove ID: 0xCFDD6FE=217962238 ,PGN:FDD6
    can_msg.set_ID29(217962238);
    //Skript bude spousten kazdych 100ms a se stejnou periodou se budou generovat data.
    //Casovani lze ovládat sliderem v okne skriptu, nicmene timto si prednastavim pozadovanou hodnotu.
    ui_set_timer_script_period (100);
end

body:
    //------------------------------------------------------
    x_neutral = 0;
    x_left = 0;
    x_right = 0;
    //Ctu hodnotu X pripojeneho joysticku (X-leva/prava).
    //Ctena hodnota je v rozsahu 0-65535, stred odpovida 32767.
    //Data dle SAE J1939 maji rozsah 0-1000. Smer neni rozlisovan a udava se
    //pomoci Left/Right Positive Position Status.
    x = ui_joy_x(0);
    //Leva strana
    if(x>32767)
    {
        x_left = 1;
        x_right = 0;
        x = x-32767;
        x = (x/32767.0) * 1000.0;
    }
    //Neutral
    else if(x==32767)
    {
        x_left = 0;
        x_right = 0;
        x = x-32767;
        x = 0;
    }
    //Prava strana
    else
    {
        x_left = 0;
        x_right = 1;
        x = 32768-x;
        x = (x/32768.0) * 1000.0;
    }
    //Okno skriptu obsahuje univerzalni ovladaci a zobrazovaci prvky.
    //Do prvniho okna pro zobrazeni ciselne hodnoty vypisu vypoctenou hodnotu.
    ui_set_d0(x);
    //Osetreni aby maximalni hodnota byla 1000 a bylo ji vzdy dosazeno.
    //Diky nepresnostem nemusi vypocet zmeny rozsahu koncit presne na hodnote 1000.
    if(x>999)
    {
        x=1000;
    }
    //Dle normy by snimani neutralni hodnoty melo byt zajisteno jinym mechanismem
    //nez je mereni polohy (bezpecnost).
    //Neutralni polohu budeme signalizovat v rozsahu -10 az 10 od stredu.
    if(x<10)
    {
        x_neutral=1;
    }
    //Jelikoz se jedna o konverzi z double na unsigned, nefunguje automaticke pretypovani timto smerem,
    //provedeme tak nejprve urceni cele casti a prevod do signed a pak konverzi na unsigned.
    //Konverze unsigned na unsigned64 je automaticka.
    value = i2u(truncd(x));
    
    //Nastavujeme hodnotu x_neutral jako polozku Neutral Position Status do CAN zpravy.
    //Metoda set_value objektu CAN zpravy ma parametry:
    // - index prvniho bitu (0), CAN zprava ma 8 datovych bajtu, tedy 64 bitu, index 0 az 63
    // - bitova delka (2 bity)
    // - data se nastavuji ve formatu little endian (false)
    // - data nejsou signed  (false)
    //Status je dle SAE J1939 dvoubitovy. My signalizujeme 0/1, stavy neznama data zde neuvazujeme,
    //jsou vzdy znama, nicmene u dalsich nevyuzitych polozek jsou bity nastaveny na 1 - neznama data.
    can_msg.set_value(x_neutral,0,2,false,false);
    //Nastaveni statusu Lever Left Negative Position Status.
    can_msg.set_value(x_left,2,2,false,false);
    //Nastaveni statusu Lever Right Positive Position Status.
    can_msg.set_value(x_right,4,2,false,false);
    //Nastaveni X-Axis Position.
    can_msg.set_value(value,6,10,false,false);
    //------------------------------------------------------
    //Identicky kod avsak tentokrat pro osu Y.
    y_neutral = 0;
    y_back = 0;
    y_forward = 0;
    y = ui_joy_y(0);
    if(y>32767)
    {
        y_back = 1;
        y_forward = 0;
        y = y-32767;
        y = (y/32767.0) * 1000.0;
    }
    else if(y==32767)
    {
        y_back = 0;
        y_forward = 0;
        y = y-32767;
        y = 0;
    }
    else
    {
        y_back = 0;
        y_forward = 1;
        y = 32768-y;
        y = (y/32768.0) * 1000.0;
    }
    ui_set_d1(y);
    if(y>1000)
    {
        y=1000;
    }
    if(y<10)
    {
        y_neutral=1;
    }

    value = i2u(truncd(y));
    
    can_msg.set_value(y_neutral,16,2,false,false);
    can_msg.set_value(y_back,18,2,false,false);
    can_msg.set_value(y_forward,20,2,false,false);
    can_msg.set_value(value,22,10,false,false);
    //------------------------------------------------------
    //Zobrazeni hodnoty tlacitek joysticku ve tretim a ctvrtem okne pro zobrazeni ciselne hodnoty 
    //v okne skriptu.
    ui_set_b0(ui_joy_b(0,0));
    ui_set_b1(ui_joy_b(0,1));
    //Ulozeni hodnoty tlacitek joysticku.
    button_1 = ui_joy_b(0,0);
    button_2 = ui_joy_b(0,1);
    //Vlozeni hodnot tlacitek do CAN zpravy.
    can_msg.set_value(button_1,46,2,false,false);
    can_msg.set_value(button_2,44,2,false,false);
    //------------------------------------------------------
    //Odeslani zpravy na CAN sbernici.
    can_msg.send();
end