ACCES “ETH Series” Software Reference

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.

Windows API DLL, AIOETHW

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:

AEW_Connect()

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.

AEW_Disconnect()

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.

AEW_SetTimeout()

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:

AEW_ChangeNetworking()

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:

AEW_ChangeDeviceIP()

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.

AEW_ChangeSubnet()

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.

AEW_ChangeGateway()

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.

AEW_GetStatus()

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:

AEW_DIO_Configure()

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:

AEW_DIO_WriteAll()

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:

AEW_DIO_Write1()

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:

AEW_DIO_ReadAll()

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:

Lower-Level Protocol

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.

Packet Structure

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.

Table 1: Inside A Packet
LengthMeaningNotes
1 byteLength of BodyThis 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 bytePayload lengthAlthough 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 # bytesPayloadThe payload varies per command type; many commands have no payload at all.

Defined packet types are as follows:

Table 2: Command Types And Documentation
TypeDirectionExample PacketMeaningPayload
Configuration
ChMCM>S0B 43 68 4D 43 AA BB CC DD EE FFChange 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)
ChNWM>S11 43 68 4E 57 C0 A8 01 AE FF FF 00 00 C0 A8 01 01Change 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)
ChIPM>S09 43 68 49 50 C0 A8 01 AEChange 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)
ChSMM>S09 43 68 53 4D FF FF 00 00Change 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)
ChGWM>S09 43 68 47 57 C0 A8 01 01Change 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)
RStaM>S06 52 53 74 61 01 01Read 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;
}
DIO
ChIOM>S0D 43 68 49 4F 06 00 01 02 03 04 05 01 03Configure 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)
RADIM>S04 52 41 44 49Read "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
RPDIReserved for reading partial DIO data.
Response:W_OK (04 57 5F 4F 4B)
WADOM>S0B 57 41 44 4F 06 01 02 04 08 10 20Write "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)
WPDOM>S12 57 50 44 4F 0C 03 00 00 00 00 00 01 00 00 00 00 00Write 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)
WRPDM>S12 57 52 50 44 0C 03 00 00 00 00 00 01 00 00 00 00 00Write 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_OKS>M05 57 5F 4F 4B 01Write succeeded.1-byte length of written data. For example, 01 to indicate success of a 1-byte write.
R_OKS>M08 52 5F 4F 4B 03 42 49 4FRead succeeded.1-byte length of read data, then read data. For example, 03 42 49 4F to read 42h, 49h, and 4Fh.
_ErrS>M08 5F 45 72 72 42 00 00 00Transaction 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.