how to set packet size in recvfrom - python

How do I set the packet size when using recvfrom()?
I am trying to capture tcp packets using a Raspberry Pi Model B. I have a python program that uses recvfrom to capture the packets and write them to a .dat file. To be compatible with the matlab code I wrote for post-processing the data. I need size (bytes) of the file to yield an integer value when divided by the packet size (in this case 8568 bytes). Is this possible? If so how do I do this?
Also I am having to shutdown and power back up the tcp source every time I run the code in order to get the recvfrom function to work. I want this to stop, do I need to add a command to clear the port at the beginning or end of the code?
while t < 5:
time.sleep(1)
t+=1
print t
i=str(t)
f=open('test_' + i ,'wb')
radar=s.recvfrom(8568)
data=str(radar)
f.write(data)
print radar
if radar == 0:
print 'no packets'
if radar != 0:
print radar
f.close()
s.close()

Related

Is there a way to get the read current values from a Keithley SourceMeter onto my computer?

I am performing a sweep, and all works well! Except for when I try to print the current values that it's reading... all it prints is the number of characters of the SPCI command I used. Here is the code:
import pyvisa
import time
import serial
# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial()
ser.port = 'COM3'
ser.baudrate = 9600
ser.open()
ser.isOpen
###Sweep
numberofiterations = 10
stepsize = 0.05
voltage = 0
currents = []
voltages = []
ser.write(str.encode('*RST' + '\r\n'))
ser.write(str.encode(':OUTP ON'+'\r\n'))
for iterations in range(numberofiterations):
#record voltage
voltages.append(round(voltage,5))
#supply voltage
ser.write(str.encode(':SOUR:FUNC VOLT'+'\r\n'))
ser.write(str.encode(':SOUR:VOLT:MODE FIX'+'\r\n'))
ser.write(str.encode(':SOUR:VOLT:RANG 20'+'\r\n'))
ser.write(str.encode(':SOUR:VOLT:LEV '+str(voltage)+'\r\n'))
#wait
time.sleep(1)
#measure current
ser.write(str.encode(':SENS:FUNC "CURR"'+'\r\n'))
ser.write(str.encode(':SENS:CURR:PROT 10e-1'+'\r\n'))
ser.write(str.encode(':SENS:CURR:RANG 10e-1'+'\r\n'))
ser.write(str.encode(':SENS:CURR:RANG:AUTO ON'+'\r\n'))
current = ser.write(str.encode(':READ?'+'\r\n')) #measure current
currents.append(current) #record current
#increase voltage
voltage += stepsize
#Print out values
for current in range(len(currents)):
print(currents[current])
for voltage in range(len(voltages)):
print(voltages[voltage])
Specifically, this is the line that's messing up my code:
current = ser.write(str.encode(':READ?'+'\r\n')) #measure current
Why is it not measuring the current on the computer? The Keithley SourceMeter is measuring it properly as the currents are showing on its screen... I just can't get these values onto the computer. What is wrong here?
Thank you!
ser.write writes bytes to the serial port, and simply reports how many bytes were written. You'll need to read the response from the instrument using ser.read (which reads one byte) or some helper function (your own or library-provided), which can understand the response format of an SCPI command.
According to this reference, it looks like the SCPI response is delimited with a newline, so you should be able to write a command using ser.write and then call ser.readline() to read a whole line of instrument output, up to a newline character. Of course, you'll get a response back in the SCPI format, so you'll need to parse it to obtain your circuit observations.
Note that if you get in an odd state where the instrument is not writing output, but you're in a readline call waiting for a response, your program may lock up. Setting a timeout for the serial port will be helpful. I'm not familiar enough with the protocol to know when this might occur.

TCP socket reads out of turn

