jacdac-ts
Advanced tools
Comparing version 1.0.12 to 1.0.13
/// <reference types="node" /> | ||
import { Packet } from "./packet"; | ||
import { ConsolePriority } from "./constants"; | ||
import { EventEmitter } from "./eventemitter"; | ||
export interface BusOptions { | ||
sendPacket: (p: Packet) => Promise<void>; | ||
disconnect: () => Promise<void>; | ||
} | ||
export interface PacketEventEmitter { | ||
/** | ||
* Event emitted when the bus is disconnected | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'disconnect', listener: () => void): boolean; | ||
/** | ||
* Event emitted when a packet is received and processed | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'packet', listener: (packet: Packet) => void): boolean; | ||
/** | ||
* Event containing an event from a sensor | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'packetevent', listener: (packet: Packet) => void): boolean; | ||
/** | ||
* Event emitted when a device is detected on the bus. The information on the device might not be fully populated yet. | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'deviceconnect', listener: (device: Device) => void): boolean; | ||
/** | ||
* Event emitted when a device hasn't been on the bus for a while and is considered disconected. | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'devicedisconnect', listener: (device: Device) => void): boolean; | ||
/** | ||
* Event emitted device advertisement information for a device has been updated | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'deviceannounce', listener: (device: Device) => void): boolean; | ||
} | ||
/** | ||
* A JACDAC bus manager. This instance maintains the list of devices on the bus. | ||
*/ | ||
export declare class Bus extends EventEmitter implements PacketEventEmitter { | ||
options: BusOptions; | ||
private _devices; | ||
private _deviceNames; | ||
private _startTime; | ||
private _gcInterval; | ||
private _minConsolePriority; | ||
/** | ||
* Creates the bus with the given transport | ||
* @param sendPacket | ||
*/ | ||
constructor(options: BusOptions); | ||
get timestamp(): number; | ||
get minConsolePriority(): ConsolePriority; | ||
set minConsolePriority(priority: ConsolePriority); | ||
private pingLoggers; | ||
sendPacket(p: Packet): Promise<void>; | ||
disconnect(): Promise<void>; | ||
/** | ||
* Gets the current list of known devices on the bus | ||
*/ | ||
devices(): Device[]; | ||
/** | ||
* Gets a device on the bus | ||
* @param id | ||
*/ | ||
device(id: string): Device; | ||
private gcDevices; | ||
/** | ||
* Ingests and process a packet received from the bus. | ||
* @param pkt a jacdac packet | ||
*/ | ||
processPacket(pkt: Packet): void; | ||
/** | ||
* Tries to find the given device by id | ||
* @param id | ||
*/ | ||
lookupName(id: string): string; | ||
log(msg: any): void; | ||
} | ||
import { Bus } from "./bus"; | ||
export declare class Device { | ||
@@ -91,0 +4,0 @@ bus: Bus; |
/// <reference types="w3c-web-usb" /> | ||
import * as U from "./utils"; | ||
import { Bus } from "./device"; | ||
import { Bus } from "./bus"; | ||
export declare const HF2_DEVICE_MAJOR = 42; | ||
@@ -5,0 +5,0 @@ export declare const HF2_CMD_BININFO = 1; |
@@ -9,4 +9,5 @@ export * from './constants'; | ||
export * from './device'; | ||
export * from './bus'; | ||
export * from './hf2'; | ||
export * from './sensor'; | ||
export * from './pretty'; |
@@ -1,3 +0,4 @@ | ||
import { Device, Bus } from "./device"; | ||
import { Device } from "./device"; | ||
import { NumberFormat } from "./buffer"; | ||
import { Bus } from "./bus"; | ||
export declare class Packet { | ||
@@ -4,0 +5,0 @@ _header: Uint8Array; |
import { Device } from "./device"; | ||
export declare class Client { | ||
device: Device; | ||
service_class: number; | ||
constructor(device: Device, service_class: number); | ||
protected setRegIntAsync(reg: number, value: number): Promise<void>; | ||
service_number: number; | ||
constructor(device: Device, service_number: number); | ||
setRegIntAsync(reg: number, value: number): Promise<void>; | ||
sendCmdAsync(cmd: number): Promise<void>; | ||
} | ||
export declare class SensorClient extends Client { | ||
device: Device; | ||
service_class: number; | ||
constructor(device: Device, service_class: number); | ||
static from(device: Device, service_class: number): SensorClient; | ||
service_number: number; | ||
constructor(device: Device, service_number: number); | ||
static fromFirstServiceClass(device: Device, service_class: number): SensorClient; | ||
setStreamingAsync(on: boolean): Promise<void>; | ||
@@ -14,0 +15,0 @@ calibrateAsync(): Promise<void>; |
{ | ||
"name": "jacdac-ts", | ||
"version": "1.0.12", | ||
"version": "1.0.13", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "keywords": [], |
import { Packet } from "./packet" | ||
import { JD_SERVICE_NUMBER_CTRL, CMD_ADVERTISEMENT_DATA, ConsolePriority, CMD_CONSOLE_SET_MIN_PRIORITY, JD_SERVICE_LOGGER, CMD_EVENT } from "./constants" | ||
import { JD_SERVICE_NUMBER_CTRL } from "./constants" | ||
import { hash, fromHex, idiv, read32, SMap, bufferEq } from "./utils" | ||
import { EventEmitter } from "./eventemitter" | ||
import { getNumber, NumberFormat } from "./buffer"; | ||
import { Bus } from "./bus"; | ||
export interface BusOptions { | ||
sendPacket: (p: Packet) => Promise<void>; | ||
disconnect: () => Promise<void>; | ||
} | ||
export interface PacketEventEmitter { | ||
/** | ||
* Event emitted when the bus is disconnected | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'disconnect', listener: () => void): boolean; | ||
/** | ||
* Event emitted when a packet is received and processed | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'packet', listener: (packet: Packet) => void): boolean; | ||
/** | ||
* Event containing an event from a sensor | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'packetevent', listener: (packet: Packet) => void): boolean; | ||
/** | ||
* Event emitted when a device is detected on the bus. The information on the device might not be fully populated yet. | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'deviceconnect', listener: (device: Device) => void): boolean; | ||
/** | ||
* Event emitted when a device hasn't been on the bus for a while and is considered disconected. | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'devicedisconnect', listener: (device: Device) => void): boolean; | ||
/** | ||
* Event emitted device advertisement information for a device has been updated | ||
* @param event | ||
* @param listener | ||
*/ | ||
on(event: 'deviceannounce', listener: (device: Device) => void): boolean; | ||
} | ||
/** | ||
* A JACDAC bus manager. This instance maintains the list of devices on the bus. | ||
*/ | ||
export class Bus extends EventEmitter implements PacketEventEmitter { | ||
private _devices: Device[] = []; | ||
private _deviceNames: SMap<string> = {}; | ||
private _startTime: number; | ||
private _gcInterval: any; | ||
private _minConsolePriority = ConsolePriority.Log; | ||
/** | ||
* Creates the bus with the given transport | ||
* @param sendPacket | ||
*/ | ||
constructor(public options: BusOptions) { | ||
super(); | ||
this._startTime = Date.now(); | ||
this.on('deviceannounce', () => this.pingLoggers()); | ||
} | ||
get timestamp() { | ||
return Date.now() - this._startTime; | ||
} | ||
get minConsolePriority(): ConsolePriority { | ||
return this._minConsolePriority; | ||
} | ||
set minConsolePriority(priority: ConsolePriority) { | ||
if (priority !== this._minConsolePriority) { | ||
this._minConsolePriority = priority; | ||
} | ||
} | ||
private pingLoggers() { | ||
if (this._minConsolePriority < ConsolePriority.Silent) { | ||
const pkt = Packet.packed(CMD_CONSOLE_SET_MIN_PRIORITY, "i", [this._minConsolePriority]); | ||
pkt.sendAsMultiCommandAsync(this, JD_SERVICE_LOGGER); | ||
} | ||
} | ||
sendPacket(p: Packet) { | ||
return this.options.sendPacket(p); | ||
} | ||
disconnect(): Promise<void> { | ||
if (this._gcInterval) { | ||
clearInterval(this._gcInterval); | ||
this._gcInterval = undefined; | ||
} | ||
return this.options.disconnect() | ||
.then(() => { this.emit("disconnect") }) | ||
} | ||
/** | ||
* Gets the current list of known devices on the bus | ||
*/ | ||
devices() { return this._devices.slice() } | ||
/** | ||
* Gets a device on the bus | ||
* @param id | ||
*/ | ||
device(id: string) { | ||
let d = this._devices.find(d => d.deviceId == id) | ||
if (!d) { | ||
d = new Device(this, id) | ||
this._devices.push(d); | ||
this.emit('deviceconnect', d); | ||
if (!this._gcInterval) | ||
this._gcInterval = setInterval(() => this.gcDevices(), 2000); | ||
} | ||
return d | ||
} | ||
private gcDevices() { | ||
const cutoff = this.timestamp - 2000; | ||
for (let i = 0; i < this._devices.length; ++i) { | ||
const dev = this._devices[i] | ||
if (dev.lastSeen < cutoff) { | ||
this._devices.splice(i, 1) | ||
i-- | ||
dev.disconnect(); | ||
this.emit('devicedisconnect', dev); | ||
} | ||
} | ||
} | ||
/** | ||
* Ingests and process a packet received from the bus. | ||
* @param pkt a jacdac packet | ||
*/ | ||
processPacket(pkt: Packet) { | ||
if (pkt.multicommand_class) { | ||
// | ||
} else if (pkt.is_command) { | ||
pkt.dev = this.device(pkt.device_identifier) | ||
} else { | ||
const dev = pkt.dev = this.device(pkt.device_identifier) | ||
dev.lastSeen = pkt.timestamp | ||
if (pkt.service_number == JD_SERVICE_NUMBER_CTRL) { | ||
if (pkt.service_command == CMD_ADVERTISEMENT_DATA) { | ||
if (!bufferEq(pkt.data, dev.services)) { | ||
dev.services = pkt.data | ||
dev.lastServiceUpdate = pkt.timestamp | ||
this.emit('deviceannounce', dev); | ||
} | ||
} | ||
} | ||
} | ||
// don't spam with duplicate advertisement events | ||
if (pkt.service_command !== CMD_ADVERTISEMENT_DATA) { | ||
this.emit('packet', pkt) | ||
} | ||
} | ||
/** | ||
* Tries to find the given device by id | ||
* @param id | ||
*/ | ||
lookupName(id: string) { | ||
return this._deviceNames[id]; | ||
} | ||
log(msg: any) { | ||
if (this._minConsolePriority > ConsolePriority.Log) | ||
return | ||
console.log(msg); | ||
} | ||
} | ||
export class Device { | ||
@@ -191,0 +8,0 @@ connected: boolean; |
import * as U from "./utils" | ||
import { Bus } from "./device"; | ||
import { Bus } from "./bus"; | ||
import { Packet } from "./packet"; | ||
@@ -435,11 +435,9 @@ | ||
await hf2.init() | ||
const startTime = Date.now(); | ||
const bus = new Bus({ | ||
sendPacket: p => { | ||
sendPacketAsync: p => { | ||
const buf = p.toBuffer(); | ||
return hf2.sendJDMessageAsync(buf) | ||
.then(() => { }); | ||
//.catch(err => log(err)); TODO | ||
.then(() => { }, err => console.log(err)); | ||
}, | ||
disconnect: () => hf2.disconnectAsync() | ||
disconnectAsync: () => hf2.disconnectAsync() | ||
}); | ||
@@ -446,0 +444,0 @@ hf2.onJDMessage(buf => { |
@@ -9,4 +9,5 @@ export * from './constants' | ||
export * from './device' | ||
export * from './bus' | ||
export * from './hf2' | ||
export * from './sensor' | ||
export * from './pretty' |
@@ -12,5 +12,6 @@ import { warn, crc, ALIGN, write16, bufferConcat, toHex, fromHex, error, read32, read16, write32 } from "./utils"; | ||
} from "./constants"; | ||
import { Device, Bus } from "./device"; | ||
import { Device } from "./device"; | ||
import { NumberFormat, getNumber } from "./buffer"; | ||
import { pack } from "./struct"; | ||
import { Bus } from "./bus"; | ||
@@ -195,3 +196,3 @@ export class Packet { | ||
write16(this._header, 0, crc(bufferConcat(this._header.slice(2), this._data))) | ||
return bus.sendPacket(this) | ||
return bus.sendPacketAsync(this) | ||
} | ||
@@ -198,0 +199,0 @@ |
@@ -137,3 +137,3 @@ import * as U from "./utils" | ||
const id = device.serviceClassAt(i); | ||
const name = serviceName(id); | ||
const name = `${i}:${serviceName(id)}`; | ||
if (i) srv += ", " | ||
@@ -216,3 +216,3 @@ srv += name; | ||
return Math.round(pkt.timestamp) + "ms: " + pdesc | ||
return (!isNaN(pkt.timestamp) ? Math.round(pkt.timestamp) + "ms: " : "") + pdesc | ||
} | ||
@@ -219,0 +219,0 @@ |
import { Device } from "./device"; | ||
import { Packet } from "./packet"; | ||
import { CMD_SET_REG, REG_IS_STREAMING, CMD_CALIBRATE, REG_LOW_THRESHOLD } from "./constants"; | ||
import { SMap } from "./utils"; | ||
import { CMD_SET_REG, REG_IS_STREAMING, CMD_CALIBRATE, REG_LOW_THRESHOLD, CMD_GET_REG } from "./constants"; | ||
@@ -9,10 +8,16 @@ export class Client { | ||
public device: Device, | ||
public service_class: number) { | ||
public service_number: number) { | ||
} | ||
protected setRegIntAsync(reg: number, value: number): Promise<void> { | ||
setRegIntAsync(reg: number, value: number): Promise<void> { | ||
const pkt = Packet.packed(CMD_SET_REG | reg, "i", [value]); | ||
pkt.service_number = this.service_number; | ||
return pkt.sendCmdAsync(this.device); | ||
} | ||
sendCmdAsync(cmd: number) { | ||
const pkt = Packet.onlyHeader(cmd); | ||
pkt.service_number = this.service_number; | ||
return pkt.sendCmdAsync(this.device); | ||
} | ||
} | ||
@@ -23,9 +28,12 @@ | ||
public device: Device, | ||
public service_class: number) { | ||
super(device, service_class); | ||
public service_number: number) { | ||
super(device, service_number); | ||
} | ||
static from(device: Device, service_class: number): SensorClient { | ||
if (device && device.hasService(service_class)) | ||
return new SensorClient(device, service_class); | ||
static fromFirstServiceClass(device: Device, service_class: number): SensorClient { | ||
const n = device.serviceLength; | ||
for (let i = 0; i < n; ++i) { | ||
if (device.serviceClassAt(i) == service_class) | ||
return new SensorClient(device, i); | ||
} | ||
return undefined; | ||
@@ -39,4 +47,3 @@ } | ||
public calibrateAsync() { | ||
const pkt = Packet.onlyHeader(CMD_CALIBRATE); | ||
return pkt.sendCmdAsync(this.device); | ||
return this.sendCmdAsync(CMD_CALIBRATE); | ||
} | ||
@@ -43,0 +50,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
496511
36
6536