Other Parts Discussed in Thread: LP-AM243
Tool/software:
EDS FILE
$ EZ-EDS Version 3.34.1.20231010 Generated Electronic Data Sheet
[File]
DescText = "EtherNet/IP(tm) Adapter am243x-lp freeRTOS";
CreateDate = 08-19-2021;
CreateTime = 17:53:35;
ModDate = 02-29-2024;
ModTime = 07:00:00;
Revision = 3.7;
HomeURL = "www.ti.com";
[Device]
VendCode = 806;
VendName = "Texas Instruments";
ProdType = 43;
ProdTypeStr = "Analog I/O + GPIO Adapter"; ; More specific
ProdCode = 24311;
MajRev = 3;
MinRev = 7;
ProdName = "LP-AM243 8AI/2DI/2DO Adapter"; ; Much clearer in device list
Catalog = "AM243-8AI"; ; Friendly name for inventory lists
Icon = "ti.ico";
IconContents =
"AAABAAEAICAAAAAAIACsAwAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAgAAAA"
"IAgGAAAAc3p69AAAAAFzUkdCAK7OHOkAAAAEZ0FNQQAAsY8L/GEFAAAACXBI"
"WXMAAA7DAAAOwwHHb6hkAAADQUlEQVRYR+1WSS9kURQusyBmNnaGxBghYpbY"
"CZGQYIWFhUQQiSkWhKUhVhIr/kzPqqhXhlK6KE2V7pL2J26f77j35T3ea0pK"
"rXzJSb07nfOd7557bzk+8Brcra2Jo4ICcVxUpJtG7bOKCiGnvC9up6fFV4dD"
"OA32g+woMfEZgfDmpghvbESXWGh+XhwgoMFcZJ6cHFOg4OKi+ET9ICe7ogMr"
"AlDBk51tCuRrbRWfqf+4uDhGBHJzoxvIDlYEDvFLNeDv7RV/d3aYyM3EhAiM"
"juqkLvv7xdXgoAgMDYmrgQH+lkORwYqAIgHJQwsL7PibbOMbhfiFvr+ToSYw"
"hkLGWMSwUwB9KiCAYNgafP/s7mYCrJT8hfHESBGcmzMRUM5OSkuFt6WFnd5M"
"TnKWnsxMbl+Pj4vjsjLeJszFqXkzgbuVlcdzLw1ZaunpJmdeupSgwEVbm6lf"
"y8ri+SCg1IkYv0ZGdAWQBch46+pMzpApFIBasovhjIvTs8e6G1JGDpmBQWdC"
"gnAlJZktJUW44uPZAQjAGeaiquVSBghCgYf9fb3/D13h6DOudSUnWxM4ra7m"
"ouFJFqbkhzOYOz9fnNbWsrOHvb3HQJQt2uH1dXFSWSk0uieMa2GY52tutibh"
"LizkCcYFdoaMITnWhWZn+RuPFNpn5eWcDPbcat3TOjHBTa+cseDsDM49eXns"
"yEcOccZ98kRoGRmWwWEg4O/stCcAqMKxcqAMji7prGO+m94EZBycmuI2ErBb"
"/yoC/q4uVkEVDwwOjVlh/PfqKjtCoWLreDHBmZYmXFTQql6MPqCUt6bm/wQA"
"OMQCOECwAzhMTdWJ4VdOtcRFRwdni7nwA38wNxXm3dLSywT8PT38tkNaX3u7"
"vsDb2MiO4Fx2WcLX1MRzYCDrpbYcej2ux8ZEYHj42UIogaq/3962dapRXUBu"
"TRZqVBGcmWECh7TXAbol73d3TUFCy8s8ru6Jd8Eh3Y6QV+0tAqpvbNu7ZG7E"
"Lb1+CIbqVtWu7M2PTqRw0gP09MJBwZ3X18eGAP4JQXp16SB7qHLZ1xcbAsBZ"
"VRUHVfJDgZgSAM4bGvjIITgUOSkpiS0BILy1JfAK4jGDKrL7Ay/A4fgH+CbX"
"ULuRjXIAAAAASUVORK5CYII=";
[Device Classification]
Class1 = EtherNetIP;
[Params]
Param1 =
0, $ first field shall equal 0
7,"20 70 24 01 31 08 03", $ path size,path
0x0000, $ descriptor
0xC6, $ data type
1, $ data size in bytes
"Output1", $ name
"", $ units
"Output Byte 1", $ help string
,,0, $ min, max, default data values
,,,, $ mult, dev, base, offset scaling not used
,,,, $ mult, dev, base, offset link not used
0; $ decimal places not used
Param2 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 09 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output2", $ name
"", $ units
"Output Byte 2", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param3 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 0A 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output3", $ name
"", $ units
"Output Byte 3", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param4 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 0B 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output4", $ name
"", $ units
"Output Byte 4", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param5 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 0C 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output5", $ name
"", $ units
"Output Byte 5", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param6 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output6", $ name
"", $ units
"Parameter 6", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param7 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output7", $ name
"", $ units
"Parameter 7", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param8 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output8", $ name
"", $ units
"Parameter 8", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param9 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output9", $ name
"", $ units
"Parameter 9", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param10 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Output10", $ name
"", $ units
"Parameter 10", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param11 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 00 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input1", $ name
"", $ units
"Input Byte 1", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param12 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 01 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input2", $ name
"", $ units
"Input Byte 2", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param13 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 02 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input3", $ name
"", $ units
"Input Byte 3", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param14 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 03 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input4", $ name
"", $ units
"Input Byte 4", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param15 =
0, $ reserved, shall equal 0
7,"20 70 24 01 31 04 03", $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input5", $ name
"", $ units
"Input Byte 5", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param16 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input6", $ name
"", $ units
"Parameter 16", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param17 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input7", $ name
"", $ units
"Parameter 17", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param18 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input8", $ name
"", $ units
"Parameter 18", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param19 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input9", $ name
"", $ units
"Parameter 19", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param20 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type
1, $ Data Size in bytes
"Input10", $ name
"", $ units
"Parameter 20", $ help string
,,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
; -------- Analog Inputs 0–7 (0x0310–0x0317) --------
Param21 = 0,7,"20 70 24 01 31 10 03", 0x0000, 0xC7, 2, "AI0", "", "Analog Input 0 (0–5V or 4–20mA)", ,,0,,,,,,,;
Param22 = 0,7,"20 70 24 01 31 11 03", 0x0000, 0xC7, 2, "AI1", "", "Analog Input 1", ,,0,,,,,,,;
Param23 = 0,7,"20 70 24 01 31 12 03", 0x0000, 0xC7, 2, "AI2", "", "Analog Input 2", ,,0,,,,,,,;
Param24 = 0,7,"20 70 24 01 31 13 03", 0x0000, 0xC7, 2, "AI3", "", "Analog Input 3", ,,0,,,,,,,;
Param25 = 0,7,"20 70 24 01 31 14 03", 0x0000, 0xC7, 2, "AI4", "", "Analog Input 4", ,,0,,,,,,,;
Param26 = 0,7,"20 70 24 01 31 15 03", 0x0000, 0xC7, 2, "AI5", "", "Analog Input 5", ,,0,,,,,,,;
Param27 = 0,7,"20 70 24 01 31 16 03", 0x0000, 0xC7, 2, "AI6", "", "Analog Input 6", ,,0,,,,,,,;
Param28 = 0,7,"20 70 24 01 31 17 03", 0x0000, 0xC7, 2, "AI7", "", "Analog Input 7", ,,0,,,,,,,;
; -------- Analog Outputs 0–7 (0x0320–0x0327) --------
Param29 = 0,7,"20 70 24 01 32 00 03", 0x0000, 0xC1, 1, "AO0", "", "Analog Output 0 (Scaled)", ,,0,,,,,,,;
Param30 = 0,7,"20 70 24 01 32 01 03", 0x0000, 0xC1, 1, "AO1", "", "Analog Output 1", ,,0,,,,,,,;
Param31 = 0,7,"20 70 24 01 32 02 03", 0x0000, 0xC1, 1, "AO2", "", "Analog Output 2", ,,0,,,,,,,;
Param32 = 0,7,"20 70 24 01 32 03 03", 0x0000, 0xC1, 1, "AO3", "", "Analog Output 3", ,,0,,,,,,,;
Param33 = 0,7,"20 70 24 01 32 04 03", 0x0000, 0xC1, 1, "AO4", "", "Analog Output 4", ,,0,,,,,,,;
Param34 = 0,7,"20 70 24 01 32 05 03", 0x0000, 0xC1, 1, "AO5", "", "Analog Output 5", ,,0,,,,,,,;
Param35 = 0,7,"20 70 24 01 32 06 03", 0x0000, 0xC1, 1, "AO6", "", "Analog Output 6", ,,0,,,,,,,;
Param36 = 0,7,"20 70 24 01 32 07 03", 0x0000, 0xC1, 1, "AO7", "", "Analog Output 7", ,,0,,,,,,,;
; -------- Digital Inputs (0x0330, 0x0331) --------
Param37 = 0,7,"20 70 24 01 33 00 03", 0x0000, 0xC1, 1, "DI0", "", "Digital Input 0", ,,0,,,,,,,;
Param38 = 0,7,"20 70 24 01 33 01 03", 0x0000, 0xC1, 1, "DI1", "", "Digital Input 1", ,,0,,,,,,,;
; -------- Digital Outputs (0x0340, 0x0341) --------
Param39 = 0,7,"20 70 24 01 34 00 03", 0x0000, 0xC1, 1, "DO0", "", "Digital Output 0", ,,0,,,,,,,;
Param40 = 0,7,"20 70 24 01 34 01 03", 0x0000, 0xC1, 1, "DO1", "", "Digital Output 1", ,,0,,,,,,,;
[Assembly]
Object_Name = "Assembly Object";
Object_Class_Code = 0x04;
MaxInst = 6;
Number_Of_Static_Instances = 6;
Max_Number_Of_Dynamic_Instances = 0;
Assem1 =
"Producing Assembly (Input Data)",
,
5,
0x0001,
,,
8,Param11,
8,Param12,
8,Param13,
8,Param14,
8,Param15;
Assem2 =
"Consuming Assembly (Output Data)",
,
5,
0x0001,
,,
8,Param1,
8,Param2,
8,Param3,
8,Param4,
8,Param5;
Assem3 =
"Analog Inputs 8AI",
,
5,
0x0001,
,,
8,Param21,
8,Param22,
8,Param23,
8,Param24,
8,Param25,
8,Param26,
8,Param27,
8,Param28;
Assem4 =
"Analog Outputs 8AO",
,
5,
0x0001,
,,
8,Param29,
8,Param30,
8,Param31,
8,Param32,
8,Param33,
8,Param34,
8,Param35,
8,Param36;
Assem5 =
"Digital Inputs 2DI",
,
1,
0x0065,
,,
1,Param37,
1,Param38;
Assem6 =
"Digital Outputs 2DO",
,
1,
0x0064,
,,
1,Param39,
1,Param40;
[Connection Manager]
Object_Name = "Connection Manager Object";
Object_Class_Code = 0x06;
Connection1 =
0x04010002, $ trigger & transport
$ 0-15 = supported transport classes (class 1)
$ 16 = cyclic (1 = supported)
$ 17 = change of state (0 = not supported)
$ 18 = on demand (0 = not supported)
$ 19-23 = reserved (must be zero)
$ 24-27 = exclusive owner
$ 28-30 = reserved (must be zero)
$ 31 = client 0 (don't care for classes 0 and 1)
0x44640005, $ point/multicast & priority & realtime format
$ 0 = O=>T fixed (1 = supported)
$ 1 = O=>T variable (0 = not supported)
$ 2 = T=>O fixed (1 = supported)
$ 3 = T=>O variable (0 = not supported)
$ 4-7 = reserved (must be zero)
$ 8-10 = O=>T header (4 byte run/idle)
$ 11 = reserved (must be zero)
$ 12-14 = T=>O header
$ 15 = reserved (must be zero)
$ 16-19 = O=>T point-to-point
$ 20-23 = T=>O multicast
$ 24-27 = O=>T scheduled
$ 28-31 = T=>O scheduled
,,Assem2, $ O=>T RPI,Size,Format
,,Assem1, $ T=>O RPI,Size,Format
,, $ config part 1 (dynamic assemblies)
,, $ config part 2 (module configuration)
"Exclusive Owner", $ connection name
"", $ Help string
"20 04 24 01 2C 65 2C 64"; $ exclusive owner path
Connection2 =
0x02010002, $ trigger & transport
$ 0-15 = supported transport classes (class 1)
$ 16 = cyclic (1 = supported)
$ 17 = change of state (0 = not supported)
$ 18 = on demand (0 = not supported)
$ 19-23 = reserved (must be zero)
$ 24-27 = exclusive owner
$ 28-30 = reserved (must be zero)
$ 31 = client 0 (don't care for classes 0 and 1)
0x44640305, $ point/multicast & priority & realtime format
$ 0 = O=>T fixed (1 = supported)
$ 1 = O=>T variable (0 = not supported)
$ 2 = T=>O fixed (1 = supported)
$ 3 = T=>O variable (0 = not supported)
$ 4-7 = reserved (must be zero)
$ 8-10 = O=>T header (4 byte run/idle)
$ 11 = reserved (must be zero)
$ 12-14 = T=>O header
$ 15 = reserved (must be zero)
$ 16-19 = O=>T point-to-point
$ 20-23 = T=>O multicast
$ 24-27 = O=>T scheduled
$ 28-31 = T=>O scheduled
,0,, $ O=>T RPI,Size,Format
,,Assem1, $ T=>O RPI,Size,Format
,, $ config part 1 (dynamic assemblies)
,, $ config part 2 (module configuration)
"Input Only", $ connection name
"", $ Help string
"20 04 24 01 2C FE 2C 64"; $ input only path
Connection3 =
0x01010002, $ trigger & transport
$ 0-15 = supported transport classes (class 1)
$ 16 = cyclic (1 = supported)
$ 17 = change of state (0 = not supported)
$ 18 = on demand (0 = not supported)
$ 19-23 = reserved (must be zero)
$ 24-27 = exclusive owner
$ 28-30 = reserved (must be zero)
$ 31 = client 0 (don't care for classes 0 and 1)
0x44640305, $ point/multicast & priority & realtime format
$ 0 = O=>T fixed (1 = supported)
$ 1 = O=>T variable (0 = not supported)
$ 2 = T=>O fixed (1 = supported)
$ 3 = T=>O variable (0 = not supported)
$ 4-7 = reserved (must be zero)
$ 8-10 = O=>T header (4 byte run/idle)
$ 11 = reserved (must be zero)
$ 12-14 = T=>O header
$ 15 = reserved (must be zero)
$ 16-19 = O=>T point-to-point
$ 20-23 = T=>O multicast
$ 24-27 = O=>T scheduled
$ 28-31 = T=>O scheduled
,0,, $ O=>T RPI,Size,Format
,,Assem1, $ T=>O RPI,Size,Format
,, $ config part 1 (dynamic assemblies)
,, $ config part 2 (module configuration)
"Listen Only", $ connection name
"", $ Help string
"20 04 24 01 2C FF 2C 64"; $ listen only path
Connection4 =
0x04010002,
0x44640005,
,,Assem3, ; T=>O: Analog Inputs (AI0–AI7)
,,
,,
"AI Group",
"",
"20 04 24 03 2C C3 2C C3";
Connection5 =
0x04010002,
0x44640005,
,,Assem4, ; O=>T: Analog Outputs (AO0–AO7)
,,
,,
"Analog Outputs (SPI)",
"",
"20 04 24 04 2C C4 2C C4";
Connection6 =
0x04010002,
0x44640005,
,,Assem5, ; T=>O: Digital Inputs (DI0–DI1)
,,
,,
"Digital Inputs",
"",
"20 04 24 05 2C C5 2C C5";
Connection7 =
0x04010002,
0x44640005,
,,Assem6, ; O=>T: Digital Outputs (DO0–DO1)
,,
,,
"Digital Outputs",
"",
"20 04 24 06 2C C6 2C C6";
[Capacity]
MaxCIPConnections = 12;
MaxConsumersPerMcast = 3;
TSpec1 = TxRx, 5, 500;
[DLR Class]
Revision = 3;
Object_Name = "Device Level Ring Object";
Object_Class_Code = 0x47;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
Ring_Supervisor_Capable = No;
[TCP/IP Interface Class]
Revision = 4;
Object_Name = "TCP/IP Interface Object";
Object_Class_Code = 0xF5;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
ENetQCT1 =
$ Numbers are preliminary estimates only:
4000, $ Ready for Connection Time
500; $ Accumulated CIP Connection Time
[Ethernet Link Class]
Revision = 4;
Object_Name = "Ethernet Link Object";
Object_Class_Code = 0xF6;
MaxInst = 2;
Number_Of_Static_Instances = 2;
Max_Number_Of_Dynamic_Instances = 0;
InterfaceLabel1 = "Port 1";
InterfaceLabel2 = "Port 2";
[Time Sync Class]
Revision = 4;
Object_Name = "Time Sync Object";
Object_Class_Code = 0x43;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
[QoS Class]
Revision = 1;
Object_Name = "QoS Object";
Object_Class_Code = 0x48;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
[LLDP Management Class]
Revision = 1;
Object_Name = "LLDP Management Object";
Object_Class_Code = 0x109;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
[LLDP Data Table Class]
Revision = 1;
Object_Name = "LLDP Data Table Object";
Object_Class_Code = 0x10A;
MaxInst = 16;
Number_Of_Static_Instances = 0;
Max_Number_Of_Dynamic_Instances = 16;
APPIO.C
#include "appIO.h"
#include <drivers/gpio.h>
#include <drivers/hw_include/hw_types.h> // For HW_WR_REG32
#include <kernel/dpl/DebugP.h>
#include "ti_drivers_config.h" // For CONFIG_GPIO_* macros
// EtherNet/IP Input Assembly (bit-packed digital inputs)
static uint8_t g_input_assembly_101[1] = {0}; // 2 DI bits packed into 1 byte
// EtherNet/IP Output Assembly (bit-packed digital outputs)
static uint8_t g_output_assembly_100[1] = {0}; // 2 DO bits packed into 1 byte
void EI_APP_IO_init(void)
{
DebugP_log("EI_APP_IO_init: Configuring 2 Digital Inputs and 2 Digital Outputs\n");
// INPUTS configured in SysConfig (set as GPIO_IN with pull-up/down as needed)
GPIO_setDirMode(CONFIG_GPIO_INPUT0_BASE_ADDR, CONFIG_GPIO_INPUT0_PIN, GPIO_DIRECTION_INPUT);
GPIO_setDirMode(CONFIG_GPIO_INPUT1_BASE_ADDR, CONFIG_GPIO_INPUT1_PIN, GPIO_DIRECTION_INPUT);
// OUTPUTS configured in SysConfig (set as GPIO_OUT)
GPIO_setDirMode(CONFIG_GPIO_OUTPUT0_BASE_ADDR, CONFIG_GPIO_OUTPUT0_PIN, GPIO_DIRECTION_OUTPUT);
GPIO_setDirMode(CONFIG_GPIO_OUTPUT1_BASE_ADDR, CONFIG_GPIO_OUTPUT1_PIN, GPIO_DIRECTION_OUTPUT);
// Optional: set initial output states
GPIO_pinWriteHigh(CONFIG_GPIO_OUTPUT0_BASE_ADDR, CONFIG_GPIO_OUTPUT0_PIN);
GPIO_pinWriteLow(CONFIG_GPIO_OUTPUT1_BASE_ADDR, CONFIG_GPIO_OUTPUT1_PIN);
}
void EI_APP_IO_cyclic(void)
{
/* === Read 2 Digital Inputs === */
uint8_t di0 = GPIO_pinRead(CONFIG_GPIO_INPUT0_BASE_ADDR, CONFIG_GPIO_INPUT0_PIN) & 0x01;
uint8_t di1 = GPIO_pinRead(CONFIG_GPIO_INPUT1_BASE_ADDR, CONFIG_GPIO_INPUT1_PIN) & 0x01;
g_input_assembly_101[0] = (di1 << 1) | di0; // Bit 1 = DI1, Bit 0 = DI0
/* === Apply 2 Digital Outputs === */
/* uint8_t do_bits = g_output_assembly_100[0];
if (do_bits & (1 << 0)) {
GPIO_pinWriteHigh(CONFIG_GPIO_OUTPUT0_BASE_ADDR, CONFIG_GPIO_OUTPUT0_PIN);
} else {
GPIO_pinWriteLow(CONFIG_GPIO_OUTPUT0_BASE_ADDR, CONFIG_GPIO_OUTPUT0_PIN);
}
if (do_bits & (1 << 1)) {
GPIO_pinWriteHigh(CONFIG_GPIO_OUTPUT1_BASE_ADDR, CONFIG_GPIO_OUTPUT1_PIN);
} else {
GPIO_pinWriteLow(CONFIG_GPIO_OUTPUT1_BASE_ADDR, CONFIG_GPIO_OUTPUT1_PIN);
}
*/
// --- Apply 2 Digital Outputs ---
uint8_t do0 = g_output_assembly_100[0] & 0x01;
uint8_t do1 = (g_output_assembly_100[0] >> 1) & 0x01;
if (do0)
GPIO_pinWriteHigh(CONFIG_GPIO_OUTPUT0_BASE_ADDR, CONFIG_GPIO_OUTPUT0_PIN);
else
GPIO_pinWriteLow(CONFIG_GPIO_OUTPUT0_BASE_ADDR, CONFIG_GPIO_OUTPUT0_PIN);
if (do1)
GPIO_pinWriteHigh(CONFIG_GPIO_OUTPUT1_BASE_ADDR, CONFIG_GPIO_OUTPUT1_PIN);
else
GPIO_pinWriteLow(CONFIG_GPIO_OUTPUT1_BASE_ADDR, CONFIG_GPIO_OUTPUT1_PIN);
// Debug log AFTER values are computed
DebugP_log("DI: %d %d, DO: %d %d\n", di0, di1, do0, do1);
}
uint8_t *EI_APP_IO_getInputAssembly(void)
{
return g_input_assembly_101;
}
uint8_t *EI_APP_IO_getOutputAssembly(void)
{
return g_output_assembly_100;
}
APPIO.H
#ifndef APP_IO_H_
#define APP_IO_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void EI_APP_IO_init(void);
void EI_APP_IO_cyclic(void);
uint8_t *EI_APP_IO_getInputAssembly(void); // Assembly 101
uint8_t *EI_APP_IO_getOutputAssembly(void); // Assembly 100
// add new *** begin
#define EI_CLASS_ID_DIGITAL_IO 0xC5
#define EI_INSTANCE_ID_DIGITAL_IO 0x01
//extern uint8_t attr_inputBits; // Mirror of input bit from hardware
//extern uint8_t attr_outputBits; // Mirror of output bit from PLC
// add new *** end
#ifdef __cplusplus
}
#endif
#endif /* APP_IO_H_ */
APP_GENRIC_DEVICE
/*!
* \file app_generic_device.c
*
* \brief
* Generic device profile declarations.
*
* \author
* Texas Instruments Incorporated
*
* \copyright
* Copyright (C) 2023 Texas Instruments Incorporated
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if (!(defined FBTLPROVIDER) || (0 == FBTLPROVIDER)) && (!(defined FBTL_REMOTE) || (0 == FBTL_REMOTE))
#include "EI_API_def.h"
#include "EI_API.h"
//#1a new IO
#include "appIO.h"
//#1a end IO
#include "osal.h"
#include "osal_error.h"
//#2a new IO
#include "EI_API_CIP.h"
//#2a end IO
#include "drivers/CUST_drivers.h"
#include "appLed.h"
#include "appNV.h"
#include "appCfg.h"
#include <device_profiles/app_device_profile.h>
#include <device_profiles/app_device_profile_intern.h>
#include <device_profiles/generic_device/app_generic_device_cfg.h>
#include <device_profiles/generic_device/app_generic_device.h>
static uint16_t EI_APP_GENERIC_DEVICE_extendedStatus_s[255] = {0};
static bool EI_APP_GENERIC_DEVICE_init (EI_API_ADP_T *pAdapter, EI_API_CIP_NODE_T *pCipNode);
static void EI_APP_GENERIC_DEVICE_run (EI_API_CIP_NODE_T *pCipNode);
static bool EI_APP_GENERIC_DEVICE_cipSetup (EI_API_CIP_NODE_T *pCipNode);
static void EI_APP_GENERIC_DEVICE_cipGenerateContent (EI_API_CIP_NODE_T *pCipNode, uint16_t classId, uint16_t instanceId);
static void EI_APP_DIGITAL_IO_cipGenerateContent(EI_API_CIP_NODE_T* cipNode);
/*!
* <!-- Description: -->
*
* \brief
* Callback function for ForwardOpen, LargeForwardOpen and ForwardClose.
*
* \details
* Callback function which is called when a request for the services
* ForwardOpen, LargeForwardOpen and ForwardClose was received.
*
*/
EI_API_ADP_SEipStatus_t EI_APP_GENERIC_DEVICE_cmgrCb(uint32_t serviceCode, EI_API_ADP_UCmgrInfo_u cmgrInfo)
{
EI_API_ADP_SEipStatus_t ret_val= {.gen_status=0,
.extended_status_size=0,
.extended_status_arr=EI_APP_GENERIC_DEVICE_extendedStatus_s};
switch(serviceCode)
{
case 0x54:
// OSAL_printf("Forward open Connection Serial Number: 0x%04x\r\n", cmgrInfo.forwardOpenInfo.conSerialNum);
break;
case 0x5b:
// OSAL_printf("Large forward open Connection Serial Number: 0x%04x\r\n", cmgrInfo.forwardOpenInfo.conSerialNum);
break;
case 0x4e:
// OSAL_printf("Forward close Connection Serial Number: 0x%04x\r\n", cmgrInfo.forwardCloseInfo.conSerialNum);
break;
default:
OSAL_printf("unknown service code %x\r\n", serviceCode);
}
return ret_val;
}
/*!
* \brief
* Registers generic device profile interface functions.
*
* \details
* Called by #EI_APP_DEVICE_PROFILE_init function of device profile interface.
* Function needs to be defined in each profile.
*
* \remark
* In time of build process only one device profile can be active.
* Rest profiles need to be excluded from the build.
*
* \param[in] pIntf Pointer to device profile interface which needs to be initialized.
*
* \return value as bool.
* \retval true Success.
* \retval false Invalid input parameter defined as NULL.
*
* \par Example
* \code{.c}
* #include "device_profiles/generic_device/app_generic_device_cfg.h"
*
* uint32_t EI_APP_DEVICE_PROFILE_init (void)
* {
* return EI_APP_DEVICE_PROFILE_register(&EI_APP_DEVICE_PROFILE_intf_s);
* }
* \endcode
*
* \see EI_APP_DEVICE_PROFILE_register EI_APP_DEVICE_PROFILE_CFG_init
*
* \ingroup EI_APP_DEVICE_PROFILE_CFG
*
*/
uint32_t EI_APP_DEVICE_PROFILE_register (EI_APP_DEVICE_PROFILE_Interface_t *pIntf)
{
uint32_t error = EI_APP_DEVICE_PROFILE_ERR_General;
if (NULL == pIntf)
{
error = EI_APP_DEVICE_PROFILE_ERR_PtrInvalid;
goto laError;
}
pIntf->task.init = EI_APP_GENERIC_DEVICE_init;
pIntf->task.run = EI_APP_GENERIC_DEVICE_run;
pIntf->cfg.init = EI_APP_GENERIC_DEVICE_CFG_init;
pIntf->cfg.isValid = EI_APP_GENERIC_DEVICE_CFG_isValid;
pIntf->cfg.setHeader = EI_APP_GENERIC_DEVICE_CFG_setHeader;
pIntf->cfg.apply = EI_APP_GENERIC_DEVICE_CFG_apply;
pIntf->cfg.setDefaultWithoutComm = EI_APP_GENERIC_DEVICE_CFG_setDefaultWithoutComm;
pIntf->cfg.callback = EI_APP_GENERIC_DEVICE_CFG_callback;
pIntf->cfg.getRuntimeData = EI_APP_GENERIC_DEVICE_CFG_getRuntimeData;
pIntf->cfg.getFactoryResetData = EI_APP_GENERIC_DEVICE_CFG_getFactoryResetData;
pIntf->cfg.getLength = EI_APP_GENERIC_DEVICE_CFG_getLength;
error = EI_APP_DEVICE_PROFILE_ERR_OK;
laError:
return error;
}
/*!
* <!-- Description: -->
*
* \brief
* Basic initialization function.
*
* \details
* Creates a new EtherNet/IP™ Adapter.<br>
* Initializes data structures from non-volatile storage.<br>
* Registers stack error handler.<br>
* Initializes the Adapter.<br>
* Create a CIP™ node.<br>
*
*/
//#3a begin *****
static uint8_t *pInput = NULL;
static uint8_t *pOutput = NULL;
static uint8_t attr_inputBits = 0;
static uint8_t attr_outputBits = 0;
void EI_APP_GENERIC_DEVICE_initPointers(void)
{
pInput = EI_APP_IO_getInputAssembly();
pOutput = EI_APP_IO_getOutputAssembly();
}
//#3a end ******
bool EI_APP_GENERIC_DEVICE_init(EI_API_ADP_T* pAdapter, EI_API_CIP_NODE_T *pCipNode)
{
bool result = false;
#if (defined BRIDGING_AND_ROUTING) && (BRIDGING_AND_ROUTING==1)
// Enable Bridging and Routing feature
EI_API_ADP_setBridgingAndRoutingSupported(pAdapter);
#endif
// Create vendor specific classes.
result = EI_APP_GENERIC_DEVICE_cipSetup(pCipNode);
//##4a BEGIN
// ... existing initialization code ...
// --- add new *** begin: init pointers and sync attributes ---
EI_APP_GENERIC_DEVICE_initPointers(); // Set pInput and pOutput pointers
attr_inputBits = pInput[0]; // Sync DI to variable
attr_outputBits = pOutput[0]; // Sync DO to variable
// --- add new *** end ---
//##4a END
return result;
}
/*!
* <!-- Description: -->
*
* \brief
* Cyclically called run function.
*
* \details
* Cyclically called run function, handles the EtherNet/IP stack and hardware
* specific functionality, such as reading switches, reading inputs, setting outputs
* and LEDs.
*
*/
void EI_APP_GENERIC_DEVICE_run(EI_API_CIP_NODE_T* pCipNode)
{
uint32_t errCode = EI_API_CIP_eERR_OK;
uint8_t attrValue = 0;
uint16_t attr;
// Mirror I/O data
for(attr = 0; attr < 5; attr++)
{
errCode = EI_API_CIP_getAttr_usint(pCipNode, 0x0070, 0x0001, attr + 0x0308, &attrValue);
if (attr == 0 && errCode == EI_API_CIP_eERR_OK)
{
EI_APP_LED_industrialSet(attrValue);
}
EI_API_CIP_setAttr_usint(pCipNode, 0x0070, 0x0001, attr + 0x0300, attrValue);
}
//##5a BEGIN APPIO.C --- add new *** begin: Digital IO CIP sync ---
extern uint8_t attr_inputBits;
extern uint8_t attr_outputBits;
uint8_t *pInputAssembly = EI_APP_IO_getInputAssembly(); // Hardware → CIP
uint8_t *pOutputAssembly = EI_APP_IO_getOutputAssembly(); // CIP → Hardware
// Sync actual input from hardware to CIP input attribute
attr_inputBits = pInputAssembly[0];
// Output attribute (set by PLC and mirrored earlier) gets sent to hardware
pOutputAssembly[0] = attr_outputBits;
//##5a END APPIO.C --- add new *** end ---
// Optional future expansion:
// EI_APP_CLASS71_run();
}
/*!
* <!-- Description: -->
*
* \brief
* Setup the application with classes, instances, attributes, and assemblies.
*
* \details
* Setup the application with classes, instances, attributes, and assemblies.<br>
* For the assemblies, use instances in the Vendor Specific range of IDs.
*
*/
static bool EI_APP_GENERIC_DEVICE_cipSetup(EI_API_CIP_NODE_T* pCipNode)
{
uint32_t errCode = 0;
uint16_t i = 0;
// 1. Create your base class and instance (0x70 / 0x01)
uint16_t classId = 0x70;
uint16_t instanceId = 0x01;
// 2. Register the GENERIC DEVICE class/instance attributes and services
EI_APP_GENERIC_DEVICE_cipGenerateContent(pCipNode, classId, instanceId);
//#6a add new APPIO.c
EI_APP_GENERIC_DEVICE_initPointers(); // Make sure attr_inputBits/outputBits are set first
// 3. Create Assembly instances for Output (0x64) and Input (0x65)
EI_API_CIP_createAssembly(pCipNode, 0x64, EI_API_CIP_eAR_GET_AND_SET);
EI_API_CIP_createAssembly(pCipNode, 0x65, EI_API_CIP_eAR_GET_AND_SET);
// 4. Optionally register DIGITAL IO and ANALOG IO class/instances
EI_APP_DIGITAL_IO_cipGenerateContent(pCipNode);
// EI_APP_ANALOG_IO_cipGenerateContent(pCipNode);
// Add attr_outputBits (0x0340) to Output Assembly 0x64
errCode = EI_API_CIP_addAssemblyMember(pCipNode, 0x64, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, 0x02);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add Digital Output Attribute to Assembly 0x64: 0x%08x\n", errCode);
}
// Add attr_inputBits (0x0330) to Input Assembly 0x65
errCode = EI_API_CIP_addAssemblyMember(pCipNode, 0x65, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, 0x01);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add Digital Input Attribute to Assembly 0x65: 0x%08x\n", errCode);
}
//#6a end APPIO.c
#if (defined BRIDGING_AND_ROUTING) && (BRIDGING_AND_ROUTING==1)
EI_APP_GENERIC_DEVICE_cipRoutingSampleSetup(pCipNode);
EI_APP_GENERIC_DEVICE_cipUnRoutingSampleSetup(pCipNode);
#endif
errCode = EI_API_CIP_createAssembly(pCipNode, 0xfe, EI_API_CIP_eAR_GET); // Input-only.
errCode = EI_API_CIP_createAssembly(pCipNode, 0xff, EI_API_CIP_eAR_GET); // Listen-only.
//##1b romoved by Thien called on
// errCode = EI_API_CIP_createAssembly(pCipNode, 0x64, EI_API_CIP_eAR_GET_AND_SET);
// errCode = EI_API_CIP_createAssembly(pCipNode, 0x65, EI_API_CIP_eAR_GET_AND_SET);
//##1b removed end
for (i = 0x300; i < 0x305; i++)
{
errCode = EI_API_CIP_addAssemblyMember(pCipNode, 0x64, classId, instanceId, i);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add Class ID %#x, Instance ID %#x, Attribute ID %#x to Assembly Instance 0x64: Error code: 0x%08x\n", classId, instanceId, (uint16_t)i, errCode);
}
errCode = EI_API_CIP_addAssemblyMember(pCipNode, 0x65, classId, instanceId, (uint16_t)(8 + i));
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to add Class ID %#x, Instance ID %#x, Attribute ID %#x to Assembly Instance 0x65: Error code: 0x%08x\n", classId, instanceId, (uint16_t)(8 + i), errCode);
}
}
return true;
}
/*!
* <!-- Description: -->
*
* \brief
* Generates attributes and services for a CIP™class.
*
* \details
* Create a CIP class with a Class IDs using the value specified in parameter classId.<br>
* Generates attributes and services for that class.<br>
* Adds read and write services.<br>
* Adds 64 8-bit attributes with callback function.<br>
* Adds 32 16-bit attributes.<br>
* Adds 16 32-bit attributes.<br>
* Adds 8 64-bit attributes.
*
*/
static void EI_APP_GENERIC_DEVICE_cipGenerateContent(EI_API_CIP_NODE_T* cipNode, uint16_t classId, uint16_t instanceId)
{
EI_API_CIP_SService_t service;
uint64_t i = 0;
EI_API_CIP_createClass(cipNode, classId);
service.getAttrAllResponseCnt = 0;
service.callback = NULL;
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
EI_API_CIP_addClassService(cipNode, classId, &service);
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
EI_API_CIP_addClassService(cipNode, classId, &service);
EI_API_CIP_createInstance(cipNode, classId, instanceId);
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
EI_API_CIP_addInstanceService(cipNode, classId, instanceId, &service);
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
EI_API_CIP_addInstanceService(cipNode, classId, instanceId, &service);
uint16_t attribID = 0x300;
// 64 USINT (uint8_t).
for (i = 0; i < 64; i++)
{
EI_API_CIP_SAttr_t attr;
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_USINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addInstanceAttr(cipNode, classId, instanceId, &attr);
EI_API_CIP_setInstanceAttr(cipNode, classId, instanceId, &attr);
attribID++;
}
// 32 UINT (uint16_t).
for (i = 0; i < 32; i++)
{
EI_API_CIP_SAttr_t attr;
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_UINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addInstanceAttr(cipNode, classId, instanceId, &attr);
EI_API_CIP_setInstanceAttr(cipNode, classId, instanceId, &attr);
attribID++;
}
// 16 UDINT (uint32_t).
for (i = 0; i < 16; i++)
{
EI_API_CIP_SAttr_t attr;
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_UDINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addInstanceAttr(cipNode, classId, instanceId, &attr);
EI_API_CIP_setInstanceAttr(cipNode, classId, instanceId, &attr);
attribID++;
}
// 8 ULINT (uint64_t).
for (i = 0; i < 8; i++)
{
EI_API_CIP_SAttr_t attr;
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_ULINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addInstanceAttr(cipNode, classId, instanceId, &attr);
EI_API_CIP_setInstanceAttr(cipNode, classId, instanceId, &attr);
attribID++;
}
}
//#7a ADD BEGIN APPIO.C CLASS ********
//#define EI_CLASS_ID_DIGITAL_IO 0x0066
//#define EI_INSTANCE_ID_DIGITAL_IO 0x0001
// Declare global digital I/O variables
bool di0 = false;
bool di1 = false;
bool do0 = false;
bool do1 = false;
static void EI_APP_DIGITAL_IO_cipGenerateContent(EI_API_CIP_NODE_T* cipNode)
{
EI_API_CIP_SService_t service;
EI_API_CIP_SAttr_t attr;
// 1. Create Class 0x66
EI_API_CIP_createClass(cipNode, EI_CLASS_ID_DIGITAL_IO);
// 2. Add Class Services
service.getAttrAllResponseCnt = 0;
service.callback = NULL;
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
EI_API_CIP_addClassService(cipNode, EI_CLASS_ID_DIGITAL_IO, &service);
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
EI_API_CIP_addClassService(cipNode, EI_CLASS_ID_DIGITAL_IO, &service);
// 3. Create Instance
EI_API_CIP_createInstance(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO);
// 4. Add Instance Services
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
EI_API_CIP_addInstanceService(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, &service);
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
EI_API_CIP_addInstanceService(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, &service);
// 5. Attribute 0x0330 → DI0 (Read-only)
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = 0x0330;
attr.edt = EI_API_CIP_eEDT_BOOL;
attr.accessRule = EI_API_CIP_eAR_GET;
attr.pvValue = &di0;
EI_API_CIP_addInstanceAttr(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, &attr);
// 6. Attribute 0x0331 → DI1 (Read-only)
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = 0x0331;
attr.edt = EI_API_CIP_eEDT_BOOL;
attr.accessRule = EI_API_CIP_eAR_GET;
attr.pvValue = &di1;
EI_API_CIP_addInstanceAttr(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, &attr);
// 7. Attribute 0x0340 → DO0 (Read/Write)
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = 0x0340;
attr.edt = EI_API_CIP_eEDT_BOOL;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &do0;
EI_API_CIP_addInstanceAttr(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, &attr);
// 8. Attribute 0x0341 → DO1 (Read/Write)
OSAL_MEMORY_memset(&attr, 0, sizeof(attr));
attr.id = 0x0341;
attr.edt = EI_API_CIP_eEDT_BOOL;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &do1;
EI_API_CIP_addInstanceAttr(cipNode, EI_CLASS_ID_DIGITAL_IO, EI_INSTANCE_ID_DIGITAL_IO, &attr);
}
//##7a ADD END APPIO.C CLASS **************
#if (defined BRIDGING_AND_ROUTING) && (BRIDGING_AND_ROUTING==1)
/*!
* <!-- Description: -->
*
* \brief
* Callback function is triggered when get_attribute_service request is received during explicit messaging.
* This function must be shown to the attribute get_callback during setup.
*
* \details
*
*
*/
uint32_t EI_APP_GENERIC_DEVICE_CLASS70_GetAttr2Inst1_Link1_cb (EI_API_CIP_NODE_T *pCipNode,
uint16_t classId,
uint16_t instanceId,
uint16_t attrId,
uint16_t *pLen,
void *pvValue,
uint16_t linkAddress)
{
/*USINT val*/
*pLen = sizeof(uint8_t);
//value to be returned as get attr response
*(uint8_t*)pvValue = 13;
return EI_API_eERR_CB_NO_ERROR;
}
/*!
* <!-- Description: -->
*
* \brief
* Callback function is triggered when set_attribute_service request is received during explicit messaging.
* This function must be shown to the attribute set_callback during setup.
*
* \details
*
*
*/
uint32_t EI_APP_GENERIC_DEVICE_CLASS70_SetAttr2Inst1_Link1_cb (EI_API_CIP_NODE_T *pCipNode,
uint16_t classId,
uint16_t instanceId,
uint16_t attrId,
uint16_t len,
void *pvValue,
uint16_t linkAddress)
{
uint8_t data=*((uint8_t*)pvValue);
OSALUNREF_PARM(data);
return EI_API_eERR_CB_NO_ERROR;
}
/*!
* <!-- Description: -->
*
* \brief
* Callback function is triggered when get_attribute_service request is received during explicit messaging.
* This function must be shown to the attribute get_callback during setup.
*
* \details
*
*
*/
uint32_t EI_APP_GENERIC_DEVICE_CLASS70_GetAttr2Inst1_cb (EI_API_CIP_NODE_T *pCipNode,
uint16_t classId,
uint16_t instanceId,
uint16_t attrId,
uint16_t *pLen,
void *pvValue)
{
/*USINT val*/
*pLen = sizeof(uint8_t);
//value to be returned as get attr response
*(uint8_t*)pvValue = 13;
return EI_API_eERR_CB_NO_ERROR;
}
/*!
* <!-- Description: -->
*
* \brief
* Callback function is triggered when set_attribute_service request is received during explicit messaging.
* This function must be shown to the attribute set_callback during setup.
*
* \details
*
*
*/
uint32_t EI_APP_GENERIC_DEVICE_CLASS70_SetAttr2Inst1_cb (EI_API_CIP_NODE_T *pCipNode,
uint16_t classId,
uint16_t instanceId,
uint16_t attrId,
uint16_t len,
void *pvValue)
{
uint8_t data=*((uint8_t*)pvValue);
OSALUNREF_PARM(data);
return EI_API_eERR_CB_NO_ERROR;
}
/*!
* <!-- Description: -->
*
* \brief
* In order to observe configurationAssemblies data , EI_APP_CFGASSEM_cb was created.
*
* \details
*
*
*/
uint32_t EI_APP_GENERIC_DEVICE_CFGASSEM_cb (EI_API_CIP_NODE_T *pCipNode,
uint16_t o2t,
uint16_t t2o,
uint16_t cfg_inst,
const uint8_t* const pCfgData,
uint16_t cfgDataSize,
uint16_t linkaddr)
{
return EI_API_eERR_CB_NO_ERROR;
}
/*!
* <!-- Description: -->
*
* \brief
* Call EI_APP_cipGenerateContentCipRouting function in order to create Assembly and use routable functionality.
*
* \details
* A routableInstance has been created by cipGenerateContent. Assemblies attributes are setting in this function.
*/
void EI_APP_GENERIC_DEVICE_cipGenerateContentCipRouting (EI_API_CIP_NODE_T *pCipNode,
uint16_t classId,
uint16_t instanceId,
uint8_t linkAddr)
{
EI_API_CIP_SService_t service;
uint16_t i = 0;
uint16_t attribID = 0x300;
uint32_t errCode = 0;
errCode = EI_API_CIP_createRoutableInstance(pCipNode, classId, instanceId, linkAddr);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to create routable instance\n");
}
service.getAttrAllResponseCnt = 0;
service.callback = NULL;
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
errCode = EI_API_CIP_addRoutableInstanceService(pCipNode, classId, instanceId, &service, linkAddr);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add routable instance service\n");
}
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
errCode = EI_API_CIP_addRoutableInstanceService(pCipNode, classId, instanceId, &service, linkAddr);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add routable instance service\n");
}
// 64 USINT (uint8_t).
for (i = 0; i < 64; i++)
{
EI_API_CIP_SAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_USINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
errCode = EI_API_CIP_addRoutableInstanceAttr(pCipNode, classId, instanceId, &attr, linkAddr);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add routable instance service\n");
}
// errCode = EI_API_CIP_setRoutableInstanceAttrFunc(pCipNode, classId, instanceId, &attr, linkAddr);
//
// if (errCode != EI_API_CIP_eERR_OK)
// {
// OSAL_printf("Failed to set routable instance service\n");
// }
attribID++;
}
// 32 UINT (uint16_t).
for (i = 0; i < 32; i++)
{
EI_API_CIP_SAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_UINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addRoutableInstanceAttr(pCipNode, classId, instanceId, &attr, linkAddr);
// EI_API_CIP_setRoutableInstanceAttrFunc(cipNode_s, classId, instanceId, &attr, linkAddr);
attribID++;
}
// 16 UDINT (uint32_t).
for (i = 0; i < 16; i++)
{
EI_API_CIP_SAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_UDINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addRoutableInstanceAttr(pCipNode, classId, instanceId, &attr, linkAddr);
// EI_API_CIP_setRoutableInstanceAttrFunc(cipNode_s, classId, instanceId, &attr, linkAddr);
attribID++;
}
// 8 ULINT (uint64_t).
for (i = 0; i < 8; i++)
{
EI_API_CIP_SAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.id = attribID;
attr.edt = EI_API_CIP_eEDT_ULINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.pvValue = &i;
EI_API_CIP_addRoutableInstanceAttr(pCipNode, classId, instanceId, &attr, linkAddr);
// EI_API_CIP_setRoutableInstanceAttrFunc(cipNode_s, classId, instanceId, &attr, linkAddr);
attribID++;
}
}
/*!
* <!-- Description: -->
*
* \brief
* Initialize the application with instance's, attribute's, service's to be able provide unrouting functionality.
* This example shows how to set explicit messaging us.
*
* \details
* In the SampleSetup application with instances,attributes callback.
* In EI_APP_cipUnRoutingSampleSetup, we must first create an Instance and the Instance services we need.
* If you need to Class Instace, You should call EI_API_CIP_addClassAttr() and EI_API_CIP_setClassAttrFunc() as well.
*/
static bool EI_APP_GENERIC_DEVICE_cipUnRoutingSampleSetup (EI_API_CIP_NODE_T *pCipNode)
{
uint32_t errCode = 0;
uint16_t classId = 0x70;
uint16_t instanceId = 6;
EI_API_CIP_SAttr_t attr = {0};
const uint16_t attr2_val = 2;
EI_API_CIP_SService_t service = {0};
/*creating routable instance 1 which is connected to link addr 1 in the 0x70 class*/
errCode = EI_API_CIP_createInstance(pCipNode, classId, instanceId);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to create Routable Instance\n");
}
// set class instance
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
errCode = EI_API_CIP_addInstanceService(pCipNode, classId, instanceId, &service);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to create Routable Instance\n");
}
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
errCode = EI_API_CIP_addInstanceService(pCipNode, classId, instanceId, &service);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to create Routable Instance\n");
}
attr.id = 2;
attr.edt = EI_API_CIP_eEDT_USINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.get_callback = EI_APP_GENERIC_DEVICE_CLASS70_GetAttr2Inst1_cb;
attr.set_callback = EI_APP_GENERIC_DEVICE_CLASS70_SetAttr2Inst1_cb;
attr.pvValue = (void *)&attr2_val;
errCode = EI_API_CIP_addInstanceAttr(pCipNode, classId, instanceId, &attr);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to add Routable Instance Attr\n");
}
errCode = EI_API_CIP_setInstanceAttrFunc(pCipNode, classId, instanceId, &attr);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to set Routable Instance attr func\n");
}
//Adding class attribute and function
EI_API_CIP_addClassAttr (pCipNode, classId, &attr);
EI_API_CIP_setClassAttrFunc (pCipNode, classId, &attr);
return true;
}
/*!
* <!-- Description: -->
*
* \brief
* Setup the application with routableinstances, routable attributes callback and routableassemblies..
*
* \details
* In the SampleSetup application with routableinstances, routable attributes callback, and routableassemblies.
* In the EI_APP_cipRoutingSampleSetup, first of all,setroutinglinkadress function should be called. after setting routable ports.
* routable Instance or assembly Instance can be created. Don't forget it, Rotable side is using the routable callback function no longer.
*/
static bool EI_APP_GENERIC_DEVICE_cipRoutingSampleSetup (EI_API_CIP_NODE_T *pCipNode)
{
uint32_t errCode = 0;
uint16_t classId = 0x10D;
uint16_t instanceId = 1;
uint8_t linkAddress = 2;
EI_API_CIP_SAttr_t attr = {0};
const uint16_t attr2_val = 2;
EI_API_CIP_SService_t service = {0};
const uint8_t maxlinkaddr = 8;
uint8_t linkaddr = 0;
//Cip routing functions
errCode = EI_API_CIP_setRoutingMaxLinkAddr(pCipNode, maxlinkaddr);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to set Max link addr\n");
}
errCode= EI_API_CIP_getRoutingMaxLinkAddr(pCipNode, &linkaddr);
if ((errCode != EI_API_CIP_eERR_OK) || (linkaddr!= maxlinkaddr)) {
OSAL_printf("Failed to get Max link addr\n");
}
const uint8_t routablePorts[] = {
11,7,3
};
errCode = EI_API_CIP_setRoutingRoutablePorts(pCipNode, routablePorts, sizeof(routablePorts)/sizeof(uint8_t));
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to set Routable Ports\n");
}
// Create instance of 0x70 CIP Routing Cylic IO messaging.
EI_APP_GENERIC_DEVICE_cipGenerateContentCipRouting(pCipNode, classId, instanceId, linkAddress);
errCode = EI_API_CIP_createCfgAssembly(pCipNode);//CFG ASSEMBLY
errCode = EI_API_CIP_createRoutingAssembly(pCipNode, 0xfe, EI_API_CIP_eAR_GET, linkAddress, EI_API_CIP_eAPP_TYPE_IO); // Input-only. (O2T)
errCode = EI_API_CIP_createRoutingAssembly(pCipNode, 0xff, EI_API_CIP_eAR_GET, linkAddress, EI_API_CIP_eAPP_TYPE_LO); // Listen-only.
errCode = EI_API_CIP_createRoutingAssembly(pCipNode, 3, EI_API_CIP_eAR_GET_AND_SET, linkAddress, EI_API_CIP_eAPP_TYPE_EO);//T2O
errCode = EI_API_CIP_createRoutingAssembly(pCipNode, 1, EI_API_CIP_eAR_GET_AND_SET, linkAddress, EI_API_CIP_eAPP_TYPE_EO);//O2T
for (uint16_t i = 0x300; i < 0x305; i++)
{
errCode = EI_API_CIP_addRoutingAssemblyMember(pCipNode, 3, classId, instanceId, i, linkAddress);
if (errCode != EI_API_CIP_eERR_OK)
{
OSAL_printf("Failed to add Class ID %#x, Instance ID %#x, Attribute ID %#x to Assembly Instance 0x64: Error code: 0x%08x\n", classId, instanceId, (uint16_t)i, errCode);
}
errCode = EI_API_CIP_addRoutingAssemblyMember(pCipNode, 1, classId, instanceId, (uint16_t)(8 + i), linkAddress);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to add Class ID %#x, Instance ID %#x, Attribute ID %#x to Assembly Instance 0x65: Error code: 0x%08x\n", classId, instanceId, (uint16_t)(8 + i), errCode);
}
}
instanceId = 6;
/*creating routable instance 1 which is connected to link addr 1 in the 0x70 class*/
errCode = EI_API_CIP_createRoutableInstance(pCipNode, classId, instanceId, linkAddress);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to create Routable Instance\n");
}
// set class instance
service.code = EI_API_CIP_eSC_GETATTRSINGLE;
errCode = EI_API_CIP_addRoutableInstanceService(pCipNode, classId, instanceId, &service, linkAddress);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to create Routable Instance\n");
}
service.code = EI_API_CIP_eSC_SETATTRSINGLE;
errCode = EI_API_CIP_addRoutableInstanceService(pCipNode, classId, instanceId, &service, linkAddress);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to create Routable Instance\n");
}
attr.id = 2;
attr.edt = EI_API_CIP_eEDT_USINT;
attr.accessRule = EI_API_CIP_eAR_GET_AND_SET;
attr.get_callback_routed = EI_APP_GENERIC_DEVICE_CLASS70_GetAttr2Inst1_Link1_cb;
attr.set_callback_routed = EI_APP_GENERIC_DEVICE_CLASS70_SetAttr2Inst1_Link1_cb;
attr.pvValue = (void *)&attr2_val;
errCode = EI_API_CIP_addRoutableInstanceAttr(pCipNode, classId, instanceId, &attr, linkAddress);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to add Routable Instance Attr\n");
}
errCode = EI_API_CIP_setRoutableInstanceAttrFunc(pCipNode, classId, instanceId, &attr, linkAddress);
if (errCode != EI_API_CIP_eERR_OK) {
OSAL_printf("Failed to set Routable Instance attr func\n");
}
//Adding class attribute and function
EI_API_CIP_addClassAttr (pCipNode, classId, &attr);
EI_API_CIP_setClassAttrFunc (pCipNode, classId, &attr);
return true;
}
#endif // (defined BRIDGING_AND_ROUTING) && (BRIDGING_AND_ROUTING==1)
#endif // (!(defined FBTLPROVIDER) || (0 == FBTLPROVIDER)) && (!(defined FBTL_REMOTE) || (0 == FBTL_REMOTE))
//*************************************************************************************************



