pxt-ev3/libs/core/analog.ts
2017-07-09 18:12:24 +01:00

376 lines
11 KiB
TypeScript

namespace input {
//% shim=pxt::unsafePollForChanges
function unsafePollForChanges(
periodMs: int32,
query: () => int32,
changeHandler: (prev: int32, curr: int32) => void
) { }
let analogMM: MMap
const enum NxtColOff {
Calibration = 0, // uint32[4][3]
CalLimits = 48, // uint16[2]
Crc = 52, // uint16
ADRaw = 54, // uint16[4]
SensorRaw = 62, // uint16[4]
Padding = 70,
Size = 72
}
const 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
}
function init() {
if (analogMM) return
analogMM = control.mmap("/dev/lms_analog", AnalogOff.Size, 0)
if (!analogMM) control.fail("no analog sensor")
}
export function portState() {
init()
return analogMM.slice(AnalogOff.Updated, 12)
}
export class AnalogSensor {
protected port: number
protected id: number
protected getPin6() {
return readAnalogPin6(this.port)
}
constructor(port: number) {
this.port = Math.clamp(1, 4, port | 0) - 1;
this.id = 200 + port;
init()
}
}
export class TouchSensor extends AnalogSensor {
private downTime: number;
constructor(port: number) {
super(port)
unsafePollForChanges(50,
() => this.isPressed() ? 1 : 0,
(prev, curr) => {
if (prev == curr) return
if (curr) {
this.downTime = control.millis()
control.raiseEvent(this.id, ButtonEvent.Down)
} else {
control.raiseEvent(this.id, ButtonEvent.Up)
let delta = control.millis() - this.downTime
control.raiseEvent(this.id, delta > 500 ? ButtonEvent.LongClick : ButtonEvent.Click)
}
})
}
isPressed() {
return this.getPin6() > 2500
}
/**
* Do something when a touch sensor is clicked, double clicked, etc...
* @param button the button that needs to be clicked or used
* @param event the kind of button gesture that needs to be detected
* @param body code to run when the event is raised
*/
onEvent(ev: ButtonEvent, body: () => void) {
control.onEvent(this.id, ev, body)
}
}
function readAnalogPin6(port: number) {
init()
port--
port = Math.clamp(0, 3, port | 0)
return analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.InPin6 + 2 * port)
}
}
const enum IrSensorMode {
None = -1,
Proximity = 0,
Seek = 1,
RemoteControl = 2,
}
const enum IrRemoteChannel {
Ch0 = 0, // top
Ch1 = 1,
Ch2 = 2,
Ch3 = 3,
}
const enum IrRemoteButton {
None = 0x00,
CenterBeacon = 0x01,
TopLeft = 0x02,
BottomLeft = 0x04,
TopRight = 0x08,
BottomRight = 0x10,
}
namespace input {
let uartMM: MMap
let devcon: Buffer
const enum DevConOff {
Connection = 0, // int8[4]
Type = 4, // int8[4]
Mode = 8, // int8[4]
Size = 12
}
const 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
}
const 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
}
const enum UartCtlOff {
TypeData = 0, // Types
Port = 56, // int8
Mode = 57, // int8
Size = 58
}
const 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,
}
function init() {
if (uartMM) return
uartMM = control.mmap("/dev/lms_uart", UartOff.Size, 0)
if (!uartMM) control.fail("no uart sensor")
devcon = output.createBuffer(DevConOff.Size)
}
function uartReset(port: number) {
port = Math.clamp(0, 3, port)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_NONE)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 0)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, 0)
uartMM.ioctl(IO.UART_SET_CONN, devcon)
}
function getUartStatus(port: number) {
return uartMM.getNumber(NumberFormat.Int8LE, UartOff.Status + port)
}
function waitNonZeroUartStatus(port: number) {
while (true) {
let s = getUartStatus(port)
if (s) return s
loops.pause(25)
}
}
function uartClearChange(port: number) {
const UART_DATA_READY = 8
const UART_PORT_CHANGED = 1
while (true) {
let status = getUartStatus(port)
if ((status & UART_DATA_READY) != 0 && (status & UART_PORT_CHANGED) == 0)
break
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_INPUT_UART)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 0)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, 0)
uartMM.ioctl(IO.UART_CLEAR_CHANGED, devcon)
uartMM.setNumber(NumberFormat.Int8LE, UartOff.Status + port,
getUartStatus(port) & 0xfffe)
loops.pause(10)
}
}
function setUartMode(port: number, mode: number) {
const UART_PORT_CHANGED = 1
port = Math.clamp(0, 3, port)
loops.pause(100)
while (true) {
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_INPUT_UART)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 33)
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
uartMM.ioctl(IO.UART_SET_CONN, devcon)
let status = waitNonZeroUartStatus(port)
if (status & UART_PORT_CHANGED) {
uartClearChange(port)
} else {
break
}
loops.pause(10)
}
}
function getUartBytes(port: number): Buffer {
let index = uartMM.getNumber(NumberFormat.UInt16LE, UartOff.Actual + port * 2)
return uartMM.slice(UartOff.Raw + 32 * 300 * port + 32 * index, 32)
}
function getUartNumber(fmt: NumberFormat, off: number, port: number) {
let index = uartMM.getNumber(NumberFormat.UInt16LE, UartOff.Actual + port * 2)
return uartMM.getNumber(fmt, UartOff.Raw + 32 * 300 * port + 32 * index + off)
}
export class UartSensor {
port: number
id: number
constructor(port: number) {
this.port = Math.clamp(1, 4, port | 0) - 1;
this.id = 210 + port;
init()
uartReset(this.port)
}
}
function mapButton(v: number) {
switch (v) {
case 0: return IrRemoteButton.None
case 1: return IrRemoteButton.TopLeft
case 2: return IrRemoteButton.BottomLeft
case 3: return IrRemoteButton.TopRight
case 4: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight
case 5: return IrRemoteButton.TopLeft | IrRemoteButton.TopRight
case 6: return IrRemoteButton.TopLeft | IrRemoteButton.BottomRight
case 7: return IrRemoteButton.BottomLeft | IrRemoteButton.TopRight
case 8: return IrRemoteButton.BottomLeft | IrRemoteButton.BottomRight
case 9: return IrRemoteButton.CenterBeacon
case 10: return IrRemoteButton.BottomLeft | IrRemoteButton.TopLeft
case 11: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight
default: return IrRemoteButton.None
}
}
export class IrSensor extends UartSensor {
private mode: IrSensorMode
private channel: IrRemoteChannel
private pollRunning: boolean
constructor(port: number) {
super(port)
this.mode = IrSensorMode.None
this.channel = IrRemoteChannel.Ch0
this.pollRunning = false
}
setRemoteChannel(c: IrRemoteChannel) {
c = Math.clamp(0, 3, c | 0)
this.channel = c
this.setMode(IrSensorMode.RemoteControl)
}
setMode(m: IrSensorMode) {
let v = Math.clamp(0, 2, m | 0)
if (v != this.mode) {
this.mode = v
setUartMode(this.port, v)
}
}
getDistance() {
this.setMode(IrSensorMode.Proximity)
return getUartNumber(NumberFormat.UInt8LE, 0, this.port)
}
getRemoteCommand() {
this.setMode(IrSensorMode.RemoteControl)
let v = getUartNumber(NumberFormat.UInt8LE, this.channel, this.port)
return v
}
getDirectionAndDistance() {
this.setMode(IrSensorMode.Seek)
return getUartNumber(NumberFormat.UInt16LE, this.channel * 2, this.port)
}
}
function testPorts() {
let tstPin = control.mmap("/dev/lms_tst_pin", 0, 0)
let tstUart = control.mmap("/dev/lms_tst_uart", 0, 0)
let buf = output.createBuffer(0)
tstPin.ioctl(IO.TST_PIN_ON, buf)
tstUart.ioctl(IO.TST_UART_ON, buf)
loops.pause(30000)
tstUart.ioctl(IO.TST_UART_OFF, buf)
tstPin.ioctl(IO.TST_PIN_OFF, buf)
}
}