Sending multiple raw packet over Bluetooth with Qt - python

I wrote this snippet of Python code (using pybluez) to send raw BNEP Bluetooth packet over L2CAP. The purpose is to do some fuzzing-like testing.
BNEP_PSM = 0x000F
btSock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
btSock.connect(('<some BDADDR>', BNEP_PSM))
for i in range(10):
btSock.send('<some payload>')
This is working quite fine and as expected creating multiple BNEP packet even if the payload is malformed.
Now, I'm trying to write the same function in C++ using Qt, but it is not working the same way. An excerpt of the code is the following:
QBluetoothSocket btSock(QBluetoothServiceInfo::L2capProtocol);
btSock.connectToService(QBluetoothAddress("<some BDADDR>"), QBluetoothUuid::Bnep);
QObject::connect(&btSock, &QBluetoothSocket::connected, [&btSock](){
int i = 10;
while (i--)
btSock.write("<some payload>");
});
Running it with i = 1 works just fine sending a single packet with the specified payload.
Running it with i = 10 will results in a single packet with the payload equals to ten times the specified payload.
For instance setting a payload of "AAAA" in a loop of 3 will result in the first case using Python in
+------------+----+ +------------+----+ +------------+----+
|L2CAP Header|AAAA| --> |L2CAP Header|AAAA| --> |L2CAP Header|AAAA|
+------------+----+ +------------+----+ +------------+----+
In the second case using Qt in
+------------+------------+
|L2CAP Header|AAAAAAAAAAAA|
+------------+------------+
How could I force Qt socket's write to behave like Python socket's send?
UPDATE:
Looking at the documentation it says that
The bytes are written when control goes back to the event loop
How could I force buffer to flush before going back to the event loop?

How could I force buffer to flush before going back to the event loop?
You can't, because the sending can only be done asynchronously, not synchronously.
But we can queue a flush the same way the packets are queued. Namely: send each packet after the previous one has been sent. Thus we shall send it every time the event loop has processed all other work. The idiom for that is zero-duration timers - note that this has nothing at all to do with timers, it's a weird overloading of the timer concept that really makes no sense otherwise.
int i = 10;
while (i--)
QTimer::singleShot(0, this, [this]{ m_btSocket.write("<some payload>"); });
m_btSocket must be a member of the class, and must be a value member - otherwise the code will be unsafe.
If you wish to ensure that stale packets are dumped in case of a disconnection and won't affect any subsequent connections, keep track of their generation and send only if it's current:
class Foo : public QObject {
unsigned int m_generation = {}; // unsigned: modulo math w/o overflows
QBluetoothSocket m_btSocket{QBluetoothServiceInfo::L2CAP};
...
bool isBtConnected() const { return m_btSocket::state() == QBluetoothSocket::ConnectedState; }
void sendSinglePacket(const QByteArray & data) {
if (!isBtConnected()) return;
auto gen = m_generation;
QTimer::singleShot(0, this, [this, gen, data] {
if (m_generation == gen)
m_btSocket.write(data);
});
}
Foo(QObject * parent = {}) : QObject(parent) {
connect(&m_btSocket, &QBluetoothSocket::Disconnected, this, [this]{
m_generation++; // drops all in-flight packets
});
...
}
};

I did not found a proper solution using QBluetoothSocket's methods, but I made it work with a little hack.
Just used C header sys/socket.h (I need to support POSIX compliant only OSs) and changed
btSock.write("<some payload>");
to
send(btSock.socketDescriptor(), "<some payload>", <payload length>);

Related

Unable to send byte from Python serial.write() to Arduino