I am using TCP with Python sockets, transfering data from one computer to another. However the recv command reads more than it should in the serverside, I could not find the issue.
client.py
while rval:
image_string = frame.tostring()
sock.sendall(image_string)
rval, frame = vc.read()
server.py
while True:
image_string = ""
while len(image_string) < message_size:
data = conn.recv(message_size)
image_string += data
The length of the message is 921600 (message_size) so it is sent with sendall, however when recieved, when I print the length of the arrived messages, the lengths are sometimes wrong, and sometimes correct.
921600
921600
921923 # wrong
922601 # wrong
921682 # wrong
921600
921600
921780 # wrong
As you see, the wrong arrivals have no pattern. As I use TCP, I expected more consistency, however it seems the buffers are mixed up and somehow recieving a part of the next message, therefore producing a longer message. What is the issue here ?
I tried to add just the relevant part of the code, I can add more if you wish, but the code performs well on localhost but fails on two computers, so there should be no errors besides the transmitting part.
Edit1: I inspected this question a bit, it mentions that all send commands in the client may not be recieved by a single recv in the server, but I could not understand how to apply this to practice.
TCP is a stream protocol. There is ABSOLUTELY NO CONNECTION between the sizes of the chunks of data you send, and the chunks of data you receive. If you want to receive data of a known size, it's entirely up to you to only request that much data: you're currently requesting the total length of the data each time, which is going to try to read too much except in the unlikely event of the entire data being retrieved by the first .recv() call. Basically, you need to do something like data = conn.recv(message_size - len(image_string)) to reflect the fact that the amount of remaining data is decreasing.
Think of TCP as a raw stream of bytes. It is your responsibility to track where you are in the stream and interpret it correctly. Buffer what you read and only extract what you currently need.
Here's an (untested) class to illustrate:
class Buffer:
def __init__(self,socket):
self.socket = socket
self.buffer = b''
def recv_exactly(self,count):
# Could return less if socket closes early...
while len(self.buffer) < count:
data = self.socket.recv(4096)
if not data: break
self.buffer += data
ret,self.buffer = self.buffer[:count],self.buffer[count:]
return ret
The recv always requests the same amount of data and queues it in a buffer. recv_exactly only returns the number of bytes requested and leaves any extra in the buffer.

Pyserial writes data but does not read

I'm relatively new to programming, so bear with me. I'm trying to communicate with the measurement device METEX M-4650CR https://sigrok.org/wiki/Voltcraft_M-4650CR and I'm using a windows 7 64bit OS. I simply want to read out the data the device measures to my python procedure and display it and calculate with it.
I found in the manual http://elektron.pol.lublin.pl/elekp/labor_instr/METEX_M-4650CR_Manual.pdf (page 25ff), that it works with a baudrate of 1200, a bytesize of 7 (with ASCII coding) and 2 stopbits.
Furthermore, it can be requested to send data to the computer by simply giving it the command "M". It then returns 14 bytes to the computer. Without anything to measured connected to it, it should return something like 'DC 00.0000V CR'. CR is the terminator here (I hope that is the right name).
Here is my code:
import pyserial
import time
ser = serial.Serial(port='COM5', baudrate=1200,
bytesize=7, stopbits=2, timeout=1,
rtscts=False, dsrdtr=True)
time.sleep(1)
ser.write("M")
time.sleep(1)
bytestoread = ser.inWaiting()
print bytestoread
output = ''
output += ser.read(1000)
print 'output:' + str(output)
time.sleep(1)
ser.close()
My problem is, that I cannot read out the data properly with pyserial. I send the command "M" to the METEX and in the display it says 'send' for a short moment, so I guess my write command works fine. But after that (it should have send the data), all I get when from ser.inWaitung is '0L' or '1L' and the ser.read command gives nothing at all.
I don't think it is a problem of the hardware, because with another programme, called 'serialwatcher', I'm able read out the data correctly. It gives exactly the characters described in the manual.
I also tried the following while loop, having the problem, that most of the time inWaiting == 0, such that it never initialises the loop.
while ser.inWaiting() > 0:
output += ser.read(1)
if output != '':
output = outpus.rstrip()
print output
So, how can I read out the data correctly, that were send to the serial port? Thanks in advance.
Unfortunately I cannot test your code because I have no serial device with me, but you could try the following:
You could set a flag, e.g. alive when you are expecting data and simply try to read something. This worked for me when I was trying to receive data from a really old spectrometer.
while alive: #loop
text = ser.read(1) #try to read one line
if text: #if there is data
n = ser.inWaiting() #look if there is more to read
if n: #if so
text = text + ser.read(n) #get all of it
A more sophisticated example can be found here wxTerminal - Pyserial example You could also simply try to modify this brilliant code for your purpose and see if you are more successful.

