Lightweight C++ callbacks

@defragster
As I was working on something different I was relooking at the Talkie library. It looks like the latest incarnation of Talkie does a bit of rework to support the Teensies: https://github.com/ArminJo/Talkie. but not the PWM version that we put together. Just a FYI. Most the lib is the same.

Wow - that was "03-26-2016, 05:02 PM" - quite a few updates since then including Teensy.

And the includes the nonBlocking Queue work including the "FIFO_BUFFER_SIZE 24" depth as @defragster wrote it - used the same 'SayQ()' name and added some other Q()'s - though uses real var names better than 'o' and 't':
Updated the PULL requested - includes indicated change to .active() return value.

Modified sample from Adrian (using Prop Shield) to demonstrate usage of .say() and all added methods of "Talkie voice"...

Edits to Talkie.cpp and .h and keywords.txt :: Removed the delay(25) from .say using .sayQ

Called it sayQ() because I added a 24 sound queue managed in the code so not one but 25 sounds can be pushed into a queue for playing sequentially without user attention or delay.

.active() - is **false** on silence, else **returns count** of sounds yet to play
.sayQ() - returns the space left in queue
.sayQ(0) empties the que and stops audio out
.say(0) empties the que and stops audio out
.say() is otherwise 'unchanged' - it will block

Added example of all methods: SayQAcorn.ino
Core Talkie code unchanged, except for cascaded timer to update synthesis data

Just noticed new "GNU General Public License" prior/current code was "released under GPLv2 license."
 
I think I might have spotted a gremlin that's crept in with the new IntervalTimer. I'd like my (library) function to be able to tell if it's been called from within an ISR, so to that end I've got the very simple:
Code:
uint32_t get_VectActive(void) { return (SCB_ICSR & 0x1FF);}
which I believe should return 16+<vector number of the current executing exception>, or 0 if in Thread mode (section B3.2.4 of ARM DDI 0403E.b). This works OK for the IRQ_SOFTWARE used for audio updates (gives 86, which is as expected, 16+70 ), but when placed in an IntervalTimer's callback function it resolutely returns zero. If, however, I put a call directly into the pit_isr(), I get the correct value of 138 for the PIT vector. So, something's happened to lose the information that we're in an interrupt by the time the body of my callback code has been reached.

I tried to revert to the old behaviour by lying about the Teensyduino version just in IntervalTimer.h, but got a link error - something appears to still want the newfangled version of callback_t, though I'm blowed if I can find it:
Code:
d:/swd/arduino-1.8.19-tmp/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\Jonathan\AppData\Local\Temp\arduino_build_238101/core\core.a(AudioStream.cpp.o): in function `bool IntervalTimer::begin<float>(stdext::inplace_function<void (), 16u, 8u>, float)':
D:\swd\arduino-1.8.19-tmp\hardware\teensy\avr\cores\teensy4/IntervalTimer.h:68: undefined reference to `IntervalTimer::beginCycles(stdext::inplace_function<void (), 16u, 8u>, unsigned long)'
collect2.exe: error: ld returned 1 exit status
I'll try to work up a simple example which doesn't need a bunch of libraries to be edited ... stay tuned!
 
AAArrrgh ... I'm a numpty ... ignore the above. I was calling the callback from loop() as well as the IntervalTimer ... because I initially wanted to test it was correct. :rolleyes:

As you were, folks.
 
AAArrrgh ... I'm a numpty ... ignore the above. I was calling the callback from loop() as well as the IntervalTimer ... because I initially wanted to test it was correct. :rolleyes:

As you were, folks.

Can you post the working sketch with the _ISR showing the expected? If reading right: Could be handy in some case (act like a parameter) if called from loop() {==0} or by normal _ISR process {==16+70} - or maybe by another _ISR {==16+??}?
 
Here you go. Shows different vector numbers for the minimal audio object and IntervalTimer callback, and the 0 "thread vector" value when I call the callback from loop().

