Heltec ESP32 LoRa Receive Interrupt - esp32

I’m trying to make a LoRa sender/receiver board.
Therefore the plan is to send some messages whenever I want, but if there is an incoming packet, I want to interrupt the sending-process (for beginning without any sending retries) and receive the incoming packet.
I tried the mix of the Heltec examples “OLED_LoRa_Sender” and “LoRaReceiverInterrupt”, and it works fine until I’m sending and receiving a message at the same time. Then the receive interrupt does not interrupt.
How can I solve that?
Thanks a lot in advance
if (sendMsg && !receivingMsg) { // sendMsg drives true, if PRG button is pressed receivingMsg drives try in "void onReceive(int packetSize)"
/*
Heltec.display->clear();
Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
Heltec.display->setFont(ArialMT_Plain_10);
//Serial.println(WiFi.macAddress());
Heltec.display->drawString(0, 0, "Sending packet: ");
Heltec.display->drawString(0, 15, WiFi.macAddress());
Heltec.display->drawString(100, 15, String(counter));
Heltec.display->display();
*/
LoRa.beginPacket();
LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
LoRa.print("hello ");
LoRa.print(counter);
LoRa.endPacket();
delay(10); // give me time to bring up serial monitor
counter++;
// put the radio into receive mode
LoRa.receive();
sendMsg = false;
}
}

Related

How to send AT commands to ESP32 LilyGo-T-Call-SIM800?

I've been working with a LilyGo-TCall-SIM800 module for several days, trying to get out of a dead end.
I have tried an example from "random nerd tutorials" which works correctly. The module connects to the internet and can send data to the cloud.
I have the problem to send AT commands to the SIM800L chip integrated in the module. I can't get the chip to react back.
I have tried using Serial1 and Serial2. I have also tried configuring the RX and TX transmission pins, and I have tried with different baudrates. Always with negative results... when sending the "AT\r" command to the SIM800L, it should return "OK". But it never does.
I have simplified the code as much as possible to minimize errors:
/*
Name: TestAT.ino
Created: 08/12/2022 23:15:28
Author: user
*/
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
// Comunications between ESP32 and SIM800L
#define SerialAT Serial1
//Comunications between ESP32 ans SIM800L go thought TX and RX pins on Serial1 Port
#define MODEM_RX1 16
#define MODEM_TX1 17
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(1000);
//Set SerialAT baud rate
SerialAT.begin(38400, SERIAL_8N1, MODEM_RX1, MODEM_TX1);
//Set timeLimit for SerialAT reads
SerialAT.setTimeout(2000);
}
void loop() {
String returned = "";
char ATcommand[] = { 'A','T','\r' };
SerialAT.print(ATcommand);
delay(1000);
returned = SerialAT.readString();
SerialMon.print(millis());
SerialMon.print(" - ");
SerialMon.print(ATcommand);
SerialMon.print(" - SerialAT returned:");
SerialMon.println(returned);
}
Anybody can help me out on this? Any idea or sugestion?
Thanks in advance

How to correctly receive data using ZeroMQ?

I have two machines in the same network :
The first machine binds to a socket on its own IP address (120.0.0.1) and receives any data coming to the socket .bind()-ed on port 5555:
zmq::context_t context{1};
zmq::socket_t socket{context, ZMQ_SUB};
socket.setsockopt(ZMQ_SUBSCRIBE, "lidar");
socket.bind("tcp://120.0.0.1:5555");
while(true)
{
zmq::message_t message;
auto recv = socket.recv(message);
ROS_INFO("Value: %d", recv.value());
}
The second machine, having an IP address 120.0.0.248, connects to the first machine and sends the messages to it:
sock.connect("tcp://120.0.0.1:5555");
while (1) {
double nodes[8192];
sock.send(zmq::buffer("lidar") , zmq::send_flags::sndmore);
sock.send(zmq::buffer(nodes, (((int)(count)) * 8)));
}
But for some reason, I cannot receive any messages on the first machine and it gets stuck on auto recv = socket.recv(message);.
What is a correct way for such communication?

Sending echo to Arduino serial port on MAC(osx)

I am trying to send an echo from a shell script on some event.
echo naval > /dev/cu.usbmodem1421
on this /dev/cu.usbmodem1421 serial port my Blend Micro Atmega32u4 Board is listening.
But every time I send an echo it says, resource busy.
I am not sure what can be the solution?
Arduino code:
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print((char)incomingByte);
}
}
have you tried killing the process ?, it seems it is hanging waiting a bit broad of a question but it could be caused by numerous things.

Linux USB driver: Interrupt URBs

