ESP8266 웹/터미널 서버 Photo

 약 5년전 mcu로 서버 만들어보겠다고 약 보름간 쌔빠지게 만들었던 적이 있었다

라이브러리 분석하고 샘플 소스 열심히 고쳐가면서 OSI 계층별로 구현해서 지금도 서버 원격 리셋 시키는 기능으로나마 잘 사용하고 있다.

얼마전 ESP8266이라는 아두이노 호환 SOC WiFi IC를 접하고 세상이 참 편해지고 있음을 느꼈다. 이러다 밥줄끈기는거 아닌지....

이 모듈을 이용해 반나절 만에 보름간 빡시게 만들었던 서버 기능과 동일하게 구현된다. 그것도 WiFi로...(물론 옛날 썻던 함수같은건 복사 했지만..)

내부 깊숙이 뭍혀있는건 몰라도 되고 제공해주는 샘플 코드들 몇개만 조합했을 뿐인데 서버 기능이 똭 나온다..ㅋㅋ

다 만들고 대박이라는 말밖에...가격도 어마어마 하다..약 3,000원....

한숨은 여기까지 하고...잠시 서버기능 소스를 봐보자..


아두이노는 setup()함수와 loop()함수가 끝이다.. 시작시 setup함수 호출, loop가 돌면서 실행...mcu프로그램의 기본인 main에서 while(1){} 이러고 시작하는걸

그냥 저렇게 만들어 놨다.. 내부 process를 봐도 뭐..똑같다..


setup함수를 보자. 간략하게 주석붙이기...

void setup() {

//Io포트를 설정한다. 뭐 다 필요없다..입력 방식, 출력 방식따윈 필요없다. 
  uint32_t temp_baud=38400;
  pinMode(OUT_PORT0, OUTPUT);
  pinMode(OUT_PORT1, OUTPUT);
  pinMode(OUT_PORT2, OUTPUT);
  pinMode(LED0, OUTPUT);  
  

// 포트 초기화
  digitalWrite(LED0, 1);
  digitalWrite(OUT_PORT0, 0);
  digitalWrite(OUT_PORT1, 0);
  digitalWrite(OUT_PORT2, 0);
 

//EEPROM.. EEPROM에 설정값을 로딩
  EEPROM.begin(512);
  ReadConfig();
 

//로딩된 설정값 적용
  if (baudrate==0)       Serial.begin(9600);
  else if (baudrate==1)  Serial.begin(19200);
  else if (baudrate==2)  Serial.begin(38400);
  else if (baudrate==3)  Serial.begin(57600);
  else if (baudrate==4)  Serial.begin(115200);
  else                   Serial.begin(38400);  

  if (ip[0]!=0 && ip[1]!=0 && ip[2]!=0 && ip[3]!=0){
    WiFi.config(ip, gateway, subnet);   // WiFi 설정...IP가 0.0.0.0이면 DHCP로 동작한다.
  }
  server = port; //터미널 서버 포트설정
  web_server=web_port; //웹서버 포트설정
 
  WiFi.begin(ssid, password); //WiFi 시작 - 참 쉽다...이걸 Base부터 할려면 아주 쎄빠지게 해야하는데..한줄이라니...잘만들었네..ㅋㅋ
  Serial.print("\r\nConnecting to "); Serial.println(ssid);
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500); // 연결될때까지 대기
  if (i == 21) {
    tickerTimer.attach_ms(100,setpin); //타이머가 MCU프로그램같이는 안된다..할려면 아두이노 시리즈 atmel 몇개 ic만 지원한다. 이런거라도 있어서 다행인가...
    Serial.print("Could not connect to "); Serial.println(ssid);
    //    while (1) delay(500);
  }
  else{
    //start UART and the server
    if (baudrate==0)       Serial.begin(9600);
    else if (baudrate==1)  Serial.begin(19200);
    else if (baudrate==2)  Serial.begin(38400);
    else if (baudrate==3)  Serial.begin(57600);
    else if (baudrate==4)  Serial.begin(115200);
    else                   Serial.begin(38400);  
    server.begin();   //서버 시작...Terminal서버를 위한 서비스 시작...참 간단하다..ㅋ
    server.setNoDelay(true);
 
    Serial.print("Ready! Use 'telnet ");
    Serial.print(WiFi.localIP());
    Serial.print(":"); 
    Serial.print(port);
    Serial.println(" to connect");
    tickerTimer.attach_ms(500,setpin);  //LED상태 출력을 위한 Ticker

    web_server.on("/", handle_Index);     //웹페이지 등록들....
    web_server.on("/index.html", handle_Index);
    web_server.on("/login.html", handle_Login);
    web_server.on("/admin.html", handle_admin);
    web_server.on("/system_setting.html", handle_admin_set);
    web_server.onNotFound ( handleNotFound );
    web_server.begin(); //웹서버 시작
 }
}


