How to print response to AT commands in Arduino serial port? - c

I want to print the response to AT command. I'm sending AT command but I'm not getting any response in the Arduino serial port. It's giving -1 instead of OK.
#include "SoftwareSerial.h"
String ssid = "connectify-krish";
String password = "12345678";
String myword= "";
SoftwareSerial esp(10, 11);
void setup() {
Serial.begin(9600);
esp.begin(9600);
esp.write("AT");
Serial.println(esp.read());
}
void loop() {}

As already pointed out in the comments you are not terminating the AT command line, so the modem will never respond to this.
Make sure you read V.250 and learn the difference between an AT command and an AT command line. ATI is an AT command, and "ATI I I\r" is a command line invoking this command three times in a row. Notice by the way in this example that you will get just one single Final result code for all three of them, i.e. the Final result code is a response to a complete command line and not to individual command invocations.
Then after fixing the sending of the command you must implement proper handling of the response. This includes reading and parsing what the modem sends back as a response to the sent command line. See this answer for the code structure and implementation hints.

As you've been told, terminate your AT commands with a carriage return character \r. Also you current code will read only a byte of the response, and thats if the response has even arrived since you included no delay at all. To communicate with the ESP interactively with the Serial monitor, I'd recommend using this:
#include <SoftwareSerial.h>
SoftwareSerial esp(10, 11);
void setup(){
Serial.begin(9600);
esp.begin(9600);
}
void loop()
{
while (Serial.available()) // forward data from monitor to esp
esp.write(Serial.read());
while (esp.available()) // forward data from esp to monitor
Serial.write(esp.read());
}
This basically makes your Arduino a conduit for communication between your PC and the ESP. You can send commands to the ESP with the Serial monitor and get their results immediately. Its great for testing commands. Just remember to set the serial monitor to BOTH NL & CR; this will serve you well for commands as well as any HTTP requests you send, as it appends \r\n to everything you send.
If you do want to write a sketch to talk to the ESP, you must provide some delay after sending a command to wait for the module to process the command and respond. The delay varies depending on the command, at least 500ms. The usual procedure is to define a timeout period for each command, depending on how long its expected to take, after which you 'give up' if there's no response yet. There are lots of libraries on GitHub that involve talking to some device using AT commands; study them to learn their techniques.

Related

Problems with issuing at#httpsnd command over UART

I have a custom board that features a Telit LE910C1-EUX module communicating with an ESP32 processor through UART (the ESP32 module is programmed using the ESP-IDF v4.3.2 framework).
Here's the routine I have written to send commands to the Telit module:
esp_err_t TelitSerialCommand(const char* command) {
// Send command over UART
uart_write_bytes(UART_NUM_1, command, strlen(command));
if(uart_wait_tx_done(UART_NUM_1, 100) != ESP_OK) {
ESP_LOGE(TAG, "Could not send Telit command");
return ESP_ERR_TIMEOUT;
}
// Wait for two seconds
vTaskDelay(2000/portTICK_RATE_MS);
return ESP_OK;
}
While here's the routine I have written to read the Telit's response:
esp_err_t TelitSerialRead(char* RxBuf, size_t length) {
// First, clean current string holding past message
strncpy(RxBuf, "", length);
// Check how many data bytes are present in UART buffer
esp_err_t status = uart_get_buffered_data_len(UART_NUM_1, &length);
if (status != ESP_OK) {
ESP_LOGE(TAG, "Could not get UART rx buffer size");
return status;
}
// Read those bytes
length = uart_read_bytes(UART_NUM_1, RxBuf, length, 100);
// Clean UART buffer
uart_flush(UART_NUM_1);
return ESP_OK;
}
With these two routines, I am able to send commands to the Telit module and read its responses. When it comes to performing a POST operation using at#httpsnd, however, it seems like the command doesn't get through.
Here's a list of commands I use:
at+cmee=2\r
at#sgact=1,1\r
at#httpcfg=0,"www.httpbin.org",80,0,,,0\r
at#httpsnd=0,0,"/post",15,"application/json"\r
After prompting the latter command, the Telit should reply with >>> signaling that it's ready to read serial data; what I get instead is the same command I issue, as if it was not terminated and the module was currently waiting for the \r symbol. I finally get the >>> reply after another AT command is sent, but I am sure that the at#httpsnd command is terminated with the carriage return, so I am not sure why the Telit behaves like this. If I communicate with the Telit using minicom through USB (hence bypassing the ESP32 mcu) then all the commands above work. I can ping the 8.8.8.8 server so I know I have network connection, and the GET command AT#HTTPQRY=0,0,"/get"\r works just fine.
Have you ever dealt with a similar problem? Any help would be appreciated!
Turns out I had to disable the rs232 flow control by issuing the command AT&K0

