Identification of packets in a byte stream - serial-port

I'm having a bit of a problem with the communication to an accelerometer sensor. The sensor puts out about 8000 readings/second continuously. The sensor is plugged in to a usb port with an adaper and shows up as com4. My problem is that I can't seem to pick out the sensor reading packets from the byte stream. The packets have the size of five bytes and have the following format:
High nibble Low nibble
Byte 1 checksum, id for packet start X high
Byte 2 X mid X low
Byte 3 Y high Y mid
Byte 4 Y low Z high
Byte 5 Y mid Y low
X, y, z is the acceleration.
In the documentation for the sensor it states that the high nibble in the first byte is the checksum (calculated Xhigh+Xlow+Yhigh+Ylow+Zhigh+Zlow) but also the identification of the packet start. I'm pretty new to programming against external devices and can't really grasp how the checksum can be used as an identifier for the start of the package (wouldn't the checksum change all the time?). Is this a common way for identifying the start of a packet? Does anyone have any idea how to solve this problem?
Any help would be greatly appreciated.

... can't really grasp how the checksum can be used as an identifier for the start of the package (wouldn't the checksum change all the time?).
Yes, the checksum would change since it is derived from the data.
But even a fixed-value start-of-packet nibble would (by itself) not be sufficient to (initially) identify (or verify) data packets. Since this is binary data (rather than text), the data can take on the same value as any fixed-value start-of-packet. If you had a trivial scan for this start-nibble, that algorithm could easily misidentify a data nibble as the start-nibble.
Is this a common way for identifying the start of a packet?
No, but given the high data rate, it seems to be a scheme to minimize the packet size.
Does anyone have any idea how to solve this problem?
You probably have to initially scan every sequence of bytes five at a time (i.e. the length of a packet).
Calculate the checksum of this "packet", and compare it to the first nibble.
A match indicates that you (may) have packet alignment.
A mismatch means that you should toss the first byte, and test the next possible packet that would start with what was the second byte (i.e. shift the 4 remaining bytes and append a new 5th byte).
Once packet alignment has been achieved (or assumed), you need to continually verify the checksum of every packet in order to confirm data integrity and ensure packet data alignment. Any checksum error should force another hunt for correct packet data alignment (starting at the 2nd byte of the current "packet").

What you need to do is get some free SerialPortTerminal in c# import in your project and first check all the data and packets you are getting, unless you have already done that. Than just to read you will need to do something like...
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace SPE
{
class SerialPortProgram
{
// Create the serial port with basic settings
private SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
[STAThread]
static void Main(string[] args)
{
// Instatiate this class
new SerialPortProgram();
}
private SerialPortProgram()
{
Console.WriteLine("Incoming Data:");
// Attach a method to be called when there // is data waiting in the port's buffer
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
// Begin communications
port.Open();
// Enter an application loop to keep this thread alive
Application.Run();
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Show all the incoming data in the port's buffer
Console.WriteLine(port.ReadExisting());
}
}
}

Related

At where TCP New Reno set the threshold value once a packet is dropped in NS3

In TCP New Reno it set the threshold value to half of the current CWND once a packet drop is identified. I need to find the method, that does the task.
In tcp-l4-protocol.h it uses TcpClassicRecovery as the recovery method. In TcpClassicRecovery entering phase, it uses the following code segment to set the current CWND,
void
TcpClassicRecovery::EnterRecovery (Ptr<TcpSocketState> tcb, uint32_t dupAckCount,
uint32_t unAckDataCount, uint32_t lastSackedBytes)
{
NS_LOG_FUNCTION (this << tcb << dupAckCount << unAckDataCount << lastSackedBytes);
NS_UNUSED (unAckDataCount);
NS_UNUSED (lastSackedBytes);
tcb->m_cWnd = tcb->m_ssThresh;
tcb->m_cWndInfl = tcb->m_ssThresh + (dupAckCount * tcb->m_segmentSize);
}
Then I assume before calling the EnterRecovery method, the cwnd is already updated. I need to find the place that cwnd is updated.
I also updated TcpNewReno::GetSsThresh and analyzed the output. But it's also not the method I need as it doesn't cut the cwnd to half.
NOTE: I'm using seventh.cc to inspect cwnd. It always drops the cwnd to 1072. The graph I'm getting is also included. What I need to do is drop the cwnd to half of the value once a packet is dropped. Maybe the seventh.cc is not using the default tcp-l4-protocol.h. If so how I can change it?
I found the answer. The problem was with the seventh.cc. It does not use the default layer 4 TCP protocol.
To run the default layer 4 TCP protocol (TCP New Reno), I found an example, which is tcp-large-transfer.cc. It's located in ns-3.30/examples/tcp/tcp-large-transfer.cc.
I just wanted to add a quick note: the code to change cwnd is in the very snippet in your question. Specifically, it is this line:
tcb->m_cWnd = tcb->m_ssThresh;
Much of the state of a TCP Socket is actually stored in the the tcb which is a Ptr<TcpSocketState>.

