AT vars (directly represented variables) - technical notes for device implementers The device implementation should implement the mapping from an AT variable address (say %MX10.3.1.0 ) to the real I/O value. This doc explains how to do it. ========================================================================================================== There are several options for implementing AT vars, each has its pro and cons. Briefly: Mode A: ( ATVARS_ALLOCATED_BY_DEVICE not defined) AT Variables are allocated by GEB generated code (struct atVars) Real IO reading/write is done during hooks, During POU execution, values of variables are read/written from/to GEB struct. Mode B: (#define ATVARS_ALLOCATED_BY_DEVICE) GEB generated code does not allocate AT variables - these are either B1 - allocated by the device code (in deviceio.c typically) in its own memory space (cache/table) Real IO reading/write is done during "hooks" macros GEB_DRV_PRE/POST_READ GEB_DRV_PRE_READ/WRITE (called once per execution cycle) During POU execution, values of variables are read/written from the cache/table B2 - directly read/written without intermediary allocation Nothing is done during GEB_DRV_PRE/POST_READ GEB_DRV_PRE_READ/WRITE Values are read/written from real IO at each access, during POU execution, PROS/CONS A Pros: simple to implement - secure Cons: assumes that different addresses correspond to different variables - does not allow for hierarchical addressing schemes (say, where %IB61.3 or %IX61.3.5 are parts of %IW61.3 ) B1 Pros: secure and flexible - allows any addressing scheme Cons: implementer must either allocate and copy the entire AT address range in each hook call, or somehow use the "hints" in the hook code (which AT vars are used) to only copy (and allocate?) the used AT vars B2 Pros: simple to implement - allows any addressing scheme Cons: I/O readings/writings done during POU execution: this violates the standard and might be ineffficient or impracticable ---------------------------------------------------------------------------------- Suggested decision workflow: - Do you need to support arbitrary (hierarchical) addressing schemes ? (say, where %IB61.3 or %IX61.3.5 overlap or are parts of %IW61.3 ) ? If no, go for A. - Else: do you want/need to read/write the real IO once per cycle ? If yes (recommended), go for B1 Else go for B2 ---------------------------------------------------------------------------------- Detailed instructions for each mode In all cases you need to provide some implementation of the final getter/setters GEB_DRV_GET_* and GEB_DRV_SET_* (which can be delegated to the simplified functions defined via USE_DRVarModuleSimple , see gebdrv.h ) but the meaning (and when they will be called) differ, as explained below. If you need to implement some global tasks (syncronization) before/after reading the real IO, then (re)define the macros GEB_DRV_PRE_READ GEB_DRV_POST_READ GEB_DRV_PRE_WRITE GEB_DRV_POST_WRITE These should be declared in gebarch.h or some header included by it. Mode A: ( ATVARS_ALLOCATED_BY_DEVICE should NOT be defined in gebarch.h) You must implement the getters/setters GEB_DRV_GET_INT(... ) and GEB_DRV_SET_INT(... ) (or the simpler delegated variants say geb_drv_get_int16(d,w,ad0,ad1,ad2,ad3) These will read/write the "real" I/O, they will be invoked at the hooks, before/after each cycle Mode B: #define ATVARS_ALLOCATED_BY_DEVICE in gebarch.h or header included by it. B1: Real IO should be part of the macros GEB_DRV_POST_READ GEB_DRV_POST_WRITE The values should be copied, inside those macros, to/from some internal table. The getters GEB_DRV_GET_INT(... ) and GEB_DRV_SET_INT(... ) should read/write not from IO but from those tables (this getters/setters will be called at POU exec time) Remember that the AT space range should be consistent with the device.properties spec (but you are allowed to use any addressing scheme) In exceptional cases (you need to use this mode but you cannot copy the entire AT range) you can implement the macros GEB_DRV_WRITE_TOIO GEB_DRV_READ_FROMIO - this macros will be called during hook time, as to hint which AT vars should effectively be used (read/write); the implementer could use this to only transfer this variables (or even allocate them?) Normally, these macros can be left as blank (NOPs) B2: You must only implement the getters/setters GEB_DRV_GET_INT(... ) and GEB_DRV_SET_INT(... ) the same as option 2. These will read/write the "real" I/O, but in this case they will be invoked during POU exec time (this mode is not standard compliant, and hence it's not recommended). ------------------- Internal details (how it works internally) C generator insert these macros: GEB_DRV_[P|H]GET(VARTYPE,varName,DIR,WIDTH,AD0,AD1,AD2,AD3) GEB_DRV_[P|H]SET(VARTYPE,varName,DIR,WIDTH,AD0,AD1,AD2,AD3,expr) Eg: GEB_DRV_HGET(INT,vat_IW61_1,'I','W',61,1,0,0); GEB_DRV_PSET(BOOL,vat_MX66_3,'M','X',66,3,0,0,v_ATvars.vat_MX66_3); These are used both inside pou execution (P) and inside the hooks (H) functions ATvars_read/ATvars_write, eg: void ATvars_read(void) { GEB_DRV_PRE_READ GEB_DRV_HGET(INT,vat_IW61_1,'I','W',61,1,0,0); GEB_DRV_HGET(BOOL,vat_MX66_3,'M','X',66,3,0,0); GEB_DRV_POST_READ } void ATvars_write(void) { GEB_DRV_PRE_WRITE GEB_DRV_HSET(INT,vat_MW63_8,'M','W',63,8,0,0,v_ATvars.vat_MW63_8); GEB_DRV_POST_WRITE } These macros are defined in gebdrv.h