Digital clock for my PC XT compatible, or having fun with Borland Graphics Interface (BGI)

Yet another day “wasted” playing with my Pravetz 16. Really I should sit on my … and do some real work, but the battery of my wall clock died and I decided to code myself a digital one 🙂

The clock in action
The clock in action

The clock is written on C using Borland Graphics Interfaces also knows as BGI. The most easy and video hardware independent option for doing graphics under DOS. BGI comes bundled with drivers for common back then graphic adapters (CGA, VGA and EGA) and vector fonts.

There are other options such as using interrupt 10h or writing directly to the graphics hardware like most of the games were doing back then.

To build the code fire up the Turbo C IDE, go to Options->Linker and check “Graphics library”, then proceed as usual.

Turbo C Linker options
Turbo C Linker options

Compiled version of the CLOCK.EXE can be obtained from here and the source code (if you don’t like Ctrl + C & Ctrl + V) is here.

Wen I got some free time and motivation I will probably enhance the clock with some neat options such as 12/24 hours mode, moving objects in the background, drawing the “Pravetz” logo in the upper left corner of the screen, command line parameters for setting an alarm etc…

If you wan’t to learn more about BGI review the examples that comes with Turbo C such as BARCHART.C. View the GRAPHICS.H header. Also take a look here.

Code listing a.k.a “The Digital Clock” source 🙂

#include <stdio.h>
#include <dos.h>
#include <graphics.h>
 
#define TIME_BUF_LEN 6
#define DATE_BUF_LEN 10
 
#define TIME_TEXT_TEMPLATE "00:00"
#define DATE_TEXT_TEMPLATE "00.00.0000"
 
#define NOTE_TEXT "Press any key to exit..."
 
#define BGI_LOCATION "C:\\TC\\bgi"
 
int gl_nMaxX = 0;
int gl_nMaxY = 0;
 
int gl_nCenterX = 0;
int gl_nCenterY = 0;
 
char gl_szTimeBuff[TIME_BUF_LEN];
char gl_szDateBuff[DATE_BUF_LEN];
 
int initGraphics( void )
{
	int nGraphicDriver = DETECT; 
	int nGraphMode;
	int nErrorCode;
 
	/* Initialize graphics system */
	initgraph(&nGraphicDriver, &nGraphMode, BGI_LOCATION);
	nErrorCode = graphresult();
 
	if (nErrorCode != grOk)
	{
	   return -1;
	}        
 
	/* Graphics OK, so return "true" */
	return 1; 
}
 
void drawNote()
{
	int textWidth, textHeight;
 
	settextstyle(DEFAULT_FONT, HORIZ_DIR, 0);
 
	textWidth = textwidth(NOTE_TEXT);
	textHeight = textheight(NOTE_TEXT);
 
	outtextxy(gl_nMaxX - textWidth,
			  gl_nMaxY - textHeight,
			  NOTE_TEXT);
}
 
void drawTime(struct time *pTime)
{
	int textWidth, textHeight;
 
	settextstyle(SANS_SERIF_FONT, HORIZ_DIR, 8);
 
	textWidth = textwidth(TIME_TEXT_TEMPLATE);
	textHeight = textheight(TIME_TEXT_TEMPLATE);
 
	sprintf(gl_szTimeBuff, "%02d:%02d", pTime->ti_hour, pTime->ti_min);
 
	outtextxy(gl_nCenterX - (textWidth / 2), 
			  gl_nCenterY - textHeight, 
			  gl_szTimeBuff);
}
 
void drawDate(struct date *pDate)
{
	int textWidth;
 
	settextstyle(SANS_SERIF_FONT, HORIZ_DIR, 6);
 
	textWidth = textwidth(DATE_TEXT_TEMPLATE);
 
	sprintf(gl_szDateBuff, 
			"%02d.%02d.%d", 
			pDate->da_day, 
			pDate->da_mon, 
			pDate->da_year);
 
	outtextxy(gl_nCenterX - (textWidth / 2), gl_nCenterY, gl_szDateBuff);
}
 
int main(void)
{
	struct time sysTime, startTime;
	struct date sysDate, startDate;	
 
	if(initGraphics() == -1)
	{
		printf("Error initializing BGI!\n");
		return 0;
	}
 
	gl_nMaxX = getmaxx();
	gl_nMaxY = getmaxy();
 
	gl_nCenterX = (getmaxx() / 2);
	gl_nCenterY = (getmaxy() / 2);		
 
	drawNote();
 
	gettime(&startTime);
	drawTime(&startTime);
 
	getdate(&sysDate);
	drawDate(&sysDate);
 
	while(!kbhit())
	{										
		gettime(&sysTime);
 
		/*
		 * To avoid flickering, redraw the screen only if there are 
		 * changes in the hour or minute values. Only some VGA and EGA
		 * drivers support 'setactivepage()' and 'setvisualpage()'.
		 */
		if(sysTime.ti_hour > startTime.ti_hour || 
		   sysTime.ti_min > startTime.ti_min)
		{
			cleardevice();
			getdate(&sysDate);
 
			drawNote();
			drawTime(&sysTime);
			drawDate(&sysDate);
 
			gettime(&startTime);
		}
	}
 
	closegraph();
 
	return 0;
}

