Page 1 of 1

Writing a getln() function

Posted: Sat Mar 18, 2006 9:04 pm
by srg_13
I am trying to write a getln() function to read keyboard input until the user presses enter, and then return what was entered. I am having some difficulty, since my keyboard driver uses interrupts. This is some psudeo code (except the keyboard handler part is real) of what I am trying to do:

Code: Select all

void keyboard_handler() // called by kb IRQ
{
    unsigned char scancode;

    // Read from the keyboard's data buffer
    scancode = inportb(0x60);

    if (scancode & 0x80)
    {
                // check if shift is released
      if(scancode == 0xaa) {shift = 0;}
    }
    else
    {   

      switch(scancode)
      {
         case 58 :   toggle_caps();
                  break;
         case 42 :   shift = 1;
                  break;
         case 54 :   shift = 1;
                  break;
         case 14 :   backspace();
                  break;
         default :   kb_getln(scancode);

      }
        
    }

}

int kbd = 0;
int done = 0;

char string[200];
int num;

void kb_getln(unsigned char scancode) // called by keyboard handler
{
    if(kbd == 0)
    {
        die(); // does C have a die() function?
    }

    if(scancode == 28) // If enter is pressed
    {
         done = 1; // signal that we are finished
    }
    else
    {
         print_character(scancode); // print the character
         string[num] = keyboard[scancode]; // look up in table
         num++; // increment number
    }
}

char getln() // called by user
{
    kbd = 1;
    done = 0;
    num = 0;

    while(done==0) // wait until done
    {
         __asm__ __volatile__("hlt");
    }

    return string;

    kbd = 0;
}
Am I on the right track? There is probably a better (and shorter) way to write this, right? I know that I'd also have to compensate for backspace, and arrow keys etc.

-Stephen

Re:Writing a getln() function

Posted: Sun Mar 19, 2006 5:37 am
by Rob
The variable done will at least need the volatile keyword if I understand what you are doing. Otherwise the interrupt routine will change it and the read routing will not (re-)read it.

Re:Writing a getln() function

Posted: Mon Mar 20, 2006 1:56 am
by srg_13
Well, I've tried to write it like this, but the loop never seems to end. Is there something i need to change to make it end when done = 1? Is there any better ways of doing this??

This is the code I am using:

Code: Select all

void keyboard_handler(struct regs *r) // This function is called whenever the keyboard interrupt fires.
{
    unsigned char scancode;


    scancode = inportb(0x60); 


    if (scancode & 0x80)
    {

      if(scancode == 0xaa) {shift = 0;} // See if shift has been released
    }
    else
    {   

      switch(scancode)
      {
         case 58 :   toggle_caps();
                  break;
         case 42 :   shift = 1; // Left shift
                  break;
         case 54 :   shift = 1; // right shift
                  break;
         default :   k_getln(scancode);
                  break;

      }
        
    }
}

char key(unsigned char scancode) // Returns an ASCII character for a scancode.
{
   char c;
   
   if(caps == 1)
   {
      if(shift == 1)
      {
         c = kbdcapshift[scancode];
      }
      else
      {
         c = kbdcaps[scancode];
      }
   }
   else
   {
      if(shift ==1)
      {
         c = kbdshift[scancode];
      }
      else
      {
         c = kbdus[scancode];
      }
   }

   return c;
}

void toggle_caps() // Turn caps on/off
{
   if(caps == 1)
   {
      caps = 0;
   }
   else
   {
      caps = 1;
   }
}

char kb_buffer[150];
int kb_num;

void k_getln(unsigned char scancode)
{
   char a;
   
   if(kb_status == 1)
   {
      switch(scancode)
      {
         case 28 :   done = 1;
                  puts(" e "); // Just to see if it picks up that enter has been pressed.
                  kb_num = kb_num + 3;
                  break;

         case 14 :   if(kb_num>=1)
                  {
                     kb_num--;
                     kb_buffer[kb_num] = 0;
                     puts("\b \b");
                  }
                  break;

         default :   a = key(scancode);
                  putch(a);
                  kb_buffer[kb_num] = a; 
                  kb_num++;
                  break;
      }
   }
}

char getln()  // this is what the user calls
{
   
   kb_status = 1;
   
    while(done!=1) // wait until kg_getln() is finished.
    {
        __asm__ __volatile__("hlt");
    }

   done = 0;

   kb_status = 0;

   return kb_buffer;
}
It does print "e" when enter is pressed, but the loop in getln() does not end...

