questions about PacketAcknowledgements in nesC,TinyOS - c

In order to learn how to use the interface PacketAcknowledgements,i try to modify the example in apps/RadioCountToLeds,but there are some problem,the transmit of data can't be done and it seems there is no ack back to the sender.
the file RadioCountToLedsC is as follows:
#include "Timer.h"
#include "RadioCountToLeds.h"
module RadioCountToLedsC #safe() {
uses {
interface Leds;
interface Boot;
interface Receive;
interface AMSend;
interface Timer<TMilli> as MilliTimer;
interface SplitControl as AMControl;
interface Packet;
interface PacketAcknowledgements;
interface AMPacket;
}
}
implementation {
message_t packet;
bool locked = FALSE;
uint16_t counter = 0;
event void Boot.booted() {
dbg("Boot","Application booted.\n");
call AMControl.start();
}
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) {
if(TOS_NODE_ID==0)
{
call MilliTimer.startPeriodic(1000);
}
}
else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t err) {
// do nothing
}
event void MilliTimer.fired() {
counter++;
dbg("RadioCountToLedsC", "RadioCountToLedsC: timer fired, counter is %hu.\n", counter);
if (locked==TRUE) {
return;
}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, sizeof(radio_count_msg_t));
if (rcm == NULL) {
return;
}
rcm->counter = counter;
call PacketAcknowledgements.requestAck(&packet);
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) {
dbg("RadioCountToLedsC", "RadioCountToLedsC: packet sent.\n", counter);
locked = TRUE;
}
}
}
event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) {
if (len != sizeof(radio_count_msg_t)) {return bufPtr;}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)payload;
dbg("RadioCountToLedsC", "Received packet of counter %u.\n", rcm->counter);
if (rcm->counter & 0x1) {
call Leds.led0On();
}
else {
call Leds.led0Off();
}
if (rcm->counter & 0x2) {
call Leds.led1On();
}
else {
call Leds.led1Off();
}
if (rcm->counter & 0x4) {
call Leds.led2On();
}
else {
call Leds.led2Off();
}
return bufPtr;
}
}
event void AMSend.sendDone(message_t* bufPtr, error_t error) {
if(call PacketAcknowledgements.wasAcked(bufPtr)){
dbg("RadioCountToLedsC", "ACKED!\n");
locked = FALSE;
}
else
{
dbg("RadioCountToLedsC", "NOT ACKED!\n");
}
}
}
i want to know where the error is.
by the way,can anyone give me an example about how to use the interface PacketAcknowledgements?
thanks very much.
the configuration file are as follows:
configuration RadioCountToLedsAppC {}
implementation {
components MainC, RadioCountToLedsC as App, LedsC;
components new AMSenderC(AM_RADIO_COUNT_MSG);
components new AMReceiverC(AM_RADIO_COUNT_MSG);
components new TimerMilliC();
components ActiveMessageC;
App.Boot -> MainC.Boot;
App.PacketAcknowledgements ->AMSenderC.Acks;
App.Receive -> AMReceiverC;
App.AMSend -> AMSenderC;
App.AMControl -> ActiveMessageC;
App.Leds -> LedsC;
App.MilliTimer -> TimerMilliC;
App.Packet -> AMSenderC;
App.AMPacket ->ActiveMessageC;
}

Related

Correct closing DBus connection

Could you explain how to close DBus connection correctly/ Below is my variant:
int P_dbus_proto_init(DBusConnection **dbus_conn, const char *name, dbus_MessageHandler mh, int num_rules, const char **rules)
{
int rc = 0;
DBusError dbus_err;
dbus_error_init(&dbus_err);
*dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_err);
if (dbus_error_is_set(&dbus_err))
{
FILTER_LOG_ERROR("Connection Error (%s)\n", dbus_err.message);
dbus_error_free(&dbus_err);
return -1;
}
rc = dbus_bus_request_name(*dbus_conn, name, DBUS_NAME_FLAG_REPLACE_EXISTING, &dbus_err);
if (dbus_error_is_set(&dbus_err) || (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != rc))
{
FILTER_LOG_ERROR("Connection Error (%s)\n", dbus_err.message);
dbus_error_free(&dbus_err);
return -1;
}
dbus_connection_add_filter(*dbus_conn, mh, NULL, NULL);
if (dbus_error_is_set(&dbus_err))
{
FILTER_LOG_ERROR("Add Filter Error (%s)\n", dbus_err.message);
dbus_error_free(&dbus_err);
return -1;
}
for(int i = 0; i < num_rules; i++)
{
dbus_bus_add_match(*dbus_conn, rules[i], &dbus_err);
if (dbus_error_is_set(&dbus_err))
{
FILTER_LOG_ERROR("Match Error (%s)\n", dbus_err.message);
dbus_error_free(&dbus_err);
return -1;
}
}
return 0;
}
static const char* rules[] = {
"interface='acl_management.method'",
};
And how I use it:
DBusConnection *dbus_conn;
if (P_dbus_proto_init(&dbus_conn, "com.bla-bla-bla.acl", P_dbus_proto_job, 1, rules) == 0)
{
while (dbus_connection_read_write_dispatch(dbus_conn, 5000))
{
if(p_ctx->execute.n_nl_exit_app == 0) //My app can be terminated by n_nl_exit_app flag
{
break;
}
}
dbus_connection_close(dbus_conn);// Should I do it or not?
dbus_connection_unref(dbus_conn);// Should I do it or not?
}
From dbus.freedesktop.org docs I cannot understand how to do it correctly. I can terminate my app by turn on 'n_nl_exit_app' flag - should I call dbus_connection_closein this case?

