Page 1 of 3

Ndless KeyListener

Unread postPosted: 06 May 2016, 05:05
by MishaShapo
Hi, I am trying to create a keylistener in Ndless that will print an ASCII string to the USB port through NspireIO. I have looked at the Zlock and nClock examples to try and emulate them, but my code doesn't seem to work. It sends the "URTX" message and then the calculator freezes, but I do know the program is running because when I press the flag button (the button that terminates the outer while loop in my main method) then the calculator goes back to normal.

Can anyone please point out what I am doing wrong? Thank you. :)


Salut, je suis en train de créer un keyListener en Ndless qui imprimera une chaîne ASCII au port USB via NspireIO. J'ai regardé les exemples ZLOCK et nClock pour essayer de les imiter, mais mon code ne semble pas fonctionner. Il envoie le message "Urtx", puis la calculatrice se fige, mais je ne sais que le programme est en cours d'exécution parce que quand je presse le bouton de drapeau (le bouton qui met fin à l'extérieur tout en boucle dans ma méthode principale), le calculateur va revenir à la normale.

Quelqu'un peut-il s'il vous plaît souligner ce que je fais mal? Je vous remercie. :)

Code: Select all
#include <os.h>
#include "libndls.h"
#include <nspireio/nspireio.h>
char *cmd = "";
bool quit = false;

