Read SerialPort RealTime in HighSpeed Mode - serial-port

I work on serial Port to read data. serial port's baud-rate is 921600 bps and i use these code to read data:
while(true)
{
bytesToRead = sensor.BytesToRead;
if (bytesToRead > 0)
{
byte[] input = new byte[bytesToRead];
sensor.Read(input, 0, bytesToRead);
}
}
sending protocols is like this. (five digit numbers in bytes + \n\r )
48 48 49 52 50 10 13 , ....
that means : "00142\n\r" -> 00142 -> 142
in each loop I read 4096 bytes of data and i looking for fast way to read all numbers in buffer. i use readLine() function also but it is too slow and some data has been lost.
is there any idea what shroud i do?
thanks.

Related

Test if socket is empty (was: Reading data from a raw socket)

At the start, I thought that the bad performance of my driver was caused by the way in which I read data from a socket.
This was the original function I used:
socket_char_reader = function(in_sock) {
string_read <- raw(0)
while((rd <- readBin(in_sock, what = "raw", n=1)) > 0) {
string_read <- c(string_read, rd)
}
return(string_read %>% strip_CR_NUL() %>% rawToChar())
}
The results from 3 consecutive calls to this function give the expected result. It takes 0.004 seconds to read 29 bytes in total.
My second try reads the socket until it is empty. Another function splits the resulting raw array in 3 separate parts.
get_response = function() {
in_sock <- self$get_socket()
BUF_SIZE <- 8
chars_read <- raw(0)
while (length(rd <- readBin(in_sock, what = "raw", n=BUF_SIZE)) > 0) {
chars_read <- c(chars_read, rd)
}
return(chars_read)
},
Reading from the socket now takes 2.049 seconds!
Can somebody explain to me what could be the cause for this difference (or what is the best method for reading the socket until it is empty)?
In the meantime I'll return to my original solution and continue looking for the cause of the bad performance.
Ben
I believe, I found the cause (but not the solution).
While debuging, I noticed that the delay is caused by the last call to readBin().
In socket_char_reader(), the stop-condition for the while-loop is based on the value of rd; if that value equals 0, the loop stops.
In get_response() the stop-condition is based on the number of bytes in the buffer. Before that number can be determined, readBin() first waits if any other bytes will be send to the socket.
The timeOut-period is set in the socketConnection() call.
private$conn <- socketConnection(host = "localhost", port,
open = "w+b", server = FALSE, blocking = TRUE,
encoding = "UTF-8", timeout = 1)
Timeout has to be give a value > 0, otherwise it will take days before the loop stops.
Is it possible to check if there still are any bytes in the socket without actually reading?
Ben

Generate QR Code with CIQRCodeDescriptor initWithPayload: symbolVersion: maskPattern errorCorrectionLevel:

