Our ETH-DIO-48 and related distributed I/O boards share a programming interface at both the Windows/DLL level, and at the raw Ethernet TCP packet level.
When operating these devices in Windows-based operating systems we highly recommend using the provided AIOETHW.dll. You can examine the source for the DLL in your {sample path}/AIOETHW.src/DLL directory.
The raw Ethernet TCP packets are described towards the bottom of this document.
To install the client, simply copy AIOETHW.dll next to the program that will use it, or to the 32-bit system directory.
The general sequence to use it is:
If the connection fails during operation, a new connection can be swapped in, like this:
function AEW_Connect(Host: PChar; Index: LongInt): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_Connect(char *Host, signed long Index);
AEW_Connect() connects to the specified host device. It returns a client reference (like a handle) that represents the connection, or zero on a failure.
Host can be an IP address in dotted decimal string form (like "192.168.1.174"), a DNS name (like "do.overthere.com"), or a name in the HOSTS file (like "localhost").
Index is normally 0. This connects to port 51936; other values are reserved for future expansion.
The returned client reference is opaque � just a 4-byte value that you pass to the other AEW_* APIs when dealing with that connection. While this is similar to a handle, it doesn't work with any handle-specific APIs, like GetHandleInformation() or CloseHandle(). On a failure, the returned reference will be zero, and the associated Windows error code can be retrieved via GetLastError(). Error codes include:
The server does allow more than one client to connect to a single device. This feature is intended for recovery from network problems, but does allow (for example) two programs to connect, one that writes data and one that checks status.
function AEW_Disconnect(uClientRef: LongWord): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_Disconnect(unsigned long uClientRef);
AEW_Disconnect() disconnects a client reference, closing the connection and cleaning up any memory used. After being passed to AEW_Disconnect(), the client reference is invalid.
function AEW_SetTimeout(uClientRef: LongWord; TimeoutMS: LongInt): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_SetTimeout(unsigned long uClientRef, signed long TimeoutMS);
AEW_SetTimeout() sets the inter-receive timeout for reply packets. This is a client setting, and thus setting it doesn't involve network traffic.
TimeoutMS is the new timeout, in milliseconds. The default for a new connection is 2000.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_ChangeNetworking(uClientRef: LongWord; NewIP, NewSubnet, NewGateway: PChar): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_ChangeNetworking(unsigned long uClientRef, char *NewIP, char *NewSubnet, char *NewGateway);
AEW_ChangeNetworking() changes the device's IP address, subnet mask, and gateway IP address. This change takes effect immediately; the device will close its end of the connection, so on success you should disconnect with AEW_Disconnect(). After a short time you can connect to the new IP with AEW_Connect().
NewIP is the new IP address in dotted decimal string form (like "192.168.1.174").
NewSubnet is the new subnet mask in dotted decimal string form (like "255.255.0.0").
NewGateway is the new gateway IP address in dotted decimal string form (like "192.168.1.1").
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_ChangeDeviceIP(uClientRef: LongWord; NewIP: PChar): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_ChangeDeviceIP(unsigned long uClientRef, char *NewIP);
AEW_ChangeDeviceIP() is similar to AEW_ChangeNetworking(), except it only changes the IP address.
function AEW_ChangeSubnet(uClientRef: LongWord; NewSubnet: PChar): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_ChangeSubnet(unsigned long uClientRef, char *NewSubnet);
AEW_ChangeSubnet() is similar to AEW_ChangeNetworking(), except it only changes the subnet mask.
function AEW_ChangeGateway(uClientRef: LongWord; NewGateway: PChar): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_ChangeGateway(unsigned long uClientRef, char *NewGateway);
AEW_ChangeGateway() is similar to AEW_ChangeNetworking(), except it only changes the gateway IP address.
function AEW_GetStatus(uClientRef: LongWord; pStatusBytes: PLongInt; pStatus: PByte): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_GetStatus(unsigned long uClientRef, signed long *pStatusBytes, unsigned char *pStatus);
AEW_GetStatus() reads the device's status block.
pStatusBytes is a pointer to a variable that holds the size of the buffer to read into, in bytes. On return, this variable will be set to the number of status bytes read.
pStatus is a pointer to the buffer to read into.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_DEF_Configure(uClientRef: LongWord; pIOConfigBytes: PLongInt; pIOConfig: PByte): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_DEF_Configure(unsigned long uClientRef, signed long *pIOConfigBytes, unsigned char *pIOConfig);
AEW_DEF_Configure writes a digital I/O configuration into nonvolatile memory that gets asserted on subsequent resets/boots
pIOConfigBytes is a pointer to a variable that holds the size of the IOConfig buffer ("7" bytes).
pIOConfig is a pointer to the IOConfig structure / buffer. As a byte buffer the first byte, "buf[0]", holds the input/output configuration for the device's I/O Groups ("ports"). Set bits for input mode, clear bits for output mode. Buf[1..6] hold the data that will be output on any ports configured as outputs (writes to inputs are ignored).
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_DEF_Config(uClientRef: LongWord; pIOConfigBytes: PLongInt; pIOConfig: PByte): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_GetIOConfig(unsigned long uClientRef, signed long *pIOConfigBytes, unsigned char *pIOConfig);
AEW_DEF_GetIOConfig reads the current digital I/O configuration as well as the configuration stored in nonvolatile memory that gets asserted on subsequent resets/boots (as configured with AEW_DEF_Configure()
pIOConfigBytes is a pointer to a variable that holds the size of the IOConfig buffer ("14" bytes). On return, this variable will be set to the number of bytes read.
pIOConfig is a pointer to the IOConfig structures / buffer that will hold the two I/O Configuration structures. As a byte buffer the first byte, "buf[0]", holds the current input/output configuration for the device's I/O Groups ("ports"). Set bits for input mode, clear bits for output mode. Buf[1..6] hold the current data seen on all bits. Buf[7] holds the Power On Default I/O settings, and buf[8..14] hold the Power On Default output port data.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_DIO_Configure(uClientRef: Pointer; pDataBytes: PLongInt; pData: PByte; pDirection: PByte): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_DIO_Configure(void *uClientRef, signed long *pDataBytes, unsigned char *pData, unsigned char *pDirection);
AEW_DIO_Configure() sets the direction of the DIO bytes, writes to all of them, and then disables the tristate. Writes to input bytes are ignored.
pDataBytes is a pointer to a variable that holds the size of the data buffer to write from, in bytes. On return, this variable will be set to the amount of data written. For the ETH-DIO-48, the variable should always be 6.
pData is a pointer to the data buffer to write from.
pDirection is a pointer to the direction buffer. This is one byte long per 8 data bytes or fraction. For the ETH-DIO-48, direction should always be 1 byte long. If bit 0 is set, DIO byte 0 becomes an input, otherwise it becomes an output; and so on for each additional DIO byte. For the ETH-DIO-48, a direction buffer of 3F is all inputs, a direction buffer of 00 is all outputs.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_DIO_WriteAll(uClientRef: LongWord; pDataBytes: PLongInt; pData: PByte): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_DIO_WriteAll(unsigned long uClientRef, signed long *pDataBytes, unsigned char *pData);
AEW_DIO_WriteAll() writes to all the DIO.
pDataBytes is a pointer to a variable that holds the size of the buffer to write from, in bytes. On return, this variable will be set to the amount of data written. For the ETH-DIO-48, the variable should always be 6.
pData is a pointer to the buffer to write from.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_DIO_Write1(uClientRef: Pointer; BitIndex: LongInt; bNewValue: ByteBool): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_DIO_Write1(unsigned long uClientRef, signed long BitIndex, unsigned char bNewValue);
AEW_DIO_Write1() writes to one bit of DIO.
BitIndex is which bit to write to. For the ETH-DIO-48, this is from 0 to 47.
bNewValue is the state of the bit to write; nonzero will set the bit, zero will clear the bit.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
function AEW_DIO_ReadAll(uClientRef: LongWord; pDataBytes: PLongInt; pData: PByte): LongWord; cdecl; external 'AIOETHW.dll';
__declspec(dllimport) unsigned long AEW_DIO_ReadAll(unsigned long uClientRef, signed long *pDataBytes, unsigned char *pData);
AEW_DIO_ReadAll() reads from all the DIO.
pDataBytes is a pointer to a variable that holds the size of the buffer to read to, in bytes. On return, this variable will be set to the amount of data read. For the ETH-DIO-48, the variable should always be 6.
pData is a pointer to the buffer to read to.
The return value is ERROR_SUCCESS (equal to zero) on success, or another Windows error code on failure. Error codes include:
AEW_Connect and AEW_Disconnect open and close a TCP/IP connection; however, it is possible to go straight to this lower-level protocol, bypassing the API provided by AIOETHW.dll.
This protocol uses a packet structure atop TCP, where packets are simply sequential in the TCP stream. Since each packet is lengthed, the next byte after it is the start of the next packet.
Each packet is a byte-lengthed string; the first byte is the length(in bytes) of the body. A packet's body consists of a 4-byte ASCII type and zero or more bytes of payload.
Length | Meaning | Notes |
---|---|---|
1 byte | Length of Body | This length should be "entire packet size -1" and must be between 4 and 255, inclusive. (Note: unlike RIFF and similar formats, this does not include the length byte itself.) |
4 bytes (ASCII) | Command Type | The mandatory minimum Body consists of just these four bytes. |
0 or 1 byte | Payload length | Although you can put "0" here, and "5" for the first byte of the packet, it is kinda silly to do so, just use "4" for the first byte, instead. |
variable # bytes | Payload | The payload varies per command type; many commands have no payload at all. |
Defined packet types are as follows:
Type | Direction | Example Packet | Meaning | Payload | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChMC | M>S | 0A 43 68 4D 43 AA BB CC DD EE FF | Change MAC address. | 6-byte MAC address. For example, AA BB CC DD EE FF for MAC address AA:BB:CC:DD:EE:FF. Device should reply with W_OK or _Err. CAUTION: All devices ship from the factory with the same MAC address configured. You must change the MAC Address if you intend on having multiple ETH- units on the same LAN segment. NOTE: After changing the device's MAC address, the socket remains connected to the old one. It's best to clear the old MAC address from the system's ARP table, so the system can fetch the new MAC address for the existing socket. On Windows, use "Cmd.exe /C ARP -d [IP address]" to do this. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:W_OK (04 57 5F 4F 4B) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChNW | M>S | 11 43 68 4E 57 C0 A8 01 AE FF FF 00 00 C0 A8 01 01 | Change network settings. | IP address, subnet mask, and gateway IP address, each in 4-byte big-endian format. For example, C0 A8 01 AE FF FF 00 00 C0 A8 01 01 for 192.168.1.174, 255.255.0.0, and 192.168.1.1. Device should reply with W_OK or _Err. NOTE: After changing the device's IP address, the existing socket becomes useless. Close it and open a new one to the device's new IP address. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:W_OK (04 57 5F 4F 4B) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChIP | M>S | 08 43 68 49 50 C0 A8 01 AE | Change IP address. | 4-byte big-endian IP address. For example, C0 A8 01 AE for 192.168.1.174. Device should reply with W_OK or _Err. NOTE: After changing the device's IP address, the existing socket becomes useless. Close it and open a new one to the device's new IP address. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:W_OK (04 57 5F 4F 4B) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChSM | M>S | 09 43 68 53 4D FF FF 00 00 | Change subnet mask. | 4-byte big-endian subnet mask. For example, FF FF 00 00 for 255.255.0.0. Device should reply with W_OK or _Err. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:W_OK (04 57 5F 4F 4B) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChGW | M>S | 08 43 68 47 57 C0 A8 01 01 | Change gateway IP address. | 4-byte big-endian gateway IP address. For example, C0 A8 01 01 for 192.168.1.1. Device should reply with W_OK or _Err. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:W_OK (04 57 5F 4F 4B) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
RSta | M>S | 06 52 53 74 61 01 01 | Read status. | 1-byte length of version, then version. The current status version is 1 byte, 01, and therefore payload is 01 01. Device should reply with R_OK or _Err. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:R_OK (25 52 5F 4F 4B 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00)
Status version 1 payload contains the following structure:struct { unsigned char op[4]; //0 ~ 3 unsigned char ver[2]; //4 ~ 5 unsigned char mac[6]; //6 ~ 11 unsigned char ip[4]; //12 ~ 15 unsigned char subnet[4]; //16 ~ 19 unsigned char gw[4]; //20 ~ 23 unsigned char dhcp; //24 unsigned char myMac[6]; //25 ~ 30 unsigned char pad; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
CDef v1.6+ | M>S | 0A 43 44 65 66 3F FF FF FF FF FF FF | Configure power-on Default state of DIO bits | Takes the following 7-byte "IOConfig" struct as the payload (no payload length byte): struct { unsigned char Ins; // 6 bits, one per I/O Group ("port"): set for input, clear for output unsigned char Data[6]; // the 48 bits of data to configure the output levels (ignored for I/O Groups configured as inputs) } IOConfigDevice should reply with W_OK or _Err. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Response:W_OK (04 57 5F 4F 4B) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
RIOC v1.6+ | M>S | 0A 52 49 4F 43Read I/O Configuration | No payload defined at this time.
| Response:Response:R_OK (13 52 5F 4F 4B 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )
A length byte followed by two copies of the IOConfig struct defined in CDef. The first struct contains the current configuration (similar to RADS); the second struct contains the Flash-stored CDef struct that will be applied at the next boot/reset
| DIO
| ChIO | M>S | 0D 43 68 49 4F 06 00 01 02 03 04 05 01 03 | Configure direction (and | write "all" DIO data). 1-byte length of DIO data, then DIO data, then 1-byte length of direction data, then direction data. See pDirection of AEW_DIO_Configure() for details on direction data. For example, 06 00 01 02 03 04 05 01 03 to set the first two bytes of DIO to input, and the last four bytes of DIO to output 02..05. Device should reply with W_OK or _Err.
| Response:W_OK (04 57 5F 4F 4B) | RADI | M>S | 04 52 41 44 49 | Read "all" DIO data. | No payload defined at this time. Device should reply with R_OK or _Err.
| Response:R_OK (0B 52 5F 4F 4B 06 05 04 03 02 01 00) NOTE: the payload size and thus the two length bytes may vary with your ETH- device' model | RADS | v1.5+ M>S | 04 52 41 44 53 | Read "all" DIO data AND "I/O Direction / Status". | No payload defined at this time. Device should reply with R_OK or _Err.
| Response:R_OK (0D 52 5F 4F 4B 06 05 04 03 02 01 00 01 XX) NOTE: the payload size and thus the three length bytes may vary with your ETH- device' model; the last XX byte is I/O direction; the only significant bits are one per I/O Group starting at the LSB | RPDI | Reserved for reading partial DIO data.
| Response:W_OK (04 57 5F 4F 4B) | WADO | M>S | 0B 57 41 44 4F 06 01 02 04 08 10 20 | Write "all" DIO data. | 1-byte length of DIO data, then DIO data. For example, 06 01 02 04 08 10 20 to set bit 0 on the first byte of DIO, bit 1 on the next byte of DIO, etc. up to bit 5 on the last byte of DIO. Device should reply with W_OK or _Err.
| Response:W_OK (04 57 5F 4F 4B) | WPDO | M>S | 12 57 50 44 4F 0C 03 00 00 00 00 00 01 00 00 00 00 00 | Write partial DIO data. | 1-byte length of mask+DIO data, then mask, then DIO data. Each bit set in mask corresponds to a bit in DIO data to write. For example, 0C 03 00 00 00 00 00 01 00 00 00 00 00 to set bit 0 high and bit 1 low on the first byte of DIO, without changing bits 2-7 or any other byte. Device should reply with W_OK or _Err.
| Response:W_OK (0457 5F 4F 4B) | WRPD | M>S | 12 57 52 50 44 0C 03 00 00 00 00 00 01 00 00 00 00 00 | Write partial DIO data then read and return state. | 1-byte length of mask+DIO data, then mask, then DIO data. Each bit set in mask corresponds to a bit in DIO data to write. For example, 0C 03 00 00 00 00 00 01 00 00 00 00 00 to set bit 0 high and bit 1 low on the first byte of DIO, without changing bits 2-7 or any other byte. Device should reply with W_OK or _Err.
| Response:R_OK (1D 52 5F 4F 4B 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00)
Payload contains the following structure: | struct { byte Data[6]; // DI values after write has occurred byte PriorData[6]; // DI values before write occurred } Replies
| W_OK | S>M | 05 57 5F 4F 4B 01 | Write succeeded. | 1-byte length of written data. For example, 01 to indicate success of a 1-byte write.
| R_OK | S>M | 08 52 5F 4F 4B 03 42 49 4F | Read succeeded. | 1-byte length of read data, then read data. For example, 03 42 49 4F to read 42h, 49h, and 4Fh.
| _Err | S>M | 08 5F 45 72 72 42 00 00 00 | Transaction failed. | 4-byte little-endian Windows error code. For example, 42 00 00 00 for ERROR_BAD_DEV_TYPE, indicating read from a write-only device or vice versa.
| |