I suppose I actually have two separate questions, but I think that they are related enough to include them both. The context is a Linux USB device driver (not userspace).
After transmitting a request URB, how do I receive the response once my complete callback is called?
How can I use interrupt URBs for single request/response pairs, and not as actual continuous interrupt polling (as they are intended)?
So for some background, I'm working on a driver for the Microchip MCP2210 a USB-to-SPI Protocol Converter with GPIO (USB 2.0, datasheet here). This device advertises as generic HID and exposes two interrupt endpoints (an in and an out) as well as it's control endpoint.
I am starting from a working, (but alpha-quality) demo driver written by somebody else and kindly shared with the community. However, this is a HID driver and the mechanism it uses to communicate with the device is very expensive! (sending a 64 byte message requires allocating a 6k HID report struct, and allocation is sometimes performed in the context of an interrupt, requiring GFP_ATOMIC!). We'll be accessing this from an embedded low-memory device.
I'm new to USB drivers and still pretty green with Linux device drivers in general. However, I'm trying to convert this to a plain-jane USB driver (not HID) so I can use the less expensive interrupt URBs for my communications. Here is my code for transmitting my request. For the sake of (attempted) brevity, I'm not including the definition of my structs, etc, but please let me know if you need more of my code. dev->cur_cmd is where I'm keeping the current command I'm processing.
/* use a local for brevity */
cmd = dev->cur_cmd;
if (cmd->state == MCP2210_CMD_STATE_NEW) {
usb_fill_int_urb(dev->int_out_urb,
dev->udev,
usb_sndintpipe(dev->udev, dev->int_out_ep->desc.bEndpointAddress),
&dev->out_buffer,
sizeof(dev->out_buffer), /* always 64 bytes */
cmd->type->complete,
cmd,
dev->int_out_ep->desc.bInterval);
ret = usb_submit_urb(dev->int_out_urb, GFP_KERNEL);
if (ret) {
/* snipped: handle error */
}
cmd->state = MCP2210_CMD_STATE_XMITED;
}
And here is my complete fn:
/* note that by "ctrl" I mean a control command, not the control endpoint */
static void ctrl_complete(struct urb *)
{
struct mcp2210_device *dev = urb->context;
struct mcp2210_command *cmd = dev->cur_cmd;
int ret;
if (unlikely(!cmd || !cmd->dev)) {
printk(KERN_ERR "mcp2210: ctrl_complete called w/o valid cmd "
"or dev\n");
return;
}
switch (cmd->state) {
/* Time to rx the response */
case MCP2210_CMD_STATE_XMITED:
/* FIXME: I think that I need to check the response URB's
* status to find out if it was even transmitted or not */
usb_fill_int_urb(dev->int_in_urb,
dev->udev,
usb_sndintpipe(dev->udev, dev->int_in_ep->desc
.bEndpointAddress),
&dev->in_buffer,
sizeof(dev->in_buffer),
cmd->type->complete,
dev,
dev->int_in_ep->desc.bInterval);
ret = usb_submit_urb(dev->int_in_urb, GFP_KERNEL);
if (ret) {
dev_err(&dev->udev->dev,
"while attempting to rx response, "
"usb_submit_urb returned %d\n", ret);
free_cur_cmd(dev);
return;
}
cmd->state = MCP2210_CMD_STATE_RXED;
return;
/* got response, now process it */
case MCP2210_CMD_STATE_RXED:
process_response(cmd);
default:
dev_err(&dev->udev->dev, "ctrl_complete called with unexpected state: %d", cmd->state);
free_cur_cmd(dev);
};
}
So am I at least close here? Secondly, both dev->int_out_ep->desc.bInterval and dev->int_in_ep->desc.bInterval are equal to 1, will this keep sending my request every 125 microseconds? And if so, how do I say "ok, ty, now stop this interrupt". The MCP2210 offers only one configuration, one interface and that has just the two interrupt endpoints. (I know everything has the control interface, not sure where that fits into the picture though.)
Rather than spam this question with the lsusb -v, I'm going to pastebin it.
Typically, request/response communication works as follows:
Submit the response URB;
submit the request URB;
in the request completion handler, if the request was not actually sent, cancel the response URB and abort;
in the response completion handler, handle the response data.
All that asynchronous completion handler stuff is a big hassle if you have a single URB that is completed almost immediately; therefore, there is the helper function usb_interrupt_msg() which works synchronously.
URBs to be used for polling must be resubmitted (typically from the completion handler).
If you do not resubmit the URB, no polling happens.

C++/Win. Not getting FD_CLOSE

