본문 바로가기
코스웨어/15년 스마트컨트롤러

20151023(금) 윤재희 - GPIO를 통한 웹서비스 메시지 제어, 메모리 출력 함수, 프로그램 실행 함수

by 알 수 없는 사용자 2015. 10. 23.
728x90
반응형

로봇제어


==================================Outline====================================

웹 프로그래밍

- GPIO를 통한 웹서비스 메시지 제어 

----------------------------------------------------------------------------

 

//PiFace는 따로 장치를 구입해서 장착해야되기 때문에 교재의 해당 부분은 넘어가도록 한다.

 

교재 p/200

 

웹 프로그래밍

 

네트워크를 사용하기 위해서는 웹 서비스를 제공하는 서버가 필요하다.

 

플라스크는 파이썬을 위한 마이크로 웹 프레임워크로 Werkzeug, Jinja2를 기반으로 하는 오픈소스 서비스이다.

 

윈도우의 경우 IIS(Internet Information Services)를 제공한다무료로 제공되는 서비스 중에 톰캣이 있다.

 

//Apache Tomcat - http://tomcat.apache.org/

 

HTML은 변수를 사용할 수 없음으로 소스코드가 고정 되어 있다.  변수를 사용하여 유동성 있는 서비스를 제공하기 위해서는 ASP, JSP, PHP으로변수를 적용한 후 다시 HTML로 변환해야 한다.

 

서비스 제공자 - ASP: Microsoft

                     JSP: JAVA

                     PHP: C문법 적용

 

일반적으로 웹 서비스를 제공하기 위해서는 웹을 표현하는 html과 ASP, JSP, PHP 중 택 1하여 사용하여야 한다.

 

//ASP는 window운영체제를 사용해야 하지만 JSP와 PHP는 운영체제를 가리지 않고 사용할 수 있다.

 

- GPIO를 통한 웹서비스 메시지 제어

 

GPIO제어를 통한 웹서비스 메시지를 제어하는 것을 해보자.

 

p/202~p/211을 참고한다.

 

우선 파이선PIP를 설치한다.

 

apt-get install python-pip

 

 

 

python-pip 설치 후 플라스크를 설치한다.

 

pip install flask

 

 

교재 p/203의 "hello_flask.py"를 작성한다.

[hello_flask.py]

 

 

 

입력을 마친 후 실행시킨다.

 

입력한 IP와 포트번호를 웹에 입력하면 자신이 설정한 메시지가 뜬다.

 

웹에서 해당 서비스를 요청한 경우 이를 라즈베리파이에서 확인할 수 있다.


 

플라스크 서버에 HTML 웹페이지를 구성하고웹브라우저를 통해 클라이언트가 접속했을 때 서버의 시간을 출력해 보자.

 

교재 p/205에 나와있는 "gettime.py"를 작성하고 작성한 파일과 동일한 위치에 "templates"라는 폴더를 만든다그런 다음 main.html 파일을 작성하여 만든 폴더에 넣는다.

 

[gettime.py]


[main.html]


 

플라스크를 기반으로 GPIO 포트 모니터링

 

플라스크를 이용하여 웹을 통해 라즈베리 파이를 제어해본다핀에 on/off 상태를 웹서버에서 확인할 수 있도록 만든다.

 

port 23, 24, 25를 사용하도록 한다.

 

[gpio.html]

 

[check_switch.py]



어셈블리

==================================Outline====================================

메모리 출력 함수 'memory_display'
프로그램 실행 함수  ‘program_execute'

----------------------------------------------------------------------------

메모리 출력 함수 'memory_display'

 

메모리를 헥사뷰로 출력하는 함수 'memory_display'를 만들어보자.

 

//'memory_modify'함수를 복사해서 필요한 부분만 수정하면 편하다.

 

사용자가 출력하고자하는 메모리의 시작 위치를 입력 받은 후 헥사뷰를 실행시켜 16씩 출력 시킨다. 페이지를 초과하는 경우 사용자로부터 아무키나 입력받으면 다음 페이지를 출력 시키고 q' 혹은 'Q' 입력할 시 출력을 멈춘다.

void memory_display()
{
  unsigned int uiAddr;
  unsigned int uiVal;  
  char cInput;

  
  while(1)
  {
    printf("Please input an address to display [%08X - %08X]  :  ", vpMem_start, vpMem_end);
    scanf("%x"&uiAddr);
    if('\n'==getchar());
    if(uiAddr < (unsigned int)vpMem_start || uiAddr > (unsigned int)vpMem_end)
    {
      printf("Wrong address \n");
      continue;
    }
    break;    
  }
  
  while( (uiAddr)< ( (unsigned int)vpMem_end ) )
  {
    hexaview((void *)uiAddr, 16*16);
    uiAddr = uiAddr + (16*16);
    if(uiAddr>(unsigned int)vpMem_end)
    {
      printf("Memory displayed\n");
      return;
    }
    printf("Please enter any to continue(stop for 'Q')\n");
    cInput = getch();    
    if(cInput == 'q' ||cInput == 'Q')
    {
      printf("Memory display interrupted\n");
      return;
    }    
  } 
  return; 
}

 

