Writing a getln() function

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
srg_13

Writing a getln() function

Post 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
Rob

Re:Writing a getln() function

Post 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.
srg_13

Re:Writing a getln() function

Post 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
RetainSoftware

Re:Writing a getln() function

Post 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 ;)
srg_13

Re:Writing a getln() function

Post 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
Rob

Re:Writing a getln() function

Post by Rob »

again, have you tried defining done as volatile?

volatile int done;
srg_13

Re:Writing a getln() function

Post 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
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Writing a getln() function

Post 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...
Every good solution is obvious once you've found it.
srg_13

Re:Writing a getln() function

Post 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]
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Writing a getln() function

Post 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?
Every good solution is obvious once you've found it.
RetainSoftware

Re:Writing a getln() function

Post 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
Rob

Re:Writing a getln() function

Post by Rob »

RetainSoft: perhaps I should put a loop around that? ;)
paulbarker

Re:Writing a getln() function

Post by paulbarker »

Code: Select all

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

finish_project();    /* never reached */
RetainSoftware

Re:Writing a getln() function

Post by RetainSoftware »

exactly os development projects never finish does the code example is perfect!! ;)
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Writing a getln() function

Post 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)
Every good solution is obvious once you've found it.
Post Reply