Code:
#include "Audio.h"

uint32_t get_VectActive(void) { return (SCB_ICSR & 0x1FF);}

//============================================================
volatile uint32_t audioVecnum,audioUpdateCount;
class AudioDummy : public AudioStream
{
  public:
    AudioDummy() : AudioStream(0,nullptr) {active = true;}
    void update() 
    {
      audioUpdateCount++;
      audioVecnum = get_VectActive();
    }
};

AudioDummy audioDummy;
AudioOutputI2S i2so;
//============================================================
volatile uint32_t pitVecnum,itUpdateCount;
void itCallback(void)
{
  itUpdateCount++;
  pitVecnum = get_VectActive();
}
IntervalTimer myTimer;

//============================================================
void setup() 
{
  AudioMemory(1); 
  myTimer.begin(itCallback,166666);
}

void loop() 
{
  Serial.printf("%d audio updates; audio vector (+16) is %d\n",audioUpdateCount,audioVecnum);
  Serial.printf("%d IntervalTimer updates; PIT vector (+16) is %d\n",itUpdateCount,pitVecnum);
  
  itCallback(); // prove the thread access gives a different result
  Serial.printf("%d IntervalTimer updates; 'thread vector' is %d\n",itUpdateCount,pitVecnum);
  
  Serial.println();
  delay(250);
}
 
There's a bug in inplace_function.h when using a function that doesn't have `void` as its return type. This is because is declared to do nothing. Instead, it should be defined to something that doesn't return, for example `__throw_bad_function_call()`. However, because this is an internal function, I don't think it's a great idea to depend on its existence _or_ even to depend on including the file that declares it (_bits/funcexcept.h_). Instead, I suggest calling `abort()` or `exit()` or something; something that's defined to not return.

The error:
Code:
/Users/me/.platformio/packages/framework-arduinoteensy/cores/teensy4/inplace_function.h:104:21: warning: no return statement in function returning non-void [-Wreturn-type]
  104 |         invoke_ptr{ [](storage_ptr_t, Args&&...) -> R
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  105 |             { SG14_INPLACE_FUNCTION_THROW(std::bad_function_call()); }

Example code to duplicate:
Code:
stdext::inplace_function<bool()> func;

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000) {
    // Wait for Serial
  }

  // Either this:
  func();

  // Or this will cause the issue:
  if (func == nullptr) {
    printf("Here\r\n");
  }
}

void loop() {
}

The Arduino IDE error:
Code:
/Users/me/Documents/Arduino/bug-inplace-func/bug-inplace-func.ino:13:12:   required from here
/Users/me/Library/Arduino15/packages/teensy/hardware/avr/0.59.3/cores/teensy4/inplace_function.h:104:21: warning: no return statement in function returning non-void [-Wreturn-type]
  104 |         invoke_ptr{ [](storage_ptr_t, Args&&...) -> R
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  105 |             { SG14_INPLACE_FUNCTION_THROW(std::bad_function_call()); }
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I've made a PR request that fixes the issue here:
https://github.com/PaulStoffregen/cores/pull/717

See the notes in _inplace_function.h_ and in the commit message for more details.
 
@luni - I have been playing around with the CallBackHelper library. Trying to learn something :D. One problem I ran into was a capitalization error in "PIT.h":
Code:
#include "callbackHelper.h"
Should be:
Code:
#include "CallbackHelper.h"
I use Linux which is sensitive to capitalization. I thought I would bring it up so if others got the file not found error they would know why.
 
Thanks, I'll fix that. However, CallbackHelper was just an experiment to understand how those things work. Please note that since the new TD1.59, the core contains teensy::Inplace_function which is a much better solution.
 
Thanks, I'll fix that. However, CallbackHelper was just an experiment to understand how those things work. Please note that since the new TD1.59, the core contains teensy::Inplace_function which is a much better solution.
Thanks Luni :D
 
Back
Top