Pyserial - is it possible to set two different stop bit settings for asynchronous serial communication - linux

I'm trying to write an application in pyserial to talk to an external device (a Casio graphics calculator) which according to its manual uses 9600bps asynchronous serial with no flow control, no parity and 8 bits, but for the stop bit values it specifies 3 stop bits for sending and 2 stop bits for receiving. The manual makes no mention of start bit length.
First, does anyone know how to specify two different stop bit values using pyserial, and secondly can you actually specify a stop bit length of 3? The only options that pyserial has are 1, 1.5 and 2 bits.
I've so far managed to send single characters from my Linux laptop to the graphics calculator (setting either 1 or 2 stop bits seemed to work) but getting characters back from the graphics calculator isn't working (I have tested both the cable and port and they should work), so I'm guessing the stop bit setting could be an issue. If anyone knows where to go from here, any help would be greatly appreciated!

Related

ESP32: BLE transmission speed is very slow

I am trying to build an Android app that interfaces with the ESP32 using BLE. I am using the RxBluetoothKotlin library from Vincent Masselis for the Android side. For the ESP32 side, I am using the default Kolban libraries that are included in the Arduino IDE. My phone is a OnePlus 5T and my ESP32 is a MH ET Live ESP32DevKIT. My Android app can be found here, and my ESP32 program here.
The whole system works pretty much perfectly for me in terms of pure functionality. That is to say, every button does what it's supposed to do, and I get the exact behaviour I had expected to get. However, the communication itself is very slow. Around 200 bytes/second. My test button in the Android app requests a bunch of text data from the ESP32, and displays this in a dialog. It also lists a number which represents the time between request and reception in milliseconds. Using this, I get around 2 seconds for 440 bytes of data. When I send less data, the time decreases approximately linearly with data size. 40 bytes of data will take around 200ms, and 20 bytes or under typically takes less than 100ms.
This seems rather slow to me. From what I understand, I should be able to at least get a few kilobytes per second. I have tried to check the speed using nRF Connect, but I get the same 2 seconds timespan for my data transfer. This suggests that the problem is not in my app, since I also have it with a completely different app. I also put the code in my main loop inside of callbacks instead (which I probably should have done in the first place), but this didn't change things at all. I have tried taking the microcontroller and my phone to a few different locations, hoping to eliminate interference. I have tried to mess with BLEDevice::setPower and BLEDevice::setMTU, as well as setting RxBluetoothGatt.requestMtu(500) on the Android side. Everything so far seems to have had little to no effect. The only thing that did anything, was adding the line "pServer->updatePeerMTU(0,500);" in my loop during the connection phase. This caused the first 23 bytes of data to be repeated whenever I pressed the test button in my app, and made the data transfer take about 3 seconds. If I'm lucky, I can get maybe a bit under 1.8 seconds for 440 bytes, but this is a very small change when I'm expecting an order of magnitude of difference, and might even be down to pure chance rather than anything I did.
Does anyone have an idea of how to increase my transfer speed?
The data transmission speed is mainly influenced by the Bluetooth LE connection interval (between 7.5 ms and 4 seconds) and is negotiated between the master (central unit) and the peripheral device. The master establishes a connection with a parameter set and the peripheral can propose to change this parameter set. In the end, however, the central unit decides which parameter set is to be used.
But the Bluetooth connection interval cannot be changed by an Android applications directly, which normally act as the central role. Instead it can request a connection priority which is known to have an influence on the connection interval.

What does dataBits option do in the node-serialport Serialport contructor?

I am using the node-serialport package, and I came across the set of options available to be passed to the constructor of a SerialPort. One of them is called dataBits. The only thing I can find in the documentation is that it can take on values 5, 6, 7, or 8 (default). What does this mean?
Also, more generally, I find the documentation for this package to be lacking many important details. Does anyone know of any great tutorial resources that may be more helpful?
You can usually ignore this option unless you need it. The default is the most common.
The linux documentaiton project has an overview on serialports which has this excerpt.
In serial transmission of bytes via RS-232 ports, the low-order bit is always sent first (the bit-order). Serial ports on PC's use asynchronous communication where there is a start bit and a stop bit to mark the beginning and end of a byte. This is called framing and the framed byte is sometimes called a frame. As a result a total of 9, 10, or 11 bits are sent per byte with 10 being the most common. 8-N-1 means 8 data bits, No parity, 1 stop bit. This adds up to 10 bits total when one counts the start bit. One stop bit is almost universally used.
I highly recommend them for an overview of how serial ports function. Node SerialPort's website is more about how to use node SerialPort.
I'll summarize however as it might be useful.
While modern equipment expect most bytes to have 8 bits, older devices often only could handle 7 (or 6 or 5) bits at a time. They would in turn expect the "packet" of a serial transmission to only include those numbers of bits. A good example of this is the first Microsoft serial mouse. It's hardware, the serial mouse protocol and it's drivers only expected 7 bits a packet. This would be 7 dataBits in serial port's terminology. So instead of waiting for an 8th bit, the OS would make a "7 bit byte" and pass it back to the application. If you didn't have this setting, it would wait around for an 8th bit that would be part of the next packet and nothing would look right.

