Sim800l: how to know network state reliably - arduino

In Sim800L AT-Commands Guide there are a lot of different status commands, that should tell, what state does is have.
For example:
AT+CPAS - check if device is ready
AT+CGREG? - check registration status in network
AT+CGATT? - check if device "attached to network"
AT+CSQ - get signal level
But, in some cases, answers to this commands could be an "ERROR", or no answer at all.
I need a reliable and fast method to know is device connected to network, or it's already in GPRS mode, and for now I came to use blinking LED on Sim800L to detect it's state.
LED has three blinking frequencies:
Fast blinking - GPRS connection is active
Medium speed of blinking - Network connection is not established yet
Slow blinging - Device is connected to network (but not the GPRS)
I can use photodiode and "read" blinging of LED, or I can wire LED's power pin to analog pin of Arduino, and read it's voltage. Next, I can count how fast LED is blinking, and determine, which state Sim800L in.
But how do I get this level of reliability without using such a crutch?

Given fast means 1 sec you could send an AT command e.g. five times and take 3 non error responses as a valid result. See pseudo code
uint8_t errorCount = 0;
for (uint8_t i=0;i<5;i++){
.... send AT command ...
if (response == "error") errorCount++;
if (errorCount >=3) errorHandling();
}
... process successful AT command ...
or your HW approach with LED to analog pin

Related

ESP32 Switch Between Promiscuous and STA Mode

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);

Sending fixed voltage to serial port

I need to monitor if a door is opened. I have a sensor that continues to generate +5V DC as long as the door is shut but drops down to 0V once the door is opened.
I now need to connect the sensor's output wire to PC's serial port and write a program that continuously polls the port.
My thought is that various serial-io parameters such as baud rate, etc., does not matter in my case. For each byte that I read, I expect the value to be 255 (logical 1s) when the door is closed. Otherwise, I will assume that the door has been opened. Is there any flaw in this logic?
I went through Sending a voltage to RS232. It appears I just need to connect the wire to pin 2 (RX). However, for the serial port to receive a logical 1, it seems the voltage needs to be between -3V and -12V. As the voltage my sensor generates is positive, I am thinking I will connect the sensor wire to pin 5 (GND) instead and connect pin 2 to ground. In effect, I inverted the voltage. Will this work?
If this logic is flawed, I may have to buy a voltage inverter.
Finally, I was told that one should not connect anything to pin 5 on a motherboard's serial port. Apparently, it is hardwired to get grounded to the chassis. Is this true? Regards.
Like mentioned in the comments, constant high would not produce 255 bytes.
I would implement this by connecting the GND to GND and connecting the +5 Vdc to the CTS pin, which can be queried for his HIGH / LOW state.
But this is only a hack, you really should use some microcontroller.

multiple i2c can't work with arduino uno

I am trying to connect 2 I2C modules to arduino uno. GY86(HMC5883L,MS5611,MPU6050) and BMP085 or any other I2C module. When i test each one separately it works ok but when both are connected to the I2C bus port, Every thing ruins. th moment i connect the BMP module, GY86 starts to output wrong numbers. I also tested my GY86 with DS1307 module. same thing happens and the moment i connect them, the DS starts to output wrong random output. i tried to apply a pull up resistor for SDA and SCL but didn't work. Whats the problem?
I2C at the Hardware Level
Signals
Each I2C bus consists of two signals: SCL and SDA. SCL is the clock signal, and SDA is the data signal. The clock signal is always generated by the current bus master; some slave devices may force the clock low at times to delay the master sensing more data.
Unlike UART or SPI connections, the I2C bus drivers are "open drain", meaning that they can pull the corresponding signal low, but cannot drive it high. Thus, there can be no bus contention where one device is trying to drive the line high while another tries to pull it low, eliminating the potential for damage to the drivers or excessive power dissipation in the system. Each signal line has a pull_up resistor on it, to restore the signal to high when no device is asserting it low.
Resistor selection varies with devices on the bus, but a good rule of thumb is to start with 4.7k and adjust down.
Signal Levels
Since the devices on the bus don't actually drive the signals high, I2C allows for some flexibility in connecting devices with different I/O voltages. In general, in a system where one device is at a higher voltage level than another, it may be possible to connect the two devices via I2C without any level shifting circuitry in between them. The trick is to connect the pull_up resistor to the lower of the two voltages. This only work in some cases, where the lower of the two system voltages exceeds the high-level input voltage of the higher voltage system - for example, a 5V Arduino and a 3.3V accelerometer.
Protocol
Communication via I2C is more complex that with UART or SPI solution. The signalling must adhere to a certain protocol for the devices on the bus to recognize it as valid I2C communications.
Basics
Messages are broken up into two types of frame: an address frame, where the master indicates the slave to which the message is being sent, and one or more data frames, which are 8-bit data messages passed from master to slave or vice versa. Data is placed on the SDA line after SCL goes low, and is sampled after the SCL line goes high. The time between clock edge and data read/write is defined by the devices on the bus and will vary from chip to chip.
Start Condition
To initiate the address frame, the master device leaves SCL high and pulls SDA low. This puts all slave devices on notice that a transmission is about to start. If two master devices wish to take ownership of the bus at one time, whichever device pulls the SDA low first wins the race and gains control of the bus. It is possible to issue repeated starts, initiating a new communication sequence without relinquishing control of the bus to other masters.
Address Frame
The address frame is always first in any new communication sequence. For a 7-but address, the address is clocked out most significant bit (MSB) first, followed by a R/W bit indicating whether this is a read (1) or write (0) operation.
The 9th bit of the frame is the NACK/ACK bit. This is the case for all frames (data or address).
Once the 8 bit of the frame are sent, the receiving device is given control over SDA. If the receiving device does not pull the SDA line low before the 9th clock pulse, it can be inferred that the receiving device either did not receive the data or did not know how to parse the message. In that case, the exchange halts, and it's up to the master of the system to decide how to proceed.
Data Frames
After the address frame has been sent, data can begin being transmitted. The master will simply continue generating clock pulses at a regular interval, and the data will be placed on SDA by either the master or the slave, depending on whether the R/W bit indicated a read or write operation. The number of data frames is arbitrary, and most slave devices will auto-increment the internal register, meaning that subsequent reads or writes come from the next register in line.
Stop Condition
Once all the data frames have been sent, the master will generate a stop condition. Stop conditions are defined by a 0->1 (low to high) transition an SDA after a 0->1 transition on SCL, with SCL remaining high. During normal data writing operation, the value on SDA should not change when SCL is high, to avoid stop condition.
I think several devices have same address. That's why you receive bad data. Usually I2C devices have extra pins to setup lower bits of addr. Do it and don't forget to change corresponding software definitions.
Update:
MPU6050 has input pin, which specifies LSB of I2C addr. You need tie this pin to high level 3.3V. Otherwise MPU6050 will have same addr as DS1307. I know it for sure, because work with both ICs a lot. To do it you need broke wire between 9nth pin of MPU6050 and Gnd. And solder it through resistor >3k to 3,3V. Or not use DS1307. From memory there is ds1302 rtc module.
You should find datasheets for all ICs you use and check what are their I2C addresses. The board consists of three parts, so you must know those 3 addresses.

