Let's Make Teaboard into a Simple Web Server


Teaboard is most suitable also as a board for running network applications, because a LAN function can be used as standard equipment. Therefore, in this article, as an example of a network application in which we use Teaboard, we will create a simple Web server. As for the contents that we will transmit, we shall make it so as to store them on a FAT format SD card in a manner that allows us to transmit as is photographs taken with a digital camera (Fig. 1).

Figure 1. Overall configuration of the system

Connection to the Network

At any rate, let's try to confirm that we can connect Teaboard/ARM920-MX1 to the network.

First, on the Teaboard side, it is necessary to load and put in place beforehand with the lodspg command the TCP/IP manager (tcpipmgr) and network driver (netdrv) as middleware. At system startup time it is loaded as standard equipment, but, just to be sure, please confirm by displaying with the "ref spg" command the list of middleware and drivers that are loaded.

Next, we set such things as the IP address on the Teaboard side. In a case where the network you will use carries out automatic IP address assignment based on DHCP, there is no problem with the standard setting as is, but, in a case where that is not so, please assign an IP address to Teaboard with the "netconf c" command. However, in this case, in order to save the setting on the NETCONF file on the startup disk, it is necessary to start up from an SD card that we can write into.

Once the above settings are finished, we at last connect the network to Teaboard's LAN connector. First, let's issue a ping for Teaboard itself with the "ping localhost" command, and confirm Teaboard's IP address. Next, specify the IP address of another machine, and then carry out the ping command from the Teaboard side; if alive is displayed, Teaboard is connected normally (Fig. 2).

Figure 2. Confirmation of network connection

Access to the SD Card

Next, let's also confirm that the FAT format SD card can be read with Teaboard.

On the Teaboard side, it is necessary to load and put in place with the lodspg command unixemu as middleware. At system startup time, it is loaded as standard equipment, but, just to be sure, please confirm by displaying with the "ref spg" command the list of middleware and drivers that are loaded.

Figure 3. Access confirmation to FAT format SD card

Once that has been confirmed, please insert into Teaboard an SD card formatted by means of something such as a digital camera or Windows personal computer, and try displaying the list of files with the "mscnv -mpcb0 l" command from the Teaboard side (Fig. 3). Here, we are specifying the first partition (logical device name pcb0) of the SD card with the "-m" option. The "l" (el) of the final argument is a specification to display the file list.

Network Programming

Well then, let us now make it our business to at last get into the network programming. We show in Fig. 4 the general flow of communications based on TCP/IP. Outside of the "so_" attached at the beginning of each API, because this is the same as general network programming, please refer to a general network programming textbook for details.

Figure 4. Communications flow based on TCP/IP

Here, the client side is a PC browser, and the server side is a Web server on Teaboard, which we will now create. The exchange of requests and replies will be carried out in accordance with the http protocols. However, because creating a web server all of a sudden is difficult, first, in a preliminary test, let us first confirm operation with a very simple server sample. We show the program in List 1. It is a program that just receives a request from the client side and displays that, responding to the client side with the contents of a very simple page.

Figure 5. Contents requested from the browser

Please actually execute this program on top of Teaboard, and then try issuing a request to the Teaboard side from the browser of the client side (PC). For example, if the IP address of Teaboard is 192.168.0.70, and if you input the URL in the manner of "http://192.168.0.70/abc/def.html" from the browser, a request will be sent (the IP address of Teaboard can be confirmed with "ping localhost"). The request that gets sent from the browser side will be passed to the Teaboard side, and it will be output on the terminal. As for the request, the details differ depending on the browser, but generally it's along the lines of Fig. 5. Following the GET at the beginning, the specified URL being passed to the server side is understood. On the other hand, the page contents the Teaboard side has responded with will be displayed on the browser side (Fig. 6).

Figure 6. Display of reply on browser

FAT File Access

Later, it comes about that all we have to do is expand List 1 in order to read in files from the SD card and respond with contents in answer to a URL that has been sent in with a request.

As for the procedure for reading the FAT format SD card, if we leave aside connecting the file system with attach() at the beginning and disconnecting with detach() at the end, the normal file access functions (fopen(), fread(), fclose(), etc.; and, open(), read(), close(), etc.) can be used as is.

Moreover, it is possible to also read in the directory, and not just files. With open(), we open the directory, and with getdents(), we acquire the directory entries. We show that example in List 2. In the simple Web server we have actually created, we have made it so that we recursively request all the image files on the SD card using this, and then line them up on one page (Fig. 7).

