Kérkel segíts, hogy ne maradjon hibás információ az oldalon!
Ha szerinted valami nem fedi a valóságot, kérlek írd meg, hogy javítani tudjam. Ha kérdésed van, fordulj hozzám bizalommal!

2010. február 22., hétfő

Advanetch CAN - Implementálás II rész

Több tapasztalat is összegyűlt :)
Az első nem is advantech, se nem implementálás jellegű, de megszívlelendő: mindig tartsd be az előírásokat. Ez úgy jött, hogy miután a kártya 1-es portja simán elbeszélgetett a 2-essel, a beckhoff CANopen fejegységgel sehogy sem akart. Ez a fejegység auto baud rate-s és ahogy elindult az üzi, kiállt hibára. Addig addig vakargattam a fejem, amig a leírásában megtaláltam, hogy ez bizony busz jellegű hiba. Keressünk szakadást, rövidzárt, ellenőrrizzük a lezáró ellenállásokat. Na, ekkor elhatároztam magam és ráforraszottam őket. Rögtön ment minden, mint a doxa óra.

Az implementálás maga jó hosszan és nehezen kezdődött. Először is meggyűlt a bajom a port írás/olvasásával. Ha asszinkron módon nyitunk meg egy fájlt/perifériát (CreateFile), akkor az írás-olvasás függvények (ReadFile, WriteFile) mindig várnak egy OVERLAPPED paramétert, amit általában előre nullázni kell. Ha ezt nem kapják meg, mindenféle hibaüziket küldenek, amikből csak az nem derül ki, hogy ez hiányzik nekik :). Az advantech függvény könyvtárakban az acCanOpen() függvény foglalja magába a port helyes megnyitását (CreateFile hívását a megfelelő paraméterekkel).

[code]
[..] //Deklarációs résznél
OVERLAPPED ov;
HANDLE hDevice;

[..]
hDevice= acCanOpen("can2", 1); // Az 1 azt jelenti, hogy asszinkron módon

ZeroMemory( &ov, sizeof(OVERLAPPED) );
ov.hEvent = CreateEvent( NULL,FALSE, FALSE, NULL );

ret=acCanWrite(hDevice, &pbyData, 1, &write_time, &ov);
ulErr= GetLastError();
if(ret!=0) printf("Writing can failed %d, %lu, wt %u\n",ret, ulErr, write_time);

[/code]
Az acCanWrite és acCanRead függvények az írás-olvasást teszik meg. Általáabn az advantechtől kapott header (.h) fájlban levő függvények és deklarációk érthetőek. Ez alól talán az üzenet szerkezet volt a kivétel.
typedef struct {
int flags; /* Flags, indicating or controlling special message properties */
int cob; /* CAN object number, used in Full CAN */
ULONG id; /* CAN message ID, 4 bytes */
short int length; /* Number of bytes in the CAN message */
UCHAR data[DATALENGTH]; /* Data, 0...8 bytes */
} canmsg_t;
Míg sima can esetében ez nem igazán volt probléma, elsőre nem tudtam, hogy a CANopen COB+ID-jét hova tenni. Rövid próbálkozások után (miután már működött a rendszer, és a lezáró ellenállások is a helyükön voltak;)) lokalizálódott: a COB+ID-et egyértelműen az ID mezőbe kell tenni. A többi tényleg egyértelmű és a commanetezés jól magyaráz. Megy minden, mint a karika csapás :).
Másik nagyon fontos, hogy ugye a CAN használ RTR flaget (Remote Request), az SDO uploadoknál nem kell RTR flaget használni, mert ha egy frameben az RTR flag = 1, akkor a controller az adat résszel nem foglalkozik és mindenféle fura adat jelenik meg, ha monitorral nézzük.

A SetBaud és hasonló beállításokat a kártyán levő chip reset módba lökése után lehetett elvégezni, így legyen itt egy minta erre:
[CODE]
int SetBaud(HANDLE ref, int nBaud)
{
int flag;
flag = acEnterResetMode(ref);
flag |= acSetBaud(ref, nBaud);
flag |= acEnterWorkMode(ref);
return flag;
}
[/CODE]

Advantech C + LabView
A labviewes wrapper fileoknál sem volt igazi probléma. Elsődlegesen a HANDLE típus passzolása nem akart rögtön menni, így ha nem is biztos, hogy gyönyörű, de jól működö megoldás az volt, hogy a LabView híváskor átadott egy int32 mutatót (32bites OS), a függvényem elkészítette a handlert és átadtad intnek castolva:
[CODE]
int CreateCanRef(unsigned int *ref, char *portName)
{
HANDLE r;

if (!ref) return -2;
r= acCanOpen(portName, 1);
if( r== INVALID_HANDLE_VALUE )
return -1;

*ref=(unsigned int)r;
return 0; // Lehetne a visszaadott érték is, akkor ez lenne itt: (unsigned int)r;
}
[/CODE]
A többi függvény értékként kapja meg a referenciát és a C fv. deklarációjában HANDLE-ként várjuk.
A különböző struktúrák átadásába nem mentem most bele, nem is azért, mert sok rossz tapasztalatom van, de inább azért, mert itt nem tűnt szükségesnek.
Nagy negatívum viszont, hogy a wrapperek használatával valamiért nagyon lassú a labview, és szinte azonnal el kezd laggolni. Gondolom memória kezelés, vagy hasonló miatt. Ezért át kell dolgoznom az egészet valahogy úgy, hogy a busz olvasás egy külön C-s thread intézi a busz forgalmat, de legalábbis az olvasást, és a labviewnek egy struct mutatót adok, amit pl íráskor felfűzök egy láncolt listára és az olvasó thread fogadott üzenetkor onnan kikeresi.

Nincsenek megjegyzések: