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:
endPokud 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
