This document describes the original 1996 first-generation HotBits software driver, which was tailored to work with the first-generation custom hardware detector. This document is for historical reference only; please see the third-generation HotBits driver description if you are interested in interfacing the current generator as used at Fourmilab.
The following C program monitors the COM port to which the HotBits interface box is attached, measures the delay for a pair of counts, and returns the resulting random bits in a variety of forms. This module is intended to run under Windows 95, and by default uses the Windows GetTickCount API call to implement a power-on delay to avoid start-up transients. If you wish to use this code without Windows, simply replace the delay loop with the equivalent for your system (or do the delay in your own program, after calling hotbitsPower).
You can configure the driver to use in-line assembly code to measure the inter-count delays, or call the _inp and _outp functions to perform I/O. The assembly code is far more accurate and, since it prevents interrupts while making the measurement, invulnerable to interrupt-induced periodicities in the results—the assembly code should be used for all production applications. The _inp and _outp option is provided only to enable debugging or experimentation on compliers that don't support in-line assembly.
Note that this code is intended to be run on a dedicated machine, not a Windows machine running other interactive applications. In order to accurately time the interval between counts in software, it's necessary to lock out interrupts for the duration of the measurement. If a large number of bits are being generated, this essentially freezes up the machine, which is fine on a dedicated machine but intolerable if you're running other programs. Also, note that no emergency escape is provided in case the counter stops sending pulses—the machine will just hang. An emergency escape timeout runs the risk of polluting the data since it is theoretically possible (although of vanishing probability if you're using an artificial radiation source) for an arbitrarily long interval to separate two counts. But if you're using background radiation as your source, the risk of an escape timeout long enough to be useful becomes significant. If you want to add an escape, it's easy enough to do.
The driver program and its companion header file containing function prototypes is available for downloading as a ZIPped archive.
This module is integrated into the HTTP server program which processes HotBits requests.
if (readerToleranceOfRantsAboutMicrosoft.OnFlame()) {
I'm not making the server program or even my modifications to it available because it is written as a gnarly Microsoft Foundation Classes (MFC) application, and while I am perfectly willing to use anything to get an in-house job done with as little time and effort as possible, distributing MFC code to others would make me an accessory to the intellectual pollution of our industry which is causing a generation of young people to never discover the joy and beauty of programming, to believe that no project can ever be truly finished, to accept “standards” which change every time Bill Gates changes his volatile mind, and to suppose the quality of software delivered by Microsoft to be the best achievable. I don't intend, in saying this, to in any way attack the author of the HTTP server, or his program. He is obviously a very talented programmer who has written a program that is both useful and instructive to examine, which saved me a tremendous amount of time and effort in developing HotBits. The author did everything in his program precisely the way Microsoft tells you to (this week), and that's precisely the problem.
For most of the nearly 30 years I've been programming, I have become accustomed to software which, albeit shaky at the start, eventually evolves to a state of maturity where it can serve as a stable platform for other software to be built on top of it. Microsoft, instead, continually shake the underlying platform, destabilising everything which is built upon it, and do so, I have come to believe, deliberately with the intent of increasing the costs to competitors of remaining in the Windows market, and providing their own products a time-to-market edge since in-house developers have first access to information about forthcoming deliberate strategically-motivated incompatibilities. If you're the biggest player in the market, by a wide margin, you can afford the additional in-house investment created by strategic incompatibility, but the cost to smaller marginal players can be unbearable, causing them to fall behind and/or drop out, to Microsoft's advantage. What is tragic about all of this is that it is consuming thousands of man-years of labour by talented programmers, forcing users to accept unreliable, deliberately over-complicated, and hostile applications, and all unnecessarily. As one who knows from direct personal experience that it doesn't have be this way, I'm not going to further contribute to this corruption of what personal computing could and should have been, and which I still hope, may still become.
}
/* HotBits Generator Driver by John Walker http://www.fourmilab.ch/ This program is in the public ___domain. */ #define ASSEMBLY /* Use assembly language interval measurement */ #define ON_WAIT 500 /* Power on delay in milliseconds */ #ifdef hotbitsTRACE #include <stdio.h> #endif #ifndef ASSEMBLY #include <conio.h> #endif #ifdef ON_WAIT #include <windows.h> #endif /* Serial I/O port properties */ static short commbase = 0x3F8; /* Serial port UART base address */ #define BUFFER commbase + 0x0 /* I/O buffer */ #define IENABLE commbase + 0x1 /* Interrupt enable */ #define LINECTL commbase + 0x3 /* Line control register */ #define MODEMCTL commbase + 0x4 /* Modem control register */ #define MODEMSTAT commbase + 0x6 /* Modem status word */ #ifdef hotbitsTRACE int hotbitsTrace = 0; #endif /* HOTBITSINIT -- Initialise the generator. Pass the UART base port address as portaddr; this is usually: COM1 0x3F8 COM2 0x2F8 COM3 0x3E8 COM4 0x2E8 */ void hotbitsInit(int portaddr) { commbase = portaddr; #ifndef ASSEMBLY _outp((unsigned short) (LINECTL), 0x03); /* Make sure not setting baud rate */ _outp((unsigned short) (IENABLE), 0); /* Disable all interrupts */ _outp((unsigned short) (MODEMCTL), 0x03); /* Enable DTR and RTS to power the apparatus */ #else _asm { mov dx,commbase add dx,3 mov al,3 out dx,al ; LINECTL = 3 mov dx,commbase inc dx xor al,al out dx,al ; IENABLE = 0 mov dx,commbase add dx,4 mov al,3 out dx,al ; MODEMCTL = 3 (power initially on) } #endif } /* HOTBITSPOWER -- Turn the sensor power on or off. */ void hotbitsPower(int turnon) { static char modemctl; modemctl = turnon ? 3 : 0; #ifndef ASSEMBLY _outp((unsigned short) (MODEMCTL), modemctl); #else _asm { mov dx,commbase add dx,4 mov al,modemctl out dx,al } #endif #ifdef ON_WAIT /* If we're powering up, wait a while to let the counter stabilise after any power-on transients. This is done in an way unkind to Windows, but what the Hell, Windows has been unkind enough to me. Besides, this is supposed to be run on an essentially dedicated machine. */ if (turnon) { MSG msg; DWORD start = GetTickCount(); while (TRUE) { DWORD now = GetTickCount(); if (now < start) { start = GetTickCount(); } else if ((now - start) > ON_WAIT) { break; } PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); } } #endif } /* HOTBITSBIT -- Obtain next random bit from the generator. */ int hotbitsBit(void) { int i; static int flipper = 0; long length[2]; #ifndef ASSEMBLY register #endif long counter; while (1) { for (i = 0; i < 2; i++) { #ifdef ASSEMBLY _asm { mov bx,0 ; Clear interval counter... mov cx,0 ; ...which is 32 bits mov dx,commbase ; Load UART base address add dx,6 ; Get modem status register address wait1: in al,dx ; Wait out current pulse, if any and al,10h jnz wait1 cli wait2: in al,dx ; Wait until next pulse begins and al,10h jz wait2 wait3: in al,dx ; Wait until down/up transition of this pulse add cx,1 adc bx,0 and al,10h jnz wait3 wait4: in al,dx ; Wait until start of next pulse add cx,1 adc bx,0 and al,10h jz wait4 sti mov word ptr counter,cx mov word ptr counter+2,bx } #else counter = 0; while ((_inp(MODEMSTAT) & 0x10) != 0) ; while ((_inp(MODEMSTAT) & 0x10) == 0) ; while ((_inp(MODEMSTAT) & 0x10) != 0) ; while ((_inp(MODEMSTAT) & 0x10) == 0) { counter++; } while ((_inp(MODEMSTAT) & 0x10) != 0) ; #endif length[i] = counter; #ifdef hotbitsTRACE if (hotbitsTrace) { printf("Interval %d: %ld\n", i, counter); } #endif } if (length[0] != length[1]) { /* There remains the possibility of a very slight bias due to long-term effects such as ionisation of a Geiger tube, poisoning of a silicon detector, or (absurdly small for any practical source) decrease in radioactivity of the source over time. To mitigate this, we invert the sense of the magnitude test between the first and second samples for alternate samples. This pushes the effect of any long-term bias to a much higher order effect. */ flipper ^= 1; return flipper ^ (length[0] > length[1]); } } } /* HOTBITSBYTE -- Return a byte of 8 random bits. */ int hotbitsByte(void) { unsigned char ch; int i; for (i = 0; i < 8; i++) { ch = (ch << 1) | hotbitsBit(); } return ch; } /* HOTBITSBUFFER -- Fill a buffer with random bits. */ void hotbitsBuffer(void *buffer, int nbytes) { unsigned char *cp = (unsigned char *) buffer; while (nbytes-- > 0) { *cp++ = hotbitsByte(); } }
![]() |