I wrote a python script that sends and receive data to and from an Arduino. I can receive data without problems, but when I send data it seems like the Arduino is receiving only garbage.
The Arduino is connected to a linux pc via USB and the pc is running Python 3.8.
Since the original code contains a lot of unrelated stuff and may be distracting, I prepared the simplest possible sketch to demontrate the problem:
Python code:
#! /usr/bin/env python
import serial
import time
if __name__ == '__main__':
ser = serial.Serial("/dev/ttyACM0", 9600, timeout=0)
time.sleep(5) # Wait for Arduino to reset and init serial
ser.write(67)
Arduino sketch
const byte LED_PIN = 13;
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
void loop() {
if (Serial.available() > 0) {
byte b = Serial.read();
if (b == 67) {
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
}
}
}
This code flashes the onboard LED when receives a byte with value 67 (uppercase C). This works with the Arduino Serial Monitor, but not when running the Python script.
I feel like my problem may be related to this question, but in that case the focus was on the user not considering the case of an empty serial input buffer, while I believe the problem is actually in the sent data. This is why I decided to leave out the receiving part and simplify the example using only the onboard led.
Update
I made it work changing the last line in the python script to:
ser.write(bytes([67]))
(note the [] added around the integer value).
Anyone can explain why this syntax produces the correct result? It seems like I'm passing a single entry array to the function bytes().
Pardon my poor skills in Pyton, I know the question is probably basic.
It's really simple; the methods you tried that worked all conform to the specification for the pyserial library.
Per the Pyserial documentation:
write(data)
Parameters: data – Data to send.
Returns: Number of bytes written.
Return type: int
Raises: SerialTimeoutException – In case a write timeout is configured for the port and the time is exceeded.
Write the bytes data to the port. This should be of type bytes (or compatible such as bytearray or memoryview). Unicode strings must be encoded (e.g. 'hello'.encode('utf-8').
This is why the b'C style worked as well as the bytes call.
Attribution: Pyserial Page

ZeroMQ RADIO socket send doesn't have an option for setting a group

I'm trying to implement my own Swift wrapper for ZeroMQ with support for draft methods such as RADIO and DISH. I have been able to successfully implement a DISH wrapper for receiving data, I have been unable to implement a RADIO wrapper for sending data. From what I can see documentation about pyzmq here,
it seems to me that the pyzmq library has a built in function that allows sending messages through groups directly. However, when looking at zmq.h's send function, I don't see any way for me to send a message to a group. I can send the message using this function without any error but the message is just not received at the dish script because there is no group attached to what I sent.
Is there any way to send data via the RADIO socket by a group?
I've also done some research onto how it would be done if I used zmq_msg_t because that has a way of attaching a group. So, I used this function in Swift:
public func sendRadioMessage(group: String, data: NSData) throws{
var msg = zmq_msg_t.init();
var result : Int32;
let flags: SocketSendRecvOption = .none
result = zmq_msg_init_data(&msg, UnsafeMutableRawPointer(mutating: data.bytes), data.length, nil, nil);
if (result == -1) { throw ZeroMQError.last }
defer {
// Clean up message on scope exit
zmq_msg_close(&msg)
}
result = zmq_msg_set_group(&msg, group);
if (result == -1) { throw ZeroMQError.last }
result = zmq_msg_send(&msg, self.handle, flags.rawValue);
if (result == -1) { throw ZeroMQError.last }
print("sent \(result) bytes")
}
which comes from my previous question.
However, while the zmq_msg_send() function does return a correct number of bytes sent, my python script doesn't seem to receive the data. I know my python script works because I've used a slightly modified version of this python script from the pyzmq examples.
Q : "Is there any way to send data via the RADIO socket by a group?"
When using DRAFT archetypes ( where a SuT is still inside a flow of continuous development, the more any next level derived-artifacts, meaning any derived language wrapper or binding prototype ), one has to accept some level of discomfort, not having stable API, net having a mature API-documentation and we have to become a sort of detectives :
zmq_msg_set_group ( zmq_msg_t *msg, const char *group );
The native API ( later bent into a more pythonic-looking module ) presents this procedural step ( later perhaps bent into a just another parameter inside a call-interface of the method of a pyzmq.Socket.send() ) has it.
Stay tuned & never give up hacking the goal having the only source we have, the native API
:o)

Attempting to send/receive over Process Pipe to python wrapper, c++ code

