Need to create an <input()> function that responds to either stdin or a serial port - python-3.7

I am using a PC with Python to control an ASCII API through a serial connection to a micro.
The Python code sends commands to the API as a result of Keyboard events.
I need to extend input() - or write a new version - that monitors the serial
connection "simultaneously". In this way a process on the micro serial connection can signal the python code and cause an event in the same way a key command on the PC causes an event.
Since input() stops code execution until (string + \n), input() needs to be
extended.
I have a working serial connection to the micro API.
I am clueless how to do this.
Things I've tried are too embarrassing to show.

You didn't specify the problem at best. However from what I understand you would like to change the input () function to your liking. Something like this can be done, even if it represents a rough solution.
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 4 20:16:13 2019
#author: Roberto Bellarosa
"""
import builtins
def fake_input(prompt):
print(prompt)
return "trgy"
builtins.input = fake_input
name = input("Enter your name >")
print("Hello,"+name+"!")

Related

Sending commands to uart on python

I am trying to write a pyserial command to the uart port to control the robot arm.
I have some manual:
manual for arm
manual command example
I use pyserial like that:
import serial
from time import sleep
port = serial.Serial("/dev/ttyUSB0", baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=8, timeout=1)
port.write(b"\x055\x55\x0B\x03\x02\x20\x03\x02\xB0\x04\x09\xFC\x03\xaa")
sleep(0.3)
#port.write(b"\x05")
#sleep(0.3)
#port.write(b"\x06")
#sleep(0.03)
#port.write(b"\x08\x01\x00")
print('send')
At first I tried to run it in one line, the buzzer will beep that the command was accepted, but the hand does not move.
Then I tried to split the Header separately for the Length in the next line and the Command with Parameters in the next.
Tell me how you can send these commands to the port, maybe there is something ready to do this in Python?
LSC Series Servo Controller Communication Protocol V1.2 manual says:
If the user transmits the correct data to the servo
controller, the blue LED 2 on the controller will flash one time, indicating that the
correct data have been received. If the user transmits the wrong data, then the blue
LED2 will not have any reaction and will keep the bright, then the buzzer will beepbeep twice to remind the user of the data error.
The only thing in that manual about that buzzer is that it beeps 2 times if there is a data error...

I2C: Raspberry Pi (Master) read Arduino (Slave)

I would like to read a block of data from my Arduino Mega (and also from an Arduino Micro in another project) with my Raspberry Pi via I2C. The code has to be in Perl because it's sort of a plug-in for my Home-Automation-Server.
I'm using the Device::SMBus interface and the connection works, I'm able to write and read single Bytes. I can even use writeBlockData with register address 0x00. I randomly discovererd that this address works.
But when I want to readBlockData, no register-address seems to work.
Does anyone know the correct register-address, or is that not even the problem that causes errors?
Thanks in advance
First off, which register(s) are you wanting to read? Here's an example using my RPi::I2C software (it should be exceptionally similar with the distribution you're using), along with a sketch that has a bunch of pseudo-registers configured for reading/writing.
First, the Perl code. It reads two bytes (the output of an analogRead() of pin A0 which is set up as register 80), then bit-shifts the two bytes into a 16-bit integer to get the full 0-1023 value of the pin:
use warnings;
use strict;
use RPi::I2C;
my $arduino_addr = 0x04;
my $arduino = RPi::I2C->new($arduino_addr);
my #bytes = $arduino->read_block(2, 80);
my $a0_value = ($bytes[0] << 8) | $bytes[1];
print "$a0_value\n";
Here's a full-blown Arduino sketch you can review that sets up a half dozen or so pseudo-registers, and when each register is specified, the Arduino writes or reads the appropriate data. If no register is specified, it operates on 0x00 register.
The I2C on the Arduino always does an onReceive() call before it does the onRequest() (when using Wire), so I set up a global variable reg to hold the register value, which I populate in the onReceive() interrupt, which is then used in the onRequest() call to send you the data at the pseudo-register you've specified.
The sketch itself doesn't really do anything useful, I just presented it as an example. It's actually part of my automated unit test platform for my RPi::WiringPi distribution.

serial monitoring method to test communication via com ports without a serial communication device

I have a Verilog code simulated and synthesized on ISE design toolkit. I've got an FPGA spartan 6 device which is to be used for the implementation. But there is a problem with the device (probably a power issue) which makes the device unavailable in any of the COM ports when I connected it to my PC. So I want to check whether my Matlab code which I made for serial communication through the device does the desired job. So I need a method to test serial communication via any of the COM ports without connecting a serial com device to the PC. Is there any such method that I can Tx Rx serial data from Matlab to COM ports? Any software or any other method would be highly appreciated :)
I found a way to test Matlab serial communication using virtual serial ports.
Download "Freeware Virtual COM Ports Emulator" from: http://freevirtualserialports.com/
I installed it in Windows 10, and it's working (as trial).
Add a pair of two serial ports:
Execute the following Matlab code sample to verify it's working:
s3 = serial('COM3','BaudRate',115200);
s4 = serial('COM4','BaudRate',115200);
fopen(s3);
fopen(s4);
fwrite(s3, uint8([1, 2, 3, 4, 5]));
%fprintf(s3, '12345');
pause(0.1);
RxBuf = fread(s4, 5)
fclose(s3);
delete(s3);
clear s3
fclose(s4);
delete(s4);
clear s4
The output is:
RxBuf =
1
2
3
4
5
Bypassing the problem "it only stays for a single test session".
There is a problem when creating a pair of virtual ports using the software, it only stays for a single test session.
I guess it's a problem with the COM port emulation software.
The following solution, is not a good practice (and not a true solution).
Declare the serial object as global, keeping the object persistent.
Create the serial object only if it's not created.
Don't delete and don't clear the serial object.
See the following code sample:
global s3 s4
if isempty(s3)
s3 = serial('COM3','BaudRate',115200);
end
if isempty(s4)
s4 = serial('COM4','BaudRate',115200);
end
fopen(s3);
fopen(s4);
fwrite(s3, uint8([1, 2, 3, 4, 5]));
pause(0.1);
RxBuf = fread(s4, 5)
fclose(s3);
%delete(s3);
%clear s3
fclose(s4);
%delete(s4);
%clear s4
You can also look for a better virtual COM port software.
As Rotem suggested, if you need to communicate via serial line between 2 program of your PC you need a virtual COM port emulator.
It seems you are running on Windows OS so I would recommend a completely free emulator (not a trial one). For Windows I use com0com Null-modem emulator (from SourceForge).
In the example below I will show how to communicate with "another" device so Matlab will not handle both side of the communication. The other device will be simulated by a simple terminal. For windows I use RealTerm: Serial/TCP Terminal (also from SourceForge).
Setup:
Execute the setup of both program with all default options. by default com0com will create a virtual pair COM3/COM4 but if these port already exist on your system the program may assign other numbers. Check the numbers before you run the example. (it will also create a CNCA0/CNCB0 pair but you can ignore this one for now).
For RealTerm, once installed (don't forget to activate the server registration at the end of the setup, it should be ticked by default though), it will look like below. Keep all default options, just set the port number and the baud rate if they need to be changed.
Test MATLAB -> Terminal
You are ready to send Ascii characters or binary values from MATLAB to your device. The animation below shows you an example of both option:
you can click on the picture to see it full size. It is running in loop so you may want to wait until it restart from the beginning.
Test Terminal -> MATLAB
Below animation shows you how to test the communication in the other way:
Don't forget to tick [CR] [LF] on RealTerm when you send Ascii characters and want to use the '%s' format specifier on MATLAB, as it needs these characters to detect the end of the string.
Note:
If you have another terminal program that you are more used too, it
will work the same.
If the RealTerm option does not suit you, or if you want to handle
both sides of communication from Matlab, then you can use the code
provided by Rotem in his first answer. Just install com0com but
ignore all the RealTerm part.

Python, Abstracting a class best practice

first question here on stack!
I have a need to create an abstraction layer between the Pyserial module and calls made to it from other modules. In short, the script will be sending commands to a device, but the method in which it sends those strings could either be via a serial port, or echo'd out a TTY line. The vast majority of the python code to control the device is rather mature and works great, but at this point we will be introducing another device type with the same features, just minus the serial port control.
For one device I do the following...
import serial
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
ser.write('command to microcontroller')
ser.close()
For the new device, since it's lacking a serial port I do the following...
import os
str = 'command to microcontroller'
a = 'echo' + " '" + str + "' " + "> " + '/dev/ttymxc0'
os.system(a)
I have a working process to handle this at the moment, but it seems very wasteful. I basically import serial in a module (the snippets above are from this module) and make all of my calls to communicate with the micro to this module, to determine if it should go out a serial port or echo out a tty line. It seems like I'm basically rewriting functions for every part of the Serial module (ser.write, ser.close, ser.DTR etc) and creating if statements based on device type.
My question is, would a class in this example be less wasteful in terms of function and lines of code, or is it splitting hairs?
Thanks!

pySerial buffer won't flush

I'm having a problem with serial IO under both Windows and Linux using pySerial. With this code the device never receives the command and the read times out:
import serial
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=5)
ser.write("get")
ser.flush()
print ser.read()
This code times out the first time through, but subsequent iterations succeed:
import serial
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=5)
while True:
ser.write("get")
ser.flush()
print ser.read()
Can anyone tell what's going on? I tried to add a call to sync() but it wouldn't take a serial object as it's argument.
Thanks,
Robert
Put some delay in between write and read
e.g.
import serial
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=5)
ser.flushInput()
ser.flushOutput()
ser.write("get")
# sleep(1) for 100 millisecond delay
# 100ms dely
sleep(.1)
print ser.read()
Question is really old, but I feel this might be relevant addition.
Some devices (such as Agilent E3631, for example) rely on DTR. Some ultra-cheap adapters do not have DTR line (or do not have it broken out), and using those, such devices may never behave in expected manner (delays between reads and writes get ridiculously long).
If you find yourself wrestling with such a device, my recommendation is to get an adapter with DTR.
This is because pyserial returns from opening the port before it is actually ready. I've noticed that things like flushInput() don't actually clear the input buffer, for example, if called immediately after the open(). Following is code to demonstrate:
import unittest
import serial
import time
"""
1) create a virtual or real connection between COM12 and COM13
2) in a terminal connected to COM12 (at 9600, N81), enter some junk text (e.g.'sdgfdsgasdg')
3) then execute this unit test
"""
class Test_test1(unittest.TestCase):
def test_A(self):
with serial.Serial(port='COM13', baudrate=9600) as s: # open serial port
print("Read ASAP: {}".format(s.read(s.in_waiting)))
time.sleep(0.1) # wait for 100 ms for pyserial port to actually be ready
print("Read after delay: {}".format(s.read(s.in_waiting)))
if __name__ == '__main__':
unittest.main()
"""
output will be:
Read ASAP: b''
Read after delay: b'sdgfdsgasdg'
.
----------------------------------------------------------------------
Ran 1 test in 0.101s
"""
My workaround has been to implement a 100ms delay after opening before doing anything.
Sorry that this is old and obvious to some, but I didn't see this option mentioned here. I ended up calling a read_all() when flush wasn't doing anything with my hardware.
# Stopped reading for a while on the connection so things build up
# Neither of these were working
conn.flush()
conn.flushInput()
# This did the trick, return value is ignored
conn.read_all()
# Waits for next line
conn.read_line()