Sim800L lag/delay before incoming calls are visible to arduino

I use SIM800L GSM module to detect incoming calls and generally it works fine. The only problem is that sometimes it takes up to 8 RINGS before the GSM module tells arduino that someone is calling (before RING appears on the serial connection). It looks like a GSM Network congestion but I do not have such issues with normal calls (I mean calls between people). It happens to often - so it cannot be network/Provider overload. Does anybody else had such a problem?
ISP/Provider: Plus GSM in Poland
I don't put any code, because the problem is in different layer I think
sorry that I didn't answer earlier. I've tested it and it turned out that in bare minimum code it worked OK! I mean, I can see 'RING' on the serial monitor immediately after dialing the number. So it's not a hardware issue!
//bare minimum code:
void loop() {
if(serialSIM800.available()){
Serial.write(serialSIM800.read());
}
if(Serial.available()){
serialSIM800.write(Serial.read());
}
}
In my real code I need to compare calling number with the trusted list. To do that I saved all trusted numbers in the contact list on the sim card (with the common prefix name 'mytrusted'). So, in the main loop there's if statement:
while(mySerial.available()){
incomingByte = mySerial.read();
inputString += incomingByte;
}
if (inputString.indexOf("mytrusted") > 0){
isTrusted = 1;
Serial.println("A TRUSTED NUMBER IS CALLING");
}
After adding this "if condition" Arduino sometimes recognize trusted number after 1'st call, and sometimes after 4'th or 5'th. I'm not suspecting the if statement itself , but the preceding while loop, where incoming bytes are combined into one string.
Any ideas, what can be improved in this simply code?
It seems, I found workaround for my problem. I just send a simple 'AT' command every 20 seconds to SIM800L (it replies with 'OK' ). I use timer to count this 20 seconds interval (instead of simply delay function)
TimerObject *timer2 = new TimerObject(20000); //AT command interval
....
timer2->setOnTimer(&SendATCMD);
....
void SendATCMD () {
mySerial.println("AT");
timer2->Stop();
timer2->Start();
}
With this simple modification Arduino always sees incoming call immediately (after 1 ring)

Arduino as slave with multiple i2c addresses