void pushButton(){
    if(isKeyPressed(KEY_NSPIRE_0)) cmd = "0";
    if(isKeyPressed(KEY_NSPIRE_1)) cmd = "1";
    if(isKeyPressed(KEY_NSPIRE_2)) cmd = "2";
    if(isKeyPressed(KEY_NSPIRE_3)) cmd = "3";
    if(isKeyPressed(KEY_NSPIRE_4)) cmd = "4";
    if(isKeyPressed(KEY_NSPIRE_5)) cmd = "5";
    if(isKeyPressed(KEY_NSPIRE_6)) cmd = "6";
    if(isKeyPressed(KEY_NSPIRE_7)) cmd = "7";
    if(isKeyPressed(KEY_NSPIRE_8)) cmd = "8";
    if(isKeyPressed(KEY_NSPIRE_9)) cmd = "9";
    if(isKeyPressed(KEY_NSPIRE_A)) cmd = "A";
    if(isKeyPressed(KEY_NSPIRE_B)) cmd = "B";
    if(isKeyPressed(KEY_NSPIRE_C)) cmd = "C";
    if(isKeyPressed(KEY_NSPIRE_D)) cmd = "D";
    if(isKeyPressed(KEY_NSPIRE_E)) cmd = "E";
    if(isKeyPressed(KEY_NSPIRE_F)) cmd = "F";
    if(isKeyPressed(KEY_NSPIRE_G)) cmd = "G";
    if(isKeyPressed(KEY_NSPIRE_H)) cmd = "H";
    if(isKeyPressed(KEY_NSPIRE_I)) cmd = "I";
    if(isKeyPressed(KEY_NSPIRE_J)) cmd = "J";
    if(isKeyPressed(KEY_NSPIRE_K)) cmd = "K";
    if(isKeyPressed(KEY_NSPIRE_L)) cmd = "L";
    if(isKeyPressed(KEY_NSPIRE_M)) cmd = "M";
    if(isKeyPressed(KEY_NSPIRE_N)) cmd = "N";
    if(isKeyPressed(KEY_NSPIRE_O)) cmd = "O";
    if(isKeyPressed(KEY_NSPIRE_P)) cmd = "P";
    if(isKeyPressed(KEY_NSPIRE_Q)) cmd = "Q";
    if(isKeyPressed(KEY_NSPIRE_R)) cmd = "R";
    if(isKeyPressed(KEY_NSPIRE_S)) cmd = "S";
    if(isKeyPressed(KEY_NSPIRE_T)) cmd = "T";
    if(isKeyPressed(KEY_NSPIRE_U)) cmd = "U";
    if(isKeyPressed(KEY_NSPIRE_V)) cmd = "V";
    if(isKeyPressed(KEY_NSPIRE_W)) cmd = "W";
    if(isKeyPressed(KEY_NSPIRE_X)) cmd = "X";
    if(isKeyPressed(KEY_NSPIRE_Y)) cmd = "Y";
    if(isKeyPressed(KEY_NSPIRE_Z)) cmd = "Z";
    if(isKeyPressed(KEY_NSPIRE_ESC)) cmd = "ESC";
    if(isKeyPressed(KEY_NSPIRE_DEL)) cmd = "DEL";
    if(isKeyPressed(KEY_NSPIRE_ENTER)) cmd = "ENT";
    if(isKeyPressed(KEY_NSPIRE_RET)) cmd = "RET";
    if(isKeyPressed(KEY_NSPIRE_SPACE)) cmd = " ";
    if(isKeyPressed(KEY_NSPIRE_NEGATIVE)) cmd = "-";
    if(isKeyPressed(KEY_NSPIRE_PERIOD)) cmd = ".";
    if(isKeyPressed(KEY_NSPIRE_THETA)) cmd = "THETA";
    if(isKeyPressed(KEY_NSPIRE_COMMA)) cmd = ",";
    if(isKeyPressed(KEY_NSPIRE_PLUS)) cmd = "+";
    if(isKeyPressed(KEY_NSPIRE_eEXP)) cmd = "eEXP";
    if(isKeyPressed(KEY_NSPIRE_PI)) cmd = "PI";
    if(isKeyPressed(KEY_NSPIRE_QUES)) cmd = "QUES";
    if(isKeyPressed(KEY_NSPIRE_QUESEXCL)) cmd = "QUESEXCL";
    if(isKeyPressed(KEY_NSPIRE_MINUS)) cmd = "-";
    if(isKeyPressed(KEY_NSPIRE_TENX)) cmd = "TENX";
    if(isKeyPressed(KEY_NSPIRE_EE)) cmd = "EE";
    if(isKeyPressed(KEY_NSPIRE_COLON)) cmd = ":";
    if(isKeyPressed(KEY_NSPIRE_MULTIPLY)) cmd = "*";
    if(isKeyPressed(KEY_NSPIRE_SQU)) cmd = "SQU";
    if(isKeyPressed(KEY_NSPIRE_II)) cmd = "II";
    if(isKeyPressed(KEY_NSPIRE_QUOTE)) cmd = "\"";
    if(isKeyPressed(KEY_NSPIRE_DIVIDE)) cmd = "/";
    if(isKeyPressed(KEY_NSPIRE_TAN)) cmd = "TAN";
    if(isKeyPressed(KEY_NSPIRE_COS)) cmd = "COS";
    if(isKeyPressed(KEY_NSPIRE_SIN)) cmd = "SIN";
    if(isKeyPressed(KEY_NSPIRE_EXP)) cmd = "EXP";
    if(isKeyPressed(KEY_NSPIRE_GTHAN)) cmd = ">";
    if(isKeyPressed(KEY_NSPIRE_APOSTROPHE)) cmd = "'";
    if(isKeyPressed(KEY_NSPIRE_CAT)) cmd = "CAT";
    if(isKeyPressed(KEY_NSPIRE_FRAC)) cmd = "FRAC";
    if(isKeyPressed(KEY_NSPIRE_RP)) cmd = "RP";
    if(isKeyPressed(KEY_NSPIRE_LP)) cmd = "LP";
    if(isKeyPressed(KEY_NSPIRE_VAR)) cmd = "VAR";
    if(isKeyPressed(KEY_NSPIRE_DEL)) cmd = "DEL";
    if(isKeyPressed(KEY_NSPIRE_LTHAN)) cmd = "<";
    if(isKeyPressed(KEY_NSPIRE_FLAG)){ cmd = "FLAG";quit=true;}
    if(isKeyPressed(KEY_NSPIRE_CLICK)) cmd = "CLICK";
    if(isKeyPressed(KEY_NSPIRE_HOME)) cmd = "HOME";
    if(isKeyPressed(KEY_NSPIRE_MENU)) cmd = "MENU";
    if(isKeyPressed(KEY_NSPIRE_BAR)) cmd = "BAR";
    if(isKeyPressed(KEY_NSPIRE_TAB)) cmd = "TAB";
    if(isKeyPressed(KEY_NSPIRE_EQU)) cmd = "EQU";
    if(isKeyPressed(KEY_NSPIRE_UP)) cmd = "UP";
    if(isKeyPressed(KEY_NSPIRE_UPRIGHT)) cmd = "UPRIGHT";
    if(isKeyPressed(KEY_NSPIRE_RIGHT)) cmd = "RIGHT";
    if(isKeyPressed(KEY_NSPIRE_RIGHTDOWN)) cmd = "RIGHTDOWN";
    if(isKeyPressed(KEY_NSPIRE_DOWN)) cmd = "DOWN";
    if(isKeyPressed(KEY_NSPIRE_DOWNLEFT)) cmd = "DOWNLEFT";
    if(isKeyPressed(KEY_NSPIRE_LEFT)) cmd = "LEFT";
    if(isKeyPressed(KEY_NSPIRE_LEFTUP)) cmd = "LEFTUP";
    if(isKeyPressed(KEY_NSPIRE_SHIFT)) cmd = "SHIFT";
    if(isKeyPressed(KEY_NSPIRE_CTRL)) cmd = "CTRL";
    if(isKeyPressed(KEY_NSPIRE_DOC)) cmd = "DOC";
    if(isKeyPressed(KEY_NSPIRE_TRIG)) cmd = "TRIG";
    if(isKeyPressed(KEY_NSPIRE_SCRATCHPAD)) cmd = "SCRPAD";

    uart_puts(cmd);
    uart_puts("!");
}

