I'd like to transmit a few bytes of data though a pipe to plot it from python.
I started with some snippets I found here but I cant get them working.
I've created the pipe like this:
int main(void){
HANDLE hPipe;
char buffer[24];
DWORD dwRead;
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1,
24 * 16,
24 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
/* do something with data in buffer */
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
return 0;}
If I execute the following code it writes but the read part blocks:
import time
import struct
f = open(r'\\.\\pipe\\Pipe', 'r+b', 0)
i = 1
sss='ccccc'
while True:
s = sss.format(i)
i += 1
f.write(struct.pack('I', len(s)) + s) # Write str length and str
f.seek(0) # EDIT: This is also necessary
print 'Wrote:', s
n = struct.unpack('I', f.read(4))[0] # Read str length
s = f.read(n) # Read str
f.seek(0) # Important!!!
print 'Read:', s
time.sleep(2)
I tried commenting the ReadFile part in the C code but It did not work. Is there any other way to achieve this? I want to write from C and read from python. I tried writing into the pipe with CreateFile (from C) and it worked as expected. I only need the read part with python.
On most systems pipe is one-directional and you use two pipes to get two-directional (bidirectional) connection.
In your Python code you can open two connections
and then you don't need seek
import time
import struct
wf = open(r'Pipe', 'wb', 0)
rf = open(r'Pipe', 'rb', 0)
i = 0
template = 'Hello World {}'
while True:
i += 1
text = template.format(i)
# write text length and text
wf.write(struct.pack('I', len(text)))
wf.write(text)
print 'Wrote:', text
# read text length and text
n = struct.unpack('I', rf.read(4))[0]
read = rf.read(n)
print 'Read:', read
time.sleep(2)
EDIT: tested on Linux Mint 17, Python 3.4 & 2.7
I've solved it with PyWin32(http://sourceforge.net/projects/pywin32/files/) which seems to be the right tool for windows. I would rather use something more cross-plataform oriented but it has solved the problem.
Related
import serial
ser= serial.Serial('com5',9600)
while 1:
Value_from_arduino = ser.readline()
Zustand = float(Value_from_arduino)
print(Zustand)
if Zustand == 1:
ser.write(0)
print('off')
elif Zustand == 0:
ser.write(1)
print(on)
This was the Python code, now here the arduino code.
char serialData;
int pin=12;
int pin2 = 5;
int Value;
void setup(){
pinMode(pin,OUTPUT);
pinMode(pin2,INPUT);
Serial.begin(9600);
}
void loop(){
Value = digitalRead(pin2);
Serial.println(Value);
delay(250);
while(Serial.available()){
serialData = Serial.read();
Serial.print(serialData);
if(serialData = '1'){
digitalWrite(pin,HIGH);
}
else if(serialData = '0'){
digitalWrite(pin,LOW);
}
}
}
My problem is, when i run my python code, it stops when he gets the Value 0 from my arduino.
Here is the report from python:
Zustand = float(Value_from_Arduino)
ValueError: could not convert string to float: b'\x000\r\n'
Python immediatly stops, but he puts the LED on.
The LED should be on if Python gets the value of 0, he do but then he just end run.
The LED should go on if value is 0 and of if value is 1.
You need to decode the serial bytes from the serial port.
Replace the Zustand = line in your code
Value_from_arduino = ser.readline()
Zustand = float(ser_bytes[0:len(Value_from_arduino )-2].decode("utf-8"))
Please check here https://makersportal.com/blog/2018/2/25/python-datalogger-reading-the-serial-output-from-arduino-to-analyze-data-using-pyserial
also try, if encodings doesn't work well
import struct
Zustand, = struct.unpack('<f',Value_from_arduino )
Finally i have found out please replace these lines of code
Steps -> Read,Decode to string, Strip /n and /r, Convert to float
please check here https://problemsolvingwithpython.com/11-Python-and-External-Hardware/11.04-Reading-a-Sensor-with-Python/
Value_from_arduino = ser.readline()
Value_from_arduino = Value_from_arduino.decode()
Value_from_arduino = Value_from_arduino.rstrip()
Zustand = float(Value_from_arduino)
Hope this Works..
I update my question because At first I think that I have the best solution However, I don't have it until now.It was my mistake in execution. I think that the error comes from the loop while in the file C.
I am trying to read lines from a text file"Plaintext.txt".
e0370734313198a2885a308d3243f6a8
ccddeeff8899aabb4455667700112233
8e73b0f7da0e6452c810f32bc4567a22
It contains now tow lines, I put just two in order to make simple test, but I must put more then 1000 texts (means more than 1000 lines) I want to read each line then send it to the uart where I will do encryption for every plaintext (The encryption algorithm is in C): This is my script:
I edit it as you tell me but I still have the encryption of one line
import string
import serial
import time
from array import array
import struct
import binascii
ser = serial.Serial(
port='COM4',\
baudrate=230400,\
parity=serial.PARITY_NONE,\
stopbits=serial.STOPBITS_ONE,\
bytesize=serial.EIGHTBITS,\
timeout=0)
f = open(r'C:\\Users\\user\\Plaintxt.txt', 'r')
for a in f:
plaintxt_16b=a[0:32]
plaintext=binascii.unhexlify(plaintxt_16b)
clear_msg=b'\x24'+b'\x73'+b'\x10'+plaintext
ser.write(clear_msg)
time.sleep(0.4)
while True:
print(ser.read(70))
ser.close() # close ports
In the C file:
while(1)
{
int rx_length = dev_uart_ptr->uart_read((void*)rx_buffer, 19);
if (rx_length <19)
{
if (rx_buffer[0]=='\x24')
{
if (rx_buffer[1]=='\x73')
{
if (rx_buffer[2]=='\x10')
{
plaintext[0] = (rx_buffer[3] << 24) |
(rx_buffer[4] << 16) |
(rx_buffer[5] << 8) |
rx_buffer[6];
plaintext[1] = (rx_buffer[7] << 24) |
(rx_buffer[8] << 16) |
(rx_buffer[9] << 8) |
rx_buffer[10];
plaintext[2] = (rx_buffer[11] << 24) |
(rx_buffer[12] << 16) |
(rx_buffer[13] << 8) |
rx_buffer[14];
plaintext[3] = (rx_buffer[15] << 24) |
(rx_buffer[16] << 16) |
(rx_buffer[17] << 8) |
rx_buffer[18];
xprintf("**************************\n");
xprintf("%8x %8x %8x %8x \n",plaintext[0],plaintext[1],plaintext[2],plaintext[3]);
aes2_set_msg((unsigned int *)plaintext); /** Reset AES message buffer */
aes2_set_key128((unsigned int *)key128); /** Put the key 128 into AES */
/** Configure AES register to enable IRQ and ENCODE */
regs_aes2_ptr-> CFG = AES2_CFG_ENC_DEC_BIT | AES2_CFG_IRQ_MASK_BIT;
/** Reset AES internaly */
regs_aes2_ptr-> CTRL = AES2_CTRL_SWRESET_BIT;
#if DEBUG
xprintf("Go encrypt..\n");
#endif
/** Start the ENCODE function */
regs_aes2_ptr-> CTRL = AES2_CTRL_START_BIT;
while(!aes2_irq_flag); /** Wait for irq flag */
aes2_irq_flag=0; /** Reset irq flag */
#if DEBUG
xprintf("Encrypt done..\n");
#endif
aes2_get_msg((unsigned int *)ciphertext); /** Retrieve encrypted message */
xprintf("%8x %8x %8x %8x \n",ciphertext[0],ciphertext[1],ciphertext[2],ciphertext[3]);
xprintf("**************************\n");
}
else
{
printf ("false");
}
}
else
{
printf ("false");
}
}
}
}// End While
}//end of C_Entry
So the problem is that It takes just the last line and repeat all the time the same encryption of that line:
$**************************
ccddeeff 8899aabb 44556677 112233
Go encrypt..
Encrypt do
ne..
d6e4d64b 27d8d055 c5c7573a 8df4e9aa
**************************
******************
********
ccddeeff 8899aabb 44556677 112233
Go encrypt..
Encrypt done..
d6e4d64b 27d
8d055 c5c7573a 8df4e9aa
**************************
**************************
ccddeeff
8899aabb 44556677 112233
Go encrypt..
Encrypt done..
d6e4d64b 27d8d055 c5c7573a 8df
4e9aa
**************************
**************************
ccddeeff 8899aabb 44556677
112233
Go encrypt..
Encrypt done..
d6e4d64b 27d8d055 c5c7573a 8df4e9aa
**********
****************
**************************
ccddeeff 8899aabb 44556677 112233
Go enc
rypt..
Encrypt done..
d6e4d64b 27d8d055 c5c7573a 8df4e9aa
....................
I would be very grateful if you could help me.
You may want to do as following:
f = open("your_file", "r")
for line in f:
do_something(line)
f.close()
or as the comment pointed out:
with open("your_file", "r") as f:
for line in f:
do_something(line)
Python will iterate over every line and give the string of the line as variable line here. You can handle every line in the file this way. Also, doing so, python reads one line each time, so it is effective for larger files.
During your for loop
for a in range (0,2):
line_array=lines[a]
plaintxt_16b=line_array[0:32]
plaintext=binascii.unhexlify(plaintxt_16b)
clear_msg=b'\x24'+b'\x73'+b'\x10'+plaintext
your overwrite the variable clear_msg in each iteration.
Once you leave the loop it contains the last value. In your case the last line (encrypted). Then you send the variable clear_msg several times without changing its content.
You need to indent the following block as well:
print(clear_msg)
ser.write(clear_msg)
time.sleep(0.4)
According to this, calling readlines() makes your code slower, less explicit, less concise, for absolutely no benefit.
A good approach to open a file without the need of closing it is by using while
with open(file) as f:
line = f.read().splitlines()
line is a list that contains all the lines of your file. You can iterate and get any entry as you would do in a list
The problem was spaces in python file: the for loop must contains
ser.write(clear_msg)
time.sleep(0.4)
print(ser.read(70))
By that way, it will not take just the last plaintext from the plaintext file.
import string
import serial
import time
from array import array
import struct
import binascii
ser = serial.Serial(
port='COM4',\
baudrate=230400,\
parity=serial.PARITY_NONE,\
stopbits=serial.STOPBITS_ONE,\
bytesize=serial.EIGHTBITS,\
timeout=0)
f = open(r'C:\\Users\\user\\Plaintxt.txt', 'r')
for a in f:
plaintxt_16b=a[0:32]
plaintext=binascii.unhexlify(plaintxt_16b)
clear_msg=b'\x24'+b'\x73'+b'\x10'+plaintext
ser.write(clear_msg)
time.sleep(0.4)
print(ser.read(70))
ser.close() # close ports
My problem is resolved. Thank you very much for your help.
I have encountered an error that has been seriously bothering me, and I have been unable to find a workaround. I have a python program that utilizes PySerial to import serial port values from a pulse oximeter. The problem is, when the function ser.readline() is invoked (in other words, when the python program is told to read values from the Arduino's serial monitor, the Arduino's serial values become distorted and the program returns a value unpack error.
Here is the python program.
import serial
import time
import pylab
import matplotlib.pyplot as plt
import numpy as np
import os
import csv
#time load
timestr = time.strftime("%Y_%m_%d")
#establish serial connection with ACM0
ser = serial.Serial('/dev/ttyACM0', 115200)
#establish variables
thymeL = [ ]
bpmL = [ ]
sp02L = [ ]
array_data = thymeL, bpmL, sp02L
#declare time
thyme = 1
#graph attributes
plt.ion()
plt.title("Pulse [BPM] & SPo2 [%] v. Time [s]", fontsize = "16")
plt.xlabel("Time [s]", fontsize = "14")
plt.ylabel("Pulse (red) [BPM] & SPo2 (blue) [%]", fontsize = "14")
while True:
data_in = ser.readline()
print data_in
data_in = data_in.strip('\n')
bpm,sp02 = data_in.split(",")
#convert string vals to float
thyme = float(thyme)
bpm = float(bpm)
sp02 = float(sp02)
#print to terminal
print "Time [s]: %s" % (thyme)
print "HR [BPM]: %s" % (bpm)
print "SPO2 [%%]: %s" % (sp02)
print
#append vectors
thymeL.append(thyme)
bpmL.append(bpm)
sp02L.append(sp02)
#print values to plot
plt.scatter(thyme,bpm,color="red")
plt.scatter(thyme,sp02,color="blue")
plt.pause(0.1)
time.sleep(0.05)
#update time
thyme = thyme + 0.5
#write to .csv
with open(full_path, 'w') as f:
writer = csv.writer(f)
for t, b, s in zip(array_data[0], array_data[1], array_data[2]):
writer.writerow([t, b, s])
The most important snippet of all is:
while True:
data_in = ser.readline()
print data_in
data_in = data_in.strip('\n')
bpm,sp02 = data_in.split(",")
The Arduino program is as follows:
#include <PinChangeInt.h>
#include <eHealth.h>
int cont = 0;
void setup() {
Serial.begin(115200);
eHealth.initPulsioximeter();
PCintPort::attachInterrupt(6, readPulsioximeter, RISING);
}
void loop() {
char buffer[32]; // make sure buffer is large enough
sprintf(buffer,"%d,%d \n",eHealth.getBPM(),eHealth.getOxygenSaturation());
Serial.print(buffer);
delay(500);
}
//=========================================================================
void readPulsioximeter(){
cont ++;
if (cont == 50) { //Get only of one 50 measures to reduce the latency
eHealth.readPulsioximeter();
cont = 0;
}
}
So, the serial monitor is outputting values like this:
67,95
66,95
67,96
and so on.
But only when ser.readline() is invoked, the values become skewed and are unable to be unpacked by the split(',') function. In the following photo (1) and (2), you can see the distortion of the values right when the ser.readline() is called.
How can I re-word the python OR Arduino program in such a way to circumvent this distortion and allow the values to be split and unpacked without any errors?
So is there any possibility that something else is calling loop() asynchronously, e.g. from an interrupt routine, which might try to simultaneously transmit another string of readings at the same time as the arduino's 'mainline' calling of the loop function? An aside: if the interrupt routine readPulsioximeter() got invoked while the mainline loop() function was between the calls to eHealth.getBPM() and eHealth.getOxygenSaturation() and updated the Pulsioximeter attributes, does your code guarantee to send values from the same reading out onto the serial port?
I have the following named pipe created in Windows Powershell.
# .NET 3.5 is required to use the System.IO.Pipes namespace
[reflection.Assembly]::LoadWithPartialName("system.core") | Out-Null
$pipeName = "pipename"
$pipeDir = [System.IO.Pipes.PipeDirection]::InOut
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream( $pipeName, $pipeDir )
Now, what i need is some Python code snippet to read from the above named pipe created. Can Python do that ?
Thanks in advance !
Courtesy :http://jonathonreinhart.blogspot.com/2012/12/named-pipes-between-c-and-python.html
Here's the C# Code
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
class PipeServer
{
static void Main()
{
var server = new NamedPipeServerStream("NPtest");
Console.WriteLine("Waiting for connection...");
server.WaitForConnection();
Console.WriteLine("Connected.");
var br = new BinaryReader(server);
var bw = new BinaryWriter(server);
while (true)
{
try
{
var len = (int)br.ReadUInt32(); // Read string length
var str = new string(br.ReadChars(len)); // Read string
Console.WriteLine("Read: \"{0}\"", str);
//str = new string(str.Reverse().ToArray()); // Aravind's edit: since Reverse() is not working, might require some import. Felt it as irrelevant
var buf = Encoding.ASCII.GetBytes(str); // Get ASCII byte array
bw.Write((uint)buf.Length); // Write string length
bw.Write(buf); // Write string
Console.WriteLine("Wrote: \"{0}\"", str);
}
catch (EndOfStreamException)
{
break; // When client disconnects
}
}
}
}
And here's the Python code:
import time
import struct
f = open(r'\\.\pipe\NPtest', 'r+b', 0)
i = 1
while True:
s = 'Message[{0}]'.format(i)
i += 1
f.write(struct.pack('I', len(s)) + s) # Write str length and str
f.seek(0) # EDIT: This is also necessary
print 'Wrote:', s
n = struct.unpack('I', f.read(4))[0] # Read str length
s = f.read(n) # Read str
f.seek(0) # Important!!!
print 'Read:', s
time.sleep(2)
Convert the C# code into a .ps1 file.
im trying to do something which arduino sends bunch of data frequently, and my objective is:
every 100 data, make a new file. (lets call it a1, a2, ...)
in one generic file, take the average of each of these a files and write it inside of that file as a new line
for experiment i coded my arduino like that:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println(random(100,500));
delay(20);
}
and here is the python code:
import serial, struct
initialfreq = 0
a = 0
interval = 0
fileName = 'general_list'
general_list = open(fileName, 'wb')
ser = serial.Serial(port = 'COM3', baudrate = 9600)
def mean(numberList):
return sum(numberList) / len(numberList)
while(1):
for i in '100' :
temparray=[]
fileName = 'interval' + str(initialfreq) + '.data'
temp_file = open(fileName, 'wb')
readoff = ser.readline()
temparray.append(readoff)
temp_file.write(readoff)
## temp_file.flush()
print("bitti")
general_list.write(str(interval)+" "+str(mean(temparray)))
general_list.write(str(mean(temparray)))
initialfreq= initialfreq + 1
a=0`
my problem is,
for loop is not working properly, even when i sad 100, its not taking 100 values.
arduino sending codes with \n. i cant see them in files but in temparray i see that there is \n 's so its not calculating the average.
thanks a lot guys.
Here is the solution for your first problem.
1)
for i in range(100):