Capture QEMU Semihosted I/O

For unit testing purposes, I want to be able to run a bare-metal binary with qemu and capture it's output.
Sample file:
#include <stdio.h>
#include <stdint.h>
static void qemu_exit() {
register uint32_t r0 __asm__("r0");
r0 = 0x18;
register uint32_t r1 __asm__("r1");
r1 = 0x20026;
__asm__ volatile("bkpt #0xAB");
}
int main(void) {
puts("This is some example text that I want to capture");
qemu_exit();
return 0;
}
Running with:
qemu-system-gnuarmeclipse --nographic --no-reboot \
--board STM32F4-Discovery --mcu STM32F429ZI \
--semihosting-config enable=on,target=native \
--image <binary>
Displayed to the console is:
QEMU 2.8.0-13 monitor - type 'help' for more information
(qemu) This is some example text that I want to capture
This 'example text' is generated within QEMU and so redirecting stdout to a file does not capture it (only: QEMU 2.8.0-13 monitor - type 'help' for more information
(qemu)). Looking at the available qemu logging options -d help does not offer anything as far as I can see.
EDIT
A hacky solution is to use script to capture terminal session:
script --quiet --command <qemu-shell-script-wrapper>
That's not an upstream QEMU, and 2.8 is also quite old, but hopefully the same things that work with upstream QEMU will work there.
Firstly, assuming you're not actually using the monitor, you can get rid of that part of the output by dropping '--nographic' and instead using '-display none'. (--nographic does a lot of things all at once, including both "no graphical display" and also "default serial output to the terminal, add a QEMU monitor and multiplex the monitor and the serial", among other things. It's convenient if that's what you want but sometimes it's less confusing to specify everything separately.)
Secondly, you say you're using semihosting output but is the guest's stdlib definitely using semihosting for its puts() string output and not serial port (UART) output? The output will come out on the terminal either way but how you tell QEMU to redirect it somewhere else will differ. (I suspect it may be using UART output, because if it were using semihosting output then the redirection of stdout that you tried should have worked.)
If the output from the guest is via the serial port then you can control where it goes using the '-serial' option (most simply, "-serial stdio" to send to stdout, but you can also do more complicated things like sending to files, pipes or TCP sockets.). If it's via semihosting then you can control where it goes using the 'chardev=id' suboption of -semihosting-config.

Get signal level of the connected WiFi network