int main(int argc, char* argv[]){

    if(argc < 1) return 0;
    cmd = "URTX";
    uart_puts(cmd);
    uart_puts("!");
    while(!quit){
        while(!any_key_pressed()){
        }
        pushButton();
    }
    return 0;
}



Re: Ndless KeyListener

Unread postPosted: 06 May 2016, 10:49
by Ti64CLi++
Bonjour,
Avec quoi compiles-tu ton code? Sous Linux ou sous Windows?

Re: Ndless KeyListener

Unread postPosted: 06 May 2016, 11:17
by Vogtinator
It sends the "URTX" message and then the calculator freezes, but I do know the program is running because when I press the flag button (the button that terminates the outer while loop in my main method) then the calculator goes back to normal.


Of course, the nspire doesn't do anything else than your loop as Ndless apps aren't multithreaded by default.
You have two options here, either add a hook somewhere in the OS or start a new thread with the OS's TCC_Create_Task function, currently not exposed by ndless as not quite stable.

nClock and zLock both use the first approach, hooking the OS's code at a place that is regularily executed.
For nClock, search for "hook_nclock" in nclock.c and you'll find everything necessary to get it running.

If you want to go the second route, I made a PoC with multithreading on https://www.omnimaga.org/ti-nspire-proj ... #msg398134
You can find the addresses for other OS's in the ndless sdk (https://github.com/ndless-nspire/Ndless ... scalls/idc).

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 06:50
by MishaShapo
Hi, Vogtinator, thank you for the reply. I see that I have to use the hooks system you mentioned. I also read through another forum post on this same topic where you explained hooks https://www.omnimaga.org/calculator-c-language/ndless-hooking-tutorial-(especially-key-hooks) . I think that I understand the concept I am just having trouble finding the hook addresses. You said on that other forum that I would have to use the firebird debugger, and if that's the case, then I still have some learning to do. I am also a little confused on the difference between a hook, an interrupt, and a syscall. Could you please give me a rough idea of the difference between them? Or do you want me to make another topic for that question?

Thanks again for replying. :)

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 10:21
by Vogtinator
You may be able to reuse the nClock hook. I don't know how often it is called though.

I am also a little confused on the difference between a hook, an interrupt, and a syscall. Could you please give me a rough idea of the difference between them?

A hook is a modification of running code at strategic places to make it call your code.
An interrupt (IRQ/FIQ) is a signal from the hardware which causes the CPU to jump to a specific address (0x18/0x1C on ARM).
A syscall is also called a software interrupt (SWI), as it is like a hardware interrupt, just caused by software (0x08 on ARM).
Ndless programs use SWIs to make calls to ndless and the OS.

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 16:45
by MishaShapo
Vogtinator, I tried to use the nClock hooks, but it did not fire regularly. How would I go about finding the OS's key interrupt handler as you said in the other forum post? I know it has to do with assembly and using the firebird debugger. But I am new to GDB and assembly in general. But if there are any resources that I should read/watch I will do that. Thanks for helping me with this. Its a project for a teacher of mine, and I really want to get it to her before the school year ends, so I appreciate you helping me with this. :)

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 17:52
by Vogtinator
Finding that is quite easy, by printing the PC during reads of the keypad. Just tell me which OS and I'll find it.

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 18:21
by MishaShapo
I will be using TI-Nspire CX (both CAS and non-CAS) with Ndless 4.2. Also, what do you mean "PC"? Thank you so much!!

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 18:36
by Vogtinator
PC is the program counter. The pointer to the current instruction.
You should be able to hook 0x10069ce0 on CX CAS and 0x1006A220 on CX.

Re: Ndless KeyListener

Unread postPosted: 07 May 2016, 19:20
by MishaShapo
Hi, Vogtinator, the hooks work! But sadly not for the touchpad and it has crashed once with this error:

Code: Select all
Warning (110ee3a0): Bad write_word: 90020018 00180018
Error (110ee3c4): LDRD/STRD with odd-numbered data register

Would it be possible to find the hook for the touchpad as well? If not, I can make this work. :)

EDIT: I've noticed the error occurs when the calculator wakes up from sleep.