I would like to use an Arduino as an i2c slave. But I require that the Arduino acts as multiple devices by registering itself with multiple i2c addresses.
This is probably not something one would normally do, but here is my reason for doing it:
I want to use an Arduino to act as Telemetry sensors for Spektrum Telemetry. The Telemetry receiver has a few i2c plugs which connects to multiple sensors (current 0x02, voltage 0x03, airspeed 0x11, etc) each that have a fixed i2c address which the Telemetry receiver expects.
I would like to use one Arduino to act as all these devices by registering itself with all of the above addresses, and responding appropriately with the readings.
I could use one Arduino per sensor, which seems silly as I can perform all these readings with one Arduino pro-mini.
I know you can register the Arduino using
Wire.begin(0x02);
But I require something similar to this (pseudo code)
Wire.begin(0x02, 0x03, 0x11);
And when a request is received, I need to know with what address the Arduino was queried.
For example (pseudo code)
void receiveEvent(byte address, int bytesReceived){
if(address == 0x02){
// Current reading
}
else if(address == 0x03){
// Voltage reading
}
else if(address == 0x11){
// Airspeed reading
}
}
Any advice would be appreciated.
It is not possible to make the Arduino listen to to multiple slave addresses by using the Wire library since Wire.begin() only allows to pass a single slave address.
Even the Atmel ATmega microcontroller on which most Arduinos are based only allows its hardware 2-wire serial interface (TWI) to be set to a single 7-bit address via its 2-wire address register TWAR. However, it is possible to work around this limitation by masking one or more address bits using the TWI address mask register TWAMR as documented (somewhat briefly) in e.g. this ATmega datasheet section 22.9.6:
The TWAMR can be loaded with a 7-bit Salve (sic!) Address mask. Each of the bits in TWAMR can mask (disable) the corresponding address bits in the TWI address Register (TWAR). If the mask bit is set to one then the address match logic ignores the compare between the incoming address bit and the corresponding bit in TWAR.
So we would first have to set up the mask bits based on all I2C addresses we want to respond to by OR'ing them and shifting right to match the TWAMR register layout (TWAMR holds mask in bit7:1, bit0 is unused):
TWAMR = (sensor1_addr | sensor2_addr | sensor3_addr) << 1;
The main problem from here on will be to find out which particular I2C address was queried (we only know it was one that matches the address mask).
If I interpret section 22.5.3 correctly, stating
The TWDR contains the address or data bytes to be transmitted, or the address or data bytes received.
we should be able to retrieve the unmasked I2C address from the TWDR register.
ATmega TWI operation is interrupt-based, more specifically, it utilizes a single interrupt vector for a plethora of different TWI events indicated by status codes in the TWSR status register.
In the TWI interrupt service routine, we'll have to
make sure the reason why we've entered the ISR is because we've been queried. This can be done by checking TWSR for status code 0xA8 (own SLA+R has been received)
decide which sensor data to send back to the master based on what I2C address was actually queried by checking the last byte on the bus in TWDR.
This part of the ISR could look something like this (untested):
if (TWSR == 0xA8) { // read request has been received
byte i2c_addr = TWDR >> 1; // retrieve address from last byte on the bus
switch (i2c_addr) {
case sensor1_addr:
// send sensor 1 reading
break;
case sensor2_addr:
// send sensor 2 reading
break;
case sensor3_addr:
// send sensor 3 reading
break;
default:
// I2C address does not match any of our sensors', ignore.
break;
}
}
Thanks for asking this interesting question!
I really do like vega8's answer, but I'd also like to mention that if your I2C master isn't going to clock things incredibly fast, using a software-based implementation of I2C would also be feasible and give you the freedom you want.
You might want to consider that approach if rough calculation shows that the time spent in the TWI ISR is too high and interrupts might start to overlap.
void setup()
{
Wire.begin(0x11 | 0x12); // Adr 11 and 12 are used for Alt and Speed by Spectrum DX
Wire.onRequest(requestEvent); // register callback function
TWAMR = (0x11 | 0x12) << 1; // set filter for given adr
}
void requestEvent() {
int adr = TWDR >> 1; // move 1 bit to align I2C adr
if (adr == 0x12) // check for altitude request at adr 12
Wire.write(tmpSpektrumDataAlt, 16); // send buffer
if (adr == 0x11) // check for speed request at adr 11
Wire.write(tmpSpektrumDataSpd, 16); // send buffer
}
This works with a Spectrum DX8 with telemetry module.
The Spectrum interface was made public on Sectrums home page. Technical documents.
There could be other devices on the I2C bus, the TWAMR should be set with as less bits as possible. So I think the better way to calculate the mask is:
AddrOr = Addr1 | Addr2 | Addr3 | Addr4 ...
AddrAnd = Addr1 & Addr2 & Addr3 & Addr4 ...
TWAMR = (AddrOr ^ AddrAnd) << 1
while TWAR can be set as either AddrOr or AddrAnd
In this way we can limit the possibility of address conflict to the minimum