Is it possible to communicate with vending machines (that uses MDB) using UART directly without using hardware adapter?

I'm building a linux-based cashless device and trying to achieve communication with VMC in vending machines over UART directly without needing additional hardware adapter to convert between 8-bit and 9-bit frame data.
I'm only using the cashless device, no intention to connect any other peripheral to the VMC.
I read questions asked about this before, some of them stressed on the need to an adapter, others suggested possible hacks to achieve the 9-bit to 8-bit conversion, but still can't find a confirmed working and stable solution.
My question is, Is it possible (and reliable) to achieve this using a pure software solution? and how?
Thanks
Yes.
The 9th bit is a control bit. It will show if the data is to be interpreted as an address or as data. If you are communicating with one device and sending only data you want to strip the 9th bit out and only look at data frames. Check and see if it's always zero:
If controlBit = 0:
ProcessData(byte)
Else:
print("This is an address: " + byte)
EDIT:
Many people have reported that your connection will not be stable without special hardware due to timing problems.
Instead of reinventing the wheel you can use opensource code as a starting point.
https://github.com/mhaqs/vendiverse/wiki/Programming-the-VMC
This way you don't have to make the same mistakes over and over again.

Measuring Multiple Voltages in LabView w/USB 6001

I'm trying to set up my LabView VI + my USB 6001 I/O box to be able to read multiple independent voltages at once, while also outputting a single constant voltage.
I've successfully gotten my USB box to output the voltage I want while reading back a single voltage, but so far I've been unable to read back more than one voltage (and if I do, the two voltages seem to be co-dependent on one another in some way).
Here's a screenshot of my VI:
Everything to the right of the screenshot window should be unimportant to the question.
If anyone is curious, this is to drive multiple LVDT's and read back their respective voltages.
Thank you all for your help!
Look at your DAQ's manual, especially the pages I noted below.
http://www.ni.com/pdf/manuals/374259a.pdf
Page 11
All the AI channels get multiplexed, and the low-side reference can be switched (RSE vs. differential). So the two channels you're sampling require both of those to switch. It might be a settling issue where the ADC is taking a sample before the input value is stable.
To verify this, try using using the same low side (differential or RSE) on both channels. Also try slowing down your sample rate (but your 1 kHz should already be slow enough...).
Page 14
Check this to make sure you have everything connected and grounded correctly.
Page 18
Check this for more details about switching between 2 sources quickly.
Perhaps you could try it using the Daqmx express VIs:
http://www.ni.com/tutorial/2744/en/

Is it possible to use 9-bit serial communication in Linux?