Using wpa_supplicant 2.4 on ARM Debian.
Is there a way to get signal level, in decibels or percents, of the wireless network I’m currently connected to?
STATUS command only returns the following set of values: bssid, freq, ssid, id, mode, pairwise_cipher, group_cipher, key_mgmt, wpa_state, ip_address, p2p_device_address, address, uuid
I can run SCAN afterwards, wait for results and search by SSID. But that’s slow and error-prone, I'd like to do better.
The driver should already know that information (because connected, and adjusting transmit levels for energy saving), is there a way to just query for that?
This question is not about general computing hardware and software. I'm using wpa_supplicant through a C API defined in wpa_ctrl.h header, interacting with the service through a pair of unix domain sockets (one for commands, another one for unsolicited events).
One reason I don’t like my current SCAN + SCAN_RESULT solution, it doesn’t work for hidden SSID networks. Scan doesn’t find the network, therefore I’m not getting signal level this way. Another issue is minor visual glitch at application startup. My app is launched by systemd, After=multi-user.target. Unless it’s the very first launch, Linux is already connected to Wi-Fi by then. In my app’s GUI (the product will feature a touch screen), I render a phone-like status bar, that includes WiFi signal strength icon. Currently, it initially shows minimal level (I know it's connected because STATUS command shows SSID), only after ~1 second I’m getting CTRL-EVENT-SCAN-RESULTS event from wpa_supplicant, run SCAN_RESULT command and update signal strength to the correct value.
On the API level my code is straightforward. I have two threads for that, both call wpa_ctrl_open, the command thread calls wpa_ctrl_request, the event thread has an endless loop that calls poll passing wpa_ctrl_get_fd() descriptor and POLLIN event mask, followed by wpa_ctrl_pending and wpa_ctrl_recv.
And here's the list of files in /sys/class/net/wlan0:
./mtu
./type
./phys_port_name
./netdev_group
./flags
./power/control
./power/async
./power/runtime_enabled
./power/runtime_active_kids
./power/runtime_active_time
./power/autosuspend_delay_ms
./power/runtime_status
./power/runtime_usage
./power/runtime_suspended_time
./speed
./dormant
./name_assign_type
./proto_down
./addr_assign_type
./phys_switch_id
./dev_id
./duplex
./gro_flush_timeout
./iflink
./phys_port_id
./addr_len
./address
./operstate
./carrier_changes
./broadcast
./queues/rx-0/rps_flow_cnt
./queues/rx-0/rps_cpus
./queues/rx-1/rps_flow_cnt
./queues/rx-1/rps_cpus
./queues/rx-2/rps_flow_cnt
./queues/rx-2/rps_cpus
./queues/rx-3/rps_flow_cnt
./queues/rx-3/rps_cpus
./queues/tx-0/xps_cpus
./queues/tx-0/tx_maxrate
./queues/tx-0/tx_timeout
./queues/tx-0/byte_queue_limits/limit
./queues/tx-0/byte_queue_limits/limit_max
./queues/tx-0/byte_queue_limits/limit_min
./queues/tx-0/byte_queue_limits/hold_time
./queues/tx-0/byte_queue_limits/inflight
./queues/tx-1/xps_cpus
./queues/tx-1/tx_maxrate
./queues/tx-1/tx_timeout
./queues/tx-1/byte_queue_limits/limit
./queues/tx-1/byte_queue_limits/limit_max
./queues/tx-1/byte_queue_limits/limit_min
./queues/tx-1/byte_queue_limits/hold_time
./queues/tx-1/byte_queue_limits/inflight
./queues/tx-2/xps_cpus
./queues/tx-2/tx_maxrate
./queues/tx-2/tx_timeout
./queues/tx-2/byte_queue_limits/limit
./queues/tx-2/byte_queue_limits/limit_max
./queues/tx-2/byte_queue_limits/limit_min
./queues/tx-2/byte_queue_limits/hold_time
./queues/tx-2/byte_queue_limits/inflight
./queues/tx-3/xps_cpus
./queues/tx-3/tx_maxrate
./queues/tx-3/tx_timeout
./queues/tx-3/byte_queue_limits/limit
./queues/tx-3/byte_queue_limits/limit_max
./queues/tx-3/byte_queue_limits/limit_min
./queues/tx-3/byte_queue_limits/hold_time
./queues/tx-3/byte_queue_limits/inflight
./tx_queue_len
./uevent
./statistics/rx_fifo_errors
./statistics/collisions
./statistics/rx_errors
./statistics/rx_compressed
./statistics/rx_dropped
./statistics/tx_packets
./statistics/tx_errors
./statistics/rx_missed_errors
./statistics/rx_over_errors
./statistics/tx_carrier_errors
./statistics/tx_heartbeat_errors
./statistics/rx_crc_errors
./statistics/multicast
./statistics/tx_fifo_errors
./statistics/tx_aborted_errors
./statistics/rx_bytes
./statistics/tx_compressed
./statistics/tx_dropped
./statistics/rx_packets
./statistics/tx_bytes
./statistics/tx_window_errors
./statistics/rx_frame_errors
./statistics/rx_length_errors
./dev_port
./ifalias
./ifindex
./link_mode
./carrier
You can get the signal level of the connected wifi by wpa_supplicant cmd SIGNAL_POLL
The wpa_supplicant would return:
RSSI=-60
LINKSPEED=867
NOISE=9999
FREQUENCY=5745
The value of the RSSI is the signal level.
You can get the signal level of the connected wifi by wpa_supplicant cmd BSS <bssid>.
About the bssid of the connected wifi, you can get from wpa_supplicant cmd STATUS.
https://android.googlesource.com/platform/external/wpa_supplicant_8/+/622b66d6efd0cccfeb8623184fadf2f76e7e8206/wpa_supplicant/ctrl_iface.c#1986
For iw compatible devices:
Following command gives the current station(aka AP) signal strength:
iw dev wlp2s0 station dump -v
If you need C API, just dig the source code of iw.
After a quick glance, the function you need is here
For broadcom devices, try search broadcom wl. It is close source, don't know if C API is provided.

Send probe requests without waiting for an answer in C

for a project I am working on, I have to regularly send probe requests (~ 10 every 10 ms) for a chosen SSID.
Currently I am doing this with the following code:
char *args[] = {"iwlist", INTERFACE, "scan", "essid", ssid, (char *) NULL};
runQuietlyNonblocking(args);
where runQuietlyNonblocking runs the command in args with execvp and fork without waiting for the new thread to finish.
But since iwlist scan waits for probe answers and this takes more time than I need to create new probe requests, the probe requests get send but I got about 10000 threads after about half an hour and the program crashes due to memory shortage.
I am working on a raspberry pi with raspbian lite installed.
Is there a better way to send probe requests without the need to wait for an answer? Can i send probe requests manually or tell iwlist not to look for responses?
There are a few options. As far as I know popen() with "w" parameter does not wait for command execution, though it forks the process and pclose() will wait until command executes. system() just waits for command execution, but you might try feeding it to shell like this
system("iwlist wlan0 scan &")
That is, if you are stuck with iwlist.
As an alternative you can try using wpa_supplicant. It has a "scan" interface and "scan_results", first one sends request while the later gives out results.
for (;;)
{
FILE *fp = popen ("wpa_cli -i wlan0 scan", "w");
if (fp)
pclose (fp);
sleep (1);
}
(implying wpa_supplicant is up and running).
Last but not least, there are drivers which allow doing background scanning with their own interfaces, have seen it on proprietary Redpine driver.

The simplest bridge example won't work - Arduino Yun

I tried to modify the Temperature Web Panel example (found in arduino-1.5.6-rw/libraries/Bridge/examples/TemperatureWebPanel) for a light sensor. Unfortunately it seems even the simplest receive and transmit result over wifi doesn't work! I even commented out the working part to just send back some text to the browser as you can see, but I still see nothing in the browser:
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>
// Listen on default port 5555, the webserver on the Yun
// will forward there all the HTTP requests for us.
YunServer server;
String startString;
long hits = 0;
void setup() {
Serial.begin(9600);
// For debugging, wait until the serial console is connected.
/*delay(4000);
while(!Serial);
Bridge.begin();
*/
// Bridge startup
pinMode(13, OUTPUT);
Bridge.begin();
digitalWrite(13, HIGH);
pinMode(A0, INPUT);
// Listen for incoming connection only from localhost
// (no one from the external network could connect)
server.listenOnLocalhost();
server.begin();
// get the time that this sketch started:
Process startTime;
startTime.runShellCommand("date");
while (startTime.available()) {
char c = startTime.read();
startString += c;
}
Serial.println("yeah\n");
Serial.println(startTime);
}
void loop() {
// Get clients coming from server
Serial.println("a\n");
YunClient client = server.accept();
// There is a new client?
if (client) {
Serial.println("Client!\n");
// read the command
String command = client.readString();
client.print('(This should definitely be sent over bridge)');
/*command.trim(); //kill whitespace
Serial.println(command);
// is "temperature" command?
if (command == "temperature") {
// get the time from the server:
Process time;
time.runShellCommand("date");
String timeString = "";
while (time.available()) {
char c = time.read();
timeString += c;
}
Serial.println(timeString);
int sensorValue = analogRead(A0);
// convert the reading to millivolts:
client.print("Current time on the Yún: ");
client.println(timeString);
client.print("<br>Current value: ");
client.print(sensorValue);
client.print("<br>This sketch has been running since ");
client.print(startString);
client.print("<br>Hits so far: ");
client.print(hits);
}*/
// Close connection and free resources.
client.stop();
hits++;
}
delay(50); // Poll every 50ms
}
I see the "a" multiple times in the serial monitor, but never see anything in the arduino.local/arduino/temperature url, just a blank response.
Furthurmore, after awhile it seems the Yun was disconnecting from the network, not accessible over http or ssh. How does one debug an issue like this, considering ssh is the main way to communicate with this computer?
After debugging step by step on my own configuration, I found that the code never advanced past Bridge.begin().
Upon further investigation, I found that the default Bridge baud rate of 250000 no longer matched the kernel baud rate of 115200.
Changing to: Bridge.begin(115200) ... fixed the issue for me.
To determine your kernel speed, run cat /proc/cmdline from a terminal into your Yun
See this link for more info: https://groups.google.com/forum/#!msg/linino/-rSmpjX4UOM/Cnjv-uzrlfgJ
If this isn't your issue, consider adding debug information (ie.. Serial.print()) in the actual source files for Bridge.cpp, etc. Unfortunately, it appears that Arduino/Linino devs often make breaking changes and do not have the resources to update documentation, examples, etc.
If you are on Windows, don't use 'arduino.local', because Windows has problems to resolve this host.
Have you tried with the IP address ?
You must televerse your script through wifi, and not through serial (in arduino Ide you must change the port)
Have you created the path 'arduino/www/'
You need a micro SD card plugged in to your Yún with a folder named “arduino” at the root. Inside the “arduino” folder, there must be a directory called “www”. You need to upload the sketch via WiFi to transfer the contents of the local “www” folder. You cannot transfer files via USB. Once uploaded, you can open your favorite browser and go to http://arduino.local/sd/TemperatureWebPanel.
you must open http://YUNS_IP/sd/TemperatureWebPanel
if you are using the Yun Shield u need to comment out the Serial commands or remove all references to serial as the Bridge and the Serial port all share the same hardware serial. I faced the same problem there was no connection.
Replace serial.begin(115...) by Bridge.begin().

Resources