home    projects    contact    about   

A network library for small embedded controllers

This package was written by me in 1999 as a way of expanding the capability of a line of microcontrollers manufactured by TERN. I created a prototype board using the Crystal (now Cirrus ) CS8900 ethernet controller chip. Tern then  incorporated this library into their toolkit.

This package is built for an older version of the Borland-based Tern software development kit which is has been replaced with a newer kit based on the Paradigm C tool chain. If you are using this newer SDK, a version of this kit is included in the directory Tern\186\SAMPLES. 

This code may be useful as an example of a lightweight, stand-alone implementation of a CS8900 driver in 8 bit mode, as well as a reasonably complete implementation of the IP portion of the TCP/IP stack.

You may download the source code of the final version HERE

TERN CS8900 Driver Library Version 0.9

17-AUG-99

(C) 1999 Cogwheel, Inc.
(C) 1999 Tern, Inc.

CONTENTS

OVERVIEW
INSTALLATION PREREQUISITES
PREPARING HARDWARE
BEFORE COMPILING SAMPLE PROGRAMS
COMPILING AND RUNNING SAMPLE PROGRAMS
SAMPLE PROGRAMS
  PINGPOLL
TROUBLESHOOTING
PNGIRUP
TERNETD
PC CLIENT SOFTWARE
Other PC Client Software - CSTEST.PL
DEBUGGING TERN-RESIDENT SOFTWARE

FUNCTION DESCRIPTIONS

cs_init
cs_errcode
cs_ledmorse
cs_bcmp
cs_bcopy
cs_bzero
cs_rdreset
cs_reset
cs_inpagew
cs_outpagew
cs_per_second_chores
cs_poll
cs_interrupt
cs_rx
cs_arp_tx_reply
cs_ip_input
cs_in_cksum
cs_arp_resolve
  cs_icmp_input
cs_arp_rx_reply
cs_ip_output
cs_txdrainq
cs_dbg_putser
cs_dbg_putsern
cs_serinit
cs_dbg_dump_bytes
cs_linkled
cs_udp_bind
cs_clearstats
cs_intsetup
cs_udp_input
cs_route
cs_pbo
cs_get_next_buffer
cs_free_bufp
cs_free_bufi

TFTP LIBRARY FUNCTIONS

tftpd_init
tftp_rx_handler
tftpd_timeout_check
tftpd_finish_reply

OVERVIEW

CS89UDP is a source code library which provides UDP-based services for CS8900-based ethernet controller as implemented for TERN microcontrollers. It supports the CS8900 Ethernet controller as supplied on the MM-A adaptor board interfaced to any AM188-based Tern controller which supports the MM-A.

The software tool chain used consists of the the Borland Turbo C++ V3.1 Compiler, Turbo Link 5.1 and Tern LOC 3.1 EV Version 6.00.43 as distributed with Tern controller products.

INSTALLATION PREREQUISITES

The distribution is a self-extracting zip archive: CSUDP09x.EXE

Its contents should be extracted into the \TERN\186 directory which was created during the installation of the TERN EV SDK. It does not overwrite any existing files. One change is required to the pre-existing MAKEFILE (see below) in order for the CS89UDP samples to run.

The following steps should be taken at a DOS command prompt; The distribution file may be contained on floppy or in a temp directory. The following assumes it is on a floppy mounted in the A drive:

  • Change Directory to \TERN\186 and unpack the archive:

C:\>CD \TERN\186
C:\tern\186> A:CSUDP09x -d

'x' will vary depending on the particular release.

The following files will be extracted:

This docment

CSREADME.HTM

Batch scripts to compile and run sample applications:

METH.BAT
TETH.BAT

Source code to library:

CS89DEFS.H CS89DEV.H CS89UDP.H IRUP188.H
CSETH_A.ASM CS89UDP.C

Sample applications:

"PING" demonstrations. Polled and Interrupt driven versions:

PNGIRUP.C
PNGPOLL.C

Trivial File Transfer Protocol - Server application demo:

TERNETD.C TFTP.C TFTP.H

Optional PC-side test routines

CSTEST.PL CS_TFTP.PM - Perl-language
TERNET/ - Microsoft Visual C project

PREPARING HARDWARE

Confirm that the MM-A board has been firmly seated into the Am188 CPU card.

CS8900 LEDs