RS-232 communication sometimes uses 9-bit bytes. This can be used to communicate with multiple microcontrollers on a bus where 8 bits are data and the extra bit indicates an address byte (rather than data). Inactive controllers only generate an interrupt for address bytes.
Can a Linux program send and receive 9-bit bytes over a serial device? How?
The termios system does not directly support 9 bit operation but it can be emulated on some systems by playing tricks with the CMSPAR flag. It is undocumented and my not appear in all implementations.
Here is a link to a detailed write-up on how 9-bit emulation is done:
http://www.lothosoft.ch/thomas/libmip/markspaceparity.php
9-bit data is a standard part of RS-485 and used in multidrop applications. Hardware based on 16C950 devices may support 9-bits, but only if the UART is used in its 950 mode (rather than the more common 450/550 modes used for RS-232).
A description of the 16C950 may be found here.
This page summarizes Linux RS-485 support, which is baked into more recent kernels (>=3.2 rc3).
9-bit data framing is possible even if a real world UARTs doesn't.
Found one library that also does it under Windows and Linux.
See http://adontec.com/9-bit-serial-communication.htm
basically what he wants is to output data from a linux box, then send it on let's say a 2 wire bus with a bunch of max232 ic's -> some microcontroller with uart or software rs232 implementation
one can leave the individual max232 level converter's away as long as there are no voltage potency issues between the individual microcontrollers (on the same pcb, for example, rather than in different buildings ;) up until the maximum output (ttl) load of the max232 (or clones, or a resistor and invertor/transistor) ic.
can't find linux termios settings for MARK or SPACE parity (Which i'm sure the hardware uarts actually do support, just not linux tty implementation), so we shall just hackzor the actual parity generation a bit.
8 data bits, 2 stop bits is the same length as 8 databits, 1 parity bit, 1 stop bit. (where the first stopbit is a logic 1, negative line voltage).
one would then use the 9th bit as an indicator that the other 8 bits are the address of the individual or group of microcontrollers, which then take the next bytes as some sort of command, or data, as well, they are 'addressed'.
this provides for an 8 bit transparant, although one way traffic, means to address 'a lot of things' (256 different (groups of) things, actually ;) on the same bus. it's one way, for when one would want to do 2 way, you'd need 2 wire pairs, or modulate at multiple frequencies, or implement colission detection and the whole lot of that.
PIC microcontrollers can do 9 bit serial communication with ehm 'some trickery' (the 9th bit is actually in another register ;)
now... considering the fact that on linux and the likes it is not -that- simple...
have you considered simply turning parity on for the 'address word' (the one in which you need 9 bits ;) and then either setting it to odd or even, calculate it so that the right one is chosen to make the 9th (parity) bit '1' with parity on and 8 bit 'data', then turn parity back off and turn 2 stop bits on. (which still keeps a 9 bit word length in as far as your microcontroller is concerned ;)... it's a long time ago but as far as i recall stop bits are just as long as data bits in the timing of things.
this should work on anything that can do 8 bit output, with parity, and with 2 stop bits. which includes pc hardware and linux. (and dos etc)
pc hardware also has options to just turn 'parity' on or off for all words (Without actually calculating it) if i recall correctly from 'back in the days'
furthermore, the 9th bit the pic datasheet speaks about, actually IS the parity bit as in RS-232 specifications. just that you're free to turn it off or on. (on PIC's anyway - in linux it's a bit more complicated than that)
(nothing a few termios settings on linux won't solve i think... just turn it on and off then... we've made that stuff do weirder things ;)
a pic microcontroller actually does exactly the same, just that it's not presented like 'what it actually is' in the datasheet. they actually call it 'the 9th bit' and things like that. on pc's and therefore on linux it works pretty much the same way tho.
anyway if this thing should work 'both ways' then good luck wiring it with 2 pairs or figuring out some way to do collission detection, which is hell a lot more problematic than getting 9 bits out.
either way it's not much more than an overrated shift register. if the uart on the pc doesn't want to do it (which i doubt), just abuse the DTR pin to just shift out the data by hand, or abuse the printer port to do the same, or hook up a shift register to the printer port... but with the parity trick it should work fine anyway.
#include<termios.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
struct termios com1pr;
int com1fd;
void bit9oneven(int fd){
cfmakeraw(&com1pr);
com1pr.c_iflag=IGNPAR;
com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB;
cfsetispeed(&com1pr,B300);
cfsetospeed(&com1pr,B300);
tcsetattr(fd,TCSANOW,&com1pr);
};//bit9even
void bit9onodd(int fd){
cfmakeraw(&com1pr);
com1pr.c_iflag=IGNPAR;
com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB|PARODD;
cfsetispeed(&com1pr,B300);
cfsetospeed(&com1pr,B300);
tcsetattr(fd,TCSANOW,&com1pr);
};//bit9odd
void bit9off(int fd){
cfmakeraw(&com1pr);
com1pr.c_iflag=IGNPAR;
com1pr.c_cflag=CS8|CREAD|CLOCAL|CSTOPB;
cfsetispeed(&com1pr,B300);
cfsetospeed(&com1pr,B300);
tcsetattr(fd,TCSANOW,&com1pr);
};//bit9off
void initrs232(){
com1fd=open("/dev/ttyUSB0",O_RDWR|O_SYNC|O_NOCTTY);
if(com1fd>=0){
tcflush(com1fd,TCIOFLUSH);
}else{printf("FAILED TO INITIALIZE\n");exit(1);};
};//initrs232
void sendaddress(unsigned char x){
unsigned char n;
unsigned char t=0;
for(n=0;n<8;n++)if(x&2^n)t++;
if(t&1)bit9oneven(com1fd);
if(!(t&1))bit9onodd(com1fd);
write(com1fd,&x,1);
};
void main(){
unsigned char datatosend=0x00; //bogus data byte to send
initrs232();
while(1){
bit9oneven(com1fd);
while(1)write(com1fd,&datatosend,1);
//sendaddress(223); // address microcontroller at address 223;
//write(com1fd,&datatosend,1); // send an a
//sendaddress(128); // address microcontroller at address 128;
//write(com1fd,&datatosend,1); //send an a
}
//close(com1fd);
};
somewhat works.. maybe some things the wrong way around but it does send 9 bits. (CSTOPB sets 2 stopbits, meaning that on 8 bit transparant data the 9th bit = 1, in addressing mode the 9th bit = 0 ;)
also take note that the actual rs232 line voltage levels are the other way around from what your software 'reads' (which is the same as the 'inverted' 5v ttl levels your pic microcontroller gets from the transistor or inverter or max232 clone ic). (-19v or -10v (pc) for logic 1, +19/+10 for logic 0), stop bits are negative voltage, like a 1, and the same lenght.
bits go out 0-7 (and in this case: 8 ;)... so start bit -> 0 ,1,2,3,4,5,6,7,
it's a bit hacky but it seems to work on the scope.
Can a Linux program send and receive 9-bit bytes over a serial device?
The standard UART hardware (8251 etc.) doesn't support 9-bit-data modes.
I also made complete demo for 9-bit UART emulation (based on even/odd parity). You can find it here.
All sources available on git.
You can easily adapt it for your device. Hope you like it.

Resources