I have a python wrapper holding some c++ code. In it is a function that I setup as a process from my python code. Its a while statement that I need to setup a condition for when it should shut down.
For this situation , the while statement is simple.
while(TERMINATE == 0)
I have data that is being sent back from within the while loop. I'm using pipe() to create 'in' and 'out' objects. I send the 'out' object to the function when I create the process.
fxn = self.FG.do_videosequence
(self.inPipe, self.outPipe) = Pipe()
self.stream = Process(target=fxn, args=(self.outPipe,))
self.stream.start()
As I mentioned, while inside the wrapper I am able to send data back to the python script with
PyObject *send = Py_BuildValue("s", "send_bytes");
PyObject_CallMethodObjArgs(pipe, send, temp, NULL);
This works just fine. However, I'm having issues with sending a message to the C++ code, in the wrapper, that tells the loop to stop.
What I figured I would do is just check poll(), as that is what I do on the python script side. I want to keep it simple. When the system sees that there is an incoming signal from the python script it would set TERMINATE = 1. so i wrote this.
PyObject *poll = Py_BuildValue("p", "poll");
As I'm expecting a true or false from the python function poll(). I figured "p" would be ideal as it would convert true to 1 and false to 0.
in the loop I have
if(PyObject_CallMethodObjArgs(pipe, poll, NULL, NULL))
TERMINATE = 1;
I wanted to use poll() as its non-blocking, like recv() is. This way I could just go about my other work and check poll() once a cycle.
however, when I send a signal from the python script it never trips.
self.inPipe.send("Hello");
I'm not sure where the disconnect is. When I print the poll() request, I get 0 the entire time. I'm either not calling it correctly, and its just defaulting to 0. or I'm not actually generating a signal to trip the poll() call. Thus its always 0.
Does anyone have any insight as what i am doing wrong?
*****UPDATE******
I found some other information.
PyObject *poll = Py_BuildValue("p", "poll");
should be
PyObject *poll = Py_BuildValue("s", "poll");
as I'm passing a string as a reference to the function im calling it should be referenced as a string. It has nothing to do with the return type.
From there the return of
PyObject_CallMethodObjArgs(pipe, poll, NULL, NULL)
is a pyobject so it needs to be checked against a pyobject. such as making a call to
PyObject_IsTrue
to determine if its true or false. I'll make changes to my code and if I have solution I'll update the post with an answer.
So I've been able to find the solution. In the end I was making two mistakes.
The first mistake was when I created the pyobject reference to the python function I was calling. I mistook the information and inserted a "p" thinking before reading the context. So
PyObject *poll = Py_BuildValue("p", "poll");
should be
PyObject *poll = Py_BuildValue("s", "poll");
The second mistake was how I was handling the return value of
PyObject_CallMethodObjArgs(pipe, poll, NULL, NULL)
while its true that its calling a python object, it is not returning a simple true false value, but rather a python object. So I specificly needed to handle the python object, by calling
PyObject_IsTrue(Pyobject o)
with the return of the poll() request as the argument. I now have the ability to send/recieve from both the python script and the C api contained in the wrapper.

implementing sendall() and recvall() in C and python