There are two LEDS on the CS8900 board, the LINK LED should come on and stay once when power is applied and a valid connection has been made on the 10BASET interface. The other LED will flicker on and off to indicate any traffic activity on the 10BASET interface.

BEFORE COMPILING SAMPLE PROGRAMS

One change is required to the stock /TERN/186/MAKEFILE as distributed by Tern; Edit it and make the following change:

Before:

USER_OBJS=

After:

#USER_OBJS=

This change allows the TETH.BAT and METH.BAT scripts to pass in their own settings for this parameter and should not disturb your ability to compile and run any other sample Tern programs.

COMPILING AND RUNNING SAMPLE PROGRAMS

Any one of the test applications can be compiled with the supplied script - METH.BAT, or compiled and run with METH.BAT; These batch scripts act the same as T.BAT and M.BAT as supplied with the Tern EV kit with the exception that they pass in the necessary list of .OBJ files to link.

SAMPLE PROGRAMS

Setting Network Parameters

Prior to running any of the sample programs, you must alter the network address definitions in the main() function of the respective program. To do this, you will need to know the following about your LAN:

  • AN UNUSED IP NETWORK ADDRESS
  • NETWORK MASK IN USE
  • OPTIONALLY, THE ADDRESS OF A DEFAULT GATEWAY ROUTER

For example, if your local net address was 192.168.0.0, with a netmask of 255.255.255.0, and there was an unused host address of 192.168.0.1 available for the controller, then in main() of the sample program, you would set the following lines:

CS_SET_IP_VAL(192,168,0,1, csp->ipoct4);
CS_SET_IP_VAL(255,255,255,0, csp->netmask_ipoct4);

Note the commas which are different from tranditional IP address notation.

If you are communicating with the controller through a router, then you will need to set the optional default gateway address; Continuing with the above example, if the gateway router's address on the controller's LAN as 192.168.0.254, the you would set the following address:

CS_SET_IP_VAL(192,168,0,254, csp->default_router_ipoct4);

PINGPOLL

Basic polled mode response to ping.

This function demonstrates basic library functionality by answering ICMP Echo, aka 'ping' packets sent from another host.

With a Tern controller / Ethernet connected serially to your PC, Compile and download with the command:

TETH PNGPOLL

Run the program. Now, from a PC on the same ethernet, At a DOS prompt type:

PING 192.168.0.1

Replace 192.168.0.1 with the address you set in pngpoll.c You should see reply packets. You may single-step PINGPOLL and analyze program flow.

PNGIRUP

This application demo behaves identically to PINGPOLL with the exception that it employs interrupts. Consequently, it will respond faster to requests.

TERNETD

This application implements a TFTP protocol server which can be connected to via any pc software which utilizes the TFTP protocol. Source code to pc programs have been provided with TERNET.EXE being the most flexible.

Compile and run TFTP by entering:

TETH TERNETD

Once running, TERNETD will listen for TFTP connects. It accepts TFTP GET commands with specifications of the command to perform as the source file parameter. The following commands are accepted by entering them as the source file parameter in the TFTP client:

File Name Parameter MEANING
ether status returns statistics on ethernet
ether clear resets all statistics counters to 0
sourcedata NNNN controller sends NNNNN bytes of test data
ledmorse message .. blinks message in morse code on controller led
bid break into debugger

In addition, TERNETD accepts commands from a selection of ae_lib functions; All paremters are numeric and can be entered decimal or hex (preceded with 0x). See the tern software documentation for more information.

COMMAND MEANING
ae_init perform ae_init() call
led state perform led() call. state = 0: off state = 1: on
pio_init bit mode perform pio_init() call.
pio_wr bit dat perform pio_wr() call.
pio_rd port perform pio_rd() call.
outport port_id value perform outport() call.
outportb port_id value perform outportb() call.
inport port_id perform inport() call.
inportb port_id perform inportb() call.
ae_ad12 channel perform ae_ad12() call.
ae_reset perform ae_reset() call. Does not return.

Be sure to set the TFTP client to transfer in BINARY mode.

PC CLIENT SOFTWARE - TERNET

TERNET

TERNET is a a win32/winsock-based utility for use with TERNETD on the Tern controller. TERNET polls the controller, sending arbitrary directives on the command line.

