Ett exempel

För att visa hur man arbetar med de klasser som översikligt beskrivits ovan, startar vi med
ett litet exempel. Klasserna beskrivs med detaljerat nedan.

I vårt exempel har vi ett ProviewR system som kommunicerar med en annan nod via UDP/IP. Vi vill
skicka ett antal meddelanden i båda riktningarna. Min nod heter 'dumle' och remote noden heter
'asterix'.

Meddelanden vi ska sända är:

d_a_RequestData      4 Byte
d_a_Report           20 Byte
och meddelanden som vi ska ta emot:

a_d_Data             365 Byte (as an answer to the d_a_RequestData-message)
a_d_Error            10 Byte
Konfigurationen i nod-hierakin ser ut så här.

Under RemoteConfig-objektet ligger ett RemnodeUPD objekt, där IP-address, nodnamn och
port-nummer är konfigurerade.



Under RemnodeUPD-objeketet ligger fyra RemTrans objekt, ett för varje meddelande. I remtrans-
objekten har riktningen (send eller receive) konfigurerats. Adresserna är numrerade för att
kunna särskilja meddelandena, och meddelandenas storlek är angiven.



Under remtrans-objektet ligger buffer-objektet. För de mindre meddelandena används Buff256 objekt.
Data meddelandet är större och använder ett Buff1440 objekt.



Data-strukturen

Data-strukturen för meddelandena är definierad i filen ra_plc_user.n i $pwrp_inc katalogen. Den
här filen inkluderas automatiskt vid kompilering av plc-koden. Data-strukturen ser ut så här:

typedef struct {
   pwr_tUInt32 Id;
} d_a_RequestData;

typedef struct {
   pwr_tUInt32 Id;
   pwr_tFloat32 data_1;
   pwr_tInt32 data_2;
   pwr_tInt32 data_3;
   pwr_tInt32 data_4;
} d_a_Report;

typedef struct {
   pwr_tUInt32 Id;
   pwr_tFloat32 data_1;
   ...
   ...
   pwr_tInt32 data_xx;
} a_d_Data;

typedef struct {
   pwr_tUInt32 Id;
   pwr_tInt32 func_no;
   pwr_tInt16 err_code;
} a_d_Data;

För att optimera läs och skrivning kommer gcc kompilatorn normalt att placera element i
data-strukturer på 32 eller 64-bit ordgräns. När man skapar strukturer för kommunikation kommer
det att skapa oreda då olika kompilatorer och plattformar har olika regler för alignment. För att
undvika detta, använd 'attribute packed' vid deklarationen av data-strukturen.

typedef struct {
   pwr_tUInt32 Id;
   pwr_tInt32 func_no;
   pwr_tInt16 err_code;
} __attribute__((__packed__)) a_d_Data;

Plc-koden


Koden ligger i ett PlcPgm med namnet Comm. I programmet finns ett RemTransSend-objekt och
ett RemTransRcv objekt. Dess objekt återfinns under mappen 'Other' i paletten i plc-editorn.
Till RemTransSend-objektet kopplas den RemTrans som ska sändas. I det här fallet
d_a_RequestData meddelandet. Meddelandet sänds när Dv-signalen "RequestData" sätts. På samma
sätt är a_d_Data meddelandet kopplat till RemTransRcv-objektet som tar emot svarsmeddelandet
på request meddelandet.



Både RemTransSend och RemTransRcv-objekten har underfönster. För RemTransSend, kommer
underfönstret att exekveras vid en positiv flank på snd-ingången. När underfönstret har
exekverats, sätts DataValid attributet i det kopplade RemTrans-objektet, och transport-processen
för den aktuella Remnoden skickar iväg meddelandet och sätter DataValid till 0.

För RemTransRcv exekveras underfönstret när DataValid attributet i det kopplade RemTrans-objektet
sätts. När transport-processen för den aktuella Remnoden tar emot ett meddelande, fyller den i
buffer-objektet med meddelandet och sätter DataValid flaggan. När underfönstret har exekverat
återställs DataValid flaggan.

Underfönstret för sändning

I send underfönstret fyller man i data för sänd-bufferten. Buffer-objektet för meddelandet kopplas
till en DataArithm. Den speciella 'structdef'-syntaxen castar Da1 till en pekare till en
d_a_RequestData struct.



Underfönstret för mottagning

I mottagnings-underfönstret packas det mottagna meddelandet upp. Buffer-objektet för mottagningen
kopplas till en DataArithm. Återigen använder vi classdef-satsen för att casta Da1 pekaren.
Data packas upp och läggs på DataArithm-objektets utgångar. Om inte utgångarna för en DataArithm
räcker till adderar man flera DataArithm-objekt och fortsätter på samma sätt.