New code for blasting

Works more like the original software.
This commit is contained in:
Simon Larsson
2020-07-05 09:07:35 +02:00
parent cfa1d53a46
commit 7a47d1e0a4
3 changed files with 228 additions and 187 deletions
+19 -20
View File
@@ -1,18 +1,27 @@
# Data Blaster for Timex
# Will not work with original adapter due to timing issues
# Will not work with original adapter due to timing; in the orinignal
# implementation timing is set by the PC
import serial
import sys
import time
import struct
class Blaster:
def __init__(self, portname, syncbuflen=16):
self.port = serial.Serial(portname, 9600, timeout=0.1)
def __init__(self, portname):
self.port = serial.Serial(portname, 9600, timeout=0.5)
time.sleep(2)
self.to_send = []
def identify(self):
self.port.write(b'x')
indata = self.port.read(1)
if indata != b'x':
raise Exception("Transceiver not detected! (x error)")
self.port.write(b'?')
indata = self.port.read(5)
if indata != b'M764\0':
raise Exception("Transceiver not detected! Got id: {}".format(indata.decode()))
return True
def send_sync(self, times55sync=128, timesAAsync=50):
@@ -23,28 +32,18 @@ class Blaster:
self.blast(0xAA)
def blast(self, data):
self.to_send.append(data)
def flush(self):
self.port.write(struct.pack('!H', len(self.to_send)))
self.port.write(self.to_send)
self.port.write(bytes([data]))
rdata = ord(self.port.read(1))
if not rdata==data:
raise Exception("Validation error! Wrote {} but received {}".format(data, rdata))
if __name__ == "__main__":
portname = sys.argv[1]
b = Blaster(portname, syncbuflen=16)
b = Blaster(portname)
if not b.identify():
print("Could not verify adapter :(")
sys.exit(-1)
b.send_sync()
for p in range(10):
b.blast(0x03)
b.blast(0x02)
b.blast(0x01)
b.flush()
+209
View File
@@ -0,0 +1,209 @@
/* Implementation of transcoder behaving more closely to the fabled
* Notebook Adapter. Hopefully, it can be made compatible with the
* original software.
*/
/* This code is paced by the transmission rate between PC and Blaster
* being 9600 baud. Inter-package delay can be done on either PC or
* blaster side. The first case works better with the Python software
* and the latter with the original software.
*/
/* If this define is enabled, the blasting will be faster. It works fine
* most of the time, but the slower speed will probably be more reliable.
*/
#undef TURBO_MODE
#define LEDPIN 13
#define IRLED 12
#define CTSPIN 11
/* =========== DATA TRANSCODER FUNCTIONS ========================= */
/* Start a timer which counts 1 each clock cycle. When it reaches
* (hicnt*256)+lowcnt, OCF1A is set. Call waitTimer() to wait until this
* bit is set.
*/
inline void startTimer(int lowcnt, int hicnt)
{
/* Set count mode and max count*/
TCCR1A = 0;
OCR1AH = hicnt;
OCR1AL = lowcnt;
/* Stop timer 1 */
TCCR1B = 0;
/* Zero out timer 1 */
TCNT1 = 0;
/* Reset overflow flag */
TIFR1 = 2; /* OCF1A */
/* Start timer with prescaler 1 */
TCCR1B = 1;
}
/* Assembly would be preferred but we're a bit lax on timing requirements */
#define waitTimer() while ( !(TIFR1 & 0x02 ) ) /* OCF1A */
#ifdef TURBO_MODE
/* These values are faster than sending using CRT but seems to work most of the time. */
/* Bit length */
#define BITLEN_L 252
#define BITLEN_H 1
/* Bit interval */
#define SPACELEN_L 206
#define SPACELEN_H 28
#define INTERBYTE_L 0
#define INTERBYTE_H 180
#define INTERBYTE_PACKAGE 25
#else
/* Timing values based more on the CRT timings. */
/* Bit length */
/* 31.78 kHz => 16 MHz / 31.78 kHz ~= 508 counts (Approx 0.0318 ms bit length) */
#define BITLEN_L 252
#define BITLEN_H 1
/* Bit interval */
/* 31.47 kHz / (15-1) => 7118 counts (Approx 0.445 ms between bits, or 0.477 ms bit interval or 2098 baud) */
#define SPACELEN_L 206
#define SPACELEN_H 28
/* Mostly a mode-up value that when combined with INTERBYTE_PACKAGE ends up with a sensible delay between packets */
#define INTERBYTE_L 0
#define INTERBYTE_H 220
/* Number of times to repeat interbyte delay between packages */
/* Set this to 0 for compatibility with original software */
#define INTERBYTE_PACKAGE 45
#endif
bool past55sync;
bool pastAAsync;
unsigned int packetLeft;
void setupTranscode()
{
past55sync = false;
pastAAsync = false;
packetLeft = 0;
pinMode(IRLED, OUTPUT);
digitalWrite(IRLED, LOW);
}
#define interPacketDelay() do { \
digitalWrite(LEDPIN, LOW); \
for (unsigned int ipd=0; ipd<INTERBYTE_PACKAGE; ipd++) { \
startTimer(INTERBYTE_L, INTERBYTE_H); \
waitTimer(); \
} \
digitalWrite(LEDPIN, HIGH); \
} while (0); \
void transcodeByte(unsigned char curbyte)
{
if (curbyte != 0x55) {
if (!past55sync) {
/* Delay between 0x55-sync and 0xAA-sync - TODO: Test if this is necessary. */
//interPacketDelay();
}
past55sync = true;
if (curbyte != 0xAA) {
pastAAsync = true;
}
}
if (pastAAsync) {
/* Delay before each package */
if (packetLeft <= 0) {
/* Get new packet length. First byte of package is package length, including this length byte. */
packetLeft = curbyte;
interPacketDelay();
}
packetLeft--;
}
noInterrupts();
/* Start bit */
startTimer(BITLEN_L, BITLEN_H);
digitalWrite(IRLED, HIGH);
waitTimer();
startTimer(SPACELEN_L, SPACELEN_H);
digitalWrite(IRLED, LOW);
waitTimer();
/* Other bits */
for (unsigned int b=0; b<8; b++) {
startTimer(BITLEN_L, BITLEN_H);
digitalWrite(IRLED, !(curbyte&0x01) );
waitTimer();
startTimer(SPACELEN_L, SPACELEN_H);
digitalWrite(IRLED, LOW);
curbyte>>=1;
waitTimer();
}
interrupts();
}
/* ======= MAIN FUNCTIONS =============== */
bool transmitState;
void setup()
{
Serial.begin(9600);
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, LOW);
pinMode(CTSPIN, INPUT_PULLUP);
setupTranscode();
transmitState = false;
}
void loop()
{
unsigned char curbyte;
if (!digitalRead(CTSPIN)) {
transmitState = false;
}
if (Serial.available()) {
curbyte = Serial.read();
} else return;
if (!transmitState) {
/* Handle control bytes */
if (curbyte == 'x') {
Serial.print('x');
} else
if (curbyte == '?') {
Serial.print("M764");
Serial.write((byte)0);
}
else
if (curbyte == 'U') {
transmitState = true;
Serial.print('U');
}
} else {
transcodeByte(curbyte);
Serial.write(curbyte);
}
}
-167
View File
@@ -1,167 +0,0 @@
/* Implementation which buffers all data before sending. See README. */
/* Start a timer which counts 1 each clock cycle. When it reaches
* (hicnt*256)+lowcnt, OCF1A is set. Call waitTimer() to wait until this
* bit is set.
*/
inline void startTimer(int lowcnt, int hicnt)
{
/* Set count mode and max count*/
TCCR1A = 0;
OCR1AH = hicnt;
OCR1AL = lowcnt;
/* Stop timer 1 */
TCCR1B = 0;
/* Zero out timer 1 */
TCNT1 = 0;
/* Reset overflow flag */
TIFR1 = 2; /* OCF1A */
/* Start timer with prescaler 1 */
TCCR1B = 1;
}
/* Assembly would be preferred but we're a bit lax on timing requirements */
#define waitTimer() while ( !(TIFR1 & 0x02 ) ) /* OCF1A */
#define LEDPIN 13
#define IRLED 12
void setup()
{
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, LOW);
pinMode(IRLED, OUTPUT);
digitalWrite(IRLED, LOW);
Serial.begin(9600);
}
/* 31.47 kHz => 16 MHz / 31.47 kHz = 508 counts (Approx .0318 ms bit length) */
#define BITLEN_L 0
#define BITLEN_H 2
//#define BITLEN_L 252
//#define BITLEN_H 1
/* 31.47 kHz / (15-1) => 7118 counts (Approx 0.445 ms between bits, or 0.477 ms bit interval or 2098 baud) */
#define SPACELEN_L 206
#define SPACELEN_H 28
//#define SPACELEN_L 206
//#define SPACELEN_H 27
/* 31.47 kHz / 68 (made up) => 34573 counts (approx 2.16 ms between bytes) */
/* Trying larger delay so that it sounds more like data from the PC. */
#define INTERBYTE_L 0
#define INTERBYTE_H 220
//#define INTERBYTE_L 13
//#define INTERBYTE_H 135
/* Number of times to repeat interbyte package between bytes */
#define INTERBYTE_BYTE 3
/* Number of times to repeat interbyte package between packages */
#define INTERBYTE_PACKAGE 45
void blastData(unsigned char* data, int datalen)
{
unsigned char curbyte;
unsigned int packetLeft = 0;
bool past55sync = false;
bool pastAAsync = false;
/* Disable arduino interrupts (temporarily breaks delay, serial, ...) */
noInterrupts();
for (unsigned int i=0; i<datalen; i++) {
curbyte = data[i];
if (curbyte != 0x55) {
if (!past55sync) {
/* Delay between 0x55-sync and 0xAA-sync - Test if this is necessary. */
digitalWrite(LEDPIN, LOW);
for (unsigned int ipd=0; ipd<INTERBYTE_PACKAGE; ipd++) {
startTimer(INTERBYTE_L, INTERBYTE_H);
waitTimer();
digitalWrite(LEDPIN, HIGH);
}
}
past55sync = true;
if (curbyte != 0xAA) {
pastAAsync = true;
}
}
if (pastAAsync) {
/* Delay before each package */
if (packetLeft <= 0) {
/* First byte of package is package length, including this length byte */
packetLeft = curbyte;
digitalWrite(LEDPIN, LOW);
for (unsigned int ipd=0; ipd<INTERBYTE_PACKAGE; ipd++) {
startTimer(INTERBYTE_L, INTERBYTE_H);
waitTimer();
}
digitalWrite(LEDPIN, HIGH);
}
packetLeft--;
}
/* Start bit */
startTimer(BITLEN_L, BITLEN_H);
digitalWrite(IRLED, HIGH);
waitTimer();
startTimer(SPACELEN_L, SPACELEN_H);
digitalWrite(IRLED, LOW);
waitTimer();
/* Other bits */
for (unsigned int b=0; b<8; b++) {
startTimer(BITLEN_L, BITLEN_H);
digitalWrite(IRLED, !(curbyte&0x01) );
waitTimer();
startTimer(SPACELEN_L, SPACELEN_H);
digitalWrite(IRLED, LOW);
curbyte>>=1;
waitTimer();
}
/* Inter-byte delay */
for (unsigned int ipd=0; ipd<INTERBYTE_BYTE; ipd++) {
startTimer(INTERBYTE_L, INTERBYTE_H);
waitTimer();
}
}
/* Re-enable arduino interrupts */
interrupts();
digitalWrite(LEDPIN,HIGH);
}
void loop()
{
size_t datalen;
unsigned char* data;
while (!Serial.available());
datalen = (Serial.read()<<8)&0xFF00;
while (!Serial.available());
datalen += (Serial.read())&0x00FF;
data=malloc(datalen);
for (int i=0; i<datalen; i++) {
while (!Serial.available());
data[i] = Serial.read()&0xFF;
}
blastData(data, datalen);
free(data);
}