Skip to content

Add support for data logging #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/board/conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import {
MICROBIT_HAL_ACCELEROMETER_EVT_TILT_LEFT,
MICROBIT_HAL_ACCELEROMETER_EVT_TILT_RIGHT,
MICROBIT_HAL_ACCELEROMETER_EVT_TILT_UP,
MICROBIT_HAL_LOG_TIMESTAMP_DAYS,
MICROBIT_HAL_LOG_TIMESTAMP_HOURS,
MICROBIT_HAL_LOG_TIMESTAMP_MILLISECONDS,
MICROBIT_HAL_LOG_TIMESTAMP_MINUTES,
MICROBIT_HAL_LOG_TIMESTAMP_NONE,
MICROBIT_HAL_LOG_TIMESTAMP_SECONDS,
MICROBIT_HAL_MICROPHONE_LEVEL_THRESHOLD_HIGH,
MICROBIT_HAL_MICROPHONE_LEVEL_THRESHOLD_LOW,
} from "./constants";
Expand Down Expand Up @@ -113,3 +119,22 @@ export function convertAccelerometerNumberToString(value: number): string {
throw new Error(`Invalid value ${value}`);
}
}

export function convertTimestampToString(value: number): string {
switch (value) {
case MICROBIT_HAL_LOG_TIMESTAMP_NONE:
return "none";
case MICROBIT_HAL_LOG_TIMESTAMP_MILLISECONDS:
return "milliseconds";
case MICROBIT_HAL_LOG_TIMESTAMP_SECONDS:
return "seconds";
case MICROBIT_HAL_LOG_TIMESTAMP_MINUTES:
return "minutes";
case MICROBIT_HAL_LOG_TIMESTAMP_HOURS:
return "hours";
case MICROBIT_HAL_LOG_TIMESTAMP_DAYS:
return "days";
default:
throw new Error(`Invalid value ${value}`);
}
}
35 changes: 35 additions & 0 deletions src/board/sensors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,38 @@ export class EnumSensor extends Sensor {
};
}
}

export interface LogData {
key: string;
value: string | number;
}

export class DataLoggingSensor extends Sensor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to radio, I'm unsure whether this fits the sensor model. Let's see how radio works out first.

public value: LogData[][] = [];
public period: string = "none";
public delete: boolean = false;
public serial: boolean = false;

constructor(id: string) {
super("log", id);
this.id = id;
}

setValue(value: any): void {
if (!Array.isArray(value)) {
throw this.valueError(value);
}
this.value = value;
}

