Emonlib+ADS1115+ESP32+Arduino Function Pointer - function-pointers

I have tried to contact the original designer for the ADS1115->EmonLib adaptation, but unfortunately his Github page has no contact information. I have also tried asking on the OpenEnergyMonitor forum and I get "Contact the person who made the changes".
So, I've come here in the hopes that the knowledgeable folk here can help me out.
Situation:
I have an ESP32 that I'm going to be using to monitor my energy consumption of my home. Because I will be monitoring several circuits I need lots of sensors. The ESP32 only has a 12-bit ADC and I'm limited to only a few sensors. Also limits future expansion if needed.
So here comes the ADS1115, which is a 16-bit ADC, but it uses I2C. Unfortunately, the EmonLib was designed to use onboard ADC, and not through an I2C device. So after doing some digging around, I found this modification to allow the ADS1115 to be used:
https://github.com/PaulWieland/EmonLib/
However, Paul Wieland is not able to be contacted through github.
Ok, so if I wanted to use only 1 ADS1115, I could just use his code as stock, which is this:
// In this example we will use an ADS1115 breakout board instead of the Arduino's local analog inputs
// This is especially useful for nodemcu/esp8266 users who only have a single analog input
#include <Wire.h>
#include <Adafruit_ADS1015.h>
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
#include <EmonLib_I2C.h> // Include Emon Library
EnergyMonitor emon1; // Create an instance
Adafruit_ADS1115 ads; // Create an instance of the ADS1115 object
// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _pin){
return ads.readADC_SingleEnded(_pin);
}
void setup()
{
emon1.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
emon1.current(1, 111.1); // Current: input pin, calibration.
}
void loop()
{
double Irms = emon1.calcIrms(1480); // Calculate Irms only
Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}
This compiles just fine. Though I am kinda confused as to how to select the "pin" of the ADS.
In the emonlib.cpp he added this code:
//--------------------------------------------------------------------------------------
// Constructor. Set the pinReader to the default pin reader method
//--------------------------------------------------------------------------------------
EnergyMonitor::EnergyMonitor()
{
this->inputPinReader = defaultInputPinReader;
}
//--------------------------------------------------------------------------------------
// By default we just call Arduino's analogRead
//--------------------------------------------------------------------------------------
int EnergyMonitor::defaultInputPinReader(int _pin)
{
return analogRead(_pin);
}
And changed this:
startV = analogRead(inPinV);
to:
startV = (this->inputPinReader)(inPinV);
and a few other spots where he made the adjustment using "this->".
And in the emonlib.h he added this to the Public section:
EnergyMonitor();
typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;
static int defaultInputPinReader(int _pin);
Now, for a single ADS1115, I think this works. At least the code compiles. But I need to use 4 ADS1115's as I'll need to be able to monitor up to 16 circuits. I can't for the life of me figure out how to add an array of ADS's to an array of emonlib's.
I tried doing this:
EnergyMonitor emon1[4]; // Create an instance
Adafruit_ADS1115 ads[4]; // Create an instance of the ADS1115 object
// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _channel, int _pin){
return ads[1].readADC_SingleEnded(_pin);
}
void setup()
{
emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
emon1[1].current(1, 111.1); // Current: input pin, calibration.
}
void loop()
{
double Irms = emon1[1].calcIrms(1480); // Calculate Irms only
Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}
but then I get this error:
Emon_ADS_Test:18:27: error: invalid conversion from 'int (*)(int, int)' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
I'm not very advanced in coding, and function pointers just confuse the heck outta me.
So my dilemma is I have several ADS1115's I need to match to the several instances of the EmonLib.
There has to be a separate instance for each wire monitored. On my working model that uses an Arduino Nano I have 2 emonlib variables (emon1, emon2). This works fine as it uses the internal ADC, tho I've found out over time that it is not very accurate and not fast enough or high enough resolution for my needs. (ie. when 0-current is flowing, it shows 50W usage).
What do I need to make a change to make this thing work?
Kori
[UPDATE 1]
Ok, after some testing, I do still get this:
emon[i * j].inputPinReader = ads1115PinReader;
emon[i * j].current(j++, 111.1);
Unfortunately this throws an error still:
Emon_ADS_Test:21:33: error: invalid conversion from 'int (*)(int, int)' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
emon1[i * j].inputPinReader = ads1115PinReader;
However, it comes to the function pointer as being a problem.
I use this code:
int ads1115PinReader(int _pin){
return ads.readADC_SingleEnded(_pin);
}
It works just fine. However if I do this:
int ads1115PinReader(int _channel, int _pin){
return ads[_channel].readADC_SingleEnded(_pin);
}
I get the error above. In the EmonLib_I2C library, the only thing I can think of is in this part:
typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;
static int defaultInputPinReader(int _pin);
not matching up. But even that doesn't make sense. In this line:
emon.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
does that mean that when I call inputPinReader, it "actually" grabs the value from ads1115PinReader instead of the one in the library?