SINFO.EXE or playing with bios interrupts on my PC XT clone

I am stuck with a problem in the game I work on for several days now. When I’m stuck I usually do something else for a couple of hours. For example playing with bios interrupts on my PC XT clone (which by the way is completely restored, but more on this in the upcoming posts).

Pravetz 16 (IBM PC XT clone)
Pravetz 16 (IBM PC XT clone) and yes that’s Windows 3.0.

NOTE: Writing code on monochrome monitor is something that every software developer should do at least ones in his career 🙂

What’s interrupt? (From Wikipedia articles on interrupts)

In system programming, an interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention. An interrupt alerts the processor to a high-priority condition requiring the interruption of the current code the processor is executing. The processor responds by suspending its current activities, saving its state, and executing a function called an interrupt handler (or an interrupt service routine, ISR) to deal with the event. This interruption is temporary, and, after the interrupt handler finishes, the processor resumes normal activities.[1] There are two types of interrupts: hardware interrupts and software interrupts.

The code below calls software interrupts 11h (Equipment Installed) and 12h (Memory Available) using inline assembly. To compile the source you will need Turbo C and TASM. They both run perfectly fine under DOSBox.

The executable is available for download here.

#include 
 
int main(void)
{
  int systemInfo;
  int floppyCount;
  int mem, memSize, memSizePost;
  int videoMode;
  int serialPorts;
  int paralelPorts;
 
  /* Call INT 11h ( Equipment Installed ) */
  asm int 11h;
  asm mov systemInfo, ax;
 
  /* Call INT 12h ( Memory Available ) */
  asm int 12h;
  asm mov memSizePost, ax;
 
  printf("********** SYSTEM INFO ***********\n");
  printf("Floppy drive(s): %s ", (systemInfo &amp; 0x0001) ? "yes" : "no");
 
  if((systemInfo &amp; 0x0001))
  {
    switch((systemInfo &amp; 0x00C0))
    {
      case 0:
      {
		floppyCount = 1;
		break;
      }
      case 64:
      {
		floppyCount = 2;
		break;
      }
      case 128:
      {
		floppyCount = 3;
		break;
      }
      case 192:
      {
		floppyCount = 4;
		break;
      }
    }
 
    printf("(%d)\n", floppyCount);
  }
  else
  {
    printf("\n");
  }
 
 
  printf("Math co-processor: %s\n", (systemInfo &amp; 0x0002) ? "yes" : "no");
 
  mem = (systemInfo &amp; 0x000C);
 
  switch(mem)
  {
    case 0:
    {
      memSize = 16;
      break;
    }    
    case 4:
    {
      memSize = 32;
      break;
    }
    case 8:
    {
      memSize = 48;
      break;
    }
    case 12:
    {
      memSize = 256;
      break;
    }
  }
  printf("On-board memory: %d K%s\n", memSize, (memSize &gt;= 256) ? "+" : " ");
  printf("Memory reported by BIOS POST: %dK\n", memSizePost);
 
  videoMode = (systemInfo &amp; 0x0030);
  switch(videoMode)
  {
    case 0:
    {
      printf("Video mode: EGA, VGA or PGA\n");
      break;
    }
    case 16:
    {
      printf("Video mode: CGA, 40 x 25\n");
      break;
    }
    case 32:
    {
      printf("Video mode: CGA, 80 x 25\n");
      break;
    }
    case 48:
    {
      printf("Video mode: monochrome, 80 x 25\n");
      break;
    }
  }
 
  printf("DMA support: %s\n", (systemInfo &amp; 0x0100) == 0 ? "yes" : "no");
  printf("Game adapter: %s\n", (systemInfo &amp; 0x1000) == 0 ? "no" : "yes");
 
  switch((systemInfo &amp; 0x0E00))
  {
    case 0:
    {
      serialPorts = 0;
      break;
    }
    case 512:
    {
      serialPorts = 1;
      break;
    }
    case 1024:
    {
      serialPorts = 2;
      break;
    }
    case 1536:
    {
      serialPorts = 3;
      break;
    }
    case 2048:
    {
      serialPorts = 4;
      break;
    }
  }
  printf("Serial ports: %d\n", serialPorts);
 
  switch((systemInfo &amp; 0xC000))
  {
    case 0:
    {
      paralelPorts = 0;
      break;
    }
    case 16384:
    {
      paralelPorts = 1;
      break;
    }
    case 32768:
    {
      paralelPorts = 2;
      break;
    }
    case 49152:
    {
      paralelPorts = 3;
      break;
    }
  }
  printf("Paralel ports: %d\n", paralelPorts);
 
  return 0;
}

