Part13. Tutorial1-프레임워크에 기능을 추가해 보자

원문 :  http://kkamagui.springnote.com/pages/353530

 

들어가기 전에...

 

0.시작하면서...

 프레임워크를 컴파일-링크해서 이미지를 만든 다음 Virtual Box로 실행하면 까마귀 프레임워크가 시작되었다는 말과 함께 아래에 Edge Task가 돌면서 우측 상단에는 타이머 인터럽트(붉은 색으로 계속 화면에 바뀌어 찍히는 것)가 발생되고 있는 것을 볼 수 있다.

 프레임워크_처음_화면.PNG

<프레임워크 실행화면>

 

1.키 입력 및 메시지 출력

 자 그럼 이제 프레임워크에 본격적으로 기능을 몇가지 추가해 보자. 일단 아래에서 돌고 있는 태스크는 무시하고 프레임워크 시작 시에 키 입력을 대기하고 키 입력이 되면 커널 쉘 기능과 태스크를 실행하도록 해보자.

 일단 키 입력을 받아야 하는데, 참고. 프레임워크 주요 함수들의 새창으로 띄워서 보면 키 입력에 관련된 함수를 볼 수 있다. 잘 살펴보면 kGetCh() 라는 함수가 있는데, 이 함수를 이용하면 키를 얻어올 수 있다. 이를 이용해서 키 입력을 대기하였다가 키가 입력이 되면 그 키 값을 화면에 표시하고 정상적으로 쉘과 태스크를 실행하도록 수정해 보자.

 프레임워크 엔트리(void FrameWorkEntry( void )) 함수가 프레임워크에서 처음으로 불리는 함수 이므로 이 부분을 수정하면 된다.

  1. 파일명 : Custom/Framework.c
  2. void FrameWorkEntry( void )
    {
        BYTE bCh;
  3.     // 인사말을 찍는다.
        kPrintxy( 1, 7, "KKAMAGUI OS FrameWork Start" );
  4.     // 키 입력을 대기하고 키가 입력되면 키 값을 찍는다.
        kPrintxy( 10, 8, "Wait For Key Input.... Please Input Anythig...");
        bCh = kGetCh();
        kPrintxy( 10, 9, "Your Input Is[ ]" );
        kPrintchxy( 24, 9, bCh );
  5.     // 간단한 쉘 실행
        Shell();
    }

 위의 파란색 부분을 추가한 뒤, makekernel.bat, makeimg.bat를 차례로 실행시키거나 프레임워크 1.0.3 버전 이상 사용자라면 make를 실행하여 커널 이미지(disk.img)를 생성하자. 그후 Virtual Box에서 이미지를 실행하면 아래와 같이 나타난다.

키입력대기.PNG

<키 입력 전>

 대기 메시지를 표시하고 키 입력을 기다리고 있는 화면이다. 우측 상단에는 타이머 인터럽트가 계속해서 발생함을 표시하고 있다.

 아래는 키 A를 입력한 뒤 화면이다. 입력된 키값(a)이 표시되고  커널 쉘과 태스크가 정상적으로 실행 되었음을 알 수 있다.

키입력후.PNG

<키 입력 후>

 

