/*********************************************************************************
 *** Battmem.bat - Display status saved in battery-backed memory registers.    ***
 ***               This examples programs displays how to use CEnvi to read    ***
 ***               data from hardware ports, and how to manipulate bits within ***
 ***               a byte.                                                     ***
 *********************************************************************************/

printf("These are values read from battery-operated memory:\n");

#define  CLOCK_ADDRESS_REG    0x70  // put address to read here
#define  CLOCK_READ_REG       0x71  // read value from address
#define  BLANK_LINE           printf("\n")

BLANK_LINE
/*****************************************************/
/* SHOW ERRORS THAT MAY OCCUR IN THE DIAGNOSTIC BYTE */
/*****************************************************/
#define  DIAGNOSTIC_REG_ADDRESS  0x0E
#define  DIAG_BYTES_UNUSED       0x03
#define  DATETIME_ERROR          0x04
#define  HARD_DRIVE_ERROR        0x08
#define  MEMSIZE_ERROR           0x10
#define  BAD_CONFIG_BYTE         0x20
#define  CHECKSUM_ERROR          0x40
#define  DEAD_CLOCK_BATTERY      0x80

diag = ReadByte(DIAGNOSTIC_REG_ADDRESS) & ~DIAG_BYTES_UNUSED
if ( 0 == diag )
   printf("No errors in the Diagnostic Byte Structure.\n")
else {
   if ( diag & DATETIME_ERROR )
      printf("Date or time incorrect!\a\n")
   if ( diag & HARD_DRIVE_ERROR )
      printf("Hard drive or controler error!\a\n")
   if ( diag & MEMSIZE_ERROR )
      printf("Memory size incorrect!\a\n")
   if ( diag & BAD_CONFIG_BYTE )
      printf("Configuration byte is incorrect!\a\n")
   if ( diag & CHECKSUM_ERROR )
      printf("Checksum incorrect!\a\n")
   if ( diag & DATETIME_ERROR )
      printf("Realtime battery clock is dead!\a\n")
}

BLANK_LINE
/*******************************/
/* STATUS AT SYSTEM POWER DOWN */
/*******************************/
#define  POWERDOWN_REG     0x0F
printf("Status at system powerdown = %d\n",ReadByte(POWERDOWN_REG))


BLANK_LINE
/***********************************/
/* STATUS OF FIRST TWO DISK DRIVES */
/***********************************/
#define  DRIVETYPE_REG     0x10
DriveTypes = ReadByte(DRIVETYPE_REG)
printf("The first floppy drive is type: %s\n", DriveDescription(Bits(DriveTypes,4,4)) )
printf("The second floppy drive is type: %s\n", DriveDescription(Bits(DriveTypes,0,4)) )

DriveDescription(type)
{
   switch( type ) {
      case 0
         description = "Not Installed"
         break
      case 1
         description = "5-1/4, 320/360K"
         break
      case 2
         description = "5-1/4, 1.2 meg"
         break
      case 3
         description = "3-1/2, 720K"
         break
      case 4
         description = "3-1/2, 1.44 meg"
         break
      default
         sprintf(description,"Unknown drive type %d",type)
         break
   }
   return(description)
}


BLANK_LINE
/***************************************/
/* SHOW TYPES OF FIRST TWO HARD DRIVES */
/***************************************/
#define  HARD_DRIVE_1_REG     0x11
#define  HARD_DRIVE_2_REG     0x12
printf("Hard drive 1 is type %d\n",ReadByte(HARD_DRIVE_1_REG))
printf("Hard drive 2 is type %d\n",ReadByte(HARD_DRIVE_2_REG))


BLANK_LINE
/**********************************/
/* SHOW CONFIGURATION INFORMATION */
/**********************************/
#define  CONFIGURATION_REG    0x14
#define  NO_DRIVE_OFFSET      0
#define  COPROCESSOR_OFFSET   1
#define  HARDDRIVE_ERROR_OFF  3
#define  VIDEO_STARTUP_OFF    4
#define  VIDEO_STARTUP_COUNT  2
#define  DISK_DRIVE_COUNT_OFF 6
#define  DISK_DRIVE_COUNT_NUM 2
config = ReadByte(CONFIGURATION_REG)
printf("At lease 1 disk drive is%s installed.\n",Bits(config,NO_DRIVE_OFFSET,1) ? "" : " NOT" )
printf("Math coprocessor is%s installed.\n",Bits(config,COPROCESSOR_OFFSET,1) ? "" : " NOT" )
if Bits(config,HARDDRIVE_ERROR_OFF,1)
   printf("Hard drive or controller error.\n")
printf("Video mode at startup is: ")
switch( Bits(config,VIDEO_STARTUP_OFF,VIDEO_STARTUP_COUNT) ) {
   case 0      printf("unknown.\n")                   break
   case 1      printf("CGA/EGA/VGA, 40 columns.\n")   break
   case 2      printf("CGA,EGA,CGA, 80 columns.\n")   break
   case 3      printf("MDA/Hercules, 80 columns\n")   break
}
printf("Number of disk drives = %d.\n",Bits(config,DISK_DRIVE_COUNT_OFF,DISK_DRIVE_COUNT_NUM))


BLANK_LINE
/***********************************************/
/* SHOW MAIN MEMORY AND EXPANSION MEMORY SIZES */
/***********************************************/
#define  MEM_SIZE_REG         0x15
#define  EXPANSION_MEM_REG    0x17
#define  EXPANSION2_REG       0x30
printf("Main memory size = %d K-bytes\n",ReadWord(MEM_SIZE_REG))
printf("Expansion board's main memory size = %d K-bytes\n",ReadWord(EXPANSION_MEM_REG))
printf("Expansion memory size = %d K-bytes\n",ReadWord(EXPANSION2_REG))


BLANK_LINE
/***************************/
/* TIME, DATE, AND CENTURY */
/***************************/
#define  CENTURY_REG       0x32
#define  CLOCK_STATUS_REG  0x0B
century = ReadByte(CENTURY_REG)
printf("Century is: %d%d00\n",Bits(century,4,4),Bits(century,0,4))
clock = ReadByte(CLOCK_STATUS_REG)
printf("Daylight savings time is%s in effect.\n",Bits(clock,0,1) ? "" : " not" )
printf("Time is kept in %d hour format.",Bits(clock,1,1) ? 24 : 12 )

/***************************************************************/
/* All done; wait until a key is pressed or the program closed */
/***************************************************************/
getch();

/******************************************/
/* UTILITY FUNCTIONS USED IN THIS PROGRAM */
/******************************************/

Bits(ByteValue,BitOffset,BitCount)
   // return specific bits in a byte, and shift them to the right.
{
   // clear all bits above BitCount
   for ( mask = 0, i = 0; i < BitCount; i++ )
      mask |= 1 << i
   return((ByteValue >> BitOffset) & mask)
}

ReadByte(RegisterAddress)
{
   outport(CLOCK_ADDRESS_REG,RegisterAddress)
   return(inport(CLOCK_READ_REG))
}

ReadWord(RegisterAddress)
{
   return( ReadByte(RegisterAddress) | ( ReadByte(RegisterAddress+1) << 8 ) )
}