TERNET [ -t timeout-secs -n repeat-count -d delay-ms -s(tamp time) ]  controller-ip-address command

A TERNET.EXE executable is located in /tern/186/ternet/debug. The director /tern/186/ternet contains the source and the other files necessary to compile it as a Microsoft VC5 project.

PC CLIENT SOFTWARE - CSTEST

A perl script which acts as a customized TFTP client is included. It requires that you install Active State Perl for WIN32, available from www.activestate.com/ActivePerl.

After installing ActiveState PERL, you can then invoke cstest.pl by double-clicking it from an Windows Explorer window or entering PERL CSTEST.PL at a DOS command prompt. It has a number of options including running any of the supported TFTP commands with one keystroke, plus an option for running them repetitively for testing..

The TFTPOLL script combined with the CSTEST script provides a complete example of how to create an application which requires two-way communication over an ethernet LAN.

Other PC Client Software

Since the Tern controller demo program TERNETD implements a tftp protocol server, Any third-party tftp client software. An example of one such client is TFTP Client 95 from Weird Solutions - (www.weird-solutions.com ).

 

TROUBLESHOOTING

If the Am188 cannot reset the the CS8900, the LED on the Am188 mainboard will blink a pattern in morse code:

PATTERN MEANING
.   .-. ER Could not reset CS8900
.   -... EI Could not initialize CS8900

Both of these patterns could most likely indicate a problem with the attachment of the CS8900 to the Am188 board.

DEBUGGING TERN-RESIDENT SOFTWARE

If you call cs_init() with the CS_DEBUG option set, debugging will be sent to the SER2 serial interface at 9600/8N1. Debugging of Interrupt-driven software in the Turbo Debugger is not reliable, so it is recommended that code be tested and development be done in polled mode. As long as the controller is operated in non-interrupt mode, all functionality of the Turbo Debugger is available.


Function Descriptions

int cs_init(u_char opts, struct cs_info *csp )

Initialize (or reinitialize) CS8900 Chip and driver code
  must be called prior to any other cs_ library calls.
  can be called with any flag

    opts - or-combinable bits: 

	CS_PROMISC - causes chip to receive all packets on network
     	CS_IENABL  - causes received packets to generate interrupts
     	CS_DEBUG   - turns on debugging information 
     	CS_RESET   - resets the ethernet chip be filled in.

    csp - pointer to ethernet controller info structure.  The following
          members must be filled in prior to calling:

		csp->baseaddr
		csp->vec
		csp->ipoct[1-4]
		csp->netmask_ipoct[1-4]
		csp->default_router_ipoct[1-4]
		csp->numbufs 
		csp->poll_interval 





void cs_errcode(char *inpat)

displays a message on the serial port and on the controller led
 using morse code
 
     inpat - char * to issue. Note, pattern should consist of no 
             more than a few characters. Pattern will blink code 
             on leds forever.





void cs_ledmorse(char *inpat,int forever)

blinks pattern on controller led. 
    
    forever = 0 : blink it once and return
            = 1 : blink it repeatedly forever 




u_int cs_bcmp( char *d, char *s, int c)

Compare memory blocks, return 0 if equal.

        d : pointer to destination
        s : pointer to source
        c : how many bytes to compare




int cs_bcopy(from, to, cnt)

Copy 'cnt' bytes from 'from' to 'to'. careful of overlay.




void cs_bzero(u_char *str, u_int cnt)

zero out a buffer

    	str : pointer to area
    	cnt : how many bytes to zero