I'm currently trying to implement a sendall() function in a server written in C, and a recvall() function on the corresponding client written in python.
I can get the server and the client to work together when they're both written in the same language (i.e. both in c or both in python), but I can't get it to work with the server in c and the client in python. currently, i want to send a simple string from the c server to the python client.
Server sendall() implementation in C as follows (referenced from Beej's guide):
int sendall(int socket, char * buf, int *len){
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(socket, buf + total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
Calling the function:
char buf[10] = "test";
int len;
len = strlen(buf);
if (sendall(command_socket, buf, &len) == -1) {
perror("sendall");
printf("We only sent %d bytes because of the error!\n", len);
}
printf("Bytes sent: %d\n", len);
Client recvall() implementation in Python (referenced from http://stupidpythonideas.blogspot.com/2013/05/sockets-are-byte-streams-not-message.html):
def recv_one_message(sock):
lengthbuf = recvall(sock, 4)
length, = struct.unpack('!I', lengthbuf)
return recvall(sock, length)
def recvall(sock, count):
buf = ''
while count:
newbuf = sock.recv(count)
print newbuf
if not newbuf:
return None
buf += newbuf
count -= len(newbuf)
return buf
Called as:
buf = recv_one_message(command_socket)
print buf
Whenever I send a message from the C-server to the Python-client, I get a return of "None." I've traced the the response coming in on the client side -- it is getting the message I sent, but the final response is always "none" and the message won't be printed. I've also tried just returning the message instead of having the None return, which also results in nothing getting printed. Can't see where I'm going wrong, any thoughts? Thanks.
Say you have a perfectly fluent English speaker and a perfectly fluent French speaker. They will not be able to communicate with each other very well. Who is at fault? -- Whoever put the two of them together expecting them to be able to communicate without first agreeing on how they would communicate.
Your send function and your receive function implement totally different protocols. The send function requires the receiver to already know the length of the data to receive. Your receive function requires the sender to send the length prior to the data. So you cannot mix and match them because they do not use the same wire format
Here's some valuable advice gained over decades of experience: Never attempt to use TCP without first documenting the protocol you're going to use on top of TCP at the byte level. As it is, there's no way to know which function is right and which is wrong because nobody has any idea what bytes are supposed to be sent over the wire.
TCP is a byte-stream protocol, and for two programs to work correctly with a TCP connection between them, each must send precisely the stream of bytes the other expects to receive. The best way to make sure this happens is to first document that stream of bytes.
If you have no idea where to start with such documentation, have a look at the simplest existing protocol that's analogous to what you're trying to do. Possible protocols to look at it include HTTP, SMTP, IRC, and DNS.

Control a specific pin on the Arduino Uno board using pyserial

I have a python code that sends in a pattern, in which a light has to blink in. (say eg. 101010. pattern may vary every time the code is run). when it is executing this infinitely i want an interrupt( again sent by the python code )to save the present conditions of the lights (say it is running 1 of the sequence) and perform a specific task like turn off the lights for 10 seconds and then resume the sequence.
one way of doing this is by interrupting the program by making the interrupt pin high. The question is can this making of high/low controlled by the pyserial.
So a simple pseudo code would be :
PYTHON part of the code:
Read the sequence:
Send the sequence to the arduino board using pyserial.
while(1)
{
Run a timer for 15 second.
When the timer overflows interrupt the arduino.
}
ARDUINO part of the code :
Read the sequence
while (1)
{
keep repeating the sequence on the LED.
}
// if interrupted on pin2 // assuming pin2 has the interrupt procedure
// Pyserial has to enable the interrupt WITHOUT using a switch for enabling the pin.
ISR
{
Save the present state of execution.
Turn off the LED.
}
FOR A BETTER UNDERSTANDING :
I built up small codes to show the doubts i had :
CODE FOR THE ARDUINO IS :
int ledpin1 = 13;
int speedy;
int patterns;
void setup()
{
Serial.begin(9600);
Serial.print("Program Initiated: \n");
pinMode(ledpin1,OUTPUT);
//activate the blackout ISR when a interrupt is achieved at a certain pin. In this case pin2 of the arduino
attachInterrupt(0,blackout,CHANGE);
}
void loop()
{
if (Serial.available()>1)
{
Serial.print("starting loop \n");
patterns = Serial.read();
patterns = patterns-48;
speedy = Serial.read();
speedy = (speedy-48)*1000;
while(1)
{
patterns = !(patterns);
Serial.print(patterns);
digitalWrite(ledpin1,patterns);
delay(speedy);
}
}
}
/*
void blackout()
{
// ***Save the present state of the LED(on pin13)***
Serial.print ("The turning off LED's for performing the python code\n");
digitalWrite(ledpin,LOW);
//wait for the Python code to complete the task it wants to perform,
//so got to dealy the completion of the ISR
delay(2000);// delay the whole thing by 2 seconds
//***Continue with the while loop by setting the condition of the light to the saved condition.***
}
*/
==================================================================================
CODE FOR THE PYTHON FRONT IS :
import serial
import time
patterns=1
speedy=1
ser = serial.Serial()
ser.setPort("COM4")
ser.baudrate = 9600
ser.open()
def main():
if (ser.isOpen()):
#while(1):
ser.write(patterns)
ser.write(speedy)
blackoutfunc()
#ser.close()
def blackoutfunc():
while(1):
time.sleep(2)
print "Performing operations as required"
===============================================================================
Now the questions I had :
1) Is there a way to be able to activate the "blackout ISR" depending on the conditions of a pin(in this case pin2 which is the INT0 pin) without using a physical switch present on the pin. Hence the pin state has to be manipulated by the software.
2) Is it possible to perform the operations as mentioned in the comments of the blackout functions?
3) In the python code is it possible to just send in the data(i.e. patterns,speedy) only once and make the arduino perform the pattern in a infinite way without again sending the data by the serial.write command. Hence avoiding the while(1) loop after the ser.isOpen().
Have a look at this:
https://github.com/ajfisher/arduino-command-server
It's something I pulled together on the Arduino side to issue arbitrary commands like switch a pin high / low and set PWM levels etc. It works over both serial and network though it's a touch buggy on the network side at the moment.
To use it, put the code on your arduino then you just write a python script (or any other language that can use a serial connection) to connect over the serial connection and then tell it what you want to do eg DIGW 1 HIGH etc
Also have a look at: https://github.com/ajfisher/arduino-django-visualiser which is where I use a variation of this library to control some LEDs based on some things going on in Django - it's more heavily python based.

Categories