How to port NimBLE to a project of nrf52832 and make ble mesh work

I have ported it, but it doesn't work . It compiled successfully but the board doesn't work and the app named nRF Mesh can't find the Unprovisioned device (the board), if I delete these codes about porting nimble then the board works I use a project like this https://github.com/InfiniTimeOrg/InfiniTime (for reference)
Here is the function I call in my main() to init nimble:
void nimble_port_init(void) {
void os_msys_init(void);
void ble_store_ram_init(void);
ble_npl_eventq_init(&g_eventq_dflt);
os_msys_init();
ble_hs_init();
ble_store_ram_init();
int res;
res = hal_timer_init(5, NULL);
ASSERT(res == 0);
res = os_cputime_init(32768);
ASSERT(res == 0);
ble_ll_init();
ble_hci_ram_init();
ble_svc_gap_init ();
ble_svc_gatt_init();
bt_mesh_register_gatt();
nimble_port_freertos_init(BleHost);
}
Here is some functions about porting and ble mesh:
(1) about controller/host task and mesh_init and provision
void
nimble_port_freertos_init(TaskFunction_t host_task_fn)
{
#if NIMBLE_CFG_CONTROLLER
/*
* Create task where NimBLE LL will run. This one is required as LL has its
* own event queue and should have highest priority. The task function is
* provided by NimBLE and in case of FreeRTOS it does not need to be wrapped
* since it has compatible prototype.
*/
xTaskCreate(nimble_port_ll_task_func, "ll", configMINIMAL_STACK_SIZE + 400,
NULL, configMAX_PRIORITIES - 1, &ll_task_h);
#endif
/*
* Create task where NimBLE host will run. It is not strictly necessary to
* have separate task for NimBLE host, but since something needs to handle
* default queue it is just easier to make separate task which does this.
*/
xTaskCreate(host_task_fn, "ble", configMINIMAL_STACK_SIZE + 400,
NULL, tskIDLE_PRIORITY + 1, &host_task_h);
}
void
mesh_initialized(TaskFunction_t mesh_task_fn)
{
xTaskCreate(mesh_task_fn,"mesh",configMINIMAL_STACK_SIZE + 400, NULL,
tskIDLE_PRIORITY + 1, &mesh_task_h);
}
void BleHost(void*) {
Int_Pub();
InitPrepare();
nimble_port_run();
}
void Int_Pub(void)
{
bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(1 + 3 +0);
bt_mesh_pub_msg_gen_data_pub_srv = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_data_pub_cli = NET_BUF_SIMPLE(2 + 2);
health_pub.msg = bt_mesh_pub_msg_health_pub;
gen_data_pub_srv.msg = bt_mesh_pub_msg_gen_data_pub_srv;
gen_data_pub_cli.msg = bt_mesh_pub_msg_gen_data_pub_cli;
}
void InitPrepare(void)
{
health_pub_init();
//os_mempool_module_init();
ble_hs_cfg.reset_cb = blemesh_on_reset;
ble_hs_cfg.sync_cb = blemesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* ble_svc_gap_init();
ble_svc_gatt_init(); */
}
void nimble_port_run(void)
{
struct ble_npl_event *ev;
while (1) {
ev = ble_npl_eventq_get(&g_eventq_dflt, BLE_NPL_TIME_FOREVER);
ble_npl_event_run(ev);
}
}
static void blemesh_on_sync(void)
{
int err;
ble_addr_t addr;
NRF_LOG_INFO("Bluetooth initialized\n");
err = ble_hs_id_gen_rnd(1,&addr);
assert(err == 0);
err = ble_hs_id_set_rnd(addr.val);
assert(err == 0);
err = bt_mesh_init(addr.type,&prov,&comp);
//err = bt_mesh_init(0,&prov,&comp);
if(err)
{
NRF_LOG_INFO("Initializing mesh failed (err %d)\n", err);
return;
}
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
if(IS_ENABLED(CONFIG_SETTINGS))
{
settings_load();
}
if(bt_mesh_is_provisioned()){
NRF_LOG_INFO("Mesh network restored from flash\n");
}
mesh_initialized(Ble_Mesh_Adv_Task);
NRF_LOG_INFO("Mesh initialized\n");
}
(2)some interrupt handlers and ...
void RADIO_IRQHandler(void) {
((void (*)(void)) radio_isr_addr)();
}
void RNG_IRQHandler(void) {
((void (*)(void)) rng_isr_addr)();
}
void RTC0_IRQHandler(void) {
((void (*)(void)) rtc0_isr_addr)();
}
void WDT_IRQHandler(void) {
nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT);
}
void npl_freertos_hw_set_isr(int irqn, void (*addr)(void)) {
switch (irqn) {
case RADIO_IRQn:
radio_isr_addr = addr;
break;
case RNG_IRQn:
rng_isr_addr = addr;
break;
case RTC0_IRQn:
rtc0_isr_addr = addr;
break;
}
}
uint32_t npl_freertos_hw_enter_critical(void) {
uint32_t ctx = __get_PRIMASK();
__disable_irq();
return (ctx & 0x01);
}
void npl_freertos_hw_exit_critical(uint32_t ctx) {
if (!ctx) {
__enable_irq();
}
}
extern struct ble_npl_eventq g_eventq_dflt;

