microchip, Generic tcp server - tcp

I'm very new to the Microchip line and I'm currently using the Pic32 Ethernet Starter Kit 2. I've been playing and testing all aspects of this product and I'm currently working with the Generic TCPIP Servo demo from Harmony. I can load the app on the Chip and log into it with Telnet. I can also see it working if I type in say "h" it will echo back "hH" as it should. Because in this demo it runs a ToUpper line on it. What I'm looking to try is to type "hello" in telnet then have it send back "World" Just something simple to get me rolling with this. Below is the current section of code that reads the incoming data converts it to Upper and sends back out.
case APP_TCPIP_SERVING_CONNECTION:
{
if (!TCPIP_TCP_IsConnected(appData.socket))
{
appData.state = APP_TCPIP_CLOSING_CONNECTION;
SYS_CONSOLE_MESSAGE("Connection was closed\r\n");
break;
}
int16_t wMaxGet, wMaxPut, wCurrentChunk;
uint16_t w, w2;
uint8_t AppBuffer[32];
//uint8_t AppBuffer2[] = "This is a Test";
// Figure out how many bytes have been received and how many we can transmit.
wMaxGet = TCPIP_TCP_GetIsReady(appData.socket); // Get TCP RX FIFO byte count
wMaxPut = TCPIP_TCP_PutIsReady(appData.socket); // Get TCP TX FIFO free space
// Make sure we don't take more bytes out of the RX FIFO than we can put into the TX FIFO
if(wMaxPut < wMaxGet)
wMaxGet = wMaxPut;
// Process all bytes that we can
// This is implemented as a loop, processing up to sizeof(AppBuffer) bytes at a time.
// This limits memory usage while maximizing performance. Single byte Gets and Puts are a lot slower than multibyte GetArrays and PutArrays.
wCurrentChunk = sizeof(AppBuffer);
for(w = 0; w < wMaxGet; w += sizeof(AppBuffer))
{
// Make sure the last chunk, which will likely be smaller than sizeof(AppBuffer), is treated correctly.
if(w + sizeof(AppBuffer) > wMaxGet)
wCurrentChunk = wMaxGet - w;
// Transfer the data out of the TCP RX FIFO and into our local processing buffer.
TCPIP_TCP_ArrayGet(appData.socket, AppBuffer, wCurrentChunk);
// Perform the "ToUpper" operation on each data byte
for(w2 = 0; w2 < wCurrentChunk; w2++)
{
i = AppBuffer[w2];
if(i >= 'a' && i <= 'z')
{
i -= ('a' - 'A');
AppBuffer[w2] = i;
}
else if(i == '\e') //escape
{
appData.state = APP_TCPIP_CLOSING_CONNECTION;
SYS_CONSOLE_MESSAGE("Connection was closed\r\n");
}
}
// Transfer the data out of our local processing buffer and into the TCP TX FIFO.
SYS_CONSOLE_PRINT("Server Sending %s\r\n", AppBuffer);
TCPIP_TCP_ArrayPut(appData.socket, AppBuffer, wCurrentChunk);
// No need to perform any flush. TCP data in TX FIFO will automatically transmit itself after it accumulates for a while. If you want to decrease latency (at the expense of wasting network bandwidth on TCP overhead), perform and explicit flush via the TCPFlush() API.
}
}
break;
Thanks in advance.
PBSnake

