Initial sim implementation

This commit is contained in:
Sam El-Husseini
2017-12-18 13:04:17 -08:00
parent 6836852122
commit 6320379d02
88 changed files with 3949 additions and 3552 deletions

68
sim/state/analog.ts Normal file
View File

@ -0,0 +1,68 @@
namespace pxsim {
enum AnalogOff {
InPin1 = 0, // int16[4]
InPin6 = 8, // int16[4]
OutPin5 = 16, // int16[4]
BatteryTemp = 24, // int16
MotorCurrent = 26, // int16
BatteryCurrent = 28, // int16
Cell123456 = 30, // int16
Pin1 = 32, // int16[300][4]
Pin6 = 2432, // int16[300][4]
Actual = 4832, // uint16[4]
LogIn = 4840, // uint16[4]
LogOut = 4848, // uint16[4]
NxtCol = 4856, // uint16[36][4] - NxtColor*4
OutPin5Low = 5144, // int16[4]
Updated = 5152, // int8[4]
InDcm = 5156, // int8[4]
InConn = 5160, // int8[4]
OutDcm = 5164, // int8[4]
OutConn = 5168, // int8[4]
Size = 5172
}
export class EV3AnalogState {
constructor() {
let data = new Uint8Array(5172)
MMapMethods.register("/dev/lms_analog", {
data,
beforeMemRead: () => {
//console.log("analog before read");
const inputNodes = ev3board().getInputNodes();
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
const node = inputNodes[port];
if (node) {
data[AnalogOff.InConn + port] = node.isUart() ? DAL.CONN_INPUT_UART : DAL.CONN_INPUT_DUMB;
if (node.isAnalog() && node.hasData()) {
//data[AnalogOff.InPin6 + 2 * port] = node.getValue();
util.map16Bit(data, AnalogOff.InPin6 + 2 * port, node.getValue())
}
}
}
},
read: buf => {
let v = "vSIM"
for (let i = 0; i < buf.data.length; ++i)
buf.data[i] = v.charCodeAt(i) || 0
console.log("analog read");
console.log(buf.data);
return buf.data.length
},
write: buf => {
console.log("analog write");
console.log(buf);
return 2
},
ioctl: (id, buf) => {
console.log("analog ioctl");
console.log(id);
console.log(buf);
return 2;
}
})
}
}
}

27
sim/state/brick.ts Normal file
View File

@ -0,0 +1,27 @@
/// <reference path="./nodeTypes.ts"/>
namespace pxsim {
export class PortNode extends BaseNode {
id = NodeType.Port;
constructor(port: number) {
super(port);
}
}
export class BrickNode extends BaseNode {
id = NodeType.Brick;
buttonState: EV3ButtonState;
lightState: EV3LightState;
constructor() {
super(-1);
this.buttonState = new EV3ButtonState();
this.lightState = new EV3LightState();
}
}
}

46
sim/state/color.ts Normal file
View File

@ -0,0 +1,46 @@
/// <reference path="./sensor.ts"/>
namespace pxsim {
export enum ColorSensorMode {
Reflected = 0,
Ambient = 1,
Colors = 2,
RefRaw = 3,
RgbRaw = 4,
ColorCal = 5
}
export enum ThresholdState {
Normal = 1,
High = 2,
Low = 3,
}
export class ColorSensorNode extends UartSensorNode {
id = NodeType.ColorSensor;
private color: number;
constructor(port: number) {
super(port);
}
getDeviceType() {
return DAL.DEVICE_TYPE_COLOR;
}
setColor(color: number) {
this.color = color;
this.changed = true;
this.valueChanged = true;
runtime.queueDisplayUpdate();
}
getValue() {
return this.color;
}
}
}

View File

