V některých případech je třeba použít v CAN skriptu funkci z externí DLL knihovny. Důvodem může být například práce s dalším hardware, volání algoritmu který by se v rámci skriptu realizoval obtížně nebo jej neznáme. My si v tomto článku ukážeme jak zavolat funkci pro výpočet klíče ze seedu při zabezpečeném přístupu do ECU. To provedeme pomocí volání funkce VKeyGenResultEx z externí DLL knihovny. Tento formát rozhraní funkce je používán v SW firmy Vector. V příkladu použijeme demonstrační DLL místo originálních DLL pro SW CANoe.
Funkce v DLL je definována takto:
enum VKeyGenResultEx { KGRE_Ok = 0, KGRE_BufferToSmall = 1, KGRE_SecurityLevelInvalid = 2, KGRE_VariantInvalid = 3, KGRE_UnspecifiedError = 4 };
VKeyGenResultEx GenerateKeyEx( const unsigned char* iSeedArray, /* Array for the seed [in] */ unsigned short iSeedArraySize, /* Length of the array for the seed [in] */ const unsigned int iSecurityLevel, /* Security level [in] */ const char* iVariant, /* Name of the active variant [in] */ unsigned char* ioKeyArray, /* Array for the key [in, out] */ unsigned int iKeyArraySize, /* Maximum length of the array for the key [in] */ unsigned int& oSize /* Length of the key [out] */ );
Abychom mohli tuto funkci zavolat, potřebujeme využít objektu obj_dllfnc. Prvním parametrem volane funkce je pole bajtů iSeedArray. Pro předání tohoto pole do funkce je třeba použít objekt obj_memory a tuto paměť alokovat. Stejně tak v případě parametrů iVariant a ioKeyArray. Pole ioKeyArray je použito pro návrat vypočteného klíče. Délka klíče je navrácena pomocí reference oSize. V tomto případě se jedná v podstatě také o ukazatel, proto i pro tento parametr je třeba alokovat paměť. Skript tak alokuje pomoci objektu obj_memory celkem 4 bloky. V případě když by bylo třeba volat funkci, která má jako parametr struktoru, postup je stejný, je třeba alokova paměť a do ní vložit data pomocí metod které tento objekt nabízí.
Skript, testovací DLL knihovna a zdrojový kód DLL knihovny je součástí instalace programu PP2CAN od verze 3.059.
Vlastní skript vypadá takto, je doplněn komentáři:
// Typ scriptu script: type = TIMER_SCRIPT; end // Definice promennych variables: bool ret; unsigned ret_unsigned; unsigned addr_seed; //pro uložení adresy pameti unsigned addr_key; unsigned addr_variant; unsigned addr_key_size; end // Definice objektu objects: obj_dllfnc dll; obj_memory seed; obj_memory key; obj_memory variant; obj_memory key_size; end // Init sekce skriptu init: seed.alloc(4);//alokace pameti pro seed ret = seed.set(0,0x01); //nastaveni jednotlivych bajtu ret = seed.set(1,0x02); ret = seed.set(2,0x03); ret = seed.set(3,0x04); addr_seed = seed.pointer(); //ziskani adresy pameti key.alloc(8); //alokace pameti pro key key.fill(0x00); //vynulovani pameti addr_key = key.pointer(); variant.alloc(32); //alokace variant.set_string(0,16,"12345678"); //vlozeni retezce do alokovane pameti addr_variant = variant.pointer(); key_size.alloc(4); key_size.fill(0x00); addr_key_size = key_size.pointer(); ret = dll.load_dll("c:\\PP2CAN\\Demo data\\TestDll.dll","GenerateKeyEx"); //nacteni DLL a vzhledani funkce ret = dll.set_abi(ABI_STDCALL); //nastaveni ABI (application binary interface) ret = dll.set_param_num(7);//pocet parametru ret = dll.set_param_type(0, PARAM_POINTER); //nastaveni typu jednotlivych parametru ret = dll.set_param_type(1, PARAM_UINT16); ret = dll.set_param_type(2, PARAM_UINT32); ret = dll.set_param_type(3, PARAM_POINTER); ret = dll.set_param_type(4, PARAM_POINTER); ret = dll.set_param_type(5, PARAM_UINT32); ret = dll.set_param_type(6, PARAM_POINTER); ret = dll.set_return_type(PARAM_UINT32); //nastaveni navratove hodnoty, vraci enum - tedy muzeme pouzít pro navrat //32 bitový int nebo unsigned int pokud enum nema zaporne hodnoty end body: ret = dll.set_param_memory(0,addr_seed); //nastavujeme parametr na hodnotu ukazatele pameti ret = dll.set_param_uint16(1,4); //tento parametr je uint16 - nastavujeme hodnotu ret = dll.set_param_uint32(2,1); ret = dll.set_param_memory(3,addr_variant); ret = dll.set_param_memory(4,addr_key); ret = dll.set_param_uint32(5,4); ret = dll.set_param_memory(6,addr_key_size); //reference ukazatel na pamet - reference - tedy vlastne ukazatel key.print(); //tisk obsahu klice - prazdny ret = dll.call(); //zavolani funkce z DLL key.print(); //tisk obsahu klice, chovani viz TestDll.c ret_unsigned = dll.get_return_uint32(); //cteni navratove hodnotz printu(ret_unsigned); ret_unsigned = key_size.get_uint32(0); //cteni delky klice, ktera je vracena pres referenci printu(ret_unsigned); stop(); //zastaveni skriptu end // Shutdown sekce skriptu shutdown: end
Pokud skript neobsahuje nastaveni všech typů parametrů, navratove hodnoty a nastaveni všech hodnot paramerů, je toto signalizováno chybou v okně logu nástroje CAN skript. To zda počet parametrů a jejich typ je správný však pochopitelně kontrolováno není.
Další díly seriálu:
- Díl 1: Periodické generování dat na CAN sběrnici.
- Díl 2: Uživatelské prvky pro řízení skriptu
- Díl 3: Simulace joysticku dle SAE J1939
- Díl 4: Monitorování a zápis událostí do souboru CSV
- Díl 5: Měření periody a zápis do CSV pomocí přiřazení objektu
- Díl 6: Komunikace pomocí TCP
- Díl 7: Komunikace pomocí sériové linky
- Díl 8: PID regulátor
- Díl 9: Výpočet CRC a objekt obj_dataset
- Díl 10: Volání funkce z externí DLL
- Díl 11: Odeslání emailu s hlášením