Store and extract specific data from serial - c++

if(mySerial.available()){
size_t len = mySerial.available();
uint8_t sbuf[len];
mySerial.readBytes(sbuf, len);
//push UART data to all connected telnet clients
for(i = 0; i < MAX_SRV_CLIENTS; i++){
if (serverClients[i] && serverClients[i].connected()){
serverClients[i].write(sbuf, len);
delay(1);
I am receiving data from UART port with this code, and sending directly to telnet clients. Since I am receiving a Modbus hex code:
10 03 02 01 1F 04 1F
I need to extract 4th and 5th pair 011F and send only that as a
decimal number to TCP.
I get it that I have to store it to a string or an array? And then extract data from that, but since I have no common end of line breaks and my numbers change (but keep the format).
I have no idea where to start. I tried to find online but I am simply stuck and am in need of an assistance.
Can someone direct me on where to look or form a code for this and try to explain the logic on what he did.
Since I am doing this on ESP8266 I am trying to keep it simple.

Related

receiving and merging the file fragments over the CAN message

I made a simple code for streaming & transferring a file over 8 bytes CAN message via the CAN Bus,
my code in c is as follows, however, my question is how to merge the fragmented file without any sequence controller?
how do I check the CRC of the receiving file?
since the CAN standard has its own acknowledgment, would that be sufficient for such huge streaming of a file?
typedef struct {
union {
struct {
uint32_t extd: 1;
uint32_t rtr: 1;
uint32_t ss: 1;
uint32_t self: 1;
uint32_t dlc_non_comp: 1;
uint32_t reserved: 27;
};
uint32_t flags;
};
uint32_t identifier;
uint8_t data_length_code;
uint8_t data[TWAI_FRAME_MAX_DLC];
} CAN_message_t;
#define destinationNode 20000x
CAN_message_t msg;
msg.identifier=destinationNode;
msg.data_length_code=8
File date = file.open("/data.bin");
uint8_t *p=date;
while(p){
char buffer[8];
memcpy(buffer, (p+8), 8);
CAN_transmit(&msg);
p+=8;
}
=========================================================
edit code
open the file and send the size and start point to the following function and then close the file
#define SEQUENCE_START 1000000
bool stream(size_t filesize,uint8_t *p){
uint32_t identifer=SEQUENCE_START;
twai_message_t message;
while(filesize<8) {
memcpy(message.data, (p+8), 8);
message.identifier=identifer;
message.data_length_code=8;
if( twai_transmit(&messageOutRPM, pdMS_TO_TICKS(1)) == ESP_OK){
p+=8;
identifer++;
filesize-=8;
}
}
if(filesize>0) {
memcpy(message.data, (p+filesize), filesize);
message.identifier=identifer;
message.data_length_code=filesize;
if( twai_transmit(&messageOutRPM, pdMS_TO_TICKS(1)) == ESP_OK) return true;
}
return true;
}
how to merge the fragmented file without any sequence controller?
There is absolutely no guarantee by CAN bus that the sent frames will be received. They might have CAN errors on the bus preventing some frames to be sent out.
Automotive engineers need to send files over the CAN network in order to implement software updates. To do that, they need to send frames which are way larger than 8 bytes. They defined a small Transport Protocol on the top of CAN: ISO-15765, usually named ISO-TP.
In this protocol, the frames are sent by group. The number of elements in the group is defined during the exchange and can possibility change during the frame transfer.
To give you an example of the communication flow:
SENDER -> RECEIVER: request to send a 800 bytes frame
SENDER <- RECEIVER: accepted, please group the frames by 4
SENDER -> RECEIVER: send part 1
SENDER -> RECEIVER: send part 2
SENDER -> RECEIVER: send part 3
SENDER -> RECEIVER: send part 4
SENDER <- RECEIVER: well-received, continue
SENDER -> RECEIVER: send part 5
SENDER -> RECEIVER: send part 6
SENDER -> RECEIVER: send part 7
SENDER -> RECEIVER: send part 8
SENDER <- RECEIVER: well-received, continue but please group by 8
SENDER -> RECEIVER: send part 9
SENDER -> RECEIVER: send part 10
SENDER -> RECEIVER: send part 11
SENDER -> RECEIVER: send part 12
SENDER -> RECEIVER: send part 13
SENDER -> RECEIVER: send part 14
SENDER -> RECEIVER: send part 15
SENDER -> RECEIVER: send part 16
SENDER <- RECEIVER: well-received, continue
In order to identify which part of the frame is being transmitted, a byte is used as a frame counter. It's a rolling counter, the point is to make sure the completeness of the data. If the frames are not received in the correct order, it does not matter much, as the software is able to determine that no frame has been lost.
[...] long exchange
SENDER -> RECEIVER: FD 00 00 00 00 00 00 00 part N+0
SENDER -> RECEIVER: FE 00 00 00 00 00 00 00 part N+1
SENDER -> RECEIVER: FF 00 00 00 00 00 00 00 part N+2
SENDER -> RECEIVER: 00 00 00 00 00 00 00 00 part N+3
^^
Rolling counter, just 1 byte
This transport layer is usually quite generic, it's frequent to see it available as a library provided by the CAN tool provider. You can also find some Open Source implementations.
since the CAN standard has its own acknowledgment, would that be sufficient for such huge streaming of a file
Actually, CAN bus has its own CRC at physical level, it should be enough for most cases. But if one want to add a custom checksum, one just need to define its length and prepend or append it to the data. Then, the receiver can re-calculate the CRC just after the completion of the transfer.
This code is questionable for several reasons.
First of all, bit-fields are poorly standardized and the bit order may not be the one you expect.
Second, the struct as you posted it will very likely contain padding after data_length_code so writing/reading it to some binary file will be problematic and non-portable.
At any rate I doubt p+8 will ever be correct, because even if there is no padding sizeof(uint32_t)+sizeof(uint32_t) puts us at the data_length_code member, not the data. Why would you want to copy the DLC and 7 bytes into some buffer? This is a bug.
since the CAN standard has its own acknowledgment, would that be sufficient for such huge streaming of a file?
You may want something as CRC32 to ensure there are no corruptions of the file. For the CAN transfer itself you don't need CRC since CAN comes with CRC-15 built-in.
But note that a CRC in the CAN data may be necessary in case of ugly hardware solutions with external CAN controllers. Such legacy solutions involve an exposed SPI bus which has no built-in error control what so ever. Modern electronics only use external CAN controllers in case one is stuck with some exotic MCU that must be used for other reasons, but it doesn't come with CAN on-chip.

How to decode modbus frame to float value using Arduino code?

Hello please I need your help, I am currently working on an emodbus project with arduino, I want to read the data from energy meter to the serial monitor on the arduino board,
I send for example the following frame of the arduino towards the meter to recover the value of the tension:
01 03 00 12 00 02 64 0E
in response from the counter to the arduino card I receive the following frame:
01 03 04 43 54 19 9A 25 9C
which must have the value: 212.1
my problem is that i could not display on the serial monitor
how can i decode this frame with arduino code to get the true value
Read here about the modbus library
Frame formats (This answers my question from the comment - you should have known that)
A Modbus "frame" consists of an Application Data Unit (ADU), which
encapsulates a Protocol Data Unit (PDU):[10]
ADU = Address + PDU + Error check,
PDU = Function code + Data.
The byte order for values in Modbus data frames is most significant
byte of a multi-byte value is sent before the others. All Modbus
variants use one of the following frame formats.[1] Modbus RTU frame
format (primarily used on asynchronous serial data lines like
RS-485/EIA-485) Name Length (bits) Function Start 28 At least 3½
character times of silence (mark condition) Address 8 Station
address Function 8 Indicates the function code; e.g., read
coils/holding registers Data n × 8 Data + length will be filled
depending on the message type CRC 16 Cyclic redundancy check End 28
At least 3½ character times of silence between frames
Before using the library or building blocks from it read the issues first.
For the application to emodbus go here: Look into the files emodbus.h and emodbus.cpp and etools.h and etools.cpp

Python reading a constant serial byte length from device

I have a device that sends 23 characters (numbers and alpha's) via RS232 serial in the following format:
$02 T AAAAA Q CCC PP ZZZ S RR I I NFF $0D
(the spaces in the above string are for readability only)
In this 23 character string the:
$02 represents the start of text 2 hex ( I am not sure what hex this is?)
$0D represents a Carriage Return 13 decimal.
I am currently reading this information in via Python mostly successfully but I still feel I am not doing it properly. I rarely program in Python but I have to use a raspberry PI so decided to go with python for the coding.
I setup my RPI serial port with the following function:
def setupSerialPort():
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1,
xonxoff=0,
rtscts=0
)
return ser
From a while loop I read the port as follow:
# setup serial port
cSerial = setupSerialPort()
while 1:
inbuff = cSerial.inWaiting()
if inbuff > 0:
msgCOM = cSerial.read(inbuff)
#vMsgCOM = re.sub('[^A-Za-z0-9]+', '', msgCOM)
//insert value into database
sleep(1)
at which point I insert the value "vMsgCOM" or "msgCOM" string into a mysql database as I read/receive the data. At first I thought that this works pretty well but after a week of data it became clear that I sometimes only capture partial data which splits over two database rows as mentioned previously. I'll give an example:
A correct 23 char string will look like this: K00000E1120002000063B00.
Now sometimes the string is split into two rows like
(1) K00000E11200020
(2) 00063B00
Another variation of the above is the multiple 23 chunks returned as:
K00000E1120002000063B00K00000E1120002000063B00K00000E1120002000063B00
This happens roughly 15 times out of 400 reads for the above.
Can anyone help me in terms of coding to somehow ensure that I always read the buffer correctly when the 23 string arrives. I know timing can be an issue hence the timeout=1 but somehow I read to quickly (or to long) when the read is not complete.
I had a look at this code (haven't tried it yet): pySerial inWaiting returns incorrect number of bytes (the def read_all(port, chunk_size=200) function part)
but thought it best to rather ask advice from those in the know.
I have in my code a bit of corrective code to concat the two rows and split the multiple chunk event should these instance(s) happen but I still think it is not the best way of doing things.
If anyone can help me with some example code I will really appreciate it.

boost asio async_read() seems to be skipping some nulls

I'm going a bit crazy with a simple boost asio TCP conversation.
I have a server and a client. I use length-prefixed messges. The client sends "one" and the server responds with "two". So this is what I see happen:
The client sends, and the server receives, 00 00 00 03 6F 6E 65 (== 0x0003 one).
The server responds by sending 00 00 00 03 74 77 6F (== 0x0003 two).
Now here is where it is very strange (code below). If the client reads four bytes, I expect it to get 00 00 00 03. If it reads seven, I expect to see 00 00 00 03 74 77 6F. (In fact, it will read four (the length header), then three (the body).)
But what I actually see is that, while if I read seven at once I do see 00 00 00 03 74 77 6F, if I only ask for four, I see 74 77 6F 03. This doesn't make any sense to me.
Here is the code I'm using to receive it (minus some print statements and such):
const int kTcpHeaderSize = 4;
const int kTcpMessageSize = 2048;
std::array<char, kTcpMessageSize + kTcpHeaderSize> receive_buffer_;
void TcpConnection::ReceiveHeader() {
boost::asio::async_read(
socket_, boost::asio::buffer(receive_buffer_, kTcpHeaderSize),
[this](boost::system::error_code error_code,
std::size_t received_length) {
if (error_code) {
LOG_WARNING << "Header read error: " << error_code;
socket_.close(); // TODO: Recover better.
return;
}
if (received_length != kTcpHeaderSize) {
LOG_ERROR << "Header length " << received_length
<< " != " << kTcpHeaderSize;
socket_.close(); // TODO: Recover better.
return;
}
uint32_t read_length_network;
memcpy(&read_length_network, receive_buffer_.data(),
kTcpHeaderSize);
uint32_t read_length = ntohl(read_length_network);
// Error: read_length is in the billions.
ReceiveBody(read_length);
});
}
Note that kTcpHeaderSize is 4. If I change it to 7 (which makes no sense, but just for the experiment) I see the stream of 7 bytes I expect. When it is 4, I see a stream that is not the first four bytes of what I expect.
Any pointers what I am doing wrong?
From what I can see in your code it should work according to the async_read documentation:
The asynchronous operation will continue until one of the following conditions is true:
The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes.
An error occurred.
However see the remark at the bottom:
This overload is equivalent to calling:
boost::asio::async_read(
s, buffers,
boost::asio::transfer_all(),
handler);
It looks like the transfer_all condition might be the only thing checked.
Try using the transfer_exactly condition and if it does work report an issue on https://github.com/boostorg/asio/issues.
The suggestion by #sergiopm to use transfer_all was good, and I'm pretty sure it helped. The other issue involved buffer lifetimes in the asynchronous send/receive functions. I got a bit confused, apparently, about how long certain things would live and how long I needed them to live, and so I was overwriting things from time to time. That may have been more important than transfer_all, but I'm still happy to give #sergiopm credit for helping getting me on my way.
The intent has just been to have a simple tcp client or server that I can declare, hand it a callback, and then go on my way knowing that I can only pay attention to those callbacks.
I'm pretty sure something like this must exist (thousands of times over). Do feel free to comment below, both for me and for those who come after, if you think there are better libraries than asio for this task (i.e., that would involve substantially less code on my part). The principle constraint is that, due to multiple languages and services, we need to own the wire protocol. Otherwise we get into things like "does library X have a module for language Y?".
As an aside, it's interesting to me that essentially every example I've found does length-prefix encoding rather than beginning/end of packet encoding. Length prefix is really easy to implement but, unless I'm quite mistaken, suffers from re-sync hell: if a stream is interrupted ("I'm going to send you 100 bytes, here are the first 50 but then I died") it's not clear to me that there aren't scenarios where I'm unable to resync properly.
Anyway, I learned a lot along the way, I recommend the exercise.

Sending ASCII Control Characters to Serial Device using libserial on Linux

I have a very basic device with which I am trying to interact via a serial connection on Linux. I am on the steep part of the learning curve here, still, so please be gentle!
One of the functions involves sending data to an attached printer. You send a command to the device, which then relays the data you input to the printer attached to the device. The command looks like this:
Send "EXEX*". The device echoes back "EXEX" (the '*' is not echoed yet)
Send a single byte indicating the length of the data you will send, including a LF at the end.
Send the data (the device will now echo back the *).
Send "#". The device will now be ready for another command.
I have a small C++ program to communicate with the device, and I can successfully send single characters and such, but when I try to send this command, I do not get the expected results.
Using Hyperterminal in Windows, it is particularly easy, using alt-key combinations to send ASCII control codes. Just connect and:
Type "EXEX*"
Type Alt+010 to send a LF character, indicating that you are sending 10 bytes to the printer (nine characters and a LF).
Type the data you wish to send: "123456789" (nine bytes in length).
Type Alt+010 again to send a final LF character to the printer.
Type "#" to finish.
Here is what I cobbled together to try in C++:
#include <SerialStream.h>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
using namespace LibSerial;
int main(){
char buffer [50];
int n;
n=sprintf (buffer, "EXEX*%c123456789%c#",10,10);
printf("Variable buffer was set to a %d character string: %s\n",n,buffer);
SerialStream my_serial_stream;
my_serial_stream.Open("/dev/ttyS0") ;
my_serial_stream.SetBaudRate( SerialStreamBuf::BAUD_19200 ) ;
my_serial_stream.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
my_serial_stream.SetFlowControl( SerialStreamBuf::FLOW_CONTROL_NONE ) ;
my_serial_stream.SetParity( SerialStreamBuf::PARITY_NONE ) ;
my_serial_stream.SetNumOfStopBits(1) ;
my_serial_stream.SetVTime(1);
my_serial_stream.SetVMin(100);
cout<<"Sending Command:\n";
my_serial_stream << buffer;
//my_serial_stream << printf("%s",buffer);
//my_serial_stream << "EXEX*\n123456789\n#";
my_serial_stream.read(next_char,100);
cout<<"Result: "<<next_char<<"\n";
my_serial_stream.Close();
return 0;
}
I also tried both of the commented out lines, and neither worked. The device does not receive the proper characters on the other end.'
I'm certain that this is pretty basic, perhaps something is grabbing the control characters in the middle? If anyone has any ideas on a better way to do this, I would really appreciate it. Specifically, I might need to send a byte with a value anywhere between 1 and 40, depending on the length of the data I wish to send to the printer.
My apologies for being unclear, please let me know if I need to break this down farther.
Many thanks,
Tom
The line you send doesn't include the # that you mention in the character sequence.
Have you checked serial comms works on /dev/ttyS0 using gtkterm / cutecom etc?
To test your interface you could read back the serial port. If you have a second port or computer, you could do that by connecting to another port via a null modem. Otherwise you could short pins 2 and 3 of your serial port and check that you are receiving back the characters you send.
You may want to check the return values of the calls to make to the serial library, to see if any errors are returned.
Perhaps there are timing requirements on the printer, and you may need to wait between sending some characters.
I compiled the code and checked the output on another serial port with gtkterm, it does receive the string you would expect:
45 58 45 58 2A 0A 31 32 - 33 34 35 36 37 38 39 0A EXEX*.12 3456789.
It won't affect the sending part of the code, but the receiving looks suspicious. If the read() member function is like the system call and if next_char is a character array, then it won't null terminate the string. Instead you have to look at the return value to get the size, and then null terminate if you are going to use it as a null-terminated C string.