2.커널 쉘(Kernel Shell) 기능 추가

 커널 쉘 파일은 콘솔을 구현하기위해 약간 복잡하게 되어있는데, 기능을 추가하기 전에 중요한 부분을 먼저 살펴보자.

 커널 쉘은 키보드에서 값을 입력받아서 엔터까지를 한 라인으로 보고 라인을 분석하여 명령을 실행하는 구조로 되어있다. 아래 함수는 계속해서 키를 입력받고 엔터가 입력이되면 라인을 분석해서 명령을 실행하는 부분이다.

  1. /**
        Shell을 처리하는 Loop
    */
    void ShellLoop( void )
    {
        BYTE cCh;
        int iBufferIndex;
        char szCommandBuffer[256];
  2.     // 커서를 설정한다.
        kSetCursor( 0, 8 );
        iBufferIndex = 0;
  3.     // 커맨드 라인을 출력한다.
        PrintCommandLine();
  4.     while(1)
        {
            cCh = kGetCh();
  5.         ProcessKeyCode( cCh, szCommandBuffer, &iBufferIndex);
        }
    }
  6. /**
        키의 입력이 있으면 키 코드를 받아서 처리하는 함수
    */
    void ProcessKeyCode( BYTE cCh, char* pcCommandBuffer, int* piBufferIndex )
    {
        // 엔터나 Back space 같은 경우는 버퍼에 넣지 않고 특별하게 처리한다.
        if( ( cCh == KEY_ENTER ) || ( cCh == KEY_BSPACE ) )
        {
            ProcessSpecialKey( cCh, pcCommandBuffer, piBufferIndex );
            return ;
        }
  7.  // 만약 버퍼가 다 차지 않았으면 화면에 찍고 버퍼에 넣는다.
     if( *piBufferIndex < COMMANDBUFFERSIZE )
     {
            pcCommandBuffer[ *piBufferIndex ] = cCh;
            *piBufferIndex = *piBufferIndex + 1;
            kPrintf( "%c", cCh );
     }
     return ;
    }
  8. /**
        특수키에 대한 처리
    */
    void ProcessSpecialKey( BYTE cCh, char* pcCommandBuffer, int* piBufferIndex )
    {
     int iX;
     int iY;
     
     // 만약 리턴이면 스크롤 시켜 본다.
     if( cCh == KEY_ENTER )
     {
      kPrintf( "\n" );
      
      // 버퍼에 든 명령을 실행
      ProcessCommand( pcCommandBuffer, piBufferIndex );
      *piBufferIndex = 0;
      
      // 커맨드라인을 다시 출력한다.
      PrintCommandLine();
     }
     // 만약 백 스페이스 이면 커서를 하나 지우고 뒤로 민다.
     else if( cCh == KEY_BSPACE )
     {
      kGetCursor( &iX, &iY );
      // 버퍼에 데이터가 입력되어 있으면
      // 커서의 위치를 하나 감소하고
      if( *piBufferIndex > 0 )
      {
       if( iX == 0 )
       {
        iX = 79;
        iY = iY - 1;
       }
       else
                {
        iX = iX - 1;
                }
  9.    // 문자를 살짝 지워준다.
       kPrintchxy( iX, iY, ' ' );
       kSetCursor( iX, iY );
       *piBufferIndex = *piBufferIndex - 1;
      }
     }
    }
  10. /**
        엔터가 쳐졌으면 버퍼의 내용으로 명령어를 처리한다.
    */
    void ProcessCommand(char* vcCommandBuffer, int* piBufferIndex)
    {
        char vcDwordBuffer[ 8 ];
        static DWORD vdwValue[ 10 ];
        static int iCount = 0;
  11.     // 화면 지우는 함수
        if( ( *piBufferIndex == 3 ) &&
            ( kMemCmp( vcCommandBuffer, "cls", 3 ) == 0 ) )
        {
    kClearScreen();
        }
    }

 위에서 중요한 부분은 파란색으로 굵게 표시를 했다. 파란색 표시를 죽 따라가면 대충 어떻게 동작하는지에 대해서 알 수 있으므로 자세한 설명은 생략하고, 우리가 기능을 추가하려면 어디를 고쳐야 하는지 알아보자. 위에 붉은 색으로 따로 표시된 ProcessCommand()라는 함수가 있다.

 이 함수의 아래를 보면 Clear Screen(cls) 명령에 대한 처리가 되어있음을 알 수 있다. 라인에 입력된 키 값이 3개이고 그 값이 "cls" 인가를 비교해서 화면을 지우는 간단한 코드이다. 뭔가 감이오지 않는가? 그렇다. 저 곳에 함수를 추가하면 된다.

 자~ 그럼 메모리 총량을 표시하는 "showmem" 이라는 명령을 추가해 보자. 메모리 총량은 참고. 프레임워크 주요 함수들에 보면 kGetTotalRAMSize()라는 함수로 구현되어있다. 이제 명령라인을 추가할 때다.

  1. /**
        엔터가 쳐졌으면 버퍼의 내용으로 명령어를 처리한다.
    */
    void ProcessCommand(char* vcCommandBuffer, int* piBufferIndex)
    {
        char vcDwordBuffer[ 8 ];
        static DWORD vdwValue[ 10 ];
        static int iCount = 0;
  2.     // 화면 지우는 함수
        if( ( *piBufferIndex == 3 ) &&
            ( kMemCmp( vcCommandBuffer, "cls", 3 ) == 0 ) )
        {
            kClearScreen();
        }
        // 메모리의 정보를 표시한다.
        else if( ( *piBufferIndex == 7 ) &&
                 ( kMemCmp( vcCommandBuffer, "showmem", 7 ) == 0 ) )
        {
            kPrintf( "%X\n", kGetTotalRAMSize() );
        }
    }

 위와 같이 수정한 뒤에 빌드하여 커널을 실행하면 아래와 같은 화면이 나타난다(아래 화면은 cls 명령으로 화면을 지운뒤, showmem 명령을 실행한 것이다).

showmem.PNG

<showmem 명령 실행>

 Virtual Box에 메모리 설정이 8Mbyte로 되어있어서 00000008 이라는 값이 표시되었다.

 

3.기타

 커널에 기능을 추가하다보면 DWORD의 값을 화면에 출력해야 하는 일이 자주 발생한다. 디버깅 시에도 필수적인 부분인데 kPrintf() 함수를 이용하면 편리하게 할 수 있다.

 

4.마치면서...

 이번에는 프레임워크에 직접적으로 기능을 추가하는 부분에 대해서 알아보았다. 내가 만든 쉘 코드나 프레임워크 시작 부분이 마음에 들지 않으면 위의 코드를 참조하여 얼마든지 수정해도 된다.

 다른 새로운 기능 추가는 각자의 몫으로 남겨두고 다음에는 멀티태스킹에 대해서 구현해보도록 하자.

 

5.첨부

 코드 첨부 

 

 

이 글은 스프링노트에서 작성되었습니다.

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts