I have to write logfile to trace init sequence from my simulator application - printf

So, I dont have much idea about logfile and i need to write a logfile using fprintf between BlueModPlusS50::Send and BlueModPlusS50::Receive as you can check in the code, so that it can trace init, scan and print sequences from the simulator application that i use. So please help me to understand what it actually means and how to do that. Even if there are different versions of your understanding, you may let me know. I am using Visual Studio 2019.
void BlueModPlusS50::Send(std::shared_ptr< Message > msg, const ms timeout) {
#ifdef SIMULATION
DWORD BytesWritten = 0;
printf(">>>>>>%s<<<<<<", msg->GetPayload());
bool Status = WriteFile(com_handle_, // Handle to the Serialport
msg->GetPayload(), // Data to be written to the port
msg->GetSize(), // No of bytes to write into the port
&BytesWritten, // No of bytes written to the port
NULL);
if (Status == FALSE) {
printf_s("\nFail to Written");
}
#endif // SIMULATION
}
void BlueModPlusS50::Receive(std::shared_ptr<Message> msg) {
#ifdef SIMULATION
DWORD NoBytesRead; // Bytes read by ReadFile()
char ReadData; // temporary Character
unsigned char received = 0;
auto payload = msg->GetPayload();
do {
bool Status = ReadFile(com_handle_, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
if (NoBytesRead > 0) {
payload[received] = ReadData;
printf("%c", ReadData);
++received;
}
} while (received < msg->GetSize());
msg->SetSize(received);

Related

Error in uploading sensor data to Azure IOT central

I have watched this video and tried to implement the same using all the required components and I have been getting errors in getting connected to the portal and am neither getting output from sensors.
this is the code that I have been using:
`
#include "DHT.h" // including the library of DHT11 temperature and humidity sensor
#include <ESP8266WiFi.h>
#define DHTTYPE DHT11
#include "D:/ARDUINO/ESP8266/ESP8266/src/iotc/common/string_buffer.h"
#include "D:/ARDUINO/ESP8266/ESP8266/src/iotc/iot"
#include "D:/ARDUINO/ESP8266/ESP8266/src/connection.h"
#define dht_dpin 12 // creating the object sensor on pin 'D12'
DHT dht(dht_dpin, DHTTYPE);
#define WIFI_SSID "<ENTER WIFI SSID>"
#define WIFI_PASSWORD "<ENTER WIFI PASSWORD>"
const char* SCOPE_ID = "<ENTER SCOPE ID>";
const char* DEVICE_ID = "<ENTER DEVICE ID>";
const char* DEVICE_KEY = "<ENTER DEVICE KEY>";
int echoPin = D6;
int trigPin = D8;
int pingTravelTime;
float pingTravelDistance;
float distanceToTarget;
float speedOfsound;
void on_event(IOTContext ctx, IOTCallbackInfo* callbackInfo);
void on_event(IOTContext ctx, IOTCallbackInfo* callbackInfo) {
// ConnectionStatus
if (strcmp(callbackInfo->eventName, "ConnectionStatus") == 0) {
LOG_VERBOSE("Is connected ? %s (%d)",
callbackInfo->statusCode == IOTC_CONNECTION_OK ? "YES" : "NO",
callbackInfo->statusCode);
isConnected = callbackInfo->statusCode == IOTC_CONNECTION_OK;
return;
}
// payload buffer doesn't have a null ending.
// add null ending in another buffer before print
AzureIOT::StringBuffer buffer;
if (callbackInfo->payloadLength > 0) {
buffer.initialize(callbackInfo->payload, callbackInfo->payloadLength);
}
LOG_VERBOSE("- [%s] event was received. Payload => %s\n",
callbackInfo->eventName, buffer.getLength() ? *buffer : "EMPTY");
if (strcmp(callbackInfo->eventName, "Command") == 0) {
LOG_VERBOSE("- Command name was => %s\r\n", callbackInfo->tag);
}
dht.begin();
}
void setup() {
Serial.begin(9600);
connect_wifi(WIFI_SSID, WIFI_PASSWORD);
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
if (context != NULL) {
lastTick = 0; // set timer in the past to enable first telemetry a.s.a.p
}
pinMode(trigPin,OUTPUT);
pinMode(echoPin,INPUT);
}
void loop() {
digitalWrite(trigPin,LOW);
delayMicroseconds(10);
digitalWrite(trigPin,HIGH);
delayMicroseconds(10);
digitalWrite(trigPin,LOW);
float h = dht.readHumidity();
float t = dht.readTemperature();
// Reading the temperature in Celsius degrees and store in the t variable
// Reading the humidity index and store in the h variable
pingTravelTime = pulseIn(echoPin,HIGH);
delay(25);
pingTravelDistance = (pingTravelTime*330*100)/(1000000);
speedOfsound = (pingTravelDistance*1000000)/pingTravelTime;
distanceToTarget = pingTravelDistance/2;
if (isConnected) {
unsigned long ms = millis();
if (ms - lastTick > 10000) { // send telemetry every 10 seconds
char msg[64] = {0};
int pos = 0, errorCode = 0;
lastTick = ms;
if (loopId++ % 4 == 0) { // send telemetry
pos = snprintf(msg, sizeof(msg) - 1, "{\"Temperature\": %f}",
t);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Humidity\":%f}",
h);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Distance\":%f}",
distanceToTarget);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Speed\":%f}",
speedOfsound);
errorCode = iotc_send_telemetry(context, msg, pos);
} else { // send property
}
msg[pos] = 0;
if (errorCode != 0) {
LOG_ERROR("Sending message has failed with error code %d", errorCode);
}
}
iotc_do_work(context); // do background work for iotc
} else {
iotc_free_context(context);
context = NULL;
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
}
delay(50);
}
`
I tried to implement this project for a thesis of mine and was not getting the results since the connection is not being established.
These are the errors i was getting:
ERROR: couldn't fetch the time from NTP. - -
X - Error at connection.h:32
Error # tcp_connect. Code 1 -
ERROR: Client was not connected. - -
iot.dps : getting auth... -
iotc.dps : getting operation id... -
ERROR: DPS endpoint PUT call has failed.
this is the github link for downloading the required header files for connection establishment
I could reproduce the same error in my NodeMCU. Please find the below image for reference.
If you let the code run and observe the NodeMCU serial monitor, it will occasionally spit out additional information as you can find in the below image
The error message in my case indicates that it is an issue with Authorization. I had the wrong Primary key provided in the code. In order to be able to connect to the device on Azure IoT Central, make sure the device is not set to be simulated when you create it.
Once you have the device created from the template, navigate to the device and click on connect to get the following details that needs to be entered in the code. Attached the below image for reference.
Here is the code snippet I have used to generate data
#include <ESP8266WiFi.h>
#include "src/iotc/common/string_buffer.h"
#include "src/iotc/iotc.h"
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11 // DHT 11
#define WIFI_SSID "<SSID>"
#define WIFI_PASSWORD "<WIFIPASSWORD>"
const char *SCOPE_ID = "<value 2 from above image>";
const char *DEVICE_ID = "<value 3 from above image>";
const char *DEVICE_KEY = "<value 4 from above image>";
DHT dht(DHTPIN, DHTTYPE);
void on_event(IOTContext ctx, IOTCallbackInfo *callbackInfo);
#include "src/connection.h"
void on_event(IOTContext ctx, IOTCallbackInfo *callbackInfo)
{
// ConnectionStatus
if (strcmp(callbackInfo->eventName, "ConnectionStatus") == 0)
{
LOG_VERBOSE("Is connected ? %s (%d)",
callbackInfo->statusCode == IOTC_CONNECTION_OK ? "YES" : "NO",
callbackInfo->statusCode);
isConnected = callbackInfo->statusCode == IOTC_CONNECTION_OK;
return;
}
// payload buffer doesn't have a null ending.
// add null ending in another buffer before print
AzureIOT::StringBuffer buffer;
if (callbackInfo->payloadLength > 0)
{
buffer.initialize(callbackInfo->payload, callbackInfo->payloadLength);
}
LOG_VERBOSE("- [%s] event was received. Payload => %s\n",
callbackInfo->eventName, buffer.getLength() ? *buffer : "EMPTY");
if (strcmp(callbackInfo->eventName, "Command") == 0)
{
LOG_VERBOSE("- Command name was => %s\r\n", callbackInfo->tag);
}
}
void setup()
{
Serial.begin(9600);
connect_wifi(WIFI_SSID, WIFI_PASSWORD);
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
if (context != NULL)
{
lastTick = 0; // set timer in the past to enable first telemetry a.s.a.p
}
dht.begin();
}
void loop()
{
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isConnected)
{
unsigned long ms = millis();
if (ms - lastTick > 10000)
{ // send telemetry every 10 seconds
char msg[64] = {0};
int pos = 0, errorCode = 0;
lastTick = ms;
if (loopId++ % 2 == 0)
{ // send telemetry
pos = snprintf(msg, sizeof(msg) - 1, "{\"Temperature\": %f}",
t);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Humidity\":%f}",
h);
errorCode = iotc_send_telemetry(context, msg, pos);
}
else
{ // send property
}
msg[pos] = 0;
if (errorCode != 0)
{
LOG_ERROR("Sending message has failed with error code %d", errorCode);
}
}
iotc_do_work(context); // do background work for iotc
}
else
{
iotc_free_context(context);
context = NULL;
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
}
}
Here are the Temperature and Humidity values generated from the code
The data generated the following graph on the Azure IoT Central.
Please note that I have used DHT11 sensor and connected to read it from the GPI0 2 (D4) pin on my NodeMCU board. I have used the Arduino IDE version 1.8.19 and ESP8266 board version 2.7.4

create Wayland desktop environment that simply binds keyboard shortcuts

There are dozens of questions on here asking how to create global keyboard bindings in a Wayland environment. Generally, the answer is "use your desktop environment" - an answer that is pretty much useless to most anyone asking the question.
So, in order to draw out a more useful answer, I ask how does one create a minimal Wayland desktop environment which can bind shortcut keys?
I've got Mutter running as my WM, and I'm using GNOME Do as a launcher. It's pretty much exactly the desktop environment I want, with the exception that I can't bind hotkeys.
I don't care if I have to write a 10k line C app to make this work. I just want to know how to proceed. How does GNOME bind keyboard shortcuts within Wayland? Where is the code for that? Where is the appropriate documentation for Wayland/Mutter?
After much research and experimentation, it looks like libevdev is maybe the right tool. I developed the program below as a proof-of-concept to bind Alt+X to launch xterm.
Unfortunately, it has to be run as root, so I'm thinking I need to somehow tie this into the local desktop session. For my purposes, it's probably good enough to just setuid using the root user and call it a day.
I'm also not convinced my keyboard detection heuristic is very good. I'm essentially looking for any device that has keys and a repeat rate, which on my system only matches my keyboard.
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <libevdev/libevdev.h>
#define DEVROOT "/dev/input/"
#define DEVROOT_LEN 12
#define PATH_LEN (DEVROOT_LEN + NAME_MAX)
int outerr(int, const char*);
struct libevdev* open_device(int);
bool kblike(struct libevdev*);
int main(int argc, char* argv[]) {
DIR* dir;
struct dirent* entry;
char path[PATH_LEN];
int fd, err;
struct libevdev* dev = NULL;
struct input_event ev;
bool key, rep, alt;
if (!(dir = opendir("/dev/input"))) {
return outerr(errno, "cannot enumerate devices");
}
// look for keyboard device
while (entry = readdir(dir)) {
if (DT_CHR == entry->d_type) {
sprintf(path, "/dev/input/%s", entry->d_name);
if (-1 == (fd = open(path, O_RDONLY|O_NONBLOCK))) {
return outerr(errno, "cannot read device");
}
if (dev = open_device(fd)) {
if (kblike(dev)) break;
libevdev_free(dev);
dev = NULL;
}
}
}
closedir(dir);
// check if keyboard was found
if (dev == NULL) {
return outerr(ENODEV, "could not detect keyboard");
} else do {
err = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
if (err == 0 && ev.type == EV_KEY) switch (ev.code) {
case KEY_LEFTALT:
alt = ev.value == 1;
break;
case KEY_X:
if (ev.value == 1 && alt) system("xterm");
break;
}
} while (err == 1 || err == 0 || err == -EAGAIN);
return 0;
}
int outerr(int errnum, const char* msg) {
fprintf(stderr, "%s (%s)\n", msg, strerror(errnum));
return errnum;
}
bool kblike(struct libevdev* dev) {
return libevdev_has_event_type(dev, EV_KEY)
&& libevdev_has_event_type(dev, EV_REP);
}
struct libevdev* open_device(int fd) {
struct libevdev* dev = libevdev_new();
int err;
if (dev == NULL) {
errno = ENOMEM;
} else if (0 > (err = libevdev_set_fd(dev, fd))) {
libevdev_free(dev);
dev = NULL;
errno = -err;
}
return dev;
}