@ -63,7 +63,6 @@ namespace pxsim.MMapMethods {
export function write(m: MMap, data: Buffer): number {
return m.impl.write(data)
}
export function read(m: MMap, data: Buffer): number {

47
sim/state/gyro.ts Normal file
View File

@ -0,0 +1,47 @@
namespace pxsim {
const enum GyroSensorMode {
None = -1,
Angle = 0,
Rate = 1,
}
export class GyroSensorNode extends UartSensorNode {
id = NodeType.GyroSensor;
private angle: number = 0;
private rate: number = 0;
constructor(port: number) {
super(port);
}
getDeviceType() {
return DAL.DEVICE_TYPE_GYRO;
}
setAngle(angle: number) {
if (this.angle != angle) {
this.angle = angle;
this.changed = true;
this.valueChanged = true;
runtime.queueDisplayUpdate();
}
}
setRate(rate: number) {
if (this.rate != rate) {
this.rate = rate;
this.changed = true;
this.valueChanged = true;
runtime.queueDisplayUpdate();
}
}
getValue() {
return this.mode == GyroSensorMode.Angle ? this.angle :
this.mode == GyroSensorMode.Rate ? this.rate : 0;
}
}
}

18
sim/state/input.ts Normal file
View File

@ -0,0 +1,18 @@
namespace pxsim.motors {
export function __motorUsed(port: number, large: boolean) {
console.log("MOTOR INIT " + port);
const motors = ev3board().getMotor(port, large);
runtime.queueDisplayUpdate();
}
}
namespace pxsim.sensors {
export function __sensorUsed(port: number, type: number) {
console.log("SENSOR INIT " + port + ", type: " + type);
const sensor = ev3board().getSensor(port, type);
runtime.queueDisplayUpdate();
}
}

View File

@ -12,7 +12,7 @@ namespace pxsim {
namespace pxsim.output {
export function setLights(pattern: number) {
const lightState = (board() as DalBoard).lightState;
const lightState = ev3board().getBrickNode().lightState;
lightState.lightPattern = pattern;
runtime.queueDisplayUpdate();
}

49
sim/state/motor.ts Normal file
View File

@ -0,0 +1,49 @@
namespace pxsim {
enum MotorDataOff {
TachoCounts = 0, // int32
Speed = 4, // int8
Padding = 5, // int8[3]
TachoSensor = 8, // int32
Size = 12
}
export class EV3MotorState {
constructor() {
let data = new Uint8Array(12 * DAL.NUM_OUTPUTS)
MMapMethods.register("/dev/lms_motor", {
data,
beforeMemRead: () => {
console.log("motor before read");
for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) {
data[MotorDataOff.TachoCounts * port] = 0; // Tacho count
data[MotorDataOff.Speed * port] = 50; // Speed
data[MotorDataOff.TachoSensor * port] = 0; // Count
}
},
read: buf => {
let v = "vSIM"
for (let i = 0; i < buf.data.length; ++i)
buf.data[i] = v.charCodeAt(i) || 0
console.log("motor read");
console.log(buf.data);
return buf.data.length
},
write: buf => {
if (buf.data.length == 0) return 2;
const cmd = buf.data[0];
console.log("motor write");
console.log(buf);
return 2
},
ioctl: (id, buf) => {
console.log("motor ioctl");
console.log(id);
console.log(buf);
return 2;
}
});
}
}
}

73
sim/state/motors.ts Normal file
View File

@ -0,0 +1,73 @@
namespace pxsim {
export class MotorNode extends BaseNode {
isOutput = true;
public angle: number = 0;
private speed: number;
private large: boolean;
private rotation: number;
private polarity: boolean;
constructor(port: number) {
super(port);
}
setSpeed(speed: number) {
if (this.speed != speed) {
this.speed = speed;
this.changed = true;
runtime.queueDisplayUpdate();
}
}
setLarge(large: boolean) {
this.large = large;
}
getSpeed() {
return this.speed;
}
stepSpeed(speed: number, angle: number, brake: boolean) {
// TODO: implement
}
setPolarity(polarity: number) {
// Either 1 or 255 (reverse)
this.polarity = polarity === 255;
// TODO: implement
}
reset() {
// TODO: implement
}
stop() {
// TODO: implement
}
start() {
// TODO: implement
runtime.queueDisplayUpdate();
}
}
export class MediumMotorNode extends MotorNode {
id = NodeType.MediumMotor;
constructor(port: number) {
super(port);
}
}
export class LargeMotorNode extends MotorNode {
id = NodeType.LargeMotor;
constructor(port: number) {
super(port);
}
}
}

36
sim/state/nodeTypes.ts Normal file
View File

@ -0,0 +1,36 @@
namespace pxsim {
export enum NodeType {
Port = 0,
Brick = 1,
TouchSensor = 2,
MediumMotor = 3,
LargeMotor = 4,
GyroSensor = 5,
ColorSensor = 6,
UltrasonicSensor = 7
}
export interface Node {
id: number;
didChange(): boolean;
}
export class BaseNode implements Node {
public id: number;
public port: number;
public isOutput = false;
private used = false;
protected changed = true;
constructor(port: number) {
this.port = port;
}
didChange() {
const res = this.changed;
this.changed = false;
return res;
}
}
}

104
sim/state/output.ts Normal file
View File

@ -0,0 +1,104 @@
namespace pxsim {
export class EV3OutputState {
constructor() {
let data = new Uint8Array(10)
MMapMethods.register("/dev/lms_pwm", {
data,
beforeMemRead: () => {
//console.log("pwm before read");
for (let i = 0; i < 10; ++i)
data[i] = 0
},
read: buf => {
let v = "vSIM"
for (let i = 0; i < buf.data.length; ++i)
buf.data[i] = v.charCodeAt(i) || 0
console.log("pwm read");
return buf.data.length
},
write: buf => {
if (buf.data.length == 0) return 2;
const cmd = buf.data[0];
switch (cmd) {
case DAL.opProgramStart: {
// init
console.log('init');
return 2;
}
case DAL.opOutputReset: {
// reset
const port = buf.data[1];
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.reset());
return 2;
}
case DAL.opOutputStepSpeed: {
// step speed
const port = buf.data[1];
const speed = buf.data[2];
// note that b[3] is padding
const step1 = buf.data[4];
const step2 = buf.data[5]; // angle
const step3 = buf.data[6];
const brake = buf.data[7];
//console.log(buf);
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.stepSpeed(speed, step2, brake === 1));
return 2;
}
case DAL.opOutputStop: {
// stop
const port = buf.data[1];
const brake = buf.data[2];
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.stop());
return 2;
}
case DAL.opOutputSpeed: {
// setSpeed
const port = buf.data[1];
const speed = buf.data[2];
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.setSpeed(speed));
return 2;
}
case DAL.opOutputStart: {
// start
const port = buf.data[1];
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.start());
return 2;
}
case DAL.opOutputPolarity: {
// reverse
const port = buf.data[1];
const polarity = buf.data[2];
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.setPolarity(polarity));
return 2;
}
case DAL.opOutputSetType: {
const port = buf.data[1];
const large = buf.data[2] == 0x07;
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.setLarge(large));
return 2;
}
}
console.log("pwm write");
console.log(buf);
return 2
},
ioctl: (id, buf) => {
console.log("pwm ioctl");
console.log(id);
console.log(buf);
return 2;
}
});
}
}
}

