Multitasking On the Cheap
by Alan Porter


Listing One

#include "wattcp.h"
#define TELNET_PORT 23
#define BUFFER_SIZE 256
int main(int argc, char ** argv) {
   tcp_Socket far Socket;
   tcp_Socket * SocketPtr;
   char Buffer[BUFFER_SIZE+1];
   int bytes;
   sock_init();
   SocketPtr=&Socket;
   // tell tcp to listen for a connection on TELNET port (23)
   // this call does not block...
   tcp_listen(SocketPtr,TELNET_PORT,0L,0,NULL,0);
   // wait for a connection
   while(!sock_established(SocketPtr)) {
      tcp_tick(NULL);
   }
   // a connection was made... send a string to the caller
   sock_mode(SocketPtr,TCP_MODE_ASCII);
   sock_puts(SocketPtr,"hello\r\n");
   // read what the caller is sending to us and print it out
   // only end when the caller disconnects
   while(tcp_tick(SocketPtr)) {
      if(sock_dataready(SocketPtr)) {
         StringFromSocket(Buffer,BUFFER_SIZE);
         bytes=sock_gets(SocketPtr,Buffer,BUFFER_SIZE);
         Buffer[bytes]=0;
         printf("received: %s", Buffer);
      }
   }
   printf("socket closed\n");
}


Listing Two

START{
   schedule CLOCK_TASK immediately
   schedule ETHERNET_TASK immediately
   schedule USER_INTERFACE_TASK immediately
   do forever
      let the "scheduler" pick a task to run
}
CLOCK_TASK{
   display time
   schedule CLOCK_TASK in 1 minute
}
ETHERNET_TASK{
   call tcp_tick()
   check ethernet input buffer
   if command waiting in queue
      process command
   schedule ETHERNET_TASK immediately
}
USER_INTERFACE_TASK{
   poll keyboard
   present the appropriate menu
   schedule USER_INTERFACE_TASK immediately
}


Listing Three

#define MAX_TASKS 50
typedef enum TypeOfTask {
   ONCE,
   REPEAT
};
typedef struct {
  boolean InUse;
  long StartTime;
  long Interval;
  TypeOfTask Type;
  void (*FunctionPtr)(void);
} Task;
static Task TaskList[MAX_TASKS];


Listing Four

/////////////////////////////////
//  TASK SCHEDULING FUNCTIONS  //
/////////////////////////////////
// add a task to the task list
boolean ScheduleTask(
   void (*FunctionPtr)(void), TypeOfTask Type, long TimeFromNow );
// remove a task from the task list
boolean UnScheduleTask(
   void (*FunctionPtr)(void) );
// determine whether or not a given task is currently scheduled to run
boolean TaskIsScheduled(
   void (*FunctionPtr)(void) );


Listing Five

////////////////////////////////
//  ADMINISTRATION FUNCTIONS  //
////////////////////////////////
typedef enum SchedulerReturns {
   SCHEDULER_SHUTDOWN, SCHEDULER_DID_SOMETHING, SCHEDULER_NOTHING_RUN
};
// clean up data structures in preparation for running
void InitializeScheduler( void );
// pick one task in the list and run it to completion
// if no tasks are ready to run, simply return
SchedulerReturns RunOneTask( void );
// set a flag that tells the scheduler to stop running
void ShutdownScheduler( void );


Listing Six

(a)
void MainMenu(void) {
  char kb;
  DrawMainMenu();
  // wait until user presses a key
  kb=WaitForKeyPress();
  switch(kb) {
    case EXIT:
      return;
    case OPTION_1:
      Option1();
      break;
    case OPTION_2:
      Option2();
      break;
    case OPTION_3:
      Option3();
      break;
  }
}

(b)
void MainMenu(void) {
  // initialize stuff here
  DrawMainMenu();
  ScheduleTask(MainMenuLoop,ONCE,0);
}
void MainMenuLoop(void) {
  char kb;
  // do not wait...
  // poll keyboard buffer once only
  kb=PollForKeyPress();
  switch(kb) {
    case EXIT:
      ScheduleTask(PreviousMenu,ONCE,0);
      return;
    case OPTION_1:

      ScheduleTask(Option1Menu,ONCE,0);
      return;
    case OPTION_2:
      ScheduleTask(Option2Menu,ONCE,0);
      return;
    case OPTION_3:
      ScheduleTask(Option3Menu,ONCE,0);
      return;
  }
  // if no key press of interest, then poll MainMenuLoop() again soon
  ScheduleTask(MainMenuLoop,ONCE,0);
}





