이더넷 기능을 사용하는 대부분의 예제에서 웹서버는 필수적으로 필요한 부분이라 테스트가 필요하다. 기존의 Aruino 환경에서 웹서버 예제는 많은 부분이 라이브러리로 구현되어 있어 간단하게 구현 하였는데 SDK를 이용한 웹서버는 여러가지 처리해 주어야 하는 것이 많다.
이전 포스트에서 DHCP 테스트 코드를 조금 수정해서 DHCP로 IP를 할당 받으면 웹서버를 수행하는 코드로 작셩했다.
(참고 W55RP20 웹서버 예제 : https://github.com/WIZnet-ioNIC/WIZnet-PICO-C/tree/main/examples/http/server)
#include "port_common.h"
#include "wizchip_conf.h"
#include "w5x00_spi.h"
#include "socket.h"
#include "dhcp/dhcp.h"
#include "dns/dns.h"
#include "timer/timer.h"
#include "httpServer/httpServer.h"
#include "httpServer/httpParser.h"
#include "httpServer/httpUtil.h"
#include "web_page.h"
#define LED1_PIN 9
#define Led1Off() gpio_put(LED1_PIN, 1);
#define Led1On() gpio_put(LED1_PIN, 0);
#define PLL_SYS_KHZ (133 * 1000)
/* Buffer */
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
#define DATA_BUF_SIZE ETHERNET_BUF_MAX_SIZE
/* Socket */
#define SOCKET_DHCP 0
#define SOCKET_DNS 1
#define DHCP_RETRY_COUNT 5
/* Socket */
#define HTTP_SOCKET_MAX_NUM 8
/**
* ----------------------------------------------------------------------------------------------------
* Variables
* ----------------------------------------------------------------------------------------------------
*/
/* Network */
static wiz_NetInfo g_net_info =
{
.mac = {0x00, 0x08, 0xDC, 0x00, 0x00, 0x00}, // MAC address
.ip = {192, 168, 1, 6}, // IP address
.sn = {255, 255, 255, 0}, // Subnet Mask
.gw = {192, 168, 1, 1}, // Gateway
.dns = {8, 8, 8, 8}, // DNS server
.dhcp = NETINFO_DHCP // DHCP enable/disable
};
/* Loopback */
static uint8_t g_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {
0,
}; // common buffer
/* DHCP */
static uint8_t g_dhcp_get_ip_flag = 0;
/* DNS */
static uint8_t g_dns_target_domain[] = "www.wiznet.io";
static uint8_t g_dns_target_ip[4] = {
0,
};
static uint8_t g_dns_get_ip_flag = 0;
/* Timer */
static volatile uint16_t g_msec_cnt = 0;
/* HTTP */
static uint8_t g_http_send_buf[ETHERNET_BUF_MAX_SIZE] = {
0,
};
static uint8_t g_http_recv_buf[ETHERNET_BUF_MAX_SIZE] = {
0,
};
static uint8_t g_http_socket_num_list[HTTP_SOCKET_MAX_NUM] = {0, 1, 2, 3,};
/**
* ----------------------------------------------------------------------------------------------------
* Functions
* ----------------------------------------------------------------------------------------------------
*/
/* Clock */
static void set_clock_khz(void);
/* DHCP */
static void wizchip_dhcp_init(void);
static void wizchip_dhcp_assign(void);
static void wizchip_dhcp_conflict(void);
/* Timer */
static void repeating_timer_callback(void);
unsigned int ProcessUserPageCb(unsigned char *uri_name, st_http_request * p_http_request)
{
if(strstr(p_http_request->URI, "led_off.html"))
{
Led1Off();
printf("LED ->%s\r\n", uri_name);
}
else if(strstr(p_http_request->URI, "led_on.html"))
{
Led1On();
printf("LED ->%s\r\n", uri_name);
}
else if(strstr(p_http_request->URI, "cam.html"))
{
//Led1On();
//mutex = 1;
printf("image displey -> %s\r\n", uri_name);
}
return 0;
}
int main()
{
uint8_t retval = 0;
uint8_t dhcp_retry = 0;
uint8_t dns_retry = 0;
int i;
int cnt = 0;
set_clock_khz();
stdio_init_all();
gpio_init(LED1_PIN);
gpio_set_dir(LED1_PIN, GPIO_OUT);
while (true) {
if(cnt>5)break;
printf("%d]Hello, world!\n", cnt++);
sleep_ms(1000);
}
// For more examples of UART use see https://github.com/raspberrypi/pico-examples/tree/master/uart
printf("W55RP20 Start\n");
stdio_init_all();
wizchip_spi_initialize();
wizchip_cris_initialize();
wizchip_reset();
wizchip_initialize();
wizchip_check();
wizchip_1ms_timer_initialize(repeating_timer_callback);
if (g_net_info.dhcp == NETINFO_DHCP) // DHCP
{
wizchip_dhcp_init();
}
else // static
{
network_initialize(g_net_info);
/* Get network information */
print_network_information(g_net_info);
}
process_dhcp();
DHCP_stop();
reg_httpServer_webContent((uint8_t *)"index.html", (uint8_t *)index_page);
reg_httpServer_webContent((uint8_t *)"led_off.html", (uint8_t *)led_off_page);
reg_httpServer_webContent((uint8_t *)"led_on.html", (uint8_t *)led_on_page);
reg_httpServer_webContentB((uint8_t *)"lamp2_off.jpg", (uint8_t *)&lamp2_off, sizeof(lamp2_off));
reg_httpServer_webContentB((uint8_t *)"lamp1.jpg", (uint8_t *)&lamp2_on, sizeof(lamp2_on));
reg_httpServer_webContent((uint8_t *)"img_page.html", (uint8_t *)img_page);
/* Infinite loop */
while (1)
{
/* Run HTTP server */
for (i = 0; i < HTTP_SOCKET_MAX_NUM; i++)
{
httpServer_run(i);
}
}
}
static void set_clock_khz(void)
{
// set a system clock frequency in khz
set_sys_clock_khz(PLL_SYS_KHZ, true);
// configure the specified clock
clock_configure(
clk_peri,
0, // No glitchless mux
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
PLL_SYS_KHZ * 1000, // Input frequency
PLL_SYS_KHZ * 1000 // Output (must be same as no divider)
);
}
테스트 결과 웹페이지 출력은 되는데... 이미지가 출력 되지 않는다.
뭐가 문제 일까?
WirShark 을이용해 패킷 캡쳐 해보자.
웹페이지에서 이미지를 요청 했을때 보드에서 초기 데이터만 전송하고 나머지는 0을 채워서 보내고 있다.
이미지 데이터를 바꿔보자
바뀐데이터이지만 여전히 뒤쪽은 0으로 채워져서 전송된다.
뭔가 데이터 전송할때 처리를 못하는것 같은데...문자열은 전송하는데 이미지 데이터는 못보내는것 같다.
httpServer.c 에 있는 웹페이지 요청시 데이터를 전송하는 함수 read_userReg_webContent() 를 보니 문자열만 처리하고 있다. 이분을 이미지 파일과 같은 데이터도 처리 할 수 있도록 수정하니 정상적으로 이미지가 출력 된다.
uint16_t read_userReg_webContent(uint16_t content_num, uint8_t * buf, uint32_t offset, uint16_t size)
{
uint16_t ret = 0;
uint8_t * ptr;
int i ;
if(content_num > total_content_cnt) return 0;
ptr = web_content[content_num].content;
if(offset) ptr += offset;
for(i= 0;i<size; i++)buf[i] = *(ptr+i);
//strncpy((char *)buf, (char *)ptr, size);
//*(buf+size) = 0; // Insert '/0' for indicates the 'End of String' (null terminated)
ret = sizeof(buf);//strlen((void *)buf);
return ret;
}
기존에도 Wiznet에서 제공하는 함수를사용하긴 했었는데... (STM32F에서 W5300 웹서버 테스트 예제)
Base64로 이미지를 인코딩 해서 이런 문제가 없었던것 같다.
테스트 결과 웹페이지가 정상적으로 출력되고 이미지 클릭시 LED 가 On/Off 되는 것을 확인 할 수 있다.
테스트보드에 LED가 너무 밝에 사진에 잘 표현되지 않지만 잘 동작 된다.