TCP socket connection interference on send message in Kubernetes

I'm creating an application in C that intermediates and manages scheduled applications (NodeJs) to collect information into MongoDB.
This makes possible the application's scalability and avoids replicated values.
Problem
Local tests: OK
Container tests: Ok
K8s Minikube tests: scheduled application error in bson parse
EKS Production tests: scheduled application error in bson parse
Code of C application to send socket message:
static void
ssq_connection_server_handler()
{
...
for (i = 0; i < ssq_max_sockets; i++) {
sd = ssq_connection->clients[i];
if (FD_ISSET(sd, &master)) {
if ((ret = ssq_connection->recv(sd, buffer, SSQ_SERVER_MAX_BUFFER_SIZE)) <= 0) {
continue;
}
buffer[ret] = '\0';
token = ssq_strtok(buffer, ":");
opts = ssq_strtok(NULL, ":");
limit = ssq_atoi(opts, ssq_strlen(opts));
if (limit == SSQ_ERROR) {
limit = 10;
}
if (ssq_strcmp("next", token) == 0) {
u_char *tasks;
size_t len;
tasks = ssq_mongo_collection_find(limit, ssq_mongo->collection, &len);
ssq_connection->send(sd, tasks, len);
}
}
}
...
}
static ssize_t
ssq_connection_send_handler(int fd, u_char *buf, size_t size)
{
ssize_t n;
ssq_err_t err;
for (;;) {
n = send(fd, buf, size, 0);
ssq_log_debug("send: fd:%d %z of %uz", fd, n, size);
if (n > 0) {
return n;
}
err = ssq_socket_errno;
if (n == 0) {
ssq_log_error(SSQ_LOG_ALERT, err, "send() returned zero");
return n;
}
if (err == SSQ_EAGAIN || err == SSQ_EINTR) {
ssq_log_debug_error(err, "send() not ready");
if (err == SSQ_EAGAIN) {
return SSQ_AGAIN;
}
} else {
return SSQ_ERROR;
}
}
}
Code in NodeJs to receive message:
const net = require('net');
const { EJSON } = require('bson');
const sock = new net.Socket();
sock.connect(process.env.SSQ_PORT || 3145, process.env.SSQ_HOST || '127.0.0.1', () => {
console.log('socket connection established');
});
sock.on('data', (data) => {
try {
const tasks = EJSON.parse(data);
console.log(tasks);
process.exit(0);
} catch (err) {
console.error(err);
process.exit(1);
}
});
sock.on('error', () => {
/* void */
});
sock.on('close', () => {
console.warn('socket connection has been closed');
});
sock.write(Buffer.from('next:10'));
I think that something coming from K8s is intercepting and modifying the message.

IBM Watson IoT - Unable to get response from topic with parameters using ESP8266

