Why are data packets missing in Zigbee arduino setup? - api

I made a setup which consists of 3 Zigbee's, 2 routers(Zigbee S2C's) and 1 coordinator(Zigbee S2). The routers are each connected to arduino nano which collects data from 2 FSR's and an IMU(frame type: zigbee transmit request and packet size 46 bytes) and sends it to the Coordinator attached to an arduino UNO. All the Xbees are in API mode 2 and working at a baud rate of 115200. I am using a library called "Simple Zigbee Library" to send all the collected data to the Coordinator. The collection and sending of data works fine except that there are packets lost in the way. The nano's sample data at a frequency of around 25Hz independently. The coordinator tries to read the data send from the zigbees(using the library of course) in every loop, but unfortunately, it seems to receive only around 40-45 samples.(Should have been 25*2=50 samples total from the 2 xbees). Can anybody suggest why this is happening. I need as less data loss as possible for my setup to achieve its motive. Any kind of help is appreciated.
P.S: It may be important to mention that the coordinator is reading the data only from one xbee in each loop.
As can be seen under the "Source" heading of this image of data received by the coordinator, "19" and "106" are the addresses of the routers and there are data packets dropped intermittently
Thank you.
void setup()
{
// Start the serial ports ...
Serial.begin( 115200 );
while( !Serial ){;} // Wait for serial port (for Leonardo only).
xbeeSerial.begin( 115200 );
// ... and set the serial port for the XBee radio.
xbee.setSerial( xbeeSerial );
// Set a non-zero frame id to receive Status packets.
xbee.setAcknowledgement(true);
}
void loop()
{
// While data is waiting in the XBee serial port ...
while( xbee.available() )
{
// ... read the data.
xbee.read();
// If a complete message is available, display the contents
if( xbee.isComplete() ){
Serial.print("\nIncoming Message: ");
printPacket( xbee.getIncomingPacketObject() );
}
}
delay(10); // Small delay for stability
// That's it! The coordinator is ready to go.
}
// Function for printing the complete contents of a packet //
void printPacket(SimpleZigBeePacket & p)
{
//Serial.print( START, HEX );
//Serial.print(' ');
//Serial.print( p.getLengthMSB(), HEX );
//Serial.print(' ');
//Serial.print( p.getLengthLSB(), HEX );
//Serial.print(' ');
// Frame Type and Frame ID are stored in Frame Data
uint8_t checksum = 0;
for( int i=10; i<p.getFrameLength(); i++){
Serial.print( p.getFrameData(i), HEX );
Serial.print(' ');
checksum += p.getFrameData(i);
}
// Calculate checksum based on summation of frame bytes
checksum = 0xff - checksum;
Serial.print(checksum, HEX );
Serial.println();
}

Although you claim to be using 115,200bps, posted code shows you opening the serial ports at 9600 baud, definitely not fast enough for 2500 bytes/second (50 packets/second * 45 bytes/packet * 110% for overhead) received from XBee and dumped by printPacket()). Remember that 802.15.4 is always 250kbps over the air, and the XBee module's serial port configuration is just for local communications with the host.
Make sure your routers are sending unicast (and not broadcast) packets to keep the radio traffic down.
You should verify that sending is working before troubleshooting code on the coordinator. Update the code on your routers to see if you get a successful Transmit Status packet for every packet sent. Aiming for 50Hz seems like a bit much -- you're trying to send 45 bytes (is that the full size of the API frame?) every 20ms.
Are you using a hardware serial port on the Arduino for both the XBee module and Serial.print()? How much time does each call to printPacket() take? If you reduce the code in printPacket() to a bare minimum (last byte of sender's address and the 1-byte frame ID), do you see all packets come through (an indication that you're spending too much time dumping the packets).

I'm concerned with the code you're using in loop. I don't know the deep internals of how the Arduino works, but does that 10ms delay block other code from processing data? What if you simplify it:
void loop()
{
xbee.read();
// Process any complete frames.
while (xbee.isComplete()){
Serial.print("\nIncoming Message: ");
printPacket( xbee.getIncomingPacketObject() );
}
}
But before going too far, you should isolate the problem would by connecting the coordinator to a terminal emulator on a PC to monitor the frame rate. If all frames arrive then there's an issue on the coordinator. If they don't, work on your router code first.