toSerializable() {
return {
type: "log",
id: this.id,
value: this.value,
period: this.period,
serial: this.serial,
delete: this.delete,
};
}
}
79 changes: 79 additions & 0 deletions src/board/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import {
import {
convertAccelerometerStringToNumber,
convertSoundEventStringToNumber,
convertTimestampToString,
} from "./conversions";
import { FileSystem } from "./fs";
import { WebAssemblyOperations } from "./listener";
import {
DataLoggingSensor,
EnumSensor,
LogData,
RangeSensor,
RangeSensorWithThresholds,
Sensor,
Expand Down Expand Up @@ -45,6 +48,7 @@ export class BoardUI {
private temperature: RangeSensor;
private microphone: MicrophoneUI;
private accelerometer: AccelerometerUI;
private dataLogging: DataLoggingUI;

// Perhaps we can remove this?
public serialInputBuffer: number[] = [];
Expand Down Expand Up @@ -92,6 +96,7 @@ export class BoardUI {
this.svg.querySelector("#LitMicrophone")!,
onSensorChange
);
this.dataLogging = new DataLoggingUI("log", onSensorChange);

this.sensors = [
this.display.lightLevel,
Expand All @@ -103,6 +108,7 @@ export class BoardUI {
this.pins[MICROBIT_HAL_PIN_P0].pin,
this.pins[MICROBIT_HAL_PIN_P1].pin,
this.pins[MICROBIT_HAL_PIN_P2].pin,
this.dataLogging.log,
...this.accelerometer.sensors,
];
this.sensorsById = new Map();
Expand Down Expand Up @@ -142,6 +148,7 @@ export class BoardUI {
this.display.initialize();
this.accelerometer.initialize(this.operations.gestureCallback!);
this.microphone.initialize(this.operations.soundLevelCallback!);
this.dataLogging.initialize();
this.serialInputBuffer.length = 0;
}

Expand Down Expand Up @@ -227,6 +234,7 @@ export class BoardUI {
this.display.dispose();
this.accelerometer.dispose();
this.microphone.dispose();
this.dataLogging.dispose();
this.serialInputBuffer.length = 0;
}
}
Expand Down Expand Up @@ -624,3 +632,74 @@ export class PinUI {

dispose() {}
}

export class DataLoggingUI {
public log: DataLoggingSensor;
private beginRowFlag: boolean = false;
private endRowFlag: boolean = true;
private logData: LogData[] = [];
private startTime: number = 0;

constructor(label: string, private onSensorChange: () => void) {
this.log = new DataLoggingSensor(label);
}

delete() {
this.log.delete = true;
this.onSensorChange();
}

setMirroring(serial: boolean) {
this.log.serial = serial;
this.onSensorChange();
}

setTimestamp(period: number) {
this.log.period = convertTimestampToString(period);
this.onSensorChange();
}

beginRow() {
this.endRowFlag = false;
this.beginRowFlag = true;
}

endRow() {
this.beginRowFlag = false;
this.endRowFlag = true;
this.sendData();
}

setLogData(key: string, value: string) {
if (this.beginRowFlag && !this.endRowFlag) {
this.logData.push({ key, value });
}
}

sendData() {
if (!this.startTime) {
this.startTime = Date.now();
}
this.logData.unshift({
key: "timestamp",
value: Date.now() - this.startTime,
});
if (this.log.value) {
this.log.setValue([...this.log.value, this.logData]);
} else {
this.log.setValue([this.logData]);
}
this.onSensorChange();
this.logData = [];
}

initialize() {}

dispose() {
this.log.delete = false;
this.log.serial = false;
this.log.period = "none";
this.logData = [];
this.log.setValue([]);
}
}
9 changes: 8 additions & 1 deletion src/jshal.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,11 @@ bool mp_js_hal_audio_is_expression_active(void);

void mp_js_hal_microphone_init(void);
void mp_js_hal_microphone_set_threshold(int kind, int value);
int mp_js_hal_microphone_get_level(void);
int mp_js_hal_microphone_get_level(void);

void mp_js_hal_log_delete(bool full_erase);
void mp_js_hal_log_set_mirroring(bool serial);
void mp_js_hal_log_set_timestamp(int period);
int mp_js_hal_log_begin_row(void);
int mp_js_hal_log_end_row(void);
int mp_js_hal_log_data(const char *key, const char *value);
27 changes: 27 additions & 0 deletions src/jshal.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,31 @@ mergeInto(LibraryManager.library, {
mp_js_hal_audio_is_expression_active: function () {
return board.audio.isSoundExpressionActive();
},

mp_js_hal_log_delete: function (full_erase) {
board.dataLogging.delete();
},

mp_js_hal_log_set_mirroring: function (serial) {
board.dataLogging.setMirroring(serial);
},

mp_js_hal_log_set_timestamp: function (period) {
board.dataLogging.setTimestamp(period);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be some kind of conversion here?

},

mp_js_hal_log_begin_row: function () {
board.dataLogging.beginRow();
return 0;
},

mp_js_hal_log_end_row: function () {
board.dataLogging.endRow();
return 0;
},

mp_js_hal_log_data: function (key, value) {
board.dataLogging.setLogData(UTF8ToString(key), UTF8ToString(value));
return 0;
},
});
9 changes: 6 additions & 3 deletions src/microbithal_js.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,18 +376,21 @@ const uint8_t *microbit_hal_get_font_data(char c) {
}

void microbit_hal_log_delete(bool full_erase) {
mp_js_hal_log_delete(full_erase);
/*
uBit.log.clear(full_erase);
*/
}

void microbit_hal_log_set_mirroring(bool serial) {
mp_js_hal_log_set_mirroring(serial);
/*
uBit.log.setSerialMirroring(serial);
*/
}

void microbit_hal_log_set_timestamp(int period) {
mp_js_hal_log_set_timestamp(period);
/*
static_assert(MICROBIT_HAL_LOG_TIMESTAMP_NONE == (int)TimeStampFormat::None);
static_assert(MICROBIT_HAL_LOG_TIMESTAMP_MILLISECONDS == (int)TimeStampFormat::Milliseconds);
Expand All @@ -400,33 +403,33 @@ void microbit_hal_log_set_timestamp(int period) {
}

int microbit_hal_log_begin_row(void) {
return mp_js_hal_log_begin_row();
/*
if (uBit.log.beginRow() != DEVICE_OK) {
return -1;
}
return 0;
*/
return 0;
}

int microbit_hal_log_end_row(void) {
return mp_js_hal_log_end_row();
/*
if (uBit.log.endRow() != DEVICE_OK) {
return -1;
}
return 0;
*/
return 0;
}

int microbit_hal_log_data(const char *key, const char *value) {
return mp_js_hal_log_data(key, value);
/*
if (uBit.log.logData(key, value) != DEVICE_OK) {
return -1;
}
return 0;
*/
return 0;
}

// This is needed by the microbitfs implementation.
Expand Down