Do DLLs have a lower priority that may affect ethernet functionality? Experiencing TCP retransmissions

I have some modbus ethernet tcp communications that I'm attempting to do in a DLL. I get numerous TCP Retransmissions from the target device, as seen in WireShark.
(In this image, 192.168.1.5 is the Modbus device. 192.168.1.72 is the computer)
However, when the same code is inserted directly into an application, there are no communication errors.
I'm wondering if DLLs have some sort of lower priority that can cause slower communications, or if anyone may have any insight as to why this code would run without TCP issue in an application, but not in a DLL.
Here is the dll header:
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
typedef void *eioTHandle;
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) int __stdcall eioConnect( unsigned short ModelId, char *Ip, eioTHandle *Handle );
#ifdef __cplusplus
}
#endif
#endif
And here is the source file:
#include "main.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdint.h>
#define EIO500_S 0
#define EIO500_MS 1000
#define eioERROR -1
#define eioSUCCESS 0
static uint8_t m_UnitId = 0xff;
static SOCKET m_Sock;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
int __stdcall eioConnect( unsigned short ModelId, char *Ip, eioTHandle *Handle )
{
WSADATA Wsa;
struct sockaddr_in Server;
int Result;
char Buffer[256];
char InBuffer[256];
// CONNECTION --------------------------------------------------------------
if (WSAStartup(MAKEWORD(2,2), &Wsa) != 0)
{
return eioERROR;
}
m_Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_Sock == INVALID_SOCKET)
{
WSACleanup();
return eioERROR;
}
Server.sin_addr.s_addr = inet_addr(Ip);
Server.sin_family = AF_INET;
Server.sin_port = htons(502);
if (connect(m_Sock, (struct sockaddr *)&Server, sizeof(Server))
== SOCKET_ERROR)
{
closesocket(m_Sock);
m_Sock = INVALID_SOCKET;
WSACleanup();
return eioERROR;
}
// -------------------------------------------------------------------------
for (int Ctr = 0; Ctr < 50000; Ctr++)
{
// SEND COMMAND --------------------------------------------------------
// 5 bytes in a Send Read Multiple Coils command.
int NumBytes = 5;
Buffer[0] = 0;
Buffer[1] = 0;
Buffer[2] = 0;
Buffer[3] = 0;
Buffer[4] = 0;
Buffer[5] = NumBytes + 1; // 1 for unit id.
Buffer[6] = m_UnitId;
// 0 = Function code.
Buffer[7] = 0x01;
// 1+2 = Address.
Buffer[8] = 0;
Buffer[9] = 8;
// 3+4 = Number of bits to read.
Buffer[10] = 0;
Buffer[11] = 8;
if (send(m_Sock, Buffer, NumBytes + 7, 0) == SOCKET_ERROR)
{
continue;
}
// ---------------------------------------------------------------------
// WAIT FOR RECEIVE ----------------------------------------------------
WSAEVENT RecvEvent;
int Ret;
RecvEvent = WSACreateEvent();
WSAEventSelect( m_Sock, RecvEvent, FD_READ );
Ret = WSAWaitForMultipleEvents(1, &RecvEvent, TRUE, 1000, FALSE);
WSAResetEvent(RecvEvent);
if (Ret == WSA_WAIT_TIMEOUT)
continue;
// -------------------------------------------------------------------------
// Check for any reply.
recv(m_Sock, InBuffer, 256, 0);
}
// DISCONNECT --------------------------------------------------------------
Result = shutdown(m_Sock, SD_SEND);
if (Result == SOCKET_ERROR)
{
closesocket(m_Sock);
WSACleanup();
m_Sock = INVALID_SOCKET;
return eioERROR;
}
// Receive until the peer closes the connection.
while (recv(m_Sock, Buffer, 256, 0) > 0);
closesocket(m_Sock);
WSACleanup();
m_Sock = INVALID_SOCKET;
// ------------------------------------------------------------------------
return eioSUCCESS;
}
I've simplified the code as much as possible. The communication is in a loop for testing. The original application would poll this data from the device.
No. From the network's perspective there's no difference in TCP segments sent some way or other. There may be a protocol prioritation though (QoS) that may cause packet drops when links are saturated.
A more likely cause could be a problem with the checksums: invalid checksums cause packet drops which in turn cause retransmissions. Possibly the API works slightly different when called from a DLL, so the checksums are calculated (correctly).