setup함수에서 모든 기능 구현이 끝났다...예전에 저거 한줄당 몇십페이지 코딩을 했던 기억이...ㅋㅋ

다음은 loop()함수
void loop() {
  uint8_t i;
  if (sCom.rxEvent) {
    Protocl_Task();    //터미널 서버용 Task...
  } 
  if(!_terminal_enable){
    if (server.hasClient()) {
      for (i = 0; i < MAX_SRV_CLIENTS; i++) {
        //find free/disconnected spot
        if (!serverClients[i] || !serverClients[i].connected()) { //터미널서버는 일단 1개만 ....
          if (serverClients[i]) serverClients[i].stop(); //Client접속이 됐는지 확인...
          serverClients[i] = server.available();
          //Serial.print("New client: "); Serial.print(i);
          continue;
        }
      }
      //no free/disconnected spot so reject
      WiFiClient serverClient = server.available();
      serverClient.stop();
    }
    //check clients for data
    for (i = 0; i < MAX_SRV_CLIENTS; i++) {
      if (serverClients[i] && serverClients[i].connected()) {
        if (!connect_cl){
          connect_cl=1;
          tickerTimer.detach();
          tickerTimer.attach(1,setpin);   //터미널서버가 클라이언트 연결이 되있으면 led를 천천히 점등..1초
        }
        if (serverClients[i].available()) {
          //get data from the telnet client and push it to the UART
          while (serverClients[i].available()) Serial.write(serverClients[i].read()); //터미널 서버 받을걸 uart로..
        }
      }
      else{
          if (connect_cl){
            connect_cl=0;
            tickerTimer.detach();
            tickerTimer.attach_ms(500,setpin); // 클라이언트 접속 끈어지면 0.5초 점등
          }
      }
    }
  }
  //check UART for data
  if (Serial.available()) {
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len); //uart로 들어온것을 저장

    //push UART data to all connected telnet clients
    SerialRxTask(sbuf, len);  //터미널 서버 설정 페이지인지 확인
    if (_terminal_enable) {
      //Serial.print("\r\nCONSOL:>");
    }
    else {
      for (i = 0; i < MAX_SRV_CLIENTS; i++) {
        if (serverClients[i] && serverClients[i].connected()) {
          serverClients[i].write(sbuf, len); //설정페이지가 아니면 tcp전송...
          delay(1);
        }
      }
    }
  }
  web_server.handleClient(); //웹서버 실행...Setup()에서 web_server.on했던 핸들들을 페이지별로 실행한다..
}

이게 주요 설정 끝....정말 쉽다..내부적으론 lwip갖다 쓰고  라이브러리 만들어 내부까지 알필요없게 참 잘 해놨다...

뭐..요즘 mcu들의 성능들이 너무 좋아져서 가능한 이야기이긴 하지만 이렇게 쉽게 될줄이야...

아두이노 라이브러리를 좀더 알았다면 더 간단하게도 가능했겠지만..아직 모르는 부분이 많아 아는걸로만 구현했다..

나머지 세부적인 부분은 첨부파일 참조...

간단한 프로그램 설명을 붙이자면....

터미널 서버는 telnet연결은 uart to telnet 모듈이다

uart <-> telnet이니 기본 예제 소스와 같다..다만

'start config'라고 보내면 consol화면으로 전환, 설정을 할 수 있다..help로 명령 확인 가능하다..

web서버는 login을 하여 설정 및 port출력을 on/off 및 60초까지 on후 off하도록 해놨다..

그냥 그렇다고....

여튼 간만에 재밌는 프로그램이였다...


Source : WiFiTelnetToSerial.ino