So, I am working with C++/CLI in VisualStudio and an Arduino based board. My goal is to implement MODBUS via RS485.
So the setup I have for development is as follows...
Laptop connected Via FTDI USB-RS485 interface cable to Maxim MAX3485 chip which is connected to Arduino serial port "Serial1".
I have been writing my MODBUS protocol in Visual Studio and testing it out by asking the Arduino to respond with the contents of 5 registers (a 5 byte array).
Everything works except for some reason, return bytes are getting split in two when I check the result.
I.E... I'm sending the following bytes from the Arduino:
0 A 0 14 0 1E 0 28 0 32
A is actually "0A", but the terminal window only displays it as "A". The software on the computer receives the bytes, and stores them in an array. I then display the bytes received on the screen as text. What I get is:
0 A 0 1 4 0 1 E 0 2 8 0 3 2
Which looks correct, except the space between the "1 & 4", "2 & 8" etc.. which is telling me that I have 14 bytes instead of the 10 bytes the I sent out.
I'm displaying each byte on the screen separated by a space. I verified the bytes leaving are correctly formatted using a terminal window on a separate com port, so the problem must be in the reading of the bytes?
My Arduino code:
// Print to terminal window to verify bytes leaving
Serial.print("Sending:- ");
for (int x = 0; x < i_Index; x++) {
Serial.print(DataTxRegister[x], HEX);
Serial.print(" ");
}
Serial.println(" ");
// CONFIGURE 485 CHIP TO TX MODE
digitalWrite(CNTL_PIN, HIGH);
delay(5);
// TRANSMIT ALL DATA FROM TX REGISTER
for (int x = 0; x < i_Index; x++) {
Serial1.print(DataTxRegister[x], HEX);
}
i_Index = 0;
delay(5);
// CONFIGURE 485 CHIP BACK TO RX MODE
digitalWrite(CNTL_PIN, LOW);
Visual Studio code
Read Bytes....
int8_t Byte;
// DATA RECIEVED FROM ARDUINO / DEVICE USING MODBUS PROTOCOL
if(sender == this->serialPort1){
Msg.Message_Length = 0;
while (this->serialPort1->BytesToRead != 0) {
Byte = this->serialPort1->ReadByte;
if (Byte != -1) {
Msg.Incoming_Bytes[Msg.Message_Length++] = (Byte);
}
}
this->BeginInvoke(gcnew EventHandler(this, &Form1::DisplayMBRecieved));
}
Display Bytes...
this->textBox1->AppendText("\r\n");
this->textBox1->AppendText("Bytes Received: ");
this->textBox1->AppendText(Convert::ToInt32(Msg.Message_Length).ToString("X8") + " :- ");
for (unsigned int i = 0; i < Msg.Message_Length; i++) {
this->textBox1->AppendText(Convert::ToString(Convert::ToChar(Msg.Incoming_Bytes[i])));
this->textBox1->AppendText(" ");
}
Msg.Message_Length = 0;
Related
I have an ESP8266 and a RPI 3B+ both equipped with LoRa-02 (SX1278) modules. I'm trying to send a packet from the ESP to the RPi, but it's not working.
Please consider the following code snippet on ESP8266:
main.cpp
#include "loRaComms.h"
void setup() {
// sender
Serial.begin(115200);
initLoRa(434800000);
}
void loop() {
// sender
brodcastBuffer();
delay(1000);
}
loRaComms.cpp
#include <LoRa.h>
void initLoRa(int freq) {
LoRa.setPins(Lora_NSS, Lora_RESET, Lora_DIO0);
LoRa.setFrequency(freq);
LoRa.setSignalBandwidth(62500);
LoRa.setSpreadingFactor(12);
LoRa.setCodingRate4(8);
LoRa.setGain(0);
LoRa.setPreambleLength(6);
if (!LoRa.begin(freq)) {
// initialize ratio at 915 MHz 433E6 - Asia, 866E6 - Europe, 915E6 - North America
Serial.println("LoRa init failed.");
} else {
Serial.println("LoRa init succeeded.");
}
}
void brodcastBuffer() {
LoRa.beginPacket(); // start packet
LoRa.print("hello!");
LoRa.endPacket();
}
I have no problem with the ESP8266 code. I have tested this code with 2 ESP8266, one sender and one receiver, everything is working fine!
Now let's see the RPi 3B+ code. I have used [this repository][1] with its own sample code as follows:
void * rx_f(void *p) {
rxData *rx = (rxData *)p;
printf("rx done \n");
printf("CRC error: %d\n", rx->CRC);
printf("Data size: %d\n", rx->size);
printf("string: %s\n", rx->buf); // Data we've received
printf("RSSI: %d\n", rx->RSSI);
printf("SNR: %f\n", rx->SNR);
free(p);
return NULL;
}
int main() {
LoRa_ctl modem;
// See for typedefs, enumerations and there values in LoRa.h header file
modem.spiCS = 0; // Raspberry SPI CE pin number
modem.rx.callback = rx_f;
modem.eth.preambleLen = 6;
modem.eth.bw = BW62_5; // Bandwidth 62.5KHz
modem.eth.sf = SF12; // Spreading Factor 12
modem.eth.ecr = CR8; // Error coding rate CR4/8
modem.eth.freq = 434800000; // 434.8MHz
modem.eth.resetGpioN = 27; // GPIO4 on lora RESET pin
modem.eth.dio0GpioN = 17; // GPIO17 on lora DIO0 pin to control Rxdone and Txdone interrupts
modem.eth.outPower = OP20; // Output power
modem.eth.powerOutPin = PA_BOOST; // Power Amplifier pin
modem.eth.AGC = 1; // Auto Gain Control
modem.eth.OCP = 240; // 45 to 240 mA. 0 to turn off protection
modem.eth.implicitHeader = 0; // Explicit header mode
modem.eth.syncWord = 0x12;
printf("%d\n", modem.eth.bw);
printf("%d\n", modem.eth.ecr);
// For detail information about SF, Error Coding Rate, Explicit header, Bandwidth, AGC, Over current protection and other features refer to sx127x datasheet https:// www.semtech.com/uploads/documents/DS_SX127$
LoRa_begin(&modem);
LoRa_receive(&modem);
while (1) {
usleep(200000);
}
printf("end\n");
LoRa_end(&modem);
}```
But I can't receive anything on RPi. I also tested the ping pong sample on two RPi 3 and it didn't work.
Did I miss something here? I'm open to use any alternative library on RPi3, but I can only use C/C++ libraries. I've used the following pins:
raspi LoRa
GPIO27, pin13 RESET
GPIO17, pin 11 DIO0
MOSI (GPIO10, pin 19) MOSI
MISO (GPIO9, pin 21) MISO
CLK (GPIO11, pin 23) SCK
SPI_CE0 (GPIO8, pin 24) NSS
[1]: https://%20github.com/YandievRuslan/sx1278-LoRa-RaspberryPi.git
You can check your pin connection
The PI 3 MISO is GPIO09 and MOSI is GPIO10.
So you need change the pin connection to the following
raspi LoRa
MOSI (GPIO10, pin 19) MISO
MISO (GPIO9, pin 21) MOSI
Here is the introduction of SPI MOSI and MISO
https://www.analog.com/en/analog-dialogue/articles/introduction-to-spi-interface.html
This is my first question on here and first project on my own. I have a client (C++ on Windows 10) using the SimConnect SDK to pull data from the Prepar3D Flight Simulator and a server (C on Ubuntu) that is receiving this data. I am using sockets and Protocol Buffers. The client receives the data from the sim, maps it to a protocol buffer and sends it. The server receives it from the socket, decodes the protocol buffer and then processes it. The issue is that the last field (dWindDirection) is always corrupted on the receiving end. I'm not entirely sure how/why it's being corrupted but it's consistent as in the same input to the socket always leads to the same corrupted output from the socket. I followed Protocol Buffer over socket in C++ for the use of protocol buffers over a socket. I have included my code below as well as the output.
Source code can also be found here. https://github.com/nbreen/Simconnect-Data-Client
Client function that sends the protobuff
DWORD WINAPI createProto(LPVOID lParam) {
ObjectData* toConvert = (ObjectData*)lParam;
fopen_s(&dataOut,"dataOut.txt", "a+");
fprintf(dataOut, "Before serialiing \n");
logData(toConvert);
simConnect::simData convertedData;
std::string toStr(toConvert->szTitle);
convertedData.set_sztitle(toStr);
convertedData.set_dabsolutetime(toConvert->dAbsoluteTime);
convertedData.set_dtime(toConvert->dTime);
convertedData.set_usimonground(toConvert->uSimOnGround);
convertedData.set_daltitude(toConvert->dAltitude);
convertedData.set_dheading(toConvert->dHeading);
convertedData.set_dspeed(toConvert->dSpeed);
convertedData.set_dverticalspeed(toConvert->dVerticalSpeed);
convertedData.set_dgpseta(toConvert->dGpsEta);
convertedData.set_dlatitude(toConvert->dLatitude);
convertedData.set_dlongitude(toConvert->dLongitude);
convertedData.set_dsimtime(toConvert->dSimTime);
convertedData.set_dtemperature(toConvert->dTemperature);
convertedData.set_dairpressure(toConvert->dPressure);
convertedData.set_dwindvelocity(toConvert->dWindVelocity);
convertedData.set_dwinddirection(toConvert->dWindDirection);
printf("Size after serializing is %ld\n", convertedData.ByteSizeLong());
long pktSize = convertedData.ByteSizeLong();
fprintf(dataOut, "After serializing before socket\n%s\n\n", convertedData.DebugString().c_str());
char* pkt = new char[pktSize];
google::protobuf::io::ArrayOutputStream aos(pkt, pktSize);
google::protobuf::io::CodedOutputStream* coded_pkt = new google::protobuf::io::CodedOutputStream(&aos);
coded_pkt->WriteVarint64(convertedData.ByteSizeLong());
convertedData.SerializeToCodedStream(coded_pkt);
int iResult = send(clientSocket, pkt, pktSize, 0);
printf("Sent bytes %d\n", iResult);
fclose(dataOut);
return 0;
}
Server function that receives and processes the protobuff
while(1) {
result = recv(client, sizeBuff, 4, MSG_PEEK);
printf("Receive is %d\n", result);
if (result == -1) {
printf("Error receiving data with byteSize\n");
break;
}else if (result == 0) {
break;
}
if (result > 0) {
printf("First read byte count is %d\n", result);
readMessage(client, readHeader(sizeBuff));
}
}
google::protobuf::uint64 readHeader(char *buf) {
google::protobuf::uint64 size;
google::protobuf::io::ArrayInputStream ais(buf,4);
google::protobuf::io::CodedInputStream coded_input(&ais);
coded_input.ReadVarint64(&size);//Decode the HDR and get the size
std::cout<<"size of payload is "<<size<<std::endl;
return size;
}
void readMessage(int csock, google::protobuf::uint64 siz) {
int bytecount;
simConnect::simData payload;
char buffer [siz+4];//size of the payload and hdr
//Read the entire buffer including the hdr
if((bytecount = recv(csock, (void *)buffer, 4+siz, 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
}
std::cout<<"Second read byte count is "<<bytecount<<std::endl;
//Assign ArrayInputStream with enough memory
google::protobuf::io::ArrayInputStream ais(buffer,siz+4);
google::protobuf::io::CodedInputStream coded_input(&ais);
//Read an unsigned integer with Varint encoding, truncating to 32 bits.
coded_input.ReadVarint64(&siz);
//After the message's length is read, PushLimit() is used to prevent the CodedInputStream
//from reading beyond that length.Limits are used when parsing length-delimited
//embedded messages
google::protobuf::io::CodedInputStream::Limit msgLimit = coded_input.PushLimit(siz);
//De-Serialize
payload.ParseFromCodedStream(&coded_input);
//Once the embedded message has been parsed, PopLimit() is called to undo the limit
coded_input.PopLimit(msgLimit);
//Print the message
//std::cout<<"Message is "<<payload.DebugString();
FILE *outFile = fopen("out.txt", "a+");
/*std::string strPkt(buffer);
payload.ParseFromString(strPkt);*/
fprintf(outFile, "From socket\n%s\n\n", payload.DebugString().c_str());
fclose(outFile);
cudaProcess(payload);
}
Client Output
Before serialiing
Title: F-22 Raptor - 525th Fighter Squadron
Absolute Time: 63631767652.278290 seconds
Zulu Time: 68452.281250 Seconds
Sim On Ground: 0
Altitude: 11842.285630 Feet
Heading: 3.627703 Radians
Speed: 426.008209 Knots
Vertical Speed: 596.607849 Feet Per Second
GPS ETA: 0.000000 Seconds
Latitude: 30.454685 Degrees
Longitude: -86.525197 Degrees
Sim Time: 2996.388142 Seconds
Temperature: -8.145923 Celsius
Air Pressure: 648.718994 Millibars
Wind Velocity: 36.988354 Feet Per Second
Wind Direction: 270.000000 Degrees
After serializing before socket
szTitle: "F-22 Raptor - 525th Fighter Squadron"
dAbsoluteTime: 63631767652.27829
dTime: 68452.28125
usimOnGround: 0
dAltitude: 11842.285629708613
dHeading: 3.6277025313026936
dSpeed: 426.00820922851562
dVerticalSpeed: 596.60784912109375
dGpsEta: 0
dLatitude: 30.454685493870045
dLongitude: -86.525197127202063
dSimTime: 2996.388142343636
dTemperature: -8.1459226608276367
dAirPressure: 648.718994140625
dWindVelocity: 36.988353729248047
dWindDirection: 270
Server Output
From socket
szTitle: "F-22 Raptor - 525th Fighter Squadron"
dAbsoluteTime: 63631767652.27829
dTime: 68452.28125
usimOnGround: 0
dAltitude: 11842.285629708613
dHeading: 3.6277025313026936
dSpeed: 426.00820922851562
dVerticalSpeed: 596.60784912109375
dGpsEta: 0
dLatitude: 30.454685493870045
dLongitude: -86.525197127202063
dSimTime: 2996.388142343636
dTemperature: -8.1459226608276367
dAirPressure: 648.718994140625
dWindVelocity: 36.988353729248047
dWindDirection: 1.2168372663711258e-309 <-- This is always the corrupt value when Wind direction is 270
If you look at the raw hex values for the dWindDirection, they are:
270: 0x00 0x00 0x00 0x00 0x00 0xe0 0x70 0x40
1.2168372663711258e-309: 0x00 0x00 0x00 0x00 0x00 0xe0 0x00 0x00
So the two last bytes of your packet are being set to 0 instead of the real value.
It sounds like there might be a problem with your socket reading code. I would start by verifying the data in network connection using e.g. Wireshark. If it is correct there, set a breakpoint in your reception code and check sizes & buffer content.
As jpa said in the comments I was not accounting for the prefix I was appending to the packet so though the size of the data was correct it was not accounting for the 4 byte header that I was appending. However, when the server read the packet it was accounting for the total size and the header that was appended so I was always short by 4 bytes when decoding the packet on the server side giving me a garbage value for the last field of the object. In the client code adding 4 (The size of the header) to pktSize fixed the problem.
I would like to send strings from USB (serial) to my esp32 microcontroller (Arduino) that are larger than the apparently default 64 bytes limit of the actual Arduino or the apparently 256 byte limit for the esp32 [1].
I found the command [2] recognized by PlatformIO:
Serial.setRxBufferSize(1024);
but as soon as I enter this line of code (with any number from 10 to 1000) the following code doesn't run anymore:
void serialEvent()
{
Serial.setRxBufferSize(64); // increasing buffer size ?
while (Serial.available())
{
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '$') // end marker of the string
{
inputStringPC = inputString;
stringCompletePC = true;
Serial.print(inputStringPC);
inChar = '0';
inputString = '0';
}
}
}
Hope anyone knows whats wrong.
Thanks!
[1] https://esp32.com/viewtopic.php?t=8589
[2] https://www.esp32.com/viewtopic.php?t=7730
Obviously this function
void serialEvent()
{
Serial.setRxBufferSize(64); // increasing buffer size ?
....
is called in the loop - so basiclly you try to dynamicly change the buffer size of RX- So try
#define BAUD_RATE 115200
#define SERIAL_SIZE_RX 1024 // used in Serial.setRxBufferSize()
setup(){
Serial.begin(BAUD_RATE);
Serial.setRxBufferSize(SERIAL_SIZE_RX);
....
}
The above code works without any problems in ESP8266 /ESP32 and ArduinoIDE 1.8.12 and ESP32 core 1.04 / ESP8266 core 2.6.3
I am trying to get an arduino board to read the state of a potentiometer which is connected to a master arduino board, without connecting the potentiometer to the second board with physical cables
I have tried using Wire.write and Wire.read to just transfer the one value.
The master arduino code:
#include <Wire.h>
const int dial = A0;
int reading = 0;
void setup() {
pinMode(dial, INPUT);
Wire.begin();
}
void loop() {
reading = analogRead(dial);
Wire.beginTransmission(9);
Wire.write(reading);
Wire.endTransmission();
}
The slave arduino code:
#include <Wire.h>
int reading = 0;
void setup() {
Wire.begin(9);
Serial.begin(9600);
Wire.onReceive(receiveEvent);
}
void receiveEvent(int bytes) {
reading = Wire.read();
}
void loop() {
Serial.println(reading);
}
When I read the Serial Monitor, the potentiometer or "reading" in the slave arduino limits at 255 (I don't know why) in 6 intervals (goes from 0 to 255, then drops to 0 and does that 6 times). I expect it to do the full range of the potentiometer to cap out at 1023.
Your ADC is 10bit and won’t fit in a byte. (Wire.write(value) sends value as a single byte). You need to send reading in 2 bytes. Here is how to make 2 bytes.
byte data1 = highByte(reading);
byte data2 = lowByte(reading);
On receiving side, reconstruct an int this way.
byte data1 = Wire.read();
byte data2 = Wire.read();
reading = int(data1) << 8 | data2;
I'm working on an Arduino board (microprocessor: ATMega328P) for a University project. I'd like to build a GPS tracker which receives data, stores it, and retransmit it via SIGFOX module.
Basically, I'm able to receive data, and I'm able to send simple SIGFOX commands via serial.
#include <TinyGPS++.h>
#include <String.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("DeviceExample.ino"));
Serial.println(TinyGPSPlus::libraryVersion());
Serial.println();
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read())) {
Serial.print(gps.location.lat(), 6); // 4 bytes
Serial.print(F(",")); // 1 byte
Serial.print(gps.location.lng(), 6); // 4 bytes
Serial.print('\n');
delay(4000);
}
if (millis() > 5000 && gps.charsProcessed() < 10){
Serial.println(F("No GPS detected: check wiring."));
while (true);
}
}
This prints correctly on screen the two values (latitude and longitude) that I need to store.
This is the part of the code in TinyGPS++.cpp :
double TinyGPSLocation::lat()
{
updated = false;
double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
return rawLatData.negative ? -ret : ret;
}
double TinyGPSLocation::lng()
{
updated = false;
double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
return rawLngData.negative ? -ret : ret;
}
Now I'd like to store this data and send it through the SIGFOX module.
A SIGFOX command is:
'N X'
Where N represents the number of bytes that are to be transmitted, and X are the values of the bytes. For example: '1 255' is 1 byte with value 255, and returns FF as output.
The problem is that the values are doubles so I don't know how to write them in the SIGFOX command.
Another problem is that I don't know how to create two serial communications in the code. I tried it but it doesn't seem to work.
Thank you so much in advance.
I saw some of the API info on the SIGFOX, I'm assuming it is this. Even if it isn't it's probably close enough for the point I'm trying to make.
https://support.sigfox.com/apidocs#operation/getDevice
You need to understand to some extent what IEEE 754 is as in my experience this is how equipment passes the data back and forth if you look at the raw bit stream.
https://en.wikipedia.org/wiki/IEEE_754
So, it is a double you send over 8 bytes on most platforms and 4 bytes for a float. When you print to the screen of hover over a variable in debug mode, the IDE/compiler takes care of this for you and gives you number with decimal points.
For making another serial port, you need to make another variable and pass in the baud rate etc of that device.