Figure 7. Photographs arranged lined up on one page

Source Lists

The source lists are recorded on the CD-ROM attached to this magazine. They are arranged in bappl/https, in the process programs. Please compile these and execute them on top of Teaboard. Furthermore, when you specify the device name (for example, pcb0) as the argument, equate that device as FAT format, and then acquire the contents from there.

Software Storage on a ROM Disk

When we employ the SD card socket of Teaboard as a FAT format SD card, there is the problem of where to store the simple Web server software itself, which we created. This is because there is the need to store the software itself on a TRON format startup disk. Accordingly, one solution is dividing one SD card into two partitions, employing one for contents storage use with FAT format, and storing the software with TRON format in the other partition. However, in this case, we cannot use the FAT partition only SD card on which we took the photographs with the digital camera.

Therefore, here, let us decide to store the simple Web server software on a ROM disk in Teaboard's Flash ROM. In the case of Teaboard, the size of the Flash ROM is 2 megabytes, but because we also place things such as T-Monitor on the Flash ROM, what can be used as ROM disk comes down to roughly 1.8 megabytes.

Figure 8. Storing of software in the ROM disk

However, ROM disk, as its name implies, cannot simply be written into. Therefore, a procedure is needed in which first, after copying onto an SD card the contents of the ROM disk, we carrying out addition/editing work on top of the SD card, and finally, using T-Monitor's wrda command, we copy the entire disk image of the SD card onto the ROM disk (Fig. 8). Also, we show in Fig. 9 the procedures of the actual example.

Figure 9. Example of procedures to store software onto the ROM disk

Summary

On Teaboard, to a standard real-time operating system, we have loaded a network driver and TCP/IP middleware. Therefore, in this article, we have introduced an example in which we constructed a simple Web server as one example of a network application in which we have put to use Teaboard's LAN function and FAT access function. We would be happy if you put Teaboard to practical use in a great many ways also as a board that runs network applications.

____________________

List 1 Server Side Test Program (httptest.c)
/*
  Test Version of Simple Web Server Using Teaboard
  Copyright (C) 2005 by Personal Media Corporation
*/
#include <stdio.h>
#include <string.h>
#include <btron/bsocket.h>
int main( INT ac, TC *av[] )
{
  int fd, er, cfd, clen, n;
  struct sockaddr_in saddr, caddr;
  static char buf[1024 * 4];
  static char reply[] =
    "HTTP/1.1 200 OK\r\n"
    "Accept-Ranges: bytes\r\n"
    "Content-Length: 64\r\n"
    "Connection: close\r\n"
    "Content-Type: text/html\r\n"
    "\r\n"
    "<html>"
    "<head><title>1234</title></head>"
    "<body>4321</body>"
    "</html>\r\n";
  fd = so_socket( AF_INET, SOCK_STREAM, 0 ); /* TCP socket creation */
  if (fd < 0) return 0;
  memset( &saddr, 0, sizeof(saddr) );
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons( 80 ); /* Port number */
  saddr.sin_addr.s_addr = htonl( INADDR_ANY );
  er = so_bind( fd, (struct sockaddr *)&saddr, sizeof(saddr) ); /* Bind */
  if (er < 0) goto e2;
  er = so_listen( fd, 5 ); /* Listen */
  if (er < 0) goto e2;
  for(;;) {
    clen = sizeof(caddr);
    cfd = so_accept( fd, (struct sockaddr *)&caddr, &clen ); /* Accept */
    if (cfd < 0) goto e2;
    
    n = so_read( cfd, buf, sizeof(buf) ); /* Receive request */
    if (n <= 0) goto e1;
    printf ("%.*s\n", n, buf); /* Display of request */
    
    so_write( cfd, reply, sizeof(reply) ); /*Transmit reply */
  e1:
    er = so_close( cfd ); /* Close socket */
  }
  
 e2:
  so_close( fd ); /* Close socket */
  return 0;
}

Makefile
#
# Test Version of Simple Web Server Using Teaboard
# Copyright (C) 2005 by Personal Media Corporation
#

# Source dependencies-related file (automatically generated)
DEPS = Dependencies
DEPENDENCIES_OUTPUT := $(DEPS)

# Process base standard rules
include ../../etc/makerules

# Target creation
TARGET = httptest

