I am trying to send and receive some serial data with QSerialPort but it take a little time. So I open a Serial Terminal. (Terminal v1.93b - 20141030B) Then with it terminal I read and send data and when I tried again with my application, it starts correctly.
So why it happens after do I open the serial terminal and some data are sended the QSerialPort works fine. It looks like if I need to reset or refresh the serial buffer on my port.
Try to call the function clear() after opening a serial port, or to call the function flush() after each sending data.
bool QSerialPort::clear(Directions directions = AllDirections)
bool QSerialPort::flush()
Related
I am making a system where I have a Pi that will send a string over UDP to an Arduino that has Wifi. The Arduino will then send some data back to the Pi. This part works flawlessly. Then the Pi will relay this same data over Serial to an Arduino Mega that has no Wifi. This is my problem. I am able to receive all the data over UDP but when I try to receive data and then send this over Serial, it glitches and nothing works. It just receives null values. I know this because on the Arduino Mega, I have setup a system where it will simply take the data it received and just send it back with the letters "ACK" signed on them so that I know that it was successfully received. All I get is null things. But when I just send the string "HI" over the Serial port and disable the UDP stuff, it magically works... sometimes. What could be going wrong?
Code on the Pi
#!/usr/bin/env python3
import serial
import time
import socket
serialData = 'null \n'
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = b'pi'
addr = ("192.168.71.146", 2390)
def wifirecv():
global serialData
s.sendto(message, addr)
data, address = s.recvfrom(10240)
#print(data.decode())
angle = data.decode()
serialData = angle + ' \n'
while(True):
ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1)
ser.flush()
ser.close()
ser.open()
while True:
try:
wifirecv()
print(serialData)
ser.write(serialData.encode('utf-8'))
#ser.write(b'hi')
line = ser.readline().decode('utf-8').rstrip()
print(line)
except(KeyboardInterrupt):
ser.close()
print("Serial Closed")
exit()
Code on the Mega
void setup() {
Serial.begin(115200);
}
void loop() {
while(Serial.available() != 0){
String data = Serial.readStringUntil('\n');
Serial.println(data + ": ACK");
}
}
Despite you mention that the response from the Arduino works fine, I believe that you should use the SerialEvent interrupt callback rather than polling for the .available method. It is a much more reliable way to detect when data is present in the input buffer. I would form the input string char by char, as done in the official tutorial.
I think that the approach you opted for might be causing timing issues on the serial port since you said:
I am able to receive all the data over UDP but when I try to receive data and then send this over Serial, it glitches and nothing works
those glitches might also be a consequence of the selected baudrate or (again) the polling approach. This is reinforced by your statement:
Serial port and disable the UDP stuff, it magically works... sometimes
Have you tried using read_until(LF, None) instead of readline()? I've had better results with the first one in some acquisition routines. Check this for reference
Are you using any other resources from the Pi or the Arduino? I am not sure if the UDP messes up with the serial communication from the RPi. I would seriously doubt it, but just check if there are no reported issues with the socket library.
Finally, a tiny time.sleep(ms) between the write() and the read() in your RPi might not hurt the communication too much. For instance, in my recent experience with the I2C protocol, a tiny delay makes a huge difference for reliable communication.
The bottom line is: you have timing issues.
I'm working on a project based on the ESP32 platform. The aim is to count the number of MAC addresses in the area, and transmit this information over WiFi (using an http POST request).
The first task is achieved by sniffing WIFI packets and collecting the contained addresses, following this example: https://blog.podkalicki.com/esp32-wifi-sniffer/
I believe that the code which "sniffs" the packets sets the ESP to run in promiscuous mode, and therefore I cannot connect to any AP anymore.
I've tried several solutions, first starting with timer interrupts. However this approach always led to a Core Panic and reset of the chip.
I also learnt I could use RTOS to run different tasks in parallel on the two cores of the CPU, but that didn't help to solve the problem.
void wifi_sniffer_packet_handler(void* buff, wifi_promiscuous_pkt_type_t type)
{
if (type != WIFI_PKT_MGMT)//aggiungere filtro su RSSI a questa altezza.
return;
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload;
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
//some analysis and then print the MAC address
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &chUpdate, true);
timerAlarmWrite(timer, 1000000, true);//timer, arr_val, reload=true
delay(4000);
wifi_sniffer_init();
timerAlarmEnable(timer);
}
// the loop function runs over and over again forever
void loop() {
//Serial.print("inside loop");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Establishing connection to WiFi..");
}
Serial.println("Connected to network");
}
I also noticed that the code in the loop gets stuck into the while, and is restarted every time the packet handler is run (I nevere get to see "Connected to network", but i see "Establishing connection to WiFi.." several times.
Anyone can explain me what's going on? Is there a different approach to achieve this result?
Thank you.
You may have two tasks and two cores, but the ESP32 still has only one wifi chip. The way your code is written (at least, the code you shared), you'll be trying to connect to a wifi network at the same time as you're trying to run promiscuous mode. You can do only one of those things at a time.
You'll need to stop promiscuous mode before you attempt to connect to an access point. Right now your code constantly attempt to connect to a wifi access point. Use a volatile variable to store the current mode - promiscuous or connected. Change it when you need to change states. Only attempt to connect to wifi when the variable says you want to be in connected mode.
There may be some code you need to run to turn off promiscuous mode when you change states, before you connect to a wifi access point.
If you're using wifi_sniffer_init() from the example you linked to, that code isn't meant to be run in an Arduino Core application. It does some network initialization that the Arduino Core will also do. It may not be safe to do that twice (it might work, it might not... but it's definitely not intended to be done that way).
You're setting an interrupt handle chUpdate() which you didn't share. I'd bet that's the cause of your Core Panics. You can do very little in an interrupt handler. You definitely can't call most Arduino Core functions or most ESP-IDF functions. Most code isn't protected against interrupts, so the timer interrupt can occur while data structures are in an inconsistent state. Re-entering code can corrupt the data structures and cause the kind of crash you described. You're best off setting a volatile variable and waking up a task that will do the work you need done while not in the interrupt handler.
Finally, you should call WiFi.mode(WIFI_STA); before you call WiFi.begin().
For anyone confused about why you can't connect to a wifi network while in promiscuous mode - what ESP8266 and ESP32 call "promiscuous mode" is really "wifi monitor mode", which lets you monitor a wifi radio channel and see all wifi frames sent on it. They use the term "promiscuous mode" differently from the rest of the industry. Usually "promiscuous mode" means seeing all the packets being sent on the network (wifi or hardwired) that you're connected to.
I know that it's been just over a year but THANKS to the info provided by romkey I think I solved this problem within my app by calling this routine before connecting to WiFi to upload MAC data.
void end_Scan_WiFi() {
esp_wifi_set_promiscuous(false);
esp_wifi_stop();
}
Followed by this ...
WiFi.mode(WIFI_STA);
WiFi.begin(ssid,pass);
I got this shield below which fits great with my Arduino Uno. Moreover, I have managed to upload code to the shield with a serial adapter and send/receive UDP messages. As the picture shows this shield goes right on top of the Arduino UNO.
My ESP8266 Shield
The problem is that the communication between Arduino and the Shield is very slow.
For example, I use the code below to Arduino to write something using Serial (115200).
void loop() {
writeString("Hello!");
delay(1000);
}
Then I use a simple code to the ESP8266 shield to read the data from Arduino and send it via UDP (writeString is just a simple converter).
Udp.beginPacket(ip, localUdpPort);
writeString(Serial.readString());
Udp.endPacket();
void writeString(String stringData) {
for (int i = 0; i < stringData.length(); i++) {
Serial.write(stringData[i]);
// Push each char 1 by 1 on each loop pass
}
}
It works fine, the "Hello!" string is read from the ESP8266 shield and sent using UDP. The problem is that if I put anything below 1,000 ms of delay in the Arduino, the ESP shield does not read anything, which is strange considering that the shield is on the top of the Arduino with no restrictions between serial communication.
From https://www.arduino.cc/en/Serial/ReadString:
Serial.readString() reads characters from the serial buffer into a string. The function terminates if it times out (see setTimeout()).
From https://www.arduino.cc/en/Serial/SetTimeout:
It defaults to 1000 milliseconds.
So because you use this Serial.readString() thing with the default timeout there will always be a delay of 1000 ms before the string is received.
If you insist on messing with String, there is a similar function: Serial.readStringUntil():
The function terminates if the terminator character is detected or it times out
So you have it detect the terminating character of the string:
Serial.readStringUntil('\n');
In this case the timeout is merely a safeguard to keep the code from hanging if for some reason the terminating character should not arrive but this should never happen if things are working correctly so there are no unnecessary delays.
The trouble with that is your current code doesn't send a terminator but that's easy enough to fix.
I recommend that you consider using the more efficient and safer string (char array) rather than String. There is an equivalent function: Serial.readBytesUntil().
I am working on an arduino board with Ethernet Shield (v2).
I have took a look to this sample program: Files > Samples > Ethernet > WebServer
There is something very strange for me in loop function: When the server ends to print data to client, i see a delay:
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
What happens if it takes more than one second to send data to client ?
What happens if data is immediatly send and if i have a second client trying to connect to the server in the 1 second delay ?
Is there a way to do something clean, for example waiting data to be flushed instead of waiting 1 second ?
Thanks
Running shell command through Bridge in Arduino Yun through a Process let's say, proc, it gives result and we can read the result bytes using following piece of code.
#include <Bridge.h>
#include <Process.h>
void setup() {
Bridge.begin();
Serial.begin(9600);
while (!Serial);
}
void loop() {
Process proc;
proc.runShellCommand("ls /root/");
while (proc.available() > 0)
Serial.print((char)proc.read());
Serial.println();
}
What if I have to access data from a blocking shell command as it gets updated like and event? Such as, some consumer that listens to Kafka or Mosquitto subscribed topic. Whenever that topic is updated/published with new data, the listener gets it.
How can I model such structure using Arduino Yun program using Bridge.
You can do it quite easily.
Run that particular command with nohup, in that case, file with the name nohup.out would be created. then after that run a script that continuously monitors that nohup.out file in case of any change in the size of nohup.out, get the latest data and push that data to anywhere you want.