From several days I searched for this problem:
I want to do a connected device (IoT) using Watson IoT Platform and ESP32 (or similar). This device have some relays on board.
On Watson dashboard I created the device type, the physical/logical interface, I connected the ESP with the platform.
I created a custom action on the dashboard that has a param to identify the relay that I want to switch (switch2) and also a simple custom action (switch) without param.
The problem is that if I generate the action without the param (switch) I see the callback print, if I generate the action with a param (switch2) nothing happens.
I tried also to use the built-in Watson action "firmware update/download", if I use firmware download (that want some params such as uri, version, etc.) nothing happens, if I use firmware update (that don't want params), I see the callback of subscription.
Here you can see the code arduino like for the ESP
// --------------- HEADERS -------------------
#include <Arduino_JSON.h>
#include <EEPROM.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <PubSubClient.h> //https://github.com/knolleary/pubsubclient/releases/tag/v2.3
WebServer server(80);
char wifi_ssid[100] = "xxxxxx";
char wifi_psw[200] = "xxxxxxx";
// ----- Watson IBM parameters
#define ORG "xxxx"
#define DEVICE_TYPE "Relay"
#define DEVICE_ID "xxxx"
#define TOKEN "xxxxxxxxxxxxxxxx"
char ibmServer[] = ORG ".messaging.internetofthings.ibmcloud.com";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
const char switchTopic[] = "iotdm-1/mgmt/custom/switch-actions-v1/switch2";
const char testTopic[] = "iotdm-1/mgmt/custom/switch-actions-v1/switch"; //"iot-2/cmd/+/fmt/+";
const char observeTopic[] = "iotdm-1/observe";
const char publishTopic[] = "iot-2/evt/status/fmt/json";
const char responseTopic[] = "iotdm-1/response";
const char deviceResponseTopic[] = "iotdevice-1/response";
const char manageTopic[] = "iotdevice-1/mgmt/manage";
const char updateTopic[] = "iotdm-1/mgmt/initiate/firmware/update";
void callback(char* topic, byte* payload, unsigned int payloadLength);
WiFiClient wifiClient;
PubSubClient client(ibmServer, 1883, callback, wifiClient);
bool outputEnable = false;
bool oldOutputEnable = false;
void setup() {
// put your setup code here, to run once:
//Init la porta seriale ed aspetta che si avii
Serial.begin(115200);
while(!Serial) {
delay(1);
}
setupWiFi();
}
void loop() {
// put your main code here, to run repeatedly:
if (!client.loop()) {
mqttConnect();
initManagedDevice();
}
delay(100);
}
// WiFi Settings
void setupWiFi() {
bool state = false;
Serial.println("---- Setup WiFi ----");
Serial.println(wifi_ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(wifi_ssid, wifi_psw);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
mqttConnect();
initManagedDevice();
publishStatus();
Serial.println("");
Serial.print("Connected to ");
Serial.println(wifi_ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
// IBM IoT
void mqttConnect() {
if (!!!client.connected()) {
Serial.print("Reconnecting MQTT client to "); Serial.println(ibmServer);
while (!!!client.connect(clientId, authMethod, token)) {
Serial.print(".");
delay(500);
}
Serial.println();
}
}
void initManagedDevice() {
if (client.subscribe("iotdm-1/response")) {
Serial.println("subscribe to responses OK");
} else {
Serial.println("subscribe to responses FAILED");
}
if (client.subscribe("iotdm-1/device/update")) {
Serial.println("subscribe to update OK");
} else {
Serial.println("subscribe to update FAILED");
}
if (client.subscribe(observeTopic)) {
Serial.println("subscribe to observe OK");
} else {
Serial.println("subscribe to observe FAILED");
}
if (client.subscribe(switchTopic)) {
Serial.println("subscribe to switch OK");
} else {
Serial.println("subscribe to switch FAILED");
}
if (client.subscribe(testTopic)) {
Serial.println("subscribe to Test OK");
} else {
Serial.println("subscribe to Test FAILED");
}
JSONVar root;
JSONVar d;
JSONVar supports;
supports["deviceActions"] = true;
supports["firmwareActions"] = true;
supports["switch-actions-v1"] = true;
d["supports"] = supports;
root["d"] = d;
char buff[300] = "";
JSON.stringify(root).toCharArray(buff, 300);
Serial.println("publishing device metadata:"); Serial.println(buff);
if (client.publish(manageTopic, buff)) {
Serial.println("device Publish ok");
} else {
Serial.print("device Publish failed:");
}
}
void callback(char* topic, byte* payload, unsigned int payloadLength) {
Serial.print("callback invoked for topic: "); Serial.println(topic);
if (strcmp (responseTopic, topic) == 0) {
return; // just print of response for now
}
if (strcmp (updateTopic, topic) == 0) {
handleUpdate(payload);
}
if (strcmp(switchTopic, topic) == 0) {
handleRemoteSwitch(payload);
}
if(strcmp(observeTopic, topic) == 0) {
handleObserve(payload);
}
}
void sendSuccessResponse(const char* reqId) {
JSONVar payload;
payload["rc"] = 200;
payload["reqId"] = reqId;
char buff[300] = "";
JSON.stringify(payload).toCharArray(buff, 300);
if (client.publish(deviceResponseTopic, buff)) {
Serial.println("Success sended");
} else {
Serial.print("Success failed:");
}
}
void publishStatus() {
String payload = "{\"relayStatus\":";
payload += outputEnable;
payload += "}";
Serial.print("Sending payload: "); Serial.println(payload);
if (client.publish(publishTopic, (char*) payload.c_str())) {
Serial.println("Publish OK");
} else {
Serial.println("Publish FAILED");
}
}
void handleUpdate(byte* payload) {
Serial.println("handle Update");
}
void handleObserve(byte* payload) {
JSONVar request = JSON.parse((char*)payload);
JSONVar d = request["d"];
JSONVar fields = d["fields"];
const char* field = fields[0]["field"];
if(strcmp(field, "mgmt.firmware") == 0) {
Serial.println("Upadete the firmware");
sendSuccessResponse(request["reqId"]);
} else {
Serial.println("Unmanaged observe");
Serial.println(request);
}
}
void handleRemoteSwitch(byte* payload) {
Serial.println("handle remote switching");
//invertedSwitch = !invertedSwitch;
outputEnable = !outputEnable;
JSONVar request = JSON.parse((char*)payload);
const char* id = request["reqId"];
sendSuccessResponse(id);
}
Thanks to everyone that wants to try to help me.
After several days I solved the issue, I post here de response for someone with the same problem:
The problem is the PubSubClient library, that accept only 128 bytes response message (including header). The Watson IBM produce longer response message than 128 bytes.
To change the buffer size for the response message, you need to modify the PubSubClient.h file at line
#define MQTT_MAX_PACKET_SIZE 128
And change the 128 byte with bigger number (eg. 1024).

How to handle errors

I was wondering what's the best way to handle errors in programmation (i'm coding in C). I'm a newbie in programmation and this is what i'm doing :
if( action1 was successfull )
{
[some code]
if (action 2 was successfull)
{
[some more code ..]
if (action 3 was successfull)
{
ETC ...
}
else
{
[Handle error3]
}
}
else
{
[handle error2]
}
}
else
{
[Handle error1]
}
But i think it's a bad habbit ... Can someone explain to me what's the most elegant way to do it ?
Thanks
I do it like this:
// more code
if (!action_1_succeeded())
{
handle_error();
return;
}
// more code
if (!action_2_succeeded())
{
handle_error();
return;
}
// more code
if (!action_3_succeeded())
{
handle_error();
return;
}
Usually, I will wrap up handle_error and return into a macro, so I just do check_error(some_statement());
Sometimes the code you show really is the best available option, but here are some alternatives.
Often you can structure your code like this instead:
if (action_1() failed) {
report error;
return -1;
}
if (action_2() failed) {
report error;
return -1;
}
/* etc */
This construct is why it's a common C idiom to return 0 on success or -1 on failure: it lets you write if (action_1() failed) as just if (action_1()).
If you need to do some cleanup before returning, and the clean-up actions nest neatly, this is another possibility:
if (action_1()) {
report error;
goto fail_a1;
}
if (action_2()) {
report error;
goto fail_a2;
}
if (action_3()) {
report error;
goto fail_a3;
}
/* etc */
return 0;
/* errors */
/* etc */
fail_a3:
clean up from a2;
fail_a2:
clean up from a1;
fail_a1:
return -1;
You are hereby licensed to use goto in order to do this.
You can create error-ids and associate an error handler with a particular type of error.
typedef struct _error {
void (*handler)(struct _error *);
int i_params;
char *c_params;
} error;
void nope(error * e) {}
void file_err(error * e) { exit(1); }
error handlers[200];
void check_error(int id) {
handlers[id].handler(&handlers[id]);
}
enum error { ER_SUCCESS, ER_FILE};
int main() {
handlers[ER_SUCCESS].handler = nope;
handlers[ER_FILE].handler = file_err;
check_error(action1());
return 0;
}

Resources