Related

GPS data blocked by other tasks in the while loop

I am trying to parse GPS data while reading pressure sensor, IMU sensor and writing some data to SD card. Since reading pressure sensor, IMU sensor and writing SD card takes some time and GPS don't wait my command to send its data, I lost some GPS data so my parser can not find meaningful message. I use uart_receive interrupt to take GPS data and circular buffer to save its data. After I parse it. Since I don't know how much bytes come from GPS, I read one by one. I tried FreeRTOS but it did not work. How can I prevent other tasks to block GPS data. I am using STM32f401cc.
Here is my FreeRTOS task;
void StartDefaultTask(void* argument)
{
IMU_setParameters(&imu, &hi2c1, imu_ADD_LOW, GPIOB, GPIOB,
GPIO_PIN_1, GPIO_PIN_2);
IMU_init(&imu, &htim3);
while ((calState.accel != 3 || calState.system != 3 || calState.gyro != 3 || calState.mag != 3) && calibFlg)
{
IMU_getCalibrationState(&imu, &calState);
}
preSensor_init_default_params(&preSensor.params);
preSensor.addr = preSensor_I2C_ADDRESS_1;
preSensor.i2c = &hi2c1;
preSensor_init(&preSensor, &preSensor.params);
initSD_CARD(&USERFatFS, USERPath);
samplePacket(&telemetry);
controlRecoveryFile(&recoveryFile, "recoveryFile.txt", &telemetry);
for (;;)
{
IMU_getDatas(&imu, &calState, &linearAccel, &IMU, &imuFlg, &offsetFlg, &calibCount);
preSensor_force_measurement(&preSensor);
preSensor_read_float(&preSensor, &temperature, &pressure, &humidty);
preSensor_get_height(pressure, &height);
telemetry.Altitude_PL = height;
telemetry.Pressure_PL = pressure;
telemetry.Temperature = temperature;
telemetry.YRP[0] = IMU.yaw;
telemetry.YRP[1] = IMU.roll;
telemetry.YRP[2] = IMU.pitch;
if (calibCount % 10 == 0)
{
writoToTelemetryDatas(&logFile, "tulparLog.txt", &telemetry, 0);
if (!writeToRecoveryDatas(&recoveryFile, "recoveryFile.txt", &telemetry))
connectionFlg = 1;
}
osDelay(1);
}
}
void StartTask02(void* argument)
{
arrangeCircularBuffer(&gpsCircular, buffer, BUFFER_LENGTH);
initGPS(&huart1, &rDATA, &gps);
for (;;)
{
getGPSdata(&huart1, &gpsCircular, &gps, &rDATA);
osDelay(1);
}
}
Here is my solution to problem.
First of all I do not use FreeRtos at all. I do all the thing in main loop. Problem is "Race Condition". In my GPS data parser, there are 4 states. MSG_ID, Finish, Check, Parse. These four states do not take four loops to find meaningfull message. It depends on message length. It can be at most 103 loop. Besides, In main loop my imu sensor, pressure sensor and SD card module takes approximately 80 ms. As you know, GPS works independent from our code. It does not wait our command to send data. Every 1 second it sends its datas. Now, imagine that your GPS sends datas every 1 seconds and your CircularBuffer has 200 bytes. Your parser begin to parse message. But your parser needs at least 30+ loops to find message. Now, 30*80 = 2400 ms (2.4 s). Untill you find meaningfull data GPS sent 2 more datas and overflow happened. To fix this situation, I write for loop for my GPS parser in the main loop and I send command to GPS for just taking GPGGA and GPRMC datas (for GPS command you can look at here. I use uart_receive_ınterrupt to store data to my circularbuffer. After taking 2 '\n', I stop taking data and wait my parser to parse these datas. At the end I start uart operation taking meaningfull datas. Important thing here is calling parser in a for loop. (it can be 8-16-24 loops depends on your other tasks delay)

Openthread CLI UDP communication from main.c (NRF52840)

We are working with NRF52840 dongles and want to be able to have them relay data over an OpenThread mesh network through UDP automatically. We have found within the OpenThread API a solid Udp.h library with all the Udp functions we need to create code that runs on the dongles from the main.c.
Below is our code that should broadcast the message: "Hallo" to all nodes that have an open socket on port 1994.
We have read that the ipv6 address ff03::1 is reserved for multicast UDP broadcasting and it works perfectly when manually performed with the CLI udp commands.
CLI: Udp open, udp send ff03::1 1994 Hallo
With all the nodes that have udp open, udp bind :: 1994, receiving the Hallo message from the sending node.
We are trying to recreate this in the main.c of our nodes so that we can provide the nodes with some intelligence of their own.
This piece of code is run once when the push button on the dongle is pressed.
The code compiles perfectly and we have tested the functions that have a return with the RGB led (green OK, red not) to confirm that there weren't any errors produced (sadly not all functions return a no_error value)
void udpSend(){
const char *buf = "Hallo";
otMessageInfo messageInfo;
otInstance *myInstance;
myInstance = thread_ot_instance_get();
otUdpSocket mySocket;
memset(&messageInfo, 0, sizeof(messageInfo));
// messageInfo.mPeerAddr = otIp6GetUnicastAddresses(myInstance)->mNext->mNext->mAddress;
otIp6AddressFromString("ff03::1", &messageInfo.mPeerAddr);
messageInfo.mPeerPort = 1994;
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
otUdpOpen(myInstance, &mySocket, NULL, NULL);
otMessage *test_Message = otUdpNewMessage(myInstance, NULL);
otMessageSetLength(test_Message, sizeof(buf));
if (otMessageAppend(test_Message, &buf, sizeof(buf)) == OT_ERROR_NONE){
nrf_gpio_pin_write(LED2_G, 0);
}
else{
nrf_gpio_pin_write(LED2_R, 0);
}
otUdpSend(&mySocket, test_Message, &messageInfo);
otCliUartOutputFormat("Done.\0");
otUdpClose(&mySocket);
}
Now, we aren't exactly experts, so we are not sure why this isn't working as we had a lot of trouble figuring out how everything is called/initialised.
We hope to create a way to send and receive data through UDP through the code, so that they can operate autonomously.
We would really appreciate it if someone could assist us with our project!
Thanks!
Jonathan
There are a few errors in your code:
Remove the call to otMessageSetLength(). The message length is automatically increased as part of otMessageAppend().
The call to otMessageAppend() should be: otMessageAppend(test_message, buf, (uint16_t)strlen(buf)).
Removed the & before buf.
Replaced sizeof() with strlen().
Couple other things you should consider:
After calling otUdpNewMessage(), if any following call returns an error, make sure to call otMessageFree() on the message buffer.
Custody is only given to OpenThread after a successful call to otUdpSend().
Do not call udpSend() from interrupt context.
OpenThread library was designed to assume a single thread of execution.
Hope that helps.

GP-635T GPS module dropping data

I have a GP-635T GPS module attached to my Arduino UNO (GPS TX->UNO RX[Pin 0]) using Serial.
Then I just read the incoming data byte for byte adding them to a string as they are read and when I reach a newline character(13) I just print the complete String of data and reset the data String for the next run.
Code:
void setup()
{
Serial.begin(9600);
Serial.println("Initialized Serial port..");
}
String data = "";
void loop()
{
while(Serial.available())
{
char gpsByte = Serial.read();// Read a byte from the GPS
data += gpsByte;
if(gpsByte == 13){
Serial.print(data);
data = "";
}
}
delay(100);
}
This code works as it is. But the problem here is the data I get from it.
The module prints out multiple datalines at 1Hz using the NMEA-0183 standard. I do not have any idea how it decides what to print when because the data is not consistent for more than 5 "prints" of the (almost)complete dataset.
Ex:
$GPGGA,213948.00,,,,,0,00,99.99,,,,,,*63
$GPGSA,A30 <--- A30?
$GPGSV,1,1,01,29,,,30*70
$GPGLL,,,,,213948.00,V,N*4F
$GPRMC,213949.00,V,,,,,,,290314,,,N*74
$GPVTG,,,,,,,,,N*30
$GPGGA,213949.00,,,,,0,00,99.99,,,,,,*62
$GPGSA,A,1,,,,PGSV,1,1,01,29,,,30*70 <--- PGSV?
$GPGLL,,,,,213949.00,V,N*4E
$GPRMC,213950.00,V,,,,,,,290314,,,N*7C
$GPVTG,,,,,,,,,N*30
$GPGGA,213950.00,,,,,0,00,99.99,,,,,,*6A
...
$GPGGA,214045SA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,01,29,,,30*70$GPRMC,214046.00,V,,,,,,,290314,,,N*75 <--- Missing linebreak?
$GPVTG,,,,,,,,,N*30
$G00,99.99,,,,,,*63 <--- $G00??
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,02,20,,,27,29,,,30*74
$GPGLL,$GPRMC,214047.00,V,,,,,,,290314,,,N*74 <--- Missing data?
$GPVTG,,,,,,,,,N*30
$GPGGA,214047.00,,,,,0,00,99.99,,,,,,*62
$,99.99*30 <--- Alot of missing data
I think you get the point, I have nothing but the GPS connected to the Arduino.
I have tried with sending the data wirelessly with some wireless modules with no change.
I have tried with using AltSoftSerial and SoftwareSerial but I got messier data with the latter.
I have tried different baud rates with no luck.
Does anyone have any idea as to why this is happening? The module is brand new and I have no idea why it would behave like this.
NOTE: I do not have a very good GPS signal to my module from within my house, I did try going outside with it and see if I could get a signal which I did from about 3 satellites, but that didn't change the output.
Well this was a very strange problem, The problem did go away when I shortened the delay from 100ms to 10ms.
It might have to do something with the buffer and maybe it just gets overflowed before I start reading bytes from it.
However if someone else have got this same problem, shorten the loop delay and you should be fine!

Serial communication error in objective-C: Resource busy

I'm writing some code which purpose is to read values send by an ECG.
The ECG sends values read by it's sensors through a serial connection and (as a start) all the program has to do is read the input and display it in a text view.
However I have hit a wall and can't seem to solve the following two problems:
I get the following error a lot of the times I try to connect with the ECG: Unable to open /dev/tty.usbserial.A700eLwM - : Resource busy.
The port is not being used by any other applications but the ECG is sending numbers.
Can I somehow tell the OS that whatever is happening and whoever is using that port I want to have full control of the port?
My code is as follows:
fd = open("/dev/tty.usbserial-A700eLwM", O_RDWR | O_NOCTTY | O_NDELAY);
[textView insertText:[NSString stringWithFormat:#"Port status: %f\n", fd]];
if (fd == -1)
{
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/tty.usbserial.A700eLwM - ");
}
else {
fcntl(fd, F_SETFL, 0);
}
My second problem is that I don't quite understand how I can buffer the reading into a string or integer variable and send it to the text view.
Any help will be appreciated
Thanks in advance
The most likely reason is that you've activated the serial port as a network device in Network Preferences. If it's listed there, select it and use the cogwheel menu item "mark as inactive".
For your second problem there's a lot of other matching questions on the site, search for it.

Detecting open PC COM port from USB Virtual Com Port device

I am using an STM32F105 microcontroller with the STM32_USB-FS-Device_Lib_V3.2.1 USB library and have adapted the VCP example for our purposes (integration with RTOS and serial API).
The problem is that if the USB cable is attached, but the port is not open on the Windows host, after a few minutes the device ends up permanently re-entering the USB ISR until the port is opened and then it all starts working normally.
I have instrumented interrupt handler and can see that when the fault occurs, the ISR handler exits and then immediately re-enters. This occurs because on exit from the interrupt the IEPINT flag in OTG_FS_GINTSTS is not clear. The OTG_FS_DAINT at this time contains 0x00000002 (IEPINT1 set), while DIEPINT1 has 0x00000080 (TXFE). The line in OTGD_FS_Handle_InEP_ISR() that clears TXFE is called, but the bit either does not clear or becomes immediately reasserted. When the COM port on the host is reopened, the state of OTG_FS_GINTSTS and OTG_FS_DAINT at the end of the interrupt is always zero, and further interrupts occur at the normal rate. Note that the problem only occurs if data is being output but the host has no port open. If either the port is open or no data is output, the system runs indefinitely. I believe that the more data that is output the sooner the problem occurs, but that is anecdotal at present.
The VCP code has a state variable that takes the following enumerated values:
UNCONNECTED,
ATTACHED,
POWERED,
SUSPENDED,
ADDRESSED,
CONFIGURED
and we use the CONFIGURED state to determine whether to put data into the driver buffer for sending. However the CONFIGURED state is set when the cable is attached not when the host has the port open and an application connected. I see that when Windows does open the port, there is a burst of interrupts so it seems that some communication occurs on this event; I wonder if it is possible therefore to detect whether the host has the port open,.
I need one of two things perhaps:
To prevent the USB code from getting stuck in the ISR in the first instance
To determine whether the host has the port open from the device end, and only push data for sending when open.
Part (1) - preventing the interrupt lock-up - was facilitated by a USB library bug fix from ST support; it was not correctly clearing the TxEmpty interrupt.
After some research and assistance from ST Support, I have determined a solution to part (2) - detecting whether the host port is open. Conventionally, when a port is opened the DTR modem control line is asserted. This information is passed to a CDC class device, so I can use this to achieve my aim. It is possible for an application to change the behaviour of DTR, but this should not happen in any of the client applications that are likely to connect to this device in this case. However there is a back-up plan that implicitly assumes the port to be open if the line-coding (baud, framing) are set. In this case there is no means of detecting closure but at least it will not prevent an unconventional application from working with my device, even if it then causes it to crash when it disconnects.
Regarding ST's VCP example code specifically I have made the following changes to usb_prop.c:
1) Added the following function:
#include <stdbool.h>
static bool host_port_open = false ;
bool Virtual_Com_Port_IsHostPortOpen()
{
return bDeviceState == CONFIGURED && host_port_open ;
}
2) Modified Virtual_Com_Port_NoData_Setup() handling of SET_CONTROL_LINE_STATE thus:
else if (RequestNo == SET_CONTROL_LINE_STATE)
{
// Test DTR state to determine if host port is open
host_port_open = (pInformation->USBwValues.bw.bb0 & 0x01) != 0 ;
return USB_SUCCESS;
}
3) To allow use with applications that do not operate DTR conventionally I have also modified Virtual_Com_Port_Data_Setup() handling of SET_LINE_CODING thus:
else if (RequestNo == SET_LINE_CODING)
{
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
{
CopyRoutine = Virtual_Com_Port_SetLineCoding;
// If line coding is set the port is implicitly open
// regardless of host's DTR control. Note: if this is
// the only indicator of port open, there will be no indication
// of closure, but this will at least allow applications that
// do not assert DTR to connect.
host_port_open = true ;
}
Request = SET_LINE_CODING;
}
I found another solution by adopting CDC_Transmit_FS.
It can now be used as output for printf by overwriting _write function.
First it checks the connection state, then it tries to send over USB endport in a busy loop, which repeats sending if USB is busy.
I found out if dev_state is not USBD_STATE_CONFIGURED the USB plug is disconnected. If the plug is connected but no VCP port is open via PuTTY or termite, the second check fails.
This implementation works fine for me for RTOS and CubeMX HAL application. The busy loop is not blocking low priority threads anymore.
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
// Check if USB interface is online and VCP connection is open.
// prior to send:
if ((hUsbDevice_0->dev_state != USBD_STATE_CONFIGURED)
|| (hUsbDevice_0->ep0_state == USBD_EP0_STATUS_IN))
{
// The physical connection fails.
// Or: The phycical connection is open, but no VCP link up.
result = USBD_FAIL;
}
else
{
USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);
// Busy wait if USB is busy or exit on success or disconnection happens
while(1)
{
//Check if USB went offline while retrying
if ((hUsbDevice_0->dev_state != USBD_STATE_CONFIGURED)
|| (hUsbDevice_0->ep0_state == USBD_EP0_STATUS_IN))
{
result = USBD_FAIL;
break;
}
// Try send
result = USBD_CDC_TransmitPacket(hUsbDevice_0);
if(result == USBD_OK)
{
break;
}
else if(result == USBD_BUSY)
{
// Retry until USB device free.
}
else
{
// Any other failure
result = USBD_FAIL;
break;
}
}
}
return result;
}
CDC_Transmit_FS is used by _write:
// This function is used by printf and puts.
int _write(int file, char *ptr, int len)
{
(void) file; // Ignore file descriptor
uint8_t result;
result = CDC_Transmit_FS((uint8_t*)ptr, len);
if(result == USBD_OK)
{
return (int)len;
}
else
{
return EOF;
}
}
Regards
Bernhard
After so much searching and a kind of reverse engineering I finally found the method for detecting the open terminal and also it's termination. I found that in the CDC class there is three Data nodes , one is a control node and the other two are data In and data Out nodes.Now when you open a terminal a code is sent to the control node and also when you close it. all we need to do is to get those codes and by them start and stop our data transmission tasks. the code that is sent is respectively 0x21 and 0x22 for opening and closing the terminal.In the usb_cdc_if.c there is a function that receive and interpret those codes (there is a switch case and the variable cmd is the code we are talking about).that function is CDC_Control_FS . Here we are, Now all we need to do is to expand that function so that it interpret the 0x22 and 0x21 . there you are , now you know in your application whether the port is open or not.
I need one of two things perhaps:
To prevent the USB code from getting stuck in the ISR in the first instance
To determine whether the host has the port open from the device end, and only push data for sending when open.
You should attempt to do option 1 instead of 2. On Windows and Linux, it is possible to open a COM port and use it without setting the control signals, which means there is no fool-proof, cross-platform way to detect that the COM port is open.
A well programmed device will not let itself stop functioning just because the USB host stopped polling for data; this is a normal thing that should be handled properly. For example, you might change your code so that you only queue up data to be sent to the USB host if there is buffer space available for the endpoint. If there is no free buffer space, you might have some special error handling code.
I have the same requirement to detect PC port open/close. I have seen it implemented it as follows:
Open detected by:
DTR asserted
CDC bulk transfer
Close detected by:
DTR deasserted
USB "unplugged", sleep etc
This seems to be working reasonably well, although more thorough testing will be needed to confirm it works robustly.
Disclaimer: I use code generated by Cube, and as a result it works with HAL drivers. Solutions, proposed here before, don't work for me, so I have found one. It is not good, but works for some purposes.
One of indirect sign of not opened port arises when you try to transmit packet by CDC_Transmit_FS, and then wait till TxState is set to 0. If port is not opened it never happens. So my solution is to fix some timeout:
uint16_t count = 0;
USBD_CDC_HandleTypeDef *hcdc =
(USBD_CDC_HandleTypeDef*) USBD_Device.pClassData;
while (hcdc->TxState != 0) {
if (++count > BUSY_TIMEOUT) { //number of cycles to wait till it makes decision
//here it's clear that port is not opened
}
}
The problem is also, that if one tries to open port, after device has tried to send a packet, it cant be done. Therefore whole routine I use:
uint8_t waitForTransferCompletion(void) {
uint16_t count = 0;
USBD_CDC_HandleTypeDef *hcdc =
(USBD_CDC_HandleTypeDef*) USBD_Device.pClassData;
while (hcdc->TxState != 0) {
if (++count > BUSY_TIMEOUT) { //number of cycles to wait till it makes decision
USBD_Stop(&USBD_Device); // stop and
MX_USB_DEVICE_Init(); // init device again
HAL_Delay(RESET_DELAY); // give a chance to open port
return USBD_FAIL; // return fail, to send last packet again
}
}
return USBD_OK;
}
The question is, how big timeout has to be, not to interrupt transmission while port is opened. I set BUSY_TIMEOUT to 3000, and now it works.
I fixed it by checking of a variable hUsbDeviceFS.ep0_state.
It equal 5 if connected and 4 if do not connected or was disconnected.
But. There are some issue in the HAL. It equal 5 when program started.
Next steps fixed it at the begin of a program
/* USER CODE BEGIN 2 */
HAL_Delay(500);
hUsbDeviceFS.ep0_state = 4;
...
I do not have any wishes to learn the HAL - I hope this post will be seeing by developers and they will fix the HAL.
It helped me to fix my issue.