Trouble with Sending HTTP 1.1 GET request

I am trying to use PubNub to publish a message to a channel but I always get "Connection Failed!".
I know the structure of a publish URL is the following:
http://pubsub.pubnub.com/publish/<PUB-KEY>/<SUB-KEY>/0/<CHANNEL>/0/%22<MESSAGE>%22
I have tested the URL on Google Chrome and it works just fine.
The following is a C flavored code is running on an Arduino UNO + Adafruit HUZZAH CC3000 WIFI Breakout. This is not an Arduino hardware question per se, because I believe there is nothing wrong with my circuit. My issue is with the structure of the HTTP GET request created using Adafruit CC3000 Library.
I am having to go with sending a GET rather than using PubNub Arduino Library because it doesn't seem to support CC3000 WIFI module. They have a JSON WIFI and Ethernet examples but both do not communicate with the CC3000 WIFI module.
char PUBKEY[] = "XXXXXXX";
char SUBKEY[] = "XXXXXXX";
Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 80);
if (client.connected())
{
client.print("GET /publish/");
client.print(PUBKEY);
client.print("/");
client.print(SUBKEY);
client.print("/0/");
client.print("MyPubChannel"); // Channel Name
client.print("/0/%22");
client.print("Hello World from Arduino!"); // Msg to publish
client.print("%22");
client.println(" HTTP/1.1");
client.print("Host: ");
client.println("pubsub.pubnub.com");
client.println();
}
else
{
Serial.println(F("Connection failed"));
}
I have read this page and understood that a correct GET request would be of the form:
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org
I am pretty sure there is something wrong with my GET request. Can anyone look at this and provide ANY hints as to what could be going wrong?
I am finally able to connect to PubNub using the code below.
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"
#define ADAFRUIT_CC3000_IRQ 3 // MUST be an interrupt pin!
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10
#define WLAN_SSID "XXXWifi"
#define WLAN_PASS "XXX"
#define WLAN_SECURITY WLAN_SEC_WPA2
#define IDLE_TIMEOUT_MS 3
uint32_t ip;
// PubNub Setup
#define WEBSITE "pubsub.pubnub.com"
#define WEBPAGE "/publish/"
char PUBKEY[] = "pub-XXXX";
char SUBKEY[] = "sub-XXXX";
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIVIDER); // you can change this clock speed
Adafruit_CC3000_Client www;
void setup(void)
{
Serial.begin(115200);
/* Initialize the module */
Serial.print(F("\n Initializing WIFI Adapter..."));
if (!cc3000.begin())
{
Serial.println(F("Couldn't begin()! Check your wiring?"));
while(1);
}
Serial.print(F("Ready!\n"));
Serial.print(F("Connecting to [")); Serial.print(WLAN_SSID);
Serial.print(F("]..."));
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
Serial.println(F("Failed!"));
while(1);
}
Serial.print(F("Connected!\n"));
//Wait for DHCP to complete
Serial.print(F("Waiting for DHCP..."));
while (!cc3000.checkDHCP())
{
delay(100); // ToDo: Insert a DHCP timeout!
}
Serial.print(F("Done!\n"));
Serial.print(F("Resolving PubNub..."));
ip = 0;
// Try looking up the website's IP address
while (ip == 0) {
if (! cc3000.getHostByName(WEBSITE, &ip)) {
Serial.println(F("Couldn't resolve!"));
}
delay(500);
}
Serial.print(F("Resolved!\n"));
www = cc3000.connectTCP(ip, 80);
for(int i=0;i<=50;i++)
{
char buffer[4];
dtostrf(i, 4, 0, buffer);
Publish("ch2", buffer);
}
/* You need to make sure to clean up after yourself or the CC3000 can freak out */
/* the next time your try to connect ... */
Serial.println(F("\n\nDisconnecting"));
www.close();
cc3000.disconnect();
}
void loop(void)
{
delay(1000);
}
void Publish(char* CH, char* MSG)
{
if (www.connected()) {
www.fastrprint(F("GET "));
www.fastrprint(WEBPAGE);
www.fastrprint(PUBKEY);
www.fastrprint(F("/"));
www.fastrprint(SUBKEY);
www.fastrprint(F("/0/"));
www.fastrprint(CH);
www.fastrprint(F("/0/%22"));
www.fastrprint(MSG);
www.fastrprint(F("%22"));
www.fastrprint(F(" HTTP/1.1\r\n"));
www.fastrprint(F("Host: "));
www.fastrprint(WEBSITE);
www.fastrprint(F("\r\n"));
www.fastrprint(F("\r\n"));
www.println();
} else {
Serial.println(F("Connection failed"));
return;
}
//Read data until either the connection is closed, or the idle timeout is reached.
unsigned long lastRead = millis();
while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
while (www.available()) {
char c = www.read();
//Serial.print(c);
lastRead = millis();
}
}
}
char* clean(char* MSG)
{
return MSG;
}

