pxt-calliope/libs/radio/test.ts

350 lines
8.9 KiB
TypeScript

/**
* Tests for the radio. Press A on mbit 1 and B on mbit 2 to run the tests.
* Sends random ints, doubles, strings, and buffers and checks them on
* the other side
*/
class FastRandom {
private lfsr: number;
public seed: number;
constructor(seed?: number) {
if (seed === undefined) seed = Math.randomRange(0x0001, 0xFFFF);
this.seed = seed;
this.lfsr = seed;
}
next(): number {
return this.lfsr = (this.lfsr >> 1) ^ ((-(this.lfsr & 1)) & 0xb400);
}
randomRange(min: number, max: number): number {
return min + (max > min ? this.next() % (max - min + 1) : 0);
}
reset() {
this.lfsr = this.seed;
}
}
enum TestStage {
Integer,
String,
Double,
IntValue,
DblValue,
Buffer
}
const TEST_COUNT = 30;
radio.setGroup(78)
const rand = new FastRandom(1234);
let stage = TestStage.Integer;
function initSender() {
let lastReceived: number;
let lastString: string;
let testIndex = 0;
let lastBuf: Buffer;
let lastAck = -1;
rand.reset();
basic.clearScreen();
// Send loop
control.inBackground(function () {
while (true) {
for (let i = 0; i < TEST_COUNT; i++) {
toggle(testIndex);
if (stage === TestStage.Integer) {
lastReceived = getNextInt();
}
else if (stage === TestStage.Double) {
lastReceived = getNextDouble();
}
else if (stage === TestStage.IntValue) {
lastString = getNextName();
console.log(truncateString(lastString, 8))
lastReceived = getNextInt();
}
else if (stage === TestStage.DblValue) {
lastString = getNextName();
lastReceived = getNextDouble();
}
else if (stage === TestStage.String) {
lastString = getNextString();
console.log(truncateString(lastString, 19))
}
else if (stage === TestStage.Buffer) {
lastBuf = getNextBuffer();
}
while (lastAck !== testIndex) {
if (stage === TestStage.Integer || stage === TestStage.Double) {
radio.sendNumber(lastReceived)
}
else if (stage === TestStage.IntValue || stage === TestStage.DblValue) {
radio.sendValue(lastString, lastReceived)
}
else if (stage === TestStage.String) {
radio.sendString(lastString);
}
else if (stage === TestStage.Buffer) {
radio.sendBuffer(lastBuf);
}
basic.pause(10);
}
testIndex++;
}
stage++;
if (stage > TestStage.Buffer) {
basic.showIcon(IconNames.Yes);
return;
}
}
})
radio.onReceivedNumber(function (receivedNumber: number) {
if (receivedNumber > lastAck) {
lastAck = receivedNumber;
}
});
}
let lastReceived: number;
let lastString: string;
let testIndex = -1;
let running = true;
let lastBuf: Buffer;
let lastPacket = new radio.Packet();
let currentPacket = new radio.Packet();
function truncateString(str: string, bytes: number) {
str = str.substr(0, bytes);
let buff = control.createBufferFromUTF8(str);
while (buff.length > bytes) {
str = str.substr(0, str.length - 1);
buff = control.createBufferFromUTF8(str);
}
return str;
}
function initReceiver() {
rand.reset();
basic.clearScreen();
radio.onDataReceived(function () {
radio.receiveNumber();
currentPacket.receivedNumber = radio.receivedNumber();
currentPacket.receivedString = radio.receivedString();
currentPacket.receivedBuffer = radio.receivedBuffer();
if (currentPacket.receivedNumber === lastPacket.receivedNumber &&
currentPacket.receivedString === lastPacket.receivedString &&
checkBufferEqual(currentPacket.receivedBuffer, lastPacket.receivedBuffer)) {
return;
}
lastPacket.receivedNumber = currentPacket.receivedNumber
lastPacket.receivedString = currentPacket.receivedString
lastPacket.receivedBuffer = currentPacket.receivedBuffer
switch (stage) {
case TestStage.Integer:
verifyInt(radio.receivedNumber());
break;
case TestStage.Double:
verifyDouble(radio.receivedNumber());
break;
case TestStage.IntValue:
verifyIntValue(radio.receivedString(), radio.receivedNumber());
break;
case TestStage.DblValue:
verifyDblValue(radio.receivedString(), radio.receivedNumber());
break;
case TestStage.String:
verifyString(radio.receivedString());
break;
case TestStage.Buffer:
verifyBuffer(radio.receivedBuffer());
break;
}
})
control.inBackground(function () {
while (running) {
radio.sendNumber(testIndex);
basic.pause(10)
}
})
}
function nextTest() {
testIndex++;
toggle(testIndex);
console.log(`test ${testIndex}`)
if (((testIndex + 1) % TEST_COUNT) === 0) {
stage++;
if (stage > TestStage.Buffer) {
basic.showIcon(IconNames.Yes)
running = false;
}
}
}
function verifyInt(int: number) {
if (int === lastReceived) return;
lastReceived = int;
if (lastReceived != getNextInt()) fail();
nextTest()
}
function verifyDouble(dbl: number) {
if (dbl === lastReceived) return;
lastReceived = dbl;
if (lastReceived != getNextDouble()) fail();
nextTest()
}
function verifyIntValue(name: string, val: number) {
if (val === lastReceived) return;
lastReceived = val;
if (name != truncateString(getNextName(), 8) || lastReceived != getNextInt()) fail();
nextTest()
}
function verifyDblValue(name: string, val: number) {
if (val === lastReceived) return;
lastReceived = val;
if (name != truncateString(getNextName(), 8) || lastReceived != getNextDouble()) fail();
nextTest()
}
function verifyString(str: string) {
if (!str || str === lastString) return;
lastString = str;
let next = truncateString(getNextString(), 19);
if (lastString !== next) {
console.log(`got ${control.createBufferFromUTF8(lastString).toHex()} expected ${control.createBufferFromUTF8(next).toHex()}`)
}
nextTest()
}
function verifyBuffer(buf: Buffer) {
if (checkBufferEqual(lastBuf, buf)) return;
lastBuf = buf;
if (!checkBufferEqual(lastBuf, getNextBuffer())) {
fail();
}
nextTest()
}
function fail() {
control.panic(testIndex);
}
let _lastInt: number;
let _lastDbl: number;
let _lastStr: string;
let _lastBuf: Buffer;
let _lastNam: string;
function getNextInt(): number {
let res = rand.next();
if (!res || res === _lastInt) return getNextInt();
_lastInt = res;
return res;
}
function getNextDouble(): number {
let res = rand.next() / rand.next();
if (res === _lastDbl) return getNextDouble();
_lastDbl = res;
return res;
}
function getNextString(): string {
let len = rand.randomRange(1, 19);
let res = "";
for (let i = 0; i < len; i++) {
res += String.fromCharCode(rand.next() & 0xbfff);
}
if (res === _lastStr) return getNextString();
_lastStr = res;
return res;
}
function getNextName(): string {
let len = rand.randomRange(1, 8);
let res = "";
for (let i = 0; i < len; i++) {
res += String.fromCharCode(rand.next() & 0xbfff);
}
if (res === _lastNam) return getNextName();
_lastNam = res;
return res;
}
function getNextBuffer(): Buffer {
let len = rand.randomRange(0, 8);
let res = control.createBuffer(len);
for (let i = 0; i < len; i++) {
res[i] = rand.next() & 0xff;
}
if (checkBufferEqual(_lastBuf, res)) return getNextBuffer();
_lastBuf = res;
return res;
}
function checkBufferEqual(a: Buffer, b: Buffer) {
if (a === b) return true;
if ((!a && b) || (a && !b)) return false;
if (a.length != b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
input.onButtonPressed(Button.A, function () {
basic.showString("S");
initSender();
})
input.onButtonPressed(Button.B, function () {
basic.showString("R");
initReceiver();
})
function toggle(index: number) {
const x = index % 5;
const y = Math.idiv(index, 5) % 5;
led.toggle(x, y);
}