I have an asynchronous socket and call to connect() + GetLastError() which returns WSA_WOULD_BLOCK, as expected. So I start "receiving/reading" thread and subscribe Event to FD_READ and FD_CLOSE.
The story is: connect will sequentially fail, since Server is not up and running. My understanding that my receiving thread should get FD_CLOSE soon and I need to follow-up with cleaning.
It does not happen. How soon should I receive FD_CLOSE? Is it proper approach? Is there any other way to understand that connect() failed? Shoul I ever receive FD_CLOSE if socket isn't connected?
I do start my receiving thread and subscribe event after successful call to DoConnect() and I am afraid that racing condition prevents me from getting FD_CLOSE.
Here is some code:
int RecvSocketThread::WaitForData()
{
int retVal = 0
while (!retVal)
{
// sockets to pool can be added on other threads.
// please validate that all of them in the pool are connected
// before doing any reading on them
retVal = DoWaitForData();
}
}
int RecvSocketThread::DoWaitForData()
{
// before waiting for incoming data, check if all sockets are connected
WaitForPendingConnection_DoForAllSocketsInThePool();
// other routine to read (FD_READ) or react to FD_CLOSE
// create array of event (each per socket) and wait
}
void RecvSocketThread::WaitForPendingConnection_DoForAllSocketsInThePool()
{
// create array and set it for events associated with pending connect sockets
HANDLE* EventArray = NULL;
int counter = 0;
EventArray = new HANDLE[m_RecvSocketInfoPool.size()];
// add those event whose associated socket is still not connected
// and wait for FD_WRITE and FD_CLOSE. At the end of this function
// don't forget to switch them to FD_READ and FD_CLOSE
while (it != m_RecvSocketInfoPool.end())
{
RecvSocketInfo* recvSocketInfo = it->second;
if (!IsEventSet(recvSocketInfo->m_Connected, &retVal2))
{
::WSAEventSelect(recvSocketInfo->m_WorkerSocket, recvSocketInfo->m_Event, FD_WRITE | FD_CLOSE);
EventArray[counter++] = recvSocketInfo->m_Event;
}
++it;
}
if (counter)
{
DWORD indexSignaled = WaitForMultipleObjects(counter, EventArray, WaitAtLeastOneEvent, INFINITE);
// no matter what is further Wait doen't return for failed to connect socket
if (WAIT_OBJECT_0 <= indexSignaled &&
indexSignaled < (WAIT_OBJECT_0 + counter))
{
it = m_RecvSocketInfoPool.begin();
while (it != m_RecvSocketInfoPool.end())
{
RecvSocketInfo* recvSocketInfo = it->second;
if (IsEventSet(recvSocketInfo->m_Event, NULL))
{
rc = WSAEnumNetworkEvents(recvSocketInfo->m_WorkerSocket,
recvSocketInfo->m_Event, &networkEvents);
// Check recvSocketInfo->m_Event using WSAEnumnetworkevents
// for FD_CLOSE using FD_CLOSE_BIT
if ((networkEvents.lNetworkEvents & FD_CLOSE))
{
recvSocketInfo->m_FD_CLOSE_Recieved = 1;
*retVal = networkEvents.iErrorCode[FD_CLOSE_BIT];
}
if ((networkEvents.lNetworkEvents & FD_WRITE))
{
WSASetEvent(recvSocketInfo->m_Connected);
*retVal = networkEvents.iErrorCode[FD_WRITE_BIT];
}
}
++it;
}
}
// if error - DoClean, if FD_WRITE (socket is writable) check if m_Connected
// before do any sending
}
}
You will not receive an FD_CLOSE notification if connect() fails. You must subscribe to FD_CONNECT to detect that. This is clearly stated in the connect() documentation:
With a nonblocking socket, the connection attempt cannot be completed
immediately. In this case, connect will return SOCKET_ERROR, and
WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are
three possible scenarios:
•Use the select function to determine the completion of the
connection request by checking to see if the socket is writeable.
•If the application is using WSAAsyncSelect to indicate interest in
connection events, then the application will receive an FD_CONNECT
notification indicating that the connect operation is complete
(successfully or not).
•If the application is using WSAEventSelect to indicate interest in
connection events, then the associated event object will be signaled
indicating that the connect operation is complete (successfully or
not).
The result code of connect() will be in the event's HIWORD(lParam) value when LOWORD(lParam) is FD_CONNECT. If the result code is 0, connect() was successful, otherwise it will be a WinSock error code.
If you call connect() and get a blocking notification you have to write more code to monitor for connect() completion (success or failure) via one of three methods as described here.
With a nonblocking socket, the connection attempt cannot be completed
immediately. In this case, connect will return SOCKET_ERROR, and
WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are
three possible scenarios:
•Use the select function to determine the completion of the connection
request by checking to see if the socket is writeable.
•If the
application is using WSAAsyncSelect to indicate interest in connection
events, then the application will receive an FD_CONNECT notification
indicating that the connect operation is complete (successfully or
not).
•If the application is using WSAEventSelect to indicate interest
in connection events, then the associated event object will be
signaled indicating that the connect operation is complete
(successfully or not).
I think I need to start Receving thread once socket handle is created, but before connect is called. It is too late to create it after connect was called on asynchronous socket.
For synchronous socket those two calls createsocket() and connect() was just two consequitive lines. Does not work for non-blocking.
In this case at the beginning of receiving thread I need to check for FD_CONNECT and/or FD_WRITE in order be informed of connect attempt status.

Resources