FPGA / ARM / DSP Wishbone SoC
<
WB+LINUX+USB+TCPIP+WEBServer >
Lab4 : TCP/IP LED/Dip-Switch
▋Introduction
Lab.4本實驗在ARM9 Linux Kernel上, 應用ARM週邊模組的Ethernet Controller與Linux核心的 protocal stack, 進行以TCP/IP作遠端控制應用。
實驗程式以Client/Server的形式, Client端發送命令要求, 設定Server端的Output(在此例以LED顯示), 或讀取Server端Input(在此例為DipSW)的狀態。
此實驗Server端為ZX Integrator實驗器, Client端為PC,在此例為Ubuntu下是應用程式, 亦可為Windows或Cygwin下的應用程式, 另外也可以將Client端改成是另一個ZX Integrator作為此一Client, 或是對稱的Peer to Peer形式。
▋ Design Codes
simplesvr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <asm/page.h>
#include <netinet/in.h>
#include <linux/fb.h>
//a framebuffer device structure;
typedef struct fbdev{
int fb;
unsigned long fb_mem_offset;
unsigned long fb_mem;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
char dev[20];
} FBDEV, *PFBDEV;
#define TRUE 1
#define FALSE 0
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define LISTENPORT 7500
#define BACKLOG 10
#define MSG "Hello, how are you?"
//open & init a frame buffer
int fb_open(PFBDEV pFbdev)
{
printf("fb_open\n");
pFbdev->fb = open(pFbdev->dev, O_RDWR);
if(pFbdev->fb < 0)
{
printf("Error opening %s: %m. Check kernel config/n", pFbdev->dev);
return FALSE;
}
if (-1 == ioctl(pFbdev->fb,FBIOGET_VSCREENINFO,&(pFbdev->fb_var)))
{
printf("ioctl FBIOGET_VSCREENINFO/n");
return FALSE;
}
if (-1 == ioctl(pFbdev->fb,FBIOGET_FSCREENINFO,&(pFbdev->fb_fix)))
{
printf("ioctl FBIOGET_FSCREENINFO/n");
return FALSE;
}
//map physics address to virtual address
pFbdev->fb_mem_offset = (unsigned long)(pFbdev->fb_fix.smem_start) & (~PAGE_MASK);
pFbdev->fb_mem = (unsigned long int)mmap(
(void *)pFbdev->fb_fix.smem_start,
pFbdev->fb_fix.smem_len + pFbdev->fb_mem_offset,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
pFbdev->fb,
0);
if (-1L == (long) pFbdev->fb_mem)
{
printf("mmap error! mem:%d offset:%d/n", pFbdev->fb_mem,
pFbdev->fb_mem_offset);
return FALSE;
}
return TRUE;
}
//close frame buffer
int fb_close(PFBDEV pFbdev)
{
close(pFbdev->fb);
pFbdev->fb=-1;
}
int main(int argc, char * argv[]) {
FBDEV fbdev;
int fid;
int sock, conn;
struct sockaddr_in my_addr, client_addr;
int sockopt_on = 1;
int sa_in_size = sizeof(struct sockaddr_in);
char rdata[80],sdata[16];
unsigned int led,dpsw;
int i;
memset(&fbdev, 0, sizeof(FBDEV));
strcpy(fbdev.dev, "/dev/fb0");
if(fb_open(&fbdev)==FALSE)
{
printf("open frame buffer error/n");
return;
}
printf("id %s\n",fbdev.fb_fix.id);
printf("fb_mem %x\n",fbdev.fb_mem);
printf("fb_mem_offset %x\n",fbdev.fb_mem_offset);
printf("fb_fix.smem_start %x\n",fbdev.fb_fix.smem_start);
printf("fb_fix.smem_len %x\n",fbdev.fb_fix.smem_len);
*(volatile unsigned int *)(fbdev.fb_mem + fbdev.fb_mem_offset +0x01f00004)=0xffffff;
for(i=0;i<24;i++)
{
*(volatile unsigned int *)(fbdev.fb_mem + fbdev.fb_mem_offset +0x01f00000)=1<<i;
usleep(100*1000);
}
printf("starting....\n");
//get a socket
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
perror("socket");
exit(1);
}
//make it reusable
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&sockopt_on,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//first zero the struct
memset((char *) &my_addr, 0, sa_in_size);
//now fill in the fields we need
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(LISTENPORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//bind our socket to the port
if (bind(sock,(struct sockaddr *)&my_addr, sa_in_size) == -1) {
perror("bind");
exit(1);
}
//start listening for incoming connections
if (listen(sock,BACKLOG) == -1) {
perror("listen");
exit(1);
}
while(1)
{
//grab connections
conn = accept(sock, (struct sockaddr *)&client_addr, &sa_in_size);
if (conn == -1) {
perror("accept");
exit(1);
}
//log the connecter
printf("got connection from %s\n", inet_ntoa(client_addr.sin_addr));
dpsw=0;
//do
//{
// receive cmd
if (recv(conn, rdata, 80, 0) == -1) { perror("recv"); break; }
//printf("The client says \"%s\"\n",rdata);
led=strtoul(rdata,0,0);
//printf("led:%x\n",led);
*(volatile unsigned int *)(fbdev.fb_mem + fbdev.fb_mem_offset +0x01f00000)=led;
usleep(100*1000);
// send status
dpsw=*(volatile unsigned int *)(fbdev.fb_mem + fbdev.fb_mem_offset +0x01f00008);
sprintf(sdata,"0x%x",dpsw>>24);
printf("dpsw:%x %s\n",dpsw,sdata);
if (send(conn,sdata,strlen(sdata)+1,0) == -1) { perror("send"); break; }
//} while(((dpsw&0xff)==0xff)||(led=0x000000));
close(conn);
fb_close(&fbdev);
close(fid);
}
return 0;
}
Makefile
CROSS=/usr/local/arm/3.4.1/bin/arm-linux-
all: simplesvr
simplesvr:
$(CROSS)gcc -o simplesvr simplesvr.c
clean:
rm -rf simplesvr simplesvr.o
simplecln.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 7500
#define BUFLEN 100
int main(int argc, char * argv[]) {
int sock;
char buf[BUFLEN],sstr[BUFLEN];
struct hostent * he;
struct sockaddr_in server_addr;
int bytecount;
if (argc != 3) {
fprintf(stderr,"usage: %s host led \n", argv[0]);
exit(1);
}
//look up the host
he = gethostbyname(argv[1]);
if (he == NULL) {
perror("gethostbyname");
exit(1);
}
//get a socket
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
perror("socket");
exit(1);
}
//set the fields for the server address struct
memset((char *) &server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr = *((struct in_addr *)he->h_addr);
//connect to the server
if (connect(sock, (struct sockaddr *) &server_addr,
sizeof(struct sockaddr_in)) == -1) {
perror("connect");
exit(1);
}
strncpy(sstr,argv[2],BUFLEN-1);
sstr[BUFLEN-1]=0;
//send the reply
if (send(sock,sstr,strlen(sstr)+1,0) == -1) {
perror("send");
exit(1);
}
//receive the greeting
bytecount = recv(sock,buf,BUFLEN-1, 0);
if (bytecount == -1) {
perror("recv");
exit(1);
}
buf[bytecount] = '\0';
printf("DPSW:%s\n",buf);
close(sock);
return 0;
}
Makefile
CRCROSS=/usr/local/arm/3.4.1/bin/arm-linux-
all: simplecln
simplesvr:
# $(CROSS)gcc -o simplesvr simplesvr.c
gcc -o simplecln simplecln.c
clean:
rm -rf simplecln simplecln.o