헥사뷰 주소 값이 ‘vpMem_end‘를 초과할 경우 해당 자리에서 헥사뷰를 멈추도록 코딩한다.

이를 위해 헥사뷰를 수정한다.

void hexaview(void * vP, unsigned int uiLen)
{
  unsigned int uiCnt;
  unsigned int uiLine;

  printf("===============================================================================\n");
  printf("  Address      Hexa           ASCII       \n"); 
  printf("-------------------------------------------------------------------------------\n");
  for (uiLine = 0; uiLine <  uiLen; uiLine += 16)
  {
    if(vP > vpMem_end)
      return;
    printf(" %08X  ", vP);
  
    for(uiCnt=0; uiCnt<16; ++uiCnt)
    {
      if(vP > vpMem_end)
      {
        while(uiCnt<16)
        {
          printf("   ");
          vP = (char *)vP + 1;
          ++uiCnt;
        }
        break;
      }
      printf("%02X ", *((unsigned char *)vP));
      vP = (char *)vP + 1;
    }
    vP = (char *)vP - 16;
    putchar(' ');

    for(uiCnt=0; uiCnt<16; ++uiCnt)
    {
      if(vP > vpMem_end)
      {
        putchar('\n');
        return;
      }
      if (32 > *((unsigned char *)vP))
      {
        putchar('.');
      }    
      else if(127 < *((unsigned char *)vP))
      {
        putchar('.');
      }
      else
      {        
        printf("%1c", *((unsigned char *)vP));
      }

      vP = (char *)vP + 1;
    }
    putchar('\n');

  }
  putchar('\n');
  return;
}


실행시킨 화면은 다음과 같다.





//코딩을 할 때 변수와 함수명의 형식에 일관성이 있어야 한다.

 

프로그램 실행 함수  ‘program_execute' 


로드함수를 사용하여 프로그램을 메모리에 적재한 후, 이것을 실행시키는 ‘program_execute'를 만들어보자. 사용자가 입력하는 명령어는 'GO'이다. 전역 변수를 만들어 주고 로드 상태에 따라 해당 변수의 값을 바꿔준다.

 

#define LOAD_ON 1

#define LOAD_OFF 0

 

unsigned int uiLoad;

 

‘program_execute'가 실행되면 로드 되어 있는 프로그램이 실행되고 난 후 다시 메뉴로 돌아가야 한다. 이를 위해 어셈블리 코드로 만든 stst‘, ’ldst‘함수를 사용한다.


레지스터 변수들을 담고 있는 ’context’‘stTempState‘라는 이름으로 선언해준다. 이 구조체는 로드된 프로그램을 실행시키고 다시 메뉴로 돌아갈 수 있게 만들어주는 징검다리 역할을 한다.


구조체의 ‘esp’에는 ‘vpStack’, ‘eip’에는 ‘vpCode’(로드된 프로그램), ‘eax’에는 ‘stOld_state’의 주소를 담아준다.

 

세팅을 끝낸 ‘stTempState‘를 ’ldst‘의 인자로 전달한다. 'eip'가 적재된 프로그램의 코드 영역을 가리키고 있음으로 프로그램이 실행된다프로그램이 수행되고 나면 레지스터를 ’stOld_state’에 저장된 상태로 되돌려 주어야 한다‘stOldState’를 'eax'에 넣어준 것이 바로 'stOldState'가 가진 레지스터의 상태로 복구 시켜주기 위함이다.



void program_execute()
{
  context stTempState;
  if(uiLoad == LOAD_OFF)
  {
    printf("No loaded program.\nPlease load program by using 'LOAD' command.\n");
    return;
  }
  memset(&stTempState, 0sizeof(context));  
  stTempState.esp = (unsigned int)vpStack;
  stTempState.eip = (unsigned int)vpCode;    
  stTempState.eax = (unsigned int)(&stOld_state);
  
  ldst(&stTempState);
  printf("System Panic!\n");
  
  return;

} 


적재된 프로그램 실행 후 레지스터를 ‘stOldState’의 값으로 복구 시키기 위해 어셈블리로 'init'함수를 만들어준다. C에서도 호환하여 사용하기 위해 언더바(_)를 붙혀준다.


(진행중)

.386

.MODEL FLAT

PUBLIC _INIT

EXTERN _smart1:NEAR32

EXTERN _ldst:NEAR32


.code

_start:

_INIT PROC NEAR32

  push eax  ;'&stOldState' 저장
  call _smart  
  call _ldst  
  

_INIT ENDP



init.asm



smart.c



728x90