Possible reason why Xbee is not able to send data

I am using an Arduino Pro Mini 328P (3.3v, 8Mhz) with Xbee series 1. I have set the frequency to 1 Mhz and the baudrate to 9600. Also I have set baudrate to 9600 in the Xbee. I have also tested that at this baudrate Xbee is sending the data properly in a normal scenario.
Now what I have done in my project:
I have registered my Xbee with the gateway and then it will go to sleep (I have used pin hibernate mode) then it will wake up by a digital pin of the Pro Mini. I have put a delay of 19ms, after which the Xbee will try to send data. After sending the data it will go back to sleep.
The problem is that it behaves randomly when sending data to the gateway (which also has the same Xbee series1). Sometimes it sends the data perfectly, sometimes sending fails. I have also enabled RR to retry 6 times in case the Xbee fails to send the data the first time.
I have no idea how to solve this problem because of the randomness in sending the data.
I have put two Xbees nearer (I have two nodes with the same hardware and the same code). There is an interval between of around 4 minutes. So when one Xbee sends the data perfectly, after that 4 minutes gae (time difference of two RTC on different nodes) the other one fails to send the data. In this condition what can I conclude?
As a side note, the Xbee will try to send the data every hour. To calculate that hour I have to use an RTC, which seems to work fine (I am sure because I have taken the logs, the RTC never fails to generate an interrupt).
So I am wondering what could be the possible reason and how can I fix this problem (without restarting anything if it is possible then nothing will be better than that).
And I have no choice to restart my controller.
How to debug this?
A few things. If possible, increase your baud rate so you spend less time sending data to/from the XBee. If you have a limited power budget, faster baud rates save time and energy. I don't know how the UARTs work on the Arduino, so I can't say whether 115,200bps is possible with a 1MHz CPU clock.
Second, make sure you wait for the XBee to assert CTS back to the Arduino after you wake it up. Never send to the XBee unless it's "clear to send".
Third, if you use API mode, you can watch for a "Transmit Status" frame from the local XBee back to the Arduino which will let you know when the module has successfully sent the frame, and it's safe for you to put it back to sleep.

Cannot connect to ESP8266 after serial speed change

After some trial and error, tonight my Arduino Uno began talking to an ESP8266 module, with the most common wiring, 3.3V power to the module from a well-sized external supply, direct connection of the 3.3V TX line, and a voltage divider to read from the 5V RX.
SoftwareSerial esp8266(2,3);
void setup()
{
Serial.begin(9600);
esp8266.begin(115200);
char buffer[50];
esp8266.write("AT\r\n");
esp8266.readBytes(buffer, sizeof(buffer));
Serial.println(buffer);
}
After setting the 115200 speed for the ESP8266<->Arduino serial communication, some clear boot messages and command responses appeared on the serial monitor.
Since these messages were interleaved by some garbage characters, I tried reducing the communication speed.
For this purpose I issued the command AT+IPR=9600 to the module, which immediately showed some action on the blue LED, an OK response on the console and finally resulted in the same LED being fixed on.
I consequently adjusted the serial speed on the Arduino side, with esp8266.begin(9600);, but could never obtain any further communication with the module.
I can now see garbage only at any speed.
Could the module have escalated to a different speed? I tried many of them (4800, 57600, 19200, back to 115200 etc.) but no clear response appeared on the monitor.
May you suggest any attempt to reestablish the connection? Any way to reset the last command result?
I'd rather avoid setting up for firmware update, if any simpler solution can be tried.
Here is the solution!
The AT+IPR command was known to break the firmware and make the module unresponsive until a complete reflash.
I found the solution in this forum discussion.

Resources