Xbee image transfer python - python

Hi there i'm quite new with xBee and struggle with data transferring. My objective is to take picture with Raspberry pi wide and send it back to computer via xBee by turn that image to hexlify code. after recieving the code with python on computer i use binascii library to turn those code back to image by this code
ASCII to IMG:
import binascii
with open("file.txt", "r") as f:
data=f.read()
data = data.strip()
data = data.replace('\n', '')
data = binascii.a2b_hex(data)
with open('image.png', 'wb') as image_file:
image_file.write(data)
but after running that code the image is corrupted. So i start taking a look at the receiving code but I'm not sure if the code is correct, because the text file that i got has a lot of "0" in it
Receiving code:
from digi.xbee.devices import XBeeDevice
PORT = 'COM11'
BAUD = 19200
ser = XBeeDevice(PORT, BAUD)
try :
ser.open()
def data_receive_callback(xbee_message):
data = xbee_message.data.decode("utf-8")
with open("file.txt","a") as f:
f.write(data)
ser.add_data_received_callback(data_receive_callback)
print("Waiting for data...\n")
input()
finally:
if ser is not None and ser.is_open():
ser.close()
camera code in RPi:
from picamera import PiCamera
import serial
import binascii
ser =serial.Serial(
port='/dev/ttyS0',
baudrate=19200,
parity= serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
camera=PiCamera()
camera.resolution(1920,1080)
camera.capture("img.png")
with open("image.png",'rb') as f:
content=f.read()
a=binascii.hexlify(content)
ser.write(a)
ser.close
What should I do or try to fix the code. I think its the receiving code that is a main problem.
Ps. i already try to convert image file to hexlify in both computer and Raspberry Pi and reverse it back and it still work fine.

Questions:
Why are you using an XBee instead of Wi-Fi and a standard TCP protocol like HTTP or FTP?
Work on debugging a piece of your system at a time. Instead of capturing an image on the Pi, use a small text file and see if it comes through correctly. It will be easier to see if you're dropping bytes in the middle, beginning or end of the file.
Whenever using an XBee module, be sure to enable hardware flow control (pins D6 and D7) so you don't lose any serial data. With hardware flow control, each side of the connection has the ability to signal the other side to temporarily stop sending while it processes data.
I also recommend increasing your baud rate to 115200 or even 230400 bps. That, in conjunction with the hardware flow control, will result in quicker transfers without lost bytes.
There's no need to hexlify the data -- the XBee is capable of sending 8-bit bytes when running in transparent serial mode (essentially a serial cable replacement).
That said, you don't have any way to indicate the start or end of the file -- the receiver doesn't know when the image begins or when to finish and close the file. If you continue to hexlify the data, you could send characters other than 0-9a-f to indicate that it's the start of an image or the image is complete.

Related

Is there some special encoding required when sending ASCII commands over Serial (USB-RS232) port in Python3.8?

Firstly, I have also researched an seen that this question is answered alot of places, but the answers don't work for me.
I am trying to send ASCII command over serial port to a PCBA and then attempting to receive the response.
HW setup:
Computer
USB-RS232 Cable
PCBA
SW:
Python 3.8
I have sent commands over RS232 terminals (realterm) and they work perfectly (LED turns on) but can't implement the same with python. The command in question is "led_r_on".
And yes, I get "COM5 is open" prompt, meaning COM5 is alive.
Thanks for helps!
code as follows:
import serial
import time
from time import sleep
from serial import Serial
port = 'COM5'
baud = 115200
ser = serial.Serial(port, baud, timeout=2)
if ser.isOpen():
print(ser.name + ' is open...')
sleep(1)
ser.write(b'led_r_on')
print(ser.readline(1000))
Since you didn't give any information on the pcba you are using. I will just assume, that you are missing some kind of end delimiter in your bytesequence. Now there are many ways of ending a transmission over serial. The most frequent ones I ran across are these two:b'led_r_on\r\n' or just b'led_r_on\n'. Try changing your bytes in the ser.write() function to this. If that does not work you might need to use this: b'led_r_on\x04' this will send the EOT (End of Transmission) ASCII character. But I don't think this will be needed.

Losing bytes with ser.read - Python

I am trying to read data out of a Microcontroller, configuration:19200,8 data bits, even parity and 1 stop bit. The controller is transmitting data via rs485 and I am reading the data via rs485 to rs232 converter. The data is transmitted every 4ms to a write and requires a reflection every 4ms on the respective bytes as displayed in the code. I have written a similar code on a microcontroller and everything works fine but I need to implement the same on Python. While reading from python I notice a few bytes are lost while reading through ser.read(). I also have a logic analyzer converted to see what data I am missing. I tried multiple solutions available on similar posts but it hasn't worked for me as the solutions require me to increase my timeout.
e.g. Losing data in received serial string
import serial
import time
ser = serial.Serial()
ser.port='COM1' # This is COM1, use 1 for COM2 etc
ser.baudrate=19200
ser.bytesize=serial.EIGHTBITS
ser.parity=serial.PARITY_EVEN
ser.stopbits=serial.STOPBITS_ONE
ser.xonxoff=0
ser.rtscts=0
ser.timeout=0
while True:
rxbuf = ser.read(1)
print(rxbuf)
if(rxbuf == b'\x05' or rxbuf == b'\x06' or rxbuf == b'\x15'):
time.sleep(0.004)
ser.write(b'\x05')
elif (rxbuf == b'\x02' or rxbuf == b'\x01'):
rxbuf_len = ser.read(16)
print(rxbuf_len)
output:
b'\x05\'
b'\x05\'
b'\x05\'
b'\x05\'
b'\xF5\'
b'\x28\'
b'\x76\'
b'\x02\'
b'\xf2\x97\x00\x00\x8er\x9a\xc0\x14\xff\xff|:F\x18\x00'
This is incorrect there is a 0x02 before 0xF5 that has not been read apart from many other bytes.

Python Serial Communication Receiving COMMAND UNKNOWN

So I'm trying to control a Thermo Scientific temperature bath over serial (USB-A to USB-B) and when I send a command I get the response "F001" telling me that that command is known. The format is "command" "carriage return" and here is what I have:
ser = serial.Serial('/dev/tty.usbserial-A800dars', 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=5) #no timeout=0
print(ser.name) # check which port was really used
ser.write(b'RT\r') # read internal temp
# TODO probably not getting 100 bytes here, need to find what to expect and whether or not to do a timeout
serial_response = ser.read(100) # read up to one hundred bytes or as much is in the buffer
print(serial_response)
I've tried adding a \n after the \r , I've tried multiple other commands, I've included a space between the RT and the \r and I've set the baud rate on the temperature bath to the same as I am sending over serial. I've also made sure I used the right drivers here from http://www.ftdichip.com/FTDrivers.htm.
Any thoughts? I'm using a Mac, sending over a USB-A to USB-B cable, and I only get the F001 response when the temperature bath is on and running.
Well as it turns out I was given the incorrect manual by the manufacturer. After finding the correct one and now knowing the correct commands to send over serial all the above code works just fine.

Reading MAC frame and feeding it to Wireshark

We have a device receiving 802.11p MAC frames from the air and feeding them to the serial port completely unchanged (no network layer headers) and we'd like to see them arranged in Wireshark, so we can have a sort of self made sniffer for this 802.11p protocol.
My approach (in linux with python) was, open the serial port, read the frames and write them to a named pipe which wireshark would be listening to. After a lot of searching I've found out that the format i have to write into that pipe has to be like the pcap files format. I've looked to some python modules that do pcap formatting (scapy, pcapy, dpkt), but i can't find any that gets a pure MAC frame and simply writes it to a file in the pcap format in a way that wireshark can read and without me having to do all the parsing. What is your suggestion?
How about just creating a tap device and writing the frames to that? Then you can sniff the tap device with wireshark just like any other device. There's an example using a tap device in Python here, and a longer tutorial (actually about tun devices) in C here.
NB: I haven't tested this, but the idea seems reasonable...
UPDATE: This seems to work. It's based on the above gist, but
simply reads frame data from a file and writes it to the device:
import sys
import fcntl
import os
import struct
import subprocess
TUNSETIFF = 0x400454ca
TUNSETOWNER = TUNSETIFF + 2
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
# Open TUN device file.
tun = open('/dev/net/tun', 'r+b')
# Tell it we want a TUN device named lars0.
ifr = struct.pack('16sH', 'lars0', IFF_TAP | IFF_NO_PI)
fcntl.ioctl(tun, TUNSETIFF, ifr)
# Optionally, we want it be accessed by the normal user.
fcntl.ioctl(tun, TUNSETOWNER, 1000)
# Bring it up and assign addresses.
subprocess.check_call(['ifconfig', 'lars0', 'up'])
print 'waiting'
sys.stdin.readline()
# Read an IP packet been sent to this TUN device.
packet = list(open('/tmp/packet.raw').read())
# Write the reply packet into TUN device.
os.write(tun.fileno(), ''.join(packet))
print 'waiting'
sys.stdin.readline()

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.

Categories

Resources