Extension functions / unexpected behaviour - SOLVED


#1

I encountered a very strange problem I can’t solve: I’ve added a C function to the uLisp extension file (using “object *fn_ …” in a second .ino file) which needs to access internal global C variables defined in the main .ino file within the section “Global variables”.

For some inexplicable reason the variables can be accessed - the compiler does not complain in any way - but not written/set from within the extension function - and even reading them there does not necessarily reflect the actual current internal state of these variables. The global variables in question are updated internally by interrupts, and accessing them from within functions (added by me) in the main .ino file works flawlessly. I’ve tried my luck with “volatile” and “external …” (the latter in the second .ino file), but that does not change the situation in any way.

Currently I have absolutely no idea what might be the cause of this, not to mention how to get around that problem. Any help is greatly appreciated!


#2

It might be caused by Arduino mis-processing the second .ino file and breaking your externs. If you move it to a separate .hpp/.cpp file pair so that Arduino won’t touch it, that might help.

I tend to avoid multiple .ino files for one project, to avoid this and so I don’t get in the habit of relying on whatever pre-pre-processing tricks the Arduino IDE applies to .ino files. I treat the main .ino file as though it were main.cpp, and everything else is explicit .hpp/.cpp files.


#3

Thanks for your suggestion that makes sense, of course. Sadly, this does not seem to be the culprit here. The web tells me that several .ino files are just loaded in alphabetical order (after the primary .ino file) - this should not cause this strange phenomenon.

I suspect it has to do with the way uLisp commands are evaluated - things (no idea what things, really) are saved to a stack (push) that is written back after evaluating the list (pop), and this looks very suspicious since my problem feels exactly like that: I set a global variable within the (uLisp command) function and somehow the value it has had before seems to be written back to it afterwards.
I still don’t have any clue how to get around this…


#4

Can you provide a minimal, reproducible example of an extensions file that demonstrates the problem, and say which version and release of uLisp you are using it with?

Thanks,
David


#5

Thanks a lot for stepping in, David. I’ll do my very best.
The uLisp version in question is 4.5. The whole thing revolves around the Teensy USB host keyboard library that hooks up interrupt service routines to detect a key press and release.

First, I added global variables to the section “Global variables”:

bool kb_pressed = false;
bool kb_released = false;

These global variable get set within tiny ISRs added to the main uLisp file:

void on_press () {
  kb_released = false;
  kb_pressed = true;
}

void on_release () {
  kb_pressed = false;
  kb_released = true;
}

These ISRs are hooked to the Teensy keyboard driver:

keyboard.attachPress(on_press);
keyboard.attachRelease(on_release);

(“keyboard” is the USB host keyboard object defined and initialized before.)

So far, so good - this mechanism drives my LispBox internal REPL mechanism without flaws: Anytime the driver is questioned for the key last released “kb_released” is tested - if true a new key has been pressed (and released) and can be processed. This is necessary because for some reason the keyboard driver library does not seem to offer “flushing” the variable that contains the key pressed and released last; it’s constantly filled with the last value. That probably makes sense in some way - anyhow, I need to detect when a new key has been pressed. Internally (i.e. within the main uLisp REPL mechanism) this works fine.

Now I want to provide a new uLisp command that allows to poll the USB keyboard from within a Lisp program. So I added it to the extension file like this:

/*
  (keyboard-get-key [on_press])
  Get key last recognized [when pressed] (default: when released).
*/
object *fn_KeyboardGetKey (object *args, object *env) {
  (void) env;
  bool check_press = false;
  if (args != NULL) {
    check_press = (first(args) == nil) ? false : true;
  }

  if (!check_press) {
    if (kb_released) {
      kb_released = false;
      char temp = translate_key(keyboard.getKey(), keyboard.getModifiers());
      if ((temp != 0) && (temp !=255)) {
        return number(temp);
      }
      return nil;
    }
  }
  else {
    if (kb_pressed) {
      kb_pressed = false;
      char temp = translate_key(keyboard.getKey(), keyboard.getModifiers());
      if ((temp != 0) && (temp !=255)) {
        return number(temp);
      }
      return nil;
    }
  }
}

(This function would allow to check whether a key has been pressed or released, but that is of minor importance here.)

As you can see, the function only returns a key value when the global variable “kb_released” has been set and resets it immediately to indicate the key value has been retrieved. When I print the variable’s value to Serial immediately after clearing it, it does have the value “false” - but when I call the Lisp command again without having pressed a new key, the same value is read and retrieved again - somehow “kb_released” has magically become “true” again. The keyboard driver is innocent, I checked that the ISR really is called and serviced when and only when a new key gets pressed.

Maybe I should note that the internal REPL mechanism using the keyboard remains active as well, but theoretically this should have no impact as long as the Lisp program is running and does not access the interactive REPL, I guess. The thing here is: Even when I retrieve a key using my new command from the external Serial connection (thus bypassing the internal REPL, no new USB key is pressed) it should deliver the last value once and only once because the indicator is reset deliberately. Instead, it delivers the same value over and over again until a new key was pressed. The value of the global variable is always “true” when entering the command function, no matter how often it gets set to “false” within afterwards.

I hope I haven’t overlooked something obvious, but I’ve tried very hard to check everything again and again. Thanks a lot for your help!


#6

I’m finding it hard to follow your code. Can you try something more minimal, such as:

  • A global C variable myCount in the main uLisp file.
  • A Lisp function increment-count defined in the extensions file that increments myCount and returns the new value.

#7

Something that strikes me as odd is that your function doesn’t return anything if kb_pressed and kb_released are false. Try moving your return nil to right before the last bracket so it always returns that if all your if statements don’t trigger. Normally C gives an error for this, not sure why it’s ok here. (Also use volatile for variables that go into an Isr)


#8

Thanks everyone so far, I’ll follow your suggestions and get back with results.


#9

Solved! @hasn0life was on the right track, thanks a lot! The strange behaviour was caused by the fact that my new uLisp function didn’t return a valid uLisp value in some cases.
So I learn from it that it’s absolutely mandatory a uLisp command function returns either uLisp’s nil or some value, but never an undefined nothing because the latter leads to unexpected effects. My apologies, I didn’t even see what @hasn0life spotted here.
Thanks everyone for reading and helping out!
(Changed topic accordingly)


#10

Announcing uLisp Release 4.6 for all versions of uLisp