pxt-ev3/libs/core/buttons.ts

283 lines
7.9 KiB
TypeScript
Raw Normal View History

2017-07-10 15:16:31 +02:00
/**
* Patterns for lights under the buttons.
*/
const enum LightsPattern {
//% block=Off enumval=0
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
Off = 0,
//% block=Green enumval=1
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
Green = 1,
//% block=Red enumval=2
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
Red = 2,
//% block=Orange enumval=3
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
Orange = 3,
//% block="Flashing Green" enumval=4
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
GreenFlash = 4,
//% block="Flashing Red" enumval=5
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
RedFlash = 5,
//% block="Flashing Orange" enumval=6
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
OrangeFlash = 6,
//% block="Pulsing Green" enumval=7
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
GreenPulse = 7,
//% block="Pulsing Red" enumval=8
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
RedPulse = 8,
//% block="Pulsing Orange" enumval=9
2017-11-29 00:23:54 +01:00
//% blockIdentity=brick.lightPattern
2017-07-10 16:11:21 +02:00
OrangePulse = 9,
2017-07-10 15:16:31 +02:00
}
2017-07-10 15:18:00 +02:00
/**
* User interaction on buttons
*/
const enum ButtonEvent {
//% block="click"
Click = 1,
//% block="up"
Up = 3,
//% block="down"
Down = 4,
}
2017-10-28 18:13:02 +02:00
namespace brick {
2017-07-10 15:18:00 +02:00
/**
* 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
2017-10-27 06:10:37 +02:00
_update(curr: boolean) {
if (this == null) return
2017-07-10 15:18:00 +02:00
if (this._isPressed == curr) return
this._isPressed = curr
if (curr) {
2017-11-29 01:02:04 +01:00
this._wasPressed = true;
2017-07-10 15:18:00 +02:00
this.downTime = control.millis()
control.raiseEvent(this._id, ButtonEvent.Down)
} else {
control.raiseEvent(this._id, ButtonEvent.Up)
2017-11-29 01:02:04 +01:00
const delta = control.millis() - this.downTime;
if (delta < 500)
control.raiseEvent(this._id, ButtonEvent.Click)
2017-07-10 15:18:00 +02:00
}
}
/**
* Check if button is currently pressed or not.
* @param button the button to query the request
*/
//% help=input/button/is-pressed
2017-12-20 00:10:13 +01:00
//% block="%button|is pressed"
2017-07-10 15:18:00 +02:00
//% blockId=buttonIsPressed
2017-10-25 01:25:03 +02:00
//% parts="brick"
2017-10-28 18:13:02 +02:00
//% blockNamespace=brick
//% weight=81 blockGap=8
2017-10-28 18:20:34 +02:00
//% group="Buttons"
//% button.fieldEditor="brickbuttons"
2017-07-10 15:18:00 +02:00
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
2017-12-20 00:10:13 +01:00
//% block="%button|was pressed"
2017-07-10 15:18:00 +02:00
//% blockId=buttonWasPressed
2017-10-25 01:25:03 +02:00
//% parts="brick"
2017-10-28 18:13:02 +02:00
//% blockNamespace=brick
//% weight=80
2017-10-28 18:20:34 +02:00
//% group="Buttons"
//% button.fieldEditor="brickbuttons"
2017-07-10 15:18:00 +02:00
wasPressed() {
const r = this._wasPressed
this._wasPressed = false
return r
}
/**
2017-10-27 06:10:37 +02:00
* Do something when a button or sensor is clicked, up or down.
2017-07-10 15:18:00 +02:00
* @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
2017-12-20 00:10:13 +01:00
//% blockId=buttonEvent block="on %button|%event"
2017-10-25 01:25:03 +02:00
//% parts="brick"
2017-10-28 18:13:02 +02:00
//% blockNamespace=brick
2017-10-25 00:58:47 +02:00
//% weight=99 blockGap=8
2017-10-28 18:20:34 +02:00
//% group="Buttons"
//% button.fieldEditor="brickbuttons"
2017-07-10 15:18:00 +02:00
onEvent(ev: ButtonEvent, body: () => void) {
control.onEvent(this._id, ev, body)
}
2017-11-30 19:05:00 +01:00
/**
* Waits until the event is raised
* @param ev the event to wait for
*/
2017-12-12 19:49:45 +01:00
//% help=input/button/pause-until
2017-12-20 00:10:13 +01:00
//% blockId=buttonWaitUntil block="pause until %button|%event"
2017-11-30 19:05:00 +01:00
//% parts="brick"
//% blockNamespace=brick
//% weight=98 blockGap=8
//% group="Buttons"
//% button.fieldEditor="brickbuttons"
pauseUntil(ev: ButtonEvent) {
2017-11-30 19:05:00 +01:00
control.waitForEvent(this._id, ev);
}
2017-07-10 15:18:00 +02:00
}
}
2017-10-28 18:13:02 +02:00
namespace brick {
2017-07-10 15:16:31 +02:00
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)
2017-07-10 15:16:31 +02:00
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
2018-01-06 07:56:11 +01:00
if (ret & DAL.BUTTON_ID_ESCAPE) {
control.reset()
2018-01-06 07:56:11 +01:00
}
2017-07-10 15:16:31 +02:00
return ret
}
function initBtns() {
if (btnsMM) return
btnsMM = control.mmap("/dev/lms_ui", DAL.NUM_BUTTONS, 0)
2017-07-10 15:16:31 +02:00
if (!btnsMM) control.fail("no buttons?")
buttons = []
2017-10-28 18:13:02 +02:00
sensors.internal.unsafePollForChanges(50, readButtons, (prev, curr) => {
2017-07-10 15:16:31 +02:00
for (let b of buttons)
2017-10-27 06:10:37 +02:00
b._update(!!(curr & b.mask))
2017-07-10 15:16:31 +02:00
})
control.dmesg("runtime started, " + control.deviceFirmwareVersion())
}
class DevButton extends Button {
mask: number
constructor(mask: number) {
super()
this.mask = mask
initBtns()
buttons.push(this)
}
2018-01-06 07:56:11 +01:00
}
2017-07-10 15:16:31 +02:00
initBtns() // always ON as it handles ESCAPE button
/**
* Enter button on the EV3 Brick.
*/
2017-11-17 07:03:43 +01:00
//% whenUsed block="enter" weight=95 fixedInstance
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
2017-07-10 15:16:31 +02:00
/**
2017-10-25 01:25:03 +02:00
* Left button on the EV3 Brick.
2017-07-10 15:16:31 +02:00
*/
2017-11-17 07:03:43 +01:00
//% whenUsed block="left" weight=95 fixedInstance
export const buttonLeft: Button = new DevButton(DAL.BUTTON_ID_LEFT)
2017-07-10 15:16:31 +02:00
/**
2017-10-25 01:25:03 +02:00
* Right button on the EV3 Brick.
2017-07-10 15:16:31 +02:00
*/
2017-11-17 07:03:43 +01:00
//% whenUsed block="right" weight=94 fixedInstance
export const buttonRight: Button = new DevButton(DAL.BUTTON_ID_RIGHT)
2017-07-10 15:16:31 +02:00
/**
2017-10-25 01:25:03 +02:00
* Up button on the EV3 Brick.
2017-07-10 15:16:31 +02:00
*/
2017-11-17 07:03:43 +01:00
//% whenUsed block="up" weight=95 fixedInstance
export const buttonUp: Button = new DevButton(DAL.BUTTON_ID_UP)
2017-07-10 15:16:31 +02:00
/**
2017-10-25 01:25:03 +02:00
* Down button on the EV3 Brick.
2017-07-10 15:16:31 +02:00
*/
2017-11-17 07:03:43 +01:00
//% whenUsed block="down" weight=95 fixedInstance
export const buttonDown: Button = new DevButton(DAL.BUTTON_ID_DOWN)
2017-07-10 15:16:31 +02:00
}
namespace control {
/**
* Determine the version of system software currently running.
*/
2018-01-06 07:56:11 +01:00
//%
2017-07-10 15:16:31 +02:00
export function deviceFirmwareVersion(): string {
let buf = output.createBuffer(6)
2017-10-28 18:13:02 +02:00
brick.internal.getBtnsMM().read(buf)
2017-07-10 15:16:31 +02:00
let r = ""
for (let i = 0; i < buf.length; ++i) {
let c = buf[i]
if (c == 0) break
r += String.fromCharCode(c)
}
return r
}
}
2017-10-28 18:13:02 +02:00
namespace brick {
2017-07-10 15:16:31 +02:00
let currPattern: LightsPattern
/**
* Set lights.
2017-08-08 02:39:37 +02:00
* @param pattern the lights pattern to use.
2017-07-10 15:16:31 +02:00
*/
2017-12-20 00:10:13 +01:00
//% blockId=setLights block="set light to %pattern=led_pattern"
//% weight=100 group="Buttons"
export function setLight(pattern: number): void {
2017-07-10 15:16:31 +02:00
if (currPattern === pattern)
return
currPattern = pattern
let cmd = output.createBuffer(2)
cmd[0] = pattern + 48
2017-10-28 18:13:02 +02:00
brick.internal.getBtnsMM().write(cmd)
2017-07-10 15:16:31 +02:00
}
2017-08-07 19:19:38 +02:00
/**
* Pattern block.
2017-08-08 02:39:37 +02:00
* @param pattern the lights pattern to use. eg: LightsPattern.Green
2017-08-07 19:19:38 +02:00
*/
//% blockId=led_pattern block="%pattern"
2017-10-28 18:13:02 +02:00
//% shim=TD_ID colorSecondary="#6e9a36" group="Light"
//% blockHidden=true useEnumVal=1 pattern.fieldOptions.decompileLiterals=1
2017-11-29 00:23:54 +01:00
export function lightPattern(pattern: LightsPattern): number {
2017-08-07 19:19:38 +02:00
return pattern;
}
2017-07-10 15:16:31 +02:00
}