// This is the main module of a terminal emulator program
// to replace PCPLUS for in-house test applications.
// compiler: Borland 3.1, DOS real mode
// author: Timothy Fox
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include <dir.h>
#include <dos.h>
#include "typedefs.h"
#include "abcconst.h"
#include "commutil.h"
#include "abcscrn.h"
#include "abckbd.h"
#include "abctabs.h"
#include "tsio.h"
#include "dostimer.h"
#include "flashdta.h"
#include "jultime.h"
#include "mmx_info.h"
#pragma option -r-
static BOOL DONE = FALSE, hooked = FALSE;
void end_program(void)
{
// TO DO: put up a dialog window
// Ask the user to confirm the EXIT command
DONE = TRUE;
}
static
void pause(UINT ticks)
{
run_timer(pause_timer, ticks);
while (!timer_done(pause_timer)) { }
}
static int mm_done;
static
void fkeyproc(void)
{
switch (getch()) {
case 0x3b: // F1 - help
cputs("\n");
cputs("Modem Manager commands:\n");
cputs(" F1 - Help\n");
cputs(" F2 - Copy non-volatile memory to disk\n");
cputs(" F3 - Copy disk to non-volatile memory\n");
cputs(" F4 - Copy flash memory to disk\n");
cputs(" F5 - Copy disk to flash memory\n");
cputs("\n");
break;
case 0x3c: // F2 - copy non-volatile memory to disk
read_nvram_data();
if (nvram_loaded()) {
if ((fp = fopen("NVRAM.DAT", "wb")) == NULL) {
cputs("Failed to open NVRAM.DAT\n");
}
else {
cputs("Write non-volatile memory to disk\n");
fwrite(nvram_data, 0x1800, 1, fp);
fclose(fp);
cputs("Ready\n");
}
}
break;
case 0x3d: // F3 - Copy disk to non-volatile memory
cputs("Read non-volatile data from disk\n");
if ((fp = fopen("NVRAM.DAT", "rb")) == NULL) {
cputs("Failed to open NVRAM.DAT\n");
}
else {
load_nv_file();
write_nvram_data();
}
break;
case 0x3e: // F4 - Copy flash memory to disk
recv_flash_data();
if (flash_loaded()) {
save_flash_file();
}
break;
case 0x3f: // F5 - Copy disk to flash memory
load_flash_file(current_ID(), current_image_type());
if (flash_loaded()) {
xmit_flash_data();
}
break;
}
}
static
void keyproc(void)
{
if (0 == kbhit()) return;
switch (getch()) {
case 0: // function keys
fkeyproc();
break;
case ESC:
mm_done = 1;
break;
default:
COM_OUT(c);
}
}
static
void process_mm (void) {
#define MAXSHUFFLE 16
#define IDLE_LIMIT 30 // seconds
ULONG jul_start, jul_now;
mm_done = 0;
send_command("READY\r","",0);
jul_start = julian_now();
while (!mm_done) {
jul_now = julian_now();
if ((jul_now - jul_start) > IDLE_LIMIT) {
cputs("\nController idle time exceeded. Abandoning update...");
return;
}
if (_shuffle())
jul_start = julian_now();
keyproc();
// "\x1B[" is the ANSI terminal escape marker
if (shuffle_contains("\x1b["))
return;
if (shuffle_contains("DEFINE_BIN\r")) {
recv_flash_data() ;
jul_start = julian_now();
}
if (shuffle_contains("DEFINE_ID\r")) {
recv_device_ID() ;
jul_start = julian_now();
}
} // while !mm_done
return;
}
int main (int _argc, char *_argv[])
{ UINT portx, rxc;
char drive[MAXDRIVE];
char dir[MAXDIR];
char file[MAXFILE];
char ext[MAXEXT];
if (_argc > 1) {
portx = atoi(_argv[1]);
if ((portx < 1) || (portx > 2)) {
cputs("\r\n The COM port you specify must be either '1' or '2'.");
cputs("\r\n You asked for port '");
cputs(_argv[1]);
cputs("'.\n");
return 0;
}
}
else {
fnsplit(_argv[0],drive,dir,file,ext);
cputs("\r\nWhen you start this program, you must specify");
cputs("\r\nthe communication port ('1' or '2') to use.");
cputs("\r\n\nFor example, ");
cputs(file);
cputs(" 1");
cputs("\r\n\nconnects to the Test Rack via COM1: \n");
return 0;
}
portx--;
setup_comport(irqnumbr[portx], baseaddr[portx]);
set_COMPARMS(0x03); // "8N1"
SET_BAUD_RATE(12); // 9600 baud
INSTALL_RTC_ISR();
hooked = TRUE;
setup_comport(irqnumbr[portx], baseaddr[portx]);
pause(10);
teardown_comport();
pause(10);
setup_comport(irqnumbr[portx], baseaddr[portx]);
init_vt_scrn();
refresh_ANSI_stats();
textattr((BLUE << 4) | LIGHTGRAY);
erase_all();
while (host_rx_count())
COM_IN(); // eat any burst of chars from startup
cputs("\nABC Terminal ready ");
if (!DSR_STATUS())
cputs("\r\n\n waiting for DSR ... ");
do {
if (host_rx_count())
break;
keyboard();
if (DONE) break;
} while (!DSR_STATUS());
cputs("\r\n\n");
do {
if (host_rx_count()) {
rxc = (COM_IN());
if (rxc == ENQ) {
COM_OUT(ACK);
// clear the screen, and wait for rx activity to stop
clrscr();
run_timer(COM_timer, 50);
while (!timer_done(COM_timer)) ;
cputs("\r\n\n Update server active ...\r\n");
if (setup_flashbuf()) {
process_mm();
}
// wait for tx queue to be empty
while (host_tx_count()) ;
run_timer(COM_timer, 30);
while (!timer_done(COM_timer)) ;
}
else {
handle_rx(rxc);
}
}
keyboard();
} while (!DONE);
clrscr();
return 0;
}
#ifdef __cplusplus
#define __CPPARGS ...
#else
#define __CPPARGS
#endif
#define CTRL_C 0x23
void interrupt (* old_ctrl_C) (__CPPARGS);
void leave_abc(void)
{
setvect(CTRL_C, old_ctrl_C);
if (hooked) {
teardown_comport();
REMOVE_RTC_ISR();
hooked = FALSE;
}
}
void interrupt ctrl_C(__CPPARGS)
{
leave_abc(); // restore all the hooked interrupts
clrscr();
_exit(1);
}
void init_abc(void)
{
old_ctrl_C = getvect(CTRL_C); // save the old ctrl-C vector
setvect(CTRL_C, ctrl_C);
}
#pragma startup init_abc
#pragma exit leave_abc