Related

getting "undefined reference to ledc_cb_register" error

I'm trying to use a callback function with the led controller of esp32, however I'm unable to compile the code. I'm not sure if something is missing or the code has errors, as I have a limited understanding of pointers or coding in general.
I'm using the Arduino framework, however when I hover over the ledc_cb_register text, VSCode will popup some more details/definition of this function, so I would expect that it does see the reference to it.
relevant esp32 documentation:
docs.espressif.com
I'm trying to copy the following example, but make it a bit simpler (using only one channel):
github
It seems this example can be compiled on my side too, but this uses espidf framework.
trying the following code (many lines are not shown here for simplicity)
static bool cb_ledc_fade_end_event(const ledc_cb_param_t *param, void *user_arg)
{
portBASE_TYPE taskAwoken = pdFALSE;
if (param->event == LEDC_FADE_END_EVT) {
isFading = false;
}
return (taskAwoken == pdTRUE);
}
[...]
void setup() {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_HIGH_SPEED_MODE, // timer mode
.duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
.timer_num = LEDC_TIMER_0, // timer index
.freq_hz = LED_frequency, // frequency of PWM signal
.clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.gpio_num = LED_PIN,
.speed_mode = LEDC_HIGH_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.duty = 4000,
.hpoint = 0,
//.flags.output_invert = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
ledc_fade_func_install(0);
ledc_cbs_t callbacks = {
.fade_cb = cb_ledc_fade_end_event
};
ledc_cb_register(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, &callbacks, 0);
and getting the following error message:
[..]/.platformio/packages/toolchain-xtensa-esp32#8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x78): undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
[..]/.platformio/packages/toolchain-xtensa-esp32#8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o: in function 'setup()':
[..]\PlatformIO\Projects\asdf/src/main.cpp:272: undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1
According to the docs, it seems to be a feature that was added in v4.4.4
but the latest Arduino core (2.0.6) is build on v4.4.3.
If you are not on the latest Arduino core, try updating that first and see if it works. If not, then you just have to wait until the Arduino core is updated to use ESP IDF v4.4.4.
Of course, you can use ledc_isr_register(...) to register an ISR handler for the interrupt.
Best of luck!
Update:
I realized that the problem (at least on my side when testing it) was that there is an error in the ledc.h file, where they forgot to add ledc_cb_register in an extern "C" block.
I manually patched it by moving the
#ifdef __cplusplus
}
#endif
part, which was located after the ledc_set_fade_step_and_start function, below ledc_cb_register instead.
So, the end of my ledc.h file looks like this now:
...
esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode);
/**
* #brief LEDC callback registration function
* ...
*/
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg);
#ifdef __cplusplus
}
#endif

std::lock_guard (mutex) produces deadlock

