PROBLEM
I'm starting to play with Arduino IoT (ESP32). I read the GPIO configuration from a file on the SD card. I have a problem with external interrupts. I need to count the number of interrupts on a given GPIO.
I wrote a class that stores the GPIO configuration, and put the objects of this class in a global array. How can I count interrupts on a given pin, so that the result is available by using the appropriate object method?
I tried different solutions, but the problem lies in the ISR method, which must be static. This method has no access to object fields, so I do not know where and how to increment the counter of interrupts.
I divided the code into several files. I attach only the necessary to solve this problem.
This holds up my project. Please help.
Main file:
#define GPIO_CONFIG_FILE "cfg/gpio.txt"
#define WIFI_AP_CONFIG_FILE "cfg/ap.txt"
#define WIFI_STA_CONFIG_FILE "cfg/sta.txt"
#define AVAILABLE_GPIO_CNT 7
#define LED_BUILTIN_OLIMEX 33
#define BTN_BUILTIN_OLIMEX 34
#include "FS.h"
#include "SD_MMC.h"
#include "GPIO_CONFIG.h"
GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
uint32_t gpio_int_cnt[AVAILABLE_GPIO_CNT] = {0};
void setup() {
if (checkSdCard()) {
setUpPinsFromFile(GPIO_CONFIG_FILE);
}
}
void loop() {
}
GPIO_CONFIG.h
#ifndef GPIO_CONFIG_h
#define GPIO_CONFIG_h
#include "Arduino.h"
#define ID_LENGTH 7
class GPIO_CONFIG {
public:
GPIO_CONFIG();
void setUp(const char * key);
void printConfig();
uint8_t number();
uint8_t mode();
uint16_t multiplier();
bool inversion();
char * id();
static void isr();
static uint32_t int_cnt();
private:
uint8_t gp_number;
uint8_t gp_mode;
uint16_t gp_multiplier;
uint32_t gp_init_value;
bool gp_inversion;
char gp_id[ID_LENGTH];
// const uint8_t gp_mode_array[4] = {INPUT, OUTPUT, INPUT_PULLUP};
};
#endif
GPIO_CONFIG.cpp
#include "GPIO_CONFIG.h"
GPIO_CONFIG::GPIO_CONFIG() {
gp_number = 0;
gp_multiplier = 1;
gp_inversion = false;
gp_init_value = 0;
}
void GPIO_CONFIG::setUp(const char * key) {
//nr|id|name|mode|multi|inv|init
char cfg[sizeof(key)];
for (uint8_t b = 0; b < sizeof(key); ++b) {
cfg[b] = key[b];
}
//PIN_NUMBER
char * tok = strtok(cfg, "|");
gp_number = atoi(tok);
//ID
tok = strtok(NULL, "|");
for (int b = 0; b < sizeof(tok); b++) {
if (b < ID_LENGTH) {
gp_id[b] = tok[b];
} else {
break;
}
}
gp_id[ID_LENGTH - 1] = '\0';
//NAME
strtok(NULL, "|");
//MODE
tok = strtok(NULL, "|");
gp_mode = atoi(tok);
//MULTIPLIER
tok = strtok(NULL, "|");
gp_multiplier = atoi(tok);
//INVERSION
tok = strtok(NULL, "|");
gp_inversion = (atoi(tok) > 0);
//INITIAL VALUE
tok = strtok(NULL, "|");
gp_init_value = atoi(tok);
//0-in; 1-out; 2-int
if (gp_mode != 1) {
if (gp_inversion) { //sterowanie podstawowe przez vcc
pinMode(gp_number, INPUT_PULLUP);
} else {
pinMode(gp_number, INPUT);
}
if (gp_mode > 2) {
attachInterrupt(digitalPinToInterrupt(gp_number), isr, FALLING);
}
} else {
pinMode(gp_number, OUTPUT);
}
}
void GPIO_CONFIG::printConfig() {
#ifdef DEBUG
Serial.print("GPIO_CONFIG:");
Serial.print(" -no:");
Serial.print(gp_number);
Serial.print(" -id:");
Serial.print(gp_id);
Serial.print(" -mode:");
Serial.print(gp_mode);
Serial.print(" -multi:");
Serial.print(gp_multiplier);
Serial.print(" -inv:");
Serial.print(gp_inversion);
Serial.println("");
#endif
}
uint8_t GPIO_CONFIG::number() {
return gp_number;
}
uint8_t GPIO_CONFIG::mode() {
return gp_mode;
}
uint16_t GPIO_CONFIG::multiplier() {
return gp_multiplier;
}
bool GPIO_CONFIG::inversion() {
return gp_inversion;
}
char * GPIO_CONFIG::id() {
return gp_id;
}
void GPIO_CONFIG::isr() {
// gpio_int_cnt[0]++;
}
uint32_t GPIO_CONFIG::int_cnt() {
// return gpio_int_cnt[0];
}
#EDIT 2018/01/04 08:10
I add some changes to files:
Main .ino file
isr_ptr isrptr[AVAILABLE_GPIO_CNT];
GPIO_CONFIG.h
#define AVAILABLE_GPIO_CNT 7
class GPIO_CONFIG;
typedef /*static*/ void (*isr_ptr)();
extern isr_ptr isrptr[AVAILABLE_GPIO_CNT];
extern GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
(...)
public:
void setIndex(const uint8_t * i);
uint8_t index();
(...)
private:
uint8_t gp_index;
uint32_t gp_cnt_value;
GPIO_CONFIG.cpp
void GPIO_CONFIG::setIndex(const uint8_t * i){
gp_index = *i;
isrptr[gp_index] = &isr;
}
uint8_t GPIO_CONFIG::index(){
return gp_index;
}
void GPIO_CONFIG::setUp(const char * key) {
(...)
attachInterrupt(digitalPinToInterrupt(gp_number), isrptr[gp_index], FALLING);
(...)
}
void GPIO_CONFIG::isr() {
for(uint8_t i=0; i<AVAILABLE_GPIO_CNT; ++i){
if(&isrptr[i] == &gpio[i].isr()){ //here is my actualy problem. how can i compare this?
gpio[i].increment_cnt_value();
break;
}
}
}
uint32_t GPIO_CONFIG::int_cnt() {
return gp_cnt_value;
}
SOLUTION
Here I place short fragments which have to be modified:
GPIO_CONFIG.cpp
From isrptr[gp_index] = &isr; to isrptr[gp_index] = isr;
From if(&isrptr[i] == &gpio[i].isr){ to if(isrptr[i] == gpio[i].isr){
I've looked over your code several times and can't find your ISR(s). I know how to handle this sort of problem in simple C code: You just define an array with one element for each interrupt pin, and increment that element from its respective ISR. I don't know how to relate that to what you've shown.
The part that often causes trouble is that you usually need to define variables shared between the main code and ISR as volatile. Failing to do this can cause problems that are really hard to find, due to the compiler optimizing away things that it decides aren't changed (in the ISR or the main code).
Best regards,
Related
I have been stuck with this problem for multiple days now and can't seem to find a fix. The problem is that after I send a command to my shift register it doesn't accept more commands.
I'm using an arduino UNO with a 74HC595 shift register.
The problem occurs in the manualOverWrite function.
uint8_t RFIDPinValues[] = { B00000101 };
sr.setAll(RFIDPinValues);
delay(4000);
uint8_t RFIDOffPinValues[] = { B00001000 };
sr.setAll(RFIDOffPinValues);
When I run this piece of my code it turns on a relay(pin 0) and stops. All my arduino code keeps working except the shift register.
#include <SPI.h>
#include <ShiftRegister74HC595.h>
byte readCard[4];
String MasterTag0 = "*******";
String MasterTag1 = "********";
String tagID = "";
//declare arduino pins
int overWrite = 0;
// Create instances
const int numberOfShiftRegisters = 1; // number of shift registers attached in series
int serialDataPin = 11;
int clockPin = 12;
int latchPin = 8;
ShiftRegister74HC595<numberOfShiftRegisters> sr(serialDataPin, clockPin, latchPin);
void setup() {
Serial.begin(115200);
Serial.println("Startup");
// Initiating inputs
pinMode(overWriteButton, INPUT);
// set base state
sr.setAllLow();
uint8_t startValues[] = { B00001000 };
sr.setAll(startValues);
}
void loop() {
//ez to use vars
overWrite = digitalRead(overWriteButton);
manualOverWrite();
}
void manualOverWrite() {
if(overWrite == HIGH) {
uint8_t turnOnPinValues[] = { B00000101 };
sr.setAll(turnOnPinValues);
delay(5000);
uint8_t turnOffPinValues[] = { B00001000 };
sr.setAll(turnOffPinValues);
}
else {
uint8_t turnOn2PinValues[] = { B00001000 };
sr.setAll(turnOn2PinValues);
}
}
My apologies for the mess
https://mega.nz/file/NEYFiAAA#Rc4QUpv6cnL-_1NJJrjKe-IaInH_33wGJlHpGlVkySM
Summarize The Problem
I'm building an operating system using C++ on Linux Mint in Parallels Desktop Mac.
I just added keyboard support except there was a problem...
When I press one key on the keyboard, it will create around 5 or more characters. This is an image of the problem:
Describe What you've tried
All of the sources were talking about Linux kernel so I couldn't find anything. I didn't try anything.
Show some code
print.h
#ifndef PRINT_H
#define PRINT_H
#include "types.h"
#include "colours.h"
class print {
public:
void printf(char *str);
void printf(int num);
void itoa(int num, char *number);
uint32_t digit_count(int num);
uint32_t strlen(const char *str);
void print_char(char ch);
void newLine();
void init_vga(uint8_t fore_color, uint8_t back_color);
void clear_vga_buffer(uint16_t **buffer, uint8_t fore_color, uint8_t back_color);
uint16_t vga_entry(unsigned char ch, uint8_t fore_color, uint8_t back_color);
void setTextColors(uint8_t foreColor, uint8_t back_color);
print *getPrinter();
void setPrinter(print *printer1);
private:
print *ksafdkjlasdlfk;
//index for video buffer array
uint32_t vga_index;
//counter to store new lines
uint32_t next_line_index = 1;
//fore & back color values
uint8_t g_fore_color = WHITE, g_back_color = BLUE;
//digit ascii code for printing integers
int digit_ascii_codes[10] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
#define VGA_ADDRESS 0xB8000
#define BUFSIZE 2200
uint16_t *vga_buffer;
#define NULL 0
};
#endif
print.cpp
#include "print.h"
void print::printf(char *str) {
uint32_t index = 0;
while (str[index]) {
print_char(str[index]);
index++;
}
}
void print::printf(int num) {
char str_num[digit_count(num) + 1];
itoa(num, str_num);
printf(str_num);
}
void print::itoa(int num, char *number) {
int dgcount = digit_count(num);
int index = dgcount - 1;
char x;
if (num == 0 && dgcount == 1) {
number[0] = '0';
number[1] = '\0';
} else {
while (num != 0) {
x = num % 10;
number[index] = x + '0';
index--;
num = num / 10;
}
number[dgcount] = '\0';
}
}
uint32_t print::digit_count(int num) {
uint32_t count = 0;
if (num == 0)
return 1;
while (num > 0) {
count++;
num = num / 10;
}
return count;
}
uint32_t print::strlen(const char *str) {
uint32_t length = 0;
while (str[length])
length++;
return length;
}
void print::print_char(char ch) {
vga_buffer[vga_index] = vga_entry(ch, g_fore_color, g_back_color);
vga_index++;
}
void print::newLine() {
if (next_line_index >= 55) {
next_line_index = 0;
clear_vga_buffer(&vga_buffer, g_fore_color, g_back_color);
}
vga_index = 80 * next_line_index;
next_line_index++;
}
void print::init_vga(uint8_t fore_color, uint8_t back_color) {
vga_buffer = (uint16_t *) VGA_ADDRESS;
clear_vga_buffer(&vga_buffer, fore_color, back_color);
g_fore_color = fore_color;
g_back_color = back_color;
}
void print::clear_vga_buffer(uint16_t **buffer, uint8_t fore_color, uint8_t back_color) {
uint32_t i;
for (i = 0; i < BUFSIZE; i++) {
(*buffer)[i] = vga_entry(NULL, fore_color, back_color);
}
next_line_index = 1;
vga_index = 0;
}
uint16_t print::vga_entry(unsigned char ch, uint8_t fore_color, uint8_t back_color) {
uint16_t ax = 0;
uint8_t ah = 0, al = 0;
ah = back_color;
ah <<= 4;
ah |= fore_color;
ax = ah;
ax <<= 8;
al = ch;
ax |= al;
return ax;
}
void print::setTextColors(uint8_t foreColor, uint8_t back_color) {
g_fore_color = foreColor;
g_back_color = back_color;
}
print *print::getPrinter() {
return ksafdkjlasdlfk;
}
void print::setPrinter(print *printer1) {
ksafdkjlasdlfk = printer1;
}
keyboard.h
#ifndef APOS_KEYBOARD_H
#define APOS_KEYBOARD_H
#include "../../utils/types.h"
#include "../../utils/print.h"
#include "char.h"
class keyboard {
public:
void enableKeyboard();
void test_input();
void sleep(uint32_t timer_count);
void wait_for_io(uint32_t timer_count);
char get_input_keycode();
void outb(uint16_t port, uint8_t data);
uint8_t inb(uint16_t port);
};
#endif //APOS_KEYBOARD_H
keyboard.cpp
#include "keyboard.h"
uint8_t keyboard::inb(uint16_t port) {
uint8_t ret;
asm volatile("inb %1, %0" : "=a"(ret) : "d"(port));
return ret;
}
void keyboard::outb(uint16_t port, uint8_t data) {
asm volatile("outb %0, %1" : "=a"(data) : "d"(port));
}
char keyboard::get_input_keycode() {
char ch = 0;
while ((ch = inb(KEYBOARD_PORT)) != 0) {
if (ch > 0)
return ch;
}
return ch;
}
/*
keep the cpu busy for doing nothing(nop)
so that io port will not be processed by cpu
here timer can also be used, but lets do this in looping counter
*/
void keyboard::wait_for_io(uint32_t timer_count) {
while (1) {
asm volatile("nop");
timer_count--;
if (timer_count <= 0)
break;
}
}
void keyboard::sleep(uint32_t timer_count) {
wait_for_io(timer_count);
}
void keyboard::test_input() {
char ch = 0;
char keycode = 0;
do {
keycode = get_input_keycode();
if (keycode == KEY_ENTER) {
print printt;
printt.getPrinter()->newLine();
} else {
ch = get_ascii_char(keycode);
print printt;
printt.getPrinter()->print_char(ch);
}
sleep(0x02FFFFFF);
} while (ch > 0);
}
void keyboard::enableKeyboard() {
test_input();
}
The kernel.cpp just has the test_intput command and prints a few things.
There are a few files there, but that main ones are the kernel.cpp, hardware/keyboard/all the files there.
Either use a seperate Thread to handle the input reckognition function, that way you can use a sleep without blocking the main Thread. You could also save the current pressed key and save it as a previous key and check if it has changed, if not the button has not been released yet. so you can avoid multiples.
I am trying to fire a function every time an ESP32 node receives a certain char. I can receive the data and parse the char out of a packet structure I have made. I register all my actions in a map of type <char,callback_function>, where
typedef void (*callback_function)(void);
The idea being that I link all the chars to their respective functions. I can then parse a char out and find the pointer to the function I want to fire easily. The only downside is I have to keep a reference to a global object to access this map from within the bluetooth_callback. I've been testing this for almost 2 days now, and I've written some example code without the espressif APIs. On its own, my code seems to work fine and it runs on the ESP32 aswell. But if I let the bluetooth_callback get called after registering it with the espressif API (ie. let a real bluetooth event to fire the callback), the behavior becomes undefined. The size of the map is still correct with the number of pairs I have added to it, but all of the values and keys are null or undefined, and if I try to access them I get a Guru Meditation Error. I have been trying to solve this problem a lot, and the behaviour is very strange to me. If I call the callback manually then everything seems to work, but if I let it get called by a bluetooth event, I get undefined behavior and crashes. I'm not sure if I am doing something wrong c++ wise or if I this is an issue specific to the esp32. I could be making a dumb mistake. I have attached my Arduino script, the header and cpp files of the library I was working on, and a sample application that should show what I am trying to do. Thank you for your help.
Hardware:
Board: ESP32 Dev Module (Sparkfun ESP32 thing)
Core Installation version: 1.0.3
IDE name: Arduino IDE
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 115200
Computer OS: Windows 10
Backtrace
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400014e8 PS : 0x00060430 A0 : 0x800d2410 A1 : 0x3ffcf1a0
A2 : 0x000000fe A3 : 0x000000fc A4 : 0x000000ff A5 : 0x0000ff00
A6 : 0x00ff0000 A7 : 0xff000000 A8 : 0x800d2228 A9 : 0x3ffcf170
A10 : 0x3ffbed90 A11 : 0x3f40148b A12 : 0x3f40148b A13 : 0x0000ff00
A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000010 EXCCAUSE: 0x0000001c
EXCVADDR: 0x000000fc LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffb
Backtrace: 0x400014e8:0x3ffcf1a0 0x400d240d:0x3ffcf1b0 0x400d242d:0x3ffcf1d0 0x400d14a2:0x3ffcf1f0 0x400d1501:0x3ffcf210 0x400df881:0x3ffcf230 0x400d8362:0x3ffcf280 0x4008d83d:0x3ffcf2b0
Decoded:
PC: 0x400014e8
EXCVADDR: 0x000000fc
Decoding stack results
0x400d240d: Print::write(char const*) at C:\Users\Jake Booth\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.3\cores\esp32/Print.h line 66
0x400d242d: Print::print(char const*) at C:\Users\Jake Booth\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.3\cores\esp32\Print.cpp line 89
0x400d14a2: NodeESP::act_message(char*) at C:\Users\Jake Booth\Documents\Arduino\libraries\NodeESP\NodeESP.cpp line 336
0x400d1501: NodeESP::bluetooth_callback(esp_spp_cb_event_t, esp_spp_cb_param_t*) at C:\Users\Jake Booth\Documents\Arduino\libraries\NodeESP\NodeESP.cpp line 176
0x400df881: btc_spp_cb_handler at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c line 152
0x400d8362: btc_task at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/core/btc_task.c line 110
0x4008d83d: vPortTaskWrapper at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/port.c line 143
I've highlighted line 336 below to show you easily which one it is.
Arduino Sketch
#include "NodeESP.h"
#define LED_PIN 5
#define TOGGLE_LED_CHAR 'l'
#define TURN_ON_LED_CHAR 'p'
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_PIN,OUTPUT);
char l = TOGGLE_LED_CHAR;
char p = TURN_ON_LED_CHAR;
esp_spp_cb_param_t ex_param;
ex_param.data_ind.data = (uint8_t*)l;
ex_param.data_ind.len = 1;
//ex_param_ptr = *ex_param;
NodeESP node_esp;
node_esp.add_func(&p, toggle_LED);
node_esp.add_func(&l, turn_on_LED);
node_esp.begin("TEST_1");
//Just calling it manually works, but when the espressif API calls it I get undefined behaviour.
// NodeESP::bluetooth_callback(ESP_SPP_DATA_IND_EVT,&ex_param);
}
void toggle_LED()
{
Serial.println("toggle_LED()");
}
void turn_on_LED()
{
Serial.println("turn_on_LED()");
}
void loop() {
// put your main code here, to run repeatedly:
while(1)
{
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
NodeESP.h
/*
NodeESP.cpp - Library for automatically connecting to and using esp32 microcontrollers
Created by Jacob Booth 11/9/2020
*/
#ifndef NodeESP_h
#define NodeESP_h
#include "Arduino.h"
#include <ESPmDNS.h>
#include <WiFi.h>
#include <map>
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "esp_gap_bt_api.h"
//---Define buffer constants--------------------------
#define RCV_BUF_SIZE 128
#define TX_BUF_SIZE 256
//---Define communication constants-------------------
#define RFCOMM_CHANNEL 1
#define RFCOMM_MAX_FRAME_SIZE 0xffff
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! please run 'make menuconfig' to enable it
#endif
class NodeESP
{
public:
//Constructor
NodeESP();
//Begin
bool begin(const char *_name);
//Typedef
typedef void (*callback_function)(void);
//Variables
uint32_t bt_handle;
const char *_name;
std::map<char*, callback_function> funcs;
char rx_buf[RCV_BUF_SIZE];
char tx_buf[RCV_BUF_SIZE];
WiFiServer server;
WiFiClient client;
//Generic
void add_func(char* command, callback_function func);
void act_message(char* trigger);
//Bluetooth
void bluetooth_write(char *buf, int len);
bool bluetooth_spp_init();
bool bluetooth_init(const char *deviceName);
static char parse_data(uint8_t *rcvd, uint16_t len);
static void bluetooth_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param);
String toString(const IPAddress & address);
private:
};
#endif
NodeESP.cpp
/*
NodeESP.cpp - Library for automatically connecting to and using esp32 microcontrollers
Created by Jacob Booth 11/9/2020
*/
#include "Arduino.h"
#include <ESPmDNS.h>
#include <WiFi.h>
#include <map>
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "esp_gap_bt_api.h"
#include "NodeESP.h"
using namespace std;
//---State Machine Variables---
//State enum that helps the state machine track its way through
//connecting to wifi.
enum state_t {
UNDEFINED,
DISCONNECTED,
WIFI_CON,
SERVER_CON
};
enum comm_t {
s,
NONE,
WIFI,
BLUETOOTH,
q
};
//The current communication protocol we are using
comm_t cur_comm = s;
//The current state
state_t cur_state = UNDEFINED;
char tx_buf[TX_BUF_SIZE];
char rx_buf[RCV_BUF_SIZE];
//---Wifi
WiFiServer server(0);
WiFiClient client;
//---Bluetooth
uint32_t bt_handle;
void* example_obj;
//---Main Init--------------------------------------------------------
NodeESP::NodeESP()
{
this->_name = "default";
example_obj = (void*)this;
}
bool NodeESP::begin(const char *_name)
{
this->_name = _name;
//For testing set the current communication method to bluetooth
cur_comm = BLUETOOTH;
switch (cur_comm)
{
case UNDEFINED:
return false;
break;
case NONE:
return false;
break;
case WIFI:
return true;
break;
case BLUETOOTH:
if (!this->bluetooth_init(_name))
{
return false;
}
break;
}
return true;
}
//---Bluetooth Functions--------------------------------
bool NodeESP::bluetooth_init(const char *deviceName)
{
//Start Bluetooth
if (!btStart())
{
return false;
}
//Start BlueDroid (bluetooth stack)
if (esp_bluedroid_init()!= ESP_OK)
{
return false;
}
//Enable BlueDroid
if (esp_bluedroid_enable()!= ESP_OK)
{
return false;
}
//Set device name
esp_bt_dev_set_device_name(deviceName);
//Set sannable and discoverable
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
//Init spp server
if (!this->bluetooth_spp_init())
{
return false;
}
//Set send bytes to the correct callback
//send_bytes = write_bluetooth;
return true;
}
bool NodeESP::bluetooth_spp_init()
{
if (esp_spp_register_callback(&bluetooth_callback) != ESP_OK)
{
return false;
}
if (esp_spp_init(ESP_SPP_MODE_CB) != ESP_OK)
{
return false;
}
if (esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 1, "") != ESP_OK)
{
return false;
}
return true;
}
void NodeESP::bluetooth_write(char *buf, int len)
{
esp_spp_write(bt_handle, len, (uint8_t*)buf);
}
void NodeESP::bluetooth_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
switch (event)
{
case ESP_SPP_SRV_OPEN_EVT:
{
NodeESP* self = (NodeESP*) example_obj;
self->bt_handle = param->srv_open.handle;
break;
}
case ESP_SPP_CL_INIT_EVT:
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_NONE);
break;
case ESP_SPP_OPEN_EVT:
break;
case ESP_SPP_DATA_IND_EVT:
{
NodeESP* self = (NodeESP*) example_obj;
//char trig = self->parse_data(param->data_ind.data, param->data_ind.len);
self->act_message((char*)param->data_ind.data);
break;
}
case ESP_SPP_CLOSE_EVT:
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
case ESP_SPP_WRITE_EVT:
break;
case ESP_SPP_CONG_EVT:
break;
}
return;
}
//---Parsing functions-------------------------------
//TODO: Add circular buffer
char NodeESP::parse_data(uint8_t *rcvd, uint16_t len)
{
char body_buf[RCV_BUF_SIZE];
uint8_t len_buf[2];
uint8_t rcvd_bytes = 0;
uint8_t recive_stage = 0;
uint16_t calc_len = 0;
//Loop through each char recieved
for (uint16_t i = 0; i < len; i++)
{
uint8_t cur_char = rcvd[i];
rcvd_bytes++;
//If we haven't recieved the length or body
//And we recieve a start delim
if (recive_stage == 0 && cur_char == 0x7E)
{
//We are ready to read the length of the message (next 2 bytes)
recive_stage = 1;
rcvd_bytes = 0;
}
else if (recive_stage == 1)//If we are recieving the length
{
//Next two bytes get stored in the length buffer
len_buf[rcvd_bytes - 1] = cur_char;
//If we have recieved the 2 length bytes
if (rcvd_bytes == 2)
{
//Decode the length
calc_len = ((uint16_t)len_buf[0]) << 8 | (uint16_t)len_buf[1];
//Ready to recieve the body
recive_stage = 2;
rcvd_bytes = 0;
}
}
else if (recive_stage == 2)//If we are recieving the body
{
//Store the recieved bytes
body_buf[rcvd_bytes - 1] = cur_char;
if (rcvd_bytes == calc_len)
{
//Reset
rcvd_bytes = 0;
recive_stage = 0;
return(cur_char);
}
}
}
return '/';
}
void NodeESP::add_func(char* command, callback_function func)
{
Serial.println("Added new callback...");
std::pair<char*, callback_function>* new_pair = new std::pair<char*, callback_function>(command,func);
this->funcs.insert(*new_pair);
}
void NodeESP::act_message(char* trigger)
{
Serial.println("[act message]");
Serial.print("funcs.size() = ");
Serial.print(this->funcs.size()); //Always returns the correct size all of the time
Serial.println("");
for (std::map<char*, callback_function>::iterator it = this->funcs.begin();
it != this->funcs.end();
++it)
{
Serial.print("funcs[i].first = ");
Serial.print(it->first); //Line 336, accessing the first element of the iterator
Serial.println(""); //This works properly when I don't call the function through the callback.
if (trigger == it->first)
{
(it->second)();
}
}
}
String NodeESP::toString(const IPAddress & address)
{
return String(address[0]) + "." + address[1] + "." + address[2] + "." + address[3];
}
Example Program
Here is an example program that shows what I want to happen and that it works correctly.
// Example program
#include <iostream>
#include <string>
#include <map>
//Global object to access the instance from within static function
using namespace std;
class example
{
public:
example();
void begin();
typedef void (*callback_function)(void);
std::map<char, callback_function> funcs;
void add_func(char command, callback_function func);
void do_something(char trigger);
static void example_callback(char cb);
};
void* example_obj;
example::example()
{
example_obj = (void*)this;
}
void example::begin()
{
//Set up everything to do with external library, peripherals, ect...
//Register the callback with the library
//register_callback(&example_callback);
}
//Static func that does something
void example::example_callback(char cb)
{
//Have to do this because the args need to match the library's requirements
example* self = (example*) example_obj;
//Do some processing...
self->do_something(cb);
}
//Add a function pointer and its command char to the vector
void example::add_func(char command, callback_function func)
{
std::pair<char, callback_function>* new_pair = new std::pair<char, callback_function>(command,func);
this->funcs.insert(*new_pair);
}
//This function is called from the callback
void example::do_something(char trigger)
{
cout << "funcs.size() = "<< (this->funcs.size())<<"\n"; //Always returns the correct size all of the time
for (std::map<char, callback_function>::iterator it = this->funcs.begin();
it != this->funcs.end();
++it)
{
cout << "funcs[i].first = "<< (it->first)<<"\n";
if (trigger == it->first)
{
(it->second)();
}
}
}
void callback()
{
cout << "Callback Called!";
}
int main()
{
cout << "Starting program...\n";
cout << "Creating example object...\n";
example ex;
cout << "Adding some callbacks...\n";
ex.add_func('x',callback);
ex.add_func('y',callback);
ex.add_func('z',callback);
cout << "Firing callback...\n";
example::example_callback('z');
}
I see there are a couple of Q&A in this topic but I still can't find the clue to my issue. I must admit I am pretty new to c++, so this might be the root cause.
Ok, so I am trying to declare a new type like :
struct measurement_t
{
int sensorID;
int sensorData;
measurement_t(int ID, int Data)
{
sensorID = ID;
sensorData = Data;
}
};
and my project contains a method, that should return this type of data:
measurement_t getLightSensorData()
{
...
}
when I try to compile the code I got error : error: 'measurement_t' does not name a type
What I also find very strange is that the error line the compiler reports is the line number of the first #define statement at the very beginning of the code :
#define CE_PIN 7
If I simply change the method to void, the the project compiles (useless, though).
I also tried returning pointer by specifying measurement_t * as return type but the result is the same. Tried remove constructor from struct, same result again.
Can someone please help me to understand what the problem is here ?
The minimal version of the code that reproducing the same issue is:
struct measurement_t
{
int sensorID;
int sensorData;
measurement_t(int ID, int Data)
{
sensorID = ID;
sensorData = Data;
}
};
measurement_t getLightSensorData()
{
int sensorValue = 1;
measurement_t m(1, sensorValue);
return m;
}
For reference, this is intended to be an arduino sketch, and the full code is as below:
#include "RF24.h"
#include <SPI.h>
#include "printf.h"
#define CE_PIN 7
#define CS_PIN 8
#define LIGHTSENSOR_PIN A0
RF24 myRadio(CE_PIN, CS_PIN);
byte rxAddr[6] = { 0x0, 0x0, 0x0, 0x0, 0x0F };
unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 3000; // send once per second
unsigned long loopSleepMillis = 200;
struct measurement_t
{
int sensorID;
int sensorData;
measurement_t(int ID, int Data)
{
sensorID = ID;
sensorData = Data;
}
};
// the setup routine runs once when you press reset:
void setup()
{
Serial.println(">>> Initializing...");
Serial.begin(115200);
printf_begin();
bool radioOk = myRadio.begin(); // Start up the physical nRF24L01 Radio
if (radioOk) Serial.println(" Radio initialized");
else Serial.println(" ERROR initializing radio !");
myRadio.setChannel(120); // Above most Wifi Channels
myRadio.setPALevel(RF24_PA_HIGH);
myRadio.setRetries(15, 15);
myRadio.openWritingPipe(rxAddr); // Use the first entry in array 'addresses' (Only 1 right now)
Serial.println("<<< Done initialization");
}
// the loop routine runs over and over again forever:
void loop()
{
currentMillis = millis();
if (currentMillis - prevMillis >= txIntervalMillis)
{
transmitData(getLightSensorData());
prevMillis = millis();
}
delay(loopSleepMillis);
}
measurement_t getLightSensorData()
{
int sensorValue = analogRead(LIGHTSENSOR_PIN);
measurement_t m(1, sensorValue);
return m;
}
void transmitData(measurement_t data)
{
myRadio.stopListening();
Serial.print("Transmitting data...");
bool writeOK = myRadio.write(&data, sizeof(data));
if (writeOK)
{
Serial.println("OK");
}
else
{
Serial.println(F("no response"));
//myRadio.printDetails();
}
}
You had to use
struct measurement_t getLightSensorData()
{
int sensorValue = analogRead(LIGHTSENSOR_PIN);
measurement_t m(1, sensorValue);
return m;
}
You might have outdated version of Arduino IDE because on my IDE it compiled without the use of struct keyword.
I'm fiddling with an Arduino project where I've got these structs in my main file:
struct gpsCoord_t {
long latitude;
long longitude;
};
struct track_t {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
};
Next to that I've got a function to dump variables of this type to the serial bus in that same file:
void dumpTrack(track_t track) {
Serial.print("\nTrack: ");
Serial.print(track.code);
Serial.print("\nTrack bounds: ");
Serial.print("\n- 1 lat: ");
Serial.print(track.bounds[0].latitude);
Serial.print("\n- 1 lon: ");
Serial.print(track.bounds[0].longitude);
}
The compiler produces 2 errors without line numbers from which I believe the first one is caused by the second one:
error: variable or field 'dumpTrack' declared void
error: 'track_t' was not declared in this scope
EDIT here's the complete file:
#include <Wire.h> //I2C library
#include <I2C_eeprom.h>
#include <SoftwareSerial.h>
#include <TinyGPS.h>
I2C_eeprom ee(0x50);
const int baseTrackAddress = 3;
const int trackSize = 68;
const int maxTracks = 480;
int powerOnLED = 2;
int gpsFixLED = 3;
int trackFoundLED = 4;
int errorLED = 6;
int gpsSensor = 7;
TinyGPS gps;
SoftwareSerial nss(gpsSensor, 255);
int calcTrackAddress(int trackId) {
return (trackId*trackSize) + baseTrackAddress;
}
struct gpsCoord_t {
long latitude;
long longitude;
};
struct track_t {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
};
track_t tracks[maxTracks];
void setup()
{
Serial.begin(115200);
Serial.flush();
Serial.print("Demo I2C eeprom library ");
Serial.print(I2C_EEPROM_VERSION);
Serial.println("\n");
strcpy(tracks[0].code, "X11");
tracks[0].bounds[0].latitude = 0;
tracks[0].bounds[0].longitude = 0;
tracks[0].points[0].latitude = 0;
tracks[0].points[0].longitude = 0;
ee.writeBlock(3, (uint8_t*)&tracks[0], trackSize);
}
void loop()
{
Serial.println("\nTEST: 64 byte page boundary writeBlock");
dumpEEPROM(0, 255);
while(1);
}
void dumpTrack(track_t track) {
Serial.print("\nTrack: ");
Serial.print(track.code);
Serial.print("\nTrack bounds: ");
Serial.print("\n- 1 lat: ");
Serial.print(track.bounds[0].latitude);
Serial.print("\n- 1 lon: ");
Serial.print(track.bounds[0].longitude);
}
void readTrack(int trackId) {
track_t track;
ee.readBlock(60, (uint8_t*)&track, 10);
}
void readTracks() {
}
void dumpEEPROM(unsigned int addr, unsigned int length)
{
// block to 10
addr = addr / 10 * 10;
length = (length + 9)/10 * 10;
byte b = ee.readByte(addr);
for (int i = 0; i < length; i++)
{
if (addr % 10 == 0)
{
Serial.println();
Serial.print(addr);
Serial.print(":\t");
}
Serial.print(b);
b = ee.readByte(++addr);
Serial.print(" ");
}
Serial.println();
}
void ProcessCommand(char* command) {
//switch(*command==)
}
char* ReadSerialCommand() {
int i=0;
char commandbuffer[100];
if(Serial.available()){
delay(100);
while( Serial.available() && i< 99) {
commandbuffer[i++] = Serial.read();
}
commandbuffer[i++]='\0';
}
if(i>0)
return (char*)commandbuffer;
else
return 0L;
}
When I put the entire dumpTrack function in comment, the errors go away. I've checked a couple of times for a typo but failed to find any.
It seems you are compiling this code as C.
Instead of
struct track_t {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
};
write
typedef struct {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
} track_t;
I suspect somewhere in a header there is a variable called dumpTrack. Why don't you just rename the function to something else?
Also in general it is good to avoid using reserved words as function names; "loop" is not a good choice for a function name.
Edit: the latter is probably the reason for your problem.