case APP_TCPIP_SERVING_CONNECTION:
{
static uint8_t message[] = "Hello";
static uint16_t pos = 0;
if (!TCPIP_TCP_IsConnected(appData.socket))
{
pos = 0;
appData.state = APP_TCPIP_CLOSING_CONNECTION;
SYS_CONSOLE_MESSAGE("Connection was closed\r\n");
break;
}
int16_t wMaxGet, wMaxPut, wCurrentChunk;
uint16_t w, w2;
uint8_t AppBuffer[32];
//uint8_t AppBuffer2[] = "This is a Test";
// Figure out how many bytes have been received and how many we can transmit.
wMaxGet = TCPIP_TCP_GetIsReady(appData.socket); // Get TCP RX FIFO byte count
wMaxPut = TCPIP_TCP_PutIsReady(appData.socket); // Get TCP TX FIFO free space
// Make sure we don't take more bytes out of the RX FIFO than we can put into the TX FIFO
if(wMaxPut < wMaxGet)
wMaxGet = wMaxPut;
// Process all bytes that we can
// This is implemented as a loop, processing up to sizeof(AppBuffer) bytes at a time.
// This limits memory usage while maximizing performance. Single byte Gets and Puts are a lot slower than multibyte GetArrays and PutArrays.
wCurrentChunk = sizeof(AppBuffer);
for(w2 = 0; w2 < wCurrentChunk; w2++)
{
i = AppBuffer[w2];
if (i == message[pos])
{
pos++;
if (pos == strlen(message))
{
pos = 0;
strcpy(AppBuffer, "World");
SYS_CONSOLE_PRINT("Server Sending %s\r\n", AppBuffer);
TCPPutArray(MySocket, AppBuffer, strlen(AppBuffer));
}
}
else
{
pos = 0;
}
if(i == '\e') //escape
{
TCPServerState = SM_CLOSING;
}
}
}
break;

Related

Serial communication on STM32F303 using HAL - Rx not working

I am using an STM32F303RE Nucleo board connected to my own PCB to do RS-232 serial communications, and I can't figure out why this code doesn't work in certain circumstances.
I'm using HAL functions (HAL_UART_Transmit and HAL_UART_Receive) for my communications, using the USB connector on the Nucleo for usart2 and a 9-pin RS-232 serial port on my own PCB for usart1. Both usart configurations have been set up by HAL.
When I communicate (using a Putty terminal) using only the USB connection (usart2), the code works perfectly. When I use usart1 for Tx and usart2 for Rx, still no problems. When I use usart2 for Tx and usart1 for Rx, it also works fine.
The problem is when I try to use usart1 (which is my RS-232 cable) for both Tx and Rx. My processor transmits the initial data fine, but when it's time to receive the data, nothing makes it into the received data register. I have some code to simply echo back any received data on the transmit line, and nothing comes through in this configuration. Once again - the code works fine in every other configuration of usart1 and usart2 for both sending and receiving, but no Rx when I try to do it all on usart1 (RS-232)
Here is the relevant section of code I'm using. COMTYPE is set to either &huart1 or &huart2 (in the problem case, it's set to &huart1)
Main loop (received data used for switch statement in menu system):
HAL_UART_Transmit(COMTYPE, prompt, sizeof(prompt), TIMEOUT);
cmd_size = UART_getstr(command);
cmd_num = parse_menu_input(command, cmd_size);
converted = (uint8_t)cmd_num + '0';
// error parsing command for menu selection
if(cmd_num == -1){
HAL_UART_Transmit(COMTYPE, parse_error, sizeof(parse_error), TIMEOUT);
}
else{
menu_switch(cmd_num);
}
}
Function containing Rx function and echo back (Tx) function:
int UART_getstr(uint8_t* command){
int x = 0; // tracker for buffer pointer
int chars = 0;
uint8_t buffer; // single char storage for UART receive
while(1){
// get single char from UART_Receive
HAL_UART_Receive(COMTYPE, &buffer, 1, HAL_MAX_DELAY);
// echo back function
HAL_UART_Transmit(COMTYPE, &buffer, sizeof(char), TIMEOUT);
// write value of received char to "command" array
command[x] = buffer;
// increment the number of valid chars
chars++;
// stop adding chars to command after [Enter] pressed
if(command[x] == '\r'){
chars--;
break;
}
// correct for storing DELETE as char in buffer
if(command[x] == 0x7F){
command -= 1;
chars -= 2;
}
else{
x++;
}
}
command[x] = '\0';
// return length of command buffer
return chars; }
I don't understand why the exact same code would work in 3 out of 4 circumstances, but not the 4th. I've checked the serial cable, and the rest of the RS-232 hardware functions fine when being used ONLY for Tx or ONLY for Rx. But the Rx seems blocked by something when trying to use RS-232 for both.
EDIT: Adding UART initialization code (generated by HAL):
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}

