ev3 BCC/C: plugged USB keyboard as an input/ stdin device?

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
Post Reply
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

ev3 BCC/C: plugged USB keyboard as an input/ stdin device?

Post by HaWe »

hey,
how can I use a USB keyboard plugged to the ev3 master USB port as a stdin device?
My program is currently not working.
What I'm trying is the following - is there maybe just a mistake by using pointers or is a USB keyboard device driver missing for Lego Linux ?

edit - now completely new from scratch:

Code: Select all

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "lms2012.h"
#include "ev3_button.h"
#include "ev3_lcd.h"


#define msleep(t) usleep(1000*t)


int main()
{
  char  text[120], tdx;
  int   key, c[120];


  ButtonLedInit();
  LcdInit();
  LcdClean();

  c[0]=32;
  tdx=0;

  while(1)
  {
     LcdClean();

     while((key=getchar())!=10) {     // read input line until [ENTER]

        if((key>31)&&(key<128)) {     // printable kbd code
           c[tdx]=key;
           text[tdx]=(char)key;       // character to text string
           LcdText(1, 0, 10, text) ;  // no autom. echo on screen
        }

        tdx++;                        // text buffer counter
     }

     if(ButtonWaitForAnyPress(100) == BUTTON_ID_ESCAPE)
         break;
     msleep(5);
  }


  LcdExit();
  ButtonLedExit();
  return 1;
}
(now the lcd is cleared, but then the ev3 hangs up, no reaction to USB kbd press, batteries have to be removed)
Last edited by HaWe on 23 Jan 2014, 17:40, edited 1 time in total.
mightor
Site Admin
Posts: 1079
Joined: 25 Sep 2010, 15:02
Location: Rotterdam, Netherlands
Contact:

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by mightor »

This as much effort as I can put into this. It works on my Ubuntu Linux VM and it should work with an EV3 brick. Experiment with the /dev/input/event<number>. You may need to use 0 or 1 or maybe even 2, I don't know. Play with it.

Taken and adapted from http://rico-studio.com/linux/read-and-w ... rd-device/

Code: Select all

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#define EV_PRESSED 1
#define EV_RELEASED 0
#define EV_REPEAT 2