Reading a long text from GPRS Shield with Arduino

I am having hell with this and I know it is probably really simple. I am trying to read a text message from my Seeed GPRS shield. I have the shield setup as a software serial and I am displaying the information received from the GPRS to the serial monitor. I am currently sending all AT commands over serial while I work on my code. To display the data from the software serial to the serial monitor, I am using the following code.
while(GPRS.available()!=0) {
Serial.write(GPRS.read());
}
GPRS is my software serial obviously. The problem is, the text is long and I only get a few characters from it. Something like this.
+CMGR: "REC READ","1511","","13/12/09,14:34:54-24" Welcome to TM eos8
This text is a "Welcome to T-Mobile" text that is much longer. The last few characters shown are scrambled. I have done some research and have seen that I can mod the serial buffer size to 256 instead of the default 64. I want to avoid this because I am sure there is an easier way. Any ideas?
Have you tried reading into a character array, one byte at a time? See if this helps:
if (GPRS.available()) { // GPRS talking ..
while(GPRS.available()) { // As long as it is talking ..
buffer[count++]=GPRS.read();     
// read char into array
if(count == 64) break; // Enough said!
}
Serial.write(buffer,count); // Display in Terminal
clearBufferArray();
count = 0;
}
You need to declare the variables 'buffer' and 'count' appropriately and define the function 'clearBufferArray()'
Let me know if this helps.
Looks like this is simply the result of the lack of flow control in all Arduino serial connections. If you cannot pace your GPRS() input byte sequence to a rate that guarantees the input FIFO can't overflow, then your Serial.write() will block when the output FIFO fills. At that point you will be dropping new GPRS input bytes on the floor until Serial output frees up more space.
Since the captured output is apparently clean up to about 64 bytes, this suggests
a) a 64 byte buffer,
b) a GPRS data rate much higher than the Serial one, and
c) that the garbage data is actually the occasional valid byte from later in the sequence.
You might confirm this by testing the return code from Serial.write. If you get back zero, that byte is getting lost.
If you were using 9600 for Serial and 57600 for GPRS, I would expect somewhat more than 64 bytes to come through before the output gets mangled, but if the GPRS rate is more than 64x the Serial rate, the entire output FIFO could fill up within a single output byte transmission time.
Capturing to an intermediate buffer should resolve your issue, as long as it is large enough for the whole message. Similarly, extending the size of either the source (in conjunction with testing the Serial.write) or destination (without any additional code) FIFOs to the maximum datagram size should work.
I've had the same problem trying to read messages and get 64 characters. I overcame it by adding a "delay(10)" in the loop calling the function that does the read from the GPRS. Seems to be enough to overcome the race scenario. - Using Arduino Mega.
void loop() {
ReadmyGPRS();
delay(10); //A race condition exists to get the data.
}
void ReadmyGPRS(){
if (Serial1.available()){ // if data is comming from GPRS serial port
count = 0; // reset counter
while(Serial1.available()) // reading data into char array
{
buffer[count++]=Serial1.read(); // writing data into array
if(count == 160)break;
}
Serial.write(buffer,count);
}
}

Simple algorithm for reliable communications