First: Thanks for reading this question and tryin' to help me out. I'm new to the whole threading topic and I'm facing a serious mutex deadlock bug right now.
Short introduction:
I wrote a game engine a few months ago, which works perfectly and is being used in games already. This engine is based on SDL2. I wanted to improve my code by making it thread safe, which would be very useful to increase performance or to play around with some other theoretical concepts.
The problem:
The game uses internal game stages to display different states of a game, like displaying the menu, or displaying other parts of the game. When entering the "Asteroid Game"-stage I recieve an exception, which is thrown by the std::lock_guard constructor call.
The problem in detail:
When entering the "Asteroid Game"-stage a modelGetDirection() function is being called to recieve a direction vector of a model. This function uses a lock_guard to make this function being thread safe. When debugging this code section this is where the exception is thrown. The program would enter this lock_guard constructor and would throw an exception. The odd thing is, that this function is NEVER being called before. This is the first time this function is being called and every test run would crash right here!
this is where the debugger would stop in threadx:
inline int _Mtx_lockX(_Mtx_t _Mtx)
{ // throw exception on failure
return (_Check_C_return(_Mtx_lock(_Mtx)));
}
And here are the actual code snippets which I think are important:
mutex struct:
struct LEMutexModel
{
// of course there are more mutexes inside here
mutex modelGetDirection;
};
engine class:
typedef class LEMoon
{
private:
LEMutexModel mtxModel;
// other mutexes, attributes, methods and so on
public:
glm::vec2 modelGetDirection(uint32_t, uint32_t);
// other methods
} *LEMoonInstance;
modelGetDirection() (engine)function definition:
glm::vec2 LEMoon::modelGetDirection(uint32_t id, uint32_t idDirection)
{
lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);
glm::vec2 direction = {0.0f, 0.0f};
LEModel * pElem = this->modelGet(id);
if(pElem == nullptr)
{pElem = this->modelGetFromBuffer(id);}
if(pElem != nullptr)
{direction = pElem->pModel->mdlGetDirection(idDirection);}
else
{
#ifdef LE_DEBUG
char * pErrorString = new char[256 + 1];
sprintf(pErrorString, "LEMoon::modelGetDirection(%u)\n\n", id);
this->printErrorDialog(LE_MDL_NOEXIST, pErrorString);
delete [] pErrorString;
#endif
}
return direction;
}
this is the game function that uses the modelGetDirection method! This function would control a space ship:
void Game::level1ControlShip(void * pointer, bool controlAble)
{
Parameter param = (Parameter) pointer;
static glm::vec2 currentSpeedLeft = {0.0f, 0.0f};
glm::vec2 speedLeft = param->engine->modelGetDirection(MODEL_VERA, LEFT);
static const double INCREASE_SPEED_LEFT = (1.0f / VERA_INCREASE_LEFT) * speedLeft.x * (-1.0f);
// ... more code, I think that's not important
}
So as mentioned before: When entering the level1ControlShip() function, the programm will enter the modelGetDirection() function. When entering the modelGetDirection() function an exception will be thrown when tryin' to call:
lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);
And as mentioned, this is the first call of this function in the whole application run!
So why is that? I appreciate any help here! The whole engine (not the game) is an open source project and can be found on gitHub in case I forgot some important code snippets (sorry! in that case):
GitHub: Lynar Moon Engine
Thanks for your help!
Greetings,
Patrick

As to the GPIOTE function(External Interrupt) of nRF52832

I have some trouble to control GPIOTE function with nRF52832 sdk,
when using 14.01 version(SDK), it seems that the GPIOTE function can't be used with BLE function, I used the code below, it made hang-up issue of system, why?
I wonder whether GPIOTE function can't be used with BLE function or not,
and another method to use the function with BLE function,
thankful for your support and kindness in advance,
#define PIN_IN BUTTON_4
//#define PIN_OUT BSP_LED_3
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
printf("love %d: %d\n", (int)pin, (int)action);
// nrf_drv_gpiote_out_toggle(PIN_OUT);
}
/**
* #brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output,
* and configures GPIOTE to give an interrupt on pin change.
*/
void gpio_external_int_init(void)//love_1108
{
uint32_t err_code;
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
//
err_code = nrf_drv_gpiote_init();
APP_ERROR_CHECK(err_code);
//
// (void)nrf_drv_gpiote_init();
// nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
// err_code = nrf_drv_gpiote_out_init(PIN_OUT, &out_config);
// APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
in_config.pull = NRF_GPIO_PIN_PULLUP;
err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_event_enable(PIN_IN, true);
}
While you don't provide much detail, such as what is meant by "used with BLE function", I have found an issue with the SDK example ble_app_template. In my case the cause was that the file bsp_btn_ble.c demands that there are more buttons than my board_custom.h defines. So the function startup_event_extract() wants to check the state of BTN_ID_WAKEUP_BOND_DELETE, which does not exist on my hardware, causes an assertion. It is disturbing that BTN_ID_WAKEUP_BOND_DELETE and other buttons are defined in the c file, rather than being derived from custom_board.h.
So, trace the board initialization and you may find something like ASSERT(button_idx < BUTTONS_NUMBER), which caused a hang in my case.

How to print a string in protected mode in c

