emu48plus-mirror/source/REDEYE.C
Gwenhael Le Moine edf519e5a1
2013-09-14: Updated to version 53
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
2024-03-20 07:46:28 +01:00

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)
{
INT 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;
}