Diskettes for the Pravetz

I finally got my hands on some 51/4” diskettes for the Pravetz. They are in good condition and full of old games and programs. There is also a pack of cleaning diskettes for the floppy drive. I’m still looking for more.

20141031_155918I’m inpatient to find a monitor, to see if this dinasour runs.

 

Restoration of Pravetz-16 Turbo (IBM PC XT compatible)

My software development career started 20 years ago. It’s sound crazy, but when I was 8, I was introduced to my first computer and Turbo Pascal.

Turbo Pascal DOS IDE
Turbo Pascal IDE

My first computer was Pravetz-16. It was something new and interesting for me, and I was hooked immediately.

Years and technology changed, the old Pravetz died from natural causes and was thrown for recycling.

Now almost 20 years later I felt the urge to have my old computer back and stated searching.  It was hard and long search until finally I saw an ad that a scrap depot is selling an old Pravetz computer. Not wasting time I called them and brought it for 100 leva ( around 70 USD ). It was the computer only, with ought the peripherals. Before the deal  I asked them to try turning it on. They said it’s starting, so I have it delivered to me.

20141029_130735
Front view of the PC

Except from being full of dust, dead spiders and dirt all around and with some minor hardware problems like the serial board apparently dead. This specimen was almost authentic. It’s still has all the marks from the factory and even a warranty card and instruction manual for the floppy disk.

20141029_125502
Warranty card. Expired 24 years ago

From the warranty card I found out that this PC was one of the last produced before the collapse of the communist regime in Bulgaria. The production date is 12.12.1989 and it’s apparently the turbo version with the following specs:

CPU: 80286 at 12 Mhz
RAM: 1 MB
HDD: 20 MB
5 1/4″ Inch Floppy drive
LPT printer port
COM port
CGA video card (VDO-3)

The floppy drive instruction manual
Floppy drive instruction manual
The support contact information
Support contact information sticker
The model sticker at the back
Model sticker at the back
Inside of the PC
Inside of the PC
The power switch
The power switch
View from the back. You can see couple of dead spiders over the video card
View from the back. You can see couple of dead spiders over the video card

It took me 7 hours to disassemble the PC, clean it screw by scree and put it back together. Every non electrical part was washed and the electrical ones were cleaned with alcohol solution and an old tooth brush. The old Pravetz now shines as new.

20141029_211651 20141029_211720I also found a keyboard yesterday, and ordered a pile of floppy disks. They should be here soon.

The keyboard
The keyboard

Now I’m looking for a CGA monitor, to be finally able to turn it on and see will it boot. Meanwhile the keyboard will be disassembled and cleaned.

 

GoClever GC-4366FMBT firmware

After a long time of collecting dust I decided that I should resurrect my broken GPS navigation – GoClever GC-4366FMBT.

goclever_4366_fmbt_tmc_bBy resurrecting I mean removing GeoShell and the cracked Garmin using PortSplitter because of who my original Mireo GPS navigation wasn’t working. It was crashing on the “Attaching GPS…” message while loading.

Trying various methods to fix the problem all unsuccessful I finally decided that I should re-install the firmware of the GPS. After searching “past the first page of Google” (it was hell of a search and the trial and error method ) I finally found a suitable firmware for GoClever-GC4366FMBT, Mireo Black Edition 3.1 and the newest maps for Bulgaria, Romania, Greece, Macedonia and Serbia. Now the GPS is working again 🙂

Here is how to re-install the firmware of the device (links for firmware download included) and how to setup the navigation software.

Firmware installation

1.Download GoClever-GC-4366FMBT-Firmware.zip and extract it.
2.Copy the contents of the archive on an SD card and insert the card in the GPS
3.Turn on the device. The device will boot and will start to update the firmware

20131105_2202584. After a few minutes you will be ready. The default language of the device after the update will be Polish. Change it to your preference by navigating to the settings icon and than to the language icon.

Don’t forget to delete the firmware files from the SD card or next time you turn on the GPS the process will start again.

Mireo viaGPS v3.1 installation

After firmware installation the device will loose it’s GPS software ( it will do if you like me don’t do a backup of the ‘MobileNavigator’ folder from the ‘Resident Flash’ )

Download Mireo viaGPS Black Edition v3.1 (detailed map of Bulgaria included) extract the archive and rename the extracted folder ‘MobileNavigator’. Copy ‘MobileNavigator’ to your resident flash or SD card. Start the device and select Navigate. That’s it. You have a working GPS navigation with updated stock software and maps.

Here is an archive with detailed maps of Bulgaria, Greece, Romania, Macedonia and Serbia as of 2012-06. If you look hard enough you will find complete map of Europe dating 2012-06.

NOTE: The license for the 3D MAPS in the archive a bough is not working