Can read, but cannot write serial ports on Ubuntu 16.04

I have a strange problem with trying to write data to a serial port.
I am running Ubuntu 16.04 on a NUC7i7DNBE, and am trying to make a serial connection to an Arduino UNO. The Serial API that I am using is found here: http://docs.ros.org/kinetic/api/serial/html/classserial_1_1Serial.html
I have written a simple program which opens the serial port "ttyACM0" to communicate with the arduino. I have tested this code on another computer running Ubuntu 16.04, and everything worked fine, the only permissions I had to set where adding the user to the dialout group.
On the NUC, however, I have added the user to the dialout group. This allowed the program to read from the Arduino, but it still does not write to the Arduino. The Arduino IDE will write to the Arduino just fine, but my program will not.
I am assuming that I am having trouble with serial write permissions in Ubuntu.
Steps I have taken:
I have added the user to the dialout group
I have added a rule in /etc/udev/rules.d/ which states:
SUBSYSTEMS=="tty", GROUP="dialout", MODE="0666"
Afterward, I sent the commands:
sudo chown root:root /etc/udev/rules.d/50-AVCusb.rules
sudo chmod 0644 /etc/udev/rules.d/50-AVCusb.rules
udevadm control --reload-rules
I followed some information found on stack exchange to get to this point:
https://unix.stackexchange.com/questions/111593/allow-non-root-user-to-read-write-dev-files
I have tried using an FTDI device to write to the Arduino port. The FTDI device uses the ttyUSB0 port rather than the ttyACM0 port. The result was the same; can read, but can't write.
I have also run my external hard-drive on the NUC to see if there was any kind of hardware issue. When I ran the program from my external hard drive, I had no problem reading from and writing to the Arduino.
I have not dealt much with Ubuntu permissions or ports in general, please help me find and upload any other information that you may need in order to help me solve this problem.
Code on NUC:
#include <ros/ros.h>
#include <serial/serial.h>
using namespace serial;
Serial ser;
static const uint8_t MOTOR_ID = 0;
void writeMotor(uint8_t byte)
{
size_t size = 4;
uint8_t buffer[size];
buffer[0] = 'G'; //PID
buffer[1] = 'O';
buffer[2] = MOTOR_ID; //address
buffer[3] = byte; //data byte
ser.write(buffer, size);
}
int main() {
ros::init(argc, argv, "servo_esc_driver");
std::string port = "/dev/ttyACM0";
Timeout timeout = Timeout(0, 0, 0, 0, 0);
bytesize_t bytesize = eightbits;
parity_t parity = parity_none;
stopbits_t stopbits = stopbits_one;
flowcontrol_t flowcontrol = flowcontrol_none;
try{
ser.setPort(port);
ser.setBaudrate(115200);
ser.setTimeout(timeout);
ser.setBytesize(bytesize);
ser.setParity(parity);
ser.setStopbits(stopbits);
ser.setFlowcontrol(flowcontrol);
ser.open();
}
catch (SerialException e) {
ROS_FATAL_NAMED("Failed to connect to the Arduino UNO, %s.", e.what());
ros::shutdown();
return 0;
}
uint8_t byte = 90;
writeMotor(byte);
}
Full Code on Arduino
#include <Servo.h>
const byte N = 2;
//Servo esc;
//Servo servo;
Servo servo[N];
//int escPos = 90;
//int servoPos = 90;
int pos[N];
static const byte ESC_PIN = 7;
static const byte SERVO_PIN = 8;
static const byte RPM_FEEDBACK_PIN = 0; //interrpt 0, pin 2
static const byte SERVO_FEEDBACK_PIN = A0;
//const float MUL = 0.7058823529; //180/255
unsigned long lastTime_servoFeedback = 0;
static const byte MOTOR_ID = 0; //ID for differentiating data received and sent over serial connections
static const byte SERVO_ID = 1;
//added for motor data timeout safety feature
static const unsigned long MOTOR_DATA_TIMEOUT = 200; //4 x 50 ms (50 ms time period expected)
static unsigned long lastTimeMotorData = 0;
static const byte NEUTRAL = 90;
unsigned long last_rpm_pulse_update_ms = 0; //used for detecting a stopped car, and rejecting old data when writing to the serial port
unsigned long last_rpm_pulse_time_us = 0;//keeps track of rpms by comparing to system timer
static const long REV_PERIOD_MAX_US = 100000; //in us
unsigned long rev_period = REV_PERIOD_MAX_US; //100 ms is considered too long to be in motion
boolean forward = true;
/*Scratch that, I want these parameters set in ROS:
static const float wheel_radius = 0.05 // meters
static const float revs_to_mps_MUL = //assuming 2.85 gear ratio for brushless motor differential: https://forums.traxxas.com/showthread.php?9080733-Diff-gear-ratios
*/
//boolean rpm_period_updated = false; //rpms must be updated every 100 ms, otherwise the car has stopped, and velocity data should show 0 m/s
void rpm_feedback()
{
//Serial.println("in rpm_feedback");
last_rpm_pulse_update_ms = millis(); //notice the 'ms' here we want to use millisecond for checking whether or not data is valid. millis() can count up to 50 days while micros() only counts up to 70 minutes, thus millis() is used here.
unsigned long time_now = micros(); //use time now for accurate time calculations
unsigned long rev_period_temp = time_now - last_rpm_pulse_time_us; //get spur-gear revolution period
if(rev_period_temp > 0) rev_period = rev_period_temp; //revs are within
else rev_period = REV_PERIOD_MAX_US;
last_rpm_pulse_time_us = time_now; //using 'time_now' ensures that the time taken to get to this point in code does not interfere with rev_period accuracy - - - micros(); //reset time
if(pos[MOTOR_ID] < 90) //determine the direction that the vehicle is traveling in
{
forward = false;
}else forward = true;
//rpm_period_updated = true; not needed, only last_rpm_pulse_time_ms is needed for checking
}
void setup() {
// put your setup code here, to run once:
pinMode(RPM_FEEDBACK_PIN, INPUT_PULLUP);
attachInterrupt(RPM_FEEDBACK_PIN, rpm_feedback,FALLING); //arduino reference recommends using digitalPinToInterrupt(RPM_FEEDBACK_PIN) but the command is not recognized here
analogReference(EXTERNAL); //Using external reference for servo position
for(int i = 0; i < N; i++) //initialize
{
pos[i] = 90;
servo[i].attach(ESC_PIN + i);
}
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() >= 1)
{
if(Serial.read() == 'G')
{
unsigned long t = millis();
while((Serial.available() < 3) && ((millis() - t) < 10)); //wait for the rest of the package, or timeout
if(Serial.available() >= 3)
{
char buf[3];
Serial.readBytes(buf, 3);
if((buf[0] == 'O') && (buf[1] >= 0) && (buf[1] < 2))
{
pos[buf[1]] = byte(buf[2]);
if(buf[1] == MOTOR_ID) lastTimeMotorData = millis(); //time stamp of last motor data retrieval
//Serial.print("buf[2]: ");
//Serial.println(byte(buf[2]), DEC);
//Serial.print("pos: ");
//Serial.println(pos[buf[1]]);
}
}
}
}
if((millis() - lastTimeMotorData) > MOTOR_DATA_TIMEOUT) pos[MOTOR_ID] = NEUTRAL; //stop the motor if data is not being received
for(int i = 0; i < N; i++)
{
servo[i].write(pos[i]);
}
if((millis() - lastTime_servoFeedback) >= 50) // 20Hz 20) //50Hz matches current ROS driver settings
{
lastTime_servoFeedback = millis();
int servo_feedback = analogRead(SERVO_FEEDBACK_PIN);
Serial.write('G'); //PID
Serial.write('O');
Serial.write(SERVO_ID);
//Serial.print(servo_feedback);
Serial.write(lowByte(servo_feedback));
Serial.write(highByte(servo_feedback));
//Serial.println(servo_feedback);
float rev_frequency;
if((last_rpm_pulse_update_ms + 100) < millis()) rev_frequency = 0; //use millis() since it can count up to 50 days, and will not have a chance of a hiccup after 70 minutes of using micros()
//instead, correct period when slowing down, also stop when the maximum threshold is reached
//if((micros() - last_rpm_pulse_time_us) >= REV_PERIOD_MAX_US) rev_frequency = 0; //car is stopped in this case. I decided not to try correcting the period as mentioned above
else rev_frequency = (float) 1/rev_period*1000000;
byte *rev_freq_bytes_to_transmit = (byte *) &rev_frequency;
if(forward == false) rev_frequency = -rev_frequency; //a negative frequency is used for reverse
Serial.write('G'); //PID
Serial.write('O');
Serial.write(MOTOR_ID); //used for addressing
Serial.write(rev_freq_bytes_to_transmit, 4);
}
}
Some good information may be:
snuc#usuavc:~$ udevadm info -a -n /dev/ttyACM0
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/tty/ttyACM0':
KERNEL=="ttyACM0"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0':
KERNELS=="1-4:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="cdc_acm"
ATTRS{authorized}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceClass}=="02"
ATTRS{bInterfaceNumber}=="00"
ATTRS{bInterfaceProtocol}=="01"
ATTRS{bInterfaceSubClass}=="02"
ATTRS{bNumEndpoints}=="01"
ATTRS{bmCapabilities}=="6"
ATTRS{supports_autosuspend}=="1"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4':
KERNELS=="1-4"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="02"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{bMaxPower}=="100mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 2"
ATTRS{bcdDevice}=="0001"
ATTRS{bmAttributes}=="c0"
ATTRS{busnum}=="1"
ATTRS{configuration}==""
ATTRS{devnum}=="4"
ATTRS{devpath}=="4"
ATTRS{idProduct}=="0043"
ATTRS{idVendor}=="2341"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Arduino (www.arduino.cc)"
ATTRS{maxchild}=="0"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="removable"
ATTRS{serial}=="55330313635351207081"
ATTRS{speed}=="12"
ATTRS{urbnum}=="6990"
ATTRS{version}==" 1.10"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1':
KERNELS=="usb1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{authorized_default}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceProtocol}=="01"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{bMaxPower}=="0mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bcdDevice}=="0415"
ATTRS{bmAttributes}=="e0"
ATTRS{busnum}=="1"
ATTRS{configuration}==""
ATTRS{devnum}=="1"
ATTRS{devpath}=="0"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{interface_authorized_default}=="1"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Linux 4.15.0-32-generic xhci-hcd"
ATTRS{maxchild}=="12"
ATTRS{product}=="xHCI Host Controller"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="unknown"
ATTRS{serial}=="0000:00:14.0"
ATTRS{speed}=="480"
ATTRS{urbnum}=="76"
ATTRS{version}==" 2.00"
looking at parent device '/devices/pci0000:00/0000:00:14.0':
KERNELS=="0000:00:14.0"
SUBSYSTEMS=="pci"
DRIVERS=="xhci_hcd"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x0c0330"
ATTRS{consistent_dma_mask_bits}=="64"
ATTRS{d3cold_allowed}=="1"
ATTRS{dbc}=="disabled"
ATTRS{device}=="0x9d2f"
ATTRS{dma_mask_bits}=="64"
ATTRS{driver_override}=="(null)"
ATTRS{enable}=="1"
ATTRS{irq}=="122"
ATTRS{local_cpulist}=="0-7"
ATTRS{local_cpus}=="ff"
ATTRS{msi_bus}=="1"
ATTRS{numa_node}=="-1"
ATTRS{revision}=="0x21"
ATTRS{subsystem_device}=="0x2070"
ATTRS{subsystem_vendor}=="0x8086"
ATTRS{vendor}=="0x8086"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
I decided that the problem was with the ROS version of serial. I decided to try some native linux library, termios, and had success writing to the port!
I found this example code:
https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux
The problem lies in the ros serial installation somehow.
Don't know if you still want to solve this with serial/serial.h, but I think that your problem might be in the timeout settings.
I'm telling you this, 'cause I had the exact same problem, I could read the incoming data, but couldn't write.
The /dev/ttyUSB0 permission was ok, but not the timeout.
I found the following config on internet, gave a try and work. Now I can read and write.
try{
ser.setPort("/dev/ttyUSB0");
ser.setBaudrate(9600);
serial::Timeout to = serial::Timeout::simpleTimeout(10);
ser.setTimeout(to);
ser.open();
return true;
}
catch (SerialException e) {
return 0;

Two xbees ( Router At) connected to Xbee(coordinator)

I have been working on a project which involves xbees. My set-up is simply one Xbee ( coordinator Api mode ) connected to an Arduino as a master unit. This master unit recieves data from multiple Xbees ( slaves ) that are only powered up by a battery and reading data from there ADC pin17. ADC values are transmitted to the master xbee to display it on the serial terminal. The slaves Xbee are configured as ( Router AT mode ). I've bee doing this between two xbees only : 1 master and 1 slave. I have a code that reads the mac address of the sending Xbee and then displays the sent ADC value which is transmitted. All of that was ok until I added another slave, I really need help since I can't associate each mac address with the right ADC value. Neither my code is capable of reading from both alternatively; at some point it stops reading from a one. If any advice on how to recognize data coming from multiple xbees on the same network, I will be grateful.
Here's my code :
#include <XBee.h>
#include <SoftwareSerial.h>
SoftwareSerial myserial(5,6);
float distance;
uint8_t myaddress[10];
XBee xbee = XBee();
uint8_t shCmd[] = {'S','H'};
uint8_t slCmd[] = {'S','L'};
AtCommandRequest atRequestSH = AtCommandRequest(shCmd);
AtCommandRequest atRequestSL = AtCommandRequest(slCmd);
AtCommandResponse atResponse = AtCommandResponse();
void getMyAddress(){
xbee.send(atRequestSL);
if(xbee.readPacket(5000)){
xbee.getResponse().getAtCommandResponse(atResponse);
if (atResponse.isOk()){
for(int i = 0; i < atResponse.getValueLength(); i++){
myaddress[i] = atResponse.getValue()[i];
}
}
}
delay(100);
}
void setup(){
Serial.begin(1200);
myserial.begin(1200);
xbee.begin(myserial);
}
void loop() {
getMyAddress();
for(int i=0; i < 10; i++) {
Serial.print(myaddress[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
if (myserial.available() >= 21) { //
if (myserial.read() == 0x7E) {
for (int i = 1; i<19; i++) { // Skip ahead to the analog data
byte discardByte = myserial.read();
}
int analogMSB = myserial.read(); // Read the first analog byte data
int analogLSB = myserial.read(); // Read the second byte
int analogReading = analogLSB + (analogMSB * 256);
distance = ((analogReading *1.0) / 1023.0)* 3.3;
Serial.println(distance);
}
}
}
In the code where you're skipping data to get to the analog value, you'll find the MAC address of the device sending the data.
if (myserial.read() == 0x7E) {
for (int i = 1; i<19; i++) { // Skip ahead to the analog data
byte discardByte = myserial.read();
}
You should be taking a closer look at that data before processing it -- ensure that it's an I/O sample by looking at the frame type, check the frame length, check the checksum at the end of the frame, etc. The library you're using appears to have functions for processing AT commands and responses, perhaps it also has functions for the I/O Sample frame type.
This Digi support page explains I/O sampling and documents the various fields in the IO Data Sample Received frame (type 0x92).

How to check for a gap between serial data

I'm working on an interface that reads serial data from a single wire bus on a car (BMW IBUS). I'm using an Microchip MCP2025 LIN bus transceiver chip to convert the single line bus to regular Rx/Tx to feed into the hardware serial pins (0 & 1) of an Arduino (Nano V3).
BMW's IBUS protocol uses Serial 8E1 at 9600 baud. Messages are variable length (between 5 and 37 bytes) Bus messages are separated by a pause of around 11 milliseconds (considerably longer than the bus high time when receiving) and I need to use this gap to detect the end of one message and the beginning of the next.
1st byte is the Source ID,
2nd byte is length of the packet excluding the first two bytes (source & length),
3rd byte is the destination ID,
4th byte onwards is the actual data,
Last byte is the checksum
Checksum is generated by XOR of the entire packet excluding the checksum itself.
My problem is that I don't know how to measure the bus idle time between messages. I think I can use bitRead(PIND,0) to tell when the bus is idle (high), but I'm not sure how to time this and go and process the message after a suitable time has passed.
I'm currently using the following code to read messages from the IBUS. It works for the most part, but gets out of sync when connected to the car. It's doesn't really know when messages have finished, but relies on the second byte of each message (the length byte) to know how many bytes to read in. As long as it reads the length byte correctly, it's fine, but if it gets out of sync, and the length byte is wrong, it reads in the wrong number of bytes and eventually overruns the array and the Arduino resets. If I can detect the idle time between messages I will know for sure that I have a complete message.
void ReadIBUS()
{
boolean inSTATE = 0;
byte IBUSbyte[40];
while(Serial.available() > 0 && inSTATE == 0 )
{
IBUSbyte[0] = Serial.read(); //read source byte
while (inSTATE == 0)
{
if(Serial.available() > 0)
{
IBUSbyte[1] = Serial.read(); //read length byte
inSTATE = 1;
}
delay(10);
}
inSTATE == 0;
LENGTH = IBUSbyte[1];
int i = 2;
while(i <= LENGTH + 1)
{
if(Serial.available() > 0)
{
IBUSbyte[i] = Serial.read();
i++;
delay(10);
}
}
checksumBYTE = 0;
byteSTATE = 0;
for (int i = 0; i < LENGTH + 1; i++){
checksumBYTE ^= IBUSbyte[i];
}
if (IBUSbyte[LENGTH + 1] == checksumBYTE){
for(int i = 0; i <= LENGTH + 1; i++)
{
mySerial.print(IBUSbyte[i], HEX);
mySerial.print(" ");
}
mySerial.println();
}
else {
debug();
inSTATE = 0;
byteSTATE = 0;
}
}
}
First off, delay is rarely a good thing to use. In this case, you can use millis to measure how long it is between characters, but only if you lose the delay:
void ReadIBUS()
{
byte IBUSbyte[40];
do {
// First, make sure we're between frames, in the quiet interval
uint32_t last_rx = millis();
while (millis() - last_rx < 5) {
// Hasn't been long enough, see if more chars are coming
if (Serial.available()) {
Serial.read(); // throw away partial frame chars
last_rx = millis();
}
}
// Haven't received any chars for a while, we must be
// between frames. Now wait for a frame.
while (!Serial.available())
; // waiting...
IBUSbyte[0] = Serial.read(); //read source byte
while (!Serial.available())
; // waiting...
IBUSbyte[1] = Serial.read(); //read length byte
LENGTH = IBUSbyte[1];
// Check the LENGTH to make sure it's not bogus. If it is, try again.
} while (LENGTH > sizeof(IBUSbyte)-1);
// LENGTH is reasonable, wait for the payload
uint8_t bytes_received = 2;
while (bytes_received <= LENGTH + 1) {
if (Serial.available()) {
IBUSbyte[ bytes_received++ ] = Serial.read(); // read frame payload byte
}
}
// All here, verify the checksum
checksumBYTE = 0;
for (int i = 0; i < LENGTH + 1; i++) {
checksumBYTE ^= IBUSbyte[i];
}
if (IBUSbyte[LENGTH + 1] == checksumBYTE) {
for(int i = 0; i <= LENGTH + 1; i++) {
mySerial.print(IBUSbyte[i], HEX);
mySerial.print(" ");
}
mySerial.println();
} else {
debug();
}
}
And the state variables are no longer needed.
BTW, this routine "blocks" the rest of the program from doing anything until a complete frame is received. It should probably be rewritten so that it is called frequently (like from loop), and last_rx and bytes_received are remembered across calls. It could return true when a complete frame has been received. This'll work, it's just sub-optimal because it blocks anything else from happening, except interrupts.

TCP socket communications are being corrupted

I am trying to use a TCP server and connect to it with a QTcpSocket client. Most of the time, the server and client happen to be on the same machine, but this is not a requirement. What I am trying to do is transfer a file from a running multithreaded process to a GUI that wants to share information used by both the server and the client.
The connect, etc seems to be just fine. In fact, the code appeared to work perfectly for a long time, but now that I am running it on different hardware, and on Ubuntu 12.04 instead of 10.04, I am occasionally getting embedded stray bytes in the received code--usually (but not always) nulls. I cant figure out whats wrong, and would welcome any advice.
Here is portion of the server that reads my file and sends the bytes to the connected client:
int fileSize;
printf(" about to open the file\n");
ini_fd = fopen (rov_ini_file_name, "r");
if(!ini_fd){
break;
}
fseek(ini_fd,0,SEEK_END);
fileSize = ftell(ini_fd);
fseek(ini_fd,0,SEEK_SET);
int totalBytesSent =0;
int line = 0;
int len;
while (!feof (ini_fd))
{
ch = fgets (&(my_line[0]), MAX_CHARACTER_COUNT - 1, ini_fd);
if (ch){
len = strlen(&(my_line[0]));
bytes_sent = sendto(tio.my_tio_port_table_entry.to_sock,
&(my_line[0]),
len,
0,
(struct sockaddr *) (&(tio.my_tio_port_table_entry.ToAddr)),
sizeof (tio.my_tio_port_table_entry.ToAddr));
totalBytesSent += bytes_sent;
line++;
//printf(" line %d bytes sent = %d total bytes = %d\n",line,bytes_sent,totalBytesSent);
}
}
len = sprintf(&(my_line[0]),"END_OF_INI_FILE");
bytes_sent = sendto(tio.my_tio_port_table_entry.to_sock,
&(my_line[0]),
len,
0,
(struct sockaddr *) (&(tio.my_tio_port_table_entry.ToAddr)),
sizeof (tio.my_tio_port_table_entry.ToAddr));
tio.my_tio_port_table_entry.connected = FALSE;
break;
Here is where I read the data being sent. This is the slot connected to the readyRead signal
void AlvGUI::readIniFromServer()
{
QByteArray inArray(iniClient->bytesAvailable(),0);
if(!iniStarted)
{
tempIniFile = new QTemporaryFile;
if(tempIniFile->open())
{
iniStarted = true;
}
else
{
// error should be here!
}
}
int bytesRead = iniClient->read(inArray.data(),inArray.size());
int endLoc = inArray.lastIndexOf("END_OF_INI_FILE");
if(-1 != endLoc)
{
inArray.chop(endLoc);
bytesRead = endLoc;
iniFinished = true;
}
tempIniFile->write(inArray.data(),bytesRead);
if(iniFinished)
{
tempIniFile->flush();
tempIniFile->close();
iniFile.close_ini();
char *theTempFile = strdup((char *)tempIniFile->fileName().toAscii().data());
iniFile.open_ini(theTempFile);
gotIni = true;
iniRequestTimer->stop();
makeGui();
free(theTempFile);
hotelSetup = true;
iniClient->abort();
}
}
as usual, asking a question makes me dig even deeper. I didn't have a tcp server problem--I confirmed that by using telnet to connect to my server and then redirected the output to a file--which was flawless
so I looked deeper into my code, and instead of truncating the incoming data, which was held in a QtByteArray, I was chopping it--which took the number of bytes read off of the end of the QtByteArray. Except that when I used the data() member function of the QtByteArray, I just got a char pointer back, and so got access to all of the data. The data was corrupted where I had done the chop()

Resources