d048b845e4
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
177 lines
4.1 KiB
C
177 lines
4.1 KiB
C
/*
|
|
* redeye.c
|
|
*
|
|
* This file is part of Emu48
|
|
*
|
|
* Copyright (C) 2011 Christoph Gießelink
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
#include "Emu48.h"
|
|
#include "io.h"
|
|
|
|
#define ERR_CHAR 127 // character for transfer error
|
|
|
|
#define H1 0x78
|
|
#define H2 0xE6
|
|
#define H3 0xD5
|
|
#define H4 0x8B
|
|
|
|
// HP redeye correction masks
|
|
static CONST BYTE byEmask[] = { H1, H2, H3, H4 };
|
|
|
|
static __inline UINT MAX(UINT a, UINT b)
|
|
{
|
|
return (a>b)?a:b;
|
|
}
|
|
|
|
static __inline BYTE Parity(BYTE b)
|
|
{
|
|
b ^= (b >> 4);
|
|
b ^= (b >> 2);
|
|
b ^= (b >> 1);
|
|
return b & 1;
|
|
}
|
|
|
|
static __inline BYTE CreateCorrectionBits(BYTE b)
|
|
{
|
|
UINT i;
|
|
BYTE byVal = 0;
|
|
|
|
for (i = 0; i < ARRAYSIZEOF(byEmask);++i)
|
|
{
|
|
byVal <<= 1;
|
|
byVal |= Parity((BYTE) (b & byEmask[i]));
|
|
}
|
|
return byVal;
|
|
}
|
|
|
|
static __inline WORD CorrectData(WORD wData,WORD wMissed)
|
|
{
|
|
while ((wMissed & 0xFF) != 0) // clear every missed bit in data area
|
|
{
|
|
BYTE byBitMask;
|
|
|
|
// detect valid H(i) mask
|
|
WORD wMi = 0x800; // first M(i) bit
|
|
INT i = 0; // index to first H(i) mask
|
|
|
|
while (TRUE)
|
|
{
|
|
if ((wMissed & wMi) == 0) // possible valid mask
|
|
{
|
|
_ASSERT(i < ARRAYSIZEOF(byEmask));
|
|
|
|
// select bit to correct
|
|
byBitMask = wMissed & byEmask[i];
|
|
|
|
if (Parity(byBitMask)) // only one bit set (parity odd)
|
|
break; // -> valid H(i) mask
|
|
}
|
|
|
|
wMi >>= 1; // next M(i) bit
|
|
i++; // next H(i) mask
|
|
}
|
|
|
|
// correct bit with H(i) mask
|
|
wMissed ^= byBitMask; // clear this missed bit
|
|
|
|
// parity odd -> wrong data value
|
|
if (Parity((BYTE) ((wData & byEmask[i]) ^ ((wData & wMi) >> 8))))
|
|
wData ^= byBitMask; // correct value
|
|
}
|
|
return wData & 0xFF; // only data byte is correct
|
|
}
|
|
|
|
VOID IrPrinter(BYTE c)
|
|
{
|
|
static INT nFrame = 0; // frame counter
|
|
static DWORD dwData = 0; // half bit data container
|
|
static INT nStart = 0; // frame counter disabled
|
|
|
|
BOOL bLSRQ;
|
|
|
|
dwData = (dwData << 1) | (c & LBO); // grab the last 32 bit send through IR
|
|
|
|
// Led Service ReQuest on Led Buffer Empty enabled
|
|
bLSRQ = (Chipset.IORam[LCR] & ELBE) != 0;
|
|
|
|
IOBit(SRQ2,LSRQ,bLSRQ); // update LSRQ bit
|
|
if (bLSRQ) // interrupt on Led Buffer Empty enabled
|
|
{
|
|
Chipset.SoftInt = TRUE; // execute interrupt
|
|
bInterrupt = TRUE;
|
|
}
|
|
|
|
// HP40G and HP49G have no IR transmitter Led
|
|
if ((cCurrentRomType == 'E' && nCurrentClass == 40) || cCurrentRomType == 'X')
|
|
return;
|
|
|
|
if (nFrame == 0) // waiting for start bit condition
|
|
{
|
|
if ((dwData & 0x3F) == 0x07) // start bit condition (000111 pattern)
|
|
{
|
|
nStart = 1; // enable frame counter
|
|
}
|
|
}
|
|
|
|
if (nFrame == 24) // 24 half bit received
|
|
{
|
|
INT i;
|
|
|
|
WORD wData = 0; // data container
|
|
WORD wMissed = 0; // missed bit container
|
|
INT nCount = 0; // no. of missed bits
|
|
|
|
nFrame = 0; // reset for next character
|
|
nStart = 0; // disable frame counter
|
|
|
|
// separate to data and missed bits
|
|
for (i = 0; i < 12; ++i) // 12 bit frames
|
|
{
|
|
BYTE b = (BYTE) (dwData & 3); // last 2 half bits
|
|
|
|
if (b == 0x0 || b == 0x3) // illegal half bit combination
|
|
{
|
|
wMissed |= (1 << i); // this is a missed bit
|
|
++nCount; // incr. number of missed bits
|
|
}
|
|
else // valid data bit
|
|
{
|
|
wData |= ((b >> 1) << i); // add data bit
|
|
}
|
|
dwData >>= 2; // next 2 half bits
|
|
}
|
|
|
|
if (nCount <= 2) // error can be fixed
|
|
{
|
|
BYTE byOrgParity,byNewParity;
|
|
|
|
byOrgParity = wData >> 8; // the original parity information with missed bits
|
|
byNewParity = ~(wMissed >> 8); // missed bit mask for recalculated parity
|
|
|
|
if (nCount > 0) // error correction
|
|
{
|
|
wData = CorrectData(wData,wMissed);
|
|
}
|
|
|
|
wData &= 0xFF; // remove parity information
|
|
|
|
// recalculate parity data
|
|
byNewParity &= CreateCorrectionBits((BYTE) wData);
|
|
|
|
// wrong parity
|
|
if (byOrgParity != byNewParity)
|
|
wData = ERR_CHAR; // character for transfer error
|
|
}
|
|
else
|
|
{
|
|
wData = ERR_CHAR; // character for transfer error
|
|
}
|
|
|
|
SendByteUdp((BYTE) wData); // send data byte
|
|
return;
|
|
}
|
|
nFrame += nStart; // next frame
|
|
return;
|
|
}
|