void main()
{
  int fd = 0;
  // Not sure if this has to be event0 or event1 on the EV3
  char *device = "/dev/input/event1";
  struct input_event event;
  unsigned int scan_code = 0;

  if( (fd = open(device, O_RDWR)) > 0 )
  {
    while (1 == 1)
    {
      int num_bytes = read(fd, &event, sizeof(struct input_event));
      if(event.type != EV_KEY)
           continue;

      if(event.value == EV_RELEASED)
      {
           // This is the key that is pressed.
           // To see which code means which key, take a look here:
           // http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/input.h?v=2.6.11.8
           // Use an array to map this value to the real character, should be trivial using the info in the link above.
           scan_code = event.code;
           printf("code: %d\n", scan_code);

      }
    }
  }
  else
  {
    fprintf(stderr, "Could not open keyboard device!\n");
  }
}
= Xander
| My Blog: I'd Rather Be Building Robots (http://botbench.com)
| RobotC 3rd Party Driver Suite: (http://rdpartyrobotcdr.sourceforge.net)
| Some people, when confronted with a problem, think, "I know, I'll use threads,"
| and then two they hav erpoblesms. (@nedbat)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by HaWe »

thank you,
now this one was actually really useful.

As a small contribution from me in return, here's the code to read keys by their ASCII value from a USB keyboard plugged to the EV3 -
Numpad numbers are working , shift and capslock is working, but shift is a little shaky because 2 keys are read shortly behind one another
(different from common PC kbd scancodes - no idea how to poll if 2 keys are pressed simultaneously).

the keys are for German kbd layout (QWERTZ),
for different layouts you'll have to change the characters of the letter QWERTZ[] string accordingly
(maybe copy QWERTZ[] to QWERTY[] and overwrite the entries).

initialize by init_USBkbd()
function call by
int key=getcharUSB();
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by HaWe »

there is a bug I cannot fix:

if I print the whole string to which the key is added then there is always a
\
at the 1st position.
e.g., if I enter
1234
it is shown
\1234

2nd problem:
in the line
(event.type != EV_KEY) ...
what is EV_KEY? it's no where been declared AFAIK...?

3rd problem:
at the first call the function appears not to wait for a keypress but runs through,
it just then waits for the 2nd, 3rd, 4th keypress and so on
(what maybe is the reason for the odd output).


what is wrong?

Code: Select all


// read letters from USB keyboard plugged to EV3
// readkeys.c
// ver. 1.02
// read USB kbd keys by: int getcharUSB()
//
// credits to Xander Soldaat
// reference:
// http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/input.h?v=2.6.11.8

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/input.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

//#include "lms2012.h"                 // still shaky because of re-definitions
#include "ev3_button.h"
#include "ev3_lcd.h"

#define cls()     LcdClean()        // more C-like
#define mline     118               // line for status msg


//..............................................................................
// USB kbd device
//..............................................................................

#define EV_PRESSED  1
#define EV_RELEASED 0
#define EV_REPEAT   2

// QWERTZ = German kbd layout representation
// uppercase overhead = 128

char QWERTZ[]=    "  1234567890-=  qwertzuiopü+  asdfghjklöä# <yxcvbnm,.- *               789-456+1230,                                                !'§$%&/()=?`  QWERTZUIOPÜ*  ASDFGHJKLÖÄ' >YXCVBNM;:_......";

#define KEY_UPPEROVHD        130    // uppercase overhead = 128
#define KEY_LEFTSHIFT         42    // kbd keycode
#define KEY_RIGHTSHIFT        54    // kbd keycode
#define KEY_CAPSLOCK          58    // kbd keycode


int     _kbd_fd_;                   // kbd file dev handle
//..............................................................................

char init_USBkbd() {
   char *device = "/dev/input/event0";    // event1: hangs up after cls
   _kbd_fd_ = 0;
   if ( (_kbd_fd_ = open(device, O_RDWR)) > 0 ) return 1;
   else  return 0;

}

//..............................................................................

int getcharUSB() {
  struct  input_event event;
  int     keycode;
  char    buf[10];
  int     retval;
  static int     UPCASE;
  static char    LEFTSHIFTTMP;
  int    num_bytes;


  while (event.type != EV_KEY) {
    num_bytes = read(_kbd_fd_, &event, sizeof(struct input_event));
  }

  if(event.value == EV_RELEASED)
  {
    keycode = event.code;

    if(keycode==KEY_CAPSLOCK)    {
      UPCASE=(UPCASE==0)?KEY_UPPEROVHD:0;
      return 0;
    }
    else
    {
                                                 // SHIFT for uppercase
      if ( (keycode==KEY_LEFTSHIFT)||(keycode==KEY_RIGHTSHIFT) )  {
        UPCASE=(UPCASE==0)?KEY_UPPEROVHD:0;             // (still shaky)
        LEFTSHIFTTMP=1;
        return 0;
      }


      if(keycode== 1) retval=27;                      // KEY_ESCAPE
      else
      if( (keycode==28)||(keycode==96) ) retval=10;   // KEY_ENTER
      else
      if(keycode==14) retval=8;                       // KEY_BACKSPACE
      else
      retval= QWERTZ[keycode+UPCASE] ;
      if (LEFTSHIFTTMP) {                             // SHIFT for uppercase
        LEFTSHIFTTMP=0;
        UPCASE=(UPCASE==0)?KEY_UPPEROVHD:0;           // (still shaky)
      }

      // debug:
      //sprintf(buf,"keycode:%3d ASCII:%3d", keycode,retval);  LcdText(1, 0,20, buf);
    }
  }

  return ( retval );

}

//..............................................................................
// task main()
// how to initialize and how to call
//..............................................................................

int main()
{

  int   key = 0, i=0;
  char  buf[120], text[120];   // text string


  ButtonLedInit();
  LcdInit();

  cls();

  if (!init_USBkbd()) {
    LcdText(1, 0, mline, "keyboard device error! ");
    Wait(2000);
    goto quit;
  }
  
  LcdText(1, 0, mline, "press keys on keyboard!  ");

  text[0]='\0';
  
  while (1) {
     key=getcharUSB();                   // read kbd kbdkeycode => ASCII code
                                         // now what to do with the key ?
     if (key==27)  goto quit;            // 27 = ESC  => stop program
     else
     if(key>32) {
       // add key to string
       text[i+1]='\0';
       text[i]  =key;
       sprintf(buf,"%c  ", key);
       LcdText(1, 0,10, buf);     // display key
       LcdText(1, 0,40, text);    // display string
       i++;
     }
     Wait(1);
  }



quit:
  LcdText(1, 0, 10,    "                       ");
  LcdText(1, 0, mline, "program terminated     ");
  Wait(500);

  cls();
  Wait(10);
  
  LcdExit();
  ButtonLedExit();

  return 1;
}
mightor
Site Admin
Posts: 1079
Joined: 25 Sep 2010, 15:02
Location: Rotterdam, Netherlands
Contact:

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by mightor »

I don't have the standard firmware on any of my bricks, nor the BCC C library, but the program seems to function just fine for me. I modified to allow me to compile it on my Ubuntu VM. I ran it in one window and typed in another:
Image

EV_KEY is the type of event that a keyboard generates. Did you look in the link I provided in the source code for input.h? It has to be declared, you would get a compile error if it hadn't.

To make your code a bit saner, avoid using gotos and change your keycode if statements to a switch/case block.

My modified code:

Code: Select all

// read letters from USB keyboard plugged to EV3
// readkeys.c
// ver. 1.02
// read USB kbd keys by: int getcharUSB()
//
// credits to Xander Soldaat
// reference:
// http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/input.h?v=2.6.11.8

// #define EV3

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/input.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#ifdef EV3
//#include "lms2012.h"                 // still shaky because of re-definitions
#include "ev3_button.h"
#include "ev3_lcd.h"

#define cls()     LcdClean()        // more C-like
#define mline     118               // line for status msg
#endif


//..............................................................................
// USB kbd device
//..............................................................................

#define EV_PRESSED  1
#define EV_RELEASED 0
#define EV_REPEAT   2

// QWERTZ = German kbd layout representation
// uppercase overhead = 128

char QWERTZ[]=    "  1234567890-=  qwertzuiopü+  asdfghjklöä# <yxcvbnm,.- *               789-456+1230,                                                !'§$%&/()=?`  QWERTZUIOPÜ*  ASDFGHJKLÖÄ' >YXCVBNM;:_......";

#define KEY_UPPEROVHD        130    // uppercase overhead = 128
#define KEY_LEFTSHIFT         42    // kbd keycode
#define KEY_RIGHTSHIFT        54    // kbd keycode
#define KEY_CAPSLOCK          58    // kbd keycode

#ifdef EV3
#define KEYBOARD_DEVNAME             "/dev/input/event0"
#else
#define KEYBOARD_DEVNAME             "/dev/input/event1"
#endif

int     _kbd_fd_;                   // kbd file dev handle
//..............................................................................

char init_USBkbd() {
   char *device = KEYBOARD_DEVNAME;    // event1: hangs up after cls

   _kbd_fd_ = 0;
   if ( (_kbd_fd_ = open(device, O_RDWR)) > 0 ) return 1;
   else  return 0;

}

//..............................................................................

int getcharUSB() {
  struct  input_event event;
  int     keycode;
  char    buf[10];
  int     retval;
  static int     UPCASE;
  static char    LEFTSHIFTTMP;
  int    num_bytes;


  while (event.type != EV_KEY) {
    num_bytes = read(_kbd_fd_, &event, sizeof(struct input_event));
  }

  if(event.value == EV_RELEASED)
  {
    keycode = event.code;

    if(keycode==KEY_CAPSLOCK)    {
      UPCASE=(UPCASE==0)?KEY_UPPEROVHD:0;
      return 0;
    }
    else
    {
                                                 // SHIFT for uppercase
      if ( (keycode==KEY_LEFTSHIFT)||(keycode==KEY_RIGHTSHIFT) )  {
        UPCASE=(UPCASE==0)?KEY_UPPEROVHD:0;             // (still shaky)
        LEFTSHIFTTMP=1;
        return 0;
      }


      if(keycode== 1) retval=27;                      // KEY_ESCAPE
      else
      if( (keycode==28)||(keycode==96) ) retval=10;   // KEY_ENTER
      else
      else
      if(keycode==14) retval=8;                       // KEY_BACKSPACE
      else
      retval= QWERTZ[keycode+UPCASE] ;
      if (LEFTSHIFTTMP) {                             // SHIFT for uppercase
        LEFTSHIFTTMP=0;
        UPCASE=(UPCASE==0)?KEY_UPPEROVHD:0;           // (still shaky)
      }

#ifdef EV3
      // debug:
      //sprintf(buf,"keycode:%3d ASCII:%3d", keycode,retval);  LcdText(1, 0,20, buf);
#else
      fprintf(stderr, "keycode:%3d ASCII:%3d\n", keycode,retval);
#endif
    }
  }

  return ( retval );

}

//..............................................................................
// task main()
// how to initialize and how to call
//..............................................................................

int main()
{

  int   key = 0, i=0;
  char  buf[120], text[120];   // text string


#ifdef EV3
  ButtonLedInit();
  LcdInit();

  cls();
#endif

  if (!init_USBkbd()) {
#ifdef EV3
    LcdText(1, 0, mline, "keyboard device error! ");
    Wait(2000);
#else
    fprintf(stderr, "keyboard device error!\n");
#endif
    goto quit;
  }

#ifdef EV3
  LcdText(1, 0, mline, "press keys on keyboard!  ");
#else
  printf("Press keys on keyboard!\n");
#endif

  text[0]='\0';

  while (1) {
     key=getcharUSB();                   // read kbd kbdkeycode => ASCII code
                                         // now what to do with the key ?
     if (key==27)  goto quit;            // 27 = ESC  => stop program
     else
     if(key>32) {
       // add key to string
       text[i+1]='\0';
       text[i]  =key;
       sprintf(buf,"%c  ", key);
#ifdef EV3
       LcdText(1, 0,10, buf);     // display key
       LcdText(1, 0,40, text);    // display string
#else
       printf("buf: %s, text: %s\n", buf, text);
#endif

       i++;
     }
#ifdef EV3
     Wait(1);
#else
     sleep(1);
#endif
  }



// Using a goto is a big nono if you can solve the issue
// with a simple function call.  This is nasty.
quit:
#ifdef EV3
  LcdText(1, 0, 10,    "                       ");
  LcdText(1, 0, mline, "program terminated     ");
  Wait(500);

  cls();
  Wait(10);

  LcdExit();
  ButtonLedExit();
#else
  fprintf(stderr, "Program terminated\n");
#endif

  return 1;
}
| My Blog: I'd Rather Be Building Robots (http://botbench.com)
| RobotC 3rd Party Driver Suite: (http://rdpartyrobotcdr.sourceforge.net)
| Some people, when confronted with a problem, think, "I know, I'll use threads,"
| and then two they hav erpoblesms. (@nedbat)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by HaWe »

thank you for your efforts!
but strangly the problem remains:
on the ev3 screen the text string is always displayed with a leading "\".
There must be issues about the string handling or the string out function - but I have no idea what's faulty.

edit:
indeed lcdline seems not to be able to display the string correctly:

LcdText(1, 0,40, text); // display string // always a leading \
sprintf(buf, text); LcdText(1, 0,40, buf); // display string // no output at all
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by HaWe »

update:
Now it just displays the key but doesn't display the combined string any longer at all.
But as it works with Xander's konsole version as expected, there must be severe bugs in John's lcd header, epecially to display strings on the lcd
(but also LcdClean is bugged).

:evil:

Code: Select all

// read letters from USB keyboard plugged to EV3
// kbdUSB.c
// ver. 1.04
// read USB kbd keys by: int getcharUSB()
//
// credits to Xander Soldaat
// reference:
// http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/input.h?v=2.6.11.8

// define EV3

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/input.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>


#include "ev3_button.h"
#include "ev3_lcd.h"

#define cls()     LcdClean()        // more C-like
#define mline     118               // line for status msg



//..............................................................................
// USB kbd device
//..............................................................................

#define EV_PRESSED  1
#define EV_RELEASED 0
#define EV_REPEAT   2

// QWERTZ = German kbd layout representation
// diphthongs/umlaut diacritics  äÄ,öÖ,üÜ,ß, and accents ´` not displayable; patch for ß=\ ü=| ö=[ ä=] Ü=~ Ö={ Ä=}  `=@

char QWERTZ[]=    "  1234567890\\@  qwertzuiop|+  asdfghjkl[]  #yxcvbnm,.- *               789-456+1230,  <                                             !'§$%&/()=?@  QWERTZUIOP~*  ASDFGHJKL{}  'YXCVBNM;:_                                > ";


#define CAPSSTROVHD          130    // uppercase overhead in QWERTZ string
#define KEY_LEFTSHIFT         42    // kbd keycode
#define KEY_RIGHTSHIFT        54    // kbd keycode
#define KEY_CAPSLOCK          58    // kbd keycode


#define KEYBOARD_DEVNAME     "/dev/input/event0"


int     _kbd_fd_;                      // kbd file dev handle
//..............................................................................

char init_USBkbd() {
   char *device = KEYBOARD_DEVNAME;    // event1: hangs up after cls

   _kbd_fd_ = 0;
   if ( (_kbd_fd_ = open(device, O_RDWR)) > 0 ) return 1;
   else  return 0;

}

//..............................................................................

int getcharUSB() {
  struct  input_event event;
  int     keycode;
  char    buf[10];
  int     retval;
  static int     UPCASE;
  static char    SHIFTTMP;
  int    num_bytes;


  while (event.type != EV_KEY) {
    num_bytes = read(_kbd_fd_, &event, sizeof(struct input_event));
  }

  if(event.value == EV_RELEASED)
  {
    keycode = event.code;

    if(keycode==KEY_CAPSLOCK)    {
      UPCASE=(UPCASE==0)?CAPSSTROVHD:0;
      return 0;
    }
    else
    {
                                                 // SHIFT for uppercase
      if ( (keycode==KEY_LEFTSHIFT)||(keycode==KEY_RIGHTSHIFT) )
      {
        UPCASE=(UPCASE==0)?CAPSSTROVHD:0;             // (still shaky)
        SHIFTTMP=1;
        return 0;
      }


      if(keycode== 1) retval=27;                      // KEY_ESCAPE
      else
      if( (keycode==28)||(keycode==96) ) retval=10;   // KEY_ENTER left/right
      else
      if(keycode==14) retval=8;                       // KEY_BACKSPACE
      else
      retval= QWERTZ[keycode+UPCASE] ;
      if (SHIFTTMP) {                             // SHIFT for uppercase
        SHIFTTMP=0;
        UPCASE=(UPCASE==0)?CAPSSTROVHD:0;             // (still shaky)
      }

      // debug:
      sprintf(buf,"keycode:%3d ASCII:%3d", keycode,retval);  LcdText(1, 0,20, buf);

    }
  }

  return ( retval );

}

//..............................................................................
// task main()
// how to initialize and how to call
//..............................................................................

int main()
{

  int   key = 0, ci=0;
  char  buf[20], text[120];   // text string


  ButtonLedInit();
  LcdInit();

  cls();

  if (!init_USBkbd()) {
    sprintf(buf,"keyboard device error! ");  LcdText(1, 0, mline, buf);
    Wait(2000);

    goto quit;
  }

  sprintf(buf,"press kbd keys!   ");  LcdText(1, 0, mline, buf);

  text[0]='\0';

  while (1) {
                                         // wait for key-press on keyboard
     key=getcharUSB();                   // read kbd kbdkeycode => ASCII code
                                         // wait for key-up
     
                           // now what to do with the key ?
                                         
     if (key==27)  goto quit;            // 27 = ESC  => stop program
     else
     if(key>31) {                        // printable key

       text[ci]  =key;                   // add key to string (char array)
       text[ci+1]='\0';                  // null-terminated string

       sprintf(buf,"%c  ", key);         // display key numbers as letters
       LcdText(1, 0,10, buf);
                                         // display string
       LcdText(1, 0,40, text);           // <<<<<<<<<<< BUG !!! Not executed!

       ci++;
     }

     Wait(1);
  }


quit:

  cls();
  LcdText(1, 0, mline, "program terminated    ");
  Wait(500);
  cls();                                 // <<<<<<<<<<< BUG !!! Not executed!
  Wait(10);

  LcdExit();
  ButtonLedExit();


  return 1;
}
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: ev3 BCC/C: plugged USB keyboard as a stdin device?

Post by HaWe »

I tried to make it run, but no chance -
although the keys are read correctly from keyboard I can't make BCC/C add them to a string and display the string on the screen.

If we only could use the C-functions like getchar, gets (with screen-echo) and also printf like by stdio.h in a console !
I guess I must give up.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest