Read data script for TCP

Hello and welcome to my newest challenge. I have some python2 source code from a manufacturer of Eddy current devices. I was able to adapt the WRITE code to control the device in a script module but am having some trouble with the READ code because it uses some external libs which I am not sure are supported here. I’m wondering what would be a good place to start in either reworking the code. The key here would be reading in from the socket and keeping the results in the dictionary data format. Post your thoughts, and I will be updating this as I learn more.

So I’m posing the Write code which works from my gateway script:

[code]from socket import socket

error_msgs = {
11: ‘UNKNOWN FAILURE’,
12: ‘USER CANCELLED’,
13: ‘NULL POINTER’,
14: ‘POINTER NOT NULL’,
15: ‘SYSTEM EXCEPTION’,
16: ‘HARDWARE NOT RESPONDING’,
17: ‘SYSTEM ERROR’,
18: ‘CANNOT ALLOCATE MEMORY’,
19: ‘FATAL ERROR’,
20: ‘SPECIFIED INDEX IS EMPTY’,
21: ‘VALUE IS OUT OF RANGE’,
22: ‘UNHANDLED CONDITION’,
23: ‘USER FORCED EXIT’,
24: ‘USER WANTS TO FORMAT DISK’,
25: ‘BATTERY IS LOW’,
26: ‘NOT ENOUGH PROCESSING POWER, STOPPING DATA COLLECTION’,
30: ‘UNKNOWN EXCEPTION’,
31: ‘FUNCTION BUSY’,
32: ‘NOT A VALID SWITCH’,
33: ‘SEMAPHORE TIMEOUT’,
34: ‘SEMAPHORE ERROR’,
52: ‘INSUFFICIENT DATA POINTS’,
53: ‘DIVIDE BY ZERO’,
59: ‘UNKNOWN DEVICE STATE’,
60: ‘DATA ENTRY BELOW MIN’,
61: ‘DATA ENTRY ABOVE MAX’,
62: ‘INCORRECT DATA LENGTH’,
63: ‘RECORD SKIPPED’,
64: ‘ZERO SLOPE’,
65: ‘INVALID DATA’,
66: ‘READ ONLY DATA’,
67: ‘NO DATA AVAILABLE’,
68: ‘UNUSABLE DATA’,
70: ‘DATA EXCEEDS CHART SPACE’,
71: ‘DATA BUFFER FULL’,
100: ‘BAD PARMETER’,
101: ‘MISSING PARMETER’,
102: ‘NOT SUPPORTED PARMETER’,
103: ‘INVALID CHARACTER IN PARAMETER’,
104: ‘COMMAND DOES NOT EXIST’,
105: ‘PARAMETER HIGH’,
106: ‘PARAMETER LOW’,
107: ‘INVALID COMMAND’,
108: ‘DROPPED CHECKSUM’,
109: ‘INCOMPLETE CHECKSUM’,
110: ‘INVALID FORMAT’,
111: ‘COMMAND NOT SUPPORTED WHILE DATASTREAM ACTIVE’,
112: ‘DEVICE NOT OPEN’,
113: ‘BAD FREQ COMBINATION’,
114: ‘NOT A NUMBER’,
115: ‘NOT AN INTEGER’,
116: ‘OUT OF RANGE’,
117: ‘CANNOT CLOSE AXIS’,
118: ‘REMOTE CONTROL DISABLED’,
119: ‘COMMAND NOt ALLOWED AT THIS TIME’,
120: ‘COMMAND TIMEOUT’,
150: ‘CHART HAS NO DATA’,
151: ‘CHART COULD NOT Be INITIALIZED’,
200: ‘SAMPLES INVALID’,
201: ‘DATA SAMPLING ALREADY ON’,
202: ‘DATA SAMPLING ALREADY OFF’,
203: ‘BAD DATA SEQUENCE NUMBER’,
230: ‘FILENAME TOO LONG’,
231: ‘FILENAME FORMAT INCORRECT’,
232: ‘FILENAME INVALID CHAR’,
233: ‘FILE DOES NOT EXIST’,
234: ‘FILE IS NOT CORRECT TYPE’,
235: ‘FILE IS INCOMPLETE’,
236: ‘FILE IS IN USE’,
237: ‘STORAGE CARD IS MISSING’,
238: ‘CANNOT CREATE FILE’,
250: ‘SETTINGS FILE CHECKSUM IS BAD’,
251: ‘SETTINGS DATA IS INVALID’,
260: ‘DID NOT CONNECT TO DEVICE’,
261: ‘ERROR RETRIEVING INFORMATION’,
262: ‘BOGUS DATA RECEIVED’,
263: ‘SERIAL ROUTINES WERE UPDATING DATA’,
264: ‘SERIAL PORT NOT FOUND (ERROR FILE NOT FOUND’,
265: ‘SERIAL PORT IN USE BY ANOTHER APPLICATION’,
266: ‘ERROR INVALID HANDLE IN WINERROR.H’,
267: ‘NOT CONNECTED TO DEVICE’,
268: ‘EXCEEDED NUMBER OF TRIES TO CONTACT BY RADIO’,
270: ‘RESPONSE WAS NOT APPROPRIATE FOR THE COMMAND’,
271: ‘DEVICE RESPONSE “ERROR” OR “?”’,
272: ‘SOME REQUIRED REQUESTED INFORMATION WAS NOT RETURNED’,
274: ‘SOME SETTINGS WERE VALID SOME RETURNED ERRORS’,
275: ‘VALUE UNAVAILABLE (GENERIC RESPONSE)’,
278: ‘UNKNOWN SERIAL COMMAND FOR A DEVICE’,
279: ‘FOR SOME REASON, THE COMMAND WAS NOT ALLOWED’,
280: ‘CONNECTED TO A DEVICE AND NOT SUPPOSED TO BE’,
283: ‘SERIAL PORT NOT VALID’,

300: 'SOCKET IS NOT OPEN',
301: 'DATA SOCKET NOT CONNECTED',
302: 'CANNOT SEND ON DATA PORT',
303: 'PORT WOULD HAVE BLOCKED',
304: 'CLIENT CLOSED CONNECTION',
305: 'CONNECTION LOST',
306: 'WRONG CLIENT',
307: 'INVALID BAUD RATE',
308: 'PORT IS NOT COMPATIBLE WITH THIS COMMAND',
400: 'CANNOT SET HIGH PASS FILTER',
401: 'CANNOT SET LOW PASS FILTER',
402: 'CANNOT TURN OFF HIGH PASS FILTER',
403: 'CANNOT TURN OFF LOW PASS FILTER',
404: 'FILTER OUT OF RANGE',
900: 'HARDWARE TIMEOUT',
901: 'COULD NOT ACCESS HARDWARE',
902: 'BAD SETTINGS SENT TO HARDWARE FROM FILE',
903: 'BAD PARAMATERS SENT TO HARDWARE',
904: 'COULD NOT WRITE TO HARDWARE',
905: 'COULD NOT PROGRAM DSP',
906: 'COULD NOT INITIALIZE DSP',
907: 'COMMAND NOT RECOGNIZED BY DSP',
908: 'COMMUNICATIONS WITH FPGA FAILED',
909: 'FAILED TO READ FPGA PROGRAM',
910: 'ERROR PROGRAMMING FPGA',
911: 'FPGA PROGRAM STATE UNKNOWN',
912: 'UNKNOWN ERROR WHILE PROGRAMMING FPGA',
913: 'NO PROGRAMMING WAS DONE TO FPGA',
914: 'ALARM ENABLE NOT LATCHED',
1000: 'DATA FILE IS WRONG SIZE',
1001: 'DATA FILE IS WRONG VERSION',
1002: 'FAILED TO RECALL DATA FILE',
1003: 'FAILED TO SAVE DATA FILE',
1100: 'AMOUNT OF DATA READ IS NOT WHAT WAS EXPECTED',
1101: 'WRONG NUMBER OF DATA CHANNELS',
1102: 'TOO FEW POINTS TO COMPUTE STANDARD DEVIATION',
1200: 'ERROR MESSAGE IS TOO LONG TO DISPLAY',
1201: 'CANNOT DISPLAY ANY MORE ERROR MESSAGES',
1300: 'FILENAME NOT VALID',
1301: 'NO FILES TO DISPLAY',
1302: 'INSTRUMENT HAS RUN OUT OF NAMES, CANNOT AUTOMATICALLY NAME FILES',
1303: 'FILENAME IS RESERVED FOR AUTO NAMING',
1400: 'THIS FEATURE IS NOT APPLICABLE FOR THIS INSTRUMENT',
1401: 'CANNOT SET CHANNEL.',
1500: 'CANNOT GET INFORMATION FOR FOLDER',
1501: 'CANNOT CREATE FILE',
1502: 'CANNOT READ FILE',
1503: 'CANNOT RENAME FILE',
1504: 'CANNOT GET INFORMATION FOR FILE',
1505: 'FILE IS NOT OPEN',
1506: 'CANNOT CREATE A STORAGE DIRECTORY',
1507: 'CANNOT CREATE MAIN DIRECTORY',
1508: 'MEDIA NOT INSTALLED',
1509: 'FILE DOES NOT EXIST',
1510: 'NO ROOM AVAILABLE ON SELECTED MEDIA',
1511: 'ERROR READING TO FILE',
1512: 'ERROR WRITING TO FILE',
1513: 'SLOT IS EMPTY',
1514: 'FORMAT NOT SUPPORTED',
1515: 'MEDIUM TYPE NOT SUPPORTED',
1600: 'CANNOT FIND PRINTER',
1601: 'CANNOT OPEN PRINTER',
1602: 'CANNOT PRINT',
1603: 'OTHER PRINTER ERROR',
1604: 'PRINTER TIMEOUT',
1605: 'UNKNOWN PRIUNTER TPYE',
1700: 'SETTINGS FILE HAS BAD CHECKSUM',
1701: 'AN INDEX IS MISSING FROM THE SETTINGS FILE',
1702: 'AN ITEM IS MISSING FROM THE SETTINGS FILE',
1703: 'NO MATCHING SECTION IN SETTINGS FILE',
1704: 'SECTION ALREADY EXISTS IN SETTINGS FILE',
1705: 'SETTINGS FILE HAS BAD CHECKSUM',
1800: 'CANNOT SAVE REPORT',
7003: 'INTERNAL NULL TIMEOUT',
65534: 'BAD CHECKSUM',

}

def sendcmd(sock, cmd):
sock.send(’-’ + cmd + ‘\r’)
ack = sock.recv(3)
if ack != ‘*!\r’:
print((repr(cmd) + ‘Bad ack: ’ + repr(ack)))
while True:
resp = sock.recv(100)
print((repr(cmd) + ‘response: ’ + repr(resp)))
if resp.find(’*OK\r’) != -1:
break
elif resp.find(’*FAIL’) != -1:
error = int(resp[6:])
error_str = resp.strip() + ', ’ + error_msgs[error]
raise Exception('command ’ + repr(cmd) + ': ’ + error_str)
break

a simple uniwest ethernet protocol command line sender

ip_addr = ‘169.254.253.54’
command = ‘GAIN 80.0’
sock = socket()
sock.connect((ip_addr, 55556))
sendcmd(sock, command)[/code]

and the READ code which does not work from my Python 2 IDE:

[code]#!/usr/bin/env python

Copyright 2014 United Western Technologies

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files (the “Software”), to deal

in the Software without restriction, including without limitation the rights

to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

copies of the Software, and to permit persons to whom the Software is

furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in

all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

THE SOFTWARE.

‘’’
us454a_data.py
collect us454a data and translate it to dictionaries for easy consumption in python
This code is provided in the hope that may useful, but has not been extensively tested
A simple usage example is provided at the bottom in the form of a main section

Eddyview Prime, Eddyview Pro and Eddyview Premium instruments are software
compatible with US-454A, and will also work with this program

‘’’
from socket import socket
from collections import deque
from struct import unpack, unpack_from

us454a_data_formats =
{
1: {‘channels’: 1, ‘encoders’: 0, ‘flags’: 0},
2: {‘channels’: 2, ‘encoders’: 0, ‘flags’: 0},
3: {‘channels’: 3, ‘encoders’: 0, ‘flags’: 0},
4: {‘channels’: 4, ‘encoders’: 0, ‘flags’: 0},
5: {‘channels’: 1, ‘encoders’: 0, ‘flags’: 1},
6: {‘channels’: 2, ‘encoders’: 0, ‘flags’: 2},
7: {‘channels’: 3, ‘encoders’: 0, ‘flags’: 3},
8: {‘channels’: 4, ‘encoders’: 0, ‘flags’: 4},
11: {‘channels’: 1, ‘encoders’: 1, ‘flags’: 0},
12: {‘channels’: 2, ‘encoders’: 1, ‘flags’: 0},
13: {‘channels’: 3, ‘encoders’: 1, ‘flags’: 0},
14: {‘channels’: 4, ‘encoders’: 1, ‘flags’: 0},
15: {‘channels’: 1, ‘encoders’: 1, ‘flags’: 1},
16: {‘channels’: 2, ‘encoders’: 1, ‘flags’: 2},
17: {‘channels’: 3, ‘encoders’: 1, ‘flags’: 3},
18: {‘channels’: 4, ‘encoders’: 1, ‘flags’: 4},
21: {‘channels’: 1, ‘encoders’: 2, ‘flags’: 0},
22: {‘channels’: 2, ‘encoders’: 2, ‘flags’: 0},
23: {‘channels’: 3, ‘encoders’: 2, ‘flags’: 0},
24: {‘channels’: 4, ‘encoders’: 2, ‘flags’: 0},
25: {‘channels’: 1, ‘encoders’: 2, ‘flags’: 1},
26: {‘channels’: 2, ‘encoders’: 2, ‘flags’: 2},
27: {‘channels’: 3, ‘encoders’: 2, ‘flags’: 3},
28: {‘channels’: 4, ‘encoders’: 2, ‘flags’: 4},
}

class Us454Data(object):
‘’‘collect data over ethernet from us454a’’’
def init(self, sock):
self.num_samples = 0
self.seq_num = None
self.sock = sock
self.streaming = False

def collect_sample(self, raw_sample):
    '''
    Collect a single sample of any us454a format
    returns a dictionary of { channels, encoders, flags }
    '''
    j = 0
    sample = {}
    channels = []

    if len(raw_sample) != self.sample_size:
        raise Exception('Short packet!')

    while j < self.fmt['channels']:
        channels.append(unpack_from('<hh', raw_sample, 4 * j))
        j += 1
    sample['channels'] = channels
    encoders = []
    j = 0
    while j  < self.fmt['encoders']:
        encoders.append(unpack_from('<i', raw_sample,
            4 * (self.fmt['channels'] + j)))
        j += 1
    sample['encoders'] = encoders

    sample['flags'] = []
    j = 0
    while j < self.fmt['flags']:
        sample['flags'].append(unpack_from('<2B', raw_sample,
                4 * (self.fmt['channels'] + self.fmt['encoders'])))
        j += 1

    self.num_samples -= 1
    return sample

def collect_data(self):
    '''
    Collect a data header and all the data associated with it.
    This could loosely be described as a "packet", but since this
    is tcp data, it is not strictly a packet
    '''
    samples = []

    self.get_us454a_header(self.sock.recv(22))

    while self.num_samples:
        raw_sample = self.sock.recv(self.sample_size)
        if len(raw_sample) < self.sample_size:
            raw_sample += self.sock.recv(self.sample_size - len(raw_sample))

        samples.append(self.collect_sample(raw_sample))
    return samples

def get_us454a_header(self, raw_header):
    '''
    read the data packet header
    '''
    header_fmt = '<8s2hI6s'
    if len(raw_header) != 22:
        raise Exception('Short header!: ' + str(len(raw_header)) + ' bytes')

    h_str, fmt, num_samples, seq_num, d_str = unpack(header_fmt, raw_header)
    if h_str != '[header]' or d_str != '[data]':
        raise Exception('Malformed header')

    if seq_num & 0x80000000: #datastream stop bit encountered
        self.streaming = False
        seq_num &= ~0x80000000
    else:
        self.streaming = True

    if self.seq_num is not None and seq_num != self.seq_num + 1:
        raise Exception('Missed packet(s): seq_num ' + str(seq_num) +
                ' is not immediately after ' + str(self.seq_num))

    try:
        self.fmt = us454a_data_formats[fmt]
        self.sample_size = (self.fmt['channels'] +
                self.fmt['encoders']) * 4 + self.fmt['flags'] * 2
    except KeyError:
        raise Exception('Unsupported format!')

    self.fmt_id = fmt
    self.num_samples = num_samples
    self.seq_num = seq_num

@staticmethod
def counts_to_uv(counts):
    '''convert us454a xy data to microvolts (uv))'''
    return counts * 28600000 / 65535

@staticmethod
def counts_to_mv(counts):
    '''convert us454a xy data to millivolts (uv))'''
    return (counts * 28600 + 32767) / 65535

@staticmethod
def uv_to_counts(uv):
    '''convert microvolts to us454a xy data counts'''
    return uv * 65535 / 28600000

This code is intended to be used as a python Object

This simple main function just collects data.

and assumes system setup has been done

At very least the command “-DATASTREAM Y” must have been sent to port 55556

of the IP address of the instrument

if name == ‘main’:
from sys import argv
if len(argv) < 2:
print(‘usage: ’ + argv[0] + ’ <IP_ADDRESS>’)
exit(1)

sock = socket()
sock.connect((argv[1], 55555))
data = Us454Data(sock)
total_samples = 0
while True:
    samples = data.collect_data()
    total_samples += len(samples)
    print('collected %d samples' % total_samples)
    for sample in samples:
        print(repr(sample))[/code]

Update:

I figured out what my problem was with the scripts, I had not written -DATASTREAM Y before reading.
Also I moved the .py files into the pylib folder to simplify the gateway script. I’m going to keep trying to use the TCP driver as well but so far have had no luck.

One choice is to use Long Path tool it’s worked for me