Calling methods and receiving signals using low-level APIs

I am trying to call the method ReadLocalBdAddrReq and receive its signal ReadLocalBdAddrCfm on dbus using the dbus low level APIs.
I have written the following code with the help of some forum posts and a dbus tutorial.
The thing is, I am not able to receive the signals back. The code is incomplete at some places as I didn't know what should be done.
So please help me so that I can receive the signals for the methods called.
Here the code I have written. Please correct any mistakes I've made.
#include <stdlib.h>
#include <stdio.h>
#include <dbus/dbus.h>
#define OBJ_PATH "/bt/cm"
static dbus_bool_t add_watch(DBusWatch *watch, void *data)
{
if (!dbus_watch_get_enabled(watch))
return TRUE;
int fd = dbus_watch_get_unix_fd(watch);
unsigned int flags = dbus_watch_get_flags(watch);
int f = 0;;
if (flags & DBUS_WATCH_READABLE) {
f |= DBUS_WATCH_READABLE;
printf("Readable\n");
}
if (flags & DBUS_WATCH_WRITABLE) {
printf("Writeable\n");
f |= DBUS_WATCH_WRITABLE;
}
/* this should not be here */
if (dbus_watch_handle(watch, f) == FALSE)
printf("dbus_watch_handle() failed\n");
return TRUE;
}
static void remove_watch(DBusWatch *watch, void *data)
{
printf("In remove watch with fd = [%d]\n",dbus_watch_get_unix_fd(watch));
}
static void toggel_watch(DBusWatch *watch, void *data)
{
printf("In toggel watch\n");
/*
if (dbus_watch_get_enabled(watch))
add_watch(watch, data);
else
remove_watch(watch, data);
*/
}
/* timeout functions */
static dbus_bool_t add_time(DBusTimeout *timeout, void *data)
{
/* Incomplete */
printf("In add_time\n");
if (!dbus_timeout_get_enabled(timeout))
return TRUE;
//dbus_timeout_handle(timeout);
return 0;
}
static void remove_time(DBusTimeout *timeout, void *data)
{
/* Incomplete */
printf("In remove_time\n");
}
static void toggel_time(DBusTimeout *timeout, void *data)
{
/* Incomplete */
printf("In toggel_time\n");
/*
if (dbus_timeout_get_enabled(timeout))
add_timeout(timeout, data);
else
remove_timeout(timeout, data);
*/
}
/* message filter -- handlers to run on all incoming messages*/
static DBusHandlerResult filter (DBusConnection *connection, DBusMessage *message, void *user_data)
{
printf("In filter\n");
char *deviceaddr;
if (dbus_message_is_signal(message, "com.bluegiga.v2.bt.cm", "ReadLocalBdAddrCfm")) {
printf("Signal received is ReadLocalBdAddrCfm\n");
if ((dbus_message_get_args(message,NULL,DBUS_TYPE_STRING, &deviceaddr,DBUS_TYPE_INVALID) == FALSE))
{
printf("Could not get the arguments from the message received\n");
return -2;
}
printf("Got Signal and device address is [%s]\n", deviceaddr);
}
return 0;
}
/* dispatch function-- simply save an indication that messages should be dispatched later, when the main loop is re-entered*/
static void dispatch_status(DBusConnection *connection, DBusDispatchStatus new_status, void *data)
{
printf("In dispatch_status\n");
if (new_status == DBUS_DISPATCH_DATA_REMAINS)
{
printf("new dbus dispatch status: DBUS_DISPATCH_DATA_REMAINS [%d]",new_status);
}
}
/* unregister function */
void unregister_func(DBusConnection *connection, void *user_data)
{
}
/* message function - Called when a message is sent to a registered object path. */
static DBusHandlerResult message_func(DBusConnection *connection, DBusMessage *message, void *data)
{
printf("Message [%s] is sent to [%s] from interface [%s] on path [%s] \n",dbus_message_get_member(message),dbus_message_get_destination(message),
dbus_message_get_interface(message),dbus_message_get_path(message)); return 0;
}
DBusObjectPathVTable table = {
.unregister_function = unregister_func,
.message_function = message_func,
};
int main(void) {
DBusMessage* msg;
DBusMessageIter args;
DBusConnection* conn;
DBusError err;
DBusPendingCall* pending;
int ret;
//unsigned int level;
char* appHandle = NULL;
//int *context;
int msg_serial;
int open;
char *deviceaddr;
dbus_error_init(&err);
// connect to the system bus and check for errors
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
exit(1);
}
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggel_watch, NULL, NULL))
{
printf("Error in dbus_set_watch_functions\n");
dbus_connection_unref(conn);
return -1;
}
/* These functions are responsible for making the application's main loop aware of timeouts */
if (!dbus_connection_set_timeout_functions(conn, add_time, remove_time, toggel_time, NULL, NULL))
{
printf("Error in dbus_set_timeout_functions\n");
dbus_connection_unref(conn);
return -1;
}
/* Used to register the handler functions run on incoming messages*/
if (!dbus_connection_add_filter(conn, filter, NULL, NULL))
{
printf("Error in adding filter\n");
dbus_connection_unref(conn);
return -1;
}
/* Filter added for incoming messages */
/* Set a function to be invoked when the dispatch status changes */
dbus_connection_set_dispatch_status_function(conn, dispatch_status, NULL ,NULL);
/* Register a handler for messages sent to a given path */
if(!dbus_connection_register_object_path(conn, OBJ_PATH, &table, NULL))
{
printf("Error in registering object\n");
return -1;
}
/* sending messages to the outgoing queue */
msg = dbus_message_new_method_call("com.bluegiga.v2.bt.cm", // target for the method call
OBJ_PATH, // object to call on
"com.bluegiga.v2.bt.cm", // interface to call on
"ReadLocalBdAddrReq"); // method name
if (NULL == msg) {
fprintf(stderr, "Message Null\n");
exit(1);
}
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT16,&appHandle)) {
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
fprintf(stderr, "Sending the connections\n");
// send message and get a handle for a reply
if (!dbus_connection_send (conn, msg, &msg_serial)) {
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
fprintf(stderr, "Connection sent and the msg serial is %d\n",msg_serial);
/* Message sent over */
/* not sure whether this should be here or above watch */
while (dbus_connection_get_dispatch_status(conn) == DBUS_DISPATCH_DATA_REMAINS)
{
//printf("Entered in dispatch\n");
/* Processes any incoming data. will call the filters registered by add_filer*/
dbus_connection_dispatch(conn);
}
return 0;
}
After I run this program it has the following output:
Readable
Sending the connections
Connection sent and the msg serial is
2(DBUS_MESSAGE_TYPE_METHOD_RETURN)
If the connection was sent to the object path then message_func should have been called correctly, but it never is called. Have I made any mistake in sending the method call?
You are missing the event loop which is otherwise available by default if you choose to go with one of the bindings. When you get a call to add_watch, libdbus expects that the application will attach an IO handler to it. The IOHandler added by application will watch for an activity on the fd (filedescriptor) queried for the watch. Whenever there is an activity on that file descriptor, the IOHandler will trigger a callback with appropriate flags that you need to convert to DBUS flags before calling dbus_watch_handle.
Suggest that you use glib if you don't know how to use event loops. I am able to get it if I use libUV or libEV as low footprint event loop.