u_int cs_rdreset(struct cs_info *csp) {

read reset status of chip generate error if there's a problem. 
    otherwise return value read from Self Control Regsiter.

        csp : pointer to cs_info ether controller information





int cs_reset(struct cs_info *csp) {

reset the cs8900 controller.




u_int cs_inpagew(struct cs_info *csp, u_int loc) {

get a single word from a specified packet page addr

    	csp : pointer to cs_info ether controller information
    	loc : cs8900 register location from which to read




void cs_outpagew(struct cs_info *csp, u_int loc, u_int val)

write a single word from a specified packet page addr
    
    	csp : pointer to cs_info ether controller information
    	loc : cs8900 register location from which to read 





void cs_per_second_chores(struct cs_info *csp)

Handle periodic timeout chores.
    Should be called 1x per second to clear out old ARP table entries, etc.

    	csp : pointer to cs_info ether controller information
    




cs_poll(struct cs_info *csp)

csp : pointer to cs_info ether controller information

    Take care of any pending business.
    In an polled environment, it should be called
    Every .1/sec . There is no harm in calling it
    as infrequently as 1/sec, however response to incoming
    packets will be delayed by up to that amount.

    In an interrupt driven environment cs_poll()
    should still be called at a minimum of at least once per second 
    to check for missed interrupts, and handle timeout chores 

    Prior to cs_init(), set csp->poll_interval to the number 
    of times you intend to call cs_poll() per second.  This
    is to calibrate how often the per_second function gets
    called by cs_poll()




void interrupt far cs_interrupt(void)

Ethernet interrupt handler. 

    Sorts out type of interrupt and calls cs_rx() if need be.
    Can be called directly as an ISR, or manually, usually via  cs_poll().




void cs_rx(void) {

called from cs_interrupt()
    Read packets in from ethernet controller.
    determine disposition and call appropriate handler functions.




void cs_arp_tx_reply( struct cs_info *csp, struct ether_arp *ea)

Reply to an arp 'whohas' packet w/our IP address.

    	csp : pointer to cs_info ether controller information
    	ea  : sender's arp information





void cs_ip_input( struct cs_info *csp, struct ip *ip)

handle packets inbound IP packets..

    	csp : pointer to cs_info ether controller information
    	ip  : ip portion of received packet




int cs_in_cksum(void *p, int len)

Checksum routine for Internet Protocol family headers (Portable Version).
    This routine is very heavily used in the network
    code and should be modified for each CPU to be as fast as possible.

    Obtained from BSD Stack.

    	p : start of buffer to checksum
        len : how many bytes to checksum

    	returns the checksum value 





struct arptabentry * cs_arp_resolve(struct cs_info *csp, struct ip *ip)

Send an arp whohas packet 

    	csp : pointer to cs_info ether controller information

    	ip  : ip packet containing the ipaddr to resolve

    	returns :  pointer to valid arp entry or 0.





void cs_icmp_input( struct cs_info *csp, struct ip *ip)

Handle inbound ICMP packets. This includes 'ping' packets

    	csp : pointer to cs_info ether controller information
    	ip  : pointer to ip portion of rx'd packet





void cs_arp_rx_reply( struct cs_info *csp, struct ether_arp *ea)

handle an answer to one of our who-has requests

    	csp : pointer to cs_info ether controller information
    	ea : pointer to received arp packet





void cs_ip_output( struct cs_info *csp, u_char bufno, struct ip *ip)

send an IP packet that is already in the
    buffer and filled in except for perhaps the ARP address. 

    	csp : pointer to cs_info ether controller information
    	bufno : index of buffer in csp->packetbuffers array
    	ip  : pointer to ip section of packet to be transmitted

    cs_ip_output() will perfrom the necessary routing and arp lookup
    to send the packet. In the case that the ARP entry for the destination
    is not on hand, it will keep the packet in keep the packet for
    later transmission. 
    


void cs_txdrainq(struct cs_info *csp)

Transmit any untransmitted packets in the queue. 
    This routine is typically called by poll
    routines and by the rx routine when the corresponding destination 
    has replied with the ARP packet.

    	csp : pointer to cs_info ether controller information



void cs_dbg_putser(char *buf)

send a message to the serial port (for debugging)

    buf : pointer to null-terminated string to send



void cs_dbg_putsern(char *buf) {

same as putser(), but add \r\n on the end


void cs_serinit(u_char speed) {

initialize serial port

    	speed : baud rate code for serial port.
             passed to s1_init() of ae_lib



void cs_dbg_dump_bytes(char *mesg, u_char *AbsBaseAddr, int Length)

dump out bytes in hex and ascii

    mesg : ascii string to print prior to dump
    AbsBaseAddr: pointer to start of area to dump
    Length : how many bytes to dump


void cs_linkled(struct cs_info *csp, int what)

control link led attached to cs8900 chip 

    	csp    : pointer to cs_info ether controller information
    	what   : 0 : turn link led off 
             1 : turn link led on
    	


void cs_udp_bind( struct cs_info *csp, u_short port, void far (*handler)(struct cs_info *csp, void *whatever) )

    csp : pointer to cs_info ether controller information
    port : udp port on which to listen 
    void far (*handler)(struct cs_info *csp, void *whatever))  : pointer to user-supplied handler function

    handler params:

    csp : pointer to cs_info ether controller information
    whatever : untyped pointer to inbound packet.
    		
    Instructs stack to accept packets inbound on udp 'port', 
    sending them to user-supplied 'handler' function. 
    Multiple calls can be made to
    define multiple handlers for different services can be defined.


cs_clearstats(struct cs_info *csp) {

clears network statistics

    csp : pointer to cs_info ether controller information





cs_intsetup(struct cs_info *csp) {

setup interrupts 

    csp : pointer to cs_info ether controller information.
    
    	  csp->vec needs be set to hardware interrupt vector
            prior to calling





void cs_udp_input( struct cs_info *csp, struct ip *ip) {

process incoming application udp packets 

    If a handler function has been setup via cs_udp_bind(),
    it will be called from here. Otherwise the packet is dropped.

    		csp : pointer to cs_info ether controller information
    		ip  : pointer to ip section of packet to be transmitted
    


int cs_route(struct cs_info *csp, struct ip *oip, struct ip *nip) {

Route an ip packet. 

    Determines if destination address
    is not on local LAN. Returns doctored-up packet with 
    destination IP address pointing to gateway if need be. 

    returns : 0 : if routing is necessary
              1 : if not



void cs_pbo(struct cs_info *csp) {

print buffer ownerships to debug

    	csp : pointer to cs_info ether controller information


u_char * cs_get_next_buffer( struct cs_info *csp, u_char *theirpointer, u_char theirstatcode)

Get next tx/rx buffer. Returns address of next free buffer.  

    	csp : pointer to cs_info ether controller information.
    	theirpointer : user pointer to be filled in.
    	theirstatcode : buffer ownership code to fill in.

    CS8900 receive and transmit buffers are shared. They are managed by tagging them 
    with 'ownerships' as defined in cs89udp.h: 

    	CS_BUF_AVAIL 	 	 : owned by no one. this function will pass one of these two you. 
    	CS_BUF_RX        	 : owned by receive code
    	CS_BUF_TX_ARP_WAIT   : queued but waiting dest for on an arp
    	CS_BUF_TXQ       	 : queued for transmission. 
    	CS_BUF_TX        	 : transmitted. not acked yet.
    	CS_BUF_USER 	     : owned by user
    	CS_BUF_NOFREE 	     : stack shouldn't free once xmitted. User will do it.
    	CS_BUF_ROUTED 	     : packet is being sent through gway
    	CS_BUF_NO_RE_TX 	 : don't re-tx this packet if there's a timeout

    returns : pointer to buffer
    side-effect: sets cs_info->curbuf to the index of the buffer allocated. 





void cs_free_bufp(struct cs_info *csp, u_char *theirpointer)

release the packet buffer pointed to by 'theirpointer'.
    changes ownership to CS_BUF_AVAIL

    	csp : pointer to cs_info ether controller information
    	theirpointer : address of buffer to release





void cs_free_bufi(u_char theirindex)

release the packet buffer pointed to by 'theirindex'

    	changes ownership of buffer with index 'theirindex' to CS_BUF_AVAIL
 

 

TFTP Server Library




void tftpd_init( void far *handler)

Initialize tftpd functions

    	handler : pointer to function which will be called when 
     inbound tftp packets are received





tftp_rx_handler(struct cs_info *csp, void *whatever)

This callback gets called when a udp packet
 on the previously bound-to udp port is received 





void tftpd_timeout_check(struct cs_info *csp)

Called at .1 sec intervals to take care 
    of timeout conditions during tftp activity

        csp : pointer to cs8900 ethernet controller information




void tftpd_finish_reply(struct cs_info *csp, u_char *pktbuf, struct udp *rx_udp, struct tftp *tx_tftp, short len)

Finishes filling in an packet and sends it off..

    	csp : pointer to ethernet controller information
    	pktbuf : buffer to be filled in
    	rx_udp : pointer to udp section of received packet
    	tx_tftp : pointer to tftp section of packet to be transmitted
    	len : length of tftp data 

(C) 1999 Cogwheel, Inc.  (C) 1999 Tern, Inc. All Rights Reserved

/

copyright ©2007 cogwheel incorporated   all rights reserved