So, I have worked on large systems in the past, like an iso stack session layer, and something like that is too big for what I need, but I do have some understanding of the big picture. What I have now is a serial point to point communications link, where some component is dropping data (often).
So I am going to have to write my own, reliable delivery system using it for transport. Can someone point me in the directions for basic algorithms, or even give a clue as to what they are called? I tried a Google, but end up with post graduate theories on genetic algorithms and such. I need the basics. e.g. 10-20 lines of pure C.
XMODEM. It's old, it's bad, but it is widely supported both in hardware and in software, with libraries available for literally every language and market niche.
HDLC - High-Level Data Link Control. It's the protocol which has fathered lots of reliable protocols over the last 3 decades, including the TCP/IP. You can't use it directly, but it is a template how to develop your own protocol. Basic premise is:
every data byte (or packet) is numbered
both sides of communication maintain locally two numbers: last received and last sent
every packet contains the copy of two number
every successful transmission is confirmed by sending back an empty (or not) packet with the updated numbers
if transmission is not confirmed within some timeout, send again.
For special handling (synchronization) add flags to the packet (often only one bit is sufficient, to tell that the packet is special and use). And do not forget the CRC.
Neither of the protocols has any kind of session support. But you can introduce one by simply adding another layer - a simple state machine and a timer:
session starts with a special packet
there should be at least one (potentially empty) packet within specified timeout
if this side hasn't sent a packet within the timeout/2, send an empty packet
if there was no packet seen from the other side of communication within the timeout, the session has been termianted
one can use another special packet for graceful session termination
That is as simple as session control can get.
There are (IMO) two aspects to this question.
Firstly, if data is being dropped then I'd look at resolving the hardware issues first, as otherwise you'll have GIGO
As for the comms protocols, your post suggests a fairly trivial system? Are you wanting to validate data (parity, sumcheck?) or are you trying to include error correction?
If validation is all that is required, I've got reliable systems running using RS232 and CRC8 sumchecks - in which case this StackOverflow page probably helps
If some components are droping data in a serial point to point link, there must exist some bugs in your code.
Firstly, you should comfirm that there is no problem in the physical layer's communication
Secondly, you need some konwledge about data communication theroy such like ARQ(automatic request retransmission)
Further thoughts, after considering your response to the first two answers... this does indicate hardware problems, and no amount of clever code is going to fix that.
I suggest you get an oscilloscope onto the link, which should help to determine where the fault lies. In particular look at the baud rate of the two sides (Tx, Rx) to ensure that they are within spec... auto-baud is often a problem?!
But look to see if drop out is regular, or can be sync-ed with any other activity.
on the sending side;
///////////////////////////////////////// XBee logging
void dataLog(int idx, int t, float f)
{
ubyte stx[2] = { 0x10, 0x02 };
ubyte etx[2] = { 0x10, 0x03 };
nxtWriteRawHS(stx, 2, 1);
wait1Msec(1);
nxtWriteRawHS(idx, 2, 1);
wait1Msec(1);
nxtWriteRawHS(t, 2, 1);
wait1Msec(1);
nxtWriteRawHS(f, 4, 1);
wait1Msec(1);
nxtWriteRawHS(etx, 2, 1);
wait1Msec(1);
}
on the receiving side
void XBeeMonitorTask()
{
int[] lastTick = Enumerable.Repeat<int>(int.MaxValue, 10).ToArray();
int[] wrapCounter = new int[10];
while (!XBeeMonitorEnd)
{
if (XBee != null && XBee.BytesToRead >= expectedMessageSize)
{
// read a data element, parse, add it to collection, see above for message format
if (XBee.BaseStream.Read(XBeeIncoming, 0, expectedMessageSize) != expectedMessageSize)
throw new InvalidProgramException();
//System.Diagnostics.Trace.WriteLine(BitConverter.ToString(XBeeIncoming, 0, expectedMessageSize));
if ((XBeeIncoming[0] != 0x10 && XBeeIncoming[1] != 0x02) || // dle stx
(XBeeIncoming[10] != 0x10 && XBeeIncoming[11] != 0x03)) // dle etx
{
System.Diagnostics.Trace.WriteLine("recover sync");
while (true)
{
int b = XBee.BaseStream.ReadByte();
if (b == 0x10)
{
int c = XBee.BaseStream.ReadByte();
if (c == 0x03)
break; // realigned (maybe)
}
}
continue; // resume at loop start
}
UInt16 idx = BitConverter.ToUInt16(XBeeIncoming, 2);
UInt16 tick = BitConverter.ToUInt16(XBeeIncoming, 4);
Single val = BitConverter.ToSingle(XBeeIncoming, 6);
if (tick < lastTick[idx])
wrapCounter[idx]++;
lastTick[idx] = tick;
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => DataAdd(idx, tick * wrapCounter[idx], val)));
}
Thread.Sleep(2); // surely we can up with the NXT
}
}

Resources