Files
smargopolo/LabJack/exodriver-master/examples/UE9/ue9EthernetExample.c
2021-05-26 15:51:40 +02:00

269 lines
8.7 KiB
C

/*
An example that shows how to use sockets to talk with the UE9. You may notice
that the code is VERY similar to ue9BasicCommConfig.c. The only difference is
using socket calls instead of calls to the Exodriver.
You can compile this example with the following command:
$ g++ -o ue9EthernetExample ue9EthernetExample.c
To run it:
$ ./ue9EthernetExample <IP Address>
It is also included in the Makefile.
*/
//Because that is what an unsigned char is.
typedef unsigned char BYTE;
/* Includes */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
// Defines how long the command is
#define COMMCONFIG_COMMAND_LENGTH 38
// Defines how long the response is
#define COMMCONFIG_RESPONSE_LENGTH 38
/* Buffer Helper Functions Protypes */
// Takes a buffer and an offset, and turns it into a 32-bit integer
int makeInt(BYTE * buffer, int offset);
// Takes a buffer and an offset, and turns it into a 16-bit integer
int makeShort(BYTE * buffer, int offset);
// Takes a buffer and calculates the checksum8 of it.
BYTE calculateChecksum8(BYTE* buffer);
// Takes a buffer and length, and calculates the checksum16 of the buffer.
int calculateChecksum16(BYTE* buffer, int len);
/* LabJack Related Helper Functions Protoypes */
// Demonstrates how to build the CommConfig packet.
void buildCommConfigBytes(BYTE * sendBuffer);
// Demonstrates how to check a response for errors.
int checkResponseForErrors(BYTE * recBuffer);
// Demonstrates how to parse the response of CommConfig.
void parseCommConfigBytes(BYTE * recBuffer);
int main(int argc, char *argv[]) {
// Setup the variables we will need.
int r = 0; // For checking return values
int devHandle = 0;
BYTE sendBuffer[COMMCONFIG_COMMAND_LENGTH], recBuffer[COMMCONFIG_RESPONSE_LENGTH];
struct addrinfo hints, *res;
if(argc < 2) {
fprintf(stderr,"Usage: %s <IP Address>\n", argv[0]);
exit(-1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
printf("Getting IP Info... ");
r = getaddrinfo(argv[1], "52360", &hints, &res);
if( r != 0 ){
perror("Couldn't parse address info. Error: ");
exit(-1);
}
printf("Done\n");
printf("Getting socket FD... ");
// Open the UE9, through a socket.
devHandle = socket(AF_INET, SOCK_STREAM, 0);
if( devHandle < 0 ) {
perror("Couldn't open socket.");
exit(-1);
}
printf("Done\n");
printf("Connecting (time out after a minute)... ");
fflush(stdout);
r = connect(devHandle, res->ai_addr, res->ai_addrlen);
if( r < 0 ){
perror("\nCouldn't connect to UE9. The error was");
close(devHandle);
exit(-1);
}
printf("Done\n");
// Builds the CommConfig command
buildCommConfigBytes(sendBuffer);
// Write the command to the device.
// LJUSB_Write( handle, sendBuffer, length of sendBuffer )
r = write( devHandle, sendBuffer, COMMCONFIG_COMMAND_LENGTH );
if( r != COMMCONFIG_COMMAND_LENGTH ) {
printf("An error occurred when trying to write the buffer. The error was: %d\n", errno);
// *Always* close the device when you error out.
close(devHandle);
exit(-1);
}
// Read the result from the device.
// LJUSB_Read( handle, recBuffer, number of bytes to read)
r = read( devHandle, recBuffer, COMMCONFIG_RESPONSE_LENGTH );
if( r != COMMCONFIG_RESPONSE_LENGTH ) {
printf("An error occurred when trying to read from the UE9. The error was: %d\n", errno);
close(devHandle);
exit(-1);
}
// Check the command for errors
if( checkResponseForErrors(recBuffer) != 0 ){
close(devHandle);
exit(-1);
}
// Parse the response into something useful
parseCommConfigBytes(recBuffer);
//Close the device.
close(devHandle);
return 0;
}
/* ------------- LabJack Related Helper Functions Definitions ------------- */
// Uses information from section 5.2.1 of the UE9 User's Guide to make a CommConfig
// packet.
// http://labjack.com/support/ue9/users-guide/5.2.1
void buildCommConfigBytes(BYTE * sendBuffer) {
int i; // For loops
int checksum = 0;
// Build up the bytes
//sendBuffer[0] = Checksum8
sendBuffer[1] = 0x78;
sendBuffer[2] = 0x10;
sendBuffer[3] = 0x01;
//sendBuffer[4] = Checksum16 (LSB)
//sendBuffer[5] = Checksum16 (MSB)
// We just want to read, so we set the WriteMask to zero, and zero out the
// rest of the bytes.
sendBuffer[6] = 0;
for( i = 7; i < COMMCONFIG_COMMAND_LENGTH; i++){
sendBuffer[i] = 0;
}
// Calculate and set the checksum16
checksum = calculateChecksum16(sendBuffer, COMMCONFIG_COMMAND_LENGTH);
sendBuffer[4] = (BYTE)( checksum & 0xff );
sendBuffer[5] = (BYTE)( (checksum / 256) & 0xff );
// Calculate and set the checksum8
sendBuffer[0] = calculateChecksum8(sendBuffer);
// The bytes have been set, and the checksum calculated. We are ready to
// write to the UE9.
}
// Checks the response for any errors.
int checkResponseForErrors(BYTE * recBuffer) {
if(recBuffer[0] == 0xB8 && recBuffer[1] == 0xB8) {
// If the packet is [ 0xB8, 0xB8 ], that's a bad checksum.
printf("The UE9 detected a bad checksum. Double check your checksum calculations and try again.\n");
return -1;
}
else if (recBuffer[1] == 0x78 && recBuffer[2] == 0x10 && recBuffer[2] == 0x01) {
// Make sure the command bytes match what we expect.
printf("Got the wrong command bytes back from the UE9.\n");
return -1;
}
// Normally, we would check byte 6 for errorcodes. CommConfig is an
// exception to that rule.
// Calculate the checksums.
int checksum16 = calculateChecksum16(recBuffer, COMMCONFIG_RESPONSE_LENGTH);
BYTE checksum8 = calculateChecksum8(recBuffer);
if ( checksum8 != recBuffer[0] || recBuffer[4] != (BYTE)( checksum16 & 0xff ) || recBuffer[5] != (BYTE)( (checksum16 / 256) & 0xff ) ) {
// Check the checksum
printf("Response had invalid checksum.\n%d != %d, %d != %d, %d != %d\n", checksum8, recBuffer[0], (BYTE)( checksum16 & 0xff ), recBuffer[4], (BYTE)( (checksum16 / 256) & 0xff ), recBuffer[5] );
return -1;
}
return 0;
}
// Parses the CommConfig packet into something useful.
void parseCommConfigBytes(BYTE * recBuffer){
printf("Results of CommConfig:\n");
printf(" LocalID = %d\n", recBuffer[8]);
printf(" PowerLevel = %d\n", recBuffer[9]);
printf(" IPAddress = %d.%d.%d.%d\n", recBuffer[13], recBuffer[12], recBuffer[11], recBuffer[10] );
printf(" Gateway = %d.%d.%d.%d\n", recBuffer[17], recBuffer[16], recBuffer[15], recBuffer[14] );
printf(" Subnet = %d.%d.%d.%d\n", recBuffer[21], recBuffer[20], recBuffer[19], recBuffer[18] );
printf(" PortA = %d\n", makeShort(recBuffer, 22));
printf(" PortB = %d\n", makeShort(recBuffer, 24));
printf(" DHCPEnabled = %d\n", recBuffer[26]);
printf(" ProductID = %d\n", recBuffer[27]);
printf(" MACAddress = %02X:%02X:%02X:%02X:%02X:%02X\n", recBuffer[33], recBuffer[32], recBuffer[31], recBuffer[30], recBuffer[29], recBuffer[28]);
BYTE serialBytes[4];
serialBytes[0] = recBuffer[28];
serialBytes[1] = recBuffer[29];
serialBytes[2] = recBuffer[30];
serialBytes[3] = 0x10;
printf(" SerialNumber = %d\n", makeInt(serialBytes, 0));
printf(" HardwareVersion = %d.%02d\n", recBuffer[35], recBuffer[34]);
printf(" FirmwareVersion = %d.%02d\n", recBuffer[37], recBuffer[36]);
}
/* ---------------- Buffer Helper Functions Definitions ---------------- */
// Takes a buffer and an offset, and turns into an 32-bit integer
int makeInt(BYTE * buffer, int offset){
return (buffer[offset+3] << 24) + (buffer[offset+2] << 16) + (buffer[offset+1] << 8) + buffer[offset];
}
// Takes a buffer and an offset, and turns into an 16-bit integer
int makeShort(BYTE * buffer, int offset) {
return (buffer[offset+1] << 8) + buffer[offset];
}
// Calculates the checksum8
BYTE calculateChecksum8(BYTE* buffer){
int i; // For loops
int temp; // For holding a value while we working.
int checksum = 0;
for( i = 1; i < 6; i++){
checksum += buffer[i];
}
temp = checksum/256;
checksum = ( checksum - 256 * temp ) + temp;
temp = checksum/256;
return (BYTE)( ( checksum - 256 * temp ) + temp );
}
// Calculates the checksum16
int calculateChecksum16(BYTE* buffer, int len){
int i;
int checksum = 0;
for( i = 6; i < len; i++){
checksum += buffer[i];
}
return checksum;
}