# Path on which source file exists
VPATH = ../src

# Source file
SRC = httptest.c

OBJ = $(addsuffix .o, $(basename $(SRC)))

CFLAGS += $(CFLAGS_WARNING)

#-----------------------------------------------------------------------------
.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJ)
	$(LINK.o) $(LDOBJS) $^ $(LOADLIBES) $(LDLIBS) $(OUTPUT_OPTION)
	$(STRIP) $@

clean:
	$(RM) $(OBJ) $(TARGET) $(DEPS)

# Source dependencies-related
ifdef DEPENDENCIES_OUTPUT
  $(DEPS): ; touch $(DEPS)
else
  $(DEPS): $(SRC) ; $(MAKEDEPS) $@ $?
endif
include $(DEPS)

List 2 Search All Files Recursively (file.c, portion in red appeared in the magazine article)
/*
  Function Group for Reading in Files/Directories
  Copyright (C) 2005 by Personal Media Corporation
 */

#include <basic.h>
#include <string.h>
#ifdef PCAT
#include <bsys/unixemu.h>
#else
#include <btron/unixemu.h>
#endif
#include <unix/sys/types.h>
#include <unix/dirent.h>
#include <unix/fcntl.h>
#include <unix/unistd.h>

extern int attach_disk( char *dev );
extern int detach_disk( char *dev );
extern int file_open( char *path, int *siz, int *tim );
extern int file_read( int f, char *buf, int n );
extern int file_close( int f );
extern int dir_list( const char *path, void (*func)( char * ) );

/* Convert ASCII alphanumeric string to TRON Code string */
static void cv( char *a, TC *t )
{
  for( ; *a != '\0'; *t++ = (*a++) + 0x2300);
  *t = 0;
}

/* Connect disk */
int attach_disk( char *dev )
{
  TC t[16];
  
  cv( dev, t );
  return attach( t, dev, UX_MSDOS );
}
/* Disconnect disk */
int detach_disk( char *dev )
{
  TC t[16];
  
  cv( dev, t );
  return detach( t, 0 );
}
/* Open file path
   Return file size to *siz, updated time to *tim */
int file_open( char *path, int *siz, int *tim )
{
  int f;
  struct stat sb;
  f = open( path, O_RDONLY );
  if (f < 0) return -1;
  fstat( f, &sb );
  *siz = sb.st_size;
  *tim = sb.st_mtimespec.tv_sec;
  return f;
}
/* Read in from the file */
int file_read( int f, char *buf, int n )
{
  return read( f, buf, n );
}
/* Close the file */
int file_close( int f )
{
  return close( f );
}
/* Search all files below the path recursively
   Each time a file is found, call callback function func */
int dir_list( const char *path, void (*func)( char * ) )
{
  int fd; int n; int k = 0;
  struct dirent *dp;
  char buf[256]; char db[512];
  fd = open( path, O_RDONLY );
  if (fd >= 0) for(;;) {
    dp = (struct dirent *)db;
    n = getdents( fd, dp, sizeof(db) );
    if (n <= 0) { close( fd ); break; }
    while (dp != (struct dirent *)(db + n)) {
      strcpy( buf, path );
      strcat( buf, "/" );
      strcat( buf, dp -> d_name );
      if (dp -> d_type == DT_DIR) {
	if (strcmp( dp -> d_name, "." ) == 0
	    || strcmp( dp -> d_name, ".." ) == 0) {
	  /* . and .. are not followed */
	} else {
	  k += dir_list( buf, func );
	}
      } else {
	func( buf );
	k++;
      }
      dp = (struct dirent *)((char *)dp + (dp -> d_reclen));
    }
  }
  return k;
}

https.c
/*
  Simple Web Server Using Teaboard
  Copyright (C) 2005 by Personal Media Corporation
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <btron/proctask.h>
#include <btron/bsocket.h>

extern int attach_disk( char *dev );
extern int detach_disk( char *dev );
extern int file_open( char *path, int *siz, int *tim );
extern int file_read( int f, char *buf, int n );
extern int file_close( int f );
extern int dir_list( const char *path, void (*func)( char * ) );

#define MSG(x) printf x

static const int ptno = 80; /* Port number */

/* Image list page */
static char *ix_p; /* Buffer beginning */
static int ix_s; /* Buffer size */
static int ix_n; /* Size used */
static int ix_c; /* Number of images */