I am trying to generate a QR Code using CoreImage.
I want to be able to control the symbol version, the masking pattern, and the error correction level.
Using the simple "CIFilter filterWithName:" does not give you the ability to set the symbol version or the mask pattern.
The only way it seems possible is to use a CIQRCodeDescriptor - using "CIQRCodeDesciptor initWithPayload: symbolVersion: maskPattern: errorCorrectionLevel:"
Has anyone been able to use this method to successfully generate a QR Code image?
If so, can you please post a simple complete example?
To be able to use CIQRCodeDescriptor you need
codewords (mode + character count + data + terminator + padding)
correct symbol version (version for the character count; 1-40)
correct mask pattern (mask with minimum penalty; 0-7)
Follows example of "Think Different".
Notice the extra bits in codeword
Think Different: 54 68 69 6E 6B 20 44 69 66 66 65 72 65 6E 74
Codeword: 40 F5 46 86 96 E6 B2 04 46 96 66 66 57 26 56 E7 40 EC 11
The codeword construction is explained at nayuiki or at the bottom.
let codeword : [UInt8] = [0x40, 0xf5, 0x46, 0x86, 0x96, 0xe6, 0xb2, 0x04, 0x46, 0x96, 0x66, 0x66, 0x57, 0x26, 0x56, 0xe7, 0x40, 0xec, 0x11]
let data = Data(bytes: codeword, count: codeword.count)
if let descriptor = CIQRCodeDescriptor(payload: data, symbolVersion: 1, maskPattern: 4, errorCorrectionLevel: .levelL) {
if let image = imageFromBarcodeCodeDescriptor(descriptor)?.transformed(by: .init(scaleX: 10, y: 10)) {
let newImage = NSImage()
newImage.addRepresentation(NSCIImageRep(ciImage: image))
imageView1.image = newImage
}
}
func imageFromBarcodeCodeDescriptor(_ descriptor: CIBarcodeDescriptor) -> CIImage? {
let filter = CIFilter(name: "CIBarcodeGenerator", parameters: ["inputBarcodeDescriptor" : descriptor])
return filter?.outputImage
}
Concatenate segments, add padding, make codewords
Notes:
The segment mode is always a 4-bit field.
The character count’s field width depends on the mode and version.
The terminator is normally four “0” bits, but fewer if the data
codeword capacity is reached.
The bit padding is between zero to seven “0” bits, to fill all unused
bits in the last byte.
The byte padding consists of alternating (hexadecimal) EC and 11 until
the capacity is reached.
The entire sequence of data bits:
01000000111101010100011010000110100101101110011010110010000001000100011010010110011001100110011001010111001001100101011011100111010000001110110000010001
The entire sequence of data codeword bytes (by splitting the bit
string into groups of 8 bits), displayed in hexadecimal: 40 F5 46 86
96 E6 B2 04 46 96 66 66 57 26 56 E7 40 EC 11
It seems CIQRCodeGenerator doesn't support those parameters.
Maybe you can find what you are looking for in this library.
You need to use "CIBarcodeGenerator" CIFilter with the CIQRCodeDescriptor as input:
let data = ... // error corrected payload data
if let barcode = CIQRCodeDescriptor(payload: data,
symbolVersion: 1, // 1...40
maskPattern: 0, // 0..7
errorCorrectionLevel: .levelL) // Any of the available enum values
{
let filter = CIFilter(name: "CIBarcodeGenerator",
parameters: ["inputBarcodeDescriptor": barcode])
let image = filter?.outputImage
}
The caveat though is that you need to obtain somehow the errorCorrectedPayload data for the message you are trying to encode. One of the ways to do this would be to use "CIQRCodeGenerator" to encode the message, parse the resulting image with Vision to extract the barcode descriptor from it, and then get the errorCorrectedPayload data from that descriptor.
A simple working example is:
// Create the CIFilter (CIQRCodeGenerator)
CIFilter *ciFilter = [CIFilter filterWithName:#"CIQRCodeGenerator"];
[ciFilter setDefaults];
NSData *data = [#"123456" dataUsingEncoding:NSUTF8StringEncoding];// QR code value
[ciFilter setValue:data forKey:#"inputMessage"];
[ciFilter setValue:#"L" forKey:#"inputCorrectionLevel"];// L: low, M: Medium, Q: Quartile, H: High
// Create the image at the desired size
CGSize size = CGSizeMake(280, 280);// Desired QR code size
CGRect rect = CGRectIntegral(ciFilter.outputImage.extent);
CIImage *ciImage = [ciFilter.outputImage imageByApplyingTransform:CGAffineTransformMakeScale(size.width/CGRectGetWidth(rect), size.height/CGRectGetHeight(rect))];
// Create a UIImage (if needed)
UIImage *image = [UIImage imageWithCIImage:ciImage];
_imageView.image = image;

Data loss via serial port (RS232)

I am trying to read a series of data via serial port. Below are my test scenarios:
I have a sender (POS terminal) and a receiver (dll) on windows 10. Both connected via RS232 cable (9 pins).
The sender writes 16 bytes of data at one time. The receiver is able to read the data, 1 byte per read, by looping 16 times.
The sender writes 114 bytes of data at one time. The receiver is able to read the data , 1 byte per read, by looping 114 times.
The sender writes 115 bytes of data at one time. The receiver is able to read the data, 1 byte per read, by looping 115 times. But the last character is lost. In other words, the last character seems to be corrupted.
E.g. Data written: ABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNO
I am able to get "ABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMN" correctly. But the last character 'O' is corrupted. Instead the data read in place of last character is (ASCII value) 205, 255, 234 etc. The data is not consistent during multiple read attempts.
Can anyone please put some light on this? Can anyone guide me if I am missing something-somewhere?
I referred this article for my project: Serial Port Communication
Below is the code snippet:
//Port opening.
HANDLE hPortDailUp = CreateFile(portfinal,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
0,
NULL);
//Setting COM timeouts.
SetCommMask(hPortDailUp, 0);
SetupComm(hPortDailUp, 2048, 2048);
GetCommTimeouts (hPortDailUp, &commTimeOuts);
commTimeOuts.ReadIntervalTimeout = 100;
commTimeOuts.ReadTotalTimeoutMultiplier = 70;
commTimeOuts.ReadTotalTimeoutConstant = 1000; //1000
commTimeOuts.WriteTotalTimeoutMultiplier = 0;
commTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hPortDailUp, &commTimeOuts);
//Setting port configuration.
DCB PortDCB;
PortDCB.DCBlength = sizeof(DCB);
PortDCB.BaudRate = BaudRate;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
PortDCB.fOutxCtsFlow = RTS_CONTROL_DISABLE;
PortDCB.fRtsControl = RTS_CONTROL_DISABLE;
SetCommState(hPortDailUp, &PortDCB)
//Reading data from serial port.
unsigned char tempRecvBuf[3001] = {'\0'};
ReadFile(hPortDailUp, tempRecvBuf + nBytesRead, 1, &TempLen, NULL);
//PortDCB Value at runtime.
PortDCB {DCBlength=28 BaudRate=115200 fBinary=1 ...} _DCB
DCBlength 28 unsigned long
BaudRate 115200 unsigned long
fBinary 1 unsigned long
fParity 0 unsigned long
fOutxCtsFlow 0 unsigned long
fOutxDsrFlow 0 unsigned long
fDtrControl 1 unsigned long
fDsrSensitivity 0 unsigned long
fTXContinueOnXoff 0 unsigned long
fOutX 0 unsigned long
fInX 0 unsigned long
fErrorChar 0 unsigned long
fNull 0 unsigned long
fRtsControl 0 unsigned long
fAbortOnError 0 unsigned long
fDummy2 0 unsigned long
wReserved 0 unsigned short
XonLim 2048 unsigned short
XoffLim 512 unsigned short
ByteSize 8 '\b' unsigned char
Parity 0 '\0' unsigned char
StopBits 0 '\0' unsigned char
XonChar 17 '\x11' char
XoffChar 19 '\x13' char
ErrorChar 0 '\0' char
EofChar 0 '\0' char
EvtChar 0 '\0' char
wReserved1 0 unsigned short
It's possible your loop doesn't get the characters read out quite fast enough, so that by the 115th time, a new character is already overwriting the last one that is being read out too late.
To test this, you can add a very short delay between characters on the transmitter side, then see if the receiver acts differently.

understanding checksum of ascii string

I am reading a manual on sending commands via serial to a device as shown:
Assume that my equipment address is 000. I would send a command like:
">000P**cr".
what would **, my checksum be? According to the manual, I need the last two digits of the total char code of "000P".
Isn't that just the hex value of "P"? I can't seem to understand this.
Yes it's a bit confused, but my guess would be:
total = ascii('0') + ascii('0') + ascii('0') + ascii('P')
total = 48 + 48 + 48 + 80
total = 224
cksum = last2digits(total) = 24
If it does not work as is, maybe try in hexadecimal notation:
hex(total) = E0
hex_cksum = last2digits(hex(total)) = E0

Arduino and Raspberry Pi Serial communication + multiple variables

I have a raspberry pi and an arduino. So far I have been able to have the Pi send data to the arduino using serial communication, however it only send one variable and I have multiple variables(2) that I want to send to the arduino (x,y coordinates). Does anyone know if this is possible. I want the first number that is sent from the pi to be the x and the second one the y and the next one the x of the next coord ect.
I have tried editing the code that I use to send one variable but it doesn't work.
Any help would be awesome
Consider the following method to send 2 variable at the same time:
int xpos, ypos;
char x_tx_buffer[20], y_tx_buffer[20];
char x_dummy_buffer[20];
char y_dummy_buffer[20];
char *p_x_tx_buffer, *p_y_tx_buffer;
sprintf(x_dummy_buffer,"%d", xposs);
sprintf(y_dummy_buffer,"%d", yposs);
p_x_tx_buffer = &x_tx_buffer[0];
*p_x_tx_buffer++ = x_dummy_buffer[0];
*p_x_tx_buffer++ = x_dummy_buffer[1];
*p_x_tx_buffer++ = x_dummy_buffer[2];
*p_x_tx_buffer++ = x_dummy_buffer[3];
p_y_tx_buffer = &y_tx_buffer[0];
*p_y_tx_buffer++ = y_dummy_buffer[0];
*p_y_tx_buffer++ = y_dummy_buffer[1];
*p_y_tx_buffer++ = y_dummy_buffer[2];
*p_y_tx_buffer++ = y_dummy_buffer[3];
uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
if (uart0_filestream == -1)
{
//ERROR - CAN'T OPEN SERIAL PORT
printf("Error - Unable to open UART. Ensure it is not in use by another application\n");
}
if (uart0_filestream != -1)
{
int countx = write(uart0_filestream, &x_tx_buffer[0], (p_x_tx_buffer - &x_tx_buffer[0])); //Filestream, bytes to write, number of bytes to write
int county = write(uart0_filestream, &y_tx_buffer[0], (p_y_tx_buffer - &y_tx_buffer[0])); //Filestream, bytes to write, number of bytes to write
if (countx < 0 || county < 0)
{
printf("UART TX error\n");
}
}
close(uart0_filestream);
You can send a max of 8 bytes at a time. Keep that in mind and with that you can modify the about code to send your x and y values in the same uart0_filestream.
Good luck.

Resources