View File

@ -7,7 +7,6 @@ namespace pxsim {
export class EV3ScreenState {
shouldUpdate: boolean;
points: Uint8Array;
constructor() {
this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
@ -24,13 +23,13 @@ namespace pxsim {
setPixel(x: number, y: number, v: number) {
this.applyMode(OFF(x, y), v)
this.shouldUpdate = true;
runtime.queueDisplayUpdate();
}
clear() {
for (let i = 0; i < this.points.length; ++i)
this.points[i] = 0;
this.shouldUpdate = true;
runtime.queueDisplayUpdate();
}
blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
@ -59,7 +58,7 @@ namespace pxsim {
}
}
this.shouldUpdate = true;
runtime.queueDisplayUpdate();
}
clearLine(x: number, y: number, w: number) {
@ -82,12 +81,12 @@ namespace pxsim.screen {
function YY(v: number) { return v >> 16 }
export function _setPixel(x: number, y: number, mode: Draw) {
const screenState = (board() as DalBoard).screenState;
const screenState = ev3board().screenState;
screenState.setPixel(x, y, mode);
}
export function _blitLine(xw: number, y: number, buf: RefBuffer, mode: Draw) {
const screenState = (board() as DalBoard).screenState;
const screenState = ev3board().screenState;
screenState.blitLineCore(XX(xw), y, YY(xw), buf, mode)
}
@ -99,7 +98,7 @@ namespace pxsim.screen {
return ((x + 7) >> 3)
}
export function clear(): void {
const screenState = (board() as DalBoard).screenState;
const screenState = ev3board().screenState;
screenState.clear()
}
@ -240,7 +239,7 @@ namespace pxsim.ImageMethods {
}
export function draw(buf: RefBuffer, x: number, y: number, mode: Draw): void {
const screenState = (board() as DalBoard).screenState;
const screenState = ev3board().screenState;
if (!screen.isValidImage(buf))
return;

73
sim/state/sensor.ts Normal file
View File

@ -0,0 +1,73 @@
namespace pxsim {
export class SensorNode extends BaseNode {
protected mode: number;
protected valueChanged: boolean;
constructor(port: number) {
super(port);
}
public isUart() {
return true;
}
public isAnalog() {
return false;
}
public getValue() {
return 0;
}
setMode(mode: number) {
this.mode = mode;
}
getMode() {
return this.mode;
}
getDeviceType() {
return DAL.DEVICE_TYPE_NONE;
}
public hasData() {
return true;
}
valueChange() {
const res = this.valueChanged;
this.valueChanged = false;
return res;
}
}
export class AnalogSensorNode extends SensorNode {
constructor(port: number) {
super(port);
}
public isUart() {
return false;
}
public isAnalog() {
return true;
}
}
export class UartSensorNode extends SensorNode {
constructor(port: number) {
super(port);
}
hasChanged() {
return this.changed;
}
}
}

42
sim/state/touch.ts Normal file
View File

@ -0,0 +1,42 @@
namespace pxsim {
export const TOUCH_SENSOR_ANALOG_PRESSED = 2600;
export class TouchSensorNode extends AnalogSensorNode {
id = NodeType.TouchSensor;
private pressed: boolean[];
constructor(port: number) {
super(port);
this.pressed = [];
}
public setPressed(pressed: boolean) {
this.pressed.push(pressed);
this.changed = true;
this.valueChanged = true;
}
public isPressed() {
return this.pressed;
}
public getValue() {
if (this.pressed.length) {
if (this.pressed.pop())
return TOUCH_SENSOR_ANALOG_PRESSED;
}
return 0;
}
getDeviceType() {
return DAL.DEVICE_TYPE_TOUCH;
}
public hasData() {
return this.pressed.length > 0;
}
}
}

156
sim/state/uart.ts Normal file
View File

@ -0,0 +1,156 @@
namespace pxsim {
enum UartOff {
TypeData = 0, // Types[8][4]
Repeat = 1792, // uint16[300][4]
Raw = 4192, // int8[32][300][4]
Actual = 42592, // uint16[4]
LogIn = 42600, // uint16[4]
Status = 42608, // int8[4]
Output = 42612, // int8[32][4]
OutputLength = 42740, // int8[4]
Size = 42744
}
enum UartStatus {
UART_PORT_CHANGED = 1,
UART_DATA_READY = 8
}
enum IO {
UART_SET_CONN = 0xc00c7500,
UART_READ_MODE_INFO = 0xc03c7501,
UART_NACK_MODE_INFO = 0xc03c7502,
UART_CLEAR_CHANGED = 0xc03c7503,
IIC_SET_CONN = 0xc00c6902,
IIC_READ_TYPE_INFO = 0xc03c6903,
IIC_SETUP = 0xc04c6905,
IIC_SET = 0xc02c6906,
TST_PIN_ON = 0xc00b7401,
TST_PIN_OFF = 0xc00b7402,
TST_PIN_READ = 0xc00b7403,
TST_PIN_WRITE = 0xc00b7404,
TST_UART_ON = 0xc0487405,
TST_UART_OFF = 0xc0487406,
TST_UART_EN = 0xc0487407,
TST_UART_DIS = 0xc0487408,
TST_UART_READ = 0xc0487409,
TST_UART_WRITE = 0xc048740a,
}
enum DevConOff {
Connection = 0, // int8[4]
Type = 4, // int8[4]
Mode = 8, // int8[4]
Size = 12
}
enum UartCtlOff {
TypeData = 0, // Types
Port = 56, // int8
Mode = 57, // int8
Size = 58
}
enum TypesOff {
Name = 0, // int8[12]
Type = 12, // int8
Connection = 13, // int8
Mode = 14, // int8
DataSets = 15, // int8
Format = 16, // int8
Figures = 17, // int8
Decimals = 18, // int8
Views = 19, // int8
RawMin = 20, // float32
RawMax = 24, // float32
PctMin = 28, // float32
PctMax = 32, // float32
SiMin = 36, // float32
SiMax = 40, // float32
InvalidTime = 44, // uint16
IdValue = 46, // uint16
Pins = 48, // int8
Symbol = 49, // int8[5]
Align = 54, // uint16
Size = 56
}
export class EV3UArtState {
constructor() {
let data = new Uint8Array(UartOff.Size);
MMapMethods.register("/dev/lms_uart", {
data,
beforeMemRead: () => {
//console.log("uart before read");
const inputNodes = ev3board().getInputNodes();
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
const node = inputNodes[port];
if (node) {
// Actual
const index = 0; //UartOff.Actual + port * 2;
data[UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index] = node.getValue();
// Status
data[UartOff.Status + port] = node.valueChange() ? UartStatus.UART_PORT_CHANGED : UartStatus.UART_DATA_READY;
}
}
},
read: buf => {
let v = "vSIM"
// for (let i = 0; i < buf.data.length; ++i)
// buf.data[i] = v.charCodeAt(i) || 0
console.log("uart read");
console.log(buf.data);
return buf.data.length
},
write: buf => {
console.log("uart write");
console.log(buf);
return 2
},
ioctl: (id, buf) => {
switch (id) {
case IO.UART_SET_CONN: {
// Set mode
console.log("IO.UART_SET_CONN");
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
const connection = buf.data[DevConOff.Connection + port]; // CONN_NONE, CONN_INPUT_UART
const type = buf.data[DevConOff.Type + port];
const mode = buf.data[DevConOff.Mode + port];
console.log(`${port}, mode: ${mode}`)
const node = ev3board().getInputNodes()[port];
if (node) node.setMode(mode);
}
return 2;
}
case IO.UART_CLEAR_CHANGED: {
console.log("IO.UART_CLEAR_CHANGED")
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
const connection = buf.data[DevConOff.Connection + port]; // CONN_NONE, CONN_INPUT_UART
const type = buf.data[DevConOff.Type + port];
const mode = buf.data[DevConOff.Mode + port];
const node = ev3board().getInputNodes()[port];
if (node) node.setMode(mode);
}
return 2;
}
case IO.UART_READ_MODE_INFO: {
console.log("IO.UART_READ_MODE_INFO")
const port = buf.data[UartCtlOff.Port];
const mode = buf.data[UartCtlOff.Mode];
const node = ev3board().getInputNodes()[port];
if (node) buf.data[UartCtlOff.TypeData + TypesOff.Type] = node.getDeviceType(); // DEVICE_TYPE_NONE, DEVICE_TYPE_TOUCH,
return 2;
}
}
console.log("uart ioctl");
console.log(id);
console.log(buf);
return 2;
}
})
}
}
}

31
sim/state/ultrasonic.ts Normal file
View File

@ -0,0 +1,31 @@
/// <reference path="./sensor.ts"/>
namespace pxsim {
export class UltrasonicSensorNode extends UartSensorNode {
id = NodeType.UltrasonicSensor;
private distance: number = 50;
constructor(port: number) {
super(port);
}
getDeviceType() {
return DAL.DEVICE_TYPE_ULTRASONIC;
}
setDistance(distance: number) {
if (this.distance != distance) {
this.distance = distance;
this.changed = true;
this.valueChanged = true;
runtime.queueDisplayUpdate();
}
}
getValue() {
return this.distance;
}
}
}

7
sim/state/util.ts Normal file
View File

@ -0,0 +1,7 @@
namespace pxsim.util {
export function map16Bit(buffer: Uint8Array, index: number, value: number) {
buffer[index] = (value >> 8) & 0xff;
buffer[index+1] = value & 0xff;
}
}