Thanks,

-Stephen

Re:Writing a getln() function

Posted: Mon Mar 20, 2006 4:09 am
by RetainSoftware

Code: Select all

char getln() // called by user
{
    kbd = 1;
    done = 0;
    num = 0;
    while(done==0) // wait until done
    {
        __asm__ __volatile__("hlt");
    }
    return string;
    kbd = 0;
}
dude, don't wanna be rude but basic programming skills would point out that kbd will never be set to 0 as the code for this is after a return statement. This doesn't solve your poblem though.

and at

Code: Select all

die(); // does C have a die() function?
only if you implement it ;)

Re:Writing a getln() function

Posted: Mon Mar 20, 2006 4:33 am
by srg_13
dude, don't wanna be rude but basic programming skills would point out that kbd will never be set to 0 as the code for this is after a return statement. This doesn't solve your poblem though.
Yeah... Well, I kinda just wrote that code quickly to show what I mean, and I must have accidently put that in the wrong place. The actual code is correct.

-Stephen

Re:Writing a getln() function

Posted: Mon Mar 20, 2006 3:06 pm
by Rob
again, have you tried defining done as volatile?

volatile int done;

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 12:22 am
by srg_13
OK, that worked... But now its not returning properley...

I assume that it is because I am trying to use a character arrary as a char or something.. This is the code I am calling:

Code: Select all

   char command = getln();

   puts("\n\n");
   puts(command);
It does the two new lines, but nothing is printed after that...

How do I fix this?

-Stephen

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 12:46 am
by Solar
puts() expects a [tt]char *[/tt] parameter. Your getln() function only returns a single char, the ASCII value of which puts() will then interpret as pointer...

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 3:16 am
by srg_13
When I make kb_buffer into a pointer, it only returns the last character tyoed. How can I make it return the whole string?

-Stephen

[edit]changed kb_buffer[/edit]

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 4:12 am
by Solar
OK, I dug through your source. (Only had a glimpse at it before.)

1) k_getln() gets a single scancode, so don't call it getln(). I was rather confused for a second.

2) I don't know about your puts() function, but the standard puts() prints a newline after the string, which would pretty much screw up your output (at least in case 14: of k_getln()). If you name a function after a standard function, make 100% sure it behaves identically. Again, I was confused for a while.

3) At some, your constructs could be improved so they don't look as "strange" as they do:

Code: Select all

kb_num--;
kb_buffer[kb_num] = 0;
// better: kb_buffer[--kb_num] = 0;

Code: Select all

kb_buffer[kb_num] = a; 
kb_num++;
// better: kb_buffer[kb_num++] = a;
4) What do you mean "when I make keyboard_buffer into a pointer"? I assume you mean kb_buffer. (Precision, dude!) That already is a pointer. In my post this morning I was talking about the return value of getln(), which should be [tt]char *[/tt] instead of [tt]char[/tt]. Which leads me to

5) Are you sure your C programming skills are up to the task of kernel space programming?

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 5:05 am
by RetainSoftware
judging the questions and the code given i would say nay, but then again if he's agile, willing, dedicated and motivated enough he might become good enough to start kernel programming.

I started learning c when i wrote my first low-level VGA program at the fine age of 12, though it took me some years to master the language completely. Reading books wasn't my best quality back then. Well back to the subject...

Steve make sure you know enough C/C++ and assembly(when needed) because os development is hard and frustrating enough even for us *senior* developers. As one of the members says: think, read, think, do though i think it needs more itterations of read and think.

be cool

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 5:49 am
by Rob
RetainSoft: perhaps I should put a loop around that? ;)

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 6:34 am
by paulbarker

Code: Select all

while (1) {
    think();
    read();
    think();
    write_code();
}

finish_project();    /* never reached */

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 8:40 am
by RetainSoftware
exactly os development projects never finish does the code example is perfect!! ;)

Re:Writing a getln() function

Posted: Tue Mar 21, 2006 8:44 am
by Solar
Hm... modified this for Open Source Software (note Emacs indenting ;D ):

Code: Select all

while (1)
  {
    write_code();
    think();
    read();
    think();
    if ( fed_up() || too_difficult() ) break;
  }
call_finished();
abandon();
Sorry. 8)