/* Encode character strings to %xx format */
static void encode( char *s, char *d )
{
  int c;
  while ( (c = *s++) != '\0') {
    if (32 < c && c < 127) *d++ = c;
    else d += sprintf( d, "%%%02X", c & 255 );
  }
  *d = '\0';
}

/* Convert hexadecimal characters */
static int hex1( int c )
{
  if ('0' <= c && c <= '9') return c - '0';
  else if ('A' <= c && c <= 'F') return c - 'A' + 10;
  else if ('a' <= c && c <= 'f') return c - 'a' + 10;
  else return -1;
}

/* Decode character strings from %xx format */
static void decode( char *s, char *d )
{
  int c, a, b;
  while ( (c = *s++) != '\0') {
    if (c == '%' && (a = hex1( s[0] )) >= 0 && (b = hex1( s[1] )) >= 0) {
      *d++ = (a << 4) | b;
      s += 2;
    } else if (c == ' ') break;
    else *d++ = c;
  }
  *d = '\0';
}

/* Check whether the end of the string st matches the string sx
   Upper and lower case not distinguished (string sx assumes lower case) */
static int suff( char *st, char *sx )
{
  char *p, *q; char c;
  for(p = st; *p != '\0'; p++); /* Set p to the end of string st */
  for(q = sx; *q != '\0'; q++); /* Set q to the end of string sx */
  for(;; p--, q--) {
    c = *p;
    if ('A' <= c && c <= 'Z') c += 'a' - 'A'; /* Upper case to lower case */
    if (c != *q) return 0; /* Does not match */
    if (q == sx) return 1; /* Matches */
    if (p == st) return 0; /* Does not match */
  }
}

/* Image list creation callback function */
static void wt( char *p )
{
  const int N = 3;
  char buf[1024];
  if (! (suff( p, ".gif" ) | suff( p, ".jpg" )
	 | suff( p, ".png" ) | suff( p, ".bmp" )
	 )) return; /* Ignore files in which images do not appear */

  if (ix_s - ix_n < 1024) { /* Memory expanded so not to be insufficient */
    ix_p = realloc( ix_p, ix_s += 1024 );
  }

  encode( p, buf );
  ix_n += sprintf( ix_p + ix_n,
		   "<a href=\"" "@" "%s\">"
		   "<img src=\"%s\" border=0 width=%d%% hspace=1%% vspace=1%%>"
		   "</a>",
		   buf, buf, (100 / N) - 2 ); /* Output link to image */
  if ((ix_c % N) == N - 1) { /* Line feed for every 1 line N images */
    ix_n += sprintf( ix_p + ix_n, "\r\n" );
  }

  ix_c++;

  MSG( ("img %s\n", buf) );
}

/* Create image list */
static void make_index( char *path )
{
  ix_p = malloc( ix_s = 1024 );
  ix_n = sprintf( ix_p,
	       "<html><head>\r\n"
	       "<title>Photo List</title>\r\n"
	       "</head><body><pre>\r\n" );
  ix_c = 0;

  dir_list( path, wt );

  ix_n += sprintf( ix_p + ix_n,
	   "</pre></body></html>\r\n" );
}

/* Display of the page at the top of the memory */
static void put_mem( int fd, char *p, int n )
{
  int m, i, k;
  char buf1[256];

  m = sprintf( buf1,
	       "HTTP/1.1 200 OK\r\n"
	       "Accept-Ranges: bytes\r\n"
	       "Content-Length: %d\r\n"
	       "Connection: close\r\n"
	       "Content-Type: text/html\r\n"
	       "\r\n",
	       n );
  if (so_write( fd, buf1, m ) != m) return;

  for (i = 0; i < n; i += k) {
    k = n - i;
    if (k > 1024) k = 1024;
    if (so_write( fd, p + i, k ) != k) return;
  }
}

/* Creation of error response */
static void put_error( int fd, int cd, char *mes )
{
  int m, n;
  char buf1[256], buf2[256];

  n = sprintf( buf2,
	       "<html><head>\r\n"
	       "<title>%d %s</title>\r\n"
	       "</head><body>\r\n"
	       "<h1>%s</h1>\r\n"
	       "</body></html>\r\n",
	       cd, mes, mes );
  m = sprintf( buf1,
	       "HTTP/1.1 %d %s\r\n"
	       "Accept-Ranges: bytes\r\n"
	       "Content-Length: %d\r\n"
	       "Connection: close\r\n"
	       "Content-Type: text/html\r\n"
	       "\r\n",
	       cd, mes, n );
  if (so_write( fd, buf1, m ) != m) return;
  if (so_write( fd, buf2, n ) != n) return;
}

/* Response to GET method */
static void get_method( int fd, char *path )
{
  int rd, n, t, k, i;
  char buf[1024 * 32];

  decode( path, buf ); /* Search for path name */
  MSG( ("GET %s\n", buf) );

  if (strcmp( buf, "/" ) == 0) { /* In case of cover page */
    put_mem( fd, ix_p, ix_n );
    return;
  }

  if (strncmp( buf, "/" "@", 2 ) == 0) { /* In case of image page */
    put_mem( fd, buf + 1024,
	     sprintf( buf + 1024, "<html><head>\r\n"
		      "<title>%s</title>\r\n"
		      "</head><body><img src=\"%s\""
		      /* " width=100%%" */
		      "></body></html>\r\n",
		      buf + 2, buf + 2 ) );
    return;
  }
  
  rd = file_open( buf, &n, &t );
  if (rd < 0) { /* In case a file cannot be opened */
    put_error( fd, 404, "Not Found" );
    return;
  }

  k = sprintf( buf,
	       "HTTP/1.1 200 OK\r\n"
	       "Accept-Ranges: bytes\r\n"
	       "Content-Length: %d\r\n"
	       "Connection: close\r\n"
	       "Content-Type: %s\r\n"
	       "\r\n",
	       n,
	       suff( buf, ".html" ) ? "text/html" :
	       suff( buf, ".gif" ) ? "image/gif" :
	       suff( buf, ".jpg" ) ? "image/jpeg" :
	       suff( buf, ".png" ) ? "image/png" :
	       suff( buf, ".bmp" ) ? "image/bmp" :
	       "text/plain" );
  if (so_write( fd, buf, k ) != k) goto e3;

  for (i = 0; i < n ; i += k) { /* Read in the file main body */
    k = n - i;
    if (k > sizeof(buf)) k = sizeof(buf);
    if (file_read( rd, buf, k ) != k) goto e3;
    if (so_write( fd, buf, k ) != k) goto e3;
  }

 e3:
  file_close( rd );
}

/* Acquisition of and reply to request */
static void session( int fd )
{
  int n;
  char buf[1024 * 8];

  n = so_read( fd, buf, sizeof(buf) ); /* Read in */
  if (n <= 0) goto e1;
  
  if (strncmp( buf, "GET ", 4) == 0) { /* GET method or not? */
    get_method( fd, buf + 4 ); /* Reply to GET method */
  } else {
    put_error( fd, 401, "Not Implemented" );
  }

 e1:
  so_close( fd );
}

/* Subtask */
static void subtask( int fd )
{
  session( fd ); /* Acquisition of and reply to request */
  ext_tsk(); /* Terminate subtask */
}

/* Web server main body */
static int https( void )
{
  int er, fd, cfd, clen;
  struct sockaddr_in saddr, caddr;

  fd = so_socket( AF_INET, SOCK_STREAM, 0 ); /* TCP socket creation */
  if (fd < 0) return fd;

  memset( &saddr, 0, sizeof(saddr) );
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons( ptno ); /* Port number */
  saddr.sin_addr.s_addr = htonl( INADDR_ANY );
  er = so_bind( fd, (struct sockaddr *)&saddr, sizeof(saddr) ); /* Bind */
  if (er < 0) goto e2;

  er = so_listen( fd, 5 ); /* Listen */
  if (er < 0) goto e2;

  for(;;) {
    clen = sizeof(caddr);
    cfd = so_accept( fd, (struct sockaddr *)&caddr, &clen ); /* Accept */
    if (cfd < 0) goto e2;
    cre_tsk( subtask, -1, cfd ); /* Acquisition of and response to request */
  }
  
 e2:
  so_close( fd );
  return er;
}

/* Obtain own IP address */
static int get_self_ip( void )
{
  ERR er;
  B buf[HBUFLEN];
  HOSTENT h;

  er = so_gethostbyname( "localhost", &h, buf );
  if (er < 0) {
    return 0;
  } else {
    return ntohl(*(long*)(*(h.h_addr_list)));
  }
}

/* Main */
int main( INT ac, TC *av[] )
{
  int k, ip, er;
  char path[20];

  /* Search for device name from first argument */
  if (ac < 2) {
    path[0] = '\0';
  } else {
    path[0] = '/';
    for(k = 0; av[1][k] != 0; k++) { path[k + 1] = av[1][k] & 255; }
    path[k + 1] = '\0';
  }

  if (path[0] != '\0') {
    er = attach_disk( path + 1 ); /* Connect disk */
    if (er < 0) { MSG ( ("Can't attach %s\n", path + 1) ); goto e1; }
  }

  make_index( path ); /* Image list creation */

  /* Display of own IP address */
  ip = get_self_ip();
  MSG( ("server start\nIP = %d.%d.%d.%d port = %d\n",
	(ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255,
	ptno ) );
  
  https(); /* Web server main body */

  if (path[0] != '\0') detach_disk( path + 1 ); /* Disconnect disk */

 e1:
  MSG( ("server end\n") );

  return 0;
}

Makefile
#
# Simple Web Server Using Teaboard
# Copyright (C) 2005 by Personal Media Corporation
#

# Source dependencies-related file (automatically generated)
DEPS = Dependencies
DEPENDENCIES_OUTPUT := $(DEPS)

# Process base standard rules
include ../../etc/makerules

# Creation target
TARGET = https

# Path on which source files exist
VPATH = ../src

# Source files
SRC = https.c file.c

OBJ = $(addsuffix .o, $(basename $(SRC)))

CFLAGS += $(CFLAGS_WARNING)

#-----------------------------------------------------------------------------
.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJ)
	$(LINK.o) $(LDOBJS) $^ $(LOADLIBES) $(LDLIBS) $(OUTPUT_OPTION)
	$(STRIP) $@

clean:
	$(RM) $(OBJ) $(TARGET) $(DEPS)

# Source dependencies-related
ifdef DEPENDENCIES_OUTPUT
  $(DEPS): ; touch $(DEPS)
else
  $(DEPS): $(SRC) ; $(MAKEDEPS) $@ $?
endif
include $(DEPS)

timer.c
/*
  Timer Process
  Copyright (C) 2005 by Personal Media Corporation
*/

#include <tstring.h>
#include <btron/tkcall.h>

/* LED control driver: data number definitions */
enum{
  DN_LE8BIT  = -200,  /* 8-bit LED attribute data number */
  DN_LE7SEGR = -201,  /* Right 7-segment LED attribute data number */
  DN_LE7SEGL = -202,  /* Left 7-segment LED attribute data number */
  DN_LEDEC   = -203   /* 7-segment LED 2-figure attribute data number */
};

/* Buzzer control driver: data number definition */
enum{
  DN_BZMode = -200 /* Buzzer 1:ON, 0:OFF */
};

INT main( INT ac, TC *av[] )
{
  int ddl, ddb, asize, n, t, k; char v; SYSTIM t1, t2;

  /* Set number of seconds in n */
  n = 0;
  if (ac >= 2) {
    n = tc_atoi( av[1] );
  }
  if (n < 1 || n > 99) n = 60; /* Default 60 seconds */

  /* Countdown of n seconds */
  ddl = tk_opn_dev( "led", TD_UPDATE ); /* Open LED control driver */
  tk_get_otm( &t1 ); /* Record initial time */
  do {
    tk_dly_tsk( 10 );
    tk_get_otm( &t2 ); /* Acquire present time */
    t = (t2.lo - t1.lo) & 0x7fffffff; /* Get elapsed time(milliseconds) */
    t /= 1000; /* Milliseconds in units of seconds */
    t = n - t; /* Countdown from n seconds */
    v = t;
    tk_swri_dev( ddl, DN_LEDEC, &v, sizeof(v), &asize ); /* LED display */
  } while ( t > 0 );
  tk_cls_dev( ddl, 0 ); /* Close LED control driver */

  /* Ring buzzer */
  ddb = tk_opn_dev( "buzzer", TD_UPDATE ); /* Open buzzer control driver */
  for(k = 0; k < 3; k++) {
    v = 1;
    tk_swri_dev( ddb, DN_BZMode, &v, sizeof(v), &asize ); /* Ring buzzer */
    tk_dly_tsk( 500 ); /* Wait 500 milliseconds */
    v = 0;
    tk_swri_dev( ddb, DN_BZMode, &v, sizeof(v), &asize ); /* Stop buzzer */
    tk_dly_tsk( 500 ); /* Wait 500 milliseconds */
  }
  tk_cls_dev( ddb, 0 ); /* Close buzzer control driver */

  return 0; /* Terminate process */
}

