284 lines
8.0 KiB
TypeScript
284 lines
8.0 KiB
TypeScript
|
|
/**
|
|
* Patterns for lights under the buttons.
|
|
*/
|
|
const enum LightsPattern {
|
|
//% block=Off enumval=0
|
|
//% blockIdentity=brick.lightPattern
|
|
Off = 0,
|
|
//% block=Green enumval=1
|
|
//% blockIdentity=brick.lightPattern
|
|
Green = 1,
|
|
//% block=Red enumval=2
|
|
//% blockIdentity=brick.lightPattern
|
|
Red = 2,
|
|
//% block=Orange enumval=3
|
|
//% blockIdentity=brick.lightPattern
|
|
Orange = 3,
|
|
//% block="Flashing Green" enumval=4
|
|
//% blockIdentity=brick.lightPattern
|
|
GreenFlash = 4,
|
|
//% block="Flashing Red" enumval=5
|
|
//% blockIdentity=brick.lightPattern
|
|
RedFlash = 5,
|
|
//% block="Flashing Orange" enumval=6
|
|
//% blockIdentity=brick.lightPattern
|
|
OrangeFlash = 6,
|
|
//% block="Pulsing Green" enumval=7
|
|
//% blockIdentity=brick.lightPattern
|
|
GreenPulse = 7,
|
|
//% block="Pulsing Red" enumval=8
|
|
//% blockIdentity=brick.lightPattern
|
|
RedPulse = 8,
|
|
//% block="Pulsing Orange" enumval=9
|
|
//% blockIdentity=brick.lightPattern
|
|
OrangePulse = 9,
|
|
}
|
|
|
|
/**
|
|
* User interaction on buttons
|
|
*/
|
|
const enum ButtonEvent {
|
|
//% block="click"
|
|
Click = 1,
|
|
//% block="up"
|
|
Up = 3,
|
|
//% block="down"
|
|
Down = 4,
|
|
}
|
|
|
|
namespace brick {
|
|
/**
|
|
* Generic button class, for device buttons and sensors.
|
|
*/
|
|
//% fixedInstances
|
|
export class Button extends control.Component {
|
|
private downTime: number;
|
|
private _isPressed: boolean;
|
|
private _wasPressed: boolean;
|
|
|
|
constructor() {
|
|
super()
|
|
this.downTime = 0
|
|
this._isPressed = false
|
|
this._wasPressed = false
|
|
}
|
|
|
|
//% hidden
|
|
_update(curr: boolean) {
|
|
if (this == null) return
|
|
if (this._isPressed == curr) return
|
|
this._isPressed = curr
|
|
if (curr) {
|
|
this._wasPressed = true;
|
|
this.downTime = control.millis()
|
|
control.raiseEvent(this._id, ButtonEvent.Down)
|
|
} else {
|
|
control.raiseEvent(this._id, ButtonEvent.Up)
|
|
const delta = control.millis() - this.downTime;
|
|
if (delta < 500)
|
|
control.raiseEvent(this._id, ButtonEvent.Click)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if button is currently pressed or not.
|
|
* @param button the button to query the request
|
|
*/
|
|
//% help=input/button/is-pressed
|
|
//% block="%button|is pressed"
|
|
//% blockId=buttonIsPressed
|
|
//% parts="brick"
|
|
//% blockNamespace=brick
|
|
//% weight=81 blockGap=8
|
|
//% group="Buttons"
|
|
//% button.fieldEditor="brickbuttons"
|
|
isPressed() {
|
|
return this._isPressed
|
|
}
|
|
|
|
/**
|
|
* See if the button was pressed again since the last time you checked.
|
|
* @param button the button to query the request
|
|
*/
|
|
//% help=input/button/was-pressed
|
|
//% block="%button|was pressed"
|
|
//% blockId=buttonWasPressed
|
|
//% parts="brick"
|
|
//% blockNamespace=brick
|
|
//% weight=80
|
|
//% group="Buttons"
|
|
//% button.fieldEditor="brickbuttons"
|
|
wasPressed() {
|
|
const r = this._wasPressed
|
|
this._wasPressed = false
|
|
return r
|
|
}
|
|
|
|
/**
|
|
* Do something when a button or sensor is clicked, up or down.
|
|
* @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
|
|
*/
|
|
//% help=input/button/on-event
|
|
//% blockId=buttonEvent block="on %button|%event"
|
|
//% parts="brick"
|
|
//% blockNamespace=brick
|
|
//% weight=99 blockGap=8
|
|
//% group="Buttons"
|
|
//% button.fieldEditor="brickbuttons"
|
|
onEvent(ev: ButtonEvent, body: () => void) {
|
|
control.onEvent(this._id, ev, body)
|
|
}
|
|
|
|
/**
|
|
* Waits until the event is raised
|
|
* @param ev the event to wait for
|
|
*/
|
|
//% help=input/button/pause-until
|
|
//% blockId=buttonWaitUntil block="pause until %button|%event"
|
|
//% parts="brick"
|
|
//% blockNamespace=brick
|
|
//% weight=98 blockGap=8
|
|
//% group="Buttons"
|
|
//% button.fieldEditor="brickbuttons"
|
|
pauseUntil(ev: ButtonEvent) {
|
|
control.waitForEvent(this._id, ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace brick {
|
|
let btnsMM: MMap
|
|
let buttons: DevButton[]
|
|
|
|
export namespace internal {
|
|
export function getBtnsMM() {
|
|
initBtns()
|
|
return btnsMM;
|
|
}
|
|
}
|
|
|
|
function readButtons() {
|
|
let sl = btnsMM.slice(0, DAL.NUM_BUTTONS)
|
|
let ret = 0
|
|
for (let i = 0; i < sl.length; ++i) {
|
|
if (sl[i])
|
|
ret |= 1 << i
|
|
}
|
|
// this needs to be done in query(), which is run without the main JS execution mutex
|
|
// otherwise, while(true){} will lock the device
|
|
if (ret & DAL.BUTTON_ID_ESCAPE) {
|
|
motors.stopAllMotors(); // ensuring that all motors are off
|
|
control.reset()
|
|
}
|
|
return ret
|
|
}
|
|
|
|
function initBtns() {
|
|
if (btnsMM) return
|
|
btnsMM = control.mmap("/dev/lms_ui", DAL.NUM_BUTTONS, 0)
|
|
if (!btnsMM) control.fail("no buttons?")
|
|
buttons = []
|
|
sensors.internal.unsafePollForChanges(50, readButtons, (prev, curr) => {
|
|
for (let b of buttons)
|
|
b._update(!!(curr & b.mask))
|
|
})
|
|
control.dmesg("runtime started, " + control.deviceFirmwareVersion())
|
|
}
|
|
|
|
class DevButton extends Button {
|
|
mask: number
|
|
constructor(mask: number) {
|
|
super()
|
|
this.mask = mask
|
|
initBtns()
|
|
buttons.push(this)
|
|
}
|
|
}
|
|
|
|
initBtns() // always ON as it handles ESCAPE button
|
|
|
|
|
|
/**
|
|
* Enter button on the EV3 Brick.
|
|
*/
|
|
//% whenUsed block="button enter" weight=95 fixedInstance
|
|
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
|
|
|
|
/**
|
|
* Left button on the EV3 Brick.
|
|
*/
|
|
//% whenUsed block="button left" weight=95 fixedInstance
|
|
export const buttonLeft: Button = new DevButton(DAL.BUTTON_ID_LEFT)
|
|
|
|
/**
|
|
* Right button on the EV3 Brick.
|
|
*/
|
|
//% whenUsed block="button right" weight=94 fixedInstance
|
|
export const buttonRight: Button = new DevButton(DAL.BUTTON_ID_RIGHT)
|
|
|
|
/**
|
|
* Up button on the EV3 Brick.
|
|
*/
|
|
//% whenUsed block="button up" weight=95 fixedInstance
|
|
export const buttonUp: Button = new DevButton(DAL.BUTTON_ID_UP)
|
|
|
|
/**
|
|
* Down button on the EV3 Brick.
|
|
*/
|
|
//% whenUsed block="button down" weight=95 fixedInstance
|
|
export const buttonDown: Button = new DevButton(DAL.BUTTON_ID_DOWN)
|
|
}
|
|
|
|
|
|
namespace control {
|
|
/**
|
|
* Determine the version of system software currently running.
|
|
*/
|
|
//%
|
|
export function deviceFirmwareVersion(): string {
|
|
let buf = output.createBuffer(6)
|
|
brick.internal.getBtnsMM().read(buf)
|
|
let r = ""
|
|
for (let i = 0; i < buf.length; ++i) {
|
|
let c = buf[i]
|
|
if (c == 0) break
|
|
r += String.fromCharCode(c)
|
|
}
|
|
return r
|
|
}
|
|
}
|
|
|
|
namespace brick {
|
|
let currPattern: LightsPattern
|
|
|
|
/**
|
|
* Set lights.
|
|
* @param pattern the lights pattern to use.
|
|
*/
|
|
//% blockId=setLights block="set light to %pattern=led_pattern"
|
|
//% weight=100 group="Buttons"
|
|
export function setLight(pattern: number): void {
|
|
if (currPattern === pattern)
|
|
return
|
|
currPattern = pattern
|
|
let cmd = output.createBuffer(2)
|
|
cmd[0] = pattern + 48
|
|
brick.internal.getBtnsMM().write(cmd)
|
|
}
|
|
|
|
|
|
/**
|
|
* Pattern block.
|
|
* @param pattern the lights pattern to use. eg: LightsPattern.Green
|
|
*/
|
|
//% blockId=led_pattern block="%pattern"
|
|
//% shim=TD_ID colorSecondary="#6e9a36" group="Light"
|
|
//% blockHidden=true useEnumVal=1 pattern.fieldOptions.decompileLiterals=1
|
|
export function lightPattern(pattern: LightsPattern): number {
|
|
return pattern;
|
|
}
|
|
}
|