I am starter in os Deving and manage to make a bootloader and then a kernel.I cam successfully jumped to protected mode and transfer the control to kernel.I able to write single characters but printing string is not working.This is my printString() function.
void printString(char * message[]){
int i;
for(i = 0; message[i] != '\0'; i++)
{
print(message[i]);
}
}
And My print Character function is here
void print(char *character){
unsigned char *vidmem = (unsigned char *) VIDEO_ADDRESS;
int offset; //Variable which hold the offset where we want to print our character
offset = GetCursor(); //Setting our offset to current cursor position
vidmem[offset+1] = character;
vidmem[offset+2] = 0x0f;
SetCursor(offset+2);
}
and this is call to function
printString("manoj");
Please help me I am a starter in os deving
I would recommend keeping track of the X and Y coordinates as (static) globals, and using them for offsets into memory. Also, it shouldn't be offset+1 and offset+2, but rather offset and offset+1. This is in addition to what tangrs said in his answer.
A good tutorial for learning how to print to the screen can be found at http://www.jamesmolloy.co.uk/tutorial_html/3.-The%20Screen.html - he goes into great detail about how to print things. It also is a good place to start learning about OSDev, along with the OSDev forums at http://forum.osdev.org/index.php.
There's several things wrong with your functions
Firstly, your print function takes a pointer to a character where it looks like you want the character itself.
Secondly, your printString function is really taking a pointer to pointer to char which isn't what you want if you're calling the printString function like printString("Hello World");.
Your compiler should have warned you about these.
Your code should looks something like this
void printString(char * message){
// ...
}
void print(char character){
// ...
vidmem[offset+1] = character;
// ...
}

saving player information in an external file

This is the main menu in my first test 2d game in the world of unity :
I want to save high scores and if the player pressed the "Best Scores" button I want to show them the best scores yet ^^ , so I think I need to use an external file to save this type of information and open it at run time ... How ? which kind of files is the best to perform that ?
In addition to the answer above:
PlayerPrefs doesn't handle and store custom types and collections unless you cast those types to strings or other data, though. It's really useful to convert desired data to JSON and store the JSON string in PlayerPrefs, then fetch and parse that data when you need it again. Doing this will add another layer of complexity, but will also add another layer of protection and the ability to encrypt the data itself. Also, the Web Player is currently the only platform that has limits on PlayerPrefs according to Unity's docs:
There is one preference file per Web player URL and the file size is
limited to 1 megabyte. If this limit is exceeded, SetInt, SetFloat and
SetString will not store the value and throw a PlayerPrefsException.
Source:
http://docs.unity3d.com/Documentation/ScriptReference/PlayerPrefs.html
Writing:
PlayerPrefs.SetInt("score",5);
PlayerPrefs.SetFloat("volume",0.6f);
PlayerPrefs.SetString("username","John Doe");
// Saving a boolean value
bool val = true;
PlayerPrefs.SetInt("PropName", val ? 1 : 0);
PlayerPrefs.Save();
Reading:
int score = PlayerPrefs.GetInt("score");
float volume = PlayerPrefs.GetFloat("volume");
string player = PlayerPrefs.GetString("username");
bool val = PlayerPrefs.GetInt("PropName") == 1 ? true : false;
The simplest solution is using PlayerPrefs. It has limited space and a small set of data that can be saved (int, float, string), but it could be enough for a simple game.
If you need more space or more complex data structures to be saved, than you have to store them on the file system itself (or in a server if you have some backend support). Unity doesn't provide any built-in support for this.
C# is like this
//these variables will send the values in.
public static string exampleString = "hi youtube"; //it needs to be public ans static
public static int exampleInt = 1;
public static float exampleFloat = 3.14;
//these vaibles will collect the saved values
string collectString;
int collectInt;
float collectFloat;
public static void Save () { //this is the save function
PlayerPrefs.SetString ("exampleStringSave", exampleString);
// the part in quotations is what the "bucket" is that holds your variables value
// the second one in quotations is the value you want saved, you can also put a variable there instead
PlayerPrefs.SetInt ("exampleIntSave", exampleInt);
PlayerPrefs.SetFloat ("exampleFloatSave", exampleFloat);
PlayerPrefs.Save ();
}
void CollectSavedValues () {
collectString = PlayerPrefs.GetString ("exampleStringSave");
collectInt = PlayerPrefs.GetInt ("exampleIntSave");
collectFloat = PlayerPrefs.GetFloat ("exampleFloatSave");
)
void Awake () { //this is simialar to the start function
Save ();
CollectSavedValues ();
}
void Update () {
Debug.Log (collectString);
Debug.Log (collectInt);
Debug.Log (collectFloat);
}