Makefile
#
# Timer Process
# Copyright (C) 2005 by Personal Media Corporation
#

# Source dependencies-related file (automatically generated)
DEPS = Dependencies
DEPENDENCIES_OUTPUT := $(DEPS)

# Process base standard rules
include ../../etc/makerules

# Creation target
TARGET = timer

# Path on which source file exists
VPATH = ../src

# Source file
SRC = timer.c

OBJ = $(addsuffix .o, $(basename $(SRC)))

CFLAGS += $(CFLAGS_WARNING)

#-----------------------------------------------------------------------------
.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJ)
	$(LINK.o) $(LDOBJS) $^ $(LOADLIBES) $(LDLIBS) $(OUTPUT_OPTION)
	$(STRIP) $@

clean:
	$(RM) $(OBJ) $(TARGET) $(DEPS)

# Source dependencies-related
ifdef DEPENDENCIES_OUTPUT
  $(DEPS): ; touch $(DEPS)
else
  $(DEPS): $(SRC) ; $(MAKEDEPS) $@ $?
endif
include $(DEPS)

readme
TRONWARE Vol. 95 Recorded
Program Collection for Teaboard Use
Copyright (c) 2005 Personal Media Corporation
This program collection is organized based on the latest information on
Teaboard, which is a product under development at the time of the writing
of this article. There is the possibility that some changes will be
needed for use in the product that is finally put on sale.

Organization of the Directory

 Process base programs

 bappl --+- https     Simple Web server
         |
         +- httptest  Simple Web server test version
         |
         +- timer     Timer

 Device drivers

 driver -+- buzzer    Buzzer control device driver
         |
         +- led       LED control device driver
         |
         +- motor     Motor control device driver

 T-Kernel base programs

 kappl --+- disc      Motor control application
         |
         +- roulette  Roulette

Make/Execution Methods

With reference to the examples below, perform make in the development
environment, and then execute on top of Teaboard. 

Furthermore, for details, please refer to the text of the articles
published in TRONWARE Vol.95.

Roulette (T-Kernel base)

  Make method

  cd kappl/roulette/tbmx1
  gmake

  Execution method

  lodspg roulette

  When you press on the right push switch, you can start and stop
  the roulette revolution. 

  When you press on the left push switch, roulette terminates.

Buzzer control device driver

  Make method

  cd driver/buzzer/tbmx1
  gmake

  Load method

  lodspg buzzer

  Because the driver just simply resides,
  please combine it with the timer program,
  for example, to confirm operation.

LED control device driver

  Make method

  cd driver/led/tbmx1
  gmake

  Load method

  lodspg led

  Because the driver just simply resides,
  please combine it with the timer program,
  for example, to confirm operation.

Timer (process base)

  Make method

  cd bappl/timer/tbmx1
  gmake

  Execution method

  Please execute after having first loaded the LED control device driver 
  and buzzer control driver.

  lodspg led
  lodspg buzzer
  timer 30

Motor control device driver

  Make method

  cd driver/motor/tbmx1
  gmake

  Load method

  lodspg motor

  Because the driver just simply resides
  please combine it with the motor control application,
  for example, to confirm operation. 
  Furthermore, motor externally attached hardware is necessary.

Motor control application (T-Kernel base)

  Make method

  cd kappl/disc/tbmx1
  gmake

  Execution method

  Please execute after having first loaded the LED control device driver
  and the motor control driver.
  Furthermore, a motor and infrared sensor external hardware are
  necessary.

  lodspg led
  lodspg motor
  lodspg disc

Simple Web server (process base)

  Make method

  cd bappl/https/tbmx1
  gmake

  Execution method

  In a case where you have placed an image file on the startup disk:
 
    https

  In a case where you have placed an image file on a FAT formatted SD 
  card:
 
    https pcb0

Simple Web server test version (process base)

  Make method

  cd bappl/httptest/tbmx1
  gmake

  Execution method

  httptest


The above article on Teaboard appeared on pages 63-68 in Vol. 95 of TRONWARE. It was translated and loaded onto this Web page with the permission of Personal Media Corporation.

Copyright © 2005 Personal Media Corporation

Copyright © 2009 Sakamura Laboratory, University Museum, University of Tokyo