Pyserial testing

I am new to Pyserial and Hardware area. I am trying to run the sample applications given in http://pyserial.sourceforge.net/shortintro.html#opening-serial-ports
import serial
ser = serial.Serial(0) # open first serial port
print ser.portstr # check which port was really used
ser.write("hello") # write a string
ser.close()
I have written this program in a python file and running it. Now if I want to test this application to check if I am sending correct string (eg: Hyperterminal or something) how can I do this. Can anyone guide me?
Use virtual serial port for your test.
For Windows I use com0com and socat for Linux.
Then, use Putty for visualization of your send.
Another quick way to test a physical serial port is to take a wire/screwdriver, crocodile clamp or anything that you have in hand and bridge the RX and TX (receive and transmit) together. At that point, everything that you send out will be looped back at you. YOu can receive it afterward by using this code snippet here:
import serial
ser = serial.Serial(0, timeout = 1) # open first serial port
print ser.portstr # check which port was really used
ser.write("hello") # write a string
msg = ser.read("100") #read the content of the input buffer until you get 100 byte or a timeout event
print(msg) #print the content you might need to decode it print(decode(msg))
ser.close()
The key aspect again for this code to work properly is to bridge RX and TX together. A lot of tutorial will show you how to do this.

python socket: sending and receiving 16 bytes

See edits below.
I have two programs that communicate through sockets. I'm trying to send a block of data from one to the other. This has been working with some test data, but is failing with others.
s.sendall('%16d' % len(data))
s.sendall(data)
print(len(data))
sends to
size = int(s.recv(16))
recvd = ''
while size > len(recvd):
data = s.recv(1024)
if not data:
break
recvd += data
print(size, len(recvd))
At one end:
s = socket.socket()
s.connect((server_ip, port))
and the other:
c = socket.socket()
c.bind(('', port))
c.listen(1)
s,a = c.accept()
In my latest test, I sent a 7973903 byte block and the receiver reports size as 7973930.
Why is the data block received off by 27 bytes?
Any other issues?
Python 2.7 or 2.5.4 if that matters.
EDIT: Aha - I'm probably reading past the end of the send buffer. If remaining bytes is less than 1024, I should only read the number of remaining bytes. Is there a standard technique for this sort of data transfer? I have the feeling I'm reinventing the wheel.
EDIT2: I'm screwing up by reading the next file in the series. I'm sending file1 and the last block is 997 bytes. Then I send file2, so the recv(1024) at the end of file1 reads the first 27 bytes of file2.
I'll start another question on how to do this better.
Thanks everyone. Asking and reading comments helped me focus.
First, the line
size = int(s.recv(16))
might read less than 16 bytes — it is unlikely, I will grant, but possible depending on how the network buffers align. The recv() call argument is a maximum value, a limit on how much data you are willing to receive. But you might only receive one byte. The operating system will generally give you control back once at least one byte has arrived, maybe (depending on the OS and on how busy the CPU is) after waiting another few milliseconds in case a second packet arrives with some further data, so that it only has to wake you up once instead of twice.
So you would want to say instead (to do the simplest possible loop; other variants are possible):
data = ''
while len(data) < 16:
more = s.recv(16 - len(data))
if not more:
raise EOFError()
data += more
This is indeed a wheel nearly everyone re-invents because it is so often needed. And your own code needs it a second time: your while loop needs its recv() to count down, asking for smaller and smaller limits until finally it has received exactly the number of bytes that were promised, and no more.

Categories

Resources