From 2719cf9007a3a172d0afbbed993b2dee59cc0cd1 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 10 Feb 2024 20:51:32 +0000 Subject: [PATCH 001/109] assets.ts & tooltips.ts: added new icons & updated ariaID.ts appopriately. --- assets.ts | 282 ++++++++++++++-------------------------------------- tooltips.ts | 11 +- 2 files changed, 83 insertions(+), 210 deletions(-) diff --git a/assets.ts b/assets.ts index c949667..c9f8628 100644 --- a/assets.ts +++ b/assets.ts @@ -19,64 +19,6 @@ namespace microcode { extraImage = icondb.sampleRailCrossingLight } - function carImages(name: string) { - if (name == TID_ACTUATOR_CAR) return icondb.car - if (name == TID_MODIFIER_CAR_FORWARD) return icondb.car_forward - if (name == TID_MODIFIER_CAR_REVERSE) return icondb.car_reverse - if (name == TID_MODIFIER_CAR_TURN_LEFT) return icondb.car_left_turn - if (name == TID_MODIFIER_CAR_TURN_RIGHT) return icondb.car_right_turn - if (name == TID_MODIFIER_CAR_STOP) return icondb.car_stop - if (name == TID_MODIFIER_CAR_FORWARD_FAST) - return icondb.car_forward_fast - if (name == TID_MODIFIER_CAR_SPIN_LEFT) return icondb.car_left_spin - if (name == TID_MODIFIER_CAR_SPIN_RIGHT) return icondb.car_right_spin - if (name == TID_MODIFIER_CAR_LED_COLOR_1) return icondb.tile_color_red - if (name == TID_MODIFIER_CAR_LED_COLOR_2) return icondb.tile_color_green - if (name == TID_MODIFIER_CAR_LED_COLOR_3) return icondb.tile_color_blue - if (name == TID_MODIFIER_CAR_LED_COLOR_4) return icondb.tile_color_black - if (name == TID_MODIFIER_CAR_ARM_OPEN) return icondb.arm_open - if (name == TID_MODIFIER_CAR_ARM_CLOSE) return icondb.arm_close - if (name == TID_SENSOR_CAR_WALL) return icondb.car_wall - if (name == TID_SENSOR_LINE) return icondb.line_sensor - if (name == TID_FILTER_LINE_LEFT) return icondb.line_left_on - if (name == TID_FILTER_LINE_RIGHT) return icondb.line_right_on - if (name == TID_FILTER_LINE_BOTH) return icondb.line_both_on - if (name == TID_FILTER_LINE_NEITHER) return icondb.line_neither_on - if (name == TID_FILTER_LINE_NEITHER_LEFT) - return icondb.line_none_from_left - if (name == TID_FILTER_LINE_NEITHER_RIGHT) - return icondb.line_none_from_right - return null - } - - // TODO: factor out all the jacdac stuff into separate file/class - // TODO: so we can generate different builds - function jacdacImages(name: string) { - if (name == TID_FILTER_KITA_KEY_1) return icondb.kita_key_1 - if (name == TID_FILTER_KITA_KEY_2) return icondb.kita_key_2 - if (name == TID_SENSOR_MAGNET) return icondb.magnet - if (name == TID_SENSOR_SLIDER) return icondb.kita_slider - if (name == TID_SENSOR_ROTARY) return icondb.kita_rotary - if (name == TID_FILTER_ROTARY_LEFT) return icondb.kita_rotary_left - if (name == TID_FILTER_ROTARY_RIGHT) return icondb.kita_rotary_right - if (name == TID_ACTUATOR_RGB_LED) return icondb.rgbLed - if (name == TID_MODIFIER_RGB_LED_COLOR_1) return icondb.tile_color_red - if (name == TID_MODIFIER_RGB_LED_COLOR_2) return icondb.tile_color_green - if (name == TID_MODIFIER_RGB_LED_COLOR_3) return icondb.tile_color_blue - if (name == TID_MODIFIER_RGB_LED_COLOR_4) - return icondb.tile_color_magenta - if (name == TID_MODIFIER_RGB_LED_COLOR_5) - return icondb.tile_color_yellow - if (name == TID_MODIFIER_RGB_LED_COLOR_6) return icondb.tile_color_black - if (name == TID_MODIFIER_RGB_LED_COLOR_RAINBOW) - return icondb.tile_rainbow - if (name == TID_MODIFIER_RGB_LED_COLOR_SPARKLE) - return icondb.tile_sparkle - if (name == TID_ACTUATOR_SERVO_SET_ANGLE) return icondb.servo_set_angle - if (name == TID_SENSOR_LIGHT) return icondb.light_sensor - return null - } - export class icons { public static get(name: string, nullIfMissing = false): SImage { // editor icons @@ -108,116 +50,13 @@ namespace microcode { // sample icons if (name == "smiley_buttons") return icondb.sampleSmileyButtons - // pages - - if (name == TID_SENSOR_START_PAGE) return icondb.tile_start_page - if (name == TID_ACTUATOR_SWITCH_PAGE) return icondb.tile_switch_page - if (name == TID_MODIFIER_PAGE_1) return icondb.tile_page_1 - if (name == TID_MODIFIER_PAGE_2) return icondb.tile_page_2 - if (name == TID_MODIFIER_PAGE_3) return icondb.tile_page_3 - if (name == TID_MODIFIER_PAGE_4) return icondb.tile_page_4 - if (name == TID_MODIFIER_PAGE_5) return icondb.tile_page_5 - - // looping - if (name == TID_MODIFIER_LOOP) return icondb.loop - - // variables - - if (name == TID_SENSOR_CUP_X_WRITTEN) return icondb.cupXwritten - if (name == TID_SENSOR_CUP_Y_WRITTEN) return icondb.cupYwritten - if (name == TID_SENSOR_CUP_Z_WRITTEN) return icondb.cupZwritten - if (name == TID_FILTER_CUP_X_READ) return icondb.cupXread - if (name == TID_FILTER_CUP_Y_READ) return icondb.cupYread - if (name == TID_FILTER_CUP_Z_READ) return icondb.cupZread - if (name == TID_ACTUATOR_CUP_X_ASSIGN) return icondb.cupXassign - if (name == TID_ACTUATOR_CUP_Y_ASSIGN) return icondb.cupYassign - if (name == TID_ACTUATOR_CUP_Z_ASSIGN) return icondb.cupZassign - if (name == TID_MODIFIER_CUP_X_READ) return icondb.cupXread - if (name == TID_MODIFIER_CUP_Y_READ) return icondb.cupYread - if (name == TID_MODIFIER_CUP_Z_READ) return icondb.cupZread - - // numbers - if (name == TID_MODIFIER_RANDOM_TOSS) return icondb.diceToss - if (name == TID_FILTER_COIN_1) return icondb.blocks1 - if (name == TID_FILTER_COIN_2) return icondb.blocks2 - if (name == TID_FILTER_COIN_3) return icondb.blocks3 - if (name == TID_FILTER_COIN_4) return icondb.blocks4 - if (name == TID_FILTER_COIN_5) return icondb.blocks5 - if (name == TID_MODIFIER_COIN_1) return icondb.blocks1 - if (name == TID_MODIFIER_COIN_2) return icondb.blocks2 - if (name == TID_MODIFIER_COIN_3) return icondb.blocks3 - if (name == TID_MODIFIER_COIN_4) return icondb.blocks4 - if (name == TID_MODIFIER_COIN_5) return icondb.blocks5 - - // micro:bit sensors - if (name == TID_SENSOR_ACCELEROMETER) return icondb.accelerometer - if (name == TID_SENSOR_TIMER) return icondb.tile_timer - if (name == TID_SENSOR_RADIO_RECEIVE) return icondb.radio_receive - if (name == TID_SENSOR_PRESS) return icondb.finger_press - if (name == TID_SENSOR_RELEASE) return icondb.finger_release - if (name == TID_SENSOR_MICROPHONE) return icondb.microphone - if (name == TID_SENSOR_TEMP) return icondb.thermometer - if (name == TID_SENSOR_LED_LIGHT) return icondb.led_light_sensor - - // micro:bit filters - if (name == TID_FILTER_LOGO) return icondb.microbit_logo - if (name == TID_FILTER_PIN_0) return icondb.tile_pin_0 - if (name == TID_FILTER_PIN_1) return icondb.tile_pin_1 - if (name == TID_FILTER_PIN_2) return icondb.tile_pin_2 - if (name == TID_FILTER_BUTTON_A) return icondb.tile_button_a - if (name == TID_FILTER_BUTTON_B) return icondb.tile_button_b - if (name == TID_FILTER_TIMESPAN_SHORT) - return icondb.tile_timespan_short - if (name == TID_FILTER_TIMESPAN_LONG) - return icondb.tile_timespan_long - if (name == TID_FILTER_TIMESPAN_VERY_LONG) - return icondb.tile_timespan_fiveSeconds - if (name == TID_FILTER_TIMESPAN_RANDOM) - return icondb.tile_timespan_random - if (name == TID_FILTER_LOUD) return icondb.speaker - if (name == TID_FILTER_TEMP_WARMER) return icondb.temp_warmer - if (name == TID_FILTER_TEMP_COLDER) return icondb.temp_colder - if (name == TID_FILTER_ACCEL_SHAKE) return icondb.moveShake - if (name == TID_FILTER_ACCEL_TILT_UP) return icondb.moveTiltUp - if (name == TID_FILTER_ACCEL_TILT_DOWN) return icondb.moveTiltDown - if (name == TID_FILTER_ACCEL_TILT_LEFT) return icondb.moveTiltLeft - if (name == TID_FILTER_ACCEL_TILT_RIGHT) return icondb.moveTiltRight - if (name == TID_FILTER_ACCEL_FACE_UP) return icondb.moveFaceUp - if (name == TID_FILTER_ACCEL_FACE_DOWN) return icondb.moveFaceDown - - // micro:bit actuators - if (name == TID_ACTUATOR_PAINT) return icondb.showScreen - if (name == TID_ACTUATOR_SHOW_NUMBER) return icondb.showNumber - if (name == TID_ACTUATOR_RADIO_SEND) return icondb.radio_send - if (name == TID_ACTUATOR_RADIO_SET_GROUP) - return icondb.radio_set_group - if (name == TID_ACTUATOR_SPEAKER) return icondb.speakerFun - if (name == TID_ACTUATOR_MUSIC) return icondb.music - - // micro:bit modifiers - if (name == TID_MODIFIER_ICON_EDITOR) return icondb.iconEditor - if (name == TID_MODIFIER_MELODY_EDITOR) return icondb.melodyEditor - - if (name == TID_MODIFIER_EMOJI_GIGGLE) return icondb.soundGiggle - if (name == TID_MODIFIER_EMOJI_HAPPY) return icondb.soundHappy - if (name == TID_MODIFIER_EMOJI_HELLO) return icondb.soundHello - if (name == TID_MODIFIER_EMOJI_MYSTERIOUS) - return icondb.soundMysterious - if (name == TID_MODIFIER_EMOJI_SAD) return icondb.soundSad - if (name == TID_MODIFIER_EMOJI_SLIDE) return icondb.soundSlide - if (name == TID_MODIFIER_EMOJI_SOARING) return icondb.soundSoaring - if (name == TID_MODIFIER_EMOJI_SPRING) return icondb.soundSpring - if (name == TID_MODIFIER_EMOJI_TWINKLE) return icondb.soundTwinkle - if (name == TID_MODIFIER_EMOJI_YAWN) return icondb.soundYawn - - if (name == TID_MODIFIER_TEMP_READ) return icondb.thermometer - if (name == TID_MODIFIER_RADIO_VALUE) return icondb.radio_value - - // micro:bit car - const car = carImages(name) - if (car) return car - const jacdac = jacdacImages(name) - if (jacdac) return jacdac + // Newly added icons for MicroData Home menu: + if (name == "linear_graph") return icondb.linearGraph + + if (name == "led_light_sensor") return icondb.led_light_sensor + if (name == "thermometer") return icondb.thermometer + if (name == "accelerometer") return icondb.accelerometer + extraImage = null extraSamples(name) // only for web app if (extraImage) return extraImage @@ -227,29 +66,30 @@ namespace microcode { } export const wordLogo = img` - .111111.......111111...1111.......................................................1111111.................................1111.................. - 11bbbbbb.....11bbbbbb.11bbbb....................................................111bbbbbbb1..............................11bbbb................. - 1bbbbbbbb...11bbbbbbbf1bbbbbf..................................................11bbbbbbbbbbb.............................1bbbbbf................ - 1bbbbbbbbb.11bbbbbbbbf1bbbbbf.................................................11bbbbbbbbbbbbb............................1bbbbbf................ - 1bbbbbbbbbb1bbbbbbbbbf1bbbbbf................................................11bbbbbbbbbbbbbbb...........................1bbbbbf................ - 1bbbbbbbbbbbbbbbbbbbbf.bbbbff...............................................11bbbbbbbbbbbbbbbbf..........................1bbbbbf................ - 1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111......1bbbbbbbbbbbbbbbbbb.....1111111.........111111bbbbbf....1111111..... - 1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...11bbbbbbbfffbbbbbbbbf..111bbbbbbb1.....111bbbbbbbbbbf..111bbbbbbb1... - 1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbbbbbff...bbbbbbbf.11bbbbbbbbbbb...11bbbbbbbbbbbbf.11bbbbbbbbbbb.. - 1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbff.....bbbbbff.1bbbbbbbbbbbbf..1bbbbbbbbbbbbbf.1bbbbbbbbbbbbf. - 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.1bbbbbbf.......fffff.11bbbbbbbbbbbbb.11bbbbbbbbbbbbbf11bbbbfffbbbbbb. - 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbf1bbbbbbf......11111..1bbbbbfffbbbbbbf1bbbbbfffbbbbbbf1bbbbff...bbbbbf - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbf1bbbbbbb.....11bbbbb.1bbbbff...bbbbbf1bbbbff..1bbbbbf1bbbbb11111bbbbf - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbf1bbbbbbbb...11bbbbbbf1bbbbf....1bbbbf1bbbbf...1bbbbbf1bbbbbbbbbbbbbbf - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbf.bbbbbbbbb111bbbbbbbf1bbbbf....1bbbbf1bbbbf...1bbbbbf1bbbbbbbbbbbbbff - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbf.1bbbbbbbbbbbbbbbbbff1bbbbb...11bbbbf1bbbbb...1bbbbbf1bbbbffffffffff. - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbf..bbbbbbbbbbbbbbbbbf.1bbbbbb111bbbbbf1bbbbbb111bbbbbf1bbbbb.......... - 1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbff...bbbbbbbbbbbbbbbff..bbbbbbbbbbbbbff.bbbbbbbbbbbbbbf.bbbbbb11111.... - 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.....bbbbbbbbbbbbbff...1bbbbbbbbbbbbf..1bbbbbbbbbbbbbf.1bbbbbbbbbbb... - 1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff......bbbbbbbbbbbff.....bbbbbbbbbbbff...bbbbbbbbbbbbbf..bbbbbbbbbbbf.. - .bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff........fbbbbbbbfff.......fbbbbbbbfff.....fbbbbbbbbbbff...fbbbbbbbbff.. - ..fffff.........fffff...ffff......fffffff......ffff.............fffffff............fffffff...........fffffff.........ffffffffff......ffffffff... + .111111.......111111...1111..........................................................1111.......................1111...................................... + 11bbbbbb.....11bbbbbb.11bbbb........................................................11bbbb.....................11bbbb..................................... + 1bbbbbbbb...11bbbbbbbf1bbbbbf.......................................................1bbbbbf....................1bbbbbf.................................... + 1bbbbbbbbb.11bbbbbbbbf1bbbbbf.......................................................1bbbbbf....................1bbbbbf.................................... + 1bbbbbbbbbb1bbbbbbbbbf1bbbbbf.......................................................1bbbbbf....................1bbbbbf.................................... + 1bbbbbbbbbbbbbbbbbbbbf.bbbbff.......................................................1bbbbbf....................1bbbbbf.................................... + 1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111.........111111bbbbbf.....11111bb........1bbbbbb11111111111..11111bb................ + 1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1.....111bbbbbbbbbbf...11bbbbbbbbb......1bbbbbbbbbbbbbbbfff1bbbbbbbbb.............. + 1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb...11bbbbbbbbbbbbf..1bbbbbbbbbbbbf....11bbbbbbbbbbbbbbf.1bbbbbbbbbbbbf........... + 1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf..1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbf....1bbbbbff.........1bbbbbbbbbbbbbf........... + 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.11bbbbbbbbbbbbbf11bbbbbbbbbbbbbf....11bbbbbf.........11bbbbbbbbbbbbbf.......... + 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbbbbf....1bbbbbff.........1bbbbbfffbbbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbf1bbbbff..1bbbbbf1bbbbff..1bbbbbf....1bbbbfff.........1bbbbff..1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbf1bbbbf...1bbbbbf1bbbbf...1bbbbbf....1bbbbfff.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbf1bbbbf...1bbbbbf1bbbbf...1bbbbbf....1bbbbfff.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbf1bbbbb...1bbbbbf1bbbbb...1bbbbbf....1bbbbbff.........1bbbbb...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbf1bbbbbb111bbbbbf1bbbbbb111bbbbbf....1bbbbbbf.........1bbbbbb111bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbff.bbbbbbbbbbbbbbf.bbbbbbbbbbbbbb1111.bbbbbbbb111111111.bbbbbbbbbbbbbbb1111...... + 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf..1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf..... + 1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff...bbbbbbbbbbbbbf..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbf...... + .bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff.....fbbbbbbbbbbff...fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbf...... + ..fffff.........fffff...ffff......fffffff......ffff.............fffffff.........ffffffffff......ffffffffffffff....ffffffffffffff....fffffffffffffff....... ` + export const microbitLogo = img` ............................ ......5555555555555555...... @@ -295,19 +135,6 @@ namespace icondb { f c c . f c c . ` - export function melodyToImage(melody: microcode.Melody) { - const ret = simage.create(16, 16) - ret.fill(1) - for (let col = 0; col < microcode.MELODY_LENGTH; col++) { - if (melody.notes[col] === ".") continue - const row = microcode.NUM_NOTES - 1 - parseInt(melody.notes[col]) - const color = 15 - const ncol = col << 2, - nrow = row * 3 + 1 - ret.drawTransparentImage(note4x3, ncol, nrow) - } - return ret - } // - upscale 5x5 image to 16 x 16, add halo export function renderMicrobitLEDs(led55: SImage) { @@ -1629,7 +1456,7 @@ namespace icondb { . . . . . . . . . . . . . . . . ` -export const led_light_sensor = img` + export const led_light_sensor = img` . . . . . . . . . . . . . . . . . . 8 8 8 8 5 5 5 8 8 8 8 . . . . . 8 8 8 5 4 4 4 5 8 8 8 . . . @@ -1647,7 +1474,7 @@ export const led_light_sensor = img` . . 8 f f f f f f f f f 8 . . . . . . . . . . . . . . . . . . . ` - + export const light_sensor = img` . . . . . . . . . . . . . . . . . . 8 8 8 8 5 5 5 8 8 8 8 . . . @@ -2071,8 +1898,8 @@ export const led_light_sensor = img` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ` - -export const moveFaceUp = img` + + export const moveFaceUp = img` . . . . . . . . . . . . . . . . . . . . . . . 8 . . . . . . . . . . . . . . 8 8 8 . . . . . . . @@ -2090,7 +1917,7 @@ f f f f f f f f f f f f f f f . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ` -export const moveFaceDown = img` + export const moveFaceDown = img` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -2108,7 +1935,7 @@ export const moveFaceDown = img` . . . . . . . . 8 . . . . . . . . . . . . . . . . . . . . . . . ` - + export const diceToss = img` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -2469,6 +2296,43 @@ export const moveFaceDown = img` .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. `*/ + + export const linearGraph = img` +.111111111111111111111111111111. +11111111111111111111111111111111 +11ff1111111111111111111111111111 +11ff1111111111111111111111114111 +11ff1111111111111111111111144111 +11ff1111111111111111111111441111 +11ff1111111111111111111114411111 +11ff1111111111111111111144111111 +11ff1111111111111111111441111111 +11ff1111111111111111114411111111 +11ff1111111111111111144111111111 +11ff1111111111111111441111111111 +11ff1111111111111114411111111111 +11ff1111111111111144111111111111 +11ff1111111111111441111111111111 +11ff1111111111114411111111111111 +11ff1111111111144111111111111111 +11ff1111111111441111111111111111 +11ff1111111114411111111111111111 +11ff1111111144111111111111111111 +11ff1111111441111111111111111111 +11ff1111114411111111111111111111 +11ff1111144111111111111111111111 +11ff1111441111111111111111111111 +11ff1114411111111111111111111111 +11ff1144111111111111111111111111 +11ff1441111111111111111111111111 +11ff4411111111111111111111111111 +11ff4111111111111111111111111111 +11ffffffffffffffffffffffffffff11 +11ffffffffffffffffffffffffffff11 +1111111111111111111111111111111b +.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. +` + export const sampleFirefly = img` .ffffffffffffffffffffffffffffff. ffffffffffffffffffffffffffffffff diff --git a/tooltips.ts b/tooltips.ts index e6848ca..8e32143 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -147,7 +147,16 @@ namespace microcode { else if (id === "F23B") res = "both"; else if (id === "F23N") res = "none"; else if (id === "F23NL") res = "lost left"; - else if (id === "F23NR") res = "lost right"; + else if (id === "F23NR") res = "lost right"; + + else if (id === "linear_graph") res = "Live" + else if (id == "led_light_sensor") res = "Light Sensor" + else if (id == "thermometer") res = "Thermometer" + else if (id == "accelerometer") res = "Accelerometer" + + // icons do not yet exist: + else if (id == "Record") res = "Record" + else if (id == "View") res = "View" return res } } \ No newline at end of file From abfb356faaa3501eaea04ab7804ec4d1b8b8a259 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 10 Feb 2024 20:55:54 +0000 Subject: [PATCH 002/109] Operational ArcadeShield: resolved building & dependencies, does not run as full prototype 1 version though - as all Home screen options direct towards the 'Live' Graph view. --- dataRecorder.ts | 59 +++++++++++++++++ fieldeditors.ts | 20 +++++- home.ts | 66 +++++++------------ liveDataViewer.ts | 71 +++++++++++++++++++++ measurementFrequencySelect.ts | 91 +++++++++++++++++++++++++++ pxt.json | 10 ++- recordedDataViewer.ts | 40 ++++++++++++ sensorSelect.ts | 115 ++++++++++++++++++++++++++++++++++ 8 files changed, 424 insertions(+), 48 deletions(-) create mode 100644 dataRecorder.ts create mode 100644 liveDataViewer.ts create mode 100644 measurementFrequencySelect.ts create mode 100644 recordedDataViewer.ts create mode 100644 sensorSelect.ts diff --git a/dataRecorder.ts b/dataRecorder.ts new file mode 100644 index 0000000..34c9020 --- /dev/null +++ b/dataRecorder.ts @@ -0,0 +1,59 @@ +namespace microcode { + const TOOLBAR_HEIGHT = 17 + const TOOLBAR_MARGIN = 2 + + export class DataRecorder extends Scene { + private selectedSensor: () => number + private sensorName: string + private numberOfMeasurements: number + private measurementFrequencyMs: number + + constructor(app: App, selectedSensor: () => number, sensorName: string, noOfMeasurements: number, frequencyMs: number) { + super(app, "dataRecorder") + + this.selectedSensor = selectedSensor + this.sensorName = sensorName + this.numberOfMeasurements = noOfMeasurements + this.measurementFrequencyMs = frequencyMs + + datalogger.deleteLog() + + // Go Back: + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => { + this.app.popScene() + this.app.pushScene(new Home(this.app)) + } + ) + } + + update() { + Screen.fillRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE, + Screen.WIDTH, + Screen.HEIGHT, + 0xc + ) + + if (this.numberOfMeasurements === 0) { + screen.printCenter("Data Logging Complete.", screen.height / 2); + screen.printCenter("Press B to back out.", (screen.height / 2) + 10); + return; + } + + else { + const secondsLeft: number = (this.measurementFrequencyMs * this.numberOfMeasurements) / 1000 + screen.printCenter("Recording data...", 10); + screen.printCenter(secondsLeft.toString() + " seconds left", screen.height / 2); + + datalogger.log(datalogger.createCV(this.sensorName, this.selectedSensor())) + + this.numberOfMeasurements -= 1 + basic.pause(this.measurementFrequencyMs) + } + } + } +} \ No newline at end of file diff --git a/fieldeditors.ts b/fieldeditors.ts index 0cdf301..95c077c 100644 --- a/fieldeditors.ts +++ b/fieldeditors.ts @@ -181,7 +181,25 @@ namespace microcode { melodyEditor(field, picker, onHide, onDelete) } toImage(field: any) { - return icondb.melodyToImage(field) + // Original code: + // return icondb.melodyToImage(field) + + const note4x3 = img` + . f f . + f c c . + f c c . + ` + const ret = simage.create(16, 16) + ret.fill(1) + for (let col = 0; col < microcode.MELODY_LENGTH; col++) { + if (field.notes[col] === ".") continue + const row = microcode.NUM_NOTES - 1 - parseInt(field.notes[col]) + const color = 15 + const ncol = col << 2, + nrow = row * 3 + 1 + ret.drawTransparentImage(note4x3, ncol, nrow) + } + return ret } toBuffer(melody: Melody) { const buf = Buffer.create(3) diff --git a/home.ts b/home.ts index d577e5b..4ec057b 100644 --- a/home.ts +++ b/home.ts @@ -1,8 +1,8 @@ namespace microcode { export class Home extends CursorScene { - samplesBtn: Button - editBtn: Button - diskBtn: Button + recordDataBtn: Button + liveDataBtn: Button + viewBtn: Button constructor(app: App) { super(app) @@ -11,72 +11,48 @@ namespace microcode { /* override */ startup() { super.startup() - this.editBtn = new Button({ + this.liveDataBtn = new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "edit_program", - ariaId: "C0", + icon: "linear_graph", + ariaId: "linear_graph", x: -50, y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new Editor(this.app)) + this.app.pushScene(new LiveDataViewer(this.app)) }, }) - this.samplesBtn = new Button({ + this.recordDataBtn = new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "smiley_buttons", - ariaId: "C1", + icon: "edit_program", + ariaId: "Record", x: 0, y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new SamplesGallery(this.app)) + this.app.pushScene(new LiveDataViewer(this.app)) }, }) - this.diskBtn = new Button({ + this.viewBtn = new Button({ parent: null, style: ButtonStyles.Transparent, icon: "largeDisk", - ariaId: "load", + ariaId: "View", x: 50, y: 30, onClick: () => { - this.pickDiskSLot() + this.app.popScene() + this.app.pushScene(new LiveDataViewer(this.app)) }, }) - const btns: Button[] = [this.editBtn, this.samplesBtn, this.diskBtn] + const btns: Button[] = [this.liveDataBtn, this.recordDataBtn, this.viewBtn] this.navigator.addButtons(btns) - // handle menu? - } - - private pickDiskSLot() { - const btns: PickerButtonDef[] = diskSlots().map(slot => { - return { - icon: slot, - } - }) - this.picker.setGroup(btns) - this.picker.show({ - title: accessibility.ariaToTooltip("load"), - onClick: index => { - let buf = settings.readBuffer(btns[index].icon) - if (!buf) { - // handles case where nothing is in slot - buf = Buffer.create(6) - for (let i = 0; i < 5; ++i) buf[i] = Tid.END_OF_PAGE - buf[5] = Tid.END_OF_PROG - } - settings.writeBuffer(SAVESLOT_AUTO, buf) - this.app.popScene() - this.app.pushScene(new Editor(this.app)) - }, - }) } /* override */ activate() { @@ -87,8 +63,8 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - microcode.VERSION, - Screen.RIGHT_EDGE - font.charWidth * microcode.VERSION.length, + "Prototype 2", + Screen.RIGHT_EDGE - font.charWidth * "Prototype 2".length, Screen.BOTTOM_EDGE - font.charHeight - 1, 0xb, font @@ -141,9 +117,9 @@ namespace microcode { ) } - this.samplesBtn.draw() - this.editBtn.draw() - this.diskBtn.draw() + this.recordDataBtn.draw() + this.liveDataBtn.draw() + this.viewBtn.draw() this.drawVersion() super.draw() } diff --git a/liveDataViewer.ts b/liveDataViewer.ts new file mode 100644 index 0000000..b3260af --- /dev/null +++ b/liveDataViewer.ts @@ -0,0 +1,71 @@ +namespace microcode { + const WIDTH_BUFFER = 16; + const HEIGHT_BUFFER = 12; + + //% shim=TD_NOOP + function connectJacdac() { + const buf = Buffer.fromUTF8(JSON.stringify({ type: "connect" })) + control.simmessages.send("usb", buf) + } + + export class LiveDataViewer extends Scene { + public rendering = false + private dataBuffer: number[] = []; + private bufferLimit = screen.width - (2 * WIDTH_BUFFER); + + constructor(app: App) { + super(app, "liveDataViewer") + this.color = 0 + + const goBack = function() { + app.popScene() + app.pushScene(new Home(app)) + }; + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => goBack() + ) + } + + update() { + // Pre-process and convet lightlevel into a y value; relative to screen-height + let light_level = input.lightLevel() / 255; + let y = Math.round(screen.height - (light_level * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER + + // Buffer management: + if (this.dataBuffer.length >= this.bufferLimit) { + this.dataBuffer.shift(); + } + this.dataBuffer.push(y); + + // Draw: + screen.fill(this.color); + this.plot() + + basic.pause(100); + } + + /** + * Display mode for plotting all incoming data on y axis + * Presumes pre-processed this.dataBuffer; y values relative to screen.height + * Bound to Microbit button A + */ + private plot() { + screen.printCenter("Light Level", 10) + this.draw_axes(); + + const start = WIDTH_BUFFER; + for (let i = 0; i < this.dataBuffer.length - 1; i++) { + screen.drawLine(start + i, this.dataBuffer[i], start + i - 1, this.dataBuffer[i + 1], 9); + } + } + + // Display helper: + draw_axes() { + screen.drawLine(WIDTH_BUFFER, screen.height - HEIGHT_BUFFER, screen.width - WIDTH_BUFFER, screen.height - HEIGHT_BUFFER, 5); + screen.drawLine(WIDTH_BUFFER, HEIGHT_BUFFER, WIDTH_BUFFER, screen.height - HEIGHT_BUFFER, 5); + } + } +} \ No newline at end of file diff --git a/measurementFrequencySelect.ts b/measurementFrequencySelect.ts new file mode 100644 index 0000000..9102329 --- /dev/null +++ b/measurementFrequencySelect.ts @@ -0,0 +1,91 @@ +namespace microcode { + const TOOLBAR_HEIGHT = 17 + const TOOLBAR_MARGIN = 2 + + const WIDTH_BUFFER = 16; + const HEIGHT_BUFFER = 12; + + export class FrequencySelect extends CursorScene { + private selectedSensor: () => number + private sensorName: string + private numberOfMeasurements: number = 5 + private measurementFrequencyMs: number = 1000 + + + /** temps */ + private selectLightSensorBtn: Button + private selectTemperatureBtn: Button + private selectAccelerometerBtn: Button + + constructor(app: App, selectedSensor: () => number, sensorName: string) { + super(app) + + this.selectedSensor = selectedSensor + this.sensorName = sensorName + + // Go Back: + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => { + this.app.popScene() + this.app.pushScene(new SensorSelect(this.app)) + } + ) + } + + /* override */ startup() { + super.startup() + + this.selectLightSensorBtn = new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "led_light_sensor", + ariaId: "Light Sensor", + x: -50, + y: 30, + onClick: () => { + this.app.popScene() + this.app.pushScene(new DataRecorder(this.app, this.selectedSensor, this.sensorName, this.numberOfMeasurements, this.measurementFrequencyMs)) + }, + }) + + const btns: Button[] = [this.selectLightSensorBtn] + this.navigator.addButtons(btns) + } + + /* override */ activate() { + super.activate() + this.color = 15 + } + + draw() { + Screen.fillRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE, + Screen.WIDTH, + Screen.HEIGHT, + 0xc + ) + + screen.printCenter("Select a sensor to log", 10) + + // const text = "Select a sensor to log" + // Screen.print( + // text, + // Screen.LEFT_EDGE + + // (Screen.WIDTH >> 1) + + // microcode.font.charWidth * text.length, + // Screen.TOP_EDGE + + // 1, + // 0xb, + // microcode.font + // ) + + this.selectLightSensorBtn.draw() + this.selectTemperatureBtn.draw() + this.selectAccelerometerBtn.draw() + super.draw() + } + } +} \ No newline at end of file diff --git a/pxt.json b/pxt.json index 4c96238..8f93556 100644 --- a/pxt.json +++ b/pxt.json @@ -6,7 +6,8 @@ "core": "*", "radio": "*", "microphone": "*", - "arcadeshield": "github:microsoft/pxt-arcadeshield#v0.0.1" + "arcadeshield": "github:microsoft/pxt-arcadeshield#v0.0.1", + "datalogger": "*" }, "files": [ "protocol.ts", @@ -42,7 +43,12 @@ "pointerevents.ts", "tooltips.ts", "utils.ts", - "jacs.ts" + "jacs.ts", + "liveDataViewer.ts", + "dataRecorder.ts", + "recordedDataViewer.ts", + "sensorSelect.ts", + "measurementFrequencySelect.ts" ], "testFiles": [], "targetVersions": { diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts new file mode 100644 index 0000000..487e543 --- /dev/null +++ b/recordedDataViewer.ts @@ -0,0 +1,40 @@ +// import * as fs from 'fs'; +// import { readFileSync } from 'fs'; + + +namespace microcode { + const TOOLBAR_HEIGHT = 17 + const TOOLBAR_MARGIN = 2 + + //% shim=TD_NOOP + function connectJacdac() { + const buf = Buffer.fromUTF8(JSON.stringify({ type: "connect" })) + control.simmessages.send("usb", buf) + } + + export class RecordedDataViewer extends Scene { + private backgroundColor = 4; + + constructor(app: App) { + super(app, "dataViewer") + + const goBack = function() { + app.popScene() + app.pushScene(new Home(app)) + }; + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => goBack() + ) + } + + update() { + screen.fill(this.backgroundColor); + + // const words = readFileSync('./MY_DATA.HTM'); + screen.printCenter("RecordedDataViewer", screen.height / 2); + } + } +} \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts new file mode 100644 index 0000000..fc6c0c4 --- /dev/null +++ b/sensorSelect.ts @@ -0,0 +1,115 @@ +namespace microcode { + const TOOLBAR_HEIGHT = 17 + const TOOLBAR_MARGIN = 2 + + const WIDTH_BUFFER = 16; + const HEIGHT_BUFFER = 12; + + //% shim=TD_NOOP + function connectJacdac() { + const buf = Buffer.fromUTF8(JSON.stringify({ type: "connect" })) + control.simmessages.send("usb", buf) + } + + export class SensorSelect extends CursorScene { + private selectedSensor: () => number + + private selectLightSensorBtn: Button + private selectTemperatureBtn: Button + private selectAccelerometerBtn: Button + + constructor(app: App) { + super(app) + + // Go Back: + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => { + this.app.popScene() + this.app.pushScene(new Home(this.app)) + } + ) + } + + /* override */ startup() { + super.startup() + + this.selectLightSensorBtn = new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "led_light_sensor", + ariaId: "Light Sensor", + x: -50, + y: 30, + onClick: () => { + this.app.popScene() + this.app.pushScene(new FrequencySelect(this.app, function () {return input.lightLevel() / 255}, "Light Level")) // Normalised function + }, + }) + + this.selectTemperatureBtn = new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "thermometer", + ariaId: "Thermometer", + x: 0, + y: 30, + onClick: () => { + this.app.popScene() + this.app.pushScene(new FrequencySelect(this.app, function () {return input.temperature()}, "Temperature C")) // Function is Not Normalised + }, + }) + + this.selectAccelerometerBtn = new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "accelerometer", + ariaId: "Accelerometer", + x: 50, + y: 30, + onClick: () => { + this.app.popScene() + this.app.pushScene(new FrequencySelect(this.app, function () {return input.acceleration(Dimension.X)}, "Accelerometer")) // Function is Not Normalised + }, + }) + + const btns: Button[] = [this.selectLightSensorBtn, this.selectTemperatureBtn, this.selectAccelerometerBtn] + this.navigator.addButtons(btns) + } + + /* override */ activate() { + super.activate() + this.color = 15 + } + + draw() { + Screen.fillRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE, + Screen.WIDTH, + Screen.HEIGHT, + 0xc + ) + + screen.printCenter("Select a sensor to log", 10) + + // const text = "Select a sensor to log" + // Screen.print( + // text, + // Screen.LEFT_EDGE + + // (Screen.WIDTH >> 1) + + // microcode.font.charWidth * text.length, + // Screen.TOP_EDGE + + // 1, + // 0xb, + // microcode.font + // ) + + this.selectLightSensorBtn.draw() + this.selectTemperatureBtn.draw() + this.selectAccelerometerBtn.draw() + super.draw() + } + } +} \ No newline at end of file From f44f4a30eab56c8bd0ca501d84f824858228bf52 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 10 Feb 2024 21:31:17 +0000 Subject: [PATCH 003/109] pxtarget.json: Updated compileService to use https://github.com/KierPalin/codal-microbit-v2 This is in preparation for future modifications to the flashlog used by codal - neccessary for reading flash memory. --- node_modules/pxt-microbit/pxtarget.json | 626 ++++++++++++++++++++++++ 1 file changed, 626 insertions(+) create mode 100644 node_modules/pxt-microbit/pxtarget.json diff --git a/node_modules/pxt-microbit/pxtarget.json b/node_modules/pxt-microbit/pxtarget.json new file mode 100644 index 0000000..7f7a43a --- /dev/null +++ b/node_modules/pxt-microbit/pxtarget.json @@ -0,0 +1,626 @@ +{ + "id": "microbit", + "nickname": "microbit", + "name": "makecode.microbit.org", + "title": "Microsoft MakeCode for micro:bit", + "description": "A Blocks / JavaScript code editor for the micro:bit powered by Microsoft MakeCode.", + "corepkg": "core", + "bundleddirs": [ + "libs/core", + "libs/radio", + "libs/devices", + "libs/bluetooth", + "libs/servo", + "libs/radio-broadcast", + "libs/microphone", + "libs/settings", + "libs/flashlog", + "libs/datalogger", + "libs/color", + "libs/audio-recording" + ], + "cloud": { + "workspace": false, + "packages": true, + "sharing": true, + "thumbnails": true, + "publishing": true, + "importing": true, + "showBadges": false, + "preferredPackages": [ + "Microsoft/pxt-neopixel" + ], + "githubPackages": true, + "cloudProviders": { + "github": { + "id": "github", + "name": "GitHub", + "icon": "/static/providers/github-mark.png", + "identity": false, + "order": 3 + }, + "microsoft": { + "id": "microsoft", + "name": "Microsoft", + "icon": "/static/providers/microsoft-logo.svg", + "identity": true, + "redirect": true, + "order": 1 + }, + "google": { + "id": "google", + "name": "Google", + "icon": "/static/providers/google-logo.svg", + "identity": true, + "redirect": true, + "order": 2 + }, + "clever": { + "id": "clever", + "name": "Clever", + "icon": "/static/providers/clever-logo.png", + "identity": true, + "redirect": true, + "order": 3 + } + } + }, + "compile": { + "isNative": false, + "hasHex": true, + "deployDrives": "(MICROBIT|MBED)", + "driveName": "MICROBIT", + "hexMimeType": "application/x-microbit-hex", + "openocdScript": "source [find interface/cmsis-dap.cfg]; source [find target/nrf51.cfg]", + "flashUsableEnd": 242688, + "flashEnd": 242688, + "flashCodeAlign": 1024, + "floatingPoint": true, + "taggedInts": true, + "utf8": false, + "gc": true, + "imageRefTag": 9, + "shimRenames": { + "sendBufferAsm": "light::sendWS2812Buffer" + }, + "patches": { + "0.0.0 - 1.0.0": [ + { + "type": "package", + "map": { + "microbit": "core", + "microbit-bluetooth": "bluetooth", + "microbit-radio": "radio", + "microbit-devices": "devices", + "microbit-led": "", + "microbit-music": "", + "microbit-game": "", + "microbit-pins": "", + "microbit-serial": "" + } + }, + { + "type": "missingPackage", + "map": { + "radio\\s*\\.": "radio", + "bluetooth\\s*\\.": "bluetooth", + "devices\\s*\\.": "devices" + } + }, + { + "type": "api", + "map": { + "bluetooth\\s*\\.\\s*uartRead\\s*\\((.*?)\\)": "bluetooth.uartReadUntil($1)", + "bluetooth\\s*\\.\\s*uartWrite\\s*\\((.*?)\\)": "bluetooth.uartWriteUntil($1)", + "input\\s*\\.\\s*calibrate\\s*\\(": "input.calibrateCompass(", + "radio\\s*\\.\\s*onDataPacketReceived\\(\\s*\\(\\{\\s*receivedNumber\\s*\\}\\)\\s*=>\\s*\\{": "radio.onReceivedNumber(function (receivedNumber) {", + "radio\\s*\\.\\s*onDataPacketReceived\\(\\s*\\(\\{\\s*receivedString: name, receivedNumber: value\\s*\\}\\)\\s*=>\\s*\\{": "radio.onReceivedValue(function (name, value) {", + "radio\\s*\\.\\s*onDataPacketReceived\\(\\s*\\(\\{\\s*receivedString\\s*\\}\\)\\s*=>\\s*\\{": "radio.onReceivedString(function (receivedString) {", + "Math\\s*\\.\\s*random\\s*\\(": "Math.randomRange(0, " + } + }, + { + "type": "blockId", + "map": { + "device_get_acceleration": "device_acceleration" + } + }, + { + "type": "blockValue", + "map": { + "device_print_message.message": "text" + } + } + ], + "0.0.0 - 1.4.12": [ + { + "type": "api", + "map": { + "DisplayMode\\s*\\.\\s*BackAndWhite": "DisplayMode.BlackAndWhite" + } + } + ], + "0.0.0 - 3.1.10": [ + { + "type": "package", + "map": { + "pxt-microbit-v2-extension": "microphone" + } + } + ], + "0.0.0 - 3.0.18": [ + { + "type": "missingPackage", + "map": { + ".*": "microphone" + } + } + ] + }, + "hidSelectors": [ + { + "usagePage": "0xFF00", + "usageId": "0x0001", + "vid": "0x0d28", + "pid": "0x0204" + } + ], + "webUSB": true, + "useNewFunctions": true + }, + "compileService": { + "yottaTarget": "bbc-microbit-classic-gcc@https://github.com/lancaster-university/yotta-target-bbc-microbit-classic-gcc", + "yottaCorePackage": "microbit", + "githubCorePackage": "lancaster-university/microbit", + "gittag": "v2.2.0-rc6", + "serviceId": "microbit", + "dockerImage": "pext/yotta:gcc5" + }, + "multiVariants": [ + "mbdal", + "mbcodal" + ], + "alwaysMultiVariant" : true, + "variants": { + "mbdal": { + "compile": {}, + "compileService": {} + }, + "mbcodal": { + "compile": { + "flashCodeAlign": 4096, + "flashUsableEnd": 487424, + "flashEnd": 524288 + }, + "compileService": { + "buildEngine": "codal", + "codalTarget": { + "name": "codal-microbit-v2", + "url": "https://github.com/KierPalin/codal-microbit-v2", + "branch": "v0.2.63", + "type": "git" + }, + "codalBinary": "MICROBIT", + "githubCorePackage": "lancaster-university/microbit-v2-samples", + "gittag": "v0.2.13", + "serviceId": "mbcodal2", + "dockerImage": "pext/yotta:latest", + "yottaConfigCompatibility": true + } + } + }, + "runtime": { + "mathBlocks": true, + "loopsBlocks": true, + "logicBlocks": true, + "variablesBlocks": true, + "textBlocks": true, + "listsBlocks": true, + "functionBlocks": true, + "breakBlock": true, + "continueBlock": true, + "functionsOptions": { + "useNewFunctions": true, + "extraFunctionEditorTypes": [ + { + "typeName": "game.LedSprite", + "label": "LedSprite", + "icon": "send", + "defaultName": "sprite" + }, + { + "typeName": "Image", + "label": "Image", + "icon": "image outline", + "defaultName": "image" + } + ] + }, + "onStartColor": "#1E90FF", + "onStartNamespace": "basic", + "onStartWeight": 54 + }, + "simulator": { + "autoRun": true, + "streams": false, + "aspectRatio": 1.22, + "parts": true, + "partsAspectRatio": 0.69, + "messageSimulators": { + "jacdac": { + "url": "https://microsoft.github.io/jacdac-docs/tools/makecode-sim?webusb=0&parentOrigin=$PARENT_ORIGIN$", + "localHostUrl": "http://localhost:8000/tools/makecode-sim?webusb=0&parentOrigin=$PARENT_ORIGIN$", + "aspectRatio": 1.22, + "permanent": true + }, + "robot": { + "url": "https://microsoft.github.io/microbit-robot/?parentOrigin=$PARENT_ORIGIN$", + "localHostUrl": "http://localhost:3000/microbit-robot/?parentOrigin=$PARENT_ORIGIN$", + "aspectRatio": 1.22, + "permanent": true + } + }, + "boardDefinition": { + "visual": "microbit", + "gpioPinBlocks": [ + [ + "P0" + ], + [ + "P1" + ], + [ + "P2" + ], + [ + "P3" + ], + [ + "P4", + "P5", + "P6", + "P7" + ], + [ + "P8", + "P9", + "P10", + "P11", + "P12" + ], + [ + "P16" + ] + ], + "gpioPinMap": { + "P0": "P0", + "P1": "P1", + "P2": "P2", + "P3": "P3", + "P4": "P4", + "P5": "P5", + "P6": "P6", + "P7": "P7", + "P8": "P8", + "P9": "P9", + "P10": "P10", + "P11": "P11", + "P12": "P12", + "P13": "P13", + "P14": "P14", + "P15": "P15", + "P16": "P16", + "P19": "P19", + "P20": "P20" + }, + "spiPins": { + "MOSI": "P15", + "MISO": "P14", + "SCK": "P13" + }, + "i2cPins": { + "SDA": "P20", + "SCL": "P19" + }, + "analogInPins": [ + "P0", + "P1", + "P2", + "P3", + "P10" + ], + "groundPins": [ + "GND" + ], + "threeVoltPins": [ + "+3v3" + ], + "attachPowerOnRight": true, + "onboardComponents": [ + "accelerometer", + "buttonpair", + "ledmatrix", + "speaker", + "bluetooth", + "thermometer", + "compass", + + "builtinspeaker", + "microphone", + "logotouch", + "flashlog", + + "v2" + ], + "pinStyles": { + "P0": "croc", + "P1": "croc", + "P2": "croc", + "GND": "croc", + "+3v3": "croc" + }, + "marginWhenBreadboarding": [ + 0, + 0, + 80, + 0 + ] + } + }, + "serial": { + "nameFilter": "^(mbed Serial Port|DAPLink CMSIS-DAP)", + "log": true, + "useEditor": true, + "editorTheme": { + "graphBackground": "#d9d9d9", + "lineColors": [ + "#6633cc", + "#3891A6", + "#3454D1", + "#EF767A", + "#F46197", + "#107C10" + ] + }, + "vendorId": "0x0d28", + "productId": "0x0204", + "rawHID": true + }, + "appTheme": { + "accentColor": "#5C005C", + "logoUrl": "https://microbit.org/", + "logo": "./static/logo.portrait.white.svg", + "docsLogo": "./static/logo.square.white.svg", + "portraitLogo": "./static/logo.square.white.svg", + "footerLogo": "./static/logo.portrait.black.svg", + "cardLogo": "./static/icons/apple-touch-icon.png", + "appLogo": "./static/icons/apple-touch-icon.png", + "organization": "Microsoft MakeCode", + "organizationUrl": "https://makecode.com/", + "organizationLogo": "./static/Microsoft_logo_rgb_W-white_D-square.png", + "organizationWideLogo": "./static/Microsoft_logo_rgb_W-white_D.png", + "homeScreenHero": { + "imageUrl": "/static/herogallery/hero-banner.png", + "name": "Flashing Heart", + "url": "/projects/flashing-heart", + "description": "New? Start here!", + "cardType": "tutorial" + }, + "homeScreenHeroGallery": "/hero-banner", + "homeUrl": "https://makecode.microbit.org/", + "embedUrl": "https://makecode.microbit.org/", + "shareUrl": "https://makecode.microbit.org/", + "privacyUrl": "https://makecode.com/privacy", + "termsOfUseUrl": "https://makecode.com/termsofuse", + "githubUrl": "https://github.com/Microsoft/pxt-microbit", + "boardName": "micro:bit", + "boardNickname": "micro:bit", + "driveDisplayName": "MICROBIT", + "appStoreID": "1092687276", + "mobileSafariDownloadProtocol": "microbithex://?data", + "crowdinProject": "makecode", + "extendEditor": true, + "extendFieldEditors": true, + "enableTrace": true, + "ignoreDocsErrors": false, + "errorList": true, + "workspaceSearch": true, + "allowPackageExtensions": true, + "addNewTypeScriptFile": true, + "experiments": [ + "accessibleBlocks", + "debugExtensionCode", + "bluetoothUartConsole", + "bluetoothPartialFlashing", + "identity", + "blocksErrorList" + ], + "bluetoothUartFilters": [ + { + "namePrefix": "BBC micro:bit" + } + ], + "docMenu": [ + { + "name": "Support", + "path": "https://support.microbit.org/" + }, + { + "name": "Reference", + "path": "/reference" + }, + { + "name": "Hardware", + "path": "/device" + }, + { + "name": "Buy", + "path": "https://microbit.org/resellers" + } + ], + "hasReferenceDocs": true, + "usbDocs": "/device/usb", + "hideHomeDetailsVideo": true, + "invertedMenu": true, + "coloredToolbox": true, + "monacoToolbox": true, + "hasAudio": true, + "socialOptions": { + "orgTwitterHandle": "MSMakeCode", + "hashtags": "MakeCode", + "discourse": "https://forum.makecode.com/", + "discourseCategory": "micro:bit" + }, + "blocklyOptions": { + "grid": { + "spacing": 45, + "length": 7, + "colour": "rgba(189, 195, 199, 0.30)", + "snap": false + } + }, + "blockColors": { + "logic": "#00A4A6", + "loops": "#00AA00", + "math": "#9400D3", + "variables": "#DC143C", + "text": "#B8860B", + "advanced": "#00272B", + "functions": "#3455DB", + "arrays": "#E65722" + }, + "blocksCollapsing": true, + "highContrast": true, + "greenScreen": true, + "print": true, + "selectLanguage": true, + "availableLocales": [ + "en", + "ar", + "bg", + "ca", + "cs", + "cy", + "da", + "de", + "el", + "es-ES", + "fi", + "fr", + "he", + "hu", + "is", + "it", + "ja", + "ko", + "nl", + "nb", + "nn-NO", + "pl", + "pt-BR", + "pt-PT", + "ru", + "si-LK", + "sk", + "sr", + "sv-SE", + "tr", + "uk", + "zh-CN", + "zh-TW" + ], + "monacoColors": { + "editor.background": "#ecf0f1" + }, + "monacoFieldEditors": [ + "soundeffect-editor" + ], + "browserDbPrefixes": { + "1": "v1", + "2": "v2", + "3": "v3", + "4": "v4", + "5": "v5", + "6": "v6" + }, + "editorVersionPaths": { + "0": "v0" + }, + "showProjectSettings": true, + "scriptManager": true, + "debugger": true, + "simGifTransparent": "rgba(0,0,0,0)", + "simGifMaxFrames": 44, + "simScreenshot": true, + "simScreenshotMaxUriLength": 300000, + "simGif": true, + "simGifWidth": 240, + "qrCode": true, + "importExtensionFiles": true, + "nameProjectFirst": true, + "githubEditor": true, + "chooseLanguageRestrictionOnNewProject": true, + "openProjectNewTab": true, + "python": true, + "appFlashingTroubleshoot": "/device/windows-app/troubleshoot", + "immersiveReader": true, + "tutorialCodeValidation": true, + "downloadDialogTheme": { + "webUSBDeviceNames": ["BBC micro:bit CMSIS-DAP", "DAPLink CMSIS-DAP"], + "minimumFirmwareVersion": "0249", + "deviceIcon": "xicon microbit", + "deviceSuccessIcon": "xicon microbit-check", + + "downloadMenuHelpURL" : "/device/usb", + "downloadHelpURL" : "/device/usb", + "troubleshootWebUSBHelpURL": "/device/usb/webusb/troubleshoot", + "incompatibleHardwareHelpURL": "/device/v2", + + "dragFileImage": "/static/download/transfer.png", + "connectDeviceImage": "/static/download/connect-microbit.gif", + "selectDeviceImage": "/static/download/selecting-microbit.gif", + "connectionSuccessImage": "/static/download/successfully-paired.png", + "incompatibleHardwareImage": "/static/download/incompatible.png", + "usbDeviceForgottenImage": "/static/download/device-forgotten.gif", + "browserUnpairImage": "/static/download/browser-unpair-image.gif" + }, + "winAppDeprImage": "/static/winapp.PNG", + "showWinAppDeprBanner": false, + "tours": { + "editor": "/tours/editor-tour" + }, + "tutorialSimSidebarLayout": true, + "preferWebUSBDownload": true, + "hideReplaceMyCode": true, + "matchWebUSBDeviceInSim": true, + "condenseProfile": true, + "cloudProfileIcon": "/static/profile/microbit-cloud.png" + }, + "queryVariants": { + "hidemenu": { + "appTheme": { + "hideMenuBar": true + } + }, + "androidapp": { + "compile": { + "webUSB": false + }, + "appTheme": { + "disableBlobObjectDownload": true + } + }, + "skillsMap=1": { + "appTheme": { + "hideReplaceMyCode": false + } + }, + "teachertool=1": { + "appTheme": { + "hideMenuBar": true, + "workspaceSearch": true + } + } + }, + "uploadDocs": true +} From 5b5db6f2d1f762f76fd508ac36e1671857a9fbbd Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 11 Feb 2024 15:58:09 +0000 Subject: [PATCH 004/109] assets.ts: Microdata -> MicroData --- assets.ts | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/assets.ts b/assets.ts index c9f8628..644f165 100644 --- a/assets.ts +++ b/assets.ts @@ -66,28 +66,28 @@ namespace microcode { } export const wordLogo = img` - .111111.......111111...1111..........................................................1111.......................1111...................................... - 11bbbbbb.....11bbbbbb.11bbbb........................................................11bbbb.....................11bbbb..................................... - 1bbbbbbbb...11bbbbbbbf1bbbbbf.......................................................1bbbbbf....................1bbbbbf.................................... - 1bbbbbbbbb.11bbbbbbbbf1bbbbbf.......................................................1bbbbbf....................1bbbbbf.................................... - 1bbbbbbbbbb1bbbbbbbbbf1bbbbbf.......................................................1bbbbbf....................1bbbbbf.................................... - 1bbbbbbbbbbbbbbbbbbbbf.bbbbff.......................................................1bbbbbf....................1bbbbbf.................................... - 1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111.........111111bbbbbf.....11111bb........1bbbbbb11111111111..11111bb................ - 1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1.....111bbbbbbbbbbf...11bbbbbbbbb......1bbbbbbbbbbbbbbbfff1bbbbbbbbb.............. - 1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb...11bbbbbbbbbbbbf..1bbbbbbbbbbbbf....11bbbbbbbbbbbbbbf.1bbbbbbbbbbbbf........... - 1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf..1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbf....1bbbbbff.........1bbbbbbbbbbbbbf........... - 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.11bbbbbbbbbbbbbf11bbbbbbbbbbbbbf....11bbbbbf.........11bbbbbbbbbbbbbf.......... - 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbbbbf....1bbbbbff.........1bbbbbfffbbbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbf1bbbbff..1bbbbbf1bbbbff..1bbbbbf....1bbbbfff.........1bbbbff..1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbf1bbbbf...1bbbbbf1bbbbf...1bbbbbf....1bbbbfff.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbf1bbbbf...1bbbbbf1bbbbf...1bbbbbf....1bbbbfff.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbf1bbbbb...1bbbbbf1bbbbb...1bbbbbf....1bbbbbff.........1bbbbb...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbf1bbbbbb111bbbbbf1bbbbbb111bbbbbf....1bbbbbbf.........1bbbbbb111bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbff.bbbbbbbbbbbbbbf.bbbbbbbbbbbbbb1111.bbbbbbbb111111111.bbbbbbbbbbbbbbb1111...... - 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf..1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf..... - 1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff...bbbbbbbbbbbbbf..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbf...... - .bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff.....fbbbbbbbbbbff...fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbf...... - ..fffff.........fffff...ffff......fffffff......ffff.............fffffff.........ffffffffff......ffffffffffffff....ffffffffffffff....fffffffffffffff....... + .111111.......111111...1111..................................................111111111........................1111...................................... + 11bbbbbb.....11bbbbbb.11bbbb................................................bbbbbbbbbbff.....................11bbbb..................................... + 1bbbbbbbb...11bbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbf....................1bbbbbf.................................... + 1bbbbbbbbb.11bbbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbbf...................1bbbbbf.................................... + 1bbbbbbbbbb1bbbbbbbbbf1bbbbbf..............................................1bbbbf..11bbbbf...................1bbbbbf.................................... + 1bbbbbbbbbbbbbbbbbbbbf.bbbbff..............................................1bbbb....1bbbbf...................1bbbbbf.................................... + 1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111.....1bbbb....1bbbbf....11111111.......1bbbbbb11111111111..11111111............... + 1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...1bbbb....1bbbbf...1bbbbbbbbbf.....1bbbbbbbbbbbbbbbfff1bbbbbbbbbf............. + 1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbb....1bbbbf..1bbbbbbbbbbbbf...11bbbbbbbbbbbbbbf.1bbbbbbbbbbbbf........... + 1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbb....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbff.........1bbbbbbbbbbbbbf........... + 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.11bbb....1bbbbf.1bbbbbbbbbbbbbf...11bbbbbf.........1bbbbbbbbbbbbbbf.......... + 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbf1bbbb....1bbbbf.1bbbbffffbbbbbf...1bbbbbbf.........1bbbbffffbbbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbf1bbbb....1bbbbf.1bbbff...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbf1bbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbf1bbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbf1bbbb....1bbbbf.1bbbbb...1bbbbf...1bbbbbbf.........1bbbbb...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbf1bbbb...111bbbf.1bbbbb111bbbbbf...1bbbbbbf.........1bbbbbb111bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbffbbbbbbbbbbbbbbf.bbbbbbbbbbbbbb1111.bbbbbbbb111111111bbbbbbbbbbbbbbbb1111...... + 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf..... + 1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff.bbbbbbbbbbbbbf...bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbff..... + .bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff..fbbbbbbbbbbff.....fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbff..... + ..fffff.........fffff...ffff......fffffff......ffff.............fffffff.....ffffffffff.........ffffffffffffff....ffffffffffffff....ffffffffffffffff...... ` export const microbitLogo = img` From 743def94224a3aba86a4b89b787eb2f79e995e5e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 12 Feb 2024 06:53:58 +0000 Subject: [PATCH 005/109] Preparation for DataLog reading: FrequencySelect stage skipped. --- app.ts | 2 + cursorscene.ts | 62 +++++++++++++++++++++++++++- dataRecorder.ts | 18 ++++---- home.ts | 2 +- liveDataViewer.ts | 8 +--- measurementFrequencySelect.ts | 77 +++++++++------------------------- sensorSelect.ts | 78 +++++++++++++++++------------------ 7 files changed, 131 insertions(+), 116 deletions(-) diff --git a/app.ts b/app.ts index e964f24..f87812f 100644 --- a/app.ts +++ b/app.ts @@ -15,7 +15,9 @@ namespace microcode { basic.pause(1) reportEvent("app.start") this.sceneManager = new SceneManager() + const home = new Home(this) + // const home = new SensorSelect(this) this.pushScene(home) } diff --git a/cursorscene.ts b/cursorscene.ts index e66b71b..cd6bff5 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -4,9 +4,10 @@ namespace microcode { public cursor: Cursor public picker: Picker - constructor(app: App) { + constructor(app: App, navigator?: INavigator) { super(app, "scene") this.color = 11 + this.navigator = navigator } protected moveCursor(dir: CursorDir) { @@ -132,4 +133,63 @@ namespace microcode { this.cursor.draw() } } + + + export class CursorSceneWithPriorPage extends CursorScene { + private goBack1PageFn: () => void; + + constructor(app: App, goBack1PageFn: () => void) { + super(app) + this.color = 11 + + this.goBack1PageFn = goBack1PageFn + } + + /* override */ startup() { + super.startup() + context.onEvent( + ControllerButtonEvent.Pressed, + controller.right.id, + () => this.moveCursor(CursorDir.Right) + ) + context.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => this.moveCursor(CursorDir.Up) + ) + context.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => this.moveCursor(CursorDir.Down) + ) + context.onEvent( + ControllerButtonEvent.Pressed, + controller.left.id, + () => this.moveCursor(CursorDir.Left) + ) + + // click + const click = () => this.cursor.click() + context.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + click + ) + context.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id + keymap.PLAYER_OFFSET, + click + ) + context.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => this.goBack1PageFn() + ) + + this.cursor = new Cursor() + this.picker = new Picker(this.cursor) + this.navigator = new RowNavigator() + this.cursor.navigator = this.navigator + } + } } diff --git a/dataRecorder.ts b/dataRecorder.ts index 34c9020..0a95a53 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,20 +1,22 @@ namespace microcode { - const TOOLBAR_HEIGHT = 17 - const TOOLBAR_MARGIN = 2 - export class DataRecorder extends Scene { private selectedSensor: () => number private sensorName: string private numberOfMeasurements: number private measurementFrequencyMs: number - constructor(app: App, selectedSensor: () => number, sensorName: string, noOfMeasurements: number, frequencyMs: number) { + constructor(app: App, opts: { + sensorFn: () => number, + sensorName: string, + noOfMeasurements: number, + frequencyMs: number + }) { super(app, "dataRecorder") - this.selectedSensor = selectedSensor - this.sensorName = sensorName - this.numberOfMeasurements = noOfMeasurements - this.measurementFrequencyMs = frequencyMs + this.selectedSensor = opts.sensorFn + this.sensorName = opts.sensorName + this.numberOfMeasurements = opts.noOfMeasurements + this.measurementFrequencyMs = opts.frequencyMs datalogger.deleteLog() diff --git a/home.ts b/home.ts index 4ec057b..79521c7 100644 --- a/home.ts +++ b/home.ts @@ -33,7 +33,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new LiveDataViewer(this.app)) + this.app.pushScene(new SensorSelect(this.app)) }, }) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index b3260af..d0e1a15 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -2,12 +2,6 @@ namespace microcode { const WIDTH_BUFFER = 16; const HEIGHT_BUFFER = 12; - //% shim=TD_NOOP - function connectJacdac() { - const buf = Buffer.fromUTF8(JSON.stringify({ type: "connect" })) - control.simmessages.send("usb", buf) - } - export class LiveDataViewer extends Scene { public rendering = false private dataBuffer: number[] = []; @@ -30,7 +24,7 @@ namespace microcode { } update() { - // Pre-process and convet lightlevel into a y value; relative to screen-height + // Pre-process and convert lightlevel into a y value; relative to screen-height let light_level = input.lightLevel() / 255; let y = Math.round(screen.height - (light_level * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER diff --git a/measurementFrequencySelect.ts b/measurementFrequencySelect.ts index 9102329..1bbf411 100644 --- a/measurementFrequencySelect.ts +++ b/measurementFrequencySelect.ts @@ -1,57 +1,34 @@ namespace microcode { - const TOOLBAR_HEIGHT = 17 - const TOOLBAR_MARGIN = 2 - - const WIDTH_BUFFER = 16; - const HEIGHT_BUFFER = 12; - - export class FrequencySelect extends CursorScene { + export class FrequencySelect extends Scene { private selectedSensor: () => number private sensorName: string private numberOfMeasurements: number = 5 private measurementFrequencyMs: number = 1000 + private minuteSprite: Sprite + + constructor(app: App, opts: {sensorFn: () => number, sensorName: string}) { + super(app, "frequencySelect") - /** temps */ - private selectLightSensorBtn: Button - private selectTemperatureBtn: Button - private selectAccelerometerBtn: Button + this.selectedSensor = opts.sensorFn + this.sensorName = opts.sensorName - constructor(app: App, selectedSensor: () => number, sensorName: string) { - super(app) - - this.selectedSensor = selectedSensor - this.sensorName = sensorName + const goBack = function() { + app.popScene() + app.pushScene(new Home(app)) + }; + + const img = microcode.icons.get("linear_graph") - // Go Back: - control.onEvent( - ControllerButtonEvent.Pressed, - controller.B.id, - () => { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app)) - } - ) + this.minuteSprite = new Sprite({ + parent: null, + img, + }) } /* override */ startup() { super.startup() - - this.selectLightSensorBtn = new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "led_light_sensor", - ariaId: "Light Sensor", - x: -50, - y: 30, - onClick: () => { - this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.selectedSensor, this.sensorName, this.numberOfMeasurements, this.measurementFrequencyMs)) - }, - }) - - const btns: Button[] = [this.selectLightSensorBtn] - this.navigator.addButtons(btns) + } /* override */ activate() { @@ -67,24 +44,8 @@ namespace microcode { Screen.HEIGHT, 0xc ) - - screen.printCenter("Select a sensor to log", 10) - // const text = "Select a sensor to log" - // Screen.print( - // text, - // Screen.LEFT_EDGE + - // (Screen.WIDTH >> 1) + - // microcode.font.charWidth * text.length, - // Screen.TOP_EDGE + - // 1, - // 0xb, - // microcode.font - // ) - - this.selectLightSensorBtn.draw() - this.selectTemperatureBtn.draw() - this.selectAccelerometerBtn.draw() + this.minuteSprite.draw() super.draw() } } diff --git a/sensorSelect.ts b/sensorSelect.ts index fc6c0c4..054ea73 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -1,17 +1,5 @@ namespace microcode { - const TOOLBAR_HEIGHT = 17 - const TOOLBAR_MARGIN = 2 - - const WIDTH_BUFFER = 16; - const HEIGHT_BUFFER = 12; - - //% shim=TD_NOOP - function connectJacdac() { - const buf = Buffer.fromUTF8(JSON.stringify({ type: "connect" })) - control.simmessages.send("usb", buf) - } - - export class SensorSelect extends CursorScene { + export class SensorSelect extends CursorSceneWithPriorPage { private selectedSensor: () => number private selectLightSensorBtn: Button @@ -19,17 +7,7 @@ namespace microcode { private selectAccelerometerBtn: Button constructor(app: App) { - super(app) - - // Go Back: - control.onEvent( - ControllerButtonEvent.Pressed, - controller.B.id, - () => { - this.app.popScene() - this.app.pushScene(new Home(this.app)) - } - ) + super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) } /* override */ startup() { @@ -39,12 +17,19 @@ namespace microcode { parent: null, style: ButtonStyles.FlatWhite, icon: "led_light_sensor", - ariaId: "Light Sensor", + ariaId: "Light Level", x: -50, y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new FrequencySelect(this.app, function () {return input.lightLevel() / 255}, "Light Level")) // Normalised function + + const opts = { + sensorFn: function () {return input.lightLevel() / 255}, + sensorName: "Light Level", + noOfMeasurements: 5, + frequencyMs: 1000 + } + this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -57,7 +42,14 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new FrequencySelect(this.app, function () {return input.temperature()}, "Temperature C")) // Function is Not Normalised + + const opts = { + sensorFn: function () {return input.temperature()}, + sensorName: "Temperature C", + noOfMeasurements: 5, + frequencyMs: 1000 + } + this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -70,7 +62,14 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new FrequencySelect(this.app, function () {return input.acceleration(Dimension.X)}, "Accelerometer")) // Function is Not Normalised + + const opts = { + sensorFn: function () {return input.acceleration(Dimension.X)}, + sensorName: "Accelerometer", + noOfMeasurements: 5, + frequencyMs: 1000 + } + this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -92,19 +91,16 @@ namespace microcode { 0xc ) - screen.printCenter("Select a sensor to log", 10) - - // const text = "Select a sensor to log" - // Screen.print( - // text, - // Screen.LEFT_EDGE + - // (Screen.WIDTH >> 1) + - // microcode.font.charWidth * text.length, - // Screen.TOP_EDGE + - // 1, - // 0xb, - // microcode.font - // ) + const text = "Select a\nsensor to log" + const half = screen.width - (font.charWidth * text.length) + + Screen.print( + text, + Screen.LEFT_EDGE + half, + Screen.TOP_EDGE + (screen.height / 3), + 0xb, + simage.font8 + ) this.selectLightSensorBtn.draw() this.selectTemperatureBtn.draw() From d70b63a087bf8c178fe98522efc2dce7344ca554 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 12 Feb 2024 18:42:25 +0000 Subject: [PATCH 006/109] Variable Measurement quantity and frequency, invocation to readRow() methods within the CODAL fork. --- dataRecorder.ts | 31 ++- home.ts | 2 +- measurementFrequencySelect.ts | 131 +++++++++-- recordedDataViewer.ts | 39 ++-- scrollable.ts | 403 ++++++++++++++++++++++++++++++++++ sensorSelect.ts | 21 +- 6 files changed, 554 insertions(+), 73 deletions(-) create mode 100644 scrollable.ts diff --git a/dataRecorder.ts b/dataRecorder.ts index 0a95a53..9c4918f 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,22 +1,21 @@ namespace microcode { export class DataRecorder extends Scene { - private selectedSensor: () => number - private sensorName: string - private numberOfMeasurements: number - private measurementFrequencyMs: number + private userOpts: { + sensorFn: () => number, + sensorName: string, + measurements: number, + frequency: number + } - constructor(app: App, opts: { + constructor(app: App, userOpts: { sensorFn: () => number, sensorName: string, - noOfMeasurements: number, - frequencyMs: number + measurements: number, + frequency: number }) { super(app, "dataRecorder") - this.selectedSensor = opts.sensorFn - this.sensorName = opts.sensorName - this.numberOfMeasurements = opts.noOfMeasurements - this.measurementFrequencyMs = opts.frequencyMs + this.userOpts = userOpts datalogger.deleteLog() @@ -40,21 +39,21 @@ namespace microcode { 0xc ) - if (this.numberOfMeasurements === 0) { + if (this.userOpts.measurements === 0) { screen.printCenter("Data Logging Complete.", screen.height / 2); screen.printCenter("Press B to back out.", (screen.height / 2) + 10); return; } else { - const secondsLeft: number = (this.measurementFrequencyMs * this.numberOfMeasurements) / 1000 + const secondsLeft: number = (this.userOpts.measurements * this.userOpts.frequency) / 1000 screen.printCenter("Recording data...", 10); screen.printCenter(secondsLeft.toString() + " seconds left", screen.height / 2); - datalogger.log(datalogger.createCV(this.sensorName, this.selectedSensor())) + datalogger.log(datalogger.createCV(this.userOpts.sensorName, this.userOpts.sensorFn())) - this.numberOfMeasurements -= 1 - basic.pause(this.measurementFrequencyMs) + this.userOpts.measurements -= 1 + basic.pause(this.userOpts.frequency) } } } diff --git a/home.ts b/home.ts index 79521c7..6d68562 100644 --- a/home.ts +++ b/home.ts @@ -46,7 +46,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new LiveDataViewer(this.app)) + this.app.pushScene(new RecordedDataViewer(this.app)) }, }) diff --git a/measurementFrequencySelect.ts b/measurementFrequencySelect.ts index 1bbf411..bb6d73f 100644 --- a/measurementFrequencySelect.ts +++ b/measurementFrequencySelect.ts @@ -1,34 +1,100 @@ namespace microcode { - export class FrequencySelect extends Scene { - private selectedSensor: () => number - private sensorName: string - private numberOfMeasurements: number = 5 - private measurementFrequencyMs: number = 1000 + interface IDictionary { + [index: string]: number; + } + const MAXIMUMS = {measurements: 1000, frequency: 10000} as IDictionary; - private minuteSprite: Sprite + export class FrequencySelect extends Scene { + // Passed to DataRecorder: + private userOpts: {sensorFn: () => number, sensorName: string} + private frequencySelectOptions: IDictionary + private mode: string = "measurements" - constructor(app: App, opts: {sensorFn: () => number, sensorName: string}) { + constructor(app: App, userOpts: {sensorFn: () => number, sensorName: string}) { super(app, "frequencySelect") - this.selectedSensor = opts.sensorFn - this.sensorName = opts.sensorName - - const goBack = function() { - app.popScene() - app.pushScene(new Home(app)) - }; - - const img = microcode.icons.get("linear_graph") + this.userOpts = userOpts; - this.minuteSprite = new Sprite({ - parent: null, - img, - }) + // Defaults: + this.frequencySelectOptions = { + measurements: 20, + frequency: 1000 + } } /* override */ startup() { super.startup() - + const mode: string = this.mode + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[mode] + 1) % MAXIMUMS[mode] + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + + () => { + if (this.frequencySelectOptions[mode] == 0) { + this.frequencySelectOptions[mode] = 1000 + } else { + this.frequencySelectOptions[mode] = (this.frequencySelectOptions[mode] - 1) % MAXIMUMS[mode] + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.right.id, + () => { + this.frequencySelectOptions[mode] = (this.frequencySelectOptions[mode] + 10) % MAXIMUMS[this.mode] + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.left.id, + () => { + if (this.frequencySelectOptions[mode] - 10 <= 0) { + this.frequencySelectOptions[mode] = 1000 + } else { + this.frequencySelectOptions[mode] = (this.frequencySelectOptions[mode] - 10) % MAXIMUMS[this.mode] + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => { + app.popScene() + app.pushScene(new Home(app)) + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + () => { + if (this.mode === "frequency") { + const userOpts = { + sensorFn: this.userOpts.sensorFn, + sensorName: this.userOpts.sensorName, + measurements: this.frequencySelectOptions.measurements, + frequency: this.frequencySelectOptions.frequency + } + this.app.pushScene(new DataRecorder(this.app, userOpts)) + } + + else { + this.mode = "frequency" + } + } + ) } /* override */ activate() { @@ -44,8 +110,29 @@ namespace microcode { Screen.HEIGHT, 0xc ) + + let valueAsString = ""; + + if (this.mode === "frequency") { + valueAsString = "" + this.frequencySelectOptions[this.mode] + screen.printCenter("Measurement frequency", 10) + } + + else if (this.mode === "measurements") { + valueAsString = "" + this.frequencySelectOptions[this.mode] + screen.printCenter("Number of measurements", 10) + } + + const textOffset = (screen.width - (font.charWidth * valueAsString.length)) / 2 + + Screen.print( + valueAsString, + Screen.LEFT_EDGE + textOffset, + Screen.TOP_EDGE + (screen.height / 2), + 0xb, + simage.font12 + ) - this.minuteSprite.draw() super.draw() } } diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 487e543..463ced6 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -1,40 +1,29 @@ -// import * as fs from 'fs'; -// import { readFileSync } from 'fs'; - - namespace microcode { - const TOOLBAR_HEIGHT = 17 - const TOOLBAR_MARGIN = 2 - - //% shim=TD_NOOP - function connectJacdac() { - const buf = Buffer.fromUTF8(JSON.stringify({ type: "connect" })) - control.simmessages.send("usb", buf) - } - export class RecordedDataViewer extends Scene { - private backgroundColor = 4; - constructor(app: App) { super(app, "dataViewer") - const goBack = function() { - app.popScene() - app.pushScene(new Home(app)) - }; - control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, - () => goBack() + () => { + app.popScene() + app.pushScene(new Home(app)) + } ) } update() { - screen.fill(this.backgroundColor); + Screen.fillRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE, + Screen.WIDTH, + Screen.HEIGHT, + 0xc + ) - // const words = readFileSync('./MY_DATA.HTM'); - screen.printCenter("RecordedDataViewer", screen.height / 2); + const text: string = datalogger.readRow(0) + screen.printCenter(text, 10) } } -} \ No newline at end of file +} diff --git a/scrollable.ts b/scrollable.ts new file mode 100644 index 0000000..55dda28 --- /dev/null +++ b/scrollable.ts @@ -0,0 +1,403 @@ +namespace microcode { + export interface IScrollable { + clear: () => void + addButtons: (btns: Button[]) => void + move: (dir: CursorDir) => Button + getCurrent: () => Button + screenToButton: (x: number, y: number) => Button + initialCursor: (row: number, col: number) => Button + updateAria: () => void + } + + export const BACK_BUTTON_ERROR_KIND = "back_button" + export const FORWARD_BUTTON_ERROR_KIND = "forward_button" + export class NavigationError { + kind: string + constructor(kind: string) { + this.kind = kind + } + } + + // ragged rows of buttons + export class RowNavigator implements INavigator { + protected buttonGroups: Button[][] + protected buttonCounters: number[][] + protected row: number + protected col: number + + constructor() { + this.buttonGroups = [] + this.buttonCounters = [] + } + + public clear() { + this.buttonGroups = [] + } + + public getRow() { + return this.row + } + + public addButtons(btns: Button[]) { + this.buttonGroups.push(btns) + } + + public screenToButton(x: number, y: number): Button { + const p = new Vec2(x, y) + for (let row = 0; row < this.buttonGroups.length; row++) { + const buttons = this.buttonGroups[row] + const target = buttons.find(btn => + Bounds.Translate(btn.bounds, btn.xfrm.worldPos).contains(p) + ) + if (target) { + this.row = row + this.col = buttons.indexOf(target) + return target + } + } + return undefined + } + + public move(dir: CursorDir) { + this.makeGood() + switch (dir) { + case CursorDir.Up: { + if (this.row == 0) + throw new NavigationError(BACK_BUTTON_ERROR_KIND) + this.row-- + // because the column in new row may be out of bounds + this.makeGood() + break + } + + case CursorDir.Down: { + if (this.row == this.buttonGroups.length - 1) + throw new NavigationError(FORWARD_BUTTON_ERROR_KIND) + this.row++ + // because the column in new row may be out of bounds + this.makeGood() + break + } + + case CursorDir.Left: { + if (this.col == 0) { + if (this.row > 0) { + this.row-- + } else { + this.row = this.buttonGroups.length - 1 + } + this.col = this.buttonGroups[this.row].length - 1 + } else this.col-- + break + } + + case CursorDir.Right: { + if (this.col == this.buttonGroups[this.row].length - 1) { + if (this.row < this.buttonGroups.length - 1) { + this.row++ + } else { + this.row = 0 + } + this.col = -1 + } + this.col++ + break + } + + case CursorDir.Back: { + if (this.col > 0) this.col = 0 + else if (this.row > 0) this.row-- + else return undefined + break + } + } + const btn = this.buttonGroups[this.row][this.col] + this.reportAria(btn) + return btn + } + + public updateAria() { + this.reportAria(this.getCurrent()) + } + + protected reportAria(btn: Button) { + if (btn) btn.reportAria(true) + } + + public getCurrent(): Button { + return this.buttonGroups[this.row][this.col] + } + + protected makeGood() { + if (this.row >= this.buttonGroups.length) + this.row = this.buttonGroups.length - 1 + if (this.col >= this.buttonGroups[this.row].length) + this.col = this.buttonGroups[this.row].length - 1 + } + + public initialCursor(row: number = 0, col: number = 0) { + const rows = this.buttonGroups.length + while (row < 0) row = (row + rows) % rows + const cols = this.buttonGroups[row].length + while (col < 0) col = (col + cols) % cols + this.row = row + this.col = col + return this.buttonGroups[row][col] + } + } + + // this adds accessibility for rule + export class RuleRowNavigator extends RowNavigator { + private rules: RuleDefn[] + + constructor() { + super() + this.rules = [] + } + + /* overrides */ + public clear() { + super.clear() + this.rules = [] + } + + public addRule(rule: RuleDefn) { + this.rules.push(rule) + } + + public atRuleStart() { + return this.row >= 1 && this.col == 0 + } + + protected reportAria(ret: Button) { + if (!ret) { + return + } + + let accessibilityMessage: accessibility.AccessibilityMessage + if (this.row > 0 && this.col == 0) { + const ruleDef = this.rules[this.row - 1] + + const whens = ruleDef.sensors + .concat(ruleDef.filters) + .map(s => tidToString(s)) + + const dos: string[] = ruleDef.actuators + .concat(ruleDef.modifiers.map(t => getTid(t))) + .map(s => tidToString(s)) + + accessibilityMessage = { + type: "rule", + whens, + dos, + } + } else { + accessibilityMessage = { + type: "tile", + value: (ret ? ret.ariaId : "") || "", + force: true, + } + } + accessibility.setLiveContent(accessibilityMessage) + } + } + + // mostly a matrix, except for last row, which may be ragged + // also supports delete button + // add support for aria + export class PickerNavigator implements INavigator { + protected deleteButton: Button + protected row: number + protected col: number + + constructor(private picker: Picker) {} + + private get width() { + return this.picker.width + } + private get length() { + return this.picker.group.defs.length + } + + get hasDelete() { + return !!this.deleteButton + } + + moveToIndex(index: number) { + assert(index < this.length, "index out of bounds") + this.row = Math.idiv(index, this.width) + this.col = index % this.width + this.reportAria() + return this.picker.group.getButtonAtIndex(index) + } + + private height() { + return Math.ceil(this.length / this.width) + } + + private currentRowWidth() { + assert(this.row >= 0, "row out of bounds") + return this.row < this.height() - 1 + ? this.width + : this.length - this.width * (this.height() - 1) + } + + public initialCursor(row: number = 0, col: number = 0): Button { + this.row = row + this.col = col + const btn = this.getCurrent() + if (btn) { + this.reportAria() + return undefined // TODO + } + return undefined + } + + clear() { + this.deleteButton = undefined + } + + addButtons(btns: ButtonBase[]) {} + + addDelete(btn: Button) { + this.deleteButton = btn + } + + getCurrent() { + // console.log(`row: ${this.row}, col: ${this.col}`) + if (this.row == -1) { + return this.deleteButton + } else { + const index = this.row * this.width + this.col + if (index < this.length) + return this.picker.group.getButtonAtIndex(index) + } + return undefined + } + + screenToButton(x: number, y: number): Button { + const p = new Vec2(x, y) + const btn = this.deleteButton + if ( + btn && + Bounds.Translate(btn.bounds, btn.xfrm.worldPos).contains(p) + ) + return btn + const np = this.picker.group.getButtonAtScreen(x, y) + if (np) { + this.row = np.y + this.col = np.x + if (this.col >= this.currentRowWidth()) + this.col = this.currentRowWidth() - 1 + return this.getCurrent() + } + return undefined + } + + move(dir: CursorDir) { + switch (dir) { + case CursorDir.Up: { + if (this.row == -1 || (!this.deleteButton && this.row == 0)) + throw new NavigationError(BACK_BUTTON_ERROR_KIND) + if (this.row > 0) this.row-- + else if (this.deleteButton) this.row = -1 + break + } + case CursorDir.Down: { + if (this.row < this.height() - 1) { + this.row++ + if (this.col >= this.currentRowWidth()) { + this.col = this.currentRowWidth() - 1 + } + } else throw new NavigationError(FORWARD_BUTTON_ERROR_KIND) + break + } + case CursorDir.Left: { + if (this.col > 0) this.col-- + else if (this.row > 0) { + this.row-- + this.col = this.width - 1 + } else if (this.deleteButton) { + this.row = -1 + } + break + } + case CursorDir.Right: { + if (this.row == -1) { + this.row = 0 + this.col = 0 + } else if (this.col < this.currentRowWidth() - 1) this.col++ + else if (this.row < this.height() - 1) { + this.row++ + this.col = 0 + } + break + } + } + this.reportAria() + return this.getCurrent() + } + + public updateAria() { + this.reportAria() + } + + protected reportAria() { + if (this.row == -1) { + accessibility.setLiveContent(< + accessibility.TextAccessibilityMessage + >{ + type: "text", + value: "delete_tile", + force: true, + }) + } + } + } + + // accessibility for LEDs + export class LEDNavigator extends PickerNavigator { + constructor(picker: Picker) { + super(picker) + this.row = 2 + this.col = 2 + } + protected reportAria() { + super.reportAria() + if (this.row == -1) return + const on = true // TODO: btn.getIcon() == "solid_red" + accessibility.setLiveContent(< + accessibility.LEDAccessibilityMessage + >{ + type: "led", + on, + x: this.col, + y: this.row, + force: true, + }) + } + } + + // accessibility for melody + export class MelodyNavigator extends PickerNavigator { + constructor(picker: Picker) { + super(picker) + this.row = 2 + this.col = 2 + } + protected reportAria() { + super.reportAria() + if (this.row == -1) return + const on = true // TODO btn.getIcon() === "note_on" + const index = this.hasDelete ? this.row - 1 : this.row + accessibility.setLiveContent(< + accessibility.NoteAccessibilityMessage + >{ + type: "note", + on, + index, + force: true, + }) + } + } +} diff --git a/sensorSelect.ts b/sensorSelect.ts index 054ea73..6121999 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -26,10 +26,11 @@ namespace microcode { const opts = { sensorFn: function () {return input.lightLevel() / 255}, sensorName: "Light Level", - noOfMeasurements: 5, - frequencyMs: 1000 + // noOfMeasurements: 5, + // frequencyMs: 1000 } - this.app.pushScene(new DataRecorder(this.app, opts)) + this.app.pushScene(new FrequencySelect(this.app, opts)) + // this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -46,10 +47,11 @@ namespace microcode { const opts = { sensorFn: function () {return input.temperature()}, sensorName: "Temperature C", - noOfMeasurements: 5, - frequencyMs: 1000 + // noOfMeasurements: 5, + // frequencyMs: 1000 } - this.app.pushScene(new DataRecorder(this.app, opts)) + this.app.pushScene(new FrequencySelect(this.app, opts)) + // this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -66,10 +68,11 @@ namespace microcode { const opts = { sensorFn: function () {return input.acceleration(Dimension.X)}, sensorName: "Accelerometer", - noOfMeasurements: 5, - frequencyMs: 1000 + // noOfMeasurements: 5, + // frequencyMs: 1000 } - this.app.pushScene(new DataRecorder(this.app, opts)) + this.app.pushScene(new FrequencySelect(this.app, opts)) + // this.app.pushScene(new DataRecorder(this.app, opts)) }, }) From db69efc271aee192a017c6b741cc5ba3213c9242 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 14:19:20 +0000 Subject: [PATCH 007/109] Completed data viewer. --- dataRecorder.ts | 16 ++++++-- fauxDatalogger.ts | 21 ++++++++++ measurementFrequencySelect.ts | 41 ++++++++++--------- pxt.json | 3 +- recordedDataViewer.ts | 75 +++++++++++++++++++++++++++++++++-- sensorSelect.ts | 13 +----- 6 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 fauxDatalogger.ts diff --git a/dataRecorder.ts b/dataRecorder.ts index 9c4918f..a49f5f4 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,5 +1,8 @@ namespace microcode { export class DataRecorder extends Scene { + private fauxDatalogger: FauxDataLogger + private loggingStartTime: number + private userOpts: { sensorFn: () => number, sensorName: string, @@ -10,14 +13,17 @@ namespace microcode { constructor(app: App, userOpts: { sensorFn: () => number, sensorName: string, - measurements: number, + measurements: number, frequency: number }) { super(app, "dataRecorder") this.userOpts = userOpts + this.fauxDatalogger = new FauxDataLogger(["Milli-\nseconds", userOpts.sensorName]) - datalogger.deleteLog() + this.loggingStartTime = input.runningTime() + + // datalogger.deleteLog() // Go Back: control.onEvent( @@ -42,7 +48,6 @@ namespace microcode { if (this.userOpts.measurements === 0) { screen.printCenter("Data Logging Complete.", screen.height / 2); screen.printCenter("Press B to back out.", (screen.height / 2) + 10); - return; } else { @@ -50,7 +55,10 @@ namespace microcode { screen.printCenter("Recording data...", 10); screen.printCenter(secondsLeft.toString() + " seconds left", screen.height / 2); - datalogger.log(datalogger.createCV(this.userOpts.sensorName, this.userOpts.sensorFn())) + // datalogger.log(datalogger.createCV(this.userOpts.sensorName, this.userOpts.sensorFn())) + // this.fauxDatalogger.log(input.runningTime().toString(), this.userOpts.sensorFn()) + + FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.userOpts.sensorFn()) this.userOpts.measurements -= 1 basic.pause(this.userOpts.frequency) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts new file mode 100644 index 0000000..8cf2d12 --- /dev/null +++ b/fauxDatalogger.ts @@ -0,0 +1,21 @@ +namespace microcode { + interface IDictionary { + [index: string]: number; + } + export class FauxDataLogger { + static headers: string[] = ["DEFAULT", "DEFAULT"] + static data: IDictionary + static numberOfRows: number + + constructor(headers: string[]) { + FauxDataLogger.headers = headers + FauxDataLogger.data = {} + FauxDataLogger.numberOfRows = 0 + } + + public static log(key: string, value: number) { + FauxDataLogger.data[key] = value + FauxDataLogger.numberOfRows += 1 + } + } +} diff --git a/measurementFrequencySelect.ts b/measurementFrequencySelect.ts index bb6d73f..685b212 100644 --- a/measurementFrequencySelect.ts +++ b/measurementFrequencySelect.ts @@ -1,8 +1,8 @@ namespace microcode { interface IDictionary { [index: string]: number; - } - const MAXIMUMS = {measurements: 1000, frequency: 10000} as IDictionary; + } + const MAXIMUMS = {measurements: 1000, frequency: 10000} as IDictionary; export class FrequencySelect extends Scene { // Passed to DataRecorder: @@ -24,13 +24,12 @@ namespace microcode { /* override */ startup() { super.startup() - const mode: string = this.mode control.onEvent( ControllerButtonEvent.Pressed, controller.up.id, () => { - this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[mode] + 1) % MAXIMUMS[mode] + this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] + 1) % MAXIMUMS[this.mode] } ) @@ -39,10 +38,10 @@ namespace microcode { controller.down.id, () => { - if (this.frequencySelectOptions[mode] == 0) { - this.frequencySelectOptions[mode] = 1000 + if (this.frequencySelectOptions[this.mode] == 0) { + this.frequencySelectOptions[this.mode] = 1000 } else { - this.frequencySelectOptions[mode] = (this.frequencySelectOptions[mode] - 1) % MAXIMUMS[mode] + this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] - 1) % MAXIMUMS[this.mode] } } ) @@ -51,7 +50,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - this.frequencySelectOptions[mode] = (this.frequencySelectOptions[mode] + 10) % MAXIMUMS[this.mode] + this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] + (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] } ) @@ -59,10 +58,10 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.left.id, () => { - if (this.frequencySelectOptions[mode] - 10 <= 0) { - this.frequencySelectOptions[mode] = 1000 + if (this.frequencySelectOptions[this.mode] - 10 <= 0) { + this.frequencySelectOptions[this.mode] = 1000 } else { - this.frequencySelectOptions[mode] = (this.frequencySelectOptions[mode] - 10) % MAXIMUMS[this.mode] + this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] - (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] } } ) @@ -87,7 +86,10 @@ namespace microcode { measurements: this.frequencySelectOptions.measurements, frequency: this.frequencySelectOptions.frequency } - this.app.pushScene(new DataRecorder(this.app, userOpts)) + + const dataRecorder = new DataRecorder(this.app, userOpts) + this.app.popScene() + this.app.pushScene(dataRecorder) } else { @@ -110,27 +112,24 @@ namespace microcode { Screen.HEIGHT, 0xc ) - - let valueAsString = ""; if (this.mode === "frequency") { - valueAsString = "" + this.frequencySelectOptions[this.mode] - screen.printCenter("Measurement frequency", 10) + screen.printCenter("Measurement frequency", 20) } else if (this.mode === "measurements") { - valueAsString = "" + this.frequencySelectOptions[this.mode] - screen.printCenter("Number of measurements", 10) + screen.printCenter("Number of measurements", 20) } - const textOffset = (screen.width - (font.charWidth * valueAsString.length)) / 2 + let value = "" + this.frequencySelectOptions[this.mode]; + const textOffset = (screen.width - (font.charWidth * value.length)) / 2 Screen.print( - valueAsString, + value, Screen.LEFT_EDGE + textOffset, Screen.TOP_EDGE + (screen.height / 2), 0xb, - simage.font12 + simage.font8 ) super.draw() diff --git a/pxt.json b/pxt.json index 8f93556..2fb47b7 100644 --- a/pxt.json +++ b/pxt.json @@ -48,7 +48,8 @@ "dataRecorder.ts", "recordedDataViewer.ts", "sensorSelect.ts", - "measurementFrequencySelect.ts" + "measurementFrequencySelect.ts", + "fauxDatalogger.ts" ], "testFiles": [], "targetVersions": { diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 463ced6..fa9089a 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -1,5 +1,9 @@ namespace microcode { + const HEADER_OFFSET = 25 + const MAX_ROWS = 10 + export class RecordedDataViewer extends Scene { + constructor(app: App) { super(app, "dataViewer") @@ -13,17 +17,82 @@ namespace microcode { ) } + draw_grid() { + const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length + const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + + for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { + Screen.drawLine( + Screen.LEFT_EDGE + colOffset, + Screen.TOP_EDGE + HEADER_OFFSET, + Screen.LEFT_EDGE + colOffset, + Screen.HEIGHT, + 0x0 + ) + } + + for (let rowOffset = HEADER_OFFSET; rowOffset <= Screen.HEIGHT; rowOffset+=rowBufferSize) { + Screen.drawLine( + Screen.LEFT_EDGE, + Screen.TOP_EDGE + rowOffset, + Screen.WIDTH, + Screen.TOP_EDGE + rowOffset, + 0x0 + ) + } + } + update() { Screen.fillRect( Screen.LEFT_EDGE, Screen.TOP_EDGE, Screen.WIDTH, Screen.HEIGHT, - 0xc + 0xC ) + + FauxDataLogger.numberOfRows = 5 + this.draw_grid() - const text: string = datalogger.readRow(0) - screen.printCenter(text, 10) + for (let i = 0; i < FauxDataLogger.headers.length; i++) { + const textOffset = (screen.width - (font.charWidth * FauxDataLogger.headers[i].length)) / 4 + Screen.print( + FauxDataLogger.headers[i], + Screen.LEFT_EDGE + textOffset + (i * 80) - 4, + Screen.TOP_EDGE + 4, + 0xb, + simage.font8 + ) + } + + interface IDictionary {[index: string]: number;} + const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5} + + const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length + const rowOffsetDelta = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + let rowOffset = 0 + + Object.keys(FauxDataLogger.data).forEach( + key => { + Screen.print( + key, + Screen.LEFT_EDGE + (colBufferSize / 2) - ((font.charWidth * key.length) / 2), + Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4, + 0xb, + simage.font8 + ) + + const sensorData = FauxDataLogger.data[key].toString().slice(0, 4) + Screen.print( + sensorData, + Screen.LEFT_EDGE + colBufferSize + (colBufferSize / 2) - ((font.charWidth *sensorData.length) / 2), + Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4, + 0xb, + simage.font8 + ) + rowOffset += rowOffsetDelta + } + ) } } } diff --git a/sensorSelect.ts b/sensorSelect.ts index 6121999..c2ccb62 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -25,12 +25,9 @@ namespace microcode { const opts = { sensorFn: function () {return input.lightLevel() / 255}, - sensorName: "Light Level", - // noOfMeasurements: 5, - // frequencyMs: 1000 + sensorName: "Light\nLevel", } this.app.pushScene(new FrequencySelect(this.app, opts)) - // this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -46,12 +43,9 @@ namespace microcode { const opts = { sensorFn: function () {return input.temperature()}, - sensorName: "Temperature C", - // noOfMeasurements: 5, - // frequencyMs: 1000 + sensorName: "Temperature", } this.app.pushScene(new FrequencySelect(this.app, opts)) - // this.app.pushScene(new DataRecorder(this.app, opts)) }, }) @@ -68,11 +62,8 @@ namespace microcode { const opts = { sensorFn: function () {return input.acceleration(Dimension.X)}, sensorName: "Accelerometer", - // noOfMeasurements: 5, - // frequencyMs: 1000 } this.app.pushScene(new FrequencySelect(this.app, opts)) - // this.app.pushScene(new DataRecorder(this.app, opts)) }, }) From 91e9a52b70fba982cc6b6d8527713b760d15e31e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 14:28:39 +0000 Subject: [PATCH 008/109] assets.ts: adjusted lighting on MicroData logo --- assets.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/assets.ts b/assets.ts index 644f165..c98aae1 100644 --- a/assets.ts +++ b/assets.ts @@ -76,15 +76,15 @@ namespace microcode { 1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...1bbbb....1bbbbf...1bbbbbbbbbf.....1bbbbbbbbbbbbbbbfff1bbbbbbbbbf............. 1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbb....1bbbbf..1bbbbbbbbbbbbf...11bbbbbbbbbbbbbbf.1bbbbbbbbbbbbf........... 1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbb....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbff.........1bbbbbbbbbbbbbf........... - 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.11bbb....1bbbbf.1bbbbbbbbbbbbbf...11bbbbbf.........1bbbbbbbbbbbbbbf.......... - 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbf1bbbb....1bbbbf.1bbbbffffbbbbbf...1bbbbbbf.........1bbbbffffbbbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbf1bbbb....1bbbbf.1bbbff...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbf1bbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbf1bbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbf1bbbb....1bbbbf.1bbbbb...1bbbbf...1bbbbbbf.........1bbbbb...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbf1bbbb...111bbbf.1bbbbb111bbbbbf...1bbbbbbf.........1bbbbbb111bbbbbf.......... + 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.1bbbb....1bbbbf.1bbbbbbbbbbbbbf...11bbbbbf.........1bbbbbbbbbbbbbbf.......... + 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbfbbbbb....1bbbbf.1bbbbffffbbbbbf...1bbbbbbf.........1bbbbffffbbbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbfbbbbb....1bbbbf.1bbbff...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbfbbbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbfbbbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbfbbbbb....1bbbbf.1bbbbb...1bbbbf...1bbbbbbf.........1bbbbb...1bbbbbf.......... + 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbfbbbbb...11bbbbf.1bbbbb111bbbbbf...1bbbbbbf.........1bbbbbb111bbbbbf.......... 1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbffbbbbbbbbbbbbbbf.bbbbbbbbbbbbbb1111.bbbbbbbb111111111bbbbbbbbbbbbbbbb1111...... - 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf..... + 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.bbbbbbbbbbbbbbf.1bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf..... 1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff.bbbbbbbbbbbbbf...bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbff..... .bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff..fbbbbbbbbbbff.....fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbff..... ..fffff.........fffff...ffff......fffffff......ffff.............fffffff.....ffffffffff.........ffffffffffffff....ffffffffffffff....ffffffffffffffff...... From dd184262cb459d03f463ed062ba9439f7183af99 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 15:18:19 +0000 Subject: [PATCH 009/109] recordedDataViewer.ts: added scrolling --- recordedDataViewer.ts | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index fa9089a..b9206c9 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -3,10 +3,13 @@ namespace microcode { const MAX_ROWS = 10 export class RecordedDataViewer extends Scene { + private scrollOffset: number; constructor(app: App) { super(app, "dataViewer") + this.scrollOffset = 0 + control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, @@ -15,6 +18,26 @@ namespace microcode { app.pushScene(new Home(app)) } ) + + const rowOffsetDelta = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + this.scrollOffset -= (Screen.HEIGHT / MAX_ROWS) * 2 + this.scrollOffset = Math.max(this.scrollOffset, 0) + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => { + this.scrollOffset += (Screen.HEIGHT / MAX_ROWS) * 2 + this.scrollOffset = Math.min(this.scrollOffset, Screen.HEIGHT - ((Screen.HEIGHT / MAX_ROWS) * 4)) + } + ) } draw_grid() { @@ -66,27 +89,27 @@ namespace microcode { } interface IDictionary {[index: string]: number;} - const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5} + const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7} const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length const rowOffsetDelta = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) let rowOffset = 0 - Object.keys(FauxDataLogger.data).forEach( + Object.keys(data).forEach( key => { Screen.print( key, Screen.LEFT_EDGE + (colBufferSize / 2) - ((font.charWidth * key.length) / 2), - Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4, + Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4 + this.scrollOffset, 0xb, simage.font8 ) - const sensorData = FauxDataLogger.data[key].toString().slice(0, 4) + const sensorData = data[key].toString().slice(0, 4) Screen.print( sensorData, Screen.LEFT_EDGE + colBufferSize + (colBufferSize / 2) - ((font.charWidth *sensorData.length) / 2), - Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4, + Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4 + this.scrollOffset, 0xb, simage.font8 ) @@ -95,4 +118,4 @@ namespace microcode { ) } } -} +} \ No newline at end of file From a68c3bfecc18a72c2312f3c4b7a2875920e875f9 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 15:35:01 +0000 Subject: [PATCH 010/109] Clean-up of codebase --- dataRecorder.ts | 2 -- recordedDataViewer.ts | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index a49f5f4..1472c9b 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -56,8 +56,6 @@ namespace microcode { screen.printCenter(secondsLeft.toString() + " seconds left", screen.height / 2); // datalogger.log(datalogger.createCV(this.userOpts.sensorName, this.userOpts.sensorFn())) - // this.fauxDatalogger.log(input.runningTime().toString(), this.userOpts.sensorFn()) - FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.userOpts.sensorFn()) this.userOpts.measurements -= 1 diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index b9206c9..a2351e6 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -18,24 +18,22 @@ namespace microcode { app.pushScene(new Home(app)) } ) - - const rowOffsetDelta = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) control.onEvent( ControllerButtonEvent.Pressed, - controller.up.id, + controller.down.id, () => { - this.scrollOffset -= (Screen.HEIGHT / MAX_ROWS) * 2 - this.scrollOffset = Math.max(this.scrollOffset, 0) + this.scrollOffset += (Screen.HEIGHT / MAX_ROWS) * 2 + this.scrollOffset = Math.min(this.scrollOffset, Screen.HEIGHT - ((Screen.HEIGHT / MAX_ROWS) * 4)) } ) control.onEvent( ControllerButtonEvent.Pressed, - controller.down.id, + controller.up.id, () => { - this.scrollOffset += (Screen.HEIGHT / MAX_ROWS) * 2 - this.scrollOffset = Math.min(this.scrollOffset, Screen.HEIGHT - ((Screen.HEIGHT / MAX_ROWS) * 4)) + this.scrollOffset -= (Screen.HEIGHT / MAX_ROWS) * 2 + this.scrollOffset = Math.max(this.scrollOffset, 0) } ) } @@ -88,14 +86,14 @@ namespace microcode { ) } - interface IDictionary {[index: string]: number;} - const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7} + // interface IDictionary {[index: string]: number;} + // const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7} const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length const rowOffsetDelta = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) let rowOffset = 0 - Object.keys(data).forEach( + Object.keys(FauxDataLogger.data).forEach( key => { Screen.print( key, @@ -105,7 +103,7 @@ namespace microcode { simage.font8 ) - const sensorData = data[key].toString().slice(0, 4) + const sensorData = FauxDataLogger.data[key].toString().slice(0, 4) Screen.print( sensorData, Screen.LEFT_EDGE + colBufferSize + (colBufferSize / 2) - ((font.charWidth *sensorData.length) / 2), From c9917d958229b3464b4ea74d49db62a08d247272 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 15:56:12 +0000 Subject: [PATCH 011/109] liveDataViewer.ts: Increased axes thickness, increased offset of line for clearer visibility. --- liveDataViewer.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index d0e1a15..b3d6563 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -50,7 +50,7 @@ namespace microcode { screen.printCenter("Light Level", 10) this.draw_axes(); - const start = WIDTH_BUFFER; + const start = WIDTH_BUFFER + 2; for (let i = 0; i < this.dataBuffer.length - 1; i++) { screen.drawLine(start + i, this.dataBuffer[i], start + i - 1, this.dataBuffer[i + 1], 9); } @@ -58,8 +58,10 @@ namespace microcode { // Display helper: draw_axes() { - screen.drawLine(WIDTH_BUFFER, screen.height - HEIGHT_BUFFER, screen.width - WIDTH_BUFFER, screen.height - HEIGHT_BUFFER, 5); - screen.drawLine(WIDTH_BUFFER, HEIGHT_BUFFER, WIDTH_BUFFER, screen.height - HEIGHT_BUFFER, 5); + for (let i = 0; i < 2; i++) { + screen.drawLine(WIDTH_BUFFER, screen.height - HEIGHT_BUFFER + i, screen.width - WIDTH_BUFFER, screen.height - HEIGHT_BUFFER + i, 5); + screen.drawLine(WIDTH_BUFFER + i, HEIGHT_BUFFER, WIDTH_BUFFER + i, screen.height - HEIGHT_BUFFER, 5); + } } } } \ No newline at end of file From 3b0a6d7f0d08e505228a8bb63fe7fe324c45bdb5 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 15:59:45 +0000 Subject: [PATCH 012/109] Incremented prototype count. Start of next prototype development begins --- home.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/home.ts b/home.ts index 6d68562..5264cf5 100644 --- a/home.ts +++ b/home.ts @@ -63,8 +63,8 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - "Prototype 2", - Screen.RIGHT_EDGE - font.charWidth * "Prototype 2".length, + "Prototype 3", + Screen.RIGHT_EDGE - font.charWidth * "Prototype 3".length, Screen.BOTTOM_EDGE - font.charHeight - 1, 0xb, font From f95d53da238c1cc8da5325425501f1620e50d75d Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 21:12:46 +0000 Subject: [PATCH 013/109] Removed scrollable.ts as it is unused, removed unused .ts files from pxt.json to reduce compile times. --- pxt.json | 5 - scrollable.ts | 403 -------------------------------------------------- 2 files changed, 408 deletions(-) delete mode 100644 scrollable.ts diff --git a/pxt.json b/pxt.json index 2fb47b7..38e42d7 100644 --- a/pxt.json +++ b/pxt.json @@ -24,8 +24,6 @@ "tiles.ts", "app.ts", "sprite.ts", - "editor.ts", - "ruleeditor.ts", "cursor.ts", "home.ts", "bounds.ts", @@ -38,9 +36,6 @@ "navigator.ts", "cursorscene.ts", "options.ts", - "samples.ts", - "gallery.ts", - "pointerevents.ts", "tooltips.ts", "utils.ts", "jacs.ts", diff --git a/scrollable.ts b/scrollable.ts deleted file mode 100644 index 55dda28..0000000 --- a/scrollable.ts +++ /dev/null @@ -1,403 +0,0 @@ -namespace microcode { - export interface IScrollable { - clear: () => void - addButtons: (btns: Button[]) => void - move: (dir: CursorDir) => Button - getCurrent: () => Button - screenToButton: (x: number, y: number) => Button - initialCursor: (row: number, col: number) => Button - updateAria: () => void - } - - export const BACK_BUTTON_ERROR_KIND = "back_button" - export const FORWARD_BUTTON_ERROR_KIND = "forward_button" - export class NavigationError { - kind: string - constructor(kind: string) { - this.kind = kind - } - } - - // ragged rows of buttons - export class RowNavigator implements INavigator { - protected buttonGroups: Button[][] - protected buttonCounters: number[][] - protected row: number - protected col: number - - constructor() { - this.buttonGroups = [] - this.buttonCounters = [] - } - - public clear() { - this.buttonGroups = [] - } - - public getRow() { - return this.row - } - - public addButtons(btns: Button[]) { - this.buttonGroups.push(btns) - } - - public screenToButton(x: number, y: number): Button { - const p = new Vec2(x, y) - for (let row = 0; row < this.buttonGroups.length; row++) { - const buttons = this.buttonGroups[row] - const target = buttons.find(btn => - Bounds.Translate(btn.bounds, btn.xfrm.worldPos).contains(p) - ) - if (target) { - this.row = row - this.col = buttons.indexOf(target) - return target - } - } - return undefined - } - - public move(dir: CursorDir) { - this.makeGood() - switch (dir) { - case CursorDir.Up: { - if (this.row == 0) - throw new NavigationError(BACK_BUTTON_ERROR_KIND) - this.row-- - // because the column in new row may be out of bounds - this.makeGood() - break - } - - case CursorDir.Down: { - if (this.row == this.buttonGroups.length - 1) - throw new NavigationError(FORWARD_BUTTON_ERROR_KIND) - this.row++ - // because the column in new row may be out of bounds - this.makeGood() - break - } - - case CursorDir.Left: { - if (this.col == 0) { - if (this.row > 0) { - this.row-- - } else { - this.row = this.buttonGroups.length - 1 - } - this.col = this.buttonGroups[this.row].length - 1 - } else this.col-- - break - } - - case CursorDir.Right: { - if (this.col == this.buttonGroups[this.row].length - 1) { - if (this.row < this.buttonGroups.length - 1) { - this.row++ - } else { - this.row = 0 - } - this.col = -1 - } - this.col++ - break - } - - case CursorDir.Back: { - if (this.col > 0) this.col = 0 - else if (this.row > 0) this.row-- - else return undefined - break - } - } - const btn = this.buttonGroups[this.row][this.col] - this.reportAria(btn) - return btn - } - - public updateAria() { - this.reportAria(this.getCurrent()) - } - - protected reportAria(btn: Button) { - if (btn) btn.reportAria(true) - } - - public getCurrent(): Button { - return this.buttonGroups[this.row][this.col] - } - - protected makeGood() { - if (this.row >= this.buttonGroups.length) - this.row = this.buttonGroups.length - 1 - if (this.col >= this.buttonGroups[this.row].length) - this.col = this.buttonGroups[this.row].length - 1 - } - - public initialCursor(row: number = 0, col: number = 0) { - const rows = this.buttonGroups.length - while (row < 0) row = (row + rows) % rows - const cols = this.buttonGroups[row].length - while (col < 0) col = (col + cols) % cols - this.row = row - this.col = col - return this.buttonGroups[row][col] - } - } - - // this adds accessibility for rule - export class RuleRowNavigator extends RowNavigator { - private rules: RuleDefn[] - - constructor() { - super() - this.rules = [] - } - - /* overrides */ - public clear() { - super.clear() - this.rules = [] - } - - public addRule(rule: RuleDefn) { - this.rules.push(rule) - } - - public atRuleStart() { - return this.row >= 1 && this.col == 0 - } - - protected reportAria(ret: Button) { - if (!ret) { - return - } - - let accessibilityMessage: accessibility.AccessibilityMessage - if (this.row > 0 && this.col == 0) { - const ruleDef = this.rules[this.row - 1] - - const whens = ruleDef.sensors - .concat(ruleDef.filters) - .map(s => tidToString(s)) - - const dos: string[] = ruleDef.actuators - .concat(ruleDef.modifiers.map(t => getTid(t))) - .map(s => tidToString(s)) - - accessibilityMessage = { - type: "rule", - whens, - dos, - } - } else { - accessibilityMessage = { - type: "tile", - value: (ret ? ret.ariaId : "") || "", - force: true, - } - } - accessibility.setLiveContent(accessibilityMessage) - } - } - - // mostly a matrix, except for last row, which may be ragged - // also supports delete button - // add support for aria - export class PickerNavigator implements INavigator { - protected deleteButton: Button - protected row: number - protected col: number - - constructor(private picker: Picker) {} - - private get width() { - return this.picker.width - } - private get length() { - return this.picker.group.defs.length - } - - get hasDelete() { - return !!this.deleteButton - } - - moveToIndex(index: number) { - assert(index < this.length, "index out of bounds") - this.row = Math.idiv(index, this.width) - this.col = index % this.width - this.reportAria() - return this.picker.group.getButtonAtIndex(index) - } - - private height() { - return Math.ceil(this.length / this.width) - } - - private currentRowWidth() { - assert(this.row >= 0, "row out of bounds") - return this.row < this.height() - 1 - ? this.width - : this.length - this.width * (this.height() - 1) - } - - public initialCursor(row: number = 0, col: number = 0): Button { - this.row = row - this.col = col - const btn = this.getCurrent() - if (btn) { - this.reportAria() - return undefined // TODO - } - return undefined - } - - clear() { - this.deleteButton = undefined - } - - addButtons(btns: ButtonBase[]) {} - - addDelete(btn: Button) { - this.deleteButton = btn - } - - getCurrent() { - // console.log(`row: ${this.row}, col: ${this.col}`) - if (this.row == -1) { - return this.deleteButton - } else { - const index = this.row * this.width + this.col - if (index < this.length) - return this.picker.group.getButtonAtIndex(index) - } - return undefined - } - - screenToButton(x: number, y: number): Button { - const p = new Vec2(x, y) - const btn = this.deleteButton - if ( - btn && - Bounds.Translate(btn.bounds, btn.xfrm.worldPos).contains(p) - ) - return btn - const np = this.picker.group.getButtonAtScreen(x, y) - if (np) { - this.row = np.y - this.col = np.x - if (this.col >= this.currentRowWidth()) - this.col = this.currentRowWidth() - 1 - return this.getCurrent() - } - return undefined - } - - move(dir: CursorDir) { - switch (dir) { - case CursorDir.Up: { - if (this.row == -1 || (!this.deleteButton && this.row == 0)) - throw new NavigationError(BACK_BUTTON_ERROR_KIND) - if (this.row > 0) this.row-- - else if (this.deleteButton) this.row = -1 - break - } - case CursorDir.Down: { - if (this.row < this.height() - 1) { - this.row++ - if (this.col >= this.currentRowWidth()) { - this.col = this.currentRowWidth() - 1 - } - } else throw new NavigationError(FORWARD_BUTTON_ERROR_KIND) - break - } - case CursorDir.Left: { - if (this.col > 0) this.col-- - else if (this.row > 0) { - this.row-- - this.col = this.width - 1 - } else if (this.deleteButton) { - this.row = -1 - } - break - } - case CursorDir.Right: { - if (this.row == -1) { - this.row = 0 - this.col = 0 - } else if (this.col < this.currentRowWidth() - 1) this.col++ - else if (this.row < this.height() - 1) { - this.row++ - this.col = 0 - } - break - } - } - this.reportAria() - return this.getCurrent() - } - - public updateAria() { - this.reportAria() - } - - protected reportAria() { - if (this.row == -1) { - accessibility.setLiveContent(< - accessibility.TextAccessibilityMessage - >{ - type: "text", - value: "delete_tile", - force: true, - }) - } - } - } - - // accessibility for LEDs - export class LEDNavigator extends PickerNavigator { - constructor(picker: Picker) { - super(picker) - this.row = 2 - this.col = 2 - } - protected reportAria() { - super.reportAria() - if (this.row == -1) return - const on = true // TODO: btn.getIcon() == "solid_red" - accessibility.setLiveContent(< - accessibility.LEDAccessibilityMessage - >{ - type: "led", - on, - x: this.col, - y: this.row, - force: true, - }) - } - } - - // accessibility for melody - export class MelodyNavigator extends PickerNavigator { - constructor(picker: Picker) { - super(picker) - this.row = 2 - this.col = 2 - } - protected reportAria() { - super.reportAria() - if (this.row == -1) return - const on = true // TODO btn.getIcon() === "note_on" - const index = this.hasDelete ? this.row - 1 : this.row - accessibility.setLiveContent(< - accessibility.NoteAccessibilityMessage - >{ - type: "note", - on, - index, - force: true, - }) - } - } -} From b6bca3a9b214d282991a0cbb12d230305e456036 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 22:09:22 +0000 Subject: [PATCH 014/109] sensorSelect.ts: Added 9 more options --- sensorSelect.ts | 137 ++++++++++++++++++++++-------------------------- 1 file changed, 64 insertions(+), 73 deletions(-) diff --git a/sensorSelect.ts b/sensorSelect.ts index c2ccb62..797e1e6 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -1,79 +1,79 @@ namespace microcode { export class SensorSelect extends CursorSceneWithPriorPage { private selectedSensor: () => number - - private selectLightSensorBtn: Button - private selectTemperatureBtn: Button - private selectAccelerometerBtn: Button + private btns: Button[] constructor(app: App) { super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) + // super(app) + this.btns = [] } /* override */ startup() { super.startup() + + interface btnData { + ariaID: string, + x: number, + y: number, + name: string, + fn: () => number + } - this.selectLightSensorBtn = new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "led_light_sensor", - ariaId: "Light Level", - x: -50, - y: 30, - onClick: () => { - this.app.popScene() + /** + * Generalisation for touch pin events + * Necessary since the inner function of input.onPinPressed(pin fn(){}) is () => void; where () => number is required + * @param pin TouchPin.P0, TouchPin.P1, TouchPin.P2 + * @returns + */ + const pinPressFunction = function(pin: TouchPin): number { + let res: number = 0 + input.onPinPressed(TouchPin.P0, function () { + res = 1 + }) + return res + } - const opts = { - sensorFn: function () {return input.lightLevel() / 255}, - sensorName: "Light\nLevel", - } - this.app.pushScene(new FrequencySelect(this.app, opts)) - }, - }) + const sensorBtnData: {[id: string]: btnData;} = { + "disk1": {ariaID: "disk1", x: -50, y: -25, name: "disk1", fn: function () {return input.compassHeading()}}, + // "disk2": {ariaID: "disk2", x: 0, y: -25, name: "disk2", fn: function () {return input.soundLevel()}}, + // "disk3": {ariaID: "disk3", x: 50, y: -25, name: "disk3", fn: function () {return input.magneticForce(Dimension.X)}}, - this.selectTemperatureBtn = new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "thermometer", - ariaId: "Thermometer", - x: 0, - y: 30, - onClick: () => { - this.app.popScene() - - const opts = { - sensorFn: function () {return input.temperature()}, - sensorName: "Temperature", - } - this.app.pushScene(new FrequencySelect(this.app, opts)) - }, - }) + "led_light_sensor": {ariaID: "Light Level", x: -50, y: 0, name: "Light\nLevel", fn: function () {return input.lightLevel()}}, + "thermometer": {ariaID: "Thermometer", x: 0, y: 0, name: "Temperature", fn: function () {return input.temperature()}}, + "accelerometer": {ariaID: "Accelerometer", x: 50, y: 0, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}}, - this.selectAccelerometerBtn = new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "accelerometer", - ariaId: "Accelerometer", - x: 50, - y: 30, - onClick: () => { - this.app.popScene() + // "a": {ariaID: "a", x: -50, y: 25, name: "Light\nLevel", fn: function() {return pinPressFunction(TouchPin.P0)}}, + // "b": {ariaID: "b", x: 0, y: 25, name: "Temperature", fn: function () {return pinPressFunction(TouchPin.P1)}}, + // "c": {ariaID: "c", x: 50, y: 25, name: "Accelerometer", fn: function () {return pinPressFunction(TouchPin.P2)}}, - const opts = { - sensorFn: function () {return input.acceleration(Dimension.X)}, - sensorName: "Accelerometer", - } - this.app.pushScene(new FrequencySelect(this.app, opts)) - }, - }) + // "moveTiltUp": {ariaID: "d", x: -50, y: 50, name: "Pitch", fn: function () {return input.rotation(Rotation.Pitch)}}, + // "moveTiltLeft": {ariaID: "e", x: 0, y: 50, name: "Roll", fn: function () {return Rotation.Roll}}, + // "finger_press": {ariaID: "f", x: 50, y: 50, name: "Pin Press", fn: function () {if(input.logoIsPressed()) {return 255} return 0}} + } - const btns: Button[] = [this.selectLightSensorBtn, this.selectTemperatureBtn, this.selectAccelerometerBtn] - this.navigator.addButtons(btns) - } - /* override */ activate() { - super.activate() - this.color = 15 + Object.keys(sensorBtnData).forEach( + key => { + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: key, + ariaId: sensorBtnData[key].ariaID, + x: sensorBtnData[key].x, + y: sensorBtnData[key].y, + onClick: () => { + this.app.popScene() + this.app.pushScene(new FrequencySelect(this.app, { + sensorFn: sensorBtnData[key].fn, + sensorName: sensorBtnData[key].name, + })) + }, + })) + } + ) + + this.navigator.addButtons(this.btns) } draw() { @@ -84,21 +84,12 @@ namespace microcode { Screen.HEIGHT, 0xc ) + + screen.printCenter("Select a sensor to log", 5) - const text = "Select a\nsensor to log" - const half = screen.width - (font.charWidth * text.length) - - Screen.print( - text, - Screen.LEFT_EDGE + half, - Screen.TOP_EDGE + (screen.height / 3), - 0xb, - simage.font8 - ) - - this.selectLightSensorBtn.draw() - this.selectTemperatureBtn.draw() - this.selectAccelerometerBtn.draw() + this.btns.forEach((btn) => { + btn.draw() + }) super.draw() } } From fdc33e17bd1ce688719de7acee620a4803f097f5 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 22:10:17 +0000 Subject: [PATCH 015/109] adding more assets and tooltips for usse by sensor select --- assets.ts | 5 +++++ tooltips.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/assets.ts b/assets.ts index c98aae1..b428e11 100644 --- a/assets.ts +++ b/assets.ts @@ -56,6 +56,11 @@ namespace microcode { if (name == "led_light_sensor") return icondb.led_light_sensor if (name == "thermometer") return icondb.thermometer if (name == "accelerometer") return icondb.accelerometer + if (name == "moveTiltUp") return icondb.moveTiltUp + if (name == "moveTiltLeft") return icondb.moveTiltLeft + if (name == "moveTiltRight") return icondb.moveTiltRight + if (name == "moveTiltDown") return icondb.moveTiltDown + if (name == "finger_press") return icondb.finger_press extraImage = null extraSamples(name) // only for web app diff --git a/tooltips.ts b/tooltips.ts index 8e32143..aaa8086 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -154,6 +154,11 @@ namespace microcode { else if (id == "thermometer") res = "Thermometer" else if (id == "accelerometer") res = "Accelerometer" + else if (id == "Roll") res = "Roll" + else if (id == "Pitch") res = "Pitch" + else if (id == "Logo Press") res = "Logo Press" + else if (id == "Pin Press") res = "Pin Press" + // icons do not yet exist: else if (id == "Record") res = "Record" else if (id == "View") res = "View" From 57382d8e8eb8621d5129074615687c92468df668 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 22:17:28 +0000 Subject: [PATCH 016/109] Staging all files in order to merge MicroData branch with main branch - granted repo renaming to MicroData. --- app.ts | 8 +++----- cursorscene.ts | 34 +--------------------------------- dataRecorder.ts | 2 -- home.ts | 25 +++++++++++-------------- recordedDataViewer.ts | 4 ++-- sensorSelect.ts | 4 ++-- 6 files changed, 19 insertions(+), 58 deletions(-) diff --git a/app.ts b/app.ts index f87812f..590faa1 100644 --- a/app.ts +++ b/app.ts @@ -12,13 +12,11 @@ namespace microcode { constructor() { // One interval delay to ensure all static constructors have executed. - basic.pause(1) + basic.pause(5) reportEvent("app.start") this.sceneManager = new SceneManager() - - const home = new Home(this) - // const home = new SensorSelect(this) - this.pushScene(home) + // this.pushScene(new Home(this)) + this.pushScene(new SensorSelect(this)) } public saveBuffer(slot: string, buf: Buffer) { diff --git a/cursorscene.ts b/cursorscene.ts index cd6bff5..0e1c4df 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -147,39 +147,7 @@ namespace microcode { /* override */ startup() { super.startup() - context.onEvent( - ControllerButtonEvent.Pressed, - controller.right.id, - () => this.moveCursor(CursorDir.Right) - ) - context.onEvent( - ControllerButtonEvent.Pressed, - controller.up.id, - () => this.moveCursor(CursorDir.Up) - ) - context.onEvent( - ControllerButtonEvent.Pressed, - controller.down.id, - () => this.moveCursor(CursorDir.Down) - ) - context.onEvent( - ControllerButtonEvent.Pressed, - controller.left.id, - () => this.moveCursor(CursorDir.Left) - ) - - // click - const click = () => this.cursor.click() - context.onEvent( - ControllerButtonEvent.Pressed, - controller.A.id, - click - ) - context.onEvent( - ControllerButtonEvent.Pressed, - controller.A.id + keymap.PLAYER_OFFSET, - click - ) + context.onEvent( ControllerButtonEvent.Pressed, controller.B.id, diff --git a/dataRecorder.ts b/dataRecorder.ts index 1472c9b..4e47aee 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -23,8 +23,6 @@ namespace microcode { this.loggingStartTime = input.runningTime() - // datalogger.deleteLog() - // Go Back: control.onEvent( ControllerButtonEvent.Pressed, diff --git a/home.ts b/home.ts index 5264cf5..201d41c 100644 --- a/home.ts +++ b/home.ts @@ -1,8 +1,8 @@ namespace microcode { export class Home extends CursorScene { - recordDataBtn: Button - liveDataBtn: Button - viewBtn: Button + private recordDataBtn: Button + private liveDataBtn: Button + private viewBtn: Button constructor(app: App) { super(app) @@ -55,11 +55,6 @@ namespace microcode { this.navigator.addButtons(btns) } - /* override */ activate() { - super.activate() - this.color = 15 - } - private drawVersion() { const font = simage.font5 Screen.print( @@ -85,17 +80,18 @@ namespace microcode { const dy = this.yOffset == 0 ? (Math.idiv(t, 800) & 1) - 1 : 0 const margin = 2 const OFFSET = (Screen.HEIGHT >> 1) - wordLogo.height - margin - const y = Screen.TOP_EDGE + OFFSET + dy + const y = Screen.TOP_EDGE + OFFSET //+ dy Screen.drawTransparentImage( wordLogo, - Screen.LEFT_EDGE + ((Screen.WIDTH - wordLogo.width) >> 1) + dy, + Screen.LEFT_EDGE + ((Screen.WIDTH - wordLogo.width) >> 1)// + dy + , y + this.yOffset ) Screen.drawTransparentImage( microbitLogo, Screen.LEFT_EDGE + - ((Screen.WIDTH - microbitLogo.width) >> 1) + - dy, + ((Screen.WIDTH - microbitLogo.width) >> 1) + dy + , y - wordLogo.height + this.yOffset + margin ) if (!this.yOffset) { @@ -103,8 +99,9 @@ namespace microcode { Screen.print( tagline, Screen.LEFT_EDGE + - ((Screen.WIDTH + wordLogo.width) >> 1) + - dy - + ((Screen.WIDTH + wordLogo.width) >> 1) + + dy + - microcode.font.charWidth * tagline.length, Screen.TOP_EDGE + OFFSET + diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index a2351e6..facc2dc 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -15,7 +15,7 @@ namespace microcode { controller.B.id, () => { app.popScene() - app.pushScene(new Home(app)) + app.pushScene(new Home(this.app)) } ) @@ -72,7 +72,6 @@ namespace microcode { 0xC ) - FauxDataLogger.numberOfRows = 5 this.draw_grid() for (let i = 0; i < FauxDataLogger.headers.length; i++) { @@ -86,6 +85,7 @@ namespace microcode { ) } + FauxDataLogger.numberOfRows = 5 // interface IDictionary {[index: string]: number;} // const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7} diff --git a/sensorSelect.ts b/sensorSelect.ts index 797e1e6..b8864a8 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -40,14 +40,14 @@ namespace microcode { // "disk3": {ariaID: "disk3", x: 50, y: -25, name: "disk3", fn: function () {return input.magneticForce(Dimension.X)}}, "led_light_sensor": {ariaID: "Light Level", x: -50, y: 0, name: "Light\nLevel", fn: function () {return input.lightLevel()}}, - "thermometer": {ariaID: "Thermometer", x: 0, y: 0, name: "Temperature", fn: function () {return input.temperature()}}, + // "thermometer": {ariaID: "Thermometer", x: 0, y: 0, name: "Temperature", fn: function () {return input.temperature()}}, "accelerometer": {ariaID: "Accelerometer", x: 50, y: 0, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}}, // "a": {ariaID: "a", x: -50, y: 25, name: "Light\nLevel", fn: function() {return pinPressFunction(TouchPin.P0)}}, // "b": {ariaID: "b", x: 0, y: 25, name: "Temperature", fn: function () {return pinPressFunction(TouchPin.P1)}}, // "c": {ariaID: "c", x: 50, y: 25, name: "Accelerometer", fn: function () {return pinPressFunction(TouchPin.P2)}}, - // "moveTiltUp": {ariaID: "d", x: -50, y: 50, name: "Pitch", fn: function () {return input.rotation(Rotation.Pitch)}}, + "moveTiltUp": {ariaID: "d", x: -50, y: 50, name: "Pitch", fn: function () {return input.rotation(Rotation.Pitch)}}, // "moveTiltLeft": {ariaID: "e", x: 0, y: 50, name: "Roll", fn: function () {return Rotation.Roll}}, // "finger_press": {ariaID: "f", x: 50, y: 50, name: "Pin Press", fn: function () {if(input.logoIsPressed()) {return 255} return 0}} } From 5a1e4fb4cf9fba85d62b155d4a0e462e409b3f43 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 14 Feb 2024 22:19:14 +0000 Subject: [PATCH 017/109] Merge with MicroData branch --- build.ps1 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 build.ps1 diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..39dc12a --- /dev/null +++ b/build.ps1 @@ -0,0 +1,2 @@ +pxt build +copy built\binary.hex F:\ \ No newline at end of file From adceac5290921927cb9c44c49f893b9262b64aad Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 15 Feb 2024 07:56:00 +0000 Subject: [PATCH 018/109] renaming measurementFrequencySelect.ts to measurementConfigSelect.ts --- measurementFrequencySelect.ts => measurementConfigSelect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename measurementFrequencySelect.ts => measurementConfigSelect.ts (98%) diff --git a/measurementFrequencySelect.ts b/measurementConfigSelect.ts similarity index 98% rename from measurementFrequencySelect.ts rename to measurementConfigSelect.ts index 685b212..5821c60 100644 --- a/measurementFrequencySelect.ts +++ b/measurementConfigSelect.ts @@ -4,7 +4,7 @@ namespace microcode { } const MAXIMUMS = {measurements: 1000, frequency: 10000} as IDictionary; - export class FrequencySelect extends Scene { + export class MeasurementConfigSelect extends Scene { // Passed to DataRecorder: private userOpts: {sensorFn: () => number, sensorName: string} private frequencySelectOptions: IDictionary From 24b269a48e9a38a2db9aa367eeba3231380caff2 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 15 Feb 2024 08:29:39 +0000 Subject: [PATCH 019/109] added SceneFactory to create new Scenes, added userOpts to constructor of LiveDataViewer, added sensorSelect in front of the LiveDataViewer, allowing for dynamic graphing. --- app.ts | 4 ++-- home.ts | 4 ++-- liveDataViewer.ts | 11 +++++++---- pxt.json | 5 +++-- sceneFactory.ts | 26 ++++++++++++++++++++++++++ sensorSelect.ts | 22 +++++++++++++--------- 6 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 sceneFactory.ts diff --git a/app.ts b/app.ts index 590faa1..937c721 100644 --- a/app.ts +++ b/app.ts @@ -15,8 +15,8 @@ namespace microcode { basic.pause(5) reportEvent("app.start") this.sceneManager = new SceneManager() - // this.pushScene(new Home(this)) - this.pushScene(new SensorSelect(this)) + this.pushScene(new Home(this)) + // this.pushScene(new SensorSelect(this)) } public saveBuffer(slot: string, buf: Buffer) { diff --git a/home.ts b/home.ts index 201d41c..9ad5fb1 100644 --- a/home.ts +++ b/home.ts @@ -20,7 +20,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new LiveDataViewer(this.app)) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) }, }) @@ -33,7 +33,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new SensorSelect(this.app)) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) }, }) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index b3d6563..7e19cc9 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -3,13 +3,16 @@ namespace microcode { const HEIGHT_BUFFER = 12; export class LiveDataViewer extends Scene { - public rendering = false private dataBuffer: number[] = []; private bufferLimit = screen.width - (2 * WIDTH_BUFFER); + private sensorFn: () => number + private sensorName: string - constructor(app: App) { + constructor(app: App, userOpts: {sensorFn: () => number, sensorName: string}) { super(app, "liveDataViewer") this.color = 0 + this.sensorFn = userOpts.sensorFn + this.sensorName = userOpts.sensorName const goBack = function() { app.popScene() @@ -25,7 +28,7 @@ namespace microcode { update() { // Pre-process and convert lightlevel into a y value; relative to screen-height - let light_level = input.lightLevel() / 255; + let light_level = this.sensorFn() / 255; let y = Math.round(screen.height - (light_level * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER // Buffer management: @@ -47,7 +50,7 @@ namespace microcode { * Bound to Microbit button A */ private plot() { - screen.printCenter("Light Level", 10) + screen.printCenter(this.sensorName, 10) this.draw_axes(); const start = WIDTH_BUFFER + 2; diff --git a/pxt.json b/pxt.json index 38e42d7..365dafd 100644 --- a/pxt.json +++ b/pxt.json @@ -43,8 +43,9 @@ "dataRecorder.ts", "recordedDataViewer.ts", "sensorSelect.ts", - "measurementFrequencySelect.ts", - "fauxDatalogger.ts" + "measurementConfigSelect.ts", + "fauxDatalogger.ts", + "sceneFactory.ts" ], "testFiles": [], "targetVersions": { diff --git a/sceneFactory.ts b/sceneFactory.ts new file mode 100644 index 0000000..0b2a049 --- /dev/null +++ b/sceneFactory.ts @@ -0,0 +1,26 @@ +namespace microcode { + export enum CursorSceneEnum { + LiveDataViewer, + SensorSelect, + MeasurementConfigSelect + } + + export function generateScene(sceneEnum: CursorSceneEnum, app: App, + userOpts?: {sensorFn: () => number, sensorName: string}, + nextScene?: CursorSceneEnum + ){ + switch (sceneEnum) { + case CursorSceneEnum.LiveDataViewer: + return new LiveDataViewer(app, userOpts) + + case CursorSceneEnum.SensorSelect: + return new SensorSelect(app, nextScene) + + case CursorSceneEnum.MeasurementConfigSelect: + return new MeasurementConfigSelect(app, userOpts) + + default: + return new LiveDataViewer(app, userOpts); + } + } +} \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index b8864a8..286759e 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -1,12 +1,12 @@ namespace microcode { export class SensorSelect extends CursorSceneWithPriorPage { - private selectedSensor: () => number private btns: Button[] + private nextSceneEnum: CursorSceneEnum - constructor(app: App) { + constructor(app: App, nextSceneEnum: CursorSceneEnum) { super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) - // super(app) this.btns = [] + this.nextSceneEnum = nextSceneEnum } /* override */ startup() { @@ -34,20 +34,24 @@ namespace microcode { return res } + + /** + * Issue with consistently being able to load this app when there are > 3 buttons + */ const sensorBtnData: {[id: string]: btnData;} = { - "disk1": {ariaID: "disk1", x: -50, y: -25, name: "disk1", fn: function () {return input.compassHeading()}}, + // "disk1": {ariaID: "disk1", x: -50, y: -25, name: "disk1", fn: function () {return input.compassHeading()}}, // "disk2": {ariaID: "disk2", x: 0, y: -25, name: "disk2", fn: function () {return input.soundLevel()}}, // "disk3": {ariaID: "disk3", x: 50, y: -25, name: "disk3", fn: function () {return input.magneticForce(Dimension.X)}}, - "led_light_sensor": {ariaID: "Light Level", x: -50, y: 0, name: "Light\nLevel", fn: function () {return input.lightLevel()}}, - // "thermometer": {ariaID: "Thermometer", x: 0, y: 0, name: "Temperature", fn: function () {return input.temperature()}}, - "accelerometer": {ariaID: "Accelerometer", x: 50, y: 0, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}}, + "led_light_sensor": {ariaID: "Light Level", x: -50, y: 0, name: "Light Level", fn: function () {return input.lightLevel()}}, + "thermometer": {ariaID: "Thermometer", x: 0, y: 0, name: "Temperature", fn: function () {return input.temperature()}}, + "accelerometer": {ariaID: "Accelerometer", x: 50, y: 0, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}} // "a": {ariaID: "a", x: -50, y: 25, name: "Light\nLevel", fn: function() {return pinPressFunction(TouchPin.P0)}}, // "b": {ariaID: "b", x: 0, y: 25, name: "Temperature", fn: function () {return pinPressFunction(TouchPin.P1)}}, // "c": {ariaID: "c", x: 50, y: 25, name: "Accelerometer", fn: function () {return pinPressFunction(TouchPin.P2)}}, - "moveTiltUp": {ariaID: "d", x: -50, y: 50, name: "Pitch", fn: function () {return input.rotation(Rotation.Pitch)}}, + // "moveTiltUp": {ariaID: "d", x: -50, y: 50, name: "Pitch", fn: function () {return input.rotation(Rotation.Pitch)}}, // "moveTiltLeft": {ariaID: "e", x: 0, y: 50, name: "Roll", fn: function () {return Rotation.Roll}}, // "finger_press": {ariaID: "f", x: 50, y: 50, name: "Pin Press", fn: function () {if(input.logoIsPressed()) {return 255} return 0}} } @@ -64,7 +68,7 @@ namespace microcode { y: sensorBtnData[key].y, onClick: () => { this.app.popScene() - this.app.pushScene(new FrequencySelect(this.app, { + this.app.pushScene(generateScene(this.nextSceneEnum, this.app, { sensorFn: sensorBtnData[key].fn, sensorName: sensorBtnData[key].name, })) From 6882ee9c1aacf988b119b39ec367206772989f62 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 15 Feb 2024 08:36:33 +0000 Subject: [PATCH 020/109] Renaming of 'frequency' to 'period' within userOpts and measurementConfigSelect --- dataRecorder.ts | 8 ++++---- measurementConfigSelect.ts | 40 +++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 4e47aee..9f59763 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -7,14 +7,14 @@ namespace microcode { sensorFn: () => number, sensorName: string, measurements: number, - frequency: number + period: number } constructor(app: App, userOpts: { sensorFn: () => number, sensorName: string, measurements: number, - frequency: number + period: number }) { super(app, "dataRecorder") @@ -49,7 +49,7 @@ namespace microcode { } else { - const secondsLeft: number = (this.userOpts.measurements * this.userOpts.frequency) / 1000 + const secondsLeft: number = (this.userOpts.measurements * this.userOpts.period) / 1000 screen.printCenter("Recording data...", 10); screen.printCenter(secondsLeft.toString() + " seconds left", screen.height / 2); @@ -57,7 +57,7 @@ namespace microcode { FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.userOpts.sensorFn()) this.userOpts.measurements -= 1 - basic.pause(this.userOpts.frequency) + basic.pause(this.userOpts.period) } } } diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index 5821c60..a2c7bf3 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -2,23 +2,23 @@ namespace microcode { interface IDictionary { [index: string]: number; } - const MAXIMUMS = {measurements: 1000, frequency: 10000} as IDictionary; + const MAXIMUMS = {measurements: 1000, period: 10000} as IDictionary; export class MeasurementConfigSelect extends Scene { // Passed to DataRecorder: private userOpts: {sensorFn: () => number, sensorName: string} - private frequencySelectOptions: IDictionary + private measurementOpts: IDictionary private mode: string = "measurements" constructor(app: App, userOpts: {sensorFn: () => number, sensorName: string}) { - super(app, "frequencySelect") + super(app, "measurementConfigSelect") this.userOpts = userOpts; // Defaults: - this.frequencySelectOptions = { + this.measurementOpts = { measurements: 20, - frequency: 1000 + period: 1000 } } @@ -29,7 +29,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] + 1) % MAXIMUMS[this.mode] + this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] + 1) % MAXIMUMS[this.mode] } ) @@ -38,10 +38,10 @@ namespace microcode { controller.down.id, () => { - if (this.frequencySelectOptions[this.mode] == 0) { - this.frequencySelectOptions[this.mode] = 1000 + if (this.measurementOpts[this.mode] == 0) { + this.measurementOpts[this.mode] = 1000 } else { - this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] - 1) % MAXIMUMS[this.mode] + this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] - 1) % MAXIMUMS[this.mode] } } ) @@ -50,7 +50,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] + (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] + this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] + (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] } ) @@ -58,10 +58,10 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.left.id, () => { - if (this.frequencySelectOptions[this.mode] - 10 <= 0) { - this.frequencySelectOptions[this.mode] = 1000 + if (this.measurementOpts[this.mode] - 10 <= 0) { + this.measurementOpts[this.mode] = 1000 } else { - this.frequencySelectOptions[this.mode] = (this.frequencySelectOptions[this.mode] - (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] + this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] - (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] } } ) @@ -79,12 +79,12 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.A.id, () => { - if (this.mode === "frequency") { + if (this.mode === "period") { const userOpts = { sensorFn: this.userOpts.sensorFn, sensorName: this.userOpts.sensorName, - measurements: this.frequencySelectOptions.measurements, - frequency: this.frequencySelectOptions.frequency + measurements: this.measurementOpts.measurements, + period: this.measurementOpts.period } const dataRecorder = new DataRecorder(this.app, userOpts) @@ -93,7 +93,7 @@ namespace microcode { } else { - this.mode = "frequency" + this.mode = "period" } } ) @@ -113,15 +113,15 @@ namespace microcode { 0xc ) - if (this.mode === "frequency") { - screen.printCenter("Measurement frequency", 20) + if (this.mode === "period") { + screen.printCenter("Measurement period", 20) } else if (this.mode === "measurements") { screen.printCenter("Number of measurements", 20) } - let value = "" + this.frequencySelectOptions[this.mode]; + let value = "" + this.measurementOpts[this.mode]; const textOffset = (screen.width - (font.charWidth * value.length)) / 2 Screen.print( From 68f00a2923583d5e1787b9a9a33ed2a8fbfb81b3 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 21 Feb 2024 09:06:48 +0000 Subject: [PATCH 021/109] Revamped data viewer --- dataRecorder.ts | 15 +-- fauxDatalogger.ts | 17 ++- home.ts | 10 +- liveDataViewer.ts | 2 +- measurementConfigSelect.ts | 219 +++++++++++++++++-------------------- recordedDataViewer.ts | 191 +++++++++++++++++++++++--------- sceneFactory.ts | 21 ++-- sensorSelect.ts | 21 ++-- userOptions.ts | 52 +++++++++ 9 files changed, 346 insertions(+), 202 deletions(-) create mode 100644 userOptions.ts diff --git a/dataRecorder.ts b/dataRecorder.ts index 9f59763..6b2af76 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -2,20 +2,9 @@ namespace microcode { export class DataRecorder extends Scene { private fauxDatalogger: FauxDataLogger private loggingStartTime: number + private userOpts: MeasurementOpts - private userOpts: { - sensorFn: () => number, - sensorName: string, - measurements: number, - period: number - } - - constructor(app: App, userOpts: { - sensorFn: () => number, - sensorName: string, - measurements: number, - period: number - }) { + constructor(app: App, userOpts: MeasurementOpts) { super(app, "dataRecorder") this.userOpts = userOpts diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 8cf2d12..ed819ea 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -1,20 +1,27 @@ namespace microcode { - interface IDictionary { - [index: string]: number; + interface MetaData { + id: number, + col1: string, + col2: string } + export class FauxDataLogger { static headers: string[] = ["DEFAULT", "DEFAULT"] - static data: IDictionary + static data: MetaData[] static numberOfRows: number constructor(headers: string[]) { FauxDataLogger.headers = headers - FauxDataLogger.data = {} + FauxDataLogger.data = [] FauxDataLogger.numberOfRows = 0 } public static log(key: string, value: number) { - FauxDataLogger.data[key] = value + FauxDataLogger.data.push({ + id: this.data.length, + col1: key, + col2: value.toString() + }) FauxDataLogger.numberOfRows += 1 } } diff --git a/home.ts b/home.ts index 9ad5fb1..2016cea 100644 --- a/home.ts +++ b/home.ts @@ -21,6 +21,13 @@ namespace microcode { onClick: () => { this.app.popScene() this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + + const sOpts: SensorOpts = { + sensorFn: function () {return input.lightLevel()}, + sensorName: "Light Level", + } + // app.pushScene(new MeasurementConfigSelect(app, sOpts)) + // app.pushScene(new LiveDataViewer(app, sOpts)) }, }) @@ -34,6 +41,7 @@ namespace microcode { onClick: () => { this.app.popScene() this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + // this.app.pushScene(new Editor(this.app)) }, }) @@ -46,7 +54,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new RecordedDataViewer(this.app)) + this.app.pushScene(new RecordedDataViewer(this.app, 1)) }, }) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 7e19cc9..0376b63 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -8,7 +8,7 @@ namespace microcode { private sensorFn: () => number private sensorName: string - constructor(app: App, userOpts: {sensorFn: () => number, sensorName: string}) { + constructor(app: App, userOpts: SensorOpts) { super(app, "liveDataViewer") this.color = 0 this.sensorFn = userOpts.sensorFn diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index a2c7bf3..190ca87 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -1,108 +1,95 @@ namespace microcode { - interface IDictionary { - [index: string]: number; - } - const MAXIMUMS = {measurements: 1000, period: 10000} as IDictionary; + // interface IDictionary { + // [index: string]: number; + // } + // const MAXIMUMS = {measurements: 1000, period: 10000} as IDictionary; - export class MeasurementConfigSelect extends Scene { + export class MeasurementConfigSelect extends CursorSceneWithPriorPage { // Passed to DataRecorder: - private userOpts: {sensorFn: () => number, sensorName: string} - private measurementOpts: IDictionary - private mode: string = "measurements" + // private sOpts: SensorOpts + // private measurementOpts: IDictionary + // private mode: string = "measurements" + // private btns: Button[] - constructor(app: App, userOpts: {sensorFn: () => number, sensorName: string}) { - super(app, "measurementConfigSelect") - - this.userOpts = userOpts; - - // Defaults: - this.measurementOpts = { - measurements: 20, - period: 1000 - } - } - - /* override */ startup() { - super.startup() - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.up.id, - () => { - this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] + 1) % MAXIMUMS[this.mode] - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.down.id, - - () => { - if (this.measurementOpts[this.mode] == 0) { - this.measurementOpts[this.mode] = 1000 - } else { - this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] - 1) % MAXIMUMS[this.mode] - } - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.right.id, - () => { - this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] + (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.left.id, - () => { - if (this.measurementOpts[this.mode] - 10 <= 0) { - this.measurementOpts[this.mode] = 1000 - } else { - this.measurementOpts[this.mode] = (this.measurementOpts[this.mode] - (MAXIMUMS[this.mode] / 100)) % MAXIMUMS[this.mode] - } - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.B.id, - () => { + // constructor(app: App, sOpts: SensorOpts) { + // super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) + + // this.sOpts = sOpts; + + // // Defaults: + // this.measurementOpts = { + // measurements: 20, + // period: 1000 + // } + // } + + private dataBuffer: number[] = []; + private sensorFn: () => number + private sensorName: string + + constructor(app: App, userOpts: SensorOpts) { + super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) + this.color = 0 + this.sensorFn = userOpts.sensorFn + this.sensorName = userOpts.sensorName + + const goBack = function() { app.popScene() app.pushScene(new Home(app)) - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.A.id, - () => { - if (this.mode === "period") { - const userOpts = { - sensorFn: this.userOpts.sensorFn, - sensorName: this.userOpts.sensorName, - measurements: this.measurementOpts.measurements, - period: this.measurementOpts.period - } - - const dataRecorder = new DataRecorder(this.app, userOpts) - this.app.popScene() - this.app.pushScene(dataRecorder) - } - - else { - this.mode = "period" - } - } - ) - } + }; + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => goBack() + ) + } - /* override */ activate() { - super.activate() - this.color = 15 - } + // /* override */ startup() { + // super.startup() + // } + + // interface btnData { + // ariaID: string, + // x: number, + // y: number, + // name: string, + // fn: () => number + // } + + // const sensorBtnData: {[id: string]: btnData;} = { + // "led_light_sensor": {ariaID: "led_light_sensor", x: -50, y: 50, name: "Light Level", fn: function () {return input.lightLevel()}}, + // "thermometer": {ariaID: "thermometer", x: 0, y: 50, name: "Temperature", fn: function () {return input.temperature()}}, + // "accelerometer": {ariaID: "accelerometer", x: 50, y: 50, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}} + // } + + // Object.keys(sensorBtnData).forEach( + // key => { + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.FlatWhite, + // icon: key, + // ariaId: sensorBtnData[key].ariaID, + // x: sensorBtnData[key].x, + // y: sensorBtnData[key].y, + // onClick: () => { + // this.app.popScene() + // this.app.pushScene(new DataRecorder(this.app, { + // sensorFn: sensorBtnData[key].fn, + // sensorName: sensorBtnData[key].name, + // measurements: this.measurementOpts.measurements, + // period: this.measurementOpts.period + // })) + // }, + // })) + // } + // ) + // } + + // /* override */ activate() { + // super.activate() + // this.color = 15 + // } draw() { Screen.fillRect( @@ -113,24 +100,24 @@ namespace microcode { 0xc ) - if (this.mode === "period") { - screen.printCenter("Measurement period", 20) - } - - else if (this.mode === "measurements") { - screen.printCenter("Number of measurements", 20) - } - - let value = "" + this.measurementOpts[this.mode]; - const textOffset = (screen.width - (font.charWidth * value.length)) / 2 - - Screen.print( - value, - Screen.LEFT_EDGE + textOffset, - Screen.TOP_EDGE + (screen.height / 2), - 0xb, - simage.font8 - ) + // if (this.mode === "period") { + // screen.printCenter("Measurement period", 20) + // } + + // else if (this.mode === "measurements") { + // screen.printCenter("Number of measurements", 20) + // } + + // let value = "" + this.measurementOpts[this.mode]; + // const textOffset = (screen.width - (font.charWidth * value.length)) / 2 + + // Screen.print( + // value, + // Screen.LEFT_EDGE + textOffset, + // Screen.TOP_EDGE + (screen.height / 2), + // 0xb, + // simage.font8 + // ) super.draw() } diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index facc2dc..afdbc8a 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -1,21 +1,48 @@ namespace microcode { - const HEADER_OFFSET = 25 + const HEADER_OFFSET = 17 const MAX_ROWS = 10 + const enum DISPLAY_MODE { + DATA_VIEW, + GRAPH_GENERATION, + METADATA_MODE, + } + export class RecordedDataViewer extends Scene { private scrollOffset: number; + private current_mode: DISPLAY_MODE; + private saveSlot: number - constructor(app: App) { + constructor(app: App, saveSlot: number) { super(app, "dataViewer") this.scrollOffset = 0 + this.current_mode = DISPLAY_MODE.METADATA_MODE + this.saveSlot = saveSlot control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, () => { - app.popScene() - app.pushScene(new Home(this.app)) + switch (this.current_mode) { + case DISPLAY_MODE.DATA_VIEW: + this.current_mode = DISPLAY_MODE.METADATA_MODE + break; + + case DISPLAY_MODE.GRAPH_GENERATION: + this.current_mode = DISPLAY_MODE.DATA_VIEW + break; + + case DISPLAY_MODE.METADATA_MODE: + app.popScene() + app.pushScene(new Home(this.app)) + break; + + default: + app.popScene() + app.pushScene(new Home(this.app)) + break; + } } ) @@ -23,8 +50,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { - this.scrollOffset += (Screen.HEIGHT / MAX_ROWS) * 2 - this.scrollOffset = Math.min(this.scrollOffset, Screen.HEIGHT - ((Screen.HEIGHT / MAX_ROWS) * 4)) + this.scrollOffset = Math.min(this.scrollOffset + 1, MAX_ROWS) } ) @@ -32,27 +58,26 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - this.scrollOffset -= (Screen.HEIGHT / MAX_ROWS) * 2 - this.scrollOffset = Math.max(this.scrollOffset, 0) + this.scrollOffset = Math.max(this.scrollOffset - 1, 0) } ) } draw_grid() { - const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length - const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + const colBufferSize = Screen.WIDTH / 2 //FauxDataLogger.headers.length + const rowBufferSize = Screen.HEIGHT / 4 // Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( Screen.LEFT_EDGE + colOffset, - Screen.TOP_EDGE + HEADER_OFFSET, + Screen.TOP_EDGE, Screen.LEFT_EDGE + colOffset, Screen.HEIGHT, 0x0 ) } - for (let rowOffset = HEADER_OFFSET; rowOffset <= Screen.HEIGHT; rowOffset+=rowBufferSize) { + for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=rowBufferSize) { Screen.drawLine( Screen.LEFT_EDGE, Screen.TOP_EDGE + rowOffset, @@ -72,48 +97,114 @@ namespace microcode { 0xC ) - this.draw_grid() - - for (let i = 0; i < FauxDataLogger.headers.length; i++) { - const textOffset = (screen.width - (font.charWidth * FauxDataLogger.headers[i].length)) / 4 - Screen.print( - FauxDataLogger.headers[i], - Screen.LEFT_EDGE + textOffset + (i * 80) - 4, - Screen.TOP_EDGE + 4, - 0xb, - simage.font8 - ) - } - - FauxDataLogger.numberOfRows = 5 - // interface IDictionary {[index: string]: number;} - // const data: IDictionary = {"1" : 1, "2" : 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7} - - const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length - const rowOffsetDelta = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) let rowOffset = 0 - Object.keys(FauxDataLogger.data).forEach( - key => { - Screen.print( - key, - Screen.LEFT_EDGE + (colBufferSize / 2) - ((font.charWidth * key.length) / 2), - Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4 + this.scrollOffset, - 0xb, - simage.font8 - ) + switch (this.current_mode) { + case DISPLAY_MODE.METADATA_MODE: + screen.printCenter("MetaData for Save " + this.saveSlot, 2) - const sensorData = FauxDataLogger.data[key].toString().slice(0, 4) - Screen.print( - sensorData, - Screen.LEFT_EDGE + colBufferSize + (colBufferSize / 2) - ((font.charWidth *sensorData.length) / 2), - Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowOffsetDelta / 2) - 4 + this.scrollOffset, - 0xb, - simage.font8 + control.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + () => { + this.current_mode = DISPLAY_MODE.DATA_VIEW + } ) - rowOffset += rowOffsetDelta - } - ) + + const colSize = Screen.WIDTH / 2 + const rowDelta = Screen.HEIGHT / 4 + + for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colSize) { + Screen.drawLine( + Screen.LEFT_EDGE + colOffset, + Screen.TOP_EDGE + HEADER_OFFSET, + Screen.LEFT_EDGE + colOffset, + Screen.HEIGHT, + 0x0 + ) + } + + for (let rowOffset = HEADER_OFFSET; rowOffset <= Screen.HEIGHT; rowOffset+=rowDelta) { + Screen.drawLine( + Screen.LEFT_EDGE, + Screen.TOP_EDGE + rowOffset, + Screen.WIDTH, + Screen.TOP_EDGE + rowOffset, + 0x0 + ) + } + + const metadata = [ + {id: 1, col1: "Save", col2: "1"}, + {id: 2, col1: "Taken", col2: "21/02/2024"}, + {id: 3, col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, + {id: 4, col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + ] + + for (let i = this.scrollOffset; i < 4; i++) { + Screen.print( + metadata[i].col1, + Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[i].col1.length) / 2), + Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowDelta / 2) - 4, + 0xb, + simage.font8 + ) + + Screen.print( + metadata[i].col2, + Screen.LEFT_EDGE + colSize + (colSize / 2) - ((font.charWidth * metadata[i].col2.length) / 2), + Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowDelta / 2) - 4, + 0xb, + simage.font8 + ) + rowOffset += rowDelta + } + break; + + case DISPLAY_MODE.GRAPH_GENERATION: + + break; + + case DISPLAY_MODE.DATA_VIEW: + this.draw_grid() + + const colSizeBuffer = Screen.WIDTH / 2 + const rowDeltaBuffer = Screen.HEIGHT / 4 + + // const data = [ + // {id: 1, col1: "1", col2: "1"}, + // {id: 2, col1: "2", col2: "2"}, + // {id: 3, col1: "3", col2: "3"}, + // {id: 4, col1: "4", col2: "4"}, + // ] + + + const data = FauxDataLogger.data + // FauxDataLogger.numberOfRows = 4 + + for (let i = this.scrollOffset; i < FauxDataLogger.numberOfRows; i++) { + Screen.print( + data[i].col1, + Screen.LEFT_EDGE + (colSizeBuffer / 2) - ((font.charWidth * data[i].col1.length) / 2), + Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, + 0xb, + simage.font8 + ) + + Screen.print( + data[i].col2, + Screen.LEFT_EDGE + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[i].col2.length) / 2), + Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, + 0xb, + simage.font8 + ) + rowOffset += rowDeltaBuffer + } + break; + + default: + break; + } } } } \ No newline at end of file diff --git a/sceneFactory.ts b/sceneFactory.ts index 0b2a049..15aba23 100644 --- a/sceneFactory.ts +++ b/sceneFactory.ts @@ -2,25 +2,28 @@ namespace microcode { export enum CursorSceneEnum { LiveDataViewer, SensorSelect, - MeasurementConfigSelect + MeasurementConfigSelect, + RecordData, } - export function generateScene(sceneEnum: CursorSceneEnum, app: App, - userOpts?: {sensorFn: () => number, sensorName: string}, - nextScene?: CursorSceneEnum - ){ + export function generateScene(sceneEnum: CursorSceneEnum, app: App, opts: MeasurementOpts): any; + export function generateScene(sceneEnum: CursorSceneEnum, app: App, opts: SensorOpts): any; + export function generateScene(sceneEnum: CursorSceneEnum, app: App, mOpts?: MeasurementOpts, sOpts?: SensorOpts, nextScene?: CursorSceneEnum) { switch (sceneEnum) { case CursorSceneEnum.LiveDataViewer: - return new LiveDataViewer(app, userOpts) + return new LiveDataViewer(app, sOpts) case CursorSceneEnum.SensorSelect: return new SensorSelect(app, nextScene) - case CursorSceneEnum.MeasurementConfigSelect: - return new MeasurementConfigSelect(app, userOpts) + // case CursorSceneEnum.MeasurementConfigSelect: + // return new MeasurementConfigSelect(app, sOpts) + + case CursorSceneEnum.RecordData: + return new DataRecorder(app, mOpts) default: - return new LiveDataViewer(app, userOpts); + return new LiveDataViewer(app, sOpts); } } } \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index 286759e..94cc975 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -43,9 +43,9 @@ namespace microcode { // "disk2": {ariaID: "disk2", x: 0, y: -25, name: "disk2", fn: function () {return input.soundLevel()}}, // "disk3": {ariaID: "disk3", x: 50, y: -25, name: "disk3", fn: function () {return input.magneticForce(Dimension.X)}}, - "led_light_sensor": {ariaID: "Light Level", x: -50, y: 0, name: "Light Level", fn: function () {return input.lightLevel()}}, - "thermometer": {ariaID: "Thermometer", x: 0, y: 0, name: "Temperature", fn: function () {return input.temperature()}}, - "accelerometer": {ariaID: "Accelerometer", x: 50, y: 0, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}} + "led_light_sensor": {ariaID: "led_light_sensor", x: -50, y: 30, name: "Light Level", fn: function () {return input.lightLevel()}}, + "thermometer": {ariaID: "thermometer", x: 0, y: 30, name: "Temperature", fn: function () {return input.temperature()}}, + "accelerometer": {ariaID: "accelerometer", x: 50, y: 30, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}} // "a": {ariaID: "a", x: -50, y: 25, name: "Light\nLevel", fn: function() {return pinPressFunction(TouchPin.P0)}}, // "b": {ariaID: "b", x: 0, y: 25, name: "Temperature", fn: function () {return pinPressFunction(TouchPin.P1)}}, @@ -67,11 +67,18 @@ namespace microcode { x: sensorBtnData[key].x, y: sensorBtnData[key].y, onClick: () => { - this.app.popScene() - this.app.pushScene(generateScene(this.nextSceneEnum, this.app, { + const sOpts: SensorOpts = { sensorFn: sensorBtnData[key].fn, - sensorName: sensorBtnData[key].name, - })) + sensorName: sensorBtnData[key].name, + } + + this.app.popScene() + // if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { + // this.app.pushScene(new LiveDataViewer(app, sOpts)) + // } + // else { + // this.app.pushScene(new MeasurementConfigSelect(app, sOpts)) + // } }, })) } diff --git a/userOptions.ts b/userOptions.ts new file mode 100644 index 0000000..3050abe --- /dev/null +++ b/userOptions.ts @@ -0,0 +1,52 @@ +namespace microcode { + export type MeasurementOpts = { + sensorFn: () => number, + sensorName: string, + measurements: number, + period: number + }; + export type SensorOpts = { + sensorFn: () => number, + sensorName: string, + }; + + // "files": [ + // "protocol.ts", + // "keymap.ts", + // "analytics.ts", + // "config.ts", + // "main.ts", + // "accessibility.ts", + // "button.ts", + // "component.ts", + // "assets.ts", + // "scene.ts", + // "language.ts", + // "tiles.ts", + // "app.ts", + // "sprite.ts", + // "cursor.ts", + // "home.ts", + // "bounds.ts", + // "picker.ts", + // "affine.ts", + // "math.ts", + // "screen.ts", + // "version.ts", + // "fieldeditors.ts", + // "navigator.ts", + // "cursorscene.ts", + // "options.ts", + // "tooltips.ts", + // "utils.ts", + // "jacs.ts", + // "liveDataViewer.ts", + // "dataRecorder.ts", + // "recordedDataViewer.ts", + // "sensorSelect.ts", + // "measurementConfigSelect.ts", + // "fauxDatalogger.ts", + // "sceneFactory.ts", + // "userOptions.ts" + // ], +} \ No newline at end of file From 3abc6f6e97ecd839a87a166e472e55490c23fa0a Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 21 Feb 2024 12:21:58 +0000 Subject: [PATCH 022/109] Revamped measurement input, recorded data screen. --- dataRecorder.ts | 5 +- fauxDatalogger.ts | 1 + home.ts | 22 ++- liveDataViewer.ts | 10 +- measurementConfigSelect.ts | 282 ++++++++++++++++++++++--------------- recordedDataViewer.ts | 2 +- sensorSelect.ts | 2 +- userOptions.ts | 1 + 8 files changed, 198 insertions(+), 127 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 6b2af76..fe669aa 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -40,7 +40,10 @@ namespace microcode { else { const secondsLeft: number = (this.userOpts.measurements * this.userOpts.period) / 1000 screen.printCenter("Recording data...", 10); - screen.printCenter(secondsLeft.toString() + " seconds left", screen.height / 2); + + screen.printCenter(this.userOpts.period + " measurement interval", 40) + screen.printCenter(this.userOpts.measurements.toString() + " measurements left", 60); + screen.printCenter(secondsLeft.toString() + " seconds left", 80); // datalogger.log(datalogger.createCV(this.userOpts.sensorName, this.userOpts.sensorFn())) FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.userOpts.sensorFn()) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index ed819ea..cdcc835 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -7,6 +7,7 @@ namespace microcode { export class FauxDataLogger { static headers: string[] = ["DEFAULT", "DEFAULT"] + static dateStamp = "21/02/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() static data: MetaData[] static numberOfRows: number diff --git a/home.ts b/home.ts index 2016cea..7d3259f 100644 --- a/home.ts +++ b/home.ts @@ -19,14 +19,18 @@ namespace microcode { x: -50, y: 30, onClick: () => { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + // this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - const sOpts: SensorOpts = { - sensorFn: function () {return input.lightLevel()}, + const mOpts: MeasurementOpts = { + sensorFn: function () {return input.lightLevel()}, sensorName: "Light Level", + measurements: 10, + period: 1000 } - // app.pushScene(new MeasurementConfigSelect(app, sOpts)) + + app.pushScene(new DataRecorder(app, mOpts)) + // app.pushScene(new LiveDataViewer(app, sOpts)) }, }) @@ -40,8 +44,14 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) // this.app.pushScene(new Editor(this.app)) + const sOpts: SensorOpts = { + sensorFn: function () {return input.lightLevel()}, + sensorName: "Light", + } + + app.pushScene(new MeasurementConfigSelect(app, sOpts)) }, }) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 0376b63..9f45365 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -14,15 +14,13 @@ namespace microcode { this.sensorFn = userOpts.sensorFn this.sensorName = userOpts.sensorName - const goBack = function() { - app.popScene() - app.pushScene(new Home(app)) - }; - control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, - () => goBack() + () => { + app.popScene() + app.pushScene(new Home(app)) + } ) } diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index 190ca87..ad0c96f 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -1,125 +1,183 @@ namespace microcode { - // interface IDictionary { - // [index: string]: number; - // } - // const MAXIMUMS = {measurements: 1000, period: 10000} as IDictionary; - - export class MeasurementConfigSelect extends CursorSceneWithPriorPage { - // Passed to DataRecorder: - // private sOpts: SensorOpts - // private measurementOpts: IDictionary - // private mode: string = "measurements" - // private btns: Button[] - - // constructor(app: App, sOpts: SensorOpts) { - // super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) - - // this.sOpts = sOpts; - - // // Defaults: - // this.measurementOpts = { - // measurements: 20, - // period: 1000 - // } - // } - - private dataBuffer: number[] = []; - private sensorFn: () => number - private sensorName: string - - constructor(app: App, userOpts: SensorOpts) { - super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) - this.color = 0 - this.sensorFn = userOpts.sensorFn - this.sensorName = userOpts.sensorName - - const goBack = function() { - app.popScene() - app.pushScene(new Home(app)) - }; - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.B.id, - () => goBack() - ) + // How the use + const CONFIG_DELTAS = [ + [1, 10], // Quantity + [1, 10], // Milli-seconds + [1, 5], // Seconds + [1, 5], // Minutes + [1, 5], // Hours + [1, 5] // Days + ] + + const enum GUI_STATE { + WRITING, + DEFAULT, + DONE + } + + export class MeasurementConfigSelect extends Scene { + private guiState: GUI_STATE + private guiRows: string[] + private currentColumn: number + private sensorOpts: SensorOpts + + // Quantity, Milli-seconds, Seconds, Minutes, Hours, Days: + private userSelection = [10, 0, 1, 0, 0, 0] + + constructor(app: App, sensorOpts: SensorOpts) { + super(app, "dataViewer") + + this.guiState = GUI_STATE.DEFAULT + this.guiRows = ["Quantity: ", "Ms: ", "Seconds: ", "Minutes: ", "Hours: ", "Days: "] + this.currentColumn = 0 + + this.sensorOpts = sensorOpts + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + () => { + if (this.guiState === GUI_STATE.DEFAULT) { + this.guiState = GUI_STATE.WRITING + } + + else { + this.guiState = GUI_STATE.DEFAULT + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => { + if (this.guiState === GUI_STATE.DEFAULT) { + this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + this.app.pushScene(new Home(app)) + } + + else { + this.guiState = GUI_STATE.DEFAULT + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + if (this.guiState === GUI_STATE.WRITING) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + CONFIG_DELTAS[this.currentColumn][0], 0) + } + + else { + // Non-negative modulo: + this.currentColumn = (((this.currentColumn - 1) % this.userSelection.length) + this.userSelection.length) % this.userSelection.length + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => { + if (this.guiState === GUI_STATE.WRITING) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - CONFIG_DELTAS[this.currentColumn][0], 0) + } + + else { + // Non-negative modulo: + this.currentColumn = (((this.currentColumn + 1) % this.userSelection.length) + this.userSelection.length) % this.userSelection.length + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.left.id, + () => { + if (this.guiState === GUI_STATE.WRITING) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - CONFIG_DELTAS[this.currentColumn][1], 0) + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.right.id, + () => { + if (this.guiState === GUI_STATE.WRITING) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + CONFIG_DELTAS[this.currentColumn][1], 0) + } + + else if (this.guiState === GUI_STATE.DEFAULT) { + // this.guiState = GUI_STATE.DONE + + this.app.popScene() + this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions())) + } + } + ) + } + + + /** + * Convert the .userSelection data into a single milli-second value, + * turn that into a MeasurementOpts obj + * @returns MeasurementOptions including the sensor information that gained from sensorSelect + */ + private generateUserOptions(): MeasurementOpts { + const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] + + let period: number = 0 + for (let i = 1; i < this.userSelection.length; i++) { + period += this.userSelection[i] * timeConversionTableMs[i - 1] } - // /* override */ startup() { - // super.startup() - // } - - // interface btnData { - // ariaID: string, - // x: number, - // y: number, - // name: string, - // fn: () => number - // } - - // const sensorBtnData: {[id: string]: btnData;} = { - // "led_light_sensor": {ariaID: "led_light_sensor", x: -50, y: 50, name: "Light Level", fn: function () {return input.lightLevel()}}, - // "thermometer": {ariaID: "thermometer", x: 0, y: 50, name: "Temperature", fn: function () {return input.temperature()}}, - // "accelerometer": {ariaID: "accelerometer", x: 50, y: 50, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}} - // } - - // Object.keys(sensorBtnData).forEach( - // key => { - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.FlatWhite, - // icon: key, - // ariaId: sensorBtnData[key].ariaID, - // x: sensorBtnData[key].x, - // y: sensorBtnData[key].y, - // onClick: () => { - // this.app.popScene() - // this.app.pushScene(new DataRecorder(this.app, { - // sensorFn: sensorBtnData[key].fn, - // sensorName: sensorBtnData[key].name, - // measurements: this.measurementOpts.measurements, - // period: this.measurementOpts.period - // })) - // }, - // })) - // } - // ) - // } - - // /* override */ activate() { - // super.activate() - // this.color = 15 - // } - - draw() { + return { + sensorFn: this.sensorOpts.sensorFn, + sensorName: this.sensorOpts.sensorName, + measurements: this.userSelection[0], + period, + } + } + + + update() { Screen.fillRect( Screen.LEFT_EDGE, Screen.TOP_EDGE, Screen.WIDTH, Screen.HEIGHT, - 0xc + 0xC ) + + screen.printCenter("Measurement Settings", 4) - // if (this.mode === "period") { - // screen.printCenter("Measurement period", 20) - // } - - // else if (this.mode === "measurements") { - // screen.printCenter("Number of measurements", 20) - // } - - // let value = "" + this.measurementOpts[this.mode]; - // const textOffset = (screen.width - (font.charWidth * value.length)) / 2 - - // Screen.print( - // value, - // Screen.LEFT_EDGE + textOffset, - // Screen.TOP_EDGE + (screen.height / 2), - // 0xb, - // simage.font8 - // ) - - super.draw() + const rowSize = Screen.HEIGHT / (this.userSelection.length + 1) + let timeAsString; + let rowOffset = 0; + + for (let i = 0; i < 6; i++) { + screen.print(this.guiRows[i], + 35 - (font.charWidth * this.guiRows[i].length) / 2, + 22 + rowOffset + ) + + timeAsString = this.userSelection[i].toString() + screen.print(timeAsString, + 70 - (font.charWidth * timeAsString[i].length) / 2, + 22 + rowOffset + ) + rowOffset += rowSize + } + + // Cursor arrow + screen.print("<--", + 100 - (font.charWidth * "<--".length) / 2, + 22 + (rowSize * this.currentColumn) + ) } } } \ No newline at end of file diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index afdbc8a..b96d67b 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -136,7 +136,7 @@ namespace microcode { const metadata = [ {id: 1, col1: "Save", col2: "1"}, - {id: 2, col1: "Taken", col2: "21/02/2024"}, + {id: 2, col1: "Taken", col2: FauxDataLogger.dateStamp}, {id: 3, col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, {id: 4, col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, ] diff --git a/sensorSelect.ts b/sensorSelect.ts index 94cc975..20069fd 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -77,7 +77,7 @@ namespace microcode { // this.app.pushScene(new LiveDataViewer(app, sOpts)) // } // else { - // this.app.pushScene(new MeasurementConfigSelect(app, sOpts)) + this.app.pushScene(new MeasurementConfigSelect(app, sOpts)) // } }, })) diff --git a/userOptions.ts b/userOptions.ts index 3050abe..c1e1c52 100644 --- a/userOptions.ts +++ b/userOptions.ts @@ -5,6 +5,7 @@ namespace microcode { measurements: number, period: number }; + export type SensorOpts = { sensorFn: () => number, sensorName: string, From 077c2f8e3a5aa4793f9a5b43160dcf19d5ddf0c2 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 21 Feb 2024 12:49:13 +0000 Subject: [PATCH 023/109] bug fixes --- dataRecorder.ts | 30 +++++++++++++++--------------- fauxDatalogger.ts | 4 +++- home.ts | 31 ++++++++++++++++--------------- recordedDataViewer.ts | 25 ++++++++++++++----------- sensorSelect.ts | 10 +++++----- 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index fe669aa..f027fb1 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -2,13 +2,13 @@ namespace microcode { export class DataRecorder extends Scene { private fauxDatalogger: FauxDataLogger private loggingStartTime: number - private userOpts: MeasurementOpts + private measurementOpts: MeasurementOpts - constructor(app: App, userOpts: MeasurementOpts) { + constructor(app: App, measurementOpts: MeasurementOpts) { super(app, "dataRecorder") - this.userOpts = userOpts - this.fauxDatalogger = new FauxDataLogger(["Milli-\nseconds", userOpts.sensorName]) + this.measurementOpts = measurementOpts + this.fauxDatalogger = new FauxDataLogger(["Milli-\nseconds", measurementOpts.sensorName], measurementOpts) this.loggingStartTime = input.runningTime() @@ -32,24 +32,24 @@ namespace microcode { 0xc ) - if (this.userOpts.measurements === 0) { - screen.printCenter("Data Logging Complete.", screen.height / 2); - screen.printCenter("Press B to back out.", (screen.height / 2) + 10); + if (this.measurementOpts.measurements === 0) { + screen.printCenter("Data Logging Complete.", (screen.height / 2) - 10); + screen.printCenter("Press B to back out.", screen.height / 2); } else { - const secondsLeft: number = (this.userOpts.measurements * this.userOpts.period) / 1000 + const secondsLeft: number = (this.measurementOpts.measurements * this.measurementOpts.period) / 1000 screen.printCenter("Recording data...", 10); - screen.printCenter(this.userOpts.period + " measurement interval", 40) - screen.printCenter(this.userOpts.measurements.toString() + " measurements left", 60); - screen.printCenter(secondsLeft.toString() + " seconds left", 80); + screen.printCenter(this.measurementOpts.period / 1000 + " second period", 45) + screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); + screen.printCenter(secondsLeft.toString() + " seconds left", 85); - // datalogger.log(datalogger.createCV(this.userOpts.sensorName, this.userOpts.sensorFn())) - FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.userOpts.sensorFn()) + // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) + FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.measurementOpts.sensorFn()) - this.userOpts.measurements -= 1 - basic.pause(this.userOpts.period) + this.measurementOpts.measurements -= 1 + basic.pause(this.measurementOpts.period) } } } diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index cdcc835..1ddaec8 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -10,11 +10,13 @@ namespace microcode { static dateStamp = "21/02/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() static data: MetaData[] static numberOfRows: number + static measurementOptions: MeasurementOpts - constructor(headers: string[]) { + constructor(headers: string[], mOpts: MeasurementOpts) { FauxDataLogger.headers = headers FauxDataLogger.data = [] FauxDataLogger.numberOfRows = 0 + FauxDataLogger.measurementOptions = mOpts } public static log(key: string, value: number) { diff --git a/home.ts b/home.ts index 7d3259f..27943fa 100644 --- a/home.ts +++ b/home.ts @@ -19,17 +19,17 @@ namespace microcode { x: -50, y: 30, onClick: () => { - // this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + this.app.popScene() + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - const mOpts: MeasurementOpts = { - sensorFn: function () {return input.lightLevel()}, - sensorName: "Light Level", - measurements: 10, - period: 1000 - } + // const mOpts: MeasurementOpts = { + // sensorFn: function () {return input.lightLevel()}, + // sensorName: "Light Level", + // measurements: 10, + // period: 1000 + // } - app.pushScene(new DataRecorder(app, mOpts)) + // app.pushScene(new DataRecorder(app, mOpts)) // app.pushScene(new LiveDataViewer(app, sOpts)) }, @@ -44,14 +44,15 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + // this.app.pushScene(new Editor(this.app)) - const sOpts: SensorOpts = { - sensorFn: function () {return input.lightLevel()}, - sensorName: "Light", - } + // const sOpts: SensorOpts = { + // sensorFn: function () {return input.lightLevel()}, + // sensorName: "Light", + // } - app.pushScene(new MeasurementConfigSelect(app, sOpts)) + // app.pushScene(new MeasurementConfigSelect(app, sOpts)) }, }) diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index b96d67b..91e8c14 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -64,8 +64,8 @@ namespace microcode { } draw_grid() { - const colBufferSize = Screen.WIDTH / 2 //FauxDataLogger.headers.length - const rowBufferSize = Screen.HEIGHT / 4 // Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length + const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( @@ -135,13 +135,15 @@ namespace microcode { } const metadata = [ - {id: 1, col1: "Save", col2: "1"}, - {id: 2, col1: "Taken", col2: FauxDataLogger.dateStamp}, - {id: 3, col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, - {id: 4, col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col1: "Save", col2: "1"}, + {col1: "Taken", col2: FauxDataLogger.dateStamp}, + {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, + {col1: "Sensor", col2: FauxDataLogger.measurementOptions.sensorName}, + {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, ] - for (let i = this.scrollOffset; i < 4; i++) { + for (let i = this.scrollOffset; i < metadata.length; i++) { Screen.print( metadata[i].col1, Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[i].col1.length) / 2), @@ -167,9 +169,6 @@ namespace microcode { case DISPLAY_MODE.DATA_VIEW: this.draw_grid() - - const colSizeBuffer = Screen.WIDTH / 2 - const rowDeltaBuffer = Screen.HEIGHT / 4 // const data = [ // {id: 1, col1: "1", col2: "1"}, @@ -177,10 +176,14 @@ namespace microcode { // {id: 3, col1: "3", col2: "3"}, // {id: 4, col1: "4", col2: "4"}, // ] + // const colSizeBuffer = Screen.WIDTH / 2 + // const rowDeltaBuffer = Screen.HEIGHT / 4 + + const colSizeBuffer = Screen.WIDTH / FauxDataLogger.headers.length + const rowDeltaBuffer = Screen.HEIGHT / FauxDataLogger.numberOfRows const data = FauxDataLogger.data - // FauxDataLogger.numberOfRows = 4 for (let i = this.scrollOffset; i < FauxDataLogger.numberOfRows; i++) { Screen.print( diff --git a/sensorSelect.ts b/sensorSelect.ts index 20069fd..8943b06 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -73,12 +73,12 @@ namespace microcode { } this.app.popScene() - // if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - // this.app.pushScene(new LiveDataViewer(app, sOpts)) - // } - // else { + if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { + this.app.pushScene(new LiveDataViewer(app, sOpts)) + } + else { this.app.pushScene(new MeasurementConfigSelect(app, sOpts)) - // } + } }, })) } From 721537364f1b11191ef1bcbff1f1a806fe2329f3 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 21 Feb 2024 14:10:06 +0000 Subject: [PATCH 024/109] LiveData View multiple sensor viewing --- home.ts | 5 ++- liveDataViewer.ts | 102 ++++++++++++++++++++++++++++++++++++---------- sceneFactory.ts | 4 +- sensorSelect.ts | 3 +- sensors.ts | 59 +++++++++++++++++++++++++++ userOptions.ts | 5 --- 6 files changed, 145 insertions(+), 33 deletions(-) create mode 100644 sensors.ts diff --git a/home.ts b/home.ts index 27943fa..62095a1 100644 --- a/home.ts +++ b/home.ts @@ -20,8 +20,9 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + this.app.pushScene(new LiveDataViewer(app, [new LightSensor(), new TemperatureSensor()])) + // const mOpts: MeasurementOpts = { // sensorFn: function () {return input.lightLevel()}, // sensorName: "Light Level", diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 9f45365..e6404eb 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -2,17 +2,28 @@ namespace microcode { const WIDTH_BUFFER = 16; const HEIGHT_BUFFER = 12; + enum GUI_STATE { + PLOTTING, + SENSOR_INFORMATION + } + export class LiveDataViewer extends Scene { - private dataBuffer: number[] = []; + private dataBuffers: number[][]; private bufferLimit = screen.width - (2 * WIDTH_BUFFER); - private sensorFn: () => number - private sensorName: string + private guiState: GUI_STATE - constructor(app: App, userOpts: SensorOpts) { + private sensors: Sensor[] + + constructor(app: App, sensors: Sensor[]) { super(app, "liveDataViewer") this.color = 0 - this.sensorFn = userOpts.sensorFn - this.sensorName = userOpts.sensorName + this.guiState = GUI_STATE.PLOTTING + + this.sensors = sensors + this.dataBuffers = [] + for (let i = 0; i < this.sensors.length; i++) { + this.dataBuffers.push([]) + } control.onEvent( ControllerButtonEvent.Pressed, @@ -22,39 +33,86 @@ namespace microcode { app.pushScene(new Home(app)) } ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + if (this.guiState === GUI_STATE.PLOTTING) { + this.guiState = GUI_STATE.SENSOR_INFORMATION + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => { + if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { + this.guiState = GUI_STATE.PLOTTING + } + } + ) } update() { - // Pre-process and convert lightlevel into a y value; relative to screen-height - let light_level = this.sensorFn() / 255; - let y = Math.round(screen.height - (light_level * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER + screen.fill(this.color); + + if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { + screen.printCenter("Press DOWN for plot", 110) - // Buffer management: - if (this.dataBuffer.length >= this.bufferLimit) { - this.dataBuffer.shift(); + let colour = 8; + + for (let i = 0; i < this.sensors.length; i++) { + screen.print(this.sensors[i].getName() + " as", 10, 25 + (i * 20)) + screen.fillRect( + 130, + 25 + (i * 20), + 10, + 10, + colour + ) + colour = (colour + 1) % 15 + } } - this.dataBuffer.push(y); - // Draw: - screen.fill(this.color); - this.plot() + else { + for (let i = 0; i < this.sensors.length; i++) { + let normalisedOutput = this.sensors[i].normalise(); + let y = Math.round(screen.height - (normalisedOutput * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER - basic.pause(100); + // Buffer management: + if (this.dataBuffers[i].length >= this.bufferLimit) { + this.dataBuffers[i].shift(); + } + this.dataBuffers[i].push(y); + } + + // Draw: + this.plot() + + basic.pause(100); + } } /** * Display mode for plotting all incoming data on y axis - * Presumes pre-processed this.dataBuffer; y values relative to screen.height + * Presumes pre-processed this.dataBuffers; y values relative to screen.height * Bound to Microbit button A */ private plot() { - screen.printCenter(this.sensorName, 10) + screen.printCenter("Press UP for info", 5) this.draw_axes(); const start = WIDTH_BUFFER + 2; - for (let i = 0; i < this.dataBuffer.length - 1; i++) { - screen.drawLine(start + i, this.dataBuffer[i], start + i - 1, this.dataBuffer[i + 1], 9); - } + let colour = 8; + + this.dataBuffers.forEach(function(dataBuffer) { + for (let i = 0; i < dataBuffer.length - 1; i++) { + screen.drawLine(start + i, dataBuffer[i], start + i - 1, dataBuffer[i + 1], colour); + } + colour = (colour + 1) % 15 + }) } // Display helper: diff --git a/sceneFactory.ts b/sceneFactory.ts index 15aba23..f217f94 100644 --- a/sceneFactory.ts +++ b/sceneFactory.ts @@ -11,7 +11,7 @@ namespace microcode { export function generateScene(sceneEnum: CursorSceneEnum, app: App, mOpts?: MeasurementOpts, sOpts?: SensorOpts, nextScene?: CursorSceneEnum) { switch (sceneEnum) { case CursorSceneEnum.LiveDataViewer: - return new LiveDataViewer(app, sOpts) + return new LiveDataViewer(app, [new LightSensor, new TemperatureSensor]) case CursorSceneEnum.SensorSelect: return new SensorSelect(app, nextScene) @@ -23,7 +23,7 @@ namespace microcode { return new DataRecorder(app, mOpts) default: - return new LiveDataViewer(app, sOpts); + return new LiveDataViewer(app, [new LightSensor, new TemperatureSensor]); } } } \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index 8943b06..51a8bad 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -56,7 +56,6 @@ namespace microcode { // "finger_press": {ariaID: "f", x: 50, y: 50, name: "Pin Press", fn: function () {if(input.logoIsPressed()) {return 255} return 0}} } - Object.keys(sensorBtnData).forEach( key => { this.btns.push(new Button({ @@ -74,7 +73,7 @@ namespace microcode { this.app.popScene() if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, sOpts)) + this.app.pushScene(new LiveDataViewer(app, [new LightSensor, new TemperatureSensor])) } else { this.app.pushScene(new MeasurementConfigSelect(app, sOpts)) diff --git a/sensors.ts b/sensors.ts new file mode 100644 index 0000000..61bca43 --- /dev/null +++ b/sensors.ts @@ -0,0 +1,59 @@ + +namespace microcode { + export type SensorOpts = { + sensorFn: () => number, + sensorName: string, + }; + + + export interface Sensor { + read(): number; + normalise(): number; + getName(): string; + } + + + export class LightSensor implements Sensor { + private sensorFn: () => number + private name: string + + constructor() { + this.sensorFn = function () {return input.lightLevel()} + this.name = "Light" + } + + read(): number { + return this.sensorFn() + } + + normalise(): number { + return this.sensorFn() / 255 + } + + getName() { + return this.name + } + } + + export class TemperatureSensor implements Sensor { + private sensorFn: () => number + private name: string + + constructor() { + this.sensorFn = function () {return input.temperature()} + this.name = "Temperature" + } + + read(): number { + return this.sensorFn() + } + + normalise(): number { + return this.sensorFn() / 100 + } + + getName() { + return this.name + } + } +} \ No newline at end of file diff --git a/userOptions.ts b/userOptions.ts index c1e1c52..80ad822 100644 --- a/userOptions.ts +++ b/userOptions.ts @@ -5,11 +5,6 @@ namespace microcode { measurements: number, period: number }; - - export type SensorOpts = { - sensorFn: () => number, - sensorName: string, - }; // "files": [ // "protocol.ts", From 0ff45de5252597aa0923c6fc0bcff354ae3758b1 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 21 Feb 2024 17:06:20 +0000 Subject: [PATCH 025/109] Demo'd prototype 4 --- dataRecorder.ts | 79 ++++++++++++++++++++-- fauxDatalogger.ts | 18 +++-- home.ts | 6 +- measurementConfigSelect.ts | 6 +- recordedDataViewer.ts | 59 ++++++++++++----- sceneFactory.ts | 2 +- sensorSelect.ts | 131 +++++++++++++++++++++++++++++-------- sensors.ts | 47 +++++++++---- tooltips.ts | 3 + 9 files changed, 277 insertions(+), 74 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index f027fb1..a38c25d 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,17 +1,82 @@ +// namespace microcode { +// export class DataRecorder extends Scene { +// private fauxDatalogger: FauxDataLogger +// private loggingStartTime: number +// private measurementOpts: MeasurementOpts + +// constructor(app: App, measurementOpts: MeasurementOpts) { +// super(app, "dataRecorder") + +// this.measurementOpts = measurementOpts +// this.fauxDatalogger = new FauxDataLogger(["Ms", measurementOpts.sensorName], measurementOpts) + +// this.loggingStartTime = input.runningTime() + +// // Go Back: +// control.onEvent( +// ControllerButtonEvent.Pressed, +// controller.B.id, +// () => { +// this.app.popScene() +// this.app.pushScene(new Home(this.app)) +// } +// ) +// } + +// update() { +// Screen.fillRect( +// Screen.LEFT_EDGE, +// Screen.TOP_EDGE, +// Screen.WIDTH, +// Screen.HEIGHT, +// 0xc +// ) + +// if (this.measurementOpts.measurements === 0) { +// screen.printCenter("Data Logging Complete.", (screen.height / 2) - 10); +// screen.printCenter("Press B to back out.", screen.height / 2); +// } + +// else { +// const secondsLeft: number = (this.measurementOpts.measurements * this.measurementOpts.period) / 1000 +// screen.printCenter("Recording data...", 10); + +// screen.printCenter(this.measurementOpts.period / 1000 + " second period", 45) +// screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); +// screen.printCenter(secondsLeft.toString() + " seconds left", 85); + +// // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) +// FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.measurementOpts.sensorFn()) + +// this.measurementOpts.measurements -= 1 +// basic.pause(this.measurementOpts.period) +// } +// } +// } +// } + namespace microcode { export class DataRecorder extends Scene { private fauxDatalogger: FauxDataLogger private loggingStartTime: number private measurementOpts: MeasurementOpts + private sensors: Sensor[] - constructor(app: App, measurementOpts: MeasurementOpts) { + constructor(app: App, measurementOpts: MeasurementOpts, sensors: Sensor[]) { super(app, "dataRecorder") - this.measurementOpts = measurementOpts - this.fauxDatalogger = new FauxDataLogger(["Milli-\nseconds", measurementOpts.sensorName], measurementOpts) + let headers: string[] = ["Ms"] + sensors.forEach(function(sensor) { + headers.push(sensor.getName()) + }) + + this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts) this.loggingStartTime = input.runningTime() + this.measurementOpts = measurementOpts + this.sensors = sensors + // Go Back: control.onEvent( ControllerButtonEvent.Pressed, @@ -46,7 +111,13 @@ namespace microcode { screen.printCenter(secondsLeft.toString() + " seconds left", 85); // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) - FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.measurementOpts.sensorFn()) + + let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] + for (let i = 0; i < this.sensors.length; i++) { + data.push(this.sensors[i].read().toString()) + } + + FauxDataLogger.log(data) this.measurementOpts.measurements -= 1 basic.pause(this.measurementOpts.period) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 1ddaec8..1a317a9 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -1,29 +1,27 @@ namespace microcode { interface MetaData { id: number, - col1: string, - col2: string + data: string[] } export class FauxDataLogger { - static headers: string[] = ["DEFAULT", "DEFAULT"] + static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] static dateStamp = "21/02/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() - static data: MetaData[] + static values: MetaData[] static numberOfRows: number static measurementOptions: MeasurementOpts constructor(headers: string[], mOpts: MeasurementOpts) { FauxDataLogger.headers = headers - FauxDataLogger.data = [] + FauxDataLogger.values = [] FauxDataLogger.numberOfRows = 0 FauxDataLogger.measurementOptions = mOpts } - public static log(key: string, value: number) { - FauxDataLogger.data.push({ - id: this.data.length, - col1: key, - col2: value.toString() + public static log(data: string[]) { + FauxDataLogger.values.push({ + id: this.values.length, + data }) FauxDataLogger.numberOfRows += 1 } diff --git a/home.ts b/home.ts index 62095a1..5db0748 100644 --- a/home.ts +++ b/home.ts @@ -20,13 +20,13 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - this.app.pushScene(new LiveDataViewer(app, [new LightSensor(), new TemperatureSensor()])) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + // this.app.pushScene(new LiveDataViewer(app, [new LightSensor(), new TemperatureSensor()])) // const mOpts: MeasurementOpts = { // sensorFn: function () {return input.lightLevel()}, // sensorName: "Light Level", - // measurements: 10, + // measurements: 10,` // period: 1000 // } diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index ad0c96f..182d434 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -20,17 +20,19 @@ namespace microcode { private guiRows: string[] private currentColumn: number private sensorOpts: SensorOpts + private sensors: Sensor[] // Quantity, Milli-seconds, Seconds, Minutes, Hours, Days: private userSelection = [10, 0, 1, 0, 0, 0] - constructor(app: App, sensorOpts: SensorOpts) { + constructor(app: App, sensorOpts: SensorOpts, sensors: Sensor[]) { super(app, "dataViewer") this.guiState = GUI_STATE.DEFAULT this.guiRows = ["Quantity: ", "Ms: ", "Seconds: ", "Minutes: ", "Hours: ", "Days: "] this.currentColumn = 0 + this.sensors = sensors this.sensorOpts = sensorOpts control.onEvent( @@ -115,7 +117,7 @@ namespace microcode { // this.guiState = GUI_STATE.DONE this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions())) + this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions(), sensors)) } } ) diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 91e8c14..4875c86 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -134,14 +134,31 @@ namespace microcode { ) } - const metadata = [ - {col1: "Save", col2: "1"}, - {col1: "Taken", col2: FauxDataLogger.dateStamp}, - {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, - {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, - {col1: "Sensor", col2: FauxDataLogger.measurementOptions.sensorName}, - {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, - ] + + let metadata = [] + + if (FauxDataLogger.headers.length == 2) { + metadata = [ + {col1: "Save", col2: "1"}, + {col1: "Taken", col2: FauxDataLogger.dateStamp}, + {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, + {col1: "Col1: Time", col2: FauxDataLogger.headers[0]}, + {col1: "Col2: Sensor", col2: FauxDataLogger.headers[1]}, + {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, + ] + } else { + metadata = [ + {col1: "Save", col2: "1"}, + {col2: "Taken", col2: FauxDataLogger.dateStamp}, + {col3: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col4: "Columns", col2: FauxDataLogger.headers.length.toString()}, + {col5: "Col1: Time", col2: FauxDataLogger.headers[0]}, + {col6: "Col2: Sensor", col2: FauxDataLogger.headers[1]}, + {col7: "Col3: Sensor", col2: FauxDataLogger.headers[2]}, + {col8: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, + ] + } for (let i = this.scrollOffset; i < metadata.length; i++) { Screen.print( @@ -182,25 +199,37 @@ namespace microcode { const colSizeBuffer = Screen.WIDTH / FauxDataLogger.headers.length const rowDeltaBuffer = Screen.HEIGHT / FauxDataLogger.numberOfRows - - const data = FauxDataLogger.data - + let colOffset = 0 + for (let i = this.scrollOffset; i < FauxDataLogger.numberOfRows; i++) { + const data = FauxDataLogger.values[i].data; + Screen.print( - data[i].col1, - Screen.LEFT_EDGE + (colSizeBuffer / 2) - ((font.charWidth * data[i].col1.length) / 2), + data[0], + Screen.LEFT_EDGE + (colSizeBuffer / 2) - ((font.charWidth * data[0].length) / 2), Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, 0xb, simage.font8 ) Screen.print( - data[i].col2, - Screen.LEFT_EDGE + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[i].col2.length) / 2), + data[1], + Screen.LEFT_EDGE + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[1].length) / 2), Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, 0xb, simage.font8 ) + + + if (FauxDataLogger.headers.length > 2) { + Screen.print( + data[2], + Screen.LEFT_EDGE + colSizeBuffer + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[2].length) / 2), + Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, + 0xb, + simage.font8 + ) + } rowOffset += rowDeltaBuffer } break; diff --git a/sceneFactory.ts b/sceneFactory.ts index f217f94..a6d3c42 100644 --- a/sceneFactory.ts +++ b/sceneFactory.ts @@ -20,7 +20,7 @@ namespace microcode { // return new MeasurementConfigSelect(app, sOpts) case CursorSceneEnum.RecordData: - return new DataRecorder(app, mOpts) + return new DataRecorder(app, mOpts, [new LightSensor, new TemperatureSensor]) default: return new LiveDataViewer(app, [new LightSensor, new TemperatureSensor]); diff --git a/sensorSelect.ts b/sensorSelect.ts index 51a8bad..713362f 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -1,12 +1,15 @@ namespace microcode { export class SensorSelect extends CursorSceneWithPriorPage { private btns: Button[] + private selectedSensors: Sensor[] private nextSceneEnum: CursorSceneEnum constructor(app: App, nextSceneEnum: CursorSceneEnum) { super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) this.btns = [] + this.selectedSensors = [] this.nextSceneEnum = nextSceneEnum + } /* override */ startup() { @@ -18,6 +21,7 @@ namespace microcode { y: number, name: string, fn: () => number + sensor: Sensor, } /** @@ -43,9 +47,21 @@ namespace microcode { // "disk2": {ariaID: "disk2", x: 0, y: -25, name: "disk2", fn: function () {return input.soundLevel()}}, // "disk3": {ariaID: "disk3", x: 50, y: -25, name: "disk3", fn: function () {return input.magneticForce(Dimension.X)}}, - "led_light_sensor": {ariaID: "led_light_sensor", x: -50, y: 30, name: "Light Level", fn: function () {return input.lightLevel()}}, - "thermometer": {ariaID: "thermometer", x: 0, y: 30, name: "Temperature", fn: function () {return input.temperature()}}, - "accelerometer": {ariaID: "accelerometer", x: 50, y: 30, name: "Accelerometer", fn: function () {return input.acceleration(Dimension.X)}} + "led_light_sensor": {ariaID: "led_light_sensor", x: -50, y: 30, + name: "Light Level", + fn: function () {return input.lightLevel()}, + sensor: new LightSensor() + }, + "thermometer": {ariaID: "thermometer", x: 0, y: 30, + name: "Temperature", + fn: function () {return input.temperature()}, + sensor: new TemperatureSensor() + }, + "touch pins": {ariaID: "accelerometer", x: 50, y: 30, + name: "Pin", + fn: function () {return pinPressFunction(TouchPin.P0)}, + sensor: new Pins(TouchPin.P0) + } // "a": {ariaID: "a", x: -50, y: 25, name: "Light\nLevel", fn: function() {return pinPressFunction(TouchPin.P0)}}, // "b": {ariaID: "b", x: 0, y: 25, name: "Temperature", fn: function () {return pinPressFunction(TouchPin.P1)}}, @@ -56,32 +72,91 @@ namespace microcode { // "finger_press": {ariaID: "f", x: 50, y: 50, name: "Pin Press", fn: function () {if(input.logoIsPressed()) {return 255} return 0}} } - Object.keys(sensorBtnData).forEach( - key => { - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: key, - ariaId: sensorBtnData[key].ariaID, - x: sensorBtnData[key].x, - y: sensorBtnData[key].y, - onClick: () => { - const sOpts: SensorOpts = { - sensorFn: sensorBtnData[key].fn, - sensorName: sensorBtnData[key].name, - } - - this.app.popScene() - if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, [new LightSensor, new TemperatureSensor])) - } - else { - this.app.pushScene(new MeasurementConfigSelect(app, sOpts)) - } - }, - })) + // Object.keys(sensorBtnData).forEach( + // key => { + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.FlatWhite, + // icon: key, + // ariaId: sensorBtnData[key].ariaID, + // x: sensorBtnData[key].x, + // y: sensorBtnData[key].y, + // onClick: () => { + // this.selectedSensors.push(sensorBtnData[key].sensor) + // }, + // })) + // } + // ) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "led_light_sensor", + ariaId: "led_light_sensor", + x: -50, + y: 30, + onClick: () => { + this.selectedSensors.push(new LightSensor()) } - ) + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "thermometer", + ariaId: "thermometer", + x: 0, + y: 30, + onClick: () => { + this.selectedSensors.push(new TemperatureSensor()) + } + })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "moveTiltLeft", + // ariaId: "Pins", + // x: 0, + // y: 30, + // onClick: () => { + // this.selectedSensors.push(new Pins(TouchPin.P0)) + // } + // })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "disk1", + ariaId: "Done", + x: 50, + y: 30, + onClick: () => { + if (this.selectedSensors.length === 0) { + return + } + + // const sOpts: SensorOpts = { + // sensorFn: this.selectedSensors[0].getFn(), + // sensorName: this.selectedSensors[0].getName(), + // } + + const sOpts: SensorOpts = { + sensorFn: this.selectedSensors[0].getFn(), + sensorName: this.selectedSensors[0].getName(), + } + + this.app.popScene() + + if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { + this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) + } + + else { + this.app.pushScene(new MeasurementConfigSelect(app, sOpts, this.selectedSensors)) + } + } + })) this.navigator.addButtons(this.btns) } diff --git a/sensors.ts b/sensors.ts index 61bca43..55c36d4 100644 --- a/sensors.ts +++ b/sensors.ts @@ -5,17 +5,16 @@ namespace microcode { sensorName: string, }; - export interface Sensor { read(): number; normalise(): number; getName(): string; + getFn(): () => number } - export class LightSensor implements Sensor { - private sensorFn: () => number - private name: string + sensorFn: () => number + name: string constructor() { this.sensorFn = function () {return input.lightLevel()} @@ -30,14 +29,13 @@ namespace microcode { return this.sensorFn() / 255 } - getName() { - return this.name - } + getName() {return this.name} + getFn() {return this.sensorFn} } export class TemperatureSensor implements Sensor { - private sensorFn: () => number - private name: string + sensorFn: () => number + name: string constructor() { this.sensorFn = function () {return input.temperature()} @@ -52,8 +50,35 @@ namespace microcode { return this.sensorFn() / 100 } - getName() { - return this.name + getName() {return this.name} + getFn() {return this.sensorFn} + } + + + export class Pins implements Sensor { + sensorFn: () => number + name: string + + constructor(pin: TouchPin) { + this.sensorFn = function () { + let res: number = 0 + input.onPinPressed(pin, function () { + res = 1 + }) + return res + } + this.name = "pin" + } + + read(): number { + return this.sensorFn() + } + + normalise(): number { + return this.sensorFn() } + + getName() {return this.name} + getFn() {return this.sensorFn} } } \ No newline at end of file diff --git a/tooltips.ts b/tooltips.ts index aaa8086..9d677e4 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -162,6 +162,9 @@ namespace microcode { // icons do not yet exist: else if (id == "Record") res = "Record" else if (id == "View") res = "View" + else if (id == "Done") res = "Done" + else if (id == "Pins") res = "Pins" + return res } } \ No newline at end of file From 18819bc8e5efd44c84de46b95f3a340f778b1d0e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 27 Feb 2024 20:47:25 +0000 Subject: [PATCH 026/109] Tiding code and adding documentation. --- dataRecorder.ts | 10 +- home.ts | 20 ---- liveDataViewer.ts | 4 +- measurementConfigSelect.ts | 13 +-- pxt.json | 9 +- recordedDataViewer.ts | 14 +-- sceneFactory.ts | 5 +- sensorSelect.ts | 191 ++++++++++++------------------------- sensors.ts | 145 +++++++++++++++++++--------- userOptions.ts | 43 +-------- 10 files changed, 192 insertions(+), 262 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index a38c25d..932a1dd 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -68,7 +68,7 @@ namespace microcode { let headers: string[] = ["Ms"] sensors.forEach(function(sensor) { - headers.push(sensor.getName()) + headers.push(sensor.name) }) this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts) @@ -106,15 +106,17 @@ namespace microcode { const secondsLeft: number = (this.measurementOpts.measurements * this.measurementOpts.period) / 1000 screen.printCenter("Recording data...", 10); - screen.printCenter(this.measurementOpts.period / 1000 + " second period", 45) + screen.printCenter(this.measurementOpts.period / 1000 + " second period", 45) screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); screen.printCenter(secondsLeft.toString() + " seconds left", 85); + // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) - let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] + // Collect the data to log: + let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] // Log time for (let i = 0; i < this.sensors.length; i++) { - data.push(this.sensors[i].read().toString()) + data.push(this.sensors[i].getReading().toString()) } FauxDataLogger.log(data) diff --git a/home.ts b/home.ts index 5db0748..6138146 100644 --- a/home.ts +++ b/home.ts @@ -21,18 +21,6 @@ namespace microcode { onClick: () => { this.app.popScene() this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - // this.app.pushScene(new LiveDataViewer(app, [new LightSensor(), new TemperatureSensor()])) - - // const mOpts: MeasurementOpts = { - // sensorFn: function () {return input.lightLevel()}, - // sensorName: "Light Level", - // measurements: 10,` - // period: 1000 - // } - - // app.pushScene(new DataRecorder(app, mOpts)) - - // app.pushScene(new LiveDataViewer(app, sOpts)) }, }) @@ -46,14 +34,6 @@ namespace microcode { onClick: () => { this.app.popScene() this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - - // this.app.pushScene(new Editor(this.app)) - // const sOpts: SensorOpts = { - // sensorFn: function () {return input.lightLevel()}, - // sensorName: "Light", - // } - - // app.pushScene(new MeasurementConfigSelect(app, sOpts)) }, }) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index e6404eb..e7bb4ce 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -64,7 +64,7 @@ namespace microcode { let colour = 8; for (let i = 0; i < this.sensors.length; i++) { - screen.print(this.sensors[i].getName() + " as", 10, 25 + (i * 20)) + screen.print(this.sensors[i].name + " as", 10, 25 + (i * 20)) screen.fillRect( 130, 25 + (i * 20), @@ -78,7 +78,7 @@ namespace microcode { else { for (let i = 0; i < this.sensors.length; i++) { - let normalisedOutput = this.sensors[i].normalise(); + let normalisedOutput = this.sensors[i].getNormalisedReading(); let y = Math.round(screen.height - (normalisedOutput * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER // Buffer management: diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index 182d434..58dc669 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -19,21 +19,19 @@ namespace microcode { private guiState: GUI_STATE private guiRows: string[] private currentColumn: number - private sensorOpts: SensorOpts - private sensors: Sensor[] + private selectedSensors: Sensor[] // Quantity, Milli-seconds, Seconds, Minutes, Hours, Days: private userSelection = [10, 0, 1, 0, 0, 0] - constructor(app: App, sensorOpts: SensorOpts, sensors: Sensor[]) { + constructor(app: App, selectedSensors: Sensor[]) { super(app, "dataViewer") this.guiState = GUI_STATE.DEFAULT this.guiRows = ["Quantity: ", "Ms: ", "Seconds: ", "Minutes: ", "Hours: ", "Days: "] this.currentColumn = 0 - this.sensors = sensors - this.sensorOpts = sensorOpts + this.selectedSensors = selectedSensors control.onEvent( ControllerButtonEvent.Pressed, @@ -117,7 +115,7 @@ namespace microcode { // this.guiState = GUI_STATE.DONE this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions(), sensors)) + this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions(), this.selectedSensors)) } } ) @@ -138,8 +136,7 @@ namespace microcode { } return { - sensorFn: this.sensorOpts.sensorFn, - sensorName: this.sensorOpts.sensorName, + sensor: this.selectedSensors[0], // Does not grant multiple sensors measurements: this.userSelection[0], period, } diff --git a/pxt.json b/pxt.json index 365dafd..e6de6d9 100644 --- a/pxt.json +++ b/pxt.json @@ -39,14 +39,21 @@ "tooltips.ts", "utils.ts", "jacs.ts", + "ruleEditor.ts", + "editor.ts", + "samples.ts", + "liveDataViewer.ts", "dataRecorder.ts", "recordedDataViewer.ts", "sensorSelect.ts", "measurementConfigSelect.ts", "fauxDatalogger.ts", - "sceneFactory.ts" + "sceneFactory.ts", + "userOptions.ts", + "sensors.ts" ], + "testFiles": [], "targetVersions": { "target": "6.1.10", diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 4875c86..3c4e837 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -150,13 +150,13 @@ namespace microcode { } else { metadata = [ {col1: "Save", col2: "1"}, - {col2: "Taken", col2: FauxDataLogger.dateStamp}, - {col3: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, - {col4: "Columns", col2: FauxDataLogger.headers.length.toString()}, - {col5: "Col1: Time", col2: FauxDataLogger.headers[0]}, - {col6: "Col2: Sensor", col2: FauxDataLogger.headers[1]}, - {col7: "Col3: Sensor", col2: FauxDataLogger.headers[2]}, - {col8: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, + {col1: "Taken", col2: FauxDataLogger.dateStamp}, + {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, + {col1: "Col1: Time", col2: FauxDataLogger.headers[0]}, + {col1: "Col2: Sensor", col2: FauxDataLogger.headers[1]}, + {col1: "Col3: Sensor", col2: FauxDataLogger.headers[2]}, + {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, ] } diff --git a/sceneFactory.ts b/sceneFactory.ts index a6d3c42..34dd1c5 100644 --- a/sceneFactory.ts +++ b/sceneFactory.ts @@ -6,9 +6,8 @@ namespace microcode { RecordData, } - export function generateScene(sceneEnum: CursorSceneEnum, app: App, opts: MeasurementOpts): any; - export function generateScene(sceneEnum: CursorSceneEnum, app: App, opts: SensorOpts): any; - export function generateScene(sceneEnum: CursorSceneEnum, app: App, mOpts?: MeasurementOpts, sOpts?: SensorOpts, nextScene?: CursorSceneEnum) { + + export function generateScene(sceneEnum: CursorSceneEnum, app: App, mOpts?: MeasurementOpts, nextScene?: CursorSceneEnum) { switch (sceneEnum) { case CursorSceneEnum.LiveDataViewer: return new LiveDataViewer(app, [new LightSensor, new TemperatureSensor]) diff --git a/sensorSelect.ts b/sensorSelect.ts index 713362f..05c9285 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -9,7 +9,6 @@ namespace microcode { this.btns = [] this.selectedSensors = [] this.nextSceneEnum = nextSceneEnum - } /* override */ startup() { @@ -19,145 +18,81 @@ namespace microcode { ariaID: string, x: number, y: number, - name: string, - fn: () => number sensor: Sensor, } - /** - * Generalisation for touch pin events - * Necessary since the inner function of input.onPinPressed(pin fn(){}) is () => void; where () => number is required - * @param pin TouchPin.P0, TouchPin.P1, TouchPin.P2 - * @returns - */ - const pinPressFunction = function(pin: TouchPin): number { - let res: number = 0 - input.onPinPressed(TouchPin.P0, function () { - res = 1 - }) - return res - } - - /** * Issue with consistently being able to load this app when there are > 3 buttons */ - const sensorBtnData: {[id: string]: btnData;} = { - // "disk1": {ariaID: "disk1", x: -50, y: -25, name: "disk1", fn: function () {return input.compassHeading()}}, - // "disk2": {ariaID: "disk2", x: 0, y: -25, name: "disk2", fn: function () {return input.soundLevel()}}, - // "disk3": {ariaID: "disk3", x: 50, y: -25, name: "disk3", fn: function () {return input.magneticForce(Dimension.X)}}, - - "led_light_sensor": {ariaID: "led_light_sensor", x: -50, y: 30, - name: "Light Level", - fn: function () {return input.lightLevel()}, - sensor: new LightSensor() - }, - "thermometer": {ariaID: "thermometer", x: 0, y: 30, - name: "Temperature", - fn: function () {return input.temperature()}, - sensor: new TemperatureSensor() - }, - "touch pins": {ariaID: "accelerometer", x: 50, y: 30, - name: "Pin", - fn: function () {return pinPressFunction(TouchPin.P0)}, - sensor: new Pins(TouchPin.P0) - } - - // "a": {ariaID: "a", x: -50, y: 25, name: "Light\nLevel", fn: function() {return pinPressFunction(TouchPin.P0)}}, - // "b": {ariaID: "b", x: 0, y: 25, name: "Temperature", fn: function () {return pinPressFunction(TouchPin.P1)}}, - // "c": {ariaID: "c", x: 50, y: 25, name: "Accelerometer", fn: function () {return pinPressFunction(TouchPin.P2)}}, - - // "moveTiltUp": {ariaID: "d", x: -50, y: 50, name: "Pitch", fn: function () {return input.rotation(Rotation.Pitch)}}, - // "moveTiltLeft": {ariaID: "e", x: 0, y: 50, name: "Roll", fn: function () {return Rotation.Roll}}, - // "finger_press": {ariaID: "f", x: 50, y: 50, name: "Pin Press", fn: function () {if(input.logoIsPressed()) {return 255} return 0}} - } + const sensorBtnData: btnData[] = [ + // {ariaID: "disk1", x: -50, y: -25, fn: function () {return input.compassHeading()}}, + // {ariaID: "disk2", x: 0, y: -25, fn: function () {return input.soundLevel()}}, + // {ariaID: "disk3", x: 50, y: -25, fn: function () {return input.magneticForce(Dimension.X)}}, + + {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()}//, + // {ariaID: "thermometer", x: 0, y: 30, sensor: new TemperatureSensor()}, + // {ariaID: "accelerometer", x: 50, y: 30, sensor: new AccelerometerSensor(Dimension.X)}, + + // {ariaID: "Pin 0", x: -50, y: 25, sensor: new PinSensor(TouchPin.P0)}, + // {ariaID: "Pin 1", x: 0, y: 25, sensor: new PinSensor(TouchPin.P1)}, + // {ariaID: "Pin 2", x: 50, y: 25, sensor: new PinSensor(TouchPin.P2)}, + + // {ariaID: "Pitch", x: -50, y: 50, sensor: new RotationSensor(Rotation.Pitch)}, + // {ariaID: "Roll", x: 0, y: 50, sensor: new RotationSensor(Rotation.Roll)}, + // {ariaID: "Logo Pressed", x: 50, y: 50, sensor: new LogoPressSensor()} + ] + + const btnData = {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()} + + // sensorBtnData.forEach(function (btnData) { + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: btnData.ariaID, + ariaId: btnData.ariaID, + x: btnData.x, + y: btnData.y, + onClick: () => { + this.selectedSensors.push(btnData.sensor) + }, + })) + // }) - // Object.keys(sensorBtnData).forEach( - // key => { - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.FlatWhite, - // icon: key, - // ariaId: sensorBtnData[key].ariaID, - // x: sensorBtnData[key].x, - // y: sensorBtnData[key].y, - // onClick: () => { - // this.selectedSensors.push(sensorBtnData[key].sensor) - // }, - // })) - // } - // ) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "led_light_sensor", - ariaId: "led_light_sensor", - x: -50, - y: 30, - onClick: () => { - this.selectedSensors.push(new LightSensor()) - } - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "thermometer", - ariaId: "thermometer", - x: 0, - y: 30, - onClick: () => { - this.selectedSensors.push(new TemperatureSensor()) - } - })) // this.btns.push(new Button({ // parent: null, - // style: ButtonStyles.Transparent, - // icon: "moveTiltLeft", - // ariaId: "Pins", - // x: 0, + // style: ButtonStyles.FlatWhite, + // icon: "disk1", + // ariaId: "Done", + // x: 50, // y: 30, // onClick: () => { - // this.selectedSensors.push(new Pins(TouchPin.P0)) + // if (this.selectedSensors.length === 0) { + // return + // } + + // // const sOpts: SensorOpts = { + // // sensorFn: this.selectedSensors[0].getFn(), + // // sensorName: this.selectedSensors[0].getName(), + // // } + + // // const sOpts: SensorOpts = { + // // sensorFn: this.selectedSensors[0].getFn(), + // // sensorName: this.selectedSensors[0].getName(), + // // } + + // this.app.popScene() + + // if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { + // this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) + // } + + // else { + // this.app.pushScene(new MeasurementConfigSelect(app, this.selectedSensors)) + // } // } // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "disk1", - ariaId: "Done", - x: 50, - y: 30, - onClick: () => { - if (this.selectedSensors.length === 0) { - return - } - - // const sOpts: SensorOpts = { - // sensorFn: this.selectedSensors[0].getFn(), - // sensorName: this.selectedSensors[0].getName(), - // } - - const sOpts: SensorOpts = { - sensorFn: this.selectedSensors[0].getFn(), - sensorName: this.selectedSensors[0].getName(), - } - - this.app.popScene() - - if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) - } - - else { - this.app.pushScene(new MeasurementConfigSelect(app, sOpts, this.selectedSensors)) - } - } - })) - this.navigator.addButtons(this.btns) } @@ -172,9 +107,9 @@ namespace microcode { screen.printCenter("Select a sensor to log", 5) - this.btns.forEach((btn) => { - btn.draw() - }) + // this.btns.forEach((btn) => { + // btn.draw() + // }) super.draw() } } diff --git a/sensors.ts b/sensors.ts index 55c36d4..01e8a00 100644 --- a/sensors.ts +++ b/sensors.ts @@ -1,84 +1,135 @@ - namespace microcode { export type SensorOpts = { sensorFn: () => number, sensorName: string, }; - export interface Sensor { - read(): number; - normalise(): number; - getName(): string; - getFn(): () => number - } + export abstract class Sensor { + private static BUFFER_LIMIT = 100; - export class LightSensor implements Sensor { sensorFn: () => number name: string - constructor() { - this.sensorFn = function () {return input.lightLevel()} - this.name = "Light" + sensorMinReading: number + sensorMaxReading: number + + private numberOfDisplayModes: number; + private currentDisplayMode: number; + + private dataBuffer: number[] + + + constructor(sensorFn: () => number, + name: string, + sensorMinReading: number, + sensorMaxReading: number, + numberOfDisplayModes: number + ) { + this.sensorFn = sensorFn + this.name = name + this.sensorMinReading = sensorMinReading + this.sensorMaxReading = sensorMaxReading + this.numberOfDisplayModes = numberOfDisplayModes + this.dataBuffer = [] } - read(): number { + cycleDisplayMode() { + this.currentDisplayMode = (this.currentDisplayMode + 1) % this.numberOfDisplayModes + } + + getReading(): number { return this.sensorFn() } - normalise(): number { - return this.sensorFn() / 255 + getNormalisedReading(): number{ + return this.sensorFn() / this.sensorMaxReading } - getName() {return this.name} - getFn() {return this.sensorFn} - } + readIntoBuffer(): void { + if (this.dataBuffer.length >= Sensor.BUFFER_LIMIT) { + this.dataBuffer.shift(); + } + this.dataBuffer.push(this.getReading()); + } - export class TemperatureSensor implements Sensor { - sensorFn: () => number - name: string + readNormalisedIntoBuffer(): void { + if (this.dataBuffer.length >= Sensor.BUFFER_LIMIT) { + this.dataBuffer.shift(); + } + this.dataBuffer.push(this.getNormalisedReading()); + } + draw(fromX: number, fromY: number, color: number): void { + for (let i = 0; i < this.dataBuffer.length - 1; i++) { + screen.drawLine(fromX + i, this.dataBuffer[i], fromY + i - 1, this.dataBuffer[i + 1], color); + } + } + } + + export class LightSensor extends Sensor { constructor() { - this.sensorFn = function () {return input.temperature()} - this.name = "Temperature" + super(function () {return input.lightLevel()}, "Light", 0, 255, 1) } + } - read(): number { - return this.sensorFn() + export class TemperatureSensor extends Sensor { + constructor() { + super(function () {return input.temperature()}, "Temperature", 0, 100, 1) } + } - normalise(): number { - return this.sensorFn() / 100 + + /** + * sensorMinReading not implemented + * sensorMaxReading not implemented + */ + export class AccelerometerSensor extends Sensor { + constructor(dim: Dimension) { + super(function () {return input.acceleration(dim)}, "Accelerometer", 0, 100, 1) } + } - getName() {return this.name} - getFn() {return this.sensorFn} + export class PinSensor extends Sensor { + constructor(pin: TouchPin) { + super(function () { + let res: number = 0 + input.onPinPressed(pin, function () { + res = 1 + }) + return res + }, + "pin", + 0, + 1, + 1 + ) + } } - export class Pins implements Sensor { - sensorFn: () => number - name: string + /** + * sensorMinReading not implemented + * sensorMaxReading not implemented + */ + export class RotationSensor extends Sensor { + constructor(rot: Rotation) { + let name: string = "Pitch" - constructor(pin: TouchPin) { - this.sensorFn = function () { - let res: number = 0 - input.onPinPressed(pin, function () { - res = 1 - }) - return res + if (rot === Rotation.Roll) { + name = "Roll" } - this.name = "pin" - } - read(): number { - return this.sensorFn() + super(function () {return input.rotation(rot)}, name, 0, 100, 1) } + } - normalise(): number { - return this.sensorFn() + /** + * sensorMinReading may change in future + * sensorMaxReading may change in future + */ + export class LogoPressSensor extends Sensor { + constructor() { + super(function () {if(input.logoIsPressed()) {return 1} return 0}, "Logo Pressed", 0, 1, 1) } - - getName() {return this.name} - getFn() {return this.sensorFn} } } \ No newline at end of file diff --git a/userOptions.ts b/userOptions.ts index 80ad822..4772e30 100644 --- a/userOptions.ts +++ b/userOptions.ts @@ -1,48 +1,7 @@ namespace microcode { export type MeasurementOpts = { - sensorFn: () => number, - sensorName: string, + sensor: Sensor, measurements: number, period: number }; - - // "files": [ - // "protocol.ts", - // "keymap.ts", - // "analytics.ts", - // "config.ts", - // "main.ts", - // "accessibility.ts", - // "button.ts", - // "component.ts", - // "assets.ts", - // "scene.ts", - // "language.ts", - // "tiles.ts", - // "app.ts", - // "sprite.ts", - // "cursor.ts", - // "home.ts", - // "bounds.ts", - // "picker.ts", - // "affine.ts", - // "math.ts", - // "screen.ts", - // "version.ts", - // "fieldeditors.ts", - // "navigator.ts", - // "cursorscene.ts", - // "options.ts", - // "tooltips.ts", - // "utils.ts", - // "jacs.ts", - // "liveDataViewer.ts", - // "dataRecorder.ts", - // "recordedDataViewer.ts", - // "sensorSelect.ts", - // "measurementConfigSelect.ts", - // "fauxDatalogger.ts", - // "sceneFactory.ts", - // "userOptions.ts" - // ], } \ No newline at end of file From b0dc42e9815b68d61ffaa092c175d7d4f34760b8 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Tue, 27 Feb 2024 21:46:35 +0000 Subject: [PATCH 027/109] Updated sensor & livedataview so that sensor.draw() is invoked instead of livedataview, to facilitate multiple draw modes, added documentation, fixed sceneFactory.# --- liveDataViewer.ts | 37 +++++++++++++++++++++---------------- measurementConfigSelect.ts | 11 ++++------- sceneFactory.ts | 12 ++++++------ sensorSelect.ts | 6 +++--- sensors.ts | 26 ++++++++++++++++---------- 5 files changed, 50 insertions(+), 42 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index e7bb4ce..b39ae14 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -7,7 +7,15 @@ namespace microcode { SENSOR_INFORMATION } + + /** + * One of the 3 main functionalities of MicroData + * Allows for the live feed of a sensor to be plotted, + * Multiple sensors may be plotted at once + * Display modes may be toggled per sensor + */ export class LiveDataViewer extends Scene { + private dataBuffers: number[][]; private bufferLimit = screen.width - (2 * WIDTH_BUFFER); private guiState: GUI_STATE @@ -18,8 +26,8 @@ namespace microcode { super(app, "liveDataViewer") this.color = 0 this.guiState = GUI_STATE.PLOTTING - this.sensors = sensors + this.dataBuffers = [] for (let i = 0; i < this.sensors.length; i++) { this.dataBuffers.push([]) @@ -77,16 +85,9 @@ namespace microcode { } else { - for (let i = 0; i < this.sensors.length; i++) { - let normalisedOutput = this.sensors[i].getNormalisedReading(); - let y = Math.round(screen.height - (normalisedOutput * (screen.height - HEIGHT_BUFFER))) - HEIGHT_BUFFER - - // Buffer management: - if (this.dataBuffers[i].length >= this.bufferLimit) { - this.dataBuffers[i].shift(); - } - this.dataBuffers[i].push(y); - } + this.sensors.forEach(function(sensor) { + sensor.readIntoBuffer() + }) // Draw: this.plot() @@ -104,15 +105,19 @@ namespace microcode { screen.printCenter("Press UP for info", 5) this.draw_axes(); - const start = WIDTH_BUFFER + 2; let colour = 8; - this.dataBuffers.forEach(function(dataBuffer) { - for (let i = 0; i < dataBuffer.length - 1; i++) { - screen.drawLine(start + i, dataBuffer[i], start + i - 1, dataBuffer[i + 1], colour); - } + this.sensors.forEach(function(sensor) { + sensor.draw(WIDTH_BUFFER + 2, HEIGHT_BUFFER, colour) colour = (colour + 1) % 15 }) + + // this.dataBuffers.forEach(function(dataBuffer) { + // for (let i = 0; i < dataBuffer.length - 1; i++) { + // screen.drawLine(start + i, dataBuffer[i], start + i - 1, dataBuffer[i + 1], colour); + // } + // colour = (colour + 1) % 15 + // }) } // Display helper: diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index 58dc669..8b487e4 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -11,8 +11,7 @@ namespace microcode { const enum GUI_STATE { WRITING, - DEFAULT, - DONE + DEFAULT } export class MeasurementConfigSelect extends Scene { @@ -21,7 +20,7 @@ namespace microcode { private currentColumn: number private selectedSensors: Sensor[] - // Quantity, Milli-seconds, Seconds, Minutes, Hours, Days: + // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days]: private userSelection = [10, 0, 1, 0, 0, 0] constructor(app: App, selectedSensors: Sensor[]) { @@ -53,8 +52,8 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.DEFAULT) { this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - this.app.pushScene(new Home(app)) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + // this.app.pushScene(new Home(app)) } else { @@ -112,8 +111,6 @@ namespace microcode { } else if (this.guiState === GUI_STATE.DEFAULT) { - // this.guiState = GUI_STATE.DONE - this.app.popScene() this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions(), this.selectedSensors)) } diff --git a/sceneFactory.ts b/sceneFactory.ts index 34dd1c5..9829b46 100644 --- a/sceneFactory.ts +++ b/sceneFactory.ts @@ -7,22 +7,22 @@ namespace microcode { } - export function generateScene(sceneEnum: CursorSceneEnum, app: App, mOpts?: MeasurementOpts, nextScene?: CursorSceneEnum) { + export function generateScene(sceneEnum: CursorSceneEnum, app: App, sensors: Sensor[], mOpts?: MeasurementOpts, nextScene?: CursorSceneEnum) { switch (sceneEnum) { case CursorSceneEnum.LiveDataViewer: - return new LiveDataViewer(app, [new LightSensor, new TemperatureSensor]) + return new LiveDataViewer(app, sensors) case CursorSceneEnum.SensorSelect: return new SensorSelect(app, nextScene) - // case CursorSceneEnum.MeasurementConfigSelect: - // return new MeasurementConfigSelect(app, sOpts) + case CursorSceneEnum.MeasurementConfigSelect: + return new MeasurementConfigSelect(app, sensors) case CursorSceneEnum.RecordData: - return new DataRecorder(app, mOpts, [new LightSensor, new TemperatureSensor]) + return new DataRecorder(app, mOpts, sensors) default: - return new LiveDataViewer(app, [new LightSensor, new TemperatureSensor]); + return new LiveDataViewer(app, sensors); } } } \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index 05c9285..36cbb33 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -107,9 +107,9 @@ namespace microcode { screen.printCenter("Select a sensor to log", 5) - // this.btns.forEach((btn) => { - // btn.draw() - // }) + this.btns.forEach((btn) => { + btn.draw() + }) super.draw() } } diff --git a/sensors.ts b/sensors.ts index 01e8a00..36d2d66 100644 --- a/sensors.ts +++ b/sensors.ts @@ -2,7 +2,7 @@ namespace microcode { export type SensorOpts = { sensorFn: () => number, sensorName: string, - }; + }; export abstract class Sensor { private static BUFFER_LIMIT = 100; @@ -51,17 +51,23 @@ namespace microcode { } this.dataBuffer.push(this.getReading()); } - - readNormalisedIntoBuffer(): void { - if (this.dataBuffer.length >= Sensor.BUFFER_LIMIT) { - this.dataBuffer.shift(); - } - this.dataBuffer.push(this.getNormalisedReading()); - } - + + + /** + * Default draw mode: may be overriden to accommodate multiple draw modes + * Each value in the data buffer is normalised and scaled to screen size per frame. + * This is inefficient since only one value is added per frame + * + * @param fromX starting x coordinate + * @param fromY starting y coordinate + * @param color + */ draw(fromX: number, fromY: number, color: number): void { for (let i = 0; i < this.dataBuffer.length - 1; i++) { - screen.drawLine(fromX + i, this.dataBuffer[i], fromY + i - 1, this.dataBuffer[i + 1], color); + const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.sensorMaxReading) * (screen.height - fromY))) - fromY + const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.sensorMaxReading) * (screen.height - fromY))) - fromY + + screen.drawLine(fromX + i, y1, fromX + i - 1, y2, color); } } } From d596b71a5ac12d28f866a929a8584ce77eb2beaa Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 28 Feb 2024 19:55:38 +0000 Subject: [PATCH 028/109] Additional assets, further experimentation with button issue --- assets.ts | 194 +++++++++++++++++++++++++++--------------------- cursor.ts | 11 ++- home.ts | 1 + sensorSelect.ts | 156 +++++++++++++++++++++++++------------- 4 files changed, 222 insertions(+), 140 deletions(-) diff --git a/assets.ts b/assets.ts index b428e11..392a836 100644 --- a/assets.ts +++ b/assets.ts @@ -61,6 +61,8 @@ namespace microcode { if (name == "moveTiltRight") return icondb.moveTiltRight if (name == "moveTiltDown") return icondb.moveTiltDown if (name == "finger_press") return icondb.finger_press + if (name == "green_tick") return icondb.green_tick + extraImage = null extraSamples(name) // only for web app @@ -612,24 +614,44 @@ namespace icondb { d d d . . . . . . . . . . . ` - export const showScreen = img` +export const showScreen = img` +. . . . . . . . . . . . . . . . +. . . . . . . . . . . . 2 4 . . +. . . . 2 . . . . . . 2 4 4 2 . +. . . . 2 . . . . . 2 4 4 2 e . +. 2 . . 2 . . . . 2 4 4 2 e b . +. . 2 . 2 . . . 2 4 4 2 e b . . +. . . . . . . d 4 4 2 e b . . . +. . f f f f f d d 2 e b . . . . +. . f f f f f 2 d d b . . . . . +. . f f 2 f 2 f f b . . . . . . +. . f f f f f f f b . 2 2 2 2 . +. . f 2 f f f 2 f b . . . . . . +. . f f 2 2 2 f f b . 2 . . . . +. . f f f f f f f b . . 2 . . . +. . . b b b b b b b . . . . . . +. . . . . . . . . . . . . . . . +` + + + export const green_tick = img` . . . . . . . . . . . . . . . . - . . . . . . . . . . . . 2 4 . . - . . . . 2 . . . . . . 2 4 4 2 . - . . . . 2 . . . . . 2 4 4 2 e . - . 2 . . 2 . . . . 2 4 4 2 e b . - . . 2 . 2 . . . 2 4 4 2 e b . . - . . . . . . . d 4 4 2 e b . . . - . . f f f f f d d 2 e b . . . . - . . f f f f f 2 d d b . . . . . - . . f f 2 f 2 f f b . . . . . . - . . f f f f f f f b . 2 2 2 2 . - . . f 2 f f f 2 f b . . . . . . - . . f f 2 2 2 f f b . 2 . . . . - . . f f f f f f f b . . 2 . . . - . . . b b b b b b b . . . . . . . . . . . . . . . . . . . . . . -` + . . . . . . . . . . . . . 6 6 . + . . . . . . . . . . . . 6 6 6 . + . . . . . . . . . . . 6 6 6 6 . + . . . . . . . . . . 6 6 6 6 6 . + . . . . . . . . . 6 6 6 6 6 . . + . 6 . . . . . . 6 6 6 6 6 . . . + . 6 6 . . . . 6 6 6 6 6 . . . . + . 6 6 6 . . 6 6 6 6 6 . . . . . + . 6 6 6 6 6 6 6 6 6 . . . . . . + . 6 6 6 6 6 6 6 6 . . . . . . . + . 6 6 6 6 6 6 6 . . . . . . . . + . . 6 6 6 6 6 . . . . . . . . . + . . . 6 6 6 . . . . . . . . . . + . . . . . . . . . . . . . . . . + ` export const showNumber = img` . . . . . . . . . . 4 4 4 4 4 4 @@ -1519,23 +1541,23 @@ namespace icondb { ` export const speaker = img` -. . . . . . . . . . . . . . . . -. . . . . . . . . . . . . . . . -. . . . . . . . . . . . . . . . -. . . . . c . . . . . . . . . . -. . . . c b . . . . . 8 . . . . -. . . c b c . . . 8 . . 8 . . . -. c c b c c . 8 . . 8 . 8 . . . -. b b c c c . . 8 . 8 . 8 . . . -. c c c c c . . 8 . 8 . 8 . . . -. c c c c c . 8 . . 8 . 8 . . . -. . . c c c . . . 8 . . 8 . . . -. . . . c c . . . . . 8 . . . . -. . . . . c . . . . . . . . . . -. . . . . . . . . . . . . . . . -. . . . . . . . . . . . . . . . -. . . . . . . . . . . . . . . . -` + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . c . . . . . . . . . . + . . . . c b . . . . . 8 . . . . + . . . c b c . . . 8 . . 8 . . . + . c c b c c . 8 . . 8 . 8 . . . + . b b c c c . . 8 . 8 . 8 . . . + . c c c c c . . 8 . 8 . 8 . . . + . c c c c c . 8 . . 8 . 8 . . . + . . . c c c . . . 8 . . 8 . . . + . . . . c c . . . . . 8 . . . . + . . . . . c . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + ` export const speakerFun = img` . . . . . . . . . . . . . . . . @@ -1575,61 +1597,61 @@ namespace icondb { . . . . . . . . . . . . . . . . ` export const note_on = img` -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 c c c c 1 1 1 1 1 -1 1 1 1 1 1 c f f f f c 1 1 1 1 -1 1 1 1 1 c f f f f f f c 1 1 1 -1 1 1 1 c f f f f f f f f c 1 1 -1 1 1 1 c f f f f f f f f c 1 1 -1 1 1 c f f f f f f f f f c 1 1 -1 1 1 c f f f f f f f f f c 1 1 -1 1 1 c f f f f f f f f f c 1 1 -1 1 1 c f f f f f f f f f c 1 1 -1 1 1 c f f f f f f f f c 1 1 1 -1 1 1 c f f f f f f f f c 1 1 1 -1 1 1 1 c f f f f f f c 1 1 1 1 -1 1 1 1 1 c f f f f c 1 1 1 1 1 -1 1 1 1 1 1 c c c c 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -` - - export const note_off = img` -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -` + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 c c c c 1 1 1 1 1 + 1 1 1 1 1 1 c f f f f c 1 1 1 1 + 1 1 1 1 1 c f f f f f f c 1 1 1 + 1 1 1 1 c f f f f f f f f c 1 1 + 1 1 1 1 c f f f f f f f f c 1 1 + 1 1 1 c f f f f f f f f f c 1 1 + 1 1 1 c f f f f f f f f f c 1 1 + 1 1 1 c f f f f f f f f f c 1 1 + 1 1 1 c f f f f f f f f f c 1 1 + 1 1 1 c f f f f f f f f c 1 1 1 + 1 1 1 c f f f f f f f f c 1 1 1 + 1 1 1 1 c f f f f f f c 1 1 1 1 + 1 1 1 1 1 c f f f f c 1 1 1 1 1 + 1 1 1 1 1 1 c c c c 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + ` + + export const note_off = img` + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + ` export const accelerometer = img` -. . . . . . . . . . . . . . . . -. . . . . . . . 8 . . . . . . . -. . . . . . . 8 8 8 . . . . . . -. . . . . . 8 8 8 8 8 . . . . . -. . . . . . 6 6 8 6 6 . . . . . -. . . . . . . . 8 . . . . . . . -. . 8 6 . . f f f f f . . . . . -. 8 8 6 . f . . . . . f . . . . -8 8 8 8 8 f . f . f . f . . . . -. 8 8 6 . f . . . . . f . . . . -. . 8 6 . . f f f f f 8 . . 6 . -. . . . . . . . . . . . 8 6 8 . -. . . . . . . . . . . . 6 8 8 . -. . . . . . . . . . . 6 8 8 8 . -. . . . . . . . . . . . . . . . -. . . . . . . . . . . . . . . . -` + . . . . . . . . . . . . . . . . + . . . . . . . . 8 . . . . . . . + . . . . . . . 8 8 8 . . . . . . + . . . . . . 8 8 8 8 8 . . . . . + . . . . . . 6 6 8 6 6 . . . . . + . . . . . . . . 8 . . . . . . . + . . 8 6 . . f f f f f . . . . . + . 8 8 6 . f . . . . . f . . . . + 8 8 8 8 8 f . f . f . f . . . . + . 8 8 6 . f . . . . . f . . . . + . . 8 6 . . f f f f f 8 . . 6 . + . . . . . . . . . . . . 8 6 8 . + . . . . . . . . . . . . 6 8 8 . + . . . . . . . . . . . 6 8 8 8 . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + ` export const soundGiggle = img` . . . . . . . . . . . . . . . . diff --git a/cursor.ts b/cursor.ts index a8e0f27..04972a8 100644 --- a/cursor.ts +++ b/cursor.ts @@ -27,11 +27,14 @@ namespace microcode { size: Bounds visible = true + private cursorOutlineColour: number + constructor() { this.xfrm = new Affine() this.cancelHandlerStack = [] this.moveDest = new Vec2() this.setSize() + this.cursorOutlineColour = 9 } public moveTo(pos: Vec2, ariaId: string, sizeHint: Bounds) { @@ -63,6 +66,10 @@ namespace microcode { else this.size = size.clone() } + public setOutlineColour(colour: number) { + this.cursorOutlineColour = colour + } + public saveState(): CursorState { return { navigator: this.navigator, @@ -113,13 +120,13 @@ namespace microcode { this.xfrm, this.size, 1, - 6 + this.cursorOutlineColour ) Screen.outlineBoundsXfrm( this.xfrm, this.size, 2, - 9 + this.cursorOutlineColour ) const text = accessibility.ariaToTooltip(this.ariaId) diff --git a/home.ts b/home.ts index 6138146..2de2a4b 100644 --- a/home.ts +++ b/home.ts @@ -117,6 +117,7 @@ namespace microcode { this.recordDataBtn.draw() this.liveDataBtn.draw() this.viewBtn.draw() + this.drawVersion() super.draw() } diff --git a/sensorSelect.ts b/sensorSelect.ts index 36cbb33..65a1aaf 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -14,22 +14,22 @@ namespace microcode { /* override */ startup() { super.startup() - interface btnData { - ariaID: string, - x: number, - y: number, - sensor: Sensor, - } + // interface btnData { + // ariaID: string, + // x: number, + // y: number, + // sensor: Sensor, + // } /** * Issue with consistently being able to load this app when there are > 3 buttons */ - const sensorBtnData: btnData[] = [ + // const sensorBtnData: btnData[] = [ // {ariaID: "disk1", x: -50, y: -25, fn: function () {return input.compassHeading()}}, // {ariaID: "disk2", x: 0, y: -25, fn: function () {return input.soundLevel()}}, // {ariaID: "disk3", x: 50, y: -25, fn: function () {return input.magneticForce(Dimension.X)}}, - {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()}//, + // {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()}, // {ariaID: "thermometer", x: 0, y: 30, sensor: new TemperatureSensor()}, // {ariaID: "accelerometer", x: 50, y: 30, sensor: new AccelerometerSensor(Dimension.X)}, @@ -40,58 +40,109 @@ namespace microcode { // {ariaID: "Pitch", x: -50, y: 50, sensor: new RotationSensor(Rotation.Pitch)}, // {ariaID: "Roll", x: 0, y: 50, sensor: new RotationSensor(Rotation.Roll)}, // {ariaID: "Logo Pressed", x: 50, y: 50, sensor: new LogoPressSensor()} - ] + // ] + + // const btnData = {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()} + + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "accelerometer", + ariaId: "accelerometer", + x: -50, + y: -25, + onClick: () => { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "Pin 0", + ariaId: "Pin 0", + x: 0, + y: -25, + onClick: () => { + this.selectedSensors.push(new PinSensor(TouchPin.P0)) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "Pin 1", + ariaId: "Pin 1", + x: 50, + y: -25, + onClick: () => { + this.selectedSensors.push(new PinSensor(TouchPin.P1)) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "led_light_sensor", + ariaId: "led_light_sensor", + x: -50, + y: 30, + onClick: () => { + this.selectedSensors.push(new LightSensor()) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "thermometer", + ariaId: "thermometer", + x: 0, + y: 30, + onClick: () => { + this.selectedSensors.push(new TemperatureSensor()) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.FlatWhite, + icon: "green_tick", + ariaId: "Done", + x: 50, + y: 30, + onClick: () => { + if (this.selectedSensors.length === 0) { + return + } + + this.app.popScene() + + if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { + this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) + } + + else { + this.app.pushScene(new MeasurementConfigSelect(app, this.selectedSensors)) + } + } + })) - const btnData = {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()} // sensorBtnData.forEach(function (btnData) { - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: btnData.ariaID, - ariaId: btnData.ariaID, - x: btnData.x, - y: btnData.y, - onClick: () => { - this.selectedSensors.push(btnData.sensor) - }, - })) - // }) - - // this.btns.push(new Button({ // parent: null, // style: ButtonStyles.FlatWhite, - // icon: "disk1", - // ariaId: "Done", - // x: 50, - // y: 30, + // icon: btnData.ariaID, + // ariaId: btnData.ariaID, + // x: btnData.x, + // y: btnData.y, // onClick: () => { - // if (this.selectedSensors.length === 0) { - // return - // } - - // // const sOpts: SensorOpts = { - // // sensorFn: this.selectedSensors[0].getFn(), - // // sensorName: this.selectedSensors[0].getName(), - // // } - - // // const sOpts: SensorOpts = { - // // sensorFn: this.selectedSensors[0].getFn(), - // // sensorName: this.selectedSensors[0].getName(), - // // } - - // this.app.popScene() - - // if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - // this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) - // } - - // else { - // this.app.pushScene(new MeasurementConfigSelect(app, this.selectedSensors)) - // } - // } + // this.selectedSensors.push(btnData.sensor) + // }, // })) + // }) this.navigator.addButtons(this.btns) } @@ -110,6 +161,7 @@ namespace microcode { this.btns.forEach((btn) => { btn.draw() }) + super.draw() } } From d6cbde664f5a275507d711b52db43704c76ed24d Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 29 Feb 2024 13:00:58 +0000 Subject: [PATCH 029/109] Added multiple new sensors, new assets and tooltips. --- assets.ts | 388 ++++++++++++++++++++++++++---------------------- sensorSelect.ts | 255 +++++++++++++++++++------------ sensors.ts | 38 ++++- tooltips.ts | 8 +- 4 files changed, 414 insertions(+), 275 deletions(-) diff --git a/assets.ts b/assets.ts index 392a836..45242fb 100644 --- a/assets.ts +++ b/assets.ts @@ -63,7 +63,17 @@ namespace microcode { if (name == "finger_press") return icondb.finger_press if (name == "green_tick") return icondb.green_tick - + if (name == "magnet") return icondb.magnet + if (name == "pin_0") return icondb.pin_0 + + if (name == "right_turn") return icondb.car_right_turn + if (name == "right_spin") return icondb.car_right_spin + + if (name == "speaker") return icondb.speaker + + if (name == "tile_button_a") return icondb.tile_button_a + // if (name == "tile_button_a") return icondb.tile_button_a + extraImage = null extraSamples(name) // only for web app if (extraImage) return extraImage @@ -73,8 +83,8 @@ namespace microcode { } export const wordLogo = img` - .111111.......111111...1111..................................................111111111........................1111...................................... - 11bbbbbb.....11bbbbbb.11bbbb................................................bbbbbbbbbbff.....................11bbbb..................................... + .111111.......111111...1111................................................11111111111........................1111...................................... + 11bbbbbb.....11bbbbbb.11bbbb...............................................1bbbbbbbbbbff.....................11bbbb..................................... 1bbbbbbbb...11bbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbf....................1bbbbbf.................................... 1bbbbbbbbb.11bbbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbbf...................1bbbbbf.................................... 1bbbbbbbbbb1bbbbbbbbbf1bbbbbf..............................................1bbbbf..11bbbbf...................1bbbbbf.................................... @@ -635,22 +645,22 @@ export const showScreen = img` export const green_tick = img` - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . 6 6 . - . . . . . . . . . . . . 6 6 6 . - . . . . . . . . . . . 6 6 6 6 . - . . . . . . . . . . 6 6 6 6 6 . - . . . . . . . . . 6 6 6 6 6 . . - . 6 . . . . . . 6 6 6 6 6 . . . - . 6 6 . . . . 6 6 6 6 6 . . . . - . 6 6 6 . . 6 6 6 6 6 . . . . . - . 6 6 6 6 6 6 6 6 6 . . . . . . - . 6 6 6 6 6 6 6 6 . . . . . . . - . 6 6 6 6 6 6 6 . . . . . . . . - . . 6 6 6 6 6 . . . . . . . . . - . . . 6 6 6 . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 6 6 1 + 1 1 1 1 1 1 1 1 1 1 1 1 6 6 6 1 + 1 1 1 1 1 1 1 1 1 1 1 6 6 6 6 1 + 1 1 1 1 1 1 1 1 1 1 6 6 6 6 6 1 + 1 1 1 1 1 1 1 1 1 6 6 6 6 6 1 1 + 1 6 1 1 1 1 1 1 6 6 6 6 6 1 1 1 + 1 6 6 1 1 1 1 6 6 6 6 6 1 1 1 1 + 1 6 6 6 1 1 6 6 6 6 6 1 1 1 1 1 + 1 6 6 6 6 6 6 6 6 6 1 1 1 1 1 1 + 1 6 6 6 6 6 6 6 6 1 1 1 1 1 1 1 + 1 6 6 6 6 6 6 6 1 1 1 1 1 1 1 1 + 1 1 6 6 6 6 6 1 1 1 1 1 1 1 1 1 + 1 1 1 6 6 6 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const showNumber = img` @@ -946,6 +956,26 @@ export const showScreen = img` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ` + export const pin_0 = img` + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 4 4 4 4 4 1 1 1 4 4 1 1 1 + 1 4 4 4 1 1 4 4 1 4 4 4 4 1 1 + 1 4 4 4 1 1 1 4 4 4 1 1 4 4 1 + 1 4 4 4 1 1 4 4 4 4 1 1 4 4 1 + 1 4 4 4 4 4 4 1 4 4 1 1 4 4 1 + 1 4 4 4 1 1 1 1 4 4 1 1 4 4 1 + 1 4 4 4 1 1 1 1 4 4 1 1 4 4 1 + 1 4 4 4 1 1 1 1 4 4 1 1 4 4 1 + 1 4 4 4 1 1 1 1 4 4 1 1 4 4 1 + 1 4 4 4 1 1 1 1 4 4 1 1 4 4 1 + 1 4 4 4 1 1 1 1 1 4 4 4 4 1 1 + 1 1 4 1 1 1 1 1 1 1 4 4 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + ` + + export const tile_pin_0 = img` . . 4 5 4 d . . . . 4 5 4 d . . . . 4 5 4 d . . . . 4 5 4 d . . @@ -1113,22 +1143,22 @@ export const showScreen = img` ` export const finger_press = img` - . . . . . . . . . . . . . . . . - . . . . . . . f . . . . . . . . - . . . . . . . f . . . . . . . . - . . . . . . . f . . . . . . . . - . . . . . f . f . f . . . . . . - . . . . . . f f f . . . . . . . - . . . . . . . f . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . 4 4 4 4 4 . . . . . . - . . . . 4 4 4 4 4 4 4 d . . . . - . . . e 4 4 4 4 4 4 4 e d . . . - . . . e 2 4 4 4 4 4 2 e d . . . - . . . e e 2 2 2 2 2 e e d . . . - . . . . e e e e e e e d . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 1 + 1 1 1 1 1 f 1 f 1 f 1 1 1 1 1 1 + 1 1 1 1 1 1 f f f 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 4 4 4 4 4 1 1 1 1 1 1 + 1 1 1 1 4 4 4 4 4 4 4 d 1 1 1 1 + 1 1 1 e 4 4 4 4 4 4 4 e d 1 1 1 + 1 1 1 e 2 4 4 4 4 4 2 e d 1 1 1 + 1 1 1 e e 2 2 2 2 2 e e d 1 1 1 + 1 1 1 1 e e e e e e e d 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const finger_release = img` . . . . . . . . . . . . . . . . @@ -1409,40 +1439,40 @@ export const showScreen = img` ` export const magnet = img` - . . . . . . . . . . . . 6 . . . - . . . . . . . . . . 6 . . . 6 . - . . . . . . . . . . . . . . . . - . . . 8 8 8 8 8 f f . . 6 . . . - . . 8 8 8 8 8 8 f f . . . . . 6 - . 8 8 8 b b b b b b . . 6 . . . - . 8 8 b . . . . . . . . . . 6 . - . 8 8 . . . . . . . . 6 . . . . - . 2 2 . . . . . . . . . . 6 . . - . 2 2 . . . . . . . . 6 . . . . - . 2 2 2 . . . . . . . . . . 6 . - . b 2 2 2 2 2 2 f f . . 6 . . . - . . b 2 2 2 2 2 f f . . . 5 5 5 - . . . b b b b b b b . . 6 5 5 5 - . . . . . . . . . . . . . 5 5 4 - . . . . . . . . . . 6 . . 4 4 . -` - export const thermometer = img` - . . . . . . . . . . . . . . . . - . . . . . . . f . . . . . . . . - . . . . . . f d f . . . . . . . - . . . . . . f d f . . . . . . . - . . . . . . f d f . . . . . . . - . . . . . . f d f . . . . . . . - . . . . . . f 2 f . . . . . . . - . . . . . . f 2 f . . . . . . . - . . . . . . f 2 f . . . . . . . - . . . . . . f 2 f . . . . . . . - . . . . . f 2 2 2 f . . . . . . - . . . . f 2 2 2 2 2 f . . . . . - . . . . f 2 2 2 2 2 f . . . . . - . . . . . f 2 2 2 f . . . . . . - . . . . . . f f f . . . . . . . - . . . . . . . . . . . . . . . . +1 1 1 1 1 1 1 1 1 1 1 1 6 1 1 1 +1 1 1 1 1 1 1 1 1 1 6 1 1 1 6 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 8 8 8 8 8 f f 1 1 6 1 1 1 +1 1 8 8 8 8 8 8 f f 1 1 1 1 1 6 +1 8 8 8 b b b b b b 1 1 6 1 1 1 +1 8 8 b 1 1 1 1 1 1 1 1 1 1 6 1 +1 8 8 1 1 1 1 1 1 1 1 6 1 1 1 1 +1 2 2 1 1 1 1 1 1 1 1 1 1 6 1 1 +1 2 2 1 1 1 1 1 1 1 1 6 1 1 1 1 +1 2 2 2 1 1 1 1 1 1 1 1 1 1 6 1 +1 b 2 2 2 2 2 2 f f 1 1 6 1 1 1 +1 1 b 2 2 2 2 2 f f 1 1 1 5 5 5 +1 1 1 b b b b b b b 1 1 6 5 5 5 +1 1 1 1 1 1 1 1 1 1 1 1 1 5 5 4 +1 1 1 1 1 1 1 1 1 1 6 1 1 4 4 1 +` +export const thermometer = img` +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 f 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 f d f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f d f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f d f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f d f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f 2 f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f 2 f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f 2 f 1 1 1 1 1 1 1 +1 1 1 1 1 1 f 2 f 1 1 1 1 1 1 1 +1 1 1 1 1 f 2 2 2 f 1 1 1 1 1 1 +1 1 1 1 f 2 2 2 2 2 f 1 1 1 1 1 +1 1 1 1 f 2 2 2 2 2 f 1 1 1 1 1 +1 1 1 1 1 f 2 2 2 f 1 1 1 1 1 1 +1 1 1 1 1 1 f f f 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const temp_warmer = img` @@ -1484,22 +1514,22 @@ export const showScreen = img` ` export const led_light_sensor = img` -. . . . . . . . . . . . . . . . -. . 8 8 8 8 5 5 5 8 8 8 8 . . . -. . 8 8 8 5 4 4 4 5 8 8 8 . . . -. . 8 8 8 5 4 4 4 5 8 8 8 . . . -. . 8 8 8 5 4 4 4 5 8 8 8 . . . -. . 8 8 8 8 5 5 5 8 8 8 8 . . . -. . 8 8 5 8 8 8 8 8 5 8 8 . . . -. . 8 5 8 8 8 5 8 8 8 5 8 . . . -. . 8 8 8 5 8 8 8 5 8 8 8 . . . -. . 8 8 5 8 8 5 8 8 5 8 8 . . . -. . 8 5 8 8 8 8 8 8 8 5 8 . . . -. . 8 8 8 8 8 5 8 8 8 8 8 . . . -. . 8 8 8 8 8 8 8 8 8 8 8 . . . -. . 8 8 8 2 2 2 2 2 8 8 8 . . . -. . 8 f f f f f f f f f 8 . . . -. . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 8 8 8 8 5 5 5 8 8 8 8 1 1 1 + 1 1 8 8 8 5 4 4 4 5 8 8 8 1 1 1 + 1 1 8 8 8 5 4 4 4 5 8 8 8 1 1 1 + 1 1 8 8 8 5 4 4 4 5 8 8 8 1 1 1 + 1 1 8 8 8 8 5 5 5 8 8 8 8 1 1 1 + 1 1 8 8 5 8 8 8 8 8 5 8 8 1 1 1 + 1 1 8 5 8 8 8 5 8 8 8 5 8 1 1 1 + 1 1 8 8 8 5 8 8 8 5 8 8 8 1 1 1 + 1 1 8 8 5 8 8 5 8 8 5 8 8 1 1 1 + 1 1 8 5 8 8 8 8 8 8 8 5 8 1 1 1 + 1 1 8 8 8 8 8 5 8 8 8 8 8 1 1 1 + 1 1 8 8 8 8 8 8 8 8 8 8 8 1 1 1 + 1 1 8 8 8 2 2 2 2 2 8 8 8 1 1 1 + 1 1 8 f f f f f f f f f 8 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const light_sensor = img` @@ -1541,22 +1571,22 @@ export const showScreen = img` ` export const speaker = img` - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . c . . . . . . . . . . - . . . . c b . . . . . 8 . . . . - . . . c b c . . . 8 . . 8 . . . - . c c b c c . 8 . . 8 . 8 . . . - . b b c c c . . 8 . 8 . 8 . . . - . c c c c c . . 8 . 8 . 8 . . . - . c c c c c . 8 . . 8 . 8 . . . - . . . c c c . . . 8 . . 8 . . . - . . . . c c . . . . . 8 . . . . - . . . . . c . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 c 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 c b 1 1 1 1 1 8 1 1 1 1 + 1 1 1 c b c 1 1 1 8 1 1 8 1 1 1 + 1 c c b c c 1 8 1 1 8 1 8 1 1 1 + 1 b b c c c 1 1 8 1 8 1 8 1 1 1 + 1 c c c c c 1 1 8 1 8 1 8 1 1 1 + 1 c c c c c 1 8 1 1 8 1 8 1 1 1 + 1 1 1 c c c 1 1 1 8 1 1 8 1 1 1 + 1 1 1 1 c c 1 1 1 1 1 8 1 1 1 1 + 1 1 1 1 1 c 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const speakerFun = img` @@ -1635,22 +1665,22 @@ export const showScreen = img` ` export const accelerometer = img` - . . . . . . . . . . . . . . . . - . . . . . . . . 8 . . . . . . . - . . . . . . . 8 8 8 . . . . . . - . . . . . . 8 8 8 8 8 . . . . . - . . . . . . 6 6 8 6 6 . . . . . - . . . . . . . . 8 . . . . . . . - . . 8 6 . . f f f f f . . . . . - . 8 8 6 . f . . . . . f . . . . - 8 8 8 8 8 f . f . f . f . . . . - . 8 8 6 . f . . . . . f . . . . - . . 8 6 . . f f f f f 8 . . 6 . - . . . . . . . . . . . . 8 6 8 . - . . . . . . . . . . . . 6 8 8 . - . . . . . . . . . . . 6 8 8 8 . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 1 + 1 1 1 1 1 1 8 8 8 8 8 1 1 1 1 1 + 1 1 1 1 1 1 6 6 8 6 6 1 1 1 1 1 + 1 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 + 1 1 8 6 1 1 f f f f f 1 1 1 1 1 + 1 8 8 6 1 f 1 1 1 1 1 f 1 1 1 1 + 8 8 8 8 8 f 1 f 1 f 1 f 1 1 1 1 + 1 8 8 6 1 f 1 1 1 1 1 f 1 1 1 1 + 1 1 8 6 1 1 f f f f f 8 1 1 6 1 + 1 1 1 1 1 1 1 1 1 1 1 1 8 6 8 1 + 1 1 1 1 1 1 1 1 1 1 1 1 6 8 8 1 + 1 1 1 1 1 1 1 1 1 1 1 6 8 8 8 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const soundGiggle = img` @@ -1872,40 +1902,40 @@ export const showScreen = img` . . . . . . . . . . . . . . . . ` export const moveTiltUp = img` -. . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . . 8 8 8 8 . . . . . . - . . . . . . . . . . 8 . . . . . - . . . . . . . . . . . 8 . . . . - . . . . . . . . . 8 8 8 8 8 . . - . . 9 9 9 9 9 9 9 9 8 8 8 . . . - . . 9 9 9 9 9 9 9 9 9 8 . . . . - . . 9 9 9 9 9 9 9 9 9 . . . . . - . . 9 9 9 9 8 8 8 8 8 f f f . . - . . 9 9 9 8 6 6 6 6 6 5 f . . . - . . 9 9 8 6 6 6 6 6 6 f . . . . - . . 9 8 6 6 6 6 6 6 8 . . . . . - . . 8 8 8 8 8 8 8 8 9 . . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 8 8 8 8 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 8 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 8 1 1 1 1 + 1 1 1 1 1 1 1 1 1 8 8 8 8 8 1 1 + 1 1 9 9 9 9 9 9 9 9 8 8 8 1 1 1 + 1 1 9 9 9 9 9 9 9 9 9 8 1 1 1 1 + 1 1 9 9 9 9 9 9 9 9 9 1 1 1 1 1 + 1 1 9 9 9 9 8 8 8 8 8 f f f 1 1 + 1 1 9 9 9 8 6 6 6 6 6 5 f 1 1 1 + 1 1 9 9 8 6 6 6 6 6 6 f 1 1 1 1 + 1 1 9 8 6 6 6 6 6 6 8 1 1 1 1 1 + 1 1 8 8 8 8 8 8 8 8 9 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const moveTiltLeft = img` -. . . . . . . . . . . . . . . . - . . . . . . . . . . 8 . . . . . - . . . . . . f f . 8 8 . . . . . - . . . . . f 5 f 8 8 8 8 8 . . . - . . 9 9 8 5 5 f 9 8 8 . . 8 . . - . . 9 8 6 5 5 f 9 9 8 . . . 8 . - . . 9 8 6 5 5 f 9 9 9 . . . 8 . - . . 9 8 6 5 5 f 9 9 9 . . . 8 . - . . 9 8 6 5 5 f 9 9 9 . . 8 . . - . . 9 8 6 5 5 f 9 9 9 . . . . . - . . 9 8 6 5 5 f 9 9 9 . . . . . - . . 9 9 8 5 5 f 9 9 9 . . . . . - . . . . . f 5 f . . . . . . . . - . . . . . . f f . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 8 1 1 1 1 1 + 1 1 1 1 1 1 f f 1 8 8 1 1 1 1 1 + 1 1 1 1 1 f 5 f 8 8 8 8 8 1 1 1 + 1 1 9 9 8 5 5 f 9 8 8 1 1 8 1 1 + 1 1 9 8 6 5 5 f 9 9 8 1 1 1 8 1 + 1 1 9 8 6 5 5 f 9 9 9 1 1 1 8 1 + 1 1 9 8 6 5 5 f 9 9 9 1 1 1 8 1 + 1 1 9 8 6 5 5 f 9 9 9 1 1 8 1 1 + 1 1 9 8 6 5 5 f 9 9 9 1 1 1 1 1 + 1 1 9 8 6 5 5 f 9 9 9 1 1 1 1 1 + 1 1 9 9 8 5 5 f 9 9 9 1 1 1 1 1 + 1 1 1 1 1 f 5 f 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 f f 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const moveTiltRight = img` . . . . . . . . . . . . . . . . @@ -3085,41 +3115,41 @@ bffffffffffffffffffffffffffffffb ` export const car_right_turn = img` - . . . . . . . . . . . . . . . . - . . . . . . . . c c c . . . . . - . . . . . . . . c 7 7 c . . . . - . . . . . c c c c 7 7 7 c . . . - . . . . c 7 7 7 7 7 7 7 7 c . . - . . . c 7 7 7 7 7 7 7 7 7 7 c . - . . c 7 7 7 7 7 7 7 7 7 7 c . . - . c 7 7 7 7 7 c c 7 7 7 c . . . - . c 7 7 7 7 c . c 7 7 c . . . . - . c 7 7 7 c d . c c c . . . . . - . c 7 7 7 c d . . . . . . . . . - . c 7 7 7 c d . . . . . . . . . - . c 7 7 7 c d . . . . . . . . . - . c 7 7 7 c d . . . . . . . . . - . c c c c c . . . . . . . . . . - . . . . . . . . . . . . . . . . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 c c c 1 1 1 1 1 + 1 1 1 1 1 1 1 1 c 7 7 c 1 1 1 1 + 1 1 1 1 1 c c c c 7 7 7 c 1 1 1 + 1 1 1 1 c 7 7 7 7 7 7 7 7 c 1 1 + 1 1 1 c 7 7 7 7 7 7 7 7 7 7 c 1 + 1 1 c 7 7 7 7 7 7 7 7 7 7 c 1 1 + 1 c 7 7 7 7 7 c c 7 7 7 c 1 1 1 + 1 c 7 7 7 7 c 1 c 7 7 c 1 1 1 1 + 1 c 7 7 7 c d 1 c c c 1 1 1 1 1 + 1 c 7 7 7 c d 1 1 1 1 1 1 1 1 1 + 1 c 7 7 7 c d 1 1 1 1 1 1 1 1 1 + 1 c 7 7 7 c d 1 1 1 1 1 1 1 1 1 + 1 c 7 7 7 c d 1 1 1 1 1 1 1 1 1 + 1 c c c c c 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const car_right_spin = img` - . . . . . . . . . . . . . . . . - . . . . . . . . . . . . . . . . - . . . . . c c c c c . . . . . . - . . . . c 7 7 7 7 7 c . . . . . - . . . c 7 7 7 7 7 7 7 c . . . . - . . c 7 7 7 7 7 7 7 7 7 c . . . - . c 7 7 7 7 7 c c 7 7 7 c . . . - c 7 7 7 7 7 c c c 7 7 7 c c c . + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 c c c c c 1 1 1 1 1 1 + 1 1 1 1 c 7 7 7 7 7 c 1 1 1 1 1 + 1 1 1 c 7 7 7 7 7 7 7 c 1 1 1 1 + 1 1 c 7 7 7 7 7 7 7 7 7 c 1 1 1 + 1 c 7 7 7 7 7 c c 7 7 7 c 1 1 1 + c 7 7 7 7 7 c c c 7 7 7 c c c 1 c 7 7 7 7 c c 7 7 7 7 7 7 7 c d c 7 7 7 c d c 7 7 7 7 7 7 7 c d - c 7 7 7 c d . c 7 7 7 7 7 c d . - c 7 7 7 c d . . c 7 7 7 c d . . - c 7 7 7 c d . . . c 7 c d . . . - c 7 7 7 c . . . . . c d . . . . - c c c c c . . . . . . . . . . . - . . . . . . . . . . . . . . . . + c 7 7 7 c d 1 c 7 7 7 7 7 c d 1 + c 7 7 7 c d 1 1 c 7 7 7 c d 1 1 + c 7 7 7 c d 1 1 1 c 7 c d 1 1 1 + c 7 7 7 c 1 1 1 1 1 c d 1 1 1 1 + c c c c c 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` export const car_stop = img` diff --git a/sensorSelect.ts b/sensorSelect.ts index 65a1aaf..cb320a0 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -13,105 +13,176 @@ namespace microcode { /* override */ startup() { super.startup() - - // interface btnData { - // ariaID: string, - // x: number, - // y: number, - // sensor: Sensor, - // } - /** - * Issue with consistently being able to load this app when there are > 3 buttons - */ - // const sensorBtnData: btnData[] = [ - // {ariaID: "disk1", x: -50, y: -25, fn: function () {return input.compassHeading()}}, - // {ariaID: "disk2", x: 0, y: -25, fn: function () {return input.soundLevel()}}, - // {ariaID: "disk3", x: 50, y: -25, fn: function () {return input.magneticForce(Dimension.X)}}, + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "accelerometer", + // ariaId: "accelerometer", + // x: -60, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // }, + // })) - // {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()}, - // {ariaID: "thermometer", x: 0, y: 30, sensor: new TemperatureSensor()}, - // {ariaID: "accelerometer", x: 50, y: 30, sensor: new AccelerometerSensor(Dimension.X)}, + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "pin_0", + // ariaId: "Pin 0", + // x: -30, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new PinSensor(TouchPin.P0)) + // }, + // })) - // {ariaID: "Pin 0", x: -50, y: 25, sensor: new PinSensor(TouchPin.P0)}, - // {ariaID: "Pin 1", x: 0, y: 25, sensor: new PinSensor(TouchPin.P1)}, - // {ariaID: "Pin 2", x: 50, y: 25, sensor: new PinSensor(TouchPin.P2)}, + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "magnet", + // ariaId: "S10", + // x: 0, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new MagnetSensor(Dimension.X)) + // }, + // })) - // {ariaID: "Pitch", x: -50, y: 50, sensor: new RotationSensor(Rotation.Pitch)}, - // {ariaID: "Roll", x: 0, y: 50, sensor: new RotationSensor(Rotation.Roll)}, - // {ariaID: "Logo Pressed", x: 50, y: 50, sensor: new LogoPressSensor()} - // ] + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "accelerometer", + // ariaId: "accelerometer", + // x: 30, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // }, + // })) - // const btnData = {ariaID: "led_light_sensor", x: -50, y: 30, sensor: new LightSensor()} + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "right_turn", + // ariaId: "Pitch", + // x: 60, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + // }, + // })) + //----------- - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "accelerometer", - ariaId: "accelerometer", - x: -50, - y: -25, - onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "right_spin", + // ariaId: "Roll", + // x: -60, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + // }, + // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "Pin 0", - ariaId: "Pin 0", - x: 0, - y: -25, - onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P0)) - }, - })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.FlatWhite, - icon: "Pin 1", - ariaId: "Pin 1", - x: 50, - y: -25, - onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P1)) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "led_light_sensor", + // ariaId: "led_light_sensor", + // x: -30, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new LightSensor()) + // }, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "thermometer", + // ariaId: "thermometer", + // x: 0, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new TemperatureSensor()) + // }, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "finger_press", + // ariaId: "Logo Press", + // x: 30, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new LogoPressSensor()) + // }, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "speaker", + // ariaId: "Volume", + // x: 60, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new VolumeSensor()) + // }, + // })) + + + //----------- this.btns.push(new Button({ parent: null, - style: ButtonStyles.FlatWhite, - icon: "led_light_sensor", - ariaId: "led_light_sensor", - x: -50, - y: 30, + style: ButtonStyles.Transparent, + icon: "right_spin", + ariaId: "Compass", + x: -60, + y: 26, onClick: () => { - this.selectedSensors.push(new LightSensor()) + this.selectedSensors.push(new CompassHeadingSensor()) }, })) this.btns.push(new Button({ parent: null, - style: ButtonStyles.FlatWhite, - icon: "thermometer", - ariaId: "thermometer", - x: 0, - y: 30, + style: ButtonStyles.Transparent, + icon: "tile_button_a", + ariaId: "F3", + x: -30, + y: 26, onClick: () => { - this.selectedSensors.push(new TemperatureSensor()) + this.selectedSensors.push(new ButtonPressSensor()) }, })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "finger_press", + // ariaId: "Logo Press", + // x: 30, + // y: -26, + // onClick: () => { + // this.selectedSensors.push(new LogoPressSensor()) + // }, + // })) + this.btns.push(new Button({ parent: null, - style: ButtonStyles.FlatWhite, + style: ButtonStyles.Transparent, icon: "green_tick", ariaId: "Done", - x: 50, - y: 30, + x: 60, + y: 40, onClick: () => { if (this.selectedSensors.length === 0) { return @@ -129,21 +200,6 @@ namespace microcode { } })) - - // sensorBtnData.forEach(function (btnData) { - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.FlatWhite, - // icon: btnData.ariaID, - // ariaId: btnData.ariaID, - // x: btnData.x, - // y: btnData.y, - // onClick: () => { - // this.selectedSensors.push(btnData.sensor) - // }, - // })) - // }) - this.navigator.addButtons(this.btns) } @@ -158,9 +214,26 @@ namespace microcode { screen.printCenter("Select a sensor to log", 5) - this.btns.forEach((btn) => { - btn.draw() - }) + + // Following 3 lines may be tabbed - results in same error regardless: + + // this.btns.forEach((btn) => { + // btn.draw() + // }) + + for (let i = 0; i < this.btns.length; ++i) { + const btn = this.btns[i] + if (!btn.isOffScreenX()) btn.draw() + } + + // Identical: + + // this.btns[0].draw() + // this.btns[1].draw() + // this.btns[2].draw() + // this.btns[3].draw() + // this.btns[4].draw() + // this.btns[5].draw() super.draw() } diff --git a/sensors.ts b/sensors.ts index 36d2d66..6368566 100644 --- a/sensors.ts +++ b/sensors.ts @@ -18,7 +18,6 @@ namespace microcode { private dataBuffer: number[] - constructor(sensorFn: () => number, name: string, sensorMinReading: number, @@ -104,7 +103,19 @@ namespace microcode { }) return res }, - "pin", + "Pin " + pin.toString(), + 0, + 1, + 1 + ) + } + } + + + export class MagnetSensor extends Sensor { + constructor(dim: Dimension) { + super(function() {return input.magneticForce(dim)}, + "Magnet " + dim.toString(), 0, 1, 1 @@ -125,7 +136,7 @@ namespace microcode { name = "Roll" } - super(function () {return input.rotation(rot)}, name, 0, 100, 1) + super(function () {return input.rotation(rot)}, name, 0, 100, 1) } } @@ -138,4 +149,25 @@ namespace microcode { super(function () {if(input.logoIsPressed()) {return 1} return 0}, "Logo Pressed", 0, 1, 1) } } + + export class CompassHeadingSensor extends Sensor { + constructor() { + super(function () {return input.compassHeading()}, "Compass", 0, 360, 1) + } + } + + export class VolumeSensor extends Sensor { + constructor() { + super(function () {return input.soundLevel()}, "Volume", 0, 255, 1) + } + } + + /** + * No access to the Microbit Buttons A & B; only the controller buttons A & B; it seems + */ + export class ButtonPressSensor extends Sensor { + constructor() { + super(function () {return 1}, "Button Press", 0, 1, 1) + } + } } \ No newline at end of file diff --git a/tooltips.ts b/tooltips.ts index 9d677e4..b118ea7 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -23,7 +23,7 @@ namespace microcode { else if (id === "S9A") res = "variable X set"; else if (id === "S9B") res = "variable Y set"; else if (id === "S9C") res = "variable Z set"; - else if (id === "S10") res = "magnet"; + else if (id === "S10") res = "Magnet"; else if (id === "S11") res = "slider"; else if (id === "S12") res = "dial"; else if (id === "rule") res = "rule"; @@ -164,7 +164,11 @@ namespace microcode { else if (id == "View") res = "View" else if (id == "Done") res = "Done" else if (id == "Pins") res = "Pins" - + else if (id == "Pin 0") res = "Pin 0" + else if (id == "Pin 1") res = "Pin 1" + else if (id == "Pin 2") res = "Pin 2" + else if (id == "Volume") res = "Volume" + else if (id == "Compass") res = "Compass" return res } } \ No newline at end of file From 3cdb157f08725c439f698eea175ed5f0c5c062b5 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 29 Feb 2024 13:56:19 +0000 Subject: [PATCH 030/109] Dynamic boundary colouring for buttons & cursors. --- button.ts | 40 ++++++++++++++- cursor.ts | 21 ++++---- cursorscene.ts | 1 + fauxDatalogger.ts | 3 ++ liveDataViewer.ts | 40 +++++++++++---- recordedDataViewer.ts | 4 ++ sensorSelect.ts | 116 +++++++++++++++++++++--------------------- 7 files changed, 146 insertions(+), 79 deletions(-) diff --git a/button.ts b/button.ts index 8093597..002cc34 100644 --- a/button.ts +++ b/button.ts @@ -198,6 +198,8 @@ namespace microcode { private iconId: string | SImage private _ariaId: string public onClick?: (button: Button) => void + private selected: boolean + private dynamicBoundaryColorsOn: boolean public get ariaId(): string { return ( @@ -226,7 +228,8 @@ namespace microcode { ariaId?: string x: number y: number - onClick?: (button: Button) => void + onClick?: (button: Button) => void, + dynamicBoundaryColorsOn?: boolean }) { super( opts.x, @@ -238,12 +241,26 @@ namespace microcode { this._ariaId = opts.ariaId this.onClick = opts.onClick this.buildSprite(this.image_()) + + this.selected = false + + if (opts.dynamicBoundaryColorsOn == null) { + opts.dynamicBoundaryColorsOn = false + } + else { + this.dynamicBoundaryColorsOn = opts.dynamicBoundaryColorsOn + } } public getIcon() { return this.iconId } + + public toggleSelected(): void { + this.selected = !this.selected + } + private image_() { return typeof this.iconId == "string" ? icons.get(this.iconId) @@ -267,5 +284,26 @@ namespace microcode { this.onClick(this) } } + + + public draw() { + super.draw() + + if (this.dynamicBoundaryColorsOn) { + let boundaryColour = 2 // Red + if (this.selected) { + boundaryColour = 7 // green + } + + for (let dist = 1; dist <= 3; dist++) { + Screen.outlineBoundsXfrm( + this.xfrm, + this.icon.bounds, + dist, + boundaryColour + ) + } + } + } } } diff --git a/cursor.ts b/cursor.ts index 04972a8..c0c4075 100644 --- a/cursor.ts +++ b/cursor.ts @@ -94,6 +94,7 @@ namespace microcode { public click(): boolean { let target = this.navigator.getCurrent() //.sort((a, b) => a.z - b.z); if (target) { + target.toggleSelected() target.click() profile() return true @@ -116,18 +117,14 @@ namespace microcode { draw() { if (!this.visible) return - Screen.outlineBoundsXfrm( - this.xfrm, - this.size, - 1, - this.cursorOutlineColour - ) - Screen.outlineBoundsXfrm( - this.xfrm, - this.size, - 2, - this.cursorOutlineColour - ) + for (let dist = 1; dist <= 3; dist++) { + Screen.outlineBoundsXfrm( + this.xfrm, + this.size, + dist, + this.cursorOutlineColour + ) + } const text = accessibility.ariaToTooltip(this.ariaId) if (text) { diff --git a/cursorscene.ts b/cursorscene.ts index 0e1c4df..2752e35 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -1,4 +1,5 @@ namespace microcode { + export class CursorScene extends Scene { navigator: INavigator public cursor: Cursor diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 1a317a9..275ffa2 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -10,15 +10,18 @@ namespace microcode { static values: MetaData[] static numberOfRows: number static measurementOptions: MeasurementOpts + static isEmpty: boolean constructor(headers: string[], mOpts: MeasurementOpts) { FauxDataLogger.headers = headers FauxDataLogger.values = [] FauxDataLogger.numberOfRows = 0 FauxDataLogger.measurementOptions = mOpts + FauxDataLogger.isEmpty = true } public static log(data: string[]) { + FauxDataLogger.isEmpty = false FauxDataLogger.values.push({ id: this.values.length, data diff --git a/liveDataViewer.ts b/liveDataViewer.ts index b39ae14..eeed554 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -15,11 +15,13 @@ namespace microcode { * Display modes may be toggled per sensor */ export class LiveDataViewer extends Scene { - private dataBuffers: number[][]; - private bufferLimit = screen.width - (2 * WIDTH_BUFFER); private guiState: GUI_STATE + // For axis: + private xUnit: number + private yUnit: number + private sensors: Sensor[] constructor(app: App, sensors: Sensor[]) { @@ -28,6 +30,9 @@ namespace microcode { this.guiState = GUI_STATE.PLOTTING this.sensors = sensors + this.xUnit = 10 + this.yUnit = 10 + this.dataBuffers = [] for (let i = 0; i < this.sensors.length; i++) { this.dataBuffers.push([]) @@ -96,6 +101,30 @@ namespace microcode { } } + + draw_grid() { + for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=this.yUnit) { + Screen.drawLine( + Screen.LEFT_EDGE + colOffset, + Screen.TOP_EDGE, + Screen.LEFT_EDGE + colOffset, + Screen.HEIGHT, + 0x0 + ) + } + + for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=this.xUnit) { + Screen.drawLine( + Screen.LEFT_EDGE, + Screen.TOP_EDGE + rowOffset, + Screen.WIDTH, + Screen.TOP_EDGE + rowOffset, + 0x0 + ) + } + } + + /** * Display mode for plotting all incoming data on y axis * Presumes pre-processed this.dataBuffers; y values relative to screen.height @@ -111,13 +140,6 @@ namespace microcode { sensor.draw(WIDTH_BUFFER + 2, HEIGHT_BUFFER, colour) colour = (colour + 1) % 15 }) - - // this.dataBuffers.forEach(function(dataBuffer) { - // for (let i = 0; i < dataBuffer.length - 1; i++) { - // screen.drawLine(start + i, dataBuffer[i], start + i - 1, dataBuffer[i + 1], colour); - // } - // colour = (colour + 1) % 15 - // }) } // Display helper: diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 3c4e837..376a26e 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -96,6 +96,10 @@ namespace microcode { Screen.HEIGHT, 0xC ) + + if (FauxDataLogger.isEmpty) { + return; + } let rowOffset = 0 diff --git a/sensorSelect.ts b/sensorSelect.ts index cb320a0..7042f7b 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -14,41 +14,44 @@ namespace microcode { /* override */ startup() { super.startup() - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "accelerometer", - // ariaId: "accelerometer", - // x: -60, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "accelerometer", + ariaId: "accelerometer", + x: -60, + y: -34, + onClick: () => { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "pin_0", - // ariaId: "Pin 0", - // x: -30, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new PinSensor(TouchPin.P0)) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "pin_0", + ariaId: "Pin 0", + x: -30, + y: -34, + onClick: () => { + this.selectedSensors.push(new PinSensor(TouchPin.P0)) + }, + dynamicBoundaryColorsOn: true, + })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "magnet", - // ariaId: "S10", - // x: 0, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new MagnetSensor(Dimension.X)) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "magnet", + ariaId: "S10", + x: 0, + y: -34, + onClick: () => { + this.selectedSensors.push(new MagnetSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) // this.btns.push(new Button({ // parent: null, @@ -140,29 +143,29 @@ namespace microcode { //----------- - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "right_spin", - ariaId: "Compass", - x: -60, - y: 26, - onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "right_spin", + // ariaId: "Compass", + // x: -60, + // y: 26, + // onClick: () => { + // this.selectedSensors.push(new CompassHeadingSensor()) + // }, + // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "tile_button_a", - ariaId: "F3", - x: -30, - y: 26, - onClick: () => { - this.selectedSensors.push(new ButtonPressSensor()) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "tile_button_a", + // ariaId: "F3", + // x: -30, + // y: 26, + // onClick: () => { + // this.selectedSensors.push(new ButtonPressSensor()) + // }, + // })) // this.btns.push(new Button({ // parent: null, @@ -212,8 +215,7 @@ namespace microcode { 0xc ) - screen.printCenter("Select a sensor to log", 5) - + screen.printCenter("Select Sensors to log", 5) // Following 3 lines may be tabbed - results in same error regardless: From acca978ad71cab05af9236f606f7a0268cfddd3a Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 29 Feb 2024 16:15:48 +0000 Subject: [PATCH 031/109] Prototype 5 --- fauxDatalogger.ts | 2 +- liveDataViewer.ts | 192 ++++++++++++++++++++++++++++++------- measurementConfigSelect.ts | 1 - sensorSelect.ts | 118 ++++++++++++----------- sensors.ts | 16 ++++ tooltips.ts | 2 + 6 files changed, 236 insertions(+), 95 deletions(-) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 275ffa2..abf1629 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -6,7 +6,7 @@ namespace microcode { export class FauxDataLogger { static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] - static dateStamp = "21/02/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() + static dateStamp = "29/02/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() static values: MetaData[] static numberOfRows: number static measurementOptions: MeasurementOpts diff --git a/liveDataViewer.ts b/liveDataViewer.ts index eeed554..9ee6bf8 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -1,9 +1,11 @@ namespace microcode { - const WIDTH_BUFFER = 16; - const HEIGHT_BUFFER = 12; + const WIDTH_BUFFER = 20; + const HEIGHT_BUFFER = 14; + const MAX_ZOOM_DEPTH = 5; enum GUI_STATE { PLOTTING, + OSCILLOSCOPE_MODE, SENSOR_INFORMATION } @@ -18,32 +20,66 @@ namespace microcode { private dataBuffers: number[][]; private guiState: GUI_STATE + + // Oscilloscope offsets: + private oscXOffset = 0; + private oscYOffset = 0; + // For axis: private xUnit: number private yUnit: number + private zoomDepth: number private sensors: Sensor[] constructor(app: App, sensors: Sensor[]) { - super(app, "liveDataViewer") + super(app, "yo") this.color = 0 - this.guiState = GUI_STATE.PLOTTING + this.guiState = GUI_STATE.OSCILLOSCOPE_MODE this.sensors = sensors this.xUnit = 10 this.yUnit = 10 + this.zoomDepth = 1 this.dataBuffers = [] for (let i = 0; i < this.sensors.length; i++) { this.dataBuffers.push([]) } + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + () => { + if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { + this.guiState = GUI_STATE.OSCILLOSCOPE_MODE + } + + if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + if (this.zoomDepth < 5) { + this.zoomDepth += 1 + } + } + } + ) + control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, () => { - app.popScene() - app.pushScene(new Home(app)) + if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE && this.zoomDepth === 1) { + this.guiState = GUI_STATE.PLOTTING + } + + if (this.zoomDepth > 1) { + this.zoomDepth -= 1 + } + + else { + app.popScene() + app.pushScene(new Home(app)) + } } ) @@ -54,6 +90,10 @@ namespace microcode { if (this.guiState === GUI_STATE.PLOTTING) { this.guiState = GUI_STATE.SENSOR_INFORMATION } + + if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + this.oscYOffset = Math.max(this.oscYOffset - 5, -HEIGHT_BUFFER) + } } ) @@ -64,13 +104,46 @@ namespace microcode { if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { this.guiState = GUI_STATE.PLOTTING } + + if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + this.oscYOffset = Math.min(this.oscYOffset + 5, HEIGHT_BUFFER) + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.left.id, + () => { + if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + this.oscXOffset = Math.max(this.oscXOffset - 5, -WIDTH_BUFFER) + } } ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.right.id, + () => { + if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + this.oscXOffset = Math.min(this.oscXOffset + 5, WIDTH_BUFFER) + } + } + ) + } + + + /* override */ startup() { + super.startup() } update() { screen.fill(this.color); + this.sensors.forEach(function(sensor) { + sensor.readIntoBuffer() + }) + if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { screen.printCenter("Press DOWN for plot", 110) @@ -87,57 +160,94 @@ namespace microcode { ) colour = (colour + 1) % 15 } - } - else { - this.sensors.forEach(function(sensor) { - sensor.readIntoBuffer() + const oscModeBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "green_tick", + ariaId: "Oscilloscope", + x: 60, + y: 30, + onClick: () => { + this.guiState = GUI_STATE.OSCILLOSCOPE_MODE + } }) - // Draw: - this.plot() + oscModeBtn.draw() + } - basic.pause(100); + else { + this.plot() } + + basic.pause(100); } draw_grid() { - for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=this.yUnit) { - Screen.drawLine( - Screen.LEFT_EDGE + colOffset, - Screen.TOP_EDGE, - Screen.LEFT_EDGE + colOffset, - Screen.HEIGHT, - 0x0 - ) + for (let x = this.xUnit; x < Screen.HEIGHT - HEIGHT_BUFFER - this.yUnit; x += this.xUnit) { + screen.drawLine( + WIDTH_BUFFER + this.oscXOffset, + HEIGHT_BUFFER + x + this.oscYOffset, + Screen.WIDTH - WIDTH_BUFFER + this.oscXOffset, + HEIGHT_BUFFER + x + this.oscYOffset, + 0x1 + ); } - for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=this.xUnit) { - Screen.drawLine( - Screen.LEFT_EDGE, - Screen.TOP_EDGE + rowOffset, - Screen.WIDTH, - Screen.TOP_EDGE + rowOffset, - 0x0 - ) + for (let y = this.yUnit; y < Screen.WIDTH - WIDTH_BUFFER - this.xUnit; y += this.yUnit) { + screen.drawLine( + WIDTH_BUFFER + y + this.oscXOffset, + HEIGHT_BUFFER + this.xUnit + this.oscYOffset, + WIDTH_BUFFER + y + this.oscXOffset, + screen.height - HEIGHT_BUFFER + this.oscYOffset, + 0x1 + ); } } - /** * Display mode for plotting all incoming data on y axis * Presumes pre-processed this.dataBuffers; y values relative to screen.height * Bound to Microbit button A */ private plot() { - screen.printCenter("Press UP for info", 5) - this.draw_axes(); + screen.printCenter("Press UP for options", 5) let colour = 8; + // Axis scale: + screen.fillCircle( + WIDTH_BUFFER + this.oscXOffset, + HEIGHT_BUFFER + 8 + this.oscYOffset, + 3, + 3 + ) + + for (let i = 0; i < this.sensors.length; i++) { + let text = this.sensors[i].sensorMaxReading.toString(); + + if (i == this.sensors.length) { + text += " &" + } + screen.print( + text, + WIDTH_BUFFER - 20 + this.oscXOffset, + HEIGHT_BUFFER + 8 + (i * 8) + this.oscYOffset, + colour, + simage.font5, + ) + colour = (colour + 1) % 15 + } + + this.draw_grid() + this.draw_axes(); + + + // Draw data + // colour = 8; this.sensors.forEach(function(sensor) { - sensor.draw(WIDTH_BUFFER + 2, HEIGHT_BUFFER, colour) + sensor.draw(WIDTH_BUFFER + 2 + this.oscXOffset, HEIGHT_BUFFER - this.oscYOffset, colour) colour = (colour + 1) % 15 }) } @@ -145,8 +255,20 @@ namespace microcode { // Display helper: draw_axes() { for (let i = 0; i < 2; i++) { - screen.drawLine(WIDTH_BUFFER, screen.height - HEIGHT_BUFFER + i, screen.width - WIDTH_BUFFER, screen.height - HEIGHT_BUFFER + i, 5); - screen.drawLine(WIDTH_BUFFER + i, HEIGHT_BUFFER, WIDTH_BUFFER + i, screen.height - HEIGHT_BUFFER, 5); + screen.drawLine( + WIDTH_BUFFER + this.oscXOffset, + screen.height - HEIGHT_BUFFER + i + this.oscYOffset, + screen.width - WIDTH_BUFFER + this.oscXOffset, + screen.height - HEIGHT_BUFFER + i + this.oscYOffset, + 5 + ); + screen.drawLine( + WIDTH_BUFFER + i + this.oscXOffset, + HEIGHT_BUFFER + this.oscYOffset, + WIDTH_BUFFER + i + this.oscXOffset, + screen.height - HEIGHT_BUFFER + this.oscYOffset, + 5 + ); } } } diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index 8b487e4..df5913d 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -53,7 +53,6 @@ namespace microcode { if (this.guiState === GUI_STATE.DEFAULT) { this.app.popScene() this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - // this.app.pushScene(new Home(app)) } else { diff --git a/sensorSelect.ts b/sensorSelect.ts index 7042f7b..cac8430 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -14,44 +14,44 @@ namespace microcode { /* override */ startup() { super.startup() - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "accelerometer", - ariaId: "accelerometer", - x: -60, - y: -34, - onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - }, - dynamicBoundaryColorsOn: true, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "accelerometer", + // ariaId: "accelerometer", + // x: -60, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // }, + // dynamicBoundaryColorsOn: true, + // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "pin_0", - ariaId: "Pin 0", - x: -30, - y: -34, - onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P0)) - }, - dynamicBoundaryColorsOn: true, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "pin_0", + // ariaId: "Pin 0", + // x: -30, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new PinSensor(TouchPin.P0)) + // }, + // dynamicBoundaryColorsOn: true, + // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "magnet", - ariaId: "S10", - x: 0, - y: -34, - onClick: () => { - this.selectedSensors.push(new MagnetSensor(Dimension.X)) - }, - dynamicBoundaryColorsOn: true, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "magnet", + // ariaId: "S10", + // x: 0, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new MagnetSensor(Dimension.X)) + // }, + // dynamicBoundaryColorsOn: true, + // })) // this.btns.push(new Button({ // parent: null, @@ -92,29 +92,31 @@ namespace microcode { // })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "led_light_sensor", - // ariaId: "led_light_sensor", - // x: -30, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new LightSensor()) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "led_light_sensor", + ariaId: "led_light_sensor", + x: -30, + y: -4, + onClick: () => { + this.selectedSensors.push(new LightSensor()) + }, + dynamicBoundaryColorsOn: true, + })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "thermometer", - // ariaId: "thermometer", - // x: 0, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new TemperatureSensor()) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "thermometer", + ariaId: "thermometer", + x: 0, + y: -4, + onClick: () => { + this.selectedSensors.push(new TemperatureSensor()) + }, + dynamicBoundaryColorsOn: true, + })) // this.btns.push(new Button({ // parent: null, diff --git a/sensors.ts b/sensors.ts index 6368566..1579002 100644 --- a/sensors.ts +++ b/sensors.ts @@ -17,6 +17,7 @@ namespace microcode { private currentDisplayMode: number; private dataBuffer: number[] + private peakDataPoint: number[] constructor(sensorFn: () => number, name: string, @@ -30,6 +31,7 @@ namespace microcode { this.sensorMaxReading = sensorMaxReading this.numberOfDisplayModes = numberOfDisplayModes this.dataBuffer = [] + this.peakDataPoint = [0, screen.height] } cycleDisplayMode() { @@ -47,6 +49,7 @@ namespace microcode { readIntoBuffer(): void { if (this.dataBuffer.length >= Sensor.BUFFER_LIMIT) { this.dataBuffer.shift(); + this.peakDataPoint[0] -= 1 } this.dataBuffer.push(this.getReading()); } @@ -62,10 +65,23 @@ namespace microcode { * @param color */ draw(fromX: number, fromY: number, color: number): void { + if (this.peakDataPoint[0] > 0) { + screen.fillCircle( + fromX + this.peakDataPoint[0], + this.peakDataPoint[1], + 5, + 6 + ) + } + for (let i = 0; i < this.dataBuffer.length - 1; i++) { const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.sensorMaxReading) * (screen.height - fromY))) - fromY const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.sensorMaxReading) * (screen.height - fromY))) - fromY + if (y1 < this.peakDataPoint[1]) { + this.peakDataPoint = [i, y1] + } + screen.drawLine(fromX + i, y1, fromX + i - 1, y2, color); } } diff --git a/tooltips.ts b/tooltips.ts index b118ea7..7049a02 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -169,6 +169,8 @@ namespace microcode { else if (id == "Pin 2") res = "Pin 2" else if (id == "Volume") res = "Volume" else if (id == "Compass") res = "Compass" + else if (id == "Oscilloscope") res = "Oscilloscope" + return res } } \ No newline at end of file From fe73c9648c49fa4b6119a6aab8ecd4390b65321f Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 29 Feb 2024 16:49:08 +0000 Subject: [PATCH 032/109] Preparing LiveDataView for further Oscilloscope development, Resetting sensorSelect to display all --- liveDataViewer.ts | 44 ++++---- sensorSelect.ts | 255 ++++++++++++++++++++++------------------------ 2 files changed, 145 insertions(+), 154 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 9ee6bf8..76b08f9 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -217,28 +217,28 @@ namespace microcode { let colour = 8; // Axis scale: - screen.fillCircle( - WIDTH_BUFFER + this.oscXOffset, - HEIGHT_BUFFER + 8 + this.oscYOffset, - 3, - 3 - ) - - for (let i = 0; i < this.sensors.length; i++) { - let text = this.sensors[i].sensorMaxReading.toString(); - - if (i == this.sensors.length) { - text += " &" - } - screen.print( - text, - WIDTH_BUFFER - 20 + this.oscXOffset, - HEIGHT_BUFFER + 8 + (i * 8) + this.oscYOffset, - colour, - simage.font5, - ) - colour = (colour + 1) % 15 - } + // screen.fillCircle( + // WIDTH_BUFFER + this.oscXOffset, + // HEIGHT_BUFFER + 8 + this.oscYOffset, + // 3, + // 3 + // ) + + // for (let i = 0; i < this.sensors.length; i++) { + // let text = this.sensors[i].sensorMaxReading.toString(); + + // if (i == this.sensors.length) { + // text += " &" + // } + // screen.print( + // text, + // WIDTH_BUFFER - 20 + this.oscXOffset, + // HEIGHT_BUFFER + 8 + (i * 8) + this.oscYOffset, + // colour, + // simage.font5, + // ) + // colour = (colour + 1) % 15 + // } this.draw_grid() this.draw_axes(); diff --git a/sensorSelect.ts b/sensorSelect.ts index cac8430..8721ea8 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -14,82 +14,85 @@ namespace microcode { /* override */ startup() { super.startup() - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "accelerometer", - // ariaId: "accelerometer", - // x: -60, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "pin_0", - // ariaId: "Pin 0", - // x: -30, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new PinSensor(TouchPin.P0)) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "magnet", - // ariaId: "S10", - // x: 0, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new MagnetSensor(Dimension.X)) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "accelerometer", - // ariaId: "accelerometer", - // x: 30, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "right_turn", - // ariaId: "Pitch", - // x: 60, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) - // }, - // })) - //----------- + // Issues with Crashing when too many buttons are visible persist: + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "accelerometer", + ariaId: "accelerometer", + x: -60, + y: -34, + onClick: () => { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "pin_0", + ariaId: "Pin 0", + x: -30, + y: -34, + onClick: () => { + this.selectedSensors.push(new PinSensor(TouchPin.P0)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "magnet", + ariaId: "S10", + x: 0, + y: -34, + onClick: () => { + this.selectedSensors.push(new MagnetSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "accelerometer", + ariaId: "accelerometer", + x: 30, + y: -34, + onClick: () => { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "right_turn", + ariaId: "Pitch", + x: 60, + y: -34, + onClick: () => { + this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + }, + })) + + // ----------- - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "right_spin", - // ariaId: "Roll", - // x: -60, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new RotationSensor(Rotation.Roll)) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "right_spin", + ariaId: "Roll", + x: -60, + y: -4, + onClick: () => { + this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + }, + })) this.btns.push(new Button({ @@ -118,68 +121,56 @@ namespace microcode { dynamicBoundaryColorsOn: true, })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "finger_press", - // ariaId: "Logo Press", - // x: 30, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new LogoPressSensor()) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "speaker", - // ariaId: "Volume", - // x: 60, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new VolumeSensor()) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "finger_press", + ariaId: "Logo Press", + x: 30, + y: -4, + onClick: () => { + this.selectedSensors.push(new LogoPressSensor()) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "speaker", + ariaId: "Volume", + x: 60, + y: -4, + onClick: () => { + this.selectedSensors.push(new VolumeSensor()) + }, + })) //----------- - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "right_spin", - // ariaId: "Compass", - // x: -60, - // y: 26, - // onClick: () => { - // this.selectedSensors.push(new CompassHeadingSensor()) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "tile_button_a", - // ariaId: "F3", - // x: -30, - // y: 26, - // onClick: () => { - // this.selectedSensors.push(new ButtonPressSensor()) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "finger_press", - // ariaId: "Logo Press", - // x: 30, - // y: -26, - // onClick: () => { - // this.selectedSensors.push(new LogoPressSensor()) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "right_spin", + ariaId: "Compass", + x: -60, + y: 26, + onClick: () => { + this.selectedSensors.push(new CompassHeadingSensor()) + }, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "tile_button_a", + ariaId: "F3", + x: -30, + y: 26, + onClick: () => { + this.selectedSensors.push(new ButtonPressSensor()) + }, + })) this.btns.push(new Button({ parent: null, From 34f6e2816d04153f2d0471c47858433340476391 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 29 Feb 2024 20:37:41 +0000 Subject: [PATCH 033/109] New version of LiveData view, added ticker, named variables, scrolling, dynamic graph sizing, peak temperature info, graph data smoothing. --- liveDataViewer.ts | 181 +++++++++++++++++----------------- sensorSelect.ts | 245 +++++++++++++++++++++++----------------------- sensors.ts | 37 ++++--- 3 files changed, 234 insertions(+), 229 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 76b08f9..71a6363 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -1,7 +1,9 @@ namespace microcode { - const WIDTH_BUFFER = 20; - const HEIGHT_BUFFER = 14; + const WIDTH_BUFFER = 18; + const TOP_EDGE_BUFFER = 5; + const BOT_EDGE_BUFFER = 20; const MAX_ZOOM_DEPTH = 5; + const MAX_Y_SCOLL = -75 enum GUI_STATE { PLOTTING, @@ -20,10 +22,11 @@ namespace microcode { private dataBuffers: number[][]; private guiState: GUI_STATE - // Oscilloscope offsets: - private oscXOffset = 0; - private oscYOffset = 0; + private oscXOffset: number + private oscYOffset: number + + private yScrollOffset: number // For axis: private xUnit: number @@ -38,6 +41,10 @@ namespace microcode { this.guiState = GUI_STATE.OSCILLOSCOPE_MODE this.sensors = sensors + this.oscXOffset = 0 + this.oscYOffset = 0 + this.yScrollOffset = 0 + this.xUnit = 10 this.yUnit = 10 this.zoomDepth = 1 @@ -47,7 +54,6 @@ namespace microcode { this.dataBuffers.push([]) } - control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, @@ -88,12 +94,10 @@ namespace microcode { controller.up.id, () => { if (this.guiState === GUI_STATE.PLOTTING) { - this.guiState = GUI_STATE.SENSOR_INFORMATION + this.guiState = GUI_STATE.SENSOR_INFORMATION } - if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - this.oscYOffset = Math.max(this.oscYOffset - 5, -HEIGHT_BUFFER) - } + this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) } ) @@ -105,9 +109,7 @@ namespace microcode { this.guiState = GUI_STATE.PLOTTING } - if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - this.oscYOffset = Math.min(this.oscYOffset + 5, HEIGHT_BUFFER) - } + this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) } ) @@ -115,9 +117,9 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.left.id, () => { - if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - this.oscXOffset = Math.max(this.oscXOffset - 5, -WIDTH_BUFFER) - } + // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + // this.oscXOffset = Math.max(this.oscXOffset - 5, -WIDTH_BUFFER) + // } } ) @@ -125,9 +127,9 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - this.oscXOffset = Math.min(this.oscXOffset + 5, WIDTH_BUFFER) - } + // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + // this.oscXOffset = Math.min(this.oscXOffset + 5, WIDTH_BUFFER) + // } } ) } @@ -145,35 +147,19 @@ namespace microcode { }) if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { - screen.printCenter("Press DOWN for plot", 110) - - let colour = 8; - - for (let i = 0; i < this.sensors.length; i++) { - screen.print(this.sensors[i].name + " as", 10, 25 + (i * 20)) - screen.fillRect( - 130, - 25 + (i * 20), - 10, - 10, - colour - ) - colour = (colour + 1) % 15 - } - - const oscModeBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "green_tick", - ariaId: "Oscilloscope", - x: 60, - y: 30, - onClick: () => { - this.guiState = GUI_STATE.OSCILLOSCOPE_MODE - } - }) - - oscModeBtn.draw() + // const oscModeBtn = new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "green_tick", + // ariaId: "Oscilloscope", + // x: 60, + // y: 30, + // onClick: () => { + // this.guiState = GUI_STATE.OSCILLOSCOPE_MODE + // } + // }) + + // oscModeBtn.draw() } else { @@ -185,12 +171,12 @@ namespace microcode { draw_grid() { - for (let x = this.xUnit; x < Screen.HEIGHT - HEIGHT_BUFFER - this.yUnit; x += this.xUnit) { + for (let x = this.xUnit; x < Screen.HEIGHT - BOT_EDGE_BUFFER - this.yUnit; x += this.xUnit) { screen.drawLine( WIDTH_BUFFER + this.oscXOffset, - HEIGHT_BUFFER + x + this.oscYOffset, + TOP_EDGE_BUFFER + x + this.oscYOffset, Screen.WIDTH - WIDTH_BUFFER + this.oscXOffset, - HEIGHT_BUFFER + x + this.oscYOffset, + TOP_EDGE_BUFFER + x + this.oscYOffset, 0x1 ); } @@ -198,9 +184,9 @@ namespace microcode { for (let y = this.yUnit; y < Screen.WIDTH - WIDTH_BUFFER - this.xUnit; y += this.yUnit) { screen.drawLine( WIDTH_BUFFER + y + this.oscXOffset, - HEIGHT_BUFFER + this.xUnit + this.oscYOffset, + TOP_EDGE_BUFFER + this.xUnit + this.oscYOffset, WIDTH_BUFFER + y + this.oscXOffset, - screen.height - HEIGHT_BUFFER + this.oscYOffset, + screen.height - TOP_EDGE_BUFFER + this.oscYOffset, 0x1 ); } @@ -211,44 +197,57 @@ namespace microcode { * Presumes pre-processed this.dataBuffers; y values relative to screen.height * Bound to Microbit button A */ - private plot() { - screen.printCenter("Press UP for options", 5) - - let colour = 8; - - // Axis scale: - // screen.fillCircle( - // WIDTH_BUFFER + this.oscXOffset, - // HEIGHT_BUFFER + 8 + this.oscYOffset, - // 3, - // 3 - // ) - - // for (let i = 0; i < this.sensors.length; i++) { - // let text = this.sensors[i].sensorMaxReading.toString(); - - // if (i == this.sensors.length) { - // text += " &" - // } - // screen.print( - // text, - // WIDTH_BUFFER - 20 + this.oscXOffset, - // HEIGHT_BUFFER + 8 + (i * 8) + this.oscYOffset, - // colour, - // simage.font5, - // ) - // colour = (colour + 1) % 15 - // } - - this.draw_grid() - this.draw_axes(); + private plot() { + let color = 8; + // Sensor information, displayed below the plot: + for (let i = 0; i < this.sensors.length; i++) { + // (this.sensors[i].name.length * simage.font5.charWidth) + + screen.fillRect( + 2, + screen.height - BOT_EDGE_BUFFER + this.yScrollOffset + 15 + (i * 12), + 7, + 7, + color + ) + + screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + + " Peak " + this.sensors[i].peakDataPoint[1], + 14, + screen.height - BOT_EDGE_BUFFER + this.yScrollOffset + 15 + (i * 12), + color + ) + + color = (color + 1) % 15 + } + + this.draw_axes(); // Draw data - // colour = 8; + color = 8; this.sensors.forEach(function(sensor) { - sensor.draw(WIDTH_BUFFER + 2 + this.oscXOffset, HEIGHT_BUFFER - this.oscYOffset, colour) - colour = (colour + 1) % 15 + sensor.draw(WIDTH_BUFFER + 2 + this.oscXOffset, BOT_EDGE_BUFFER + this.oscYOffset - this.yScrollOffset, color) + // sensor.draw(WIDTH_BUFFER + 2 + this.oscXOffset, BOT_EDGE_BUFFER - this.oscYOffset + 1, color) + color = (color + 1) % 15 + }) + + + // Value of the latest readings + const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) + + // Draw the latest reading on the right-hand side: + color = 8; + latestReadings.forEach(function(reading) { + const y = Math.round(screen.height - ((reading[0] / reading[1]) * (screen.height))) - TOP_EDGE_BUFFER - BOT_EDGE_BUFFER + screen.print( + reading[0].toString(), + screen.width - WIDTH_BUFFER + 1, + y + this.yScrollOffset, + color, + simage.font5, + ) + color = (color + 1) % 15 }) } @@ -257,16 +256,16 @@ namespace microcode { for (let i = 0; i < 2; i++) { screen.drawLine( WIDTH_BUFFER + this.oscXOffset, - screen.height - HEIGHT_BUFFER + i + this.oscYOffset, + screen.height - BOT_EDGE_BUFFER + i + this.oscYOffset + this.yScrollOffset, screen.width - WIDTH_BUFFER + this.oscXOffset, - screen.height - HEIGHT_BUFFER + i + this.oscYOffset, + screen.height - BOT_EDGE_BUFFER + i + this.oscYOffset + this.yScrollOffset, 5 ); screen.drawLine( WIDTH_BUFFER + i + this.oscXOffset, - HEIGHT_BUFFER + this.oscYOffset, + TOP_EDGE_BUFFER + this.oscYOffset + this.yScrollOffset, WIDTH_BUFFER + i + this.oscXOffset, - screen.height - HEIGHT_BUFFER + this.oscYOffset, + screen.height - BOT_EDGE_BUFFER + this.oscYOffset + this.yScrollOffset, 5 ); } diff --git a/sensorSelect.ts b/sensorSelect.ts index 8721ea8..953bcb1 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -14,85 +14,84 @@ namespace microcode { /* override */ startup() { super.startup() - // Issues with Crashing when too many buttons are visible persist: - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "accelerometer", - ariaId: "accelerometer", - x: -60, - y: -34, - onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - }, - dynamicBoundaryColorsOn: true, - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "pin_0", - ariaId: "Pin 0", - x: -30, - y: -34, - onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P0)) - }, - dynamicBoundaryColorsOn: true, - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "magnet", - ariaId: "S10", - x: 0, - y: -34, - onClick: () => { - this.selectedSensors.push(new MagnetSensor(Dimension.X)) - }, - dynamicBoundaryColorsOn: true, - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "accelerometer", - ariaId: "accelerometer", - x: 30, - y: -34, - onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - }, - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "right_turn", - ariaId: "Pitch", - x: 60, - y: -34, - onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) - }, - })) - - // ----------- - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "right_spin", - ariaId: "Roll", - x: -60, - y: -4, - onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Roll)) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "accelerometer", + // ariaId: "accelerometer", + // x: -60, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // }, + // dynamicBoundaryColorsOn: true, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "pin_0", + // ariaId: "Pin 0", + // x: -30, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new PinSensor(TouchPin.P0)) + // }, + // dynamicBoundaryColorsOn: true, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "magnet", + // ariaId: "S10", + // x: 0, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new MagnetSensor(Dimension.X)) + // }, + // dynamicBoundaryColorsOn: true, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "accelerometer", + // ariaId: "accelerometer", + // x: 30, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // }, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "right_turn", + // ariaId: "Pitch", + // x: 60, + // y: -34, + // onClick: () => { + // this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + // }, + // })) + + // // ----------- + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "right_spin", + // ariaId: "Roll", + // x: -60, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + // }, + // })) this.btns.push(new Button({ @@ -121,56 +120,56 @@ namespace microcode { dynamicBoundaryColorsOn: true, })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "finger_press", - ariaId: "Logo Press", - x: 30, - y: -4, - onClick: () => { - this.selectedSensors.push(new LogoPressSensor()) - }, - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "speaker", - ariaId: "Volume", - x: 60, - y: -4, - onClick: () => { - this.selectedSensors.push(new VolumeSensor()) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "finger_press", + // ariaId: "Logo Press", + // x: 30, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new LogoPressSensor()) + // }, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "speaker", + // ariaId: "Volume", + // x: 60, + // y: -4, + // onClick: () => { + // this.selectedSensors.push(new VolumeSensor()) + // }, + // })) //----------- - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "right_spin", - ariaId: "Compass", - x: -60, - y: 26, - onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) - }, - })) - - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "tile_button_a", - ariaId: "F3", - x: -30, - y: 26, - onClick: () => { - this.selectedSensors.push(new ButtonPressSensor()) - }, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "right_spin", + // ariaId: "Compass", + // x: -60, + // y: 26, + // onClick: () => { + // this.selectedSensors.push(new CompassHeadingSensor()) + // }, + // })) + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "tile_button_a", + // ariaId: "F3", + // x: -30, + // y: 26, + // onClick: () => { + // this.selectedSensors.push(new ButtonPressSensor()) + // }, + // })) this.btns.push(new Button({ parent: null, diff --git a/sensors.ts b/sensors.ts index 1579002..9127dd2 100644 --- a/sensors.ts +++ b/sensors.ts @@ -3,6 +3,8 @@ namespace microcode { sensorFn: () => number, sensorName: string, }; + + const PLOT_SMOOTHING_CONSTANT = 8 export abstract class Sensor { private static BUFFER_LIMIT = 100; @@ -10,14 +12,14 @@ namespace microcode { sensorFn: () => number name: string - sensorMinReading: number - sensorMaxReading: number + minReading: number + maxReading: number + peakDataPoint: number[] private numberOfDisplayModes: number; private currentDisplayMode: number; private dataBuffer: number[] - private peakDataPoint: number[] constructor(sensorFn: () => number, name: string, @@ -27,11 +29,11 @@ namespace microcode { ) { this.sensorFn = sensorFn this.name = name - this.sensorMinReading = sensorMinReading - this.sensorMaxReading = sensorMaxReading + this.minReading = sensorMinReading + this.maxReading = sensorMaxReading this.numberOfDisplayModes = numberOfDisplayModes this.dataBuffer = [] - this.peakDataPoint = [0, screen.height] + this.peakDataPoint = [0, this.minReading] } cycleDisplayMode() { @@ -43,7 +45,7 @@ namespace microcode { } getNormalisedReading(): number{ - return this.sensorFn() / this.sensorMaxReading + return this.sensorFn() / this.maxReading } readIntoBuffer(): void { @@ -68,18 +70,23 @@ namespace microcode { if (this.peakDataPoint[0] > 0) { screen.fillCircle( fromX + this.peakDataPoint[0], - this.peakDataPoint[1], - 5, - 6 + Math.round(screen.height - ((this.peakDataPoint[1] / this.maxReading) * (screen.height - fromY))) - fromY, + 3, + 3 ) } for (let i = 0; i < this.dataBuffer.length - 1; i++) { - const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.sensorMaxReading) * (screen.height - fromY))) - fromY - const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.sensorMaxReading) * (screen.height - fromY))) - fromY + const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.maxReading) * (screen.height - fromY))) - fromY + const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.maxReading) * (screen.height - fromY))) - fromY + + if (this.dataBuffer[i] > this.peakDataPoint[1]) { + this.peakDataPoint = [i, this.dataBuffer[i]] + } - if (y1 < this.peakDataPoint[1]) { - this.peakDataPoint = [i, y1] + // Minimal data smoothing: + if (Math.abs(y1 - y2) <= PLOT_SMOOTHING_CONSTANT) { + screen.drawLine(fromX + i, y1, fromX + i - 1, y1, color); } screen.drawLine(fromX + i, y1, fromX + i - 1, y2, color); @@ -95,7 +102,7 @@ namespace microcode { export class TemperatureSensor extends Sensor { constructor() { - super(function () {return input.temperature()}, "Temperature", 0, 100, 1) + super(function () {return input.temperature()}, "Temp.", 0, 100, 1) } } From 89e63403d3bc07cdbfc79b57d2981733e916873b Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 1 Mar 2024 14:44:27 +0000 Subject: [PATCH 034/109] Rudimentary oscilloscope. --- cursorscene.ts | 16 ++--- liveDataViewer.ts | 153 +++++++++++++++++++++------------------------- 2 files changed, 76 insertions(+), 93 deletions(-) diff --git a/cursorscene.ts b/cursorscene.ts index 2752e35..f61879c 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -37,22 +37,22 @@ namespace microcode { /* override */ startup() { super.startup() - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.right.id, () => this.moveCursor(CursorDir.Right) ) - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.up.id, () => this.moveCursor(CursorDir.Up) ) - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.down.id, () => this.moveCursor(CursorDir.Down) ) - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.left.id, () => this.moveCursor(CursorDir.Left) @@ -60,17 +60,17 @@ namespace microcode { // click const click = () => this.cursor.click() - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, click ) - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.A.id + keymap.PLAYER_OFFSET, click ) - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, () => this.back() @@ -149,7 +149,7 @@ namespace microcode { /* override */ startup() { super.startup() - context.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, () => this.goBack1PageFn() diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 71a6363..3b7d897 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -22,16 +22,15 @@ namespace microcode { private dataBuffers: number[][]; private guiState: GUI_STATE - // Oscilloscope offsets: - private oscXOffset: number - private oscYOffset: number + private windowWidth: number + private windowHeight: number - private yScrollOffset: number + private windowWidthBuffer: number + private windowTopBuffer: number + private windowBotBuffer: number - // For axis: - private xUnit: number - private yUnit: number - private zoomDepth: number + private xScrollOffset: number + private yScrollOffset: number private sensors: Sensor[] @@ -41,13 +40,15 @@ namespace microcode { this.guiState = GUI_STATE.OSCILLOSCOPE_MODE this.sensors = sensors - this.oscXOffset = 0 - this.oscYOffset = 0 - this.yScrollOffset = 0 + this.windowWidth = Screen.WIDTH + this.windowHeight = Screen.HEIGHT - this.xUnit = 10 - this.yUnit = 10 - this.zoomDepth = 1 + this.windowWidthBuffer = 18 + this.windowTopBuffer = 5 + this.windowBotBuffer = 20 + + this.xScrollOffset = 0 + this.yScrollOffset = 0 this.dataBuffers = [] for (let i = 0; i < this.sensors.length; i++) { @@ -58,15 +59,22 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.A.id, () => { - if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { - this.guiState = GUI_STATE.OSCILLOSCOPE_MODE - } + // if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { + // this.guiState = GUI_STATE.OSCILLOSCOPE_MODE + // } - if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - if (this.zoomDepth < 5) { - this.zoomDepth += 1 - } - } + this.windowHeight = this.windowHeight + (Screen.HEIGHT * 0.33) + this.windowWidth = this.windowWidth + (Screen.WIDTH * 0.60) + + this.windowWidthBuffer = this.windowWidthBuffer - (18 * 0.60) + this.windowTopBuffer = this.windowTopBuffer - (5 * 0.33) + this.windowBotBuffer = this.windowBotBuffer - (20 * 0.33) + + // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { + // if (this.zoomDepth < 5) { + // this.zoomDepth += 1 + // } + // } } ) @@ -74,17 +82,18 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.B.id, () => { - if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE && this.zoomDepth === 1) { - this.guiState = GUI_STATE.PLOTTING - } - - if (this.zoomDepth > 1) { - this.zoomDepth -= 1 + if (this.windowHeight <= Screen.HEIGHT && this.windowWidth <= Screen.WIDTH) { + app.popScene() + app.pushScene(new Home(app)) } else { - app.popScene() - app.pushScene(new Home(app)) + this.windowHeight = this.windowHeight - (Screen.HEIGHT * 0.33) + this.windowWidth = this.windowWidth - (Screen.WIDTH * 0.60) + + this.windowWidthBuffer = this.windowWidthBuffer + (18 * 0.60) + this.windowTopBuffer = this.windowTopBuffer + (5 * 0.33) + this.windowBotBuffer = this.windowBotBuffer + (20 * 0.33) } } ) @@ -93,9 +102,9 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - if (this.guiState === GUI_STATE.PLOTTING) { - this.guiState = GUI_STATE.SENSOR_INFORMATION - } + // if (this.guiState === GUI_STATE.PLOTTING) { + // this.guiState = GUI_STATE.SENSOR_INFORMATION + // } this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) } @@ -105,9 +114,9 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { - if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { - this.guiState = GUI_STATE.PLOTTING - } + // if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { + // this.guiState = GUI_STATE.PLOTTING + // } this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) } @@ -118,7 +127,7 @@ namespace microcode { controller.left.id, () => { // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - // this.oscXOffset = Math.max(this.oscXOffset - 5, -WIDTH_BUFFER) + this.xScrollOffset = Math.min(this.xScrollOffset + 10, this.windowWidth) // } } ) @@ -128,7 +137,8 @@ namespace microcode { controller.right.id, () => { // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - // this.oscXOffset = Math.min(this.oscXOffset + 5, WIDTH_BUFFER) + this.xScrollOffset = Math.max(this.xScrollOffset - 10, -this.windowWidth) + // } } ) @@ -165,33 +175,9 @@ namespace microcode { else { this.plot() } - basic.pause(100); } - - draw_grid() { - for (let x = this.xUnit; x < Screen.HEIGHT - BOT_EDGE_BUFFER - this.yUnit; x += this.xUnit) { - screen.drawLine( - WIDTH_BUFFER + this.oscXOffset, - TOP_EDGE_BUFFER + x + this.oscYOffset, - Screen.WIDTH - WIDTH_BUFFER + this.oscXOffset, - TOP_EDGE_BUFFER + x + this.oscYOffset, - 0x1 - ); - } - - for (let y = this.yUnit; y < Screen.WIDTH - WIDTH_BUFFER - this.xUnit; y += this.yUnit) { - screen.drawLine( - WIDTH_BUFFER + y + this.oscXOffset, - TOP_EDGE_BUFFER + this.xUnit + this.oscYOffset, - WIDTH_BUFFER + y + this.oscXOffset, - screen.height - TOP_EDGE_BUFFER + this.oscYOffset, - 0x1 - ); - } - } - /** * Display mode for plotting all incoming data on y axis * Presumes pre-processed this.dataBuffers; y values relative to screen.height @@ -202,20 +188,18 @@ namespace microcode { // Sensor information, displayed below the plot: for (let i = 0; i < this.sensors.length; i++) { - // (this.sensors[i].name.length * simage.font5.charWidth) - screen.fillRect( 2, - screen.height - BOT_EDGE_BUFFER + this.yScrollOffset + 15 + (i * 12), + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + 15 + (i * 12), 7, 7, color ) - screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading - + " Peak " + this.sensors[i].peakDataPoint[1], + screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + + " Peak " + this.sensors[i].peakDataPoint[1], 14, - screen.height - BOT_EDGE_BUFFER + this.yScrollOffset + 15 + (i * 12), + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + 15 + (i * 12), color ) @@ -227,23 +211,22 @@ namespace microcode { // Draw data color = 8; this.sensors.forEach(function(sensor) { - sensor.draw(WIDTH_BUFFER + 2 + this.oscXOffset, BOT_EDGE_BUFFER + this.oscYOffset - this.yScrollOffset, color) - // sensor.draw(WIDTH_BUFFER + 2 + this.oscXOffset, BOT_EDGE_BUFFER - this.oscYOffset + 1, color) + sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset, color) color = (color + 1) % 15 }) - // Value of the latest readings - const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) - - // Draw the latest reading on the right-hand side: + // Draw the latest reading on the right-hand side as a Ticker: + color = 8; + const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) + latestReadings.forEach(function(reading) { - const y = Math.round(screen.height - ((reading[0] / reading[1]) * (screen.height))) - TOP_EDGE_BUFFER - BOT_EDGE_BUFFER + const y = Math.round(Screen.HEIGHT - ((reading[0] / reading[1]) * (Screen.HEIGHT))) screen.print( reading[0].toString(), - screen.width - WIDTH_BUFFER + 1, - y + this.yScrollOffset, + Screen.WIDTH + this.xScrollOffset - 18 + 1, + y + this.yScrollOffset - this.windowBotBuffer - this.windowTopBuffer, color, simage.font5, ) @@ -255,17 +238,17 @@ namespace microcode { draw_axes() { for (let i = 0; i < 2; i++) { screen.drawLine( - WIDTH_BUFFER + this.oscXOffset, - screen.height - BOT_EDGE_BUFFER + i + this.oscYOffset + this.yScrollOffset, - screen.width - WIDTH_BUFFER + this.oscXOffset, - screen.height - BOT_EDGE_BUFFER + i + this.oscYOffset + this.yScrollOffset, + this.windowWidthBuffer + this.xScrollOffset, + this.windowHeight - this.windowBotBuffer + i + this.yScrollOffset + this.yScrollOffset, + this.windowWidth - this.windowWidthBuffer + this.xScrollOffset, + this.windowHeight - this.windowBotBuffer + i + this.yScrollOffset + this.yScrollOffset, 5 ); screen.drawLine( - WIDTH_BUFFER + i + this.oscXOffset, - TOP_EDGE_BUFFER + this.oscYOffset + this.yScrollOffset, - WIDTH_BUFFER + i + this.oscXOffset, - screen.height - BOT_EDGE_BUFFER + this.oscYOffset + this.yScrollOffset, + this.windowWidthBuffer + i + this.xScrollOffset, + this.windowTopBuffer + this.yScrollOffset + this.yScrollOffset, + this.windowWidthBuffer + i + this.xScrollOffset, + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset, 5 ); } From fa22da280bc6b410cbd8f5ff3ba806f73fcac924 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 1 Mar 2024 15:04:04 +0000 Subject: [PATCH 035/109] Fixed zooming bug, added circle to centre for better zoom testing, next step is point selection - then 2 offsets to correct the this.windowWidth & this.windowBuffer (same for height) to adjust the screen so that it is perfectly centered upon the selected point. Then potentially add some data just above the selected point upon zooming. --- liveDataViewer.ts | 63 ++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 3b7d897..86bf220 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -32,6 +32,8 @@ namespace microcode { private xScrollOffset: number private yScrollOffset: number + private selectedXCoordinate: number + private sensors: Sensor[] constructor(app: App, sensors: Sensor[]) { @@ -50,6 +52,8 @@ namespace microcode { this.xScrollOffset = 0 this.yScrollOffset = 0 + this.selectedXCoordinate = (Screen.WIDTH / 2) + this.dataBuffers = [] for (let i = 0; i < this.sensors.length; i++) { this.dataBuffers.push([]) @@ -63,18 +67,13 @@ namespace microcode { // this.guiState = GUI_STATE.OSCILLOSCOPE_MODE // } - this.windowHeight = this.windowHeight + (Screen.HEIGHT * 0.33) - this.windowWidth = this.windowWidth + (Screen.WIDTH * 0.60) + this.windowHeight = this.windowHeight + (Screen.HEIGHT * 0.5) + this.windowWidth = this.windowWidth + (Screen.WIDTH * 0.5) - this.windowWidthBuffer = this.windowWidthBuffer - (18 * 0.60) - this.windowTopBuffer = this.windowTopBuffer - (5 * 0.33) - this.windowBotBuffer = this.windowBotBuffer - (20 * 0.33) + this.windowWidthBuffer = this.windowWidthBuffer - (18 * 0.5) + this.windowTopBuffer = this.windowTopBuffer - (5 * 0.5) + this.windowBotBuffer = this.windowBotBuffer - (20 * 0.5) - // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { - // if (this.zoomDepth < 5) { - // this.zoomDepth += 1 - // } - // } } ) @@ -88,12 +87,12 @@ namespace microcode { } else { - this.windowHeight = this.windowHeight - (Screen.HEIGHT * 0.33) - this.windowWidth = this.windowWidth - (Screen.WIDTH * 0.60) + this.windowHeight = this.windowHeight - (Screen.HEIGHT * 0.5) + this.windowWidth = this.windowWidth - (Screen.WIDTH * 0.5) - this.windowWidthBuffer = this.windowWidthBuffer + (18 * 0.60) - this.windowTopBuffer = this.windowTopBuffer + (5 * 0.33) - this.windowBotBuffer = this.windowBotBuffer + (20 * 0.33) + this.windowWidthBuffer = this.windowWidthBuffer + (18 * 0.5) + this.windowTopBuffer = this.windowTopBuffer + (5 * 0.5) + this.windowBotBuffer = this.windowBotBuffer + (20 * 0.5) } } ) @@ -107,6 +106,7 @@ namespace microcode { // } this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) + this.update() } ) @@ -119,6 +119,7 @@ namespace microcode { // } this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) + this.update() } ) @@ -128,6 +129,8 @@ namespace microcode { () => { // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { this.xScrollOffset = Math.min(this.xScrollOffset + 10, this.windowWidth) + + this.update() // } } ) @@ -139,6 +142,8 @@ namespace microcode { // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { this.xScrollOffset = Math.max(this.xScrollOffset - 10, -this.windowWidth) + + this.update() // } } ) @@ -156,32 +161,14 @@ namespace microcode { sensor.readIntoBuffer() }) - if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { - // const oscModeBtn = new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "green_tick", - // ariaId: "Oscilloscope", - // x: 60, - // y: 30, - // onClick: () => { - // this.guiState = GUI_STATE.OSCILLOSCOPE_MODE - // } - // }) - - // oscModeBtn.draw() - } + this.plot() - else { - this.plot() - } basic.pause(100); } /** * Display mode for plotting all incoming data on y axis * Presumes pre-processed this.dataBuffers; y values relative to screen.height - * Bound to Microbit button A */ private plot() { let color = 8; @@ -214,6 +201,14 @@ namespace microcode { sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset, color) color = (color + 1) % 15 }) + + + screen.fillCircle( + (Screen.WIDTH / 2),// + this.windowWidth - this.windowWidth, + (Screen.HEIGHT / 2),// + this.windowTopBuffer - this.windowBotBuffer, + 8, + 4 + ) // Draw the latest reading on the right-hand side as a Ticker: From 3196d8a2aca674ab2ba5680eb4bb9d24be984947 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 1 Mar 2024 15:13:00 +0000 Subject: [PATCH 036/109] Removed unneccesary components, documented code. --- liveDataViewer.ts | 79 ++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 86bf220..9a092b2 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -1,17 +1,7 @@ namespace microcode { - const WIDTH_BUFFER = 18; - const TOP_EDGE_BUFFER = 5; - const BOT_EDGE_BUFFER = 20; - const MAX_ZOOM_DEPTH = 5; + /** No information beyond this Y coordinate */ const MAX_Y_SCOLL = -75 - enum GUI_STATE { - PLOTTING, - OSCILLOSCOPE_MODE, - SENSOR_INFORMATION - } - - /** * One of the 3 main functionalities of MicroData * Allows for the live feed of a sensor to be plotted, @@ -19,9 +9,6 @@ namespace microcode { * Display modes may be toggled per sensor */ export class LiveDataViewer extends Scene { - private dataBuffers: number[][]; - private guiState: GUI_STATE - private windowWidth: number private windowHeight: number @@ -32,14 +19,15 @@ namespace microcode { private xScrollOffset: number private yScrollOffset: number + /* X coordinate that the user wants to zoom in on; adjust offsets to make this point centred, whilst zoomed */ private selectedXCoordinate: number + /* To plot */ private sensors: Sensor[] constructor(app: App, sensors: Sensor[]) { super(app, "yo") this.color = 0 - this.guiState = GUI_STATE.OSCILLOSCOPE_MODE this.sensors = sensors this.windowWidth = Screen.WIDTH @@ -54,19 +42,16 @@ namespace microcode { this.selectedXCoordinate = (Screen.WIDTH / 2) - this.dataBuffers = [] - for (let i = 0; i < this.sensors.length; i++) { - this.dataBuffers.push([]) - } + //-------------------------------- + // Oscilloscope Movement Controls: + //-------------------------------- + + // Zoom in: control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, () => { - // if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { - // this.guiState = GUI_STATE.OSCILLOSCOPE_MODE - // } - this.windowHeight = this.windowHeight + (Screen.HEIGHT * 0.5) this.windowWidth = this.windowWidth + (Screen.WIDTH * 0.5) @@ -77,6 +62,7 @@ namespace microcode { } ) + // Zoom out, if at default zoom (none), then go back to home control.onEvent( ControllerButtonEvent.Pressed, controller.B.id, @@ -101,12 +87,8 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - // if (this.guiState === GUI_STATE.PLOTTING) { - // this.guiState = GUI_STATE.SENSOR_INFORMATION - // } - this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) - this.update() + this.update() // For fast response to the above change } ) @@ -114,12 +96,8 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { - // if (this.guiState === GUI_STATE.SENSOR_INFORMATION) { - // this.guiState = GUI_STATE.PLOTTING - // } - this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) - this.update() + this.update() // For fast response to the above change } ) @@ -127,11 +105,8 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.left.id, () => { - // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { this.xScrollOffset = Math.min(this.xScrollOffset + 10, this.windowWidth) - - this.update() - // } + this.update() // For fast response to the above change } ) @@ -139,21 +114,17 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - // if (this.guiState === GUI_STATE.OSCILLOSCOPE_MODE) { this.xScrollOffset = Math.max(this.xScrollOffset - 10, -this.windowWidth) - - - this.update() - // } + this.update() // For fast response to the above change } ) } - /* override */ startup() { - super.startup() - } - + /** + * Request each sensor updates its buffers, + * Then draw to screen + */ update() { screen.fill(this.color); @@ -168,13 +139,15 @@ namespace microcode { /** * Display mode for plotting all incoming data on y axis - * Presumes pre-processed this.dataBuffers; y values relative to screen.height */ private plot() { let color = 8; - // Sensor information, displayed below the plot: + this.draw_axes(); + + // Write Sensor information, displayed below the plot: for (let i = 0; i < this.sensors.length; i++) { + // Colour used to represent this sensor, same colour as plotted & ticker: screen.fillRect( 2, this.windowHeight - this.windowBotBuffer + this.yScrollOffset + 15 + (i * 12), @@ -183,6 +156,7 @@ namespace microcode { color ) + // Name, reading / maximum, peak screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + " Peak " + this.sensors[i].peakDataPoint[1], 14, @@ -193,16 +167,15 @@ namespace microcode { color = (color + 1) % 15 } - this.draw_axes(); - // Draw data + // Draw data lines: color = 8; this.sensors.forEach(function(sensor) { sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset, color) color = (color + 1) % 15 }) - + // Draw circle in the screen centre for better testing: screen.fillCircle( (Screen.WIDTH / 2),// + this.windowWidth - this.windowWidth, (Screen.HEIGHT / 2),// + this.windowTopBuffer - this.windowBotBuffer, @@ -229,7 +202,9 @@ namespace microcode { }) } - // Display helper: + /** + * 2 Axis of Double-thickness each, in yellow + */ draw_axes() { for (let i = 0; i < 2; i++) { screen.drawLine( From 2a4ac3715fa2ec76a5c4063c8a6c1bf711c6f15f Mon Sep 17 00:00:00 2001 From: KierPalin <45743174+KierPalin@users.noreply.github.com> Date: Fri, 1 Mar 2024 15:16:54 +0000 Subject: [PATCH 037/109] README.md explanation of the project --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 125edc7..abc4402 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ -# microcode_mbit \ No newline at end of file +# MicroData +The objective of this ongoing project is to create an extension that utilises the Arcade shield and Microbit V2 to create an easy to use data science library. MicroData utilises the variety of sensors & buttons onboard the Microbit to: +⦁ Record data +⦁ Create graphs +⦁ View raw data & events in a tabular format +⦁ Perform simple data manipulation & creation + + +With the objective of allowing people to: +⦁ Teach and better understand Data Science +⦁ Experiment with Physical Computing +⦁ Perform Science Experiments +⦁ Explore the diverse features of the BBC Microbit V2 From 77fcb2a4594493bf4007944cddbd375f1ac7d8b1 Mon Sep 17 00:00:00 2001 From: KierPalin <45743174+KierPalin@users.noreply.github.com> Date: Fri, 1 Mar 2024 15:18:22 +0000 Subject: [PATCH 038/109] Update README.md formatting --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index abc4402..1c1ad04 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # MicroData The objective of this ongoing project is to create an extension that utilises the Arcade shield and Microbit V2 to create an easy to use data science library. MicroData utilises the variety of sensors & buttons onboard the Microbit to: -⦁ Record data -⦁ Create graphs -⦁ View raw data & events in a tabular format -⦁ Perform simple data manipulation & creation +* Record data +* Create graphs +* View raw data & events in a tabular format +* Perform simple data manipulation & creation With the objective of allowing people to: -⦁ Teach and better understand Data Science -⦁ Experiment with Physical Computing -⦁ Perform Science Experiments -⦁ Explore the diverse features of the BBC Microbit V2 +* Teach and better understand Data Science +* Experiment with Physical Computing +* Perform Science Experiments +* Explore the diverse features of the BBC Microbit V2 From 2b659e0f8735433d35e558143a438a5d93bc2903 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 1 Mar 2024 16:30:06 +0000 Subject: [PATCH 039/109] Button Issue appears to be resolved, add dynamicColouring to buttons, updated version count to be 'Prototype 6' --- home.ts | 2 +- sensorSelect.ts | 254 +++++++++++++++++++++++++----------------------- 2 files changed, 131 insertions(+), 125 deletions(-) diff --git a/home.ts b/home.ts index 2de2a4b..36678b3 100644 --- a/home.ts +++ b/home.ts @@ -59,7 +59,7 @@ namespace microcode { const font = simage.font5 Screen.print( "Prototype 3", - Screen.RIGHT_EDGE - font.charWidth * "Prototype 3".length, + Screen.RIGHT_EDGE - font.charWidth * "Prototype 6".length, Screen.BOTTOM_EDGE - font.charHeight - 1, 0xb, font diff --git a/sensorSelect.ts b/sensorSelect.ts index 953bcb1..c7b27eb 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -16,82 +16,85 @@ namespace microcode { // Issues with Crashing when too many buttons are visible persist: - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "accelerometer", - // ariaId: "accelerometer", - // x: -60, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "pin_0", - // ariaId: "Pin 0", - // x: -30, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new PinSensor(TouchPin.P0)) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "magnet", - // ariaId: "S10", - // x: 0, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new MagnetSensor(Dimension.X)) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "accelerometer", - // ariaId: "accelerometer", - // x: 30, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "right_turn", - // ariaId: "Pitch", - // x: 60, - // y: -34, - // onClick: () => { - // this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) - // }, - // })) - - // // ----------- - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "right_spin", - // ariaId: "Roll", - // x: -60, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new RotationSensor(Rotation.Roll)) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "accelerometer", + ariaId: "accelerometer", + x: -60, + y: -34, + onClick: () => { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "pin_0", + ariaId: "Pin 0", + x: -30, + y: -34, + onClick: () => { + this.selectedSensors.push(new PinSensor(TouchPin.P0)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "magnet", + ariaId: "S10", + x: 0, + y: -34, + onClick: () => { + this.selectedSensors.push(new MagnetSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "accelerometer", + ariaId: "accelerometer", + x: 30, + y: -34, + onClick: () => { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "right_turn", + ariaId: "Pitch", + x: 60, + y: -34, + onClick: () => { + this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + }, + dynamicBoundaryColorsOn: true, + })) + + // ----------- + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "right_spin", + ariaId: "Roll", + x: -60, + y: -4, + onClick: () => { + this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + }, + dynamicBoundaryColorsOn: true, + })) this.btns.push(new Button({ @@ -120,56 +123,60 @@ namespace microcode { dynamicBoundaryColorsOn: true, })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "finger_press", - // ariaId: "Logo Press", - // x: 30, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new LogoPressSensor()) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "speaker", - // ariaId: "Volume", - // x: 60, - // y: -4, - // onClick: () => { - // this.selectedSensors.push(new VolumeSensor()) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "finger_press", + ariaId: "Logo Press", + x: 30, + y: -4, + onClick: () => { + this.selectedSensors.push(new LogoPressSensor()) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "speaker", + ariaId: "Volume", + x: 60, + y: -4, + onClick: () => { + this.selectedSensors.push(new VolumeSensor()) + }, + dynamicBoundaryColorsOn: true, + })) //----------- - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "right_spin", - // ariaId: "Compass", - // x: -60, - // y: 26, - // onClick: () => { - // this.selectedSensors.push(new CompassHeadingSensor()) - // }, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "tile_button_a", - // ariaId: "F3", - // x: -30, - // y: 26, - // onClick: () => { - // this.selectedSensors.push(new ButtonPressSensor()) - // }, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "right_spin", + ariaId: "Compass", + x: -60, + y: 26, + onClick: () => { + this.selectedSensors.push(new CompassHeadingSensor()) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "tile_button_a", + ariaId: "F3", + x: -30, + y: 26, + onClick: () => { + this.selectedSensors.push(new ButtonPressSensor()) + }, + dynamicBoundaryColorsOn: true, + })) this.btns.push(new Button({ parent: null, @@ -216,8 +223,7 @@ namespace microcode { // }) for (let i = 0; i < this.btns.length; ++i) { - const btn = this.btns[i] - if (!btn.isOffScreenX()) btn.draw() + this.btns[i].draw() } // Identical: From aa8de92cea268566860e05bda276f295976037e4 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 1 Mar 2024 18:17:14 +0000 Subject: [PATCH 040/109] New screen for the Recorded Data view; presenting option for metadata, raw data & graph generation. --- fauxDatalogger.ts | 3 +- recordedDataViewer.ts | 132 +++++++++++++++++++++++------------------- tooltips.ts | 5 ++ 3 files changed, 79 insertions(+), 61 deletions(-) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index abf1629..38d417e 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -10,14 +10,13 @@ namespace microcode { static values: MetaData[] static numberOfRows: number static measurementOptions: MeasurementOpts - static isEmpty: boolean + static isEmpty: boolean = true constructor(headers: string[], mOpts: MeasurementOpts) { FauxDataLogger.headers = headers FauxDataLogger.values = [] FauxDataLogger.numberOfRows = 0 FauxDataLogger.measurementOptions = mOpts - FauxDataLogger.isEmpty = true } public static log(data: string[]) { diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 376a26e..6f0ad9a 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -3,66 +3,70 @@ namespace microcode { const MAX_ROWS = 10 const enum DISPLAY_MODE { + META_DATA_VIEW, DATA_VIEW, - GRAPH_GENERATION, - METADATA_MODE, + GRAPH_VIEW, + SELECT_SCREEN, } - - export class RecordedDataViewer extends Scene { + + export class RecordedDataViewer extends CursorSceneWithPriorPage { private scrollOffset: number; - private current_mode: DISPLAY_MODE; + private guiState: DISPLAY_MODE; private saveSlot: number - constructor(app: App, saveSlot: number) { - super(app, "dataViewer") + private metaDataBtn: Button + private dataViewBtn: Button + private graphViewBtn: Button - this.scrollOffset = 0 - this.current_mode = DISPLAY_MODE.METADATA_MODE + constructor(app: App, saveSlot: number) { + super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) + this.guiState = DISPLAY_MODE.SELECT_SCREEN this.saveSlot = saveSlot + } - control.onEvent( - ControllerButtonEvent.Pressed, - controller.B.id, - () => { - switch (this.current_mode) { - case DISPLAY_MODE.DATA_VIEW: - this.current_mode = DISPLAY_MODE.METADATA_MODE - break; - - case DISPLAY_MODE.GRAPH_GENERATION: - this.current_mode = DISPLAY_MODE.DATA_VIEW - break; - - case DISPLAY_MODE.METADATA_MODE: - app.popScene() - app.pushScene(new Home(this.app)) - break; - - default: - app.popScene() - app.pushScene(new Home(this.app)) - break; - } - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.down.id, - () => { - this.scrollOffset = Math.min(this.scrollOffset + 1, MAX_ROWS) - } - ) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.up.id, - () => { - this.scrollOffset = Math.max(this.scrollOffset - 1, 0) - } - ) + /* override */ startup() { + super.startup() + + this.metaDataBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "linear_graph", + ariaId: "Meta Data", + x: -50, + y: 30, + onClick: () => { + this.guiState = DISPLAY_MODE.META_DATA_VIEW + }, + }) + + this.dataViewBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "edit_program", + ariaId: "View Data", + x: 0, + y: 30, + onClick: () => { + this.guiState = DISPLAY_MODE.DATA_VIEW + }, + }) + + this.graphViewBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "largeDisk", + ariaId: "View Graph", + x: 50, + y: 30, + onClick: () => { + this.guiState = DISPLAY_MODE.GRAPH_VIEW + }, + }) + + this.navigator.addButtons([this.metaDataBtn, this.dataViewBtn, this.graphViewBtn]) } + draw_grid() { const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) @@ -88,7 +92,7 @@ namespace microcode { } } - update() { + draw() { Screen.fillRect( Screen.LEFT_EDGE, Screen.TOP_EDGE, @@ -98,20 +102,28 @@ namespace microcode { ) if (FauxDataLogger.isEmpty) { + screen.printCenter("No data has been recorded", Screen.HALF_HEIGHT) return; } - + let rowOffset = 0 - switch (this.current_mode) { - case DISPLAY_MODE.METADATA_MODE: + switch (this.guiState) { + case DISPLAY_MODE.SELECT_SCREEN: + screen.printCenter("Recorded Data Options", 5) + this.metaDataBtn.draw() + this.dataViewBtn.draw() + this.graphViewBtn.draw() + break + + case DISPLAY_MODE.META_DATA_VIEW: screen.printCenter("MetaData for Save " + this.saveSlot, 2) control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, () => { - this.current_mode = DISPLAY_MODE.DATA_VIEW + this.guiState = DISPLAY_MODE.DATA_VIEW } ) @@ -184,10 +196,6 @@ namespace microcode { } break; - case DISPLAY_MODE.GRAPH_GENERATION: - - break; - case DISPLAY_MODE.DATA_VIEW: this.draw_grid() @@ -237,10 +245,16 @@ namespace microcode { rowOffset += rowDeltaBuffer } break; + + case DISPLAY_MODE.DATA_VIEW: + + break default: break; } + + super.draw() } } } \ No newline at end of file diff --git a/tooltips.ts b/tooltips.ts index 7049a02..b0016c1 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -170,6 +170,11 @@ namespace microcode { else if (id == "Volume") res = "Volume" else if (id == "Compass") res = "Compass" else if (id == "Oscilloscope") res = "Oscilloscope" + + else if (id == "Meta Data") res = "Meta Data" + else if (id == "View Data") res = "View Data" + else if (id == "View Graph") res = "View Graph" + return res } From 69613d63fa99e8c58624eadb5c3339728b01d9cd Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 2 Mar 2024 13:42:16 +0000 Subject: [PATCH 041/109] added dataViewSelect.ts, splitting responsibility between selecting between 'metadata', 'data view' & 'graph generation' selection & their implementations. --- dataViewSelect.ts | 80 +++++++++++++++++++++++++++++++++++++ home.ts | 2 +- pxt.json | 1 + recordedDataViewer.ts | 92 +++++++++++++------------------------------ 4 files changed, 110 insertions(+), 65 deletions(-) create mode 100644 dataViewSelect.ts diff --git a/dataViewSelect.ts b/dataViewSelect.ts new file mode 100644 index 0000000..58ef01c --- /dev/null +++ b/dataViewSelect.ts @@ -0,0 +1,80 @@ +namespace microcode { + export class DataViewSelect extends CursorSceneWithPriorPage { + private metaDataBtn: Button + private dataViewBtn: Button + private graphViewBtn: Button + + constructor(app: App) { + super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) + } + + /* override */ startup() { + super.startup() + + this.metaDataBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "linear_graph", + ariaId: "Meta Data", + x: -50, + y: 30, + onClick: () => { + app.popScene() + app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW)) + }, + }) + + this.dataViewBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "edit_program", + ariaId: "View Data", + x: 0, + y: 30, + onClick: () => { + app.popScene() + app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.DATA_VIEW)) + }, + }) + + this.graphViewBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "largeDisk", + ariaId: "View Graph", + x: 50, + y: 30, + onClick: () => { + app.popScene() + app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.GRAPH_VIEW)) + }, + }) + + this.navigator.addButtons([this.metaDataBtn, this.dataViewBtn, this.graphViewBtn]) + } + + draw() { + Screen.fillRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE, + Screen.WIDTH, + Screen.HEIGHT, + 0xC + ) + + if (FauxDataLogger.isEmpty) { + screen.printCenter("No data has been recorded", Screen.HALF_HEIGHT) + return; + } + + else { + screen.printCenter("Recorded Data Options", 5) + this.metaDataBtn.draw() + this.dataViewBtn.draw() + this.graphViewBtn.draw() + } + + super.draw() + } + } +} \ No newline at end of file diff --git a/home.ts b/home.ts index 36678b3..f6ee42a 100644 --- a/home.ts +++ b/home.ts @@ -46,7 +46,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new RecordedDataViewer(this.app, 1)) + this.app.pushScene(new DataViewSelect(this.app)) }, }) diff --git a/pxt.json b/pxt.json index e6de6d9..99ecb28 100644 --- a/pxt.json +++ b/pxt.json @@ -51,6 +51,7 @@ "fauxDatalogger.ts", "sceneFactory.ts", "userOptions.ts", + "dataViewSelect.ts", "sensors.ts" ], diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index 6f0ad9a..bdc0c9e 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -2,71 +2,45 @@ namespace microcode { const HEADER_OFFSET = 17 const MAX_ROWS = 10 - const enum DISPLAY_MODE { + export const enum DATA_VIEW_DISPLAY_MODE { META_DATA_VIEW, DATA_VIEW, GRAPH_VIEW, - SELECT_SCREEN, } - export class RecordedDataViewer extends CursorSceneWithPriorPage { - private scrollOffset: number; - private guiState: DISPLAY_MODE; + export class RecordedDataViewer extends Scene { + private guiState: DATA_VIEW_DISPLAY_MODE private saveSlot: number - private metaDataBtn: Button - private dataViewBtn: Button - private graphViewBtn: Button + private scrollOffset: number - constructor(app: App, saveSlot: number) { - super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) - this.guiState = DISPLAY_MODE.SELECT_SCREEN + constructor(app: App, saveSlot: number, guiState: DATA_VIEW_DISPLAY_MODE) { + super(app, "recordedDataViewer") + this.guiState = guiState this.saveSlot = saveSlot + this.scrollOffset = 0 } /* override */ startup() { super.startup() - this.metaDataBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "linear_graph", - ariaId: "Meta Data", - x: -50, - y: 30, - onClick: () => { - this.guiState = DISPLAY_MODE.META_DATA_VIEW - }, - }) - - this.dataViewBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "edit_program", - ariaId: "View Data", - x: 0, - y: 30, - onClick: () => { - this.guiState = DISPLAY_MODE.DATA_VIEW - }, - }) - - this.graphViewBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "largeDisk", - ariaId: "View Graph", - x: 50, - y: 30, - onClick: () => { - this.guiState = DISPLAY_MODE.GRAPH_VIEW - }, - }) + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => { + this.scrollOffset = Math.min(this.scrollOffset + 1, MAX_ROWS) + } + ) - this.navigator.addButtons([this.metaDataBtn, this.dataViewBtn, this.graphViewBtn]) + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + this.scrollOffset = Math.max(this.scrollOffset - 1, 0) + } + ) } - draw_grid() { const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) @@ -101,29 +75,17 @@ namespace microcode { 0xC ) - if (FauxDataLogger.isEmpty) { - screen.printCenter("No data has been recorded", Screen.HALF_HEIGHT) - return; - } - let rowOffset = 0 switch (this.guiState) { - case DISPLAY_MODE.SELECT_SCREEN: - screen.printCenter("Recorded Data Options", 5) - this.metaDataBtn.draw() - this.dataViewBtn.draw() - this.graphViewBtn.draw() - break - - case DISPLAY_MODE.META_DATA_VIEW: + case DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW: screen.printCenter("MetaData for Save " + this.saveSlot, 2) control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, () => { - this.guiState = DISPLAY_MODE.DATA_VIEW + this.guiState = DATA_VIEW_DISPLAY_MODE.DATA_VIEW } ) @@ -176,6 +138,8 @@ namespace microcode { ] } + + for (let i = this.scrollOffset; i < metadata.length; i++) { Screen.print( metadata[i].col1, @@ -196,7 +160,7 @@ namespace microcode { } break; - case DISPLAY_MODE.DATA_VIEW: + case DATA_VIEW_DISPLAY_MODE.DATA_VIEW: this.draw_grid() // const data = [ @@ -246,7 +210,7 @@ namespace microcode { } break; - case DISPLAY_MODE.DATA_VIEW: + case DATA_VIEW_DISPLAY_MODE.DATA_VIEW: break From d07b2bf55a37efc00b803325a906d3bfaa27cbc3 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 2 Mar 2024 14:46:50 +0000 Subject: [PATCH 042/109] Added assets for compass, pin 1 & pin 2, adjusted the MicroData logo so that it is centred, smaller t, larger D. Adjusted the position of the buttons within sensorSelect to better make use of the space. --- assets.ts | 108 ++++++++++++++++++++++++++++-------- sensorSelect.ts | 144 +++++++++++++++++++++++++++++++----------------- 2 files changed, 178 insertions(+), 74 deletions(-) diff --git a/assets.ts b/assets.ts index 45242fb..6ab1559 100644 --- a/assets.ts +++ b/assets.ts @@ -65,6 +65,8 @@ namespace microcode { if (name == "magnet") return icondb.magnet if (name == "pin_0") return icondb.pin_0 + if (name == "pin_1") return icondb.pin_1 + if (name == "pin_2") return icondb.pin_2 if (name == "right_turn") return icondb.car_right_turn if (name == "right_spin") return icondb.car_right_spin @@ -72,7 +74,11 @@ namespace microcode { if (name == "speaker") return icondb.speaker if (name == "tile_button_a") return icondb.tile_button_a - // if (name == "tile_button_a") return icondb.tile_button_a + if (name == "compass") return icondb.compass + + // if (name == "compass") return icondb.compass + // if (name == "compass") return icondb.compass + // if (name == "compass") return icondb.compass extraImage = null extraSamples(name) // only for web app @@ -83,28 +89,28 @@ namespace microcode { } export const wordLogo = img` - .111111.......111111...1111................................................11111111111........................1111...................................... - 11bbbbbb.....11bbbbbb.11bbbb...............................................1bbbbbbbbbbff.....................11bbbb..................................... - 1bbbbbbbb...11bbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbf....................1bbbbbf.................................... - 1bbbbbbbbb.11bbbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbbf...................1bbbbbf.................................... - 1bbbbbbbbbb1bbbbbbbbbf1bbbbbf..............................................1bbbbf..11bbbbf...................1bbbbbf.................................... - 1bbbbbbbbbbbbbbbbbbbbf.bbbbff..............................................1bbbb....1bbbbf...................1bbbbbf.................................... - 1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111.....1bbbb....1bbbbf....11111111.......1bbbbbb11111111111..11111111............... - 1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...1bbbb....1bbbbf...1bbbbbbbbbf.....1bbbbbbbbbbbbbbbfff1bbbbbbbbbf............. - 1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbb....1bbbbf..1bbbbbbbbbbbbf...11bbbbbbbbbbbbbbf.1bbbbbbbbbbbbf........... - 1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbb....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbff.........1bbbbbbbbbbbbbf........... - 1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.1bbbb....1bbbbf.1bbbbbbbbbbbbbf...11bbbbbf.........1bbbbbbbbbbbbbbf.......... - 1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbfbbbbb....1bbbbf.1bbbbffffbbbbbf...1bbbbbbf.........1bbbbffffbbbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbfbbbbb....1bbbbf.1bbbff...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbfbbbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbfbbbbb....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf.........1bbbbf...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbfbbbbb....1bbbbf.1bbbbb...1bbbbf...1bbbbbbf.........1bbbbb...1bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbfbbbbb...11bbbbf.1bbbbb111bbbbbf...1bbbbbbf.........1bbbbbb111bbbbbf.......... - 1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbffbbbbbbbbbbbbbbf.bbbbbbbbbbbbbb1111.bbbbbbbb111111111bbbbbbbbbbbbbbbb1111...... - 1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.bbbbbbbbbbbbbbf.1bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf..... - 1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff.bbbbbbbbbbbbbf...bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbff..... - .bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff..fbbbbbbbbbbff.....fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbff..... - ..fffff.........fffff...ffff......fffffff......ffff.............fffffff.....ffffffffff.........ffffffffffffff....ffffffffffffff....ffffffffffffffff...... + ....111111.......111111...1111................................................11111111111.........................1111................................. + ...11bbbbbb.....11bbbbbb.11bbbb...............................................1bbbbbbbbbbff......................11bbbb................................ + ...1bbbbbbbb...11bbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbff.....................1bbbbbf............................... + ...1bbbbbbbbb.11bbbbbbbbf1bbbbbf..............................................1bbbbbbbbbbbbbf....................1bbbbbf............................... + ...1bbbbbbbbbb1bbbbbbbbbf1bbbbbf..............................................1bbbbf..bbbbbbf....................1bbbbbf............................... + ...1bbbbbbbbbbbbbbbbbbbbf.bbbbff..............................................1bbbb....bbbbbbf...................1bbbbbf............................... + ...1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111.....1bbbb.....1bbbbf....11111111.......1bbbbbb11111111....11111111........... + ...1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...1bbbb.....1bbbbf...1bbbbbbbbbf.....1bbbbbbbbbbbbfff..1bbbbbbbbbf......... + ...1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbb.....1bbbbf..1bbbbbbbbbbbbf...1bbbbbbbbbbbbf...1bbbbbbbbbbbbf....... + ...1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbb.....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbff........1bbbbbbbbbbbbbf....... + ...1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.1bbbb.....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbbf........1bbbbbbbbbbbbbbf...... + ...1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbfbbbbb.....1bbbbf.1bbbbffffbbbbbf...1bbbbbbf........1bbbbffffbbbbbbf...... + ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbfbbbbb.....1bbbbf.1bbbff...1bbbbf...1bbbbbbf........1bbbbf...1bbbbbf...... + ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf.....ffff.1bbbbbf.......1bbbbf....1bbbbfbbbbb.....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf........1bbbbf...1bbbbbf...... + ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbfbbbbb.....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf........1bbbbf...1bbbbbf...... + ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbfbbbbb....bbbbbbf.1bbbbb...1bbbbf...1bbbbbbf........1bbbbb...1bbbbbf...... + ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbfbbbbb...bbbbbbbf.1bbbbb111bbbbbf...1bbbbbbf........1bbbbbb111bbbbbf...... + ...1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbffbbbbbbbbbbbbbbf..bbbbbbbbbbbbb1111.bbbbbbbb1111111bbbbbbbbbbbbbbbb1111... + ...1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.bbbbbbbbbbbbbbf..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf.. + ...1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff.bbbbbbbbbbbbbff..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbff.. + ....bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff..bbbbbbbbbbbff.....fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbff.. + .....fffff.........fffff...ffff......fffffff......ffff.............fffffff....bffffffffff.........ffffffffffffff....ffffffffffff....ffffffffffffffff... ` export const microbitLogo = img` @@ -975,6 +981,62 @@ export const showScreen = img` 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ` + export const pin_1 = img` + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 4 4 4 4 4 1 1 4 4 4 4 1 1 + 1 4 4 4 1 1 4 4 4 4 4 4 4 1 1 + 1 4 4 4 1 1 1 4 4 4 4 4 4 1 1 + 1 4 4 4 1 1 4 4 1 1 4 4 4 1 1 + 1 4 4 4 4 4 4 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 4 4 4 4 4 4 1 + 1 1 4 1 1 1 1 4 4 4 4 4 4 4 4 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +` + export const pin_2 = img` + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 4 4 4 4 4 1 1 4 4 4 4 1 1 + 1 4 4 4 1 1 4 4 4 4 4 4 4 4 1 + 1 4 4 4 1 1 1 4 4 4 1 1 4 4 4 + 1 4 4 4 1 1 4 4 4 1 1 1 4 4 4 + 1 4 4 4 4 4 4 1 1 1 1 1 4 4 4 + 1 4 4 4 1 1 1 1 1 1 1 4 4 4 1 + 1 4 4 4 1 1 1 1 1 1 1 4 4 4 1 + 1 4 4 4 1 1 1 1 1 1 4 4 4 1 1 + 1 4 4 4 1 1 1 1 1 4 4 4 4 1 1 + 1 4 4 4 1 1 1 1 4 4 4 4 1 1 1 + 1 4 4 4 1 1 1 4 4 4 4 4 4 4 4 + 1 1 4 1 1 1 1 4 4 4 4 4 4 4 4 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +` + + export const compass = img` + 1 1 1 1 5 5 5 5 5 5 5 1 1 1 1 + 1 1 1 5 5 5 5 5 5 5 5 5 1 1 1 + 1 1 5 5 5 f f f f f 5 5 5 1 1 + 1 5 5 5 f f f f f f 2 5 5 5 1 + 5 5 5 f f f f f f 2 2 2 5 5 5 + 5 5 f f f f f f 2 2 2 f f 5 5 + 5 f f f f f f 2 2 2 f f f f 5 + 5 f f f f f 1 1 1 2 f f f f 5 + 5 f f f f 8 1 1 1 f f f f f 5 + 5 f f f 8 8 1 1 1 f f f f f 5 + 5 5 f 8 8 8 8 f f f f f f 5 5 + 5 5 5 8 8 8 f f f f f f 5 5 5 + 1 5 5 5 8 f f f f f f 5 5 5 1 + 1 1 5 5 5 f f f f f 5 5 5 1 1 + 1 1 1 5 5 5 5 5 5 5 5 5 1 1 1 + 1 1 1 1 5 5 5 5 5 5 5 1 1 1 1 +` + export const tile_pin_0 = img` . . 4 5 4 d . . . . 4 5 4 d . . diff --git a/sensorSelect.ts b/sensorSelect.ts index c7b27eb..7c74c96 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -13,7 +13,7 @@ namespace microcode { /* override */ startup() { super.startup() - + // Issues with Crashing when too many buttons are visible persist: this.btns.push(new Button({ @@ -22,7 +22,7 @@ namespace microcode { icon: "accelerometer", ariaId: "accelerometer", x: -60, - y: -34, + y: -40, onClick: () => { this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) }, @@ -35,7 +35,7 @@ namespace microcode { icon: "pin_0", ariaId: "Pin 0", x: -30, - y: -34, + y: -40, onClick: () => { this.selectedSensors.push(new PinSensor(TouchPin.P0)) }, @@ -45,27 +45,42 @@ namespace microcode { this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "magnet", - ariaId: "S10", + icon: "pin_1", + ariaId: "Pin 1", x: 0, - y: -34, + y: -40, onClick: () => { - this.selectedSensors.push(new MagnetSensor(Dimension.X)) + this.selectedSensors.push(new PinSensor(TouchPin.P1)) }, dynamicBoundaryColorsOn: true, })) + this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "accelerometer", - ariaId: "accelerometer", + icon: "pin_2", + ariaId: "Pin 2", x: 30, - y: -34, + y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + this.selectedSensors.push(new PinSensor(TouchPin.P2)) }, - dynamicBoundaryColorsOn: true, + dynamicBoundaryColorsOn: true, + })) + + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "magnet", + ariaId: "S10", + x: 60, + y: -40, + onClick: () => { + this.selectedSensors.push(new MagnetSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, })) this.btns.push(new Button({ @@ -73,8 +88,8 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "right_turn", ariaId: "Pitch", - x: 60, - y: -34, + x: -60, + y: -11, onClick: () => { this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) }, @@ -88,8 +103,8 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "right_spin", ariaId: "Roll", - x: -60, - y: -4, + x: -30, + y: -11, onClick: () => { this.selectedSensors.push(new RotationSensor(Rotation.Roll)) }, @@ -102,8 +117,8 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "led_light_sensor", ariaId: "led_light_sensor", - x: -30, - y: -4, + x: 0, + y: -11, onClick: () => { this.selectedSensors.push(new LightSensor()) }, @@ -115,8 +130,8 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "thermometer", ariaId: "thermometer", - x: 0, - y: -4, + x: 30, + y: -11, onClick: () => { this.selectedSensors.push(new TemperatureSensor()) }, @@ -128,8 +143,8 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "finger_press", ariaId: "Logo Press", - x: 30, - y: -4, + x: 60, + y: -11, onClick: () => { this.selectedSensors.push(new LogoPressSensor()) }, @@ -141,8 +156,8 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "speaker", ariaId: "Volume", - x: 60, - y: -4, + x: -60, + y: 15, onClick: () => { this.selectedSensors.push(new VolumeSensor()) }, @@ -155,10 +170,10 @@ namespace microcode { this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "right_spin", + icon: "compass", ariaId: "Compass", - x: -60, - y: 26, + x: -30, + y: 15, onClick: () => { this.selectedSensors.push(new CompassHeadingSensor()) }, @@ -168,23 +183,65 @@ namespace microcode { this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "tile_button_a", - ariaId: "F3", - x: -30, - y: 26, + icon: "compass", + ariaId: "Compass", + x: 0, + y: 15, onClick: () => { - this.selectedSensors.push(new ButtonPressSensor()) - }, - dynamicBoundaryColorsOn: true, + this.selectedSensors.push(new CompassHeadingSensor()) + }, + dynamicBoundaryColorsOn: true, })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "compass", + ariaId: "Compass", + x: 30, + y: 15, + onClick: () => { + this.selectedSensors.push(new CompassHeadingSensor()) + }, + dynamicBoundaryColorsOn: true, + })) + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "compass", + ariaId: "Compass", + x: 60, + y: 15, + onClick: () => { + this.selectedSensors.push(new CompassHeadingSensor()) + }, + dynamicBoundaryColorsOn: true, + })) + + //----------- + + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "tile_button_a", + // ariaId: "F3", + // x: -60, + // y: 56, + // onClick: () => { + // this.selectedSensors.push(new ButtonPressSensor()) + // }, + // dynamicBoundaryColorsOn: true, + // })) + + this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, icon: "green_tick", ariaId: "Done", x: 60, - y: 40, + y: 41, onClick: () => { if (this.selectedSensors.length === 0) { return @@ -214,27 +271,12 @@ namespace microcode { 0xc ) - screen.printCenter("Select Sensors to log", 5) - - // Following 3 lines may be tabbed - results in same error regardless: - - // this.btns.forEach((btn) => { - // btn.draw() - // }) + screen.printCenter("Sensor Selection", 2) for (let i = 0; i < this.btns.length; ++i) { this.btns[i].draw() } - // Identical: - - // this.btns[0].draw() - // this.btns[1].draw() - // this.btns[2].draw() - // this.btns[3].draw() - // this.btns[4].draw() - // this.btns[5].draw() - super.draw() } } From 10acc439b2a93e944ce7f70bed3cdc85b002912e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 2 Mar 2024 16:28:36 +0000 Subject: [PATCH 043/109] Revamped measurementConfigSelect.ts, added Delay option to it. Iterated Prototype version to 6. Added ability to record data from View if none is recorded. Adjustments to MicroData logo. --- assets.ts | 6 ++-- dataViewSelect.ts | 14 +++++++- home.ts | 4 +-- measurementConfigSelect.ts | 52 ++++++++++++++++++--------- recordedDataViewer.ts | 11 +++++- sensorSelect.ts | 72 +++++++++++++++++++------------------- userOptions.ts | 3 +- 7 files changed, 101 insertions(+), 61 deletions(-) diff --git a/assets.ts b/assets.ts index 6ab1559..9ad92d8 100644 --- a/assets.ts +++ b/assets.ts @@ -106,11 +106,11 @@ namespace microcode { ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbf....1111..1bbbbbf.......1bbbbf....1bbbbfbbbbb.....1bbbbf.1bbbbf...1bbbbf...1bbbbbbf........1bbbbf...1bbbbbf...... ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbb...11bbbb.1bbbbbf.......1bbbbb...11bbbbfbbbbb....bbbbbbf.1bbbbb...1bbbbf...1bbbbbbf........1bbbbb...1bbbbbf...... ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbbb111bbbbbf1bbbbbf.......1bbbbbb111bbbbbfbbbbb...bbbbbbbf.1bbbbb111bbbbbf...1bbbbbbf........1bbbbbb111bbbbbf...... - ...1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbffbbbbbbbbbbbbbbf..bbbbbbbbbbbbb1111.bbbbbbbb1111111bbbbbbbbbbbbbbbb1111... - ...1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.bbbbbbbbbbbbbbf..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbf1bbbbbbbbbbbbbbbbbbf.. + ...1bbbbbbf......1bbbbbbf1bbbbbf.bbbbbbbbbbbbbff1bbbbbf........bbbbbbbbbbbbbffbbbbbbbbbbbbbbf..bbbbbbbbbbbbb1111.bbbbbbbb11111111bbbbbbbbbbbbbbb1111... + ...1bbbbbbf......1bbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbf........1bbbbbbbbbbbbf.bbbbbbbbbbbbbbf..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbbf.. ...1bbbbbbf......1bbbbbbf1bbbbbf..bbbbbbbbbbbff.1bbbbbf.........bbbbbbbbbbbff.bbbbbbbbbbbbbff..bbbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbfbbbbbbbbbbbbbbbbbbff.. ....bbbbbff.......bbbbbff.bbbbff...fbbbbbbbfff...bbbbff..........fbbbbbbbfff..bbbbbbbbbbbff.....fbbbbbbbbbbbbbbbf.fbbbbbbbbbbbbbf.fbbbbbbbbbbbbbbbbff.. - .....fffff.........fffff...ffff......fffffff......ffff.............fffffff....bffffffffff.........ffffffffffffff....ffffffffffff....ffffffffffffffff... + .....fffff.........fffff...ffff......fffffff......ffff.............fffffff....fffffffffff.........ffffffffffffff....ffffffffffff....ffffffffffffffff... ` export const microbitLogo = img` diff --git a/dataViewSelect.ts b/dataViewSelect.ts index 58ef01c..66cde0b 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -11,6 +11,17 @@ namespace microcode { /* override */ startup() { super.startup() + if (FauxDataLogger.isEmpty) { + control.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + () => { + this.app.popScene() + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + } + ) + } + this.metaDataBtn = new Button({ parent: null, style: ButtonStyles.Transparent, @@ -63,7 +74,8 @@ namespace microcode { ) if (FauxDataLogger.isEmpty) { - screen.printCenter("No data has been recorded", Screen.HALF_HEIGHT) + screen.printCenter("No data has been recorded", 5) + screen.printCenter("Press A to Record some!", Screen.HALF_HEIGHT) return; } diff --git a/home.ts b/home.ts index f6ee42a..a960224 100644 --- a/home.ts +++ b/home.ts @@ -58,9 +58,9 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - "Prototype 3", + "Prototype 6", Screen.RIGHT_EDGE - font.charWidth * "Prototype 6".length, - Screen.BOTTOM_EDGE - font.charHeight - 1, + Screen.BOTTOM_EDGE - font.charHeight - 2, 0xb, font ) diff --git a/measurementConfigSelect.ts b/measurementConfigSelect.ts index df5913d..03bdf13 100644 --- a/measurementConfigSelect.ts +++ b/measurementConfigSelect.ts @@ -6,7 +6,8 @@ namespace microcode { [1, 5], // Seconds [1, 5], // Minutes [1, 5], // Hours - [1, 5] // Days + [1, 5], // Days + [1, 5] // Delay ] const enum GUI_STATE { @@ -20,18 +21,28 @@ namespace microcode { private currentColumn: number private selectedSensors: Sensor[] - // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days]: - private userSelection = [10, 0, 1, 0, 0, 0] + // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: + private userSelection: number[] constructor(app: App, selectedSensors: Sensor[]) { super(app, "dataViewer") this.guiState = GUI_STATE.DEFAULT - this.guiRows = ["Quantity: ", "Ms: ", "Seconds: ", "Minutes: ", "Hours: ", "Days: "] - this.currentColumn = 0 + this.guiRows = ["Measurements: ", + "Milli-Seconds: ", + "Seconds: ", + "Minutes: ", + "Hours: ", + "Days: ", + "Start Delay: " + ] + this.currentColumn = 0 this.selectedSensors = selectedSensors + // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: + this.userSelection = [10, 0, 1, 0, 0, 0, 0] + control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, @@ -127,7 +138,7 @@ namespace microcode { const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] let period: number = 0 - for (let i = 1; i < this.userSelection.length; i++) { + for (let i = 1; i < this.userSelection.length - 1; i++) { period += this.userSelection[i] * timeConversionTableMs[i - 1] } @@ -135,6 +146,7 @@ namespace microcode { sensor: this.selectedSensors[0], // Does not grant multiple sensors measurements: this.userSelection[0], period, + delay: this.userSelection[6] } } @@ -148,30 +160,36 @@ namespace microcode { 0xC ) - screen.printCenter("Measurement Settings", 4) - - const rowSize = Screen.HEIGHT / (this.userSelection.length + 1) let timeAsString; let rowOffset = 0; - for (let i = 0; i < 6; i++) { + const headerX = 2 + const optionX = (font.charWidth * this.guiRows[0].length) + 10 + const pointerX = optionX + 20 + const rowSize = Screen.HEIGHT / (this.userSelection.length + 1) + + + screen.printCenter("Measurement Settings", 2) + + for (let i = 0; i < this.userSelection.length; i++) { screen.print(this.guiRows[i], - 35 - (font.charWidth * this.guiRows[i].length) / 2, - 22 + rowOffset + headerX, + 18 + rowOffset ) - + timeAsString = this.userSelection[i].toString() screen.print(timeAsString, - 70 - (font.charWidth * timeAsString[i].length) / 2, - 22 + rowOffset + optionX, + 18 + rowOffset ) rowOffset += rowSize } // Cursor arrow screen.print("<--", - 100 - (font.charWidth * "<--".length) / 2, - 22 + (rowSize * this.currentColumn) + pointerX, + 18 + (rowSize * this.currentColumn), + 0 ) } } diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index bdc0c9e..c05b844 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -39,11 +39,20 @@ namespace microcode { this.scrollOffset = Math.max(this.scrollOffset - 1, 0) } ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.B.id, + () => { + app.popScene() + app.pushScene(new DataViewSelect(this.app)) + } + ) } draw_grid() { const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length - const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( diff --git a/sensorSelect.ts b/sensorSelect.ts index 7c74c96..2e53053 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -180,44 +180,44 @@ namespace microcode { dynamicBoundaryColorsOn: true, })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "compass", - ariaId: "Compass", - x: 0, - y: 15, - onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) - }, - dynamicBoundaryColorsOn: true, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "compass", + // ariaId: "Compass", + // x: 0, + // y: 15, + // onClick: () => { + // this.selectedSensors.push(new CompassHeadingSensor()) + // }, + // dynamicBoundaryColorsOn: true, + // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "compass", - ariaId: "Compass", - x: 30, - y: 15, - onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) - }, - dynamicBoundaryColorsOn: true, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "compass", + // ariaId: "Compass", + // x: 30, + // y: 15, + // onClick: () => { + // this.selectedSensors.push(new CompassHeadingSensor()) + // }, + // dynamicBoundaryColorsOn: true, + // })) - this.btns.push(new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "compass", - ariaId: "Compass", - x: 60, - y: 15, - onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) - }, - dynamicBoundaryColorsOn: true, - })) + // this.btns.push(new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "compass", + // ariaId: "Compass", + // x: 60, + // y: 15, + // onClick: () => { + // this.selectedSensors.push(new CompassHeadingSensor()) + // }, + // dynamicBoundaryColorsOn: true, + // })) //----------- diff --git a/userOptions.ts b/userOptions.ts index 4772e30..2a67a94 100644 --- a/userOptions.ts +++ b/userOptions.ts @@ -2,6 +2,7 @@ namespace microcode { export type MeasurementOpts = { sensor: Sensor, measurements: number, - period: number + period: number, + delay: number }; } \ No newline at end of file From cf0f3aa787055fa2e3fb21c7651019de5779f1ba Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 2 Mar 2024 18:07:50 +0000 Subject: [PATCH 044/109] Added ability to change boundary colour to buttons, added such a boundary to the buttons on the Recorded Data Options screen. Added delay countdown before recording. Asset improvements --- assets.ts | 120 ++++++++++++++++++++++++++++++++++++++++++++-- button.ts | 10 +++- dataRecorder.ts | 68 ++++---------------------- dataViewSelect.ts | 9 ++-- home.ts | 2 +- 5 files changed, 141 insertions(+), 68 deletions(-) diff --git a/assets.ts b/assets.ts index 9ad92d8..cfb938b 100644 --- a/assets.ts +++ b/assets.ts @@ -41,6 +41,7 @@ namespace microcode { if (name == "disk3") return icondb.disk3 if (name == "largeDisk") return icondb.largeDiskIcon + // basic colors led editor if (name == "solid_red") return icondb.solid_red if (name == "solid_black") return icondb.solid_black @@ -51,7 +52,9 @@ namespace microcode { if (name == "smiley_buttons") return icondb.sampleSmileyButtons // Newly added icons for MicroData Home menu: - if (name == "linear_graph") return icondb.linearGraph + if (name == "linear_graph_1") return icondb.linearGraph1 + if (name == "linear_graph_2") return icondb.linearGraph2 + if (name == "led_light_sensor") return icondb.led_light_sensor if (name == "thermometer") return icondb.thermometer @@ -76,8 +79,8 @@ namespace microcode { if (name == "tile_button_a") return icondb.tile_button_a if (name == "compass") return icondb.compass - // if (name == "compass") return icondb.compass - // if (name == "compass") return icondb.compass + if (name == "settingsGear") return icondb.settingsGear + if (name == "largeSettingsGear") return icondb.largeSettingsGear // if (name == "compass") return icondb.compass extraImage = null @@ -369,6 +372,42 @@ namespace icondb { .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. ` +export const largeMetaDataIcon = img` + .666666666666666666666666666666. + 66666666666666666666666666666666 + 66666666666666666666666666666666 + 6666bbbbbbbbbbbbbbbbbbbbbb666666 + 666bb811111111111111111118b66666 + 666b88111111111111111111188b6666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 6666b88ccccc111111111cccccc88b66 + 6666bcccccddb111111cbbccccc88b66 + 6666bccccdbbbbbbbbbbcccc8888b666 + 6666b8cccccddbcccbdcccc88888b666 + 6666b888dbbcc11111cbddd88888b666 + 6666bddbbbcc111111cccbbb8888b666 + 66ddddbbb11111111111bbbcccc8b666 + 66ddddbbb11111111111bbbcccc8b666 + 6666bddbbbcc111111ccbbbc8888b666 + 6666b888cbbcc11111cbbcc88888b666 + 666b888ccccddbcccbdcccc88888b666 + 666b88cccdbbbbbbbbbbcccc8888b666 + 666bcccccddb1111111cbbccccc8b666 + 666b8ccccc1111111111ccccc888b666 + 666b8811111111111111111118f8b666 + 666bb81111111111111111111888b666 + 6666bbbbbbbbbbbbbbbbbbbbbbbbb666 + 66666666666666666666666666666666 + 66666666666666666666666666666666 + b666666666666666666666666666666b + .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. +` + export const MISSING = img` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -2272,6 +2311,43 @@ f f f f f f f f f f f f f f f . .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. ` + + +export const largeSettingsGear = img` +66666666666666666666666666666666 +66666666666666666666666666666666 +666666666666666dd666666666666666 +66666666666666dddd66666666666666 +66666dddd666ddbbbbcc666dddd66666 +66666dddd666ddbbbbcc666dddd66666 +666dddbbbb66ddbbbbcc66dbbbccc666 +666dddbbbbccddbbbbccdddbbbccc666 +6666ddbbbbbbbbbbbbbbbbbbbbcc6666 +66666dbbbbbbbbbbbbbbbbbbbbc66666 +666666ccbbddbbccccbbddbbcc666666 +666666ccbbddbbc66cbbddbbcc666666 +66666dddbbbbcc6666ccbbbbdddd6666 +6666ddddbbbbc666666cbbbbdddd6666 +666dbbbbbbcc66666666ccbbbbbbc666 +6dddbbbbbbc6666666666cbbbbbbccc6 +6dddbbbbbbc6666666666cbbbbbbccc6 +6dddbbbbbbcc66666666ccbbbbbbccc6 +666cccccbbbbc6666666cbbbbcccc666 +6666ccccbbbbcc66666ccbbbbccc6666 +666666ddbbddbbc66cbbddbbcc666666 +666666ddbbddbbccccbbddbbcc666666 +66666dbbbbbbbbbbbbbbbbbbbbc66666 +6666ddbbbbbbbbbbbbbbbbbbbbcc6666 +6666ddbbbbccccbbbbccccbbbbcc6666 +6666ddbbbb66ccbbbbcc66bbbbcc6666 +66666cccc666ccbbbbcc666cccc66666 +66666cccc666ccbbbbcc666cccc66666 +66666666666666cccc66666666666666 +666666666666666cc666666666666666 +66666666666666666666666666666666 +66666666666666666666666666666666 +` + export const largeNewProgramIcon = img` .11111111..............11111111. 1bbbbbbbb..............bbbbbbbb1 @@ -2416,7 +2492,7 @@ f f f f f f f f f f f f f f f . `*/ - export const linearGraph = img` +export const linearGraph1 = img` .111111111111111111111111111111. 11111111111111111111111111111111 11ff1111111111111111111111111111 @@ -2450,6 +2526,42 @@ f f f f f f f f f f f f f f f . 11ffffffffffffffffffffffffffff11 1111111111111111111111111111111b .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. +` + +export const linearGraph2 = img` +.111111111111111111111111111111. +11111111111111111111111111111111 +11ff1111111111111111111111111111 +11ff1111111111111111111111141111 +11ff1111111111111111111111441111 +11ff1111111111111111111114411888 +11ff1111111111111111111144188881 +11ff1111111111111111111448881111 +11ff1111111111111111114888111111 +11ff1111111111111111888111111111 +11ff1111111111111188441111111111 +11ff1111111111118884411111111111 +11ff1111111111188144111111111111 +11ff1111111118811441111111111111 +11ff1111111188114411111111111111 +11ff1111111881144111111111111111 +11ff1111118811441111111111111111 +11ff1111188114411111111111111111 +11ff1111881144111111111111111111 +11ff1118811441111111111111111111 +11ff1188114411111111111111111111 +11ff1881144111111111111111111111 +11ff1811441111111111111111111111 +11ff8814411111111111111111111111 +11ff8844111111111111111111111111 +11ff8441111111111111111111111111 +11ff8441111111111111111111111111 +11ff4411111111111111111111111111 +11ff4111111111111111111111111111 +11ffffffffffffffffffffffffffff11 +11ffffffffffffffffffffffffffff11 +1111111111111111111111111111111b +.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. ` export const sampleFirefly = img` diff --git a/button.ts b/button.ts index 002cc34..4060c7a 100644 --- a/button.ts +++ b/button.ts @@ -200,6 +200,7 @@ namespace microcode { public onClick?: (button: Button) => void private selected: boolean private dynamicBoundaryColorsOn: boolean + private boundaryColor: number public get ariaId(): string { return ( @@ -230,6 +231,7 @@ namespace microcode { y: number onClick?: (button: Button) => void, dynamicBoundaryColorsOn?: boolean + boundaryColor?: number }) { super( opts.x, @@ -249,6 +251,12 @@ namespace microcode { } else { this.dynamicBoundaryColorsOn = opts.dynamicBoundaryColorsOn + this.boundaryColor = 2 + } + + if (opts.boundaryColor != null) { + this.dynamicBoundaryColorsOn = true + this.boundaryColor = opts.boundaryColor } } @@ -290,7 +298,7 @@ namespace microcode { super.draw() if (this.dynamicBoundaryColorsOn) { - let boundaryColour = 2 // Red + let boundaryColour = this.boundaryColor // Red if (this.selected) { boundaryColour = 7 // green } diff --git a/dataRecorder.ts b/dataRecorder.ts index 932a1dd..67b9d33 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,60 +1,3 @@ -// namespace microcode { -// export class DataRecorder extends Scene { -// private fauxDatalogger: FauxDataLogger -// private loggingStartTime: number -// private measurementOpts: MeasurementOpts - -// constructor(app: App, measurementOpts: MeasurementOpts) { -// super(app, "dataRecorder") - -// this.measurementOpts = measurementOpts -// this.fauxDatalogger = new FauxDataLogger(["Ms", measurementOpts.sensorName], measurementOpts) - -// this.loggingStartTime = input.runningTime() - -// // Go Back: -// control.onEvent( -// ControllerButtonEvent.Pressed, -// controller.B.id, -// () => { -// this.app.popScene() -// this.app.pushScene(new Home(this.app)) -// } -// ) -// } - -// update() { -// Screen.fillRect( -// Screen.LEFT_EDGE, -// Screen.TOP_EDGE, -// Screen.WIDTH, -// Screen.HEIGHT, -// 0xc -// ) - -// if (this.measurementOpts.measurements === 0) { -// screen.printCenter("Data Logging Complete.", (screen.height / 2) - 10); -// screen.printCenter("Press B to back out.", screen.height / 2); -// } - -// else { -// const secondsLeft: number = (this.measurementOpts.measurements * this.measurementOpts.period) / 1000 -// screen.printCenter("Recording data...", 10); - -// screen.printCenter(this.measurementOpts.period / 1000 + " second period", 45) -// screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); -// screen.printCenter(secondsLeft.toString() + " seconds left", 85); - -// // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) -// FauxDataLogger.log((input.runningTime() - this.loggingStartTime).toString(), this.measurementOpts.sensorFn()) - -// this.measurementOpts.measurements -= 1 -// basic.pause(this.measurementOpts.period) -// } -// } -// } -// } - namespace microcode { export class DataRecorder extends Scene { private fauxDatalogger: FauxDataLogger @@ -65,8 +8,7 @@ namespace microcode { constructor(app: App, measurementOpts: MeasurementOpts, sensors: Sensor[]) { super(app, "dataRecorder") - - let headers: string[] = ["Ms"] + let headers: string[] = ["Milli-Sec"] sensors.forEach(function(sensor) { headers.push(sensor.name) }) @@ -102,6 +44,14 @@ namespace microcode { screen.printCenter("Press B to back out.", screen.height / 2); } + if (this.measurementOpts.delay > 0) { + screen.printCenter("Data logger starting in", (screen.height / 2) - 10); + screen.printCenter(this.measurementOpts.delay + " seconds...", screen.height / 2) + this.measurementOpts.delay -= 1 + + basic.pause(1000) + } + else { const secondsLeft: number = (this.measurementOpts.measurements * this.measurementOpts.period) / 1000 screen.printCenter("Recording data...", 10); diff --git a/dataViewSelect.ts b/dataViewSelect.ts index 66cde0b..d306661 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -25,7 +25,7 @@ namespace microcode { this.metaDataBtn = new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "linear_graph", + icon: "largeSettingsGear", ariaId: "Meta Data", x: -50, y: 30, @@ -33,12 +33,13 @@ namespace microcode { app.popScene() app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW)) }, + boundaryColor: 7, }) this.dataViewBtn = new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "edit_program", + icon: "largeDisk", ariaId: "View Data", x: 0, y: 30, @@ -46,12 +47,13 @@ namespace microcode { app.popScene() app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.DATA_VIEW)) }, + boundaryColor: 7, }) this.graphViewBtn = new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "largeDisk", + icon: "linear_graph_2", ariaId: "View Graph", x: 50, y: 30, @@ -59,6 +61,7 @@ namespace microcode { app.popScene() app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.GRAPH_VIEW)) }, + boundaryColor: 7, }) this.navigator.addButtons([this.metaDataBtn, this.dataViewBtn, this.graphViewBtn]) diff --git a/home.ts b/home.ts index a960224..cdbcda9 100644 --- a/home.ts +++ b/home.ts @@ -14,7 +14,7 @@ namespace microcode { this.liveDataBtn = new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "linear_graph", + icon: "linear_graph_1", ariaId: "linear_graph", x: -50, y: 30, From 647f8604962fa897165036fb09fca9a220393221 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 2 Mar 2024 18:18:50 +0000 Subject: [PATCH 045/109] text adjustments to the countdown. --- dataRecorder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 67b9d33..1df31c6 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -44,7 +44,7 @@ namespace microcode { screen.printCenter("Press B to back out.", screen.height / 2); } - if (this.measurementOpts.delay > 0) { + else if (this.measurementOpts.delay > 0) { screen.printCenter("Data logger starting in", (screen.height / 2) - 10); screen.printCenter(this.measurementOpts.delay + " seconds...", screen.height / 2) this.measurementOpts.delay -= 1 From 6ad1ce26c80dc6c309d824cc7ffdcd826e8e6285 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 6 Mar 2024 13:49:24 +0000 Subject: [PATCH 046/109] Fixed bugs with objects in the wrong position after scrolling. --- liveDataViewer.ts | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 9a092b2..1e0e620 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -19,14 +19,15 @@ namespace microcode { private xScrollOffset: number private yScrollOffset: number - /* X coordinate that the user wants to zoom in on; adjust offsets to make this point centred, whilst zoomed */ - private selectedXCoordinate: number + /* Coordinates that the user wants to zoom in on; adjust offsets to make this point centred, whilst zoomed */ + private selectedXCoordinate: number = null + private selectedYCoordinate: number = null /* To plot */ private sensors: Sensor[] constructor(app: App, sensors: Sensor[]) { - super(app, "yo") + super(app, "liveDataViewer") this.color = 0 this.sensors = sensors @@ -41,7 +42,7 @@ namespace microcode { this.yScrollOffset = 0 this.selectedXCoordinate = (Screen.WIDTH / 2) - + this.selectedYCoordinate = (Screen.HEIGHT / 2) //-------------------------------- // Oscilloscope Movement Controls: @@ -52,6 +53,11 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.A.id, () => { + if (this.selectedXCoordinate == null || this.selectedYCoordinate == null) { + this.selectedXCoordinate = Math.round(this.sensors[0].getDataBufferLength() / 2) + this.selectedYCoordinate = this.sensors[0].getNthReading(this.selectedXCoordinate) + } + this.windowHeight = this.windowHeight + (Screen.HEIGHT * 0.5) this.windowWidth = this.windowWidth + (Screen.WIDTH * 0.5) @@ -150,7 +156,7 @@ namespace microcode { // Colour used to represent this sensor, same colour as plotted & ticker: screen.fillRect( 2, - this.windowHeight - this.windowBotBuffer + this.yScrollOffset + 15 + (i * 12), + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), 7, 7, color @@ -160,7 +166,7 @@ namespace microcode { screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + " Peak " + this.sensors[i].peakDataPoint[1], 14, - this.windowHeight - this.windowBotBuffer + this.yScrollOffset + 15 + (i * 12), + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), color ) @@ -171,17 +177,17 @@ namespace microcode { // Draw data lines: color = 8; this.sensors.forEach(function(sensor) { - sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset, color) + sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, color) color = (color + 1) % 15 }) - // Draw circle in the screen centre for better testing: - screen.fillCircle( - (Screen.WIDTH / 2),// + this.windowWidth - this.windowWidth, - (Screen.HEIGHT / 2),// + this.windowTopBuffer - this.windowBotBuffer, - 8, - 4 - ) + // // Draw circle in the screen centre for better testing: + // screen.fillCircle( + // (Screen.WIDTH / 2),// + this.windowWidth - this.windowWidth, + // (Screen.HEIGHT / 2),// + this.windowTopBuffer - this.windowBotBuffer, + // 8, + // 4 + // ) // Draw the latest reading on the right-hand side as a Ticker: @@ -190,11 +196,13 @@ namespace microcode { const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) latestReadings.forEach(function(reading) { - const y = Math.round(Screen.HEIGHT - ((reading[0] / reading[1]) * (Screen.HEIGHT))) + const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset + const y = Math.round(Screen.HEIGHT - ((reading[0] / reading[1]) * (Screen.HEIGHT - fromY))) - fromY + screen.print( reading[0].toString(), Screen.WIDTH + this.xScrollOffset - 18 + 1, - y + this.yScrollOffset - this.windowBotBuffer - this.windowTopBuffer, + y - 2, color, simage.font5, ) From aa4157691e58ad77a0f043066503ed1bd080ef3f Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 6 Mar 2024 15:20:19 +0000 Subject: [PATCH 047/109] Oscilloscope for Prototype 6 --- generateGraph.ts | 108 ++++++++++++++++++++++++++++++++++++++++ liveDataViewer.ts | 123 +++++++++++++++++++++++++++++++++------------- sensors.ts | 8 +++ 3 files changed, 205 insertions(+), 34 deletions(-) create mode 100644 generateGraph.ts diff --git a/generateGraph.ts b/generateGraph.ts new file mode 100644 index 0000000..db8bcde --- /dev/null +++ b/generateGraph.ts @@ -0,0 +1,108 @@ +namespace microcode { + /** No information beyond this Y coordinate */ + const MAX_Y_SCOLL = -75 + + /** + * One of the 3 main functionalities of MicroData + * Allows for the live feed of a sensor to be plotted, + * Multiple sensors may be plotted at once + * Display modes may be toggled per sensor + */ + export class GraphGenerator extends Scene { + private windowWidth: number + private windowHeight: number + + private windowWidthBuffer: number + private windowTopBuffer: number + private windowBotBuffer: number + + constructor(app: App) { + super(app, "liveDataViewer") + this.color = 0 + + this.windowWidth = Screen.WIDTH + this.windowHeight = Screen.HEIGHT + + this.windowWidthBuffer = 18 + this.windowTopBuffer = 5 + this.windowBotBuffer = 20 + } + + + /** + * Request each sensor updates its buffers, + * Then draw to screen + */ + update() { + screen.fill(this.color); + + // this.sensors.forEach(function(sensor) { + // sensor.readIntoBuffer() + // }) + + this.plot() + + basic.pause(100); + } + + /** + * Display mode for plotting all incoming data on y axis + */ + private plot() { + let color = 8; + + this.draw_axes(); + + // Write Sensor information, displayed below the plot: + for (let i = 0; i < this.sensors.length; i++) { + // Colour used to represent this sensor, same colour as plotted & ticker: + screen.fillRect( + 2, + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), + 7, + 7, + color + ) + + // Name, reading / maximum, peak + screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + + " Peak " + this.sensors[i].peakDataPoint[1], + 14, + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), + color + ) + + color = (color + 1) % 15 + } + + // Draw data lines: + color = 8; + this.sensors.forEach(function(sensor) { + sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, color) + color = (color + 1) % 15 + }) + } + + /** + * 2 Axis of Double-thickness each, in yellow + */ + draw_axes() { + for (let i = 0; i < 2; i++) { + screen.drawLine( + this.windowWidthBuffer, + this.windowHeight - this.windowBotBuffer + i, + this.windowWidth - this.windowWidthBuffer, + this.windowHeight - this.windowBotBuffer + i, + 5 + ); + screen.drawLine( + this.windowWidthBuffer, + this.windowTopBuffer, + this.windowWidthBuffer, + this.windowHeight - this.windowBotBuffer, + 5 + ); + } + } + } +} \ No newline at end of file diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 1e0e620..bf5566b 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -20,8 +20,11 @@ namespace microcode { private yScrollOffset: number /* Coordinates that the user wants to zoom in on; adjust offsets to make this point centred, whilst zoomed */ - private selectedXCoordinate: number = null - private selectedYCoordinate: number = null + private selectedXCoordinate: number + private selectedYCoordinate: number + + + private currentZoomDepth: number /* To plot */ private sensors: Sensor[] @@ -41,8 +44,10 @@ namespace microcode { this.xScrollOffset = 0 this.yScrollOffset = 0 - this.selectedXCoordinate = (Screen.WIDTH / 2) - this.selectedYCoordinate = (Screen.HEIGHT / 2) + this.selectedXCoordinate = null + this.selectedYCoordinate = null + + this.currentZoomDepth = 0 //-------------------------------- // Oscilloscope Movement Controls: @@ -57,7 +62,9 @@ namespace microcode { this.selectedXCoordinate = Math.round(this.sensors[0].getDataBufferLength() / 2) this.selectedYCoordinate = this.sensors[0].getNthReading(this.selectedXCoordinate) } - + + this.xScrollOffset = Math.round(Screen.HALF_WIDTH - this.selectedXCoordinate) + this.windowHeight = this.windowHeight + (Screen.HEIGHT * 0.5) this.windowWidth = this.windowWidth + (Screen.WIDTH * 0.5) @@ -65,6 +72,7 @@ namespace microcode { this.windowTopBuffer = this.windowTopBuffer - (5 * 0.5) this.windowBotBuffer = this.windowBotBuffer - (20 * 0.5) + this.currentZoomDepth += 1 } ) @@ -79,12 +87,16 @@ namespace microcode { } else { + this.xScrollOffset = 0 + this.windowHeight = this.windowHeight - (Screen.HEIGHT * 0.5) this.windowWidth = this.windowWidth - (Screen.WIDTH * 0.5) this.windowWidthBuffer = this.windowWidthBuffer + (18 * 0.5) this.windowTopBuffer = this.windowTopBuffer + (5 * 0.5) - this.windowBotBuffer = this.windowBotBuffer + (20 * 0.5) + this.windowBotBuffer = this.windowBotBuffer + (20 * 0.5) + + this.currentZoomDepth -= 1 } } ) @@ -111,8 +123,14 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.left.id, () => { - this.xScrollOffset = Math.min(this.xScrollOffset + 10, this.windowWidth) - this.update() // For fast response to the above change + if (this.currentZoomDepth != 0) { + if (this.selectedXCoordinate - (Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) > 0) { + this.selectedXCoordinate -= Math.round(Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) + this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate + } + + this.update() // For fast response to the above change + } } ) @@ -120,8 +138,14 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - this.xScrollOffset = Math.max(this.xScrollOffset - 10, -this.windowWidth) - this.update() // For fast response to the above change + if (this.currentZoomDepth != 0) { + if (this.selectedXCoordinate + (Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) < this.sensors[0].getDataBufferLength()) { + this.selectedXCoordinate += Math.round(Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) + this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate + } + + this.update() // For fast response to the above change + } } ) } @@ -170,43 +194,74 @@ namespace microcode { color ) - color = (color + 1) % 15 + color = (color + 3) % 15 } + // Circle around selected data point: + if (this.selectedXCoordinate != null && this.selectedYCoordinate != null) { + const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset + const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[0].maxReading) * (Screen.HEIGHT - fromY))) - fromY - // Draw data lines: - color = 8; - this.sensors.forEach(function(sensor) { - sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, color) - color = (color + 1) % 15 - }) - - // // Draw circle in the screen centre for better testing: - // screen.fillCircle( - // (Screen.WIDTH / 2),// + this.windowWidth - this.windowWidth, - // (Screen.HEIGHT / 2),// + this.windowTopBuffer - this.windowBotBuffer, - // 8, - // 4 - // ) - + screen.drawCircle( + this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset, + y, + 5, + 1 + ) + } - // Draw the latest reading on the right-hand side as a Ticker: + // Draw the latest reading on the right-hand side as a Ticker if at no-zoom: color = 8; - const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) + if (this.currentZoomDepth == 0) { + const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) + + latestReadings.forEach(function(reading) { + const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset + const y = Math.round(Screen.HEIGHT - ((reading[0] / reading[1]) * (Screen.HEIGHT - fromY))) - fromY + + screen.print( + reading[0].toString(), + Screen.WIDTH + this.xScrollOffset - 18 + 1, + y - 2, + color, + simage.font5, + ) + color = (color + 3) % 15 + }) + } - latestReadings.forEach(function(reading) { + else { const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const y = Math.round(Screen.HEIGHT - ((reading[0] / reading[1]) * (Screen.HEIGHT - fromY))) - fromY + const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[0].maxReading) * (Screen.HEIGHT - fromY))) - fromY + screen.print( - reading[0].toString(), - Screen.WIDTH + this.xScrollOffset - 18 + 1, - y - 2, + "x =" + this.selectedXCoordinate.toString(), + this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, + y - 20, + // this.windowWidth - 10, + // 5, color, simage.font5, ) - color = (color + 1) % 15 + + screen.print( + "y =" + this.sensors[0].getReading().toString(), + this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, + y - 10, + // this.windowWidth - 10, + // 15, + color, + simage.font5, + ) + } + + // Draw data lines: + color = 8; + this.sensors.forEach(function(sensor) { + sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, color) + color = (color + 3) % 15 }) } diff --git a/sensors.ts b/sensors.ts index 9127dd2..035478a 100644 --- a/sensors.ts +++ b/sensors.ts @@ -44,6 +44,14 @@ namespace microcode { return this.sensorFn() } + getNthReading(n: number): number { + return this.dataBuffer[n] + } + + getDataBufferLength(): number { + return this.dataBuffer.length + } + getNormalisedReading(): number{ return this.sensorFn() / this.maxReading } From 142f2ab4bbb9612b3e47eb9f44443b3354562f6c Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 9 Mar 2024 23:00:37 +0000 Subject: [PATCH 048/109] Added ability to change selected sensor for the oscilloscope feature in the live data viewer. --- dataViewSelect.ts | 2 +- fauxDatalogger.ts | 2 +- generateGraph.ts | 91 ++++++++++++++++++++++++++++------------------- liveDataViewer.ts | 45 +++++++++++++---------- 4 files changed, 84 insertions(+), 56 deletions(-) diff --git a/dataViewSelect.ts b/dataViewSelect.ts index d306661..739024b 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -59,7 +59,7 @@ namespace microcode { y: 30, onClick: () => { app.popScene() - app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.GRAPH_VIEW)) + app.pushScene(new GraphGenerator(this.app)) }, boundaryColor: 7, }) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 38d417e..9334752 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -6,7 +6,7 @@ namespace microcode { export class FauxDataLogger { static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] - static dateStamp = "29/02/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() + static dateStamp = "06/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() static values: MetaData[] static numberOfRows: number static measurementOptions: MeasurementOpts diff --git a/generateGraph.ts b/generateGraph.ts index db8bcde..93431a0 100644 --- a/generateGraph.ts +++ b/generateGraph.ts @@ -1,13 +1,6 @@ namespace microcode { - /** No information beyond this Y coordinate */ - const MAX_Y_SCOLL = -75 - - /** - * One of the 3 main functionalities of MicroData - * Allows for the live feed of a sensor to be plotted, - * Multiple sensors may be plotted at once - * Display modes may be toggled per sensor - */ + const PLOT_SMOOTHING_CONSTANT = 8 + export class GraphGenerator extends Scene { private windowWidth: number private windowHeight: number @@ -17,13 +10,13 @@ namespace microcode { private windowBotBuffer: number constructor(app: App) { - super(app, "liveDataViewer") + super(app, "graphGeneration") this.color = 0 this.windowWidth = Screen.WIDTH this.windowHeight = Screen.HEIGHT - this.windowWidthBuffer = 18 + this.windowWidthBuffer = 18 this.windowTopBuffer = 5 this.windowBotBuffer = 20 } @@ -36,10 +29,6 @@ namespace microcode { update() { screen.fill(this.color); - // this.sensors.forEach(function(sensor) { - // sensor.readIntoBuffer() - // }) - this.plot() basic.pause(100); @@ -53,32 +42,62 @@ namespace microcode { this.draw_axes(); - // Write Sensor information, displayed below the plot: - for (let i = 0; i < this.sensors.length; i++) { - // Colour used to represent this sensor, same colour as plotted & ticker: - screen.fillRect( - 2, - this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), - 7, - 7, - color - ) + // // Write Sensor information, displayed below the plot: + // for (let i = 0; i < FauxDataLogger.headers.length; i++) { + // // Colour used to represent this sensor, same colour as plotted & ticker: + // screen.fillRect( + // 2, + // this.windowHeight - this.windowBotBuffer + 15 + (i * 12), + // 7, + // 7, + // color + // ) - // Name, reading / maximum, peak - screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + - " Peak " + this.sensors[i].peakDataPoint[1], - 14, - this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), - color - ) + // // Name, reading / maximum, peak + // screen.print(FauxDataLogger.headers[i], + // 14, + // this.windowHeight - this.windowBotBuffer + 15 + (i * 12), + // color + // ) - color = (color + 1) % 15 - } + // color = (color + 1) % 15 + // } // Draw data lines: color = 8; - this.sensors.forEach(function(sensor) { - sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, color) + let x = 0 + let xOffset = this.windowWidthBuffer / FauxDataLogger.numberOfRows + + FauxDataLogger.values.forEach(function(metadata) { + // const y1 = Math.round(screen.height - ((metadata.data[1] / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer + // const y2 = Math.round(screen.height - ((Number(metadata.data[1]) / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer + + // if (this.dataBuffer[i] > this.peakDataPoint[1]) { + // this.peakDataPoint = [i, this.dataBuffer[i]] + // } + + // Minimal data smoothing: + // if (Math.abs(y1 - y2) <= PLOT_SMOOTHING_CONSTANT) { + // screen.drawLine(this.windowWidthBuffer + x, y1, this.windowWidthBuffer + x - 1, y1, color); + // } + + + x += xOffset + + // const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer + // const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer + + // if (this.dataBuffer[i] > this.peakDataPoint[1]) { + // this.peakDataPoint = [i, this.dataBuffer[i]] + // } + + // // Minimal data smoothing: + // if (Math.abs(y1 - y2) <= PLOT_SMOOTHING_CONSTANT) { + // screen.drawLine(this.windowWidthBuffer + i, y1, this.windowWidthBuffer + i - 1, y1, color); + // } + + // screen.drawLine(this.windowWidthBuffer + i, y1, this.windowWidthBuffer + i - 1, y2, color); + color = (color + 1) % 15 }) } diff --git a/liveDataViewer.ts b/liveDataViewer.ts index bf5566b..ea04570 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -23,9 +23,10 @@ namespace microcode { private selectedXCoordinate: number private selectedYCoordinate: number - private currentZoomDepth: number + private selectedSensorIndex: number + /* To plot */ private sensors: Sensor[] @@ -49,6 +50,8 @@ namespace microcode { this.currentZoomDepth = 0 + this.selectedSensorIndex = 0 + //-------------------------------- // Oscilloscope Movement Controls: //-------------------------------- @@ -59,8 +62,8 @@ namespace microcode { controller.A.id, () => { if (this.selectedXCoordinate == null || this.selectedYCoordinate == null) { - this.selectedXCoordinate = Math.round(this.sensors[0].getDataBufferLength() / 2) - this.selectedYCoordinate = this.sensors[0].getNthReading(this.selectedXCoordinate) + this.selectedXCoordinate = Math.round(this.sensors[this.selectedSensorIndex].getDataBufferLength() / 2) + this.selectedYCoordinate = this.sensors[this.selectedSensorIndex].getNthReading(this.selectedXCoordinate) } this.xScrollOffset = Math.round(Screen.HALF_WIDTH - this.selectedXCoordinate) @@ -105,7 +108,13 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) + if (this.currentZoomDepth > 0) { + this.selectedSensorIndex = ((this.selectedSensorIndex + 1) % this.sensors.length) + this.selectedYCoordinate = this.sensors[this.selectedSensorIndex].getNthReading(this.selectedXCoordinate) + } + else { + this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) + } this.update() // For fast response to the above change } ) @@ -114,7 +123,13 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { - this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) + if (this.currentZoomDepth > 0) { + this.selectedSensorIndex = Math.max(this.selectedSensorIndex - 1, 0) + this.selectedYCoordinate = this.sensors[this.selectedSensorIndex].getNthReading(this.selectedXCoordinate) + } + else { + this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) + } this.update() // For fast response to the above change } ) @@ -124,8 +139,8 @@ namespace microcode { controller.left.id, () => { if (this.currentZoomDepth != 0) { - if (this.selectedXCoordinate - (Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) > 0) { - this.selectedXCoordinate -= Math.round(Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) + if (this.selectedXCoordinate - (Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) > 0) { + this.selectedXCoordinate -= Math.round(Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate } @@ -139,8 +154,8 @@ namespace microcode { controller.right.id, () => { if (this.currentZoomDepth != 0) { - if (this.selectedXCoordinate + (Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) < this.sensors[0].getDataBufferLength()) { - this.selectedXCoordinate += Math.round(Math.abs(this.sensors[0].getDataBufferLength() - this.selectedXCoordinate) / 2) + if (this.selectedXCoordinate + (Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) < this.sensors[this.selectedSensorIndex].getDataBufferLength()) { + this.selectedXCoordinate += Math.round(Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate } @@ -200,7 +215,7 @@ namespace microcode { // Circle around selected data point: if (this.selectedXCoordinate != null && this.selectedYCoordinate != null) { const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[0].maxReading) * (Screen.HEIGHT - fromY))) - fromY + const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[this.selectedSensorIndex].maxReading) * (Screen.HEIGHT - fromY))) - fromY screen.drawCircle( this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset, @@ -210,7 +225,6 @@ namespace microcode { ) } - // Draw the latest reading on the right-hand side as a Ticker if at no-zoom: color = 8; if (this.currentZoomDepth == 0) { @@ -233,25 +247,20 @@ namespace microcode { else { const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[0].maxReading) * (Screen.HEIGHT - fromY))) - fromY - + const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[this.selectedSensorIndex].maxReading) * (Screen.HEIGHT - fromY))) - fromY screen.print( "x =" + this.selectedXCoordinate.toString(), this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, y - 20, - // this.windowWidth - 10, - // 5, color, simage.font5, ) screen.print( - "y =" + this.sensors[0].getReading().toString(), + "y =" + this.sensors[this.selectedSensorIndex].getReading().toString(), this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, y - 10, - // this.windowWidth - 10, - // 15, color, simage.font5, ) From 2d102375de6cb173f7a285e0cc637cf5938dc1f1 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 11 Mar 2024 19:50:34 +0000 Subject: [PATCH 049/109] liveDataViewer.ts: fixed y-axis issue, added ability to pause data flow, fixed selected coordinate drifting off screen, more accurate selected coordinate tracking, documentation, added support for changing the x-axis movement mode on the oscilloscope via the microbit B button - though the B button is currently disfunctional. --- liveDataViewer.ts | 106 +++++++++++++++++++++++++++++++++++----------- sensors.ts | 39 +++++++++-------- 2 files changed, 102 insertions(+), 43 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index ea04570..dc11d81 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -25,6 +25,10 @@ namespace microcode { private currentZoomDepth: number + /* Continue reading from the sensors? Or pause sensor reading? */ + private requestDataMode: boolean + /* Use the Left & Right Buttons to move by 1 unit? or jump relative to the start/end? */ + private oscilloscopeMovementMode: boolean private selectedSensorIndex: number /* To plot */ @@ -49,12 +53,24 @@ namespace microcode { this.selectedYCoordinate = null this.currentZoomDepth = 0 - + this.requestDataMode = true // Constant data flow + this.oscilloscopeMovementMode = true // Move Left/Right by 1 unit this.selectedSensorIndex = 0 //-------------------------------- // Oscilloscope Movement Controls: - //-------------------------------- + //-------------------------------- + + // Use Microbit A button to pause/continue reading new data: + control.onEvent(DAL.DEVICE_BUTTON_EVT_DOWN, DAL.DEVICE_ID_BUTTON_A, () => { + this.requestDataMode = !this.requestDataMode + }) + + // Use Microbit B button to control the oscilloscope x-axis movement mode: + control.onEvent(DAL.DEVICE_BUTTON_EVT_DOWN, DAL.DEVICE_ID_BUTTON_B, () => { + this.oscilloscopeMovementMode = !this.oscilloscopeMovementMode + // basic.showNumber(5) + }) // Zoom in: control.onEvent( @@ -139,11 +155,17 @@ namespace microcode { controller.left.id, () => { if (this.currentZoomDepth != 0) { - if (this.selectedXCoordinate - (Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) > 0) { + if (!this.oscilloscopeMovementMode && this.selectedXCoordinate - (Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) > 0) { this.selectedXCoordinate -= Math.round(Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) - this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate + + } + else { + this.selectedXCoordinate = Math.max(0, this.selectedXCoordinate - 1) } + this.selectedYCoordinate = this.sensors[this.selectedSensorIndex].getNthReading(this.selectedXCoordinate) + this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate + this.update() // For fast response to the above change } } @@ -155,7 +177,15 @@ namespace microcode { () => { if (this.currentZoomDepth != 0) { if (this.selectedXCoordinate + (Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) < this.sensors[this.selectedSensorIndex].getDataBufferLength()) { - this.selectedXCoordinate += Math.round(Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) + if (this.oscilloscopeMovementMode) { + this.selectedXCoordinate = Math.min(this.selectedXCoordinate + 1, this.sensors[this.selectedSensorIndex].getDataBufferLength()) + } + else { + this.selectedXCoordinate += Math.round(Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) + } + + this.selectedYCoordinate = this.sensors[this.selectedSensorIndex].getNthReading(this.selectedXCoordinate) + this.xScrollOffset = Screen.HALF_WIDTH - this.selectedXCoordinate } @@ -173,9 +203,11 @@ namespace microcode { update() { screen.fill(this.color); - this.sensors.forEach(function(sensor) { - sensor.readIntoBuffer() - }) + if (this.requestDataMode) { + this.sensors.forEach(function(sensor) { + sensor.readIntoBuffer() + }) + } this.plot() @@ -202,7 +234,7 @@ namespace microcode { ) // Name, reading / maximum, peak - screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maxReading + + screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maximum + " Peak " + this.sensors[i].peakDataPoint[1], 14, this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), @@ -212,10 +244,24 @@ namespace microcode { color = (color + 3) % 15 } + + // The data from the sensors will shift to the left over time as the buffer is filled + // Shift the selected coordinate appropriately; so that the Circle around the selected point is accurate + if (this.requestDataMode && this.selectedXCoordinate != null && this.sensors[this.selectedSensorIndex].getBufferSize() == Sensor.BUFFER_LIMIT) { + this.selectedXCoordinate -= 1 + + if (this.selectedXCoordinate <= 0) { + this.selectedXCoordinate = null + this.selectedYCoordinate = null + } + } + // Circle around selected data point: if (this.selectedXCoordinate != null && this.selectedYCoordinate != null) { const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[this.selectedSensorIndex].maxReading) * (Screen.HEIGHT - fromY))) - fromY + + const sensorRange = Math.abs(this.sensors[this.selectedSensorIndex].minimum) + this.sensors[this.selectedSensorIndex].maximum + const y = Math.round(Screen.HEIGHT - (((this.selectedYCoordinate - this.sensors[this.selectedSensorIndex].minimum) / sensorRange) * (Screen.HEIGHT - fromY))) - fromY screen.drawCircle( this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset, @@ -228,31 +274,37 @@ namespace microcode { // Draw the latest reading on the right-hand side as a Ticker if at no-zoom: color = 8; if (this.currentZoomDepth == 0) { - const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.maxReading]}) + const latestReadings = this.sensors.map(function(sensor) {return [sensor.getReading(), sensor.minimum, Math.abs(sensor.minimum) + sensor.maximum]}) latestReadings.forEach(function(reading) { const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const y = Math.round(Screen.HEIGHT - ((reading[0] / reading[1]) * (Screen.HEIGHT - fromY))) - fromY - - screen.print( - reading[0].toString(), - Screen.WIDTH + this.xScrollOffset - 18 + 1, - y - 2, - color, - simage.font5, - ) + const y = Math.round(Screen.HEIGHT - ((((reading[0] - reading[1]) / reading[2]) * (Screen.HEIGHT - fromY)))) - fromY + + // Not minimum value: + if (y != reading[1]) { + screen.print( + reading[0].toString(), + Screen.WIDTH + this.xScrollOffset - 25, + y - 2, + color, + simage.font5, + ) + } color = (color + 3) % 15 }) } - else { + // Check because they may become null my scrolling off the screen: + else if (this.selectedXCoordinate != null && this.selectedYCoordinate != null) { const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const y = Math.round(Screen.HEIGHT - ((this.selectedYCoordinate / this.sensors[this.selectedSensorIndex].maxReading) * (Screen.HEIGHT - fromY))) - fromY + const sensorRange = (this.sensors[this.selectedSensorIndex].maximum + Math.abs(this.sensors[this.selectedSensorIndex].minimum)) + const norm = ((this.selectedYCoordinate / sensorRange) * (Screen.HEIGHT - fromY)) + const y = Math.round(Screen.HEIGHT - norm) - fromY screen.print( "x =" + this.selectedXCoordinate.toString(), this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, - y - 20, + y - 5, color, simage.font5, ) @@ -260,7 +312,7 @@ namespace microcode { screen.print( "y =" + this.sensors[this.selectedSensorIndex].getReading().toString(), this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, - y - 10, + y - 15, color, simage.font5, ) @@ -269,7 +321,11 @@ namespace microcode { // Draw data lines: color = 8; this.sensors.forEach(function(sensor) { - sensor.draw(this.windowWidthBuffer + 2 + this.xScrollOffset, this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, color) + sensor.draw( + this.windowWidthBuffer + 2 + this.xScrollOffset, + this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, + color + ) color = (color + 3) % 15 }) } diff --git a/sensors.ts b/sensors.ts index 035478a..883adbf 100644 --- a/sensors.ts +++ b/sensors.ts @@ -7,13 +7,13 @@ namespace microcode { const PLOT_SMOOTHING_CONSTANT = 8 export abstract class Sensor { - private static BUFFER_LIMIT = 100; + static BUFFER_LIMIT = 100; sensorFn: () => number name: string - minReading: number - maxReading: number + minimum: number + maximum: number peakDataPoint: number[] private numberOfDisplayModes: number; @@ -29,17 +29,21 @@ namespace microcode { ) { this.sensorFn = sensorFn this.name = name - this.minReading = sensorMinReading - this.maxReading = sensorMaxReading + this.minimum = sensorMinReading + this.maximum = sensorMaxReading this.numberOfDisplayModes = numberOfDisplayModes this.dataBuffer = [] - this.peakDataPoint = [0, this.minReading] + this.peakDataPoint = [0, this.minimum] } cycleDisplayMode() { this.currentDisplayMode = (this.currentDisplayMode + 1) % this.numberOfDisplayModes } + getBufferSize(): number { + return this.dataBuffer.length + } + getReading(): number { return this.sensorFn() } @@ -53,7 +57,7 @@ namespace microcode { } getNormalisedReading(): number{ - return this.sensorFn() / this.maxReading + return this.sensorFn() / this.maximum } readIntoBuffer(): void { @@ -75,18 +79,12 @@ namespace microcode { * @param color */ draw(fromX: number, fromY: number, color: number): void { - if (this.peakDataPoint[0] > 0) { - screen.fillCircle( - fromX + this.peakDataPoint[0], - Math.round(screen.height - ((this.peakDataPoint[1] / this.maxReading) * (screen.height - fromY))) - fromY, - 3, - 3 - ) - } for (let i = 0; i < this.dataBuffer.length - 1; i++) { - const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.maxReading) * (screen.height - fromY))) - fromY - const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.maxReading) * (screen.height - fromY))) - fromY + const norm1 = ((this.dataBuffer[i] - this.minimum) / (this.maximum + Math.abs(this.minimum))) * (screen.height - fromY) + const norm2 = ((this.dataBuffer[i + 1] - this.minimum) / (this.maximum + Math.abs(this.minimum))) * (screen.height - fromY) + const y1 = Math.round(screen.height - norm1) - fromY + const y2 = Math.round(screen.height - norm2) - fromY if (this.dataBuffer[i] > this.peakDataPoint[1]) { this.peakDataPoint = [i, this.dataBuffer[i]] @@ -121,7 +119,7 @@ namespace microcode { */ export class AccelerometerSensor extends Sensor { constructor(dim: Dimension) { - super(function () {return input.acceleration(dim)}, "Accelerometer", 0, 100, 1) + super(function () {return input.acceleration(dim)}, "Accel.", -1023, 1023, 1) } } @@ -199,6 +197,11 @@ namespace microcode { export class ButtonPressSensor extends Sensor { constructor() { super(function () {return 1}, "Button Press", 0, 1, 1) + + control.onEvent(DAL.DEVICE_BUTTON_EVT_UP, DAL.DEVICE_ID_BUTTON_A, () => { + basic.showIcon(IconNames.No) + + }) } } } \ No newline at end of file From e718340c4b8a836b29155fb4464d828bc705f265 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 12 Mar 2024 01:45:59 +0000 Subject: [PATCH 050/109] recordedDataViewer.ts: Fixed bug with incorrect number of rows for large number of measurements. --- recordedDataViewer.ts | 44 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index c05b844..b9ac309 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -1,6 +1,6 @@ namespace microcode { const HEADER_OFFSET = 17 - const MAX_ROWS = 10 + const MAX_ROWS = 9 export const enum DATA_VIEW_DISPLAY_MODE { META_DATA_VIEW, @@ -147,7 +147,6 @@ namespace microcode { ] } - for (let i = this.scrollOffset; i < metadata.length; i++) { Screen.print( @@ -172,22 +171,11 @@ namespace microcode { case DATA_VIEW_DISPLAY_MODE.DATA_VIEW: this.draw_grid() - // const data = [ - // {id: 1, col1: "1", col2: "1"}, - // {id: 2, col1: "2", col2: "2"}, - // {id: 3, col1: "3", col2: "3"}, - // {id: 4, col1: "4", col2: "4"}, - // ] - // const colSizeBuffer = Screen.WIDTH / 2 - // const rowDeltaBuffer = Screen.HEIGHT / 4 - - const colSizeBuffer = Screen.WIDTH / FauxDataLogger.headers.length - const rowDeltaBuffer = Screen.HEIGHT / FauxDataLogger.numberOfRows - let colOffset = 0 - - for (let i = this.scrollOffset; i < FauxDataLogger.numberOfRows; i++) { - const data = FauxDataLogger.values[i].data; + const rowDeltaBuffer = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + + for (let i = 0; i < Math.min(FauxDataLogger.numberOfRows, MAX_ROWS); i++) { + const data = FauxDataLogger.values[i + this.scrollOffset].data; Screen.print( data[0], @@ -206,22 +194,18 @@ namespace microcode { ) - if (FauxDataLogger.headers.length > 2) { - Screen.print( - data[2], - Screen.LEFT_EDGE + colSizeBuffer + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[2].length) / 2), - Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, - 0xb, - simage.font8 - ) - } + // if (FauxDataLogger.headers.length > 2) { + // Screen.print( + // data[2], + // Screen.LEFT_EDGE + colSizeBuffer + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[2].length) / 2), + // Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, + // 0xb, + // simage.font8 + // ) + // } rowOffset += rowDeltaBuffer } break; - - case DATA_VIEW_DISPLAY_MODE.DATA_VIEW: - - break default: break; From b76c3ce9cecaed8cfd10d0f23929f62261103a6c Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 12 Mar 2024 03:02:16 +0000 Subject: [PATCH 051/109] recordedDataViewer.ts: Neatend code, ability to draw any number of columns, fixed column issue, added MAX_COLS. --- recordedDataViewer.ts | 141 +++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/recordedDataViewer.ts b/recordedDataViewer.ts index b9ac309..2a2fb5f 100644 --- a/recordedDataViewer.ts +++ b/recordedDataViewer.ts @@ -1,6 +1,8 @@ namespace microcode { - const HEADER_OFFSET = 17 const MAX_ROWS = 9 + const MAX_COLS = 3 + + // git commit -m "recordedDataViewer.ts: Neatend code, ability to draw any number of columns." export const enum DATA_VIEW_DISPLAY_MODE { META_DATA_VIEW, @@ -10,25 +12,34 @@ namespace microcode { export class RecordedDataViewer extends Scene { private guiState: DATA_VIEW_DISPLAY_MODE - private saveSlot: number + private xScrollOffset: number + private yScrollOffset: number - private scrollOffset: number + private numberOfMetadataRows: number constructor(app: App, saveSlot: number, guiState: DATA_VIEW_DISPLAY_MODE) { super(app, "recordedDataViewer") this.guiState = guiState - this.saveSlot = saveSlot - this.scrollOffset = 0 + + this.xScrollOffset = 0 + this.yScrollOffset = 0 + + this.numberOfMetadataRows = 4 + FauxDataLogger.headers.length } /* override */ startup() { super.startup() + //---------- + // Controls: + //---------- + control.onEvent( ControllerButtonEvent.Pressed, - controller.down.id, + controller.B.id, () => { - this.scrollOffset = Math.min(this.scrollOffset + 1, MAX_ROWS) + app.popScene() + app.pushScene(new DataViewSelect(this.app)) } ) @@ -36,23 +47,44 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - this.scrollOffset = Math.max(this.scrollOffset - 1, 0) + this.xScrollOffset = Math.max(this.xScrollOffset - 1, 0) } ) + control.onEvent( ControllerButtonEvent.Pressed, - controller.B.id, + controller.down.id, () => { - app.popScene() - app.pushScene(new DataViewSelect(this.app)) + if (this.xScrollOffset + 5 < this.numberOfMetadataRows) { + this.xScrollOffset += 1 + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.left.id, + () => { + this.yScrollOffset = Math.max(this.yScrollOffset - 1, 0) } ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.right.id, + () => { + if (this.yScrollOffset + MAX_COLS < FauxDataLogger.headers.length) { + this.yScrollOffset += 1 + } + } + ) + } draw_grid() { - const colBufferSize = Screen.WIDTH / FauxDataLogger.headers.length - const rowBufferSize = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + const colBufferSize = Screen.WIDTH / Math.min(FauxDataLogger.headers.length, MAX_COLS) + const rowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, MAX_ROWS) for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( @@ -84,34 +116,23 @@ namespace microcode { 0xC ) - let rowOffset = 0 - switch (this.guiState) { case DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW: - screen.printCenter("MetaData for Save " + this.saveSlot, 2) - - control.onEvent( - ControllerButtonEvent.Pressed, - controller.A.id, - () => { - this.guiState = DATA_VIEW_DISPLAY_MODE.DATA_VIEW - } - ) - + const rowSize = 6 const colSize = Screen.WIDTH / 2 - const rowDelta = Screen.HEIGHT / 4 + const rowDelta = Screen.HEIGHT / rowSize for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colSize) { Screen.drawLine( Screen.LEFT_EDGE + colOffset, - Screen.TOP_EDGE + HEADER_OFFSET, + Screen.TOP_EDGE, Screen.LEFT_EDGE + colOffset, Screen.HEIGHT, 0x0 ) } - for (let rowOffset = HEADER_OFFSET; rowOffset <= Screen.HEIGHT; rowOffset+=rowDelta) { + for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=rowDelta) { Screen.drawLine( Screen.LEFT_EDGE, Screen.TOP_EDGE + rowOffset, @@ -121,12 +142,10 @@ namespace microcode { ) } - let metadata = [] if (FauxDataLogger.headers.length == 2) { metadata = [ - {col1: "Save", col2: "1"}, {col1: "Taken", col2: FauxDataLogger.dateStamp}, {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, @@ -136,7 +155,6 @@ namespace microcode { ] } else { metadata = [ - {col1: "Save", col2: "1"}, {col1: "Taken", col2: FauxDataLogger.dateStamp}, {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, @@ -147,63 +165,44 @@ namespace microcode { ] } - - for (let i = this.scrollOffset; i < metadata.length; i++) { + for (let row = 0; row < rowSize; row++) { Screen.print( - metadata[i].col1, - Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[i].col1.length) / 2), - Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowDelta / 2) - 4, + metadata[row + this.xScrollOffset].col1, + Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[row + this.xScrollOffset].col1.length) / 2), + Screen.TOP_EDGE + (row * rowDelta) + (rowDelta / 2) - 4, 0xb, simage.font8 ) Screen.print( - metadata[i].col2, - Screen.LEFT_EDGE + colSize + (colSize / 2) - ((font.charWidth * metadata[i].col2.length) / 2), - Screen.TOP_EDGE + HEADER_OFFSET + rowOffset + (rowDelta / 2) - 4, + metadata[row + this.xScrollOffset].col2, + Screen.LEFT_EDGE + colSize + (colSize / 2) - ((font.charWidth * metadata[row + this.xScrollOffset].col2.length) / 2), + Screen.TOP_EDGE + (row * rowDelta) + (rowDelta / 2) - 4, 0xb, simage.font8 ) - rowOffset += rowDelta } break; case DATA_VIEW_DISPLAY_MODE.DATA_VIEW: this.draw_grid() - const colSizeBuffer = Screen.WIDTH / FauxDataLogger.headers.length + const colSizeBuffer = Screen.WIDTH / Math.min(MAX_COLS, FauxDataLogger.headers.length) const rowDeltaBuffer = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) - for (let i = 0; i < Math.min(FauxDataLogger.numberOfRows, MAX_ROWS); i++) { - const data = FauxDataLogger.values[i + this.scrollOffset].data; - - Screen.print( - data[0], - Screen.LEFT_EDGE + (colSizeBuffer / 2) - ((font.charWidth * data[0].length) / 2), - Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, - 0xb, - simage.font8 - ) - - Screen.print( - data[1], - Screen.LEFT_EDGE + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[1].length) / 2), - Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, - 0xb, - simage.font8 - ) - - - // if (FauxDataLogger.headers.length > 2) { - // Screen.print( - // data[2], - // Screen.LEFT_EDGE + colSizeBuffer + colSizeBuffer + (colSizeBuffer / 2) - ((font.charWidth * data[2].length) / 2), - // Screen.TOP_EDGE + rowOffset + (rowDeltaBuffer / 2) - 4, - // 0xb, - // simage.font8 - // ) - // } - rowOffset += rowDeltaBuffer + for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, MAX_ROWS); row++) { + const data = FauxDataLogger.values[row + this.xScrollOffset].data; + + for (let col = 0; col < Math.min(FauxDataLogger.headers.length, MAX_COLS); col++) { + const colID = col + this.yScrollOffset + Screen.print( + data[colID], + Screen.LEFT_EDGE + (col * colSizeBuffer) + (colSizeBuffer / 2) - ((font.charWidth * data[colID].length) / 2), + Screen.TOP_EDGE + (row * rowDeltaBuffer) + (rowDeltaBuffer / 2) - 4, + 0xb, + simage.font8 + ) + } } break; From a0dca052082e8cb3469d49f73e9013160b97a231 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 12 Mar 2024 17:32:30 +0000 Subject: [PATCH 052/109] renamed and refactored recordedDataViewer.ts into tabularDataViewer.ts, experimentation with button events. --- asci_art.txt | 117 ++++++++++++++++++ dataViewSelect.ts | 4 +- pxt.json | 5 +- sensorSelect.ts | 24 ++-- sensors.ts | 7 +- recordedDataViewer.ts => tabularDataViewer.ts | 4 +- 6 files changed, 139 insertions(+), 22 deletions(-) create mode 100644 asci_art.txt rename recordedDataViewer.ts => tabularDataViewer.ts (98%) diff --git a/asci_art.txt b/asci_art.txt new file mode 100644 index 0000000..e321934 --- /dev/null +++ b/asci_art.txt @@ -0,0 +1,117 @@ + ................................ + ................................ + ...............dd............... + ..............dddd.............. + .....dddd...ddbbbbcc...dddd..... + .....dddd...ddbbbbcc...dddd..... + ...dddbbbb..ddbbbbcc..dbbbccc... + ...dddbbbbccddbbbbccdddbbbccc... + ....ddbbbbbbbbbbbbbbbbbbbbcc.... + .....dbbbbbbbbbbbbbbbbbbbbc..... + ......ccbbddbbccccbbddbbcc...... + ......ccbbddbbc..cbbddbbcc...... + .....dddbbbbcc....ccbbbbdddd.... + ....ddddbbbbc......cbbbbdddd.... + ...dbbbbbbcc........ccbbbbbbc... + .dddbbbbbbc..........cbbbbbbccc. + .dddbbbbbbc..........cbbbbbbccc. + .dddbbbbbbcc........ccbbbbbbccc. + ...cccccbbbbc.......cbbbbcccc... + ....ccccbbbbcc.....ccbbbbccc.... + ......ddbbddbbc..cbbddbbcc...... + ......ddbbddbbccccbbddbbcc...... + .....dbbbbbbbbbbbbbbbbbbbbc..... + ....ddbbbbbbbbbbbbbbbbbbbbcc.... + ....ddbbbbccccbbbbccccbbbbcc.... + ....ddbbbb..ccbbbbcc..bbbbcc.... + .....cccc...ccbbbbcc...cccc..... + .....cccc...ccbbbbcc...cccc..... + ..............cccc.............. + ...............cc............... + ................................ + ................................ + + . . . . . . . . . . . . . . . . + . . . . . . . d d . . . . . . . + . . . d d . d b b c . d d . . . + . . d b b c d b b c d b b c . . + . . d b b b b b b b b b b c . . + . . . c b d b c c b d b c . . . + . . d d b b c . . c b b d d . . + . d b b b c . . . . c b b b c . + . d b b b c . . . . c b b b c . + . . c c b b c . . c b b c c . . + . . . d b d b c c b d b c . . . + . . d b b b b b b b b b b c . . + . . d b b c c b b c c b b c . . + . . . c c . c b b c . c c . . . + . . . . . . . c c . . . . . . . + . . . . . . . . . . . . . . . . + + .11111111..............11111111. + 1bbbbbbbb..............bbbbbbbb1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + b..............................b + ................................ + ...............11............... + ...............11............... + ...............11............... + ...............11............... + ...........1111111111........... + ...........1111111111........... + ...........bbbb11bbbb........... + ...............11............... + ...............11............... + ...............11............... + ...............bb............... + ................................ + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + 1..............................1 + b11111111..............11111111b + .bbbbbbbb..............bbbbbbbb. + + .666666666666666666666666666666. + 66666666666666666666666666666666 + 66666666666666666666666666666666 + 6666bbbbbbbbbbbbbbbbbbbbbb666666 + 666bb811111111111111111118b66666 + 666b88111111111111111111188b6666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 666b881111111111111111111888b666 + 6666b88ccccc111111111cccccc88b66 + 6666bcccccddb111111cbbccccc88b66 + 6666bccccdbbbbbbbbbbcccc8888b666 + 6666b8cccccddbcccbdcccc88888b666 + 6666b888dbbcc11111cbddd88888b666 + 6666bddbbbcc111111cccbbb8888b666 + 66ddddbbb11111111111bbbcccc8b666 + 66ddddbbb11111111111bbbcccc8b666 + 6666bddbbbcc111111ccbbbc8888b666 + 6666b888cbbcc11111cbbcc88888b666 + 666b888ccccddbcccbdcccc88888b666 + 666b88cccdbbbbbbbbbbcccc8888b666 + 666bcccccddb1111111cbbccccc8b666 + 666b8ccccc1111111111ccccc888b666 + 666b8811111111111111111118f8b666 + 666bb81111111111111111111888b666 + 6666bbbbbbbbbbbbbbbbbbbbbbbbb666 + 66666666666666666666666666666666 + 66666666666666666666666666666666 + b666666666666666666666666666666b + .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. \ No newline at end of file diff --git a/dataViewSelect.ts b/dataViewSelect.ts index 739024b..eb087b9 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -31,7 +31,7 @@ namespace microcode { y: 30, onClick: () => { app.popScene() - app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW)) + app.pushScene(new TabularDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW)) }, boundaryColor: 7, }) @@ -45,7 +45,7 @@ namespace microcode { y: 30, onClick: () => { app.popScene() - app.pushScene(new RecordedDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.DATA_VIEW)) + app.pushScene(new TabularDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.DATA_VIEW)) }, boundaryColor: 7, }) diff --git a/pxt.json b/pxt.json index 99ecb28..9178b00 100644 --- a/pxt.json +++ b/pxt.json @@ -45,14 +45,15 @@ "liveDataViewer.ts", "dataRecorder.ts", - "recordedDataViewer.ts", + "tabularDataViewer.ts", "sensorSelect.ts", "measurementConfigSelect.ts", "fauxDatalogger.ts", "sceneFactory.ts", "userOptions.ts", "dataViewSelect.ts", - "sensors.ts" + "sensors.ts", + "generateGraph.ts" ], "testFiles": [], diff --git a/sensorSelect.ts b/sensorSelect.ts index 2e53053..5a31285 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -221,18 +221,18 @@ namespace microcode { //----------- - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "tile_button_a", - // ariaId: "F3", - // x: -60, - // y: 56, - // onClick: () => { - // this.selectedSensors.push(new ButtonPressSensor()) - // }, - // dynamicBoundaryColorsOn: true, - // })) + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "tile_button_a", + ariaId: "F3", + x: -60, + y: 41, + onClick: () => { + this.selectedSensors.push(new ButtonPressSensor()) + }, + dynamicBoundaryColorsOn: true, + })) this.btns.push(new Button({ diff --git a/sensors.ts b/sensors.ts index 883adbf..9900bc0 100644 --- a/sensors.ts +++ b/sensors.ts @@ -191,16 +191,17 @@ namespace microcode { } } + + /** - * No access to the Microbit Buttons A & B; only the controller buttons A & B; it seems + * Need to be transformed into an event based system */ export class ButtonPressSensor extends Sensor { constructor() { super(function () {return 1}, "Button Press", 0, 1, 1) control.onEvent(DAL.DEVICE_BUTTON_EVT_UP, DAL.DEVICE_ID_BUTTON_A, () => { - basic.showIcon(IconNames.No) - + return 1 }) } } diff --git a/recordedDataViewer.ts b/tabularDataViewer.ts similarity index 98% rename from recordedDataViewer.ts rename to tabularDataViewer.ts index 2a2fb5f..7d07a91 100644 --- a/recordedDataViewer.ts +++ b/tabularDataViewer.ts @@ -2,15 +2,13 @@ namespace microcode { const MAX_ROWS = 9 const MAX_COLS = 3 - // git commit -m "recordedDataViewer.ts: Neatend code, ability to draw any number of columns." - export const enum DATA_VIEW_DISPLAY_MODE { META_DATA_VIEW, DATA_VIEW, GRAPH_VIEW, } - export class RecordedDataViewer extends Scene { + export class TabularDataViewer extends Scene { private guiState: DATA_VIEW_DISPLAY_MODE private xScrollOffset: number private yScrollOffset: number From acf49361ea4a4edaab37315116f6dac3320de764 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Tue, 12 Mar 2024 18:40:59 +0000 Subject: [PATCH 053/109] Added the ability to generate metadata from FauxDataLogger, renamed the userOpts to measurementOptions. --- fauxDatalogger.ts | 24 ++++++++++++++++++++++-- measurementOptions.ts | 8 ++++++++ pxt.json | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 measurementOptions.ts diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 9334752..41272fb 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -9,13 +9,17 @@ namespace microcode { static dateStamp = "06/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() static values: MetaData[] static numberOfRows: number - static measurementOptions: MeasurementOpts static isEmpty: boolean = true + static measurementOptions: MeasurementOpts - constructor(headers: string[], mOpts: MeasurementOpts) { + private static sensors: Sensor[] + + constructor(headers: string[], mOpts: MeasurementOpts, sensors: Sensor[]) { FauxDataLogger.headers = headers FauxDataLogger.values = [] FauxDataLogger.numberOfRows = 0 + + FauxDataLogger.sensors = sensors FauxDataLogger.measurementOptions = mOpts } @@ -27,5 +31,21 @@ namespace microcode { }) FauxDataLogger.numberOfRows += 1 } + + public static getMetadata() { + let metadata = [ + {col1: "Date", col2: FauxDataLogger.dateStamp}, + {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, + {col1: "Measurements", col2: FauxDataLogger.measurementOptions.measurements.toString()}, + {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()} + ] + + for (let i = 0; i < FauxDataLogger.headers.length; i++) { + metadata.push({col1: "Col 1: " + FauxDataLogger.sensors[i], col2: FauxDataLogger.headers[i]}) + } + + return metadata + } } } diff --git a/measurementOptions.ts b/measurementOptions.ts new file mode 100644 index 0000000..2a67a94 --- /dev/null +++ b/measurementOptions.ts @@ -0,0 +1,8 @@ +namespace microcode { + export type MeasurementOpts = { + sensor: Sensor, + measurements: number, + period: number, + delay: number + }; +} \ No newline at end of file diff --git a/pxt.json b/pxt.json index 9178b00..f6a2a91 100644 --- a/pxt.json +++ b/pxt.json @@ -50,7 +50,7 @@ "measurementConfigSelect.ts", "fauxDatalogger.ts", "sceneFactory.ts", - "userOptions.ts", + "measurementOptions.ts", "dataViewSelect.ts", "sensors.ts", "generateGraph.ts" From 331da36298ef4ebd419016f4501ff15dcce6180c Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 12 Mar 2024 23:39:04 +0000 Subject: [PATCH 054/109] Fixed tabularDataView metadata view issue, documentation, improved fauxDatalogger, neatend tabularDataViewer --- dataRecorder.ts | 2 +- dataViewSelect.ts | 4 +- fauxDatalogger.ts | 6 ++- tabularDataViewer.ts | 98 +++++++++++++++++++++----------------------- 4 files changed, 54 insertions(+), 56 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 1df31c6..b095bf3 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -13,7 +13,7 @@ namespace microcode { headers.push(sensor.name) }) - this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts) + this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts, sensors) this.loggingStartTime = input.runningTime() this.measurementOpts = measurementOpts diff --git a/dataViewSelect.ts b/dataViewSelect.ts index eb087b9..2ce6ff0 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -31,7 +31,7 @@ namespace microcode { y: 30, onClick: () => { app.popScene() - app.pushScene(new TabularDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW)) + app.pushScene(new TabularDataViewer(this.app, DATA_VIEW_DISPLAY_MODE.METADATA_VIEW)) }, boundaryColor: 7, }) @@ -45,7 +45,7 @@ namespace microcode { y: 30, onClick: () => { app.popScene() - app.pushScene(new TabularDataViewer(this.app, 1, DATA_VIEW_DISPLAY_MODE.DATA_VIEW)) + app.pushScene(new TabularDataViewer(this.app, DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW)) }, boundaryColor: 7, }) diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 41272fb..55916ae 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -32,6 +32,10 @@ namespace microcode { FauxDataLogger.numberOfRows += 1 } + public static getNumberOfMetadataRows(): number { + return 5 + FauxDataLogger.headers.length + } + public static getMetadata() { let metadata = [ {col1: "Date", col2: FauxDataLogger.dateStamp}, @@ -42,7 +46,7 @@ namespace microcode { ] for (let i = 0; i < FauxDataLogger.headers.length; i++) { - metadata.push({col1: "Col 1: " + FauxDataLogger.sensors[i], col2: FauxDataLogger.headers[i]}) + metadata.push({col1: "Col " + (i + 1).toString(), col2: FauxDataLogger.headers[i]}) } return metadata diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index 7d07a91..f1d7d9d 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -1,13 +1,21 @@ namespace microcode { - const MAX_ROWS = 9 - const MAX_COLS = 3 + /** + * Display limits + * Data in excess will require scrolling to view + */ + const TABULAR_MAX_ROWS = 9 + const TABULAR_MAX_COLS = 3 + const METADATA_MAX_ROWS = 6 export const enum DATA_VIEW_DISPLAY_MODE { - META_DATA_VIEW, - DATA_VIEW, - GRAPH_VIEW, + METADATA_VIEW, + TABULAR_DATA_VIEW, } + + /** + * Used to view the recorded data & its meta data + */ export class TabularDataViewer extends Scene { private guiState: DATA_VIEW_DISPLAY_MODE private xScrollOffset: number @@ -15,14 +23,14 @@ namespace microcode { private numberOfMetadataRows: number - constructor(app: App, saveSlot: number, guiState: DATA_VIEW_DISPLAY_MODE) { + constructor(app: App, guiState: DATA_VIEW_DISPLAY_MODE) { super(app, "recordedDataViewer") this.guiState = guiState this.xScrollOffset = 0 this.yScrollOffset = 0 - this.numberOfMetadataRows = 4 + FauxDataLogger.headers.length + this.numberOfMetadataRows = FauxDataLogger.getNumberOfMetadataRows() } /* override */ startup() { @@ -45,7 +53,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - this.xScrollOffset = Math.max(this.xScrollOffset - 1, 0) + this.yScrollOffset = Math.max(this.xScrollOffset - 1, 0) } ) @@ -54,8 +62,16 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { - if (this.xScrollOffset + 5 < this.numberOfMetadataRows) { - this.xScrollOffset += 1 + if (this.guiState === DATA_VIEW_DISPLAY_MODE.METADATA_VIEW) { + if (this.yScrollOffset + 1 < this.numberOfMetadataRows - METADATA_MAX_ROWS) { + this.yScrollOffset += 1 + } + } + + else { + if (this.yScrollOffset + 1 < FauxDataLogger.numberOfRows - TABULAR_MAX_ROWS) { + this.yScrollOffset += 1 + } } } ) @@ -64,7 +80,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.left.id, () => { - this.yScrollOffset = Math.max(this.yScrollOffset - 1, 0) + this.xScrollOffset = Math.max(this.xScrollOffset - 1, 0) } ) @@ -72,8 +88,8 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - if (this.yScrollOffset + MAX_COLS < FauxDataLogger.headers.length) { - this.yScrollOffset += 1 + if (this.xScrollOffset + TABULAR_MAX_COLS < FauxDataLogger.headers.length) { + this.xScrollOffset += 1 } } ) @@ -81,8 +97,8 @@ namespace microcode { } draw_grid() { - const colBufferSize = Screen.WIDTH / Math.min(FauxDataLogger.headers.length, MAX_COLS) - const rowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, MAX_ROWS) + const colBufferSize = Screen.WIDTH / Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS) + const rowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS) for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( @@ -115,10 +131,9 @@ namespace microcode { ) switch (this.guiState) { - case DATA_VIEW_DISPLAY_MODE.META_DATA_VIEW: - const rowSize = 6 + case DATA_VIEW_DISPLAY_MODE.METADATA_VIEW: const colSize = Screen.WIDTH / 2 - const rowDelta = Screen.HEIGHT / rowSize + const rowDelta = Screen.HEIGHT / METADATA_MAX_ROWS for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colSize) { Screen.drawLine( @@ -140,41 +155,20 @@ namespace microcode { ) } - let metadata = [] - - if (FauxDataLogger.headers.length == 2) { - metadata = [ - {col1: "Taken", col2: FauxDataLogger.dateStamp}, - {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, - {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, - {col1: "Col1: Time", col2: FauxDataLogger.headers[0]}, - {col1: "Col2: Sensor", col2: FauxDataLogger.headers[1]}, - {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, - ] - } else { - metadata = [ - {col1: "Taken", col2: FauxDataLogger.dateStamp}, - {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, - {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, - {col1: "Col1: Time", col2: FauxDataLogger.headers[0]}, - {col1: "Col2: Sensor", col2: FauxDataLogger.headers[1]}, - {col1: "Col3: Sensor", col2: FauxDataLogger.headers[2]}, - {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()}, - ] - } + const metadata = FauxDataLogger.getMetadata() - for (let row = 0; row < rowSize; row++) { + for (let row = 0; row < METADATA_MAX_ROWS; row++) { Screen.print( - metadata[row + this.xScrollOffset].col1, - Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[row + this.xScrollOffset].col1.length) / 2), + metadata[row + this.yScrollOffset].col1, + Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[row + this.yScrollOffset].col1.length) / 2), Screen.TOP_EDGE + (row * rowDelta) + (rowDelta / 2) - 4, 0xb, simage.font8 ) Screen.print( - metadata[row + this.xScrollOffset].col2, - Screen.LEFT_EDGE + colSize + (colSize / 2) - ((font.charWidth * metadata[row + this.xScrollOffset].col2.length) / 2), + metadata[row + this.yScrollOffset].col2, + Screen.LEFT_EDGE + colSize + (colSize / 2) - ((font.charWidth * metadata[row + this.yScrollOffset].col2.length) / 2), Screen.TOP_EDGE + (row * rowDelta) + (rowDelta / 2) - 4, 0xb, simage.font8 @@ -182,17 +176,17 @@ namespace microcode { } break; - case DATA_VIEW_DISPLAY_MODE.DATA_VIEW: + case DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW: this.draw_grid() - const colSizeBuffer = Screen.WIDTH / Math.min(MAX_COLS, FauxDataLogger.headers.length) - const rowDeltaBuffer = Screen.HEIGHT / Math.min(MAX_ROWS, FauxDataLogger.numberOfRows) + const colSizeBuffer = Screen.WIDTH / Math.min(TABULAR_MAX_COLS, FauxDataLogger.headers.length) + const rowDeltaBuffer = Screen.HEIGHT / Math.min(TABULAR_MAX_ROWS, FauxDataLogger.numberOfRows) - for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, MAX_ROWS); row++) { - const data = FauxDataLogger.values[row + this.xScrollOffset].data; + for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS); row++) { + const data = FauxDataLogger.values[row + this.yScrollOffset].data; - for (let col = 0; col < Math.min(FauxDataLogger.headers.length, MAX_COLS); col++) { - const colID = col + this.yScrollOffset + for (let col = 0; col < Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS); col++) { + const colID = col + this.xScrollOffset Screen.print( data[colID], Screen.LEFT_EDGE + (col * colSizeBuffer) + (colSizeBuffer / 2) - ((font.charWidth * data[colID].length) / 2), From 0b9df592e655097ee465e2d217f84f74adff6e8e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 12 Mar 2024 23:50:09 +0000 Subject: [PATCH 055/109] Refactored to use parameterised draw_grid(), better variable naming, resulting in shorter, more concise & cleaner code. --- tabularDataViewer.ts | 48 ++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index f1d7d9d..89957ff 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -96,10 +96,7 @@ namespace microcode { } - draw_grid() { - const colBufferSize = Screen.WIDTH / Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS) - const rowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS) - + draw_grid(colBufferSize: number, rowBufferSize: number) { for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( Screen.LEFT_EDGE + colOffset, @@ -132,44 +129,25 @@ namespace microcode { switch (this.guiState) { case DATA_VIEW_DISPLAY_MODE.METADATA_VIEW: - const colSize = Screen.WIDTH / 2 - const rowDelta = Screen.HEIGHT / METADATA_MAX_ROWS - - for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colSize) { - Screen.drawLine( - Screen.LEFT_EDGE + colOffset, - Screen.TOP_EDGE, - Screen.LEFT_EDGE + colOffset, - Screen.HEIGHT, - 0x0 - ) - } - - for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=rowDelta) { - Screen.drawLine( - Screen.LEFT_EDGE, - Screen.TOP_EDGE + rowOffset, - Screen.WIDTH, - Screen.TOP_EDGE + rowOffset, - 0x0 - ) - } + const metadataColSize = Screen.WIDTH / 2 + const metadataRowSize = Screen.HEIGHT / METADATA_MAX_ROWS + this.draw_grid(metadataColSize, metadataRowSize) const metadata = FauxDataLogger.getMetadata() for (let row = 0; row < METADATA_MAX_ROWS; row++) { Screen.print( metadata[row + this.yScrollOffset].col1, - Screen.LEFT_EDGE + (colSize / 2) - ((font.charWidth * metadata[row + this.yScrollOffset].col1.length) / 2), - Screen.TOP_EDGE + (row * rowDelta) + (rowDelta / 2) - 4, + Screen.LEFT_EDGE + (metadataColSize / 2) - ((font.charWidth * metadata[row + this.yScrollOffset].col1.length) / 2), + Screen.TOP_EDGE + (row * metadataRowSize) + (metadataRowSize / 2) - 4, 0xb, simage.font8 ) Screen.print( metadata[row + this.yScrollOffset].col2, - Screen.LEFT_EDGE + colSize + (colSize / 2) - ((font.charWidth * metadata[row + this.yScrollOffset].col2.length) / 2), - Screen.TOP_EDGE + (row * rowDelta) + (rowDelta / 2) - 4, + Screen.LEFT_EDGE + metadataColSize + (metadataColSize / 2) - ((font.charWidth * metadata[row + this.yScrollOffset].col2.length) / 2), + Screen.TOP_EDGE + (row * metadataRowSize) + (metadataRowSize / 2) - 4, 0xb, simage.font8 ) @@ -177,10 +155,10 @@ namespace microcode { break; case DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW: - this.draw_grid() + const tabularColSize = Screen.WIDTH / Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS) + const tabularRowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS) - const colSizeBuffer = Screen.WIDTH / Math.min(TABULAR_MAX_COLS, FauxDataLogger.headers.length) - const rowDeltaBuffer = Screen.HEIGHT / Math.min(TABULAR_MAX_ROWS, FauxDataLogger.numberOfRows) + this.draw_grid(tabularColSize, tabularRowBufferSize) for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS); row++) { const data = FauxDataLogger.values[row + this.yScrollOffset].data; @@ -189,8 +167,8 @@ namespace microcode { const colID = col + this.xScrollOffset Screen.print( data[colID], - Screen.LEFT_EDGE + (col * colSizeBuffer) + (colSizeBuffer / 2) - ((font.charWidth * data[colID].length) / 2), - Screen.TOP_EDGE + (row * rowDeltaBuffer) + (rowDeltaBuffer / 2) - 4, + Screen.LEFT_EDGE + (col * tabularColSize) + (tabularColSize / 2) - ((font.charWidth * data[colID].length) / 2), + Screen.TOP_EDGE + (row * tabularRowBufferSize) + (tabularRowBufferSize / 2) - 4, 0xb, simage.font8 ) From 80cec8a91dbd3d4f3be6c3fc93a3642269e2a763 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 13 Mar 2024 05:58:04 +0000 Subject: [PATCH 056/109] moved CursorSceneEnum to cursorscene & removed sceneFactory. --- cursorscene.ts | 8 +++++++- pxt.json | 1 - sceneFactory.ts | 28 ---------------------------- 3 files changed, 7 insertions(+), 30 deletions(-) delete mode 100644 sceneFactory.ts diff --git a/cursorscene.ts b/cursorscene.ts index f61879c..62ce97f 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -1,5 +1,11 @@ namespace microcode { - + export enum CursorSceneEnum { + LiveDataViewer, + SensorSelect, + MeasurementConfigSelect, + RecordData, + } + export class CursorScene extends Scene { navigator: INavigator public cursor: Cursor diff --git a/pxt.json b/pxt.json index f6a2a91..98973d1 100644 --- a/pxt.json +++ b/pxt.json @@ -49,7 +49,6 @@ "sensorSelect.ts", "measurementConfigSelect.ts", "fauxDatalogger.ts", - "sceneFactory.ts", "measurementOptions.ts", "dataViewSelect.ts", "sensors.ts", diff --git a/sceneFactory.ts b/sceneFactory.ts deleted file mode 100644 index 9829b46..0000000 --- a/sceneFactory.ts +++ /dev/null @@ -1,28 +0,0 @@ -namespace microcode { - export enum CursorSceneEnum { - LiveDataViewer, - SensorSelect, - MeasurementConfigSelect, - RecordData, - } - - - export function generateScene(sceneEnum: CursorSceneEnum, app: App, sensors: Sensor[], mOpts?: MeasurementOpts, nextScene?: CursorSceneEnum) { - switch (sceneEnum) { - case CursorSceneEnum.LiveDataViewer: - return new LiveDataViewer(app, sensors) - - case CursorSceneEnum.SensorSelect: - return new SensorSelect(app, nextScene) - - case CursorSceneEnum.MeasurementConfigSelect: - return new MeasurementConfigSelect(app, sensors) - - case CursorSceneEnum.RecordData: - return new DataRecorder(app, mOpts, sensors) - - default: - return new LiveDataViewer(app, sensors); - } - } -} \ No newline at end of file From 1b79cc420b34ba1fd18cc76d99e4aa8b06aab6f5 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 13 Mar 2024 13:57:52 +0000 Subject: [PATCH 057/109] Additional documentation, Accelerometer X & Z axis. --- dataRecorder.ts | 3 +- dataViewSelect.ts | 12 +++- fauxDatalogger.ts | 6 +- sensorSelect.ts | 164 +++++++++++++++++++++------------------------- sensors.ts | 62 ++++++++++++------ tooltips.ts | 3 + 6 files changed, 133 insertions(+), 117 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index b095bf3..4d87258 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -13,7 +13,7 @@ namespace microcode { headers.push(sensor.name) }) - this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts, sensors) + this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts) this.loggingStartTime = input.runningTime() this.measurementOpts = measurementOpts @@ -60,7 +60,6 @@ namespace microcode { screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); screen.printCenter(secondsLeft.toString() + " seconds left", 85); - // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) // Collect the data to log: diff --git a/dataViewSelect.ts b/dataViewSelect.ts index 2ce6ff0..00d1b1b 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -1,4 +1,10 @@ -namespace microcode { +namespace microcode { + /** + * Choose between viewing: + * Metadata of the recoreded data + * A tabular view of the recorded data + * A graph of the recorded data + */ export class DataViewSelect extends CursorSceneWithPriorPage { private metaDataBtn: Button private dataViewBtn: Button @@ -11,6 +17,10 @@ namespace microcode { /* override */ startup() { super.startup() + //--------- + // Control: + //--------- + if (FauxDataLogger.isEmpty) { control.onEvent( ControllerButtonEvent.Pressed, diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index 55916ae..ebf82e0 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -11,15 +11,11 @@ namespace microcode { static numberOfRows: number static isEmpty: boolean = true static measurementOptions: MeasurementOpts - - private static sensors: Sensor[] - constructor(headers: string[], mOpts: MeasurementOpts, sensors: Sensor[]) { + constructor(headers: string[], mOpts: MeasurementOpts) { FauxDataLogger.headers = headers FauxDataLogger.values = [] FauxDataLogger.numberOfRows = 0 - - FauxDataLogger.sensors = sensors FauxDataLogger.measurementOptions = mOpts } diff --git a/sensorSelect.ts b/sensorSelect.ts index 5a31285..8856633 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -1,4 +1,10 @@ namespace microcode { + /** + * Responsible for allowing the user to select any number of sensors. + * These sensors are passed to either the measurement screen or the live data view + * + * More buttons may be added to support additional sensors + */ export class SensorSelect extends CursorSceneWithPriorPage { private btns: Button[] private selectedSensors: Sensor[] @@ -13,14 +19,12 @@ namespace microcode { /* override */ startup() { super.startup() - - // Issues with Crashing when too many buttons are visible persist: this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, icon: "accelerometer", - ariaId: "accelerometer", + ariaId: "accelerometer X", x: -60, y: -40, onClick: () => { @@ -32,12 +36,12 @@ namespace microcode { this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "pin_0", - ariaId: "Pin 0", + icon: "accelerometer", + ariaId: "accelerometer Y", x: -30, y: -40, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P0)) + this.selectedSensors.push(new AccelerometerSensor(Dimension.Y)) }, dynamicBoundaryColorsOn: true, })) @@ -45,70 +49,82 @@ namespace microcode { this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "pin_1", - ariaId: "Pin 1", + icon: "accelerometer", + ariaId: "accelerometer Z", x: 0, y: -40, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P1)) + this.selectedSensors.push(new AccelerometerSensor(Dimension.Z)) }, dynamicBoundaryColorsOn: true, })) - this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "pin_2", - ariaId: "Pin 2", + icon: "right_turn", + ariaId: "Pitch", x: 30, y: -40, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P2)) - }, - dynamicBoundaryColorsOn: true, + this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + }, + dynamicBoundaryColorsOn: true, })) - this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "magnet", - ariaId: "S10", + icon: "right_spin", + ariaId: "Roll", x: 60, y: -40, onClick: () => { - this.selectedSensors.push(new MagnetSensor(Dimension.X)) + this.selectedSensors.push(new RotationSensor(Rotation.Roll)) }, - dynamicBoundaryColorsOn: true, + dynamicBoundaryColorsOn: true, })) + // ----------- + this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "right_turn", - ariaId: "Pitch", + icon: "pin_0", + ariaId: "Pin 0", x: -60, y: -11, onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) - }, - dynamicBoundaryColorsOn: true, + this.selectedSensors.push(new PinSensor(TouchPin.P0)) + }, + dynamicBoundaryColorsOn: true, })) - // ----------- - this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "right_spin", - ariaId: "Roll", + icon: "pin_1", + ariaId: "Pin 1", x: -30, y: -11, onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + this.selectedSensors.push(new PinSensor(TouchPin.P1)) }, - dynamicBoundaryColorsOn: true, + dynamicBoundaryColorsOn: true, + })) + + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "pin_2", + ariaId: "Pin 2", + x: 0, + y: -11, + onClick: () => { + this.selectedSensors.push(new PinSensor(TouchPin.P2)) + }, + dynamicBoundaryColorsOn: true, })) @@ -117,7 +133,7 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "led_light_sensor", ariaId: "led_light_sensor", - x: 0, + x: 30, y: -11, onClick: () => { this.selectedSensors.push(new LightSensor()) @@ -130,7 +146,7 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "thermometer", ariaId: "thermometer", - x: 30, + x: 60, y: -11, onClick: () => { this.selectedSensors.push(new TemperatureSensor()) @@ -138,13 +154,28 @@ namespace microcode { dynamicBoundaryColorsOn: true, })) + // ----------- + + this.btns.push(new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "magnet", + ariaId: "S10", + x: -60, + y: 18, + onClick: () => { + this.selectedSensors.push(new MagnetSensor(Dimension.X)) + }, + dynamicBoundaryColorsOn: true, + })) + this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, icon: "finger_press", ariaId: "Logo Press", - x: 60, - y: -11, + x: -30, + y: 18, onClick: () => { this.selectedSensors.push(new LogoPressSensor()) }, @@ -156,84 +187,41 @@ namespace microcode { style: ButtonStyles.Transparent, icon: "speaker", ariaId: "Volume", - x: -60, - y: 15, + x: 0, + y: 18, onClick: () => { this.selectedSensors.push(new VolumeSensor()) }, dynamicBoundaryColorsOn: true, })) - - //----------- - this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, icon: "compass", ariaId: "Compass", - x: -30, - y: 15, + x: 30, + y: 18, onClick: () => { this.selectedSensors.push(new CompassHeadingSensor()) }, dynamicBoundaryColorsOn: true, })) - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "compass", - // ariaId: "Compass", - // x: 0, - // y: 15, - // onClick: () => { - // this.selectedSensors.push(new CompassHeadingSensor()) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "compass", - // ariaId: "Compass", - // x: 30, - // y: 15, - // onClick: () => { - // this.selectedSensors.push(new CompassHeadingSensor()) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - // this.btns.push(new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "compass", - // ariaId: "Compass", - // x: 60, - // y: 15, - // onClick: () => { - // this.selectedSensors.push(new CompassHeadingSensor()) - // }, - // dynamicBoundaryColorsOn: true, - // })) - - //----------- - this.btns.push(new Button({ parent: null, style: ButtonStyles.Transparent, - icon: "tile_button_a", + icon: "tile_button_a", ariaId: "F3", - x: -60, - y: 41, + x: 60, + y: 18, onClick: () => { this.selectedSensors.push(new ButtonPressSensor()) - }, + }, dynamicBoundaryColorsOn: true, })) + //----------- this.btns.push(new Button({ parent: null, @@ -241,7 +229,7 @@ namespace microcode { icon: "green_tick", ariaId: "Done", x: 60, - y: 41, + y: 44, onClick: () => { if (this.selectedSensors.length === 0) { return diff --git a/sensors.ts b/sensors.ts index 9900bc0..5897724 100644 --- a/sensors.ts +++ b/sensors.ts @@ -1,20 +1,17 @@ namespace microcode { - export type SensorOpts = { - sensorFn: () => number, - sensorName: string, - }; - - const PLOT_SMOOTHING_CONSTANT = 8 - + /** + * Abstraction for all available sensors, + * Methods are seldom overidden + */ export abstract class Sensor { static BUFFER_LIMIT = 100; + static PLOT_SMOOTHING_CONSTANT = 8 - sensorFn: () => number - name: string - - minimum: number - maximum: number - peakDataPoint: number[] + public sensorFn: () => number + public name: string + public minimum: number + public maximum: number + public peakDataPoint: number[] private numberOfDisplayModes: number; private currentDisplayMode: number; @@ -79,8 +76,8 @@ namespace microcode { * @param color */ draw(fromX: number, fromY: number, color: number): void { - for (let i = 0; i < this.dataBuffer.length - 1; i++) { + // Normalise the data points, then calculate their position for the graph: const norm1 = ((this.dataBuffer[i] - this.minimum) / (this.maximum + Math.abs(this.minimum))) * (screen.height - fromY) const norm2 = ((this.dataBuffer[i + 1] - this.minimum) / (this.maximum + Math.abs(this.minimum))) * (screen.height - fromY) const y1 = Math.round(screen.height - norm1) - fromY @@ -91,7 +88,7 @@ namespace microcode { } // Minimal data smoothing: - if (Math.abs(y1 - y2) <= PLOT_SMOOTHING_CONSTANT) { + if (Math.abs(y1 - y2) <= Sensor.PLOT_SMOOTHING_CONSTANT) { screen.drawLine(fromX + i, y1, fromX + i - 1, y1, color); } @@ -100,12 +97,18 @@ namespace microcode { } } + /** + * Onboard Light Sensor; ranged between 0 and 255 + */ export class LightSensor extends Sensor { constructor() { super(function () {return input.lightLevel()}, "Light", 0, 255, 1) } } + /** + * Onboard Thermometer; ranged between 0 and 100 + */ export class TemperatureSensor extends Sensor { constructor() { super(function () {return input.temperature()}, "Temp.", 0, 100, 1) @@ -114,8 +117,7 @@ namespace microcode { /** - * sensorMinReading not implemented - * sensorMaxReading not implemented + * Onboard Accelerometer for X, Y, Z dimensions; ranged between -1023, 1023 */ export class AccelerometerSensor extends Sensor { constructor(dim: Dimension) { @@ -123,6 +125,9 @@ namespace microcode { } } + /** + * Onboard Touch Pin Sensor for TouchPin 0, 1, 2; ranged between 0 and 1 + */ export class PinSensor extends Sensor { constructor(pin: TouchPin) { super(function () { @@ -141,6 +146,11 @@ namespace microcode { } + /** + * Onboard Magnometer for X, Y, Z dimensions + * + * MIN & MAX RANGE UNVERIFIED + */ export class MagnetSensor extends Sensor { constructor(dim: Dimension) { super(function() {return input.magneticForce(dim)}, @@ -154,8 +164,9 @@ namespace microcode { /** - * sensorMinReading not implemented - * sensorMaxReading not implemented + * Onboard Pitch or Roll sensor + * + * MIN & MAX RANGE UNVERIFIED */ export class RotationSensor extends Sensor { constructor(rot: Rotation) { @@ -170,6 +181,8 @@ namespace microcode { } /** + * Detection of whether of not the Logo has been pressed + * * sensorMinReading may change in future * sensorMaxReading may change in future */ @@ -179,21 +192,28 @@ namespace microcode { } } + /** + * Sensor for the current Compass Heading + * Ranged between 0 and 360 degrees + */ export class CompassHeadingSensor extends Sensor { constructor() { super(function () {return input.compassHeading()}, "Compass", 0, 360, 1) } } + /** + * Sensor for the Microphone + * Ranged between 0 and 255 + */ export class VolumeSensor extends Sensor { constructor() { super(function () {return input.soundLevel()}, "Volume", 0, 255, 1) } } - - /** + * Sensor for Microbit A & B Buttons * Need to be transformed into an event based system */ export class ButtonPressSensor extends Sensor { diff --git a/tooltips.ts b/tooltips.ts index b0016c1..4a5ba3d 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -153,6 +153,9 @@ namespace microcode { else if (id == "led_light_sensor") res = "Light Sensor" else if (id == "thermometer") res = "Thermometer" else if (id == "accelerometer") res = "Accelerometer" + else if (id == "accelerometer X") res = "Accelerometer X" + else if (id == "accelerometer Y") res = "Accelerometer Y" + else if (id == "accelerometer Z") res = "Accelerometer Z" else if (id == "Roll") res = "Roll" else if (id == "Pitch") res = "Pitch" From 8084dc20e21196ec40c436231909e9f703a4c90f Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 13 Mar 2024 14:11:57 +0000 Subject: [PATCH 058/109] Oscilloscope selection now wraps around, selection starts on sensor with lowest reading, additional documentation, oscilloscope starts on relative movement mode - instead of move-by-1-unit mode. --- home.ts | 4 ++-- liveDataViewer.ts | 16 ++++++++++++++-- tabularDataViewer.ts | 3 --- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/home.ts b/home.ts index cdbcda9..9c56a4c 100644 --- a/home.ts +++ b/home.ts @@ -58,8 +58,8 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - "Prototype 6", - Screen.RIGHT_EDGE - font.charWidth * "Prototype 6".length, + "Prototype 8", + Screen.RIGHT_EDGE - font.charWidth * "Prototype 8".length, Screen.BOTTOM_EDGE - font.charHeight - 2, 0xb, font diff --git a/liveDataViewer.ts b/liveDataViewer.ts index dc11d81..d9786cb 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -27,6 +27,7 @@ namespace microcode { /* Continue reading from the sensors? Or pause sensor reading? */ private requestDataMode: boolean + /* Use the Left & Right Buttons to move by 1 unit? or jump relative to the start/end? */ private oscilloscopeMovementMode: boolean private selectedSensorIndex: number @@ -54,9 +55,19 @@ namespace microcode { this.currentZoomDepth = 0 this.requestDataMode = true // Constant data flow - this.oscilloscopeMovementMode = true // Move Left/Right by 1 unit + this.oscilloscopeMovementMode = false // Move Left/Right relative to end/start position + + // Ensure selectedSensorIndex is set to the lowest current reading this.selectedSensorIndex = 0 + let minimumReading = sensors[0].getReading() + for (let i = 1; i < sensors.length; i++) { + if (sensors[i].getReading() < minimumReading) { + minimumReading = sensors[i].getReading() + this.selectedSensorIndex = i + } + } + //-------------------------------- // Oscilloscope Movement Controls: //-------------------------------- @@ -140,7 +151,8 @@ namespace microcode { controller.down.id, () => { if (this.currentZoomDepth > 0) { - this.selectedSensorIndex = Math.max(this.selectedSensorIndex - 1, 0) + // Handling negative modulo: + this.selectedSensorIndex = (((this.selectedSensorIndex - 1) % this.sensors.length) + this.sensors.length) % this.sensors.length this.selectedYCoordinate = this.sensors[this.selectedSensorIndex].getNthReading(this.selectedXCoordinate) } else { diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index 89957ff..73ea38a 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -11,7 +11,6 @@ namespace microcode { METADATA_VIEW, TABULAR_DATA_VIEW, } - /** * Used to view the recorded data & its meta data @@ -57,7 +56,6 @@ namespace microcode { } ) - control.onEvent( ControllerButtonEvent.Pressed, controller.down.id, @@ -93,7 +91,6 @@ namespace microcode { } } ) - } draw_grid(colBufferSize: number, rowBufferSize: number) { From fd5a6e8da8e63371162741c653a55fabb35229f5 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 13 Mar 2024 18:12:14 +0000 Subject: [PATCH 059/109] Additional documentation, added sensor to FauxDataLogger, working graph Generation - though rudimentary. --- dataRecorder.ts | 2 +- fauxDatalogger.ts | 24 ++++++++++---- generateGraph.ts | 77 ++++++++++++-------------------------------- liveDataViewer.ts | 3 +- tabularDataViewer.ts | 2 +- 5 files changed, 41 insertions(+), 67 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 4d87258..3cb57de 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -13,7 +13,7 @@ namespace microcode { headers.push(sensor.name) }) - this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts) + this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts, sensors) this.loggingStartTime = input.runningTime() this.measurementOpts = measurementOpts diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index ebf82e0..f20fd74 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -1,28 +1,38 @@ namespace microcode { - interface MetaData { + /** + * Internal representation of an logged entry + */ + interface DataEntry { id: number, data: string[] } + /** + * Temporary replacement for the DataLogger extension + * Allows for development of MicroData without such an extension. + * The downside is that the FauxDatalogger stores the data in RAM. + */ export class FauxDataLogger { static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] - static dateStamp = "06/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() - static values: MetaData[] + static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() + static entries: DataEntry[] static numberOfRows: number static isEmpty: boolean = true static measurementOptions: MeasurementOpts + static sensors: Sensor[] - constructor(headers: string[], mOpts: MeasurementOpts) { + constructor(headers: string[], mOpts: MeasurementOpts, sensors: Sensor[]) { FauxDataLogger.headers = headers - FauxDataLogger.values = [] + FauxDataLogger.entries = [] FauxDataLogger.numberOfRows = 0 FauxDataLogger.measurementOptions = mOpts + FauxDataLogger.sensors = sensors } public static log(data: string[]) { FauxDataLogger.isEmpty = false - FauxDataLogger.values.push({ - id: this.values.length, + FauxDataLogger.entries.push({ + id: this.entries.length, data }) FauxDataLogger.numberOfRows += 1 diff --git a/generateGraph.ts b/generateGraph.ts index 93431a0..60e35c5 100644 --- a/generateGraph.ts +++ b/generateGraph.ts @@ -1,6 +1,4 @@ namespace microcode { - const PLOT_SMOOTHING_CONSTANT = 8 - export class GraphGenerator extends Scene { private windowWidth: number private windowHeight: number @@ -30,7 +28,6 @@ namespace microcode { screen.fill(this.color); this.plot() - basic.pause(100); } @@ -38,68 +35,36 @@ namespace microcode { * Display mode for plotting all incoming data on y axis */ private plot() { - let color = 8; + let color = 8 - this.draw_axes(); - - // // Write Sensor information, displayed below the plot: - // for (let i = 0; i < FauxDataLogger.headers.length; i++) { - // // Colour used to represent this sensor, same colour as plotted & ticker: - // screen.fillRect( - // 2, - // this.windowHeight - this.windowBotBuffer + 15 + (i * 12), - // 7, - // 7, - // color - // ) - - // // Name, reading / maximum, peak - // screen.print(FauxDataLogger.headers[i], - // 14, - // this.windowHeight - this.windowBotBuffer + 15 + (i * 12), - // color - // ) - - // color = (color + 1) % 15 - // } + this.draw_axes() // Draw data lines: - color = 8; - let x = 0 - let xOffset = this.windowWidthBuffer / FauxDataLogger.numberOfRows + const fromY = this.windowBotBuffer + const fromX = this.windowWidthBuffer + 2 - FauxDataLogger.values.forEach(function(metadata) { - // const y1 = Math.round(screen.height - ((metadata.data[1] / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer - // const y2 = Math.round(screen.height - ((Number(metadata.data[1]) / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer - - // if (this.dataBuffer[i] > this.peakDataPoint[1]) { - // this.peakDataPoint = [i, this.dataBuffer[i]] - // } - - // Minimal data smoothing: - // if (Math.abs(y1 - y2) <= PLOT_SMOOTHING_CONSTANT) { - // screen.drawLine(this.windowWidthBuffer + x, y1, this.windowWidthBuffer + x - 1, y1, color); - // } + for (let col = 1; col < FauxDataLogger.headers.length; col++) { + const minimum = FauxDataLogger.sensors[col - 1].minimum + const maximum = FauxDataLogger.sensors[col - 1].maximum + for (let row = 0; row < FauxDataLogger.numberOfRows - 1; row++) { + const norm1 = ((+FauxDataLogger.entries[row].data[col] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) + const norm2 = ((+FauxDataLogger.entries[row + 1].data[col] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) - x += xOffset + // const a = FauxDataLogger.entries[row].data[0] + + const y1 = Math.round(screen.height - norm1) - fromY + const y2 = Math.round(screen.height - norm2) - fromY - // const y1 = Math.round(screen.height - ((this.dataBuffer[i] / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer - // const y2 = Math.round(screen.height - ((this.dataBuffer[i + 1] / this.maxReading) * (screen.height - this.windowBotBuffer))) - this.windowBotBuffer - - // if (this.dataBuffer[i] > this.peakDataPoint[1]) { - // this.peakDataPoint = [i, this.dataBuffer[i]] - // } - - // // Minimal data smoothing: - // if (Math.abs(y1 - y2) <= PLOT_SMOOTHING_CONSTANT) { - // screen.drawLine(this.windowWidthBuffer + i, y1, this.windowWidthBuffer + i - 1, y1, color); - // } + // Minimal data smoothing: + if (Math.abs(y1 - y2) <= Sensor.PLOT_SMOOTHING_CONSTANT) { + screen.drawLine(fromX + row, y1, fromX + row - 1, y1, color); + } - // screen.drawLine(this.windowWidthBuffer + i, y1, this.windowWidthBuffer + i - 1, y2, color); - + screen.drawLine(fromX + row, y1, fromX + row - 1, y2, color); + } color = (color + 1) % 15 - }) + } } /** diff --git a/liveDataViewer.ts b/liveDataViewer.ts index d9786cb..fe600ba 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -74,13 +74,12 @@ namespace microcode { // Use Microbit A button to pause/continue reading new data: control.onEvent(DAL.DEVICE_BUTTON_EVT_DOWN, DAL.DEVICE_ID_BUTTON_A, () => { - this.requestDataMode = !this.requestDataMode + this.requestDataMode = !this.requestDataMode }) // Use Microbit B button to control the oscilloscope x-axis movement mode: control.onEvent(DAL.DEVICE_BUTTON_EVT_DOWN, DAL.DEVICE_ID_BUTTON_B, () => { this.oscilloscopeMovementMode = !this.oscilloscopeMovementMode - // basic.showNumber(5) }) // Zoom in: diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index 73ea38a..c9637e4 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -158,7 +158,7 @@ namespace microcode { this.draw_grid(tabularColSize, tabularRowBufferSize) for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS); row++) { - const data = FauxDataLogger.values[row + this.yScrollOffset].data; + const data = FauxDataLogger.entries[row + this.yScrollOffset].data; for (let col = 0; col < Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS); col++) { const colID = col + this.xScrollOffset From f8f76bfcab72ed4a3142c19bade3870d04b11d10 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sat, 16 Mar 2024 23:54:01 +0000 Subject: [PATCH 060/109] Preperation for datalogger experiments, incremented prototype version. --- dataRecorder.ts | 2 +- generateGraph.ts | 2 -- home.ts | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 3cb57de..77145a9 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -60,7 +60,7 @@ namespace microcode { screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); screen.printCenter(secondsLeft.toString() + " seconds left", 85); - // datalogger.log(datalogger.createCV(this.measurementOpts.sensorName, this.measurementOpts.sensorFn())) + datalogger.log(datalogger.createCV("col1", "hello")) // Collect the data to log: let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] // Log time diff --git a/generateGraph.ts b/generateGraph.ts index 60e35c5..89c4623 100644 --- a/generateGraph.ts +++ b/generateGraph.ts @@ -50,8 +50,6 @@ namespace microcode { for (let row = 0; row < FauxDataLogger.numberOfRows - 1; row++) { const norm1 = ((+FauxDataLogger.entries[row].data[col] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) const norm2 = ((+FauxDataLogger.entries[row + 1].data[col] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) - - // const a = FauxDataLogger.entries[row].data[0] const y1 = Math.round(screen.height - norm1) - fromY const y2 = Math.round(screen.height - norm2) - fromY diff --git a/home.ts b/home.ts index 9c56a4c..3aff348 100644 --- a/home.ts +++ b/home.ts @@ -58,8 +58,8 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - "Prototype 8", - Screen.RIGHT_EDGE - font.charWidth * "Prototype 8".length, + "Prototype 9", + Screen.RIGHT_EDGE - font.charWidth * "Prototype 9".length, Screen.BOTTOM_EDGE - font.charHeight - 2, 0xb, font From 59230713fe02f91e562349f551ddef1ecb87048a Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 17 Mar 2024 23:56:08 +0000 Subject: [PATCH 061/109] Modified the dataRecorder to use a state design pattern for the recording behaviour: Event or Timed, refactored the code into 1 external class, 2 internal classes for the concrete behaviours, an internal enum & an internal interface. --- asci_art.txt | 117 ------------------------------------------------ dataRecorder.ts | 59 +++++++++++++++++++----- 2 files changed, 49 insertions(+), 127 deletions(-) delete mode 100644 asci_art.txt diff --git a/asci_art.txt b/asci_art.txt deleted file mode 100644 index e321934..0000000 --- a/asci_art.txt +++ /dev/null @@ -1,117 +0,0 @@ - ................................ - ................................ - ...............dd............... - ..............dddd.............. - .....dddd...ddbbbbcc...dddd..... - .....dddd...ddbbbbcc...dddd..... - ...dddbbbb..ddbbbbcc..dbbbccc... - ...dddbbbbccddbbbbccdddbbbccc... - ....ddbbbbbbbbbbbbbbbbbbbbcc.... - .....dbbbbbbbbbbbbbbbbbbbbc..... - ......ccbbddbbccccbbddbbcc...... - ......ccbbddbbc..cbbddbbcc...... - .....dddbbbbcc....ccbbbbdddd.... - ....ddddbbbbc......cbbbbdddd.... - ...dbbbbbbcc........ccbbbbbbc... - .dddbbbbbbc..........cbbbbbbccc. - .dddbbbbbbc..........cbbbbbbccc. - .dddbbbbbbcc........ccbbbbbbccc. - ...cccccbbbbc.......cbbbbcccc... - ....ccccbbbbcc.....ccbbbbccc.... - ......ddbbddbbc..cbbddbbcc...... - ......ddbbddbbccccbbddbbcc...... - .....dbbbbbbbbbbbbbbbbbbbbc..... - ....ddbbbbbbbbbbbbbbbbbbbbcc.... - ....ddbbbbccccbbbbccccbbbbcc.... - ....ddbbbb..ccbbbbcc..bbbbcc.... - .....cccc...ccbbbbcc...cccc..... - .....cccc...ccbbbbcc...cccc..... - ..............cccc.............. - ...............cc............... - ................................ - ................................ - - . . . . . . . . . . . . . . . . - . . . . . . . d d . . . . . . . - . . . d d . d b b c . d d . . . - . . d b b c d b b c d b b c . . - . . d b b b b b b b b b b c . . - . . . c b d b c c b d b c . . . - . . d d b b c . . c b b d d . . - . d b b b c . . . . c b b b c . - . d b b b c . . . . c b b b c . - . . c c b b c . . c b b c c . . - . . . d b d b c c b d b c . . . - . . d b b b b b b b b b b c . . - . . d b b c c b b c c b b c . . - . . . c c . c b b c . c c . . . - . . . . . . . c c . . . . . . . - . . . . . . . . . . . . . . . . - - .11111111..............11111111. - 1bbbbbbbb..............bbbbbbbb1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - b..............................b - ................................ - ...............11............... - ...............11............... - ...............11............... - ...............11............... - ...........1111111111........... - ...........1111111111........... - ...........bbbb11bbbb........... - ...............11............... - ...............11............... - ...............11............... - ...............bb............... - ................................ - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - 1..............................1 - b11111111..............11111111b - .bbbbbbbb..............bbbbbbbb. - - .666666666666666666666666666666. - 66666666666666666666666666666666 - 66666666666666666666666666666666 - 6666bbbbbbbbbbbbbbbbbbbbbb666666 - 666bb811111111111111111118b66666 - 666b88111111111111111111188b6666 - 666b881111111111111111111888b666 - 666b881111111111111111111888b666 - 666b881111111111111111111888b666 - 666b881111111111111111111888b666 - 666b881111111111111111111888b666 - 666b881111111111111111111888b666 - 6666b88ccccc111111111cccccc88b66 - 6666bcccccddb111111cbbccccc88b66 - 6666bccccdbbbbbbbbbbcccc8888b666 - 6666b8cccccddbcccbdcccc88888b666 - 6666b888dbbcc11111cbddd88888b666 - 6666bddbbbcc111111cccbbb8888b666 - 66ddddbbb11111111111bbbcccc8b666 - 66ddddbbb11111111111bbbcccc8b666 - 6666bddbbbcc111111ccbbbc8888b666 - 6666b888cbbcc11111cbbcc88888b666 - 666b888ccccddbcccbdcccc88888b666 - 666b88cccdbbbbbbbbbbcccc8888b666 - 666bcccccddb1111111cbbccccc8b666 - 666b8ccccc1111111111ccccc888b666 - 666b8811111111111111111118f8b666 - 666bb81111111111111111111888b666 - 6666bbbbbbbbbbbbbbbbbbbbbbbbb666 - 66666666666666666666666666666666 - 66666666666666666666666666666666 - b666666666666666666666666666666b - .bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. \ No newline at end of file diff --git a/dataRecorder.ts b/dataRecorder.ts index 77145a9..5e1da3a 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,11 +1,14 @@ namespace microcode { + export enum RecordingMode { + EVENT, + TIME + } + export class DataRecorder extends Scene { private fauxDatalogger: FauxDataLogger - private loggingStartTime: number - private measurementOpts: MeasurementOpts - private sensors: Sensor[] + private recordingBehaviour: RecordingBehaviour - constructor(app: App, measurementOpts: MeasurementOpts, sensors: Sensor[]) { + constructor(app: App, measurementOpts: MeasurementOpts, sensors: Sensor[], recordingMode: RecordingMode) { super(app, "dataRecorder") let headers: string[] = ["Milli-Sec"] @@ -13,11 +16,15 @@ namespace microcode { headers.push(sensor.name) }) - this.fauxDatalogger = new FauxDataLogger(headers, measurementOpts, sensors) - this.loggingStartTime = input.runningTime() + new FauxDataLogger(headers, measurementOpts, sensors) - this.measurementOpts = measurementOpts - this.sensors = sensors + if (recordingMode === RecordingMode.TIME) { + this.recordingBehaviour = new TimeBasedRecording(measurementOpts, sensors) + } + + else { + this.recordingBehaviour = new EventBasedRecording() + } // Go Back: control.onEvent( @@ -39,6 +46,31 @@ namespace microcode { 0xc ) + this.recordingBehaviour.update() + } + } + + interface RecordingBehaviour { + update(): void; + } + + class TimeBasedRecording implements RecordingBehaviour { + private loggingStartTime: number + private measurementOpts: MeasurementOpts + private sensors: Sensor[] + + constructor(measurementOpts: MeasurementOpts, sensors: Sensor[]) { + let headers: string[] = ["Milli-Sec"] + sensors.forEach(function(sensor) { + headers.push(sensor.name) + }) + + this.loggingStartTime = input.runningTime() + this.measurementOpts = measurementOpts + this.sensors = sensors + } + + update(): void { if (this.measurementOpts.measurements === 0) { screen.printCenter("Data Logging Complete.", (screen.height / 2) - 10); screen.printCenter("Press B to back out.", screen.height / 2); @@ -60,10 +92,11 @@ namespace microcode { screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); screen.printCenter(secondsLeft.toString() + " seconds left", 85); - datalogger.log(datalogger.createCV("col1", "hello")) + // datalogger.log(datalogger.createCV("col1", "hello")) + + let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] // Collect the data to log: - let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] // Log time for (let i = 0; i < this.sensors.length; i++) { data.push(this.sensors[i].getReading().toString()) } @@ -75,4 +108,10 @@ namespace microcode { } } } + + export class EventBasedRecording implements RecordingBehaviour { + update(): void { + + } + } } \ No newline at end of file From e3f8fe98cea4a7b809c31cbc9037e093a1a9bb1c Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 18 Mar 2024 00:23:51 +0000 Subject: [PATCH 062/109] Removed redundant userOptions.ts; duplicate of measurementOptions.ts --- userOptions.ts | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 userOptions.ts diff --git a/userOptions.ts b/userOptions.ts deleted file mode 100644 index 2a67a94..0000000 --- a/userOptions.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace microcode { - export type MeasurementOpts = { - sensor: Sensor, - measurements: number, - period: number, - delay: number - }; -} \ No newline at end of file From 4065b28ff337bf6f0c8aeb091213f9265bdee8ff Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 18 Mar 2024 01:01:36 +0000 Subject: [PATCH 063/109] Large refactor to fauxDataLogger into a fauxLogger abstract that is extended by a fauxDataLogger & fauxEventLogger. Similar refactor to measurementConfigSelection.ts. Renamed files and classes such as measurementConfig and measurementConfigSelect into recordingConfig, recordingConfigSelection. New recordingModeSelection.ts file for future selection between the Measurement Mode and the Event mode. --- cursorscene.ts | 1 + dataRecorder.ts | 43 +++++-- eventConfigSelect.ts | 20 ++++ fauxDatalogger.ts | 108 +++++++++--------- fauxLoggers.ts | 77 +++++++++++++ pxt.json | 13 ++- measurementOptions.ts => recordingConfig.ts | 3 +- ...igSelect.ts => recordingConfigSelection.ts | 101 ++++++++++------ recordingModeSelection.ts | 54 +++++++++ sensorSelect.ts | 4 + tooltips.ts | 2 + 11 files changed, 322 insertions(+), 104 deletions(-) create mode 100644 eventConfigSelect.ts create mode 100644 fauxLoggers.ts rename measurementOptions.ts => recordingConfig.ts (63%) rename measurementConfigSelect.ts => recordingConfigSelection.ts (68%) create mode 100644 recordingModeSelection.ts diff --git a/cursorscene.ts b/cursorscene.ts index 62ce97f..44dca5c 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -3,6 +3,7 @@ namespace microcode { LiveDataViewer, SensorSelect, MeasurementConfigSelect, + EventConfigSelect, RecordData, } diff --git a/dataRecorder.ts b/dataRecorder.ts index 5e1da3a..a1b71f2 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -5,12 +5,13 @@ namespace microcode { } export class DataRecorder extends Scene { - private fauxDatalogger: FauxDataLogger + /** State pattern; see the internal classes that implement these behaviours below this file */ private recordingBehaviour: RecordingBehaviour - constructor(app: App, measurementOpts: MeasurementOpts, sensors: Sensor[], recordingMode: RecordingMode) { + constructor(app: App, measurementOpts: RecordingConfig, sensors: Sensor[], recordingMode: RecordingMode) { super(app, "dataRecorder") + let headers: string[] = ["Milli-Sec"] sensors.forEach(function(sensor) { headers.push(sensor.name) @@ -18,6 +19,8 @@ namespace microcode { new FauxDataLogger(headers, measurementOpts, sensors) + + // Get the specified behaviour from the passed RecordingMode Enum: if (recordingMode === RecordingMode.TIME) { this.recordingBehaviour = new TimeBasedRecording(measurementOpts, sensors) } @@ -26,6 +29,11 @@ namespace microcode { this.recordingBehaviour = new EventBasedRecording() } + + //--------------- + // User Controls: + //--------------- + // Go Back: control.onEvent( ControllerButtonEvent.Pressed, @@ -50,16 +58,37 @@ namespace microcode { } } + + //------------------------------------- + // Recording behaviour implementations: + //------------------------------------- + interface RecordingBehaviour { update(): void; } + /** + * A public recording behaviour. + * This + */ + export class EventBasedRecording implements RecordingBehaviour { + update(): void { + + } + } + + + /** + * Take N recordings on each of the passed sensors with the specified period, + * Makes use of the static FauxDataLogger that was setup in the parent constructor DataRecorder + * Internal Class unlike EventBasedRecording, since this class is only ever invoked via the DataRecorder + */ class TimeBasedRecording implements RecordingBehaviour { private loggingStartTime: number - private measurementOpts: MeasurementOpts + private measurementOpts: RecordingConfig private sensors: Sensor[] - constructor(measurementOpts: MeasurementOpts, sensors: Sensor[]) { + constructor(measurementOpts: RecordingConfig, sensors: Sensor[]) { let headers: string[] = ["Milli-Sec"] sensors.forEach(function(sensor) { headers.push(sensor.name) @@ -108,10 +137,4 @@ namespace microcode { } } } - - export class EventBasedRecording implements RecordingBehaviour { - update(): void { - - } - } } \ No newline at end of file diff --git a/eventConfigSelect.ts b/eventConfigSelect.ts new file mode 100644 index 0000000..979b02c --- /dev/null +++ b/eventConfigSelect.ts @@ -0,0 +1,20 @@ +namespace microcode { + const enum GUI_STATE { + WRITING, + DEFAULT + } + + export class EventConfigSelect extends Scene { + private guiState: GUI_STATE + private guiRows: string[] + private currentColumn: number + private selectedSensors: Sensor[] + + // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: + private userSelection: number[] + + constructor(app: App, selectedSensors: Sensor[]) { + super(app, "dataViewer") + } + } +} \ No newline at end of file diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts index f20fd74..1532128 100644 --- a/fauxDatalogger.ts +++ b/fauxDatalogger.ts @@ -1,61 +1,61 @@ -namespace microcode { - /** - * Internal representation of an logged entry - */ - interface DataEntry { - id: number, - data: string[] - } +// namespace microcode { +// /** +// * Internal representation of an logged entry +// */ +// interface DataEntry { +// id: number, +// data: string[] +// } - /** - * Temporary replacement for the DataLogger extension - * Allows for development of MicroData without such an extension. - * The downside is that the FauxDatalogger stores the data in RAM. - */ - export class FauxDataLogger { - static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] - static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() - static entries: DataEntry[] - static numberOfRows: number - static isEmpty: boolean = true - static measurementOptions: MeasurementOpts - static sensors: Sensor[] +// /** +// * Temporary replacement for the DataLogger extension +// * Allows for development of MicroData without such an extension. +// * The downside is that the FauxDatalogger stores the data in RAM. +// */ +// export class FauxDataLogger { +// static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] +// static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() +// static entries: DataEntry[] +// static numberOfRows: number +// static isEmpty: boolean = true +// static measurementOptions: MeasurementOpts +// static sensors: Sensor[] - constructor(headers: string[], mOpts: MeasurementOpts, sensors: Sensor[]) { - FauxDataLogger.headers = headers - FauxDataLogger.entries = [] - FauxDataLogger.numberOfRows = 0 - FauxDataLogger.measurementOptions = mOpts - FauxDataLogger.sensors = sensors - } +// constructor(headers: string[], mOpts: MeasurementOpts, sensors: Sensor[]) { +// FauxDataLogger.headers = headers +// FauxDataLogger.entries = [] +// FauxDataLogger.numberOfRows = 0 +// FauxDataLogger.measurementOptions = mOpts +// FauxDataLogger.sensors = sensors +// } - public static log(data: string[]) { - FauxDataLogger.isEmpty = false - FauxDataLogger.entries.push({ - id: this.entries.length, - data - }) - FauxDataLogger.numberOfRows += 1 - } +// public static log(data: string[]) { +// FauxDataLogger.isEmpty = false +// FauxDataLogger.entries.push({ +// id: this.entries.length, +// data +// }) +// FauxDataLogger.numberOfRows += 1 +// } - public static getNumberOfMetadataRows(): number { - return 5 + FauxDataLogger.headers.length - } +// public static getNumberOfMetadataRows(): number { +// return 5 + FauxDataLogger.headers.length +// } - public static getMetadata() { - let metadata = [ - {col1: "Date", col2: FauxDataLogger.dateStamp}, - {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, - {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, - {col1: "Measurements", col2: FauxDataLogger.measurementOptions.measurements.toString()}, - {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()} - ] +// public static getMetadata() { +// let metadata = [ +// {col1: "Date", col2: FauxDataLogger.dateStamp}, +// {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, +// {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, +// {col1: "Measurements", col2: FauxDataLogger.measurementOptions.measurements.toString()}, +// {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()} +// ] - for (let i = 0; i < FauxDataLogger.headers.length; i++) { - metadata.push({col1: "Col " + (i + 1).toString(), col2: FauxDataLogger.headers[i]}) - } +// for (let i = 0; i < FauxDataLogger.headers.length; i++) { +// metadata.push({col1: "Col " + (i + 1).toString(), col2: FauxDataLogger.headers[i]}) +// } - return metadata - } - } -} +// return metadata +// } +// } +// } diff --git a/fauxLoggers.ts b/fauxLoggers.ts new file mode 100644 index 0000000..ae9cbd3 --- /dev/null +++ b/fauxLoggers.ts @@ -0,0 +1,77 @@ +namespace microcode { + /** + * Internal representation of an logged entry + */ + interface DataEntry { + id: number, + data: string[] + } + + abstract class Logger { + static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] + static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() + static entries: DataEntry[] + static numberOfRows: number + static isEmpty: boolean = true + static measurementOptions: RecordingConfig + static sensors: Sensor[] + + constructor(headers: string[], mOpts: RecordingConfig, sensors: Sensor[]) { + Logger.headers = headers + Logger.entries = [] + Logger.numberOfRows = 0 + Logger.measurementOptions = mOpts + Logger.sensors = sensors + } + + public static log(data: string[]) { + Logger.isEmpty = false + Logger.entries.push({ + id: this.entries.length, + data + }) + Logger.numberOfRows += 1 + } + + public static getNumberOfMetadataRows(): number { + return 5 + Logger.headers.length + } + + public static getMetadata() { + let metadata = [ + {col1: "Date", col2: Logger.dateStamp}, + {col1: "Rows", col2: Logger.numberOfRows.toString()}, + {col1: "Columns", col2: Logger.headers.length.toString()}, + {col1: "Measurements", col2: Logger.measurementOptions.measurements.toString()}, + {col1: "Period", col2: Logger.measurementOptions.period.toString()} + ] + + for (let i = 0; i < Logger.headers.length; i++) { + metadata.push({col1: "Col " + (i + 1).toString(), col2: Logger.headers[i]}) + } + + return metadata + } + } + + export class FauxDataLogger extends Logger { + constructor(headers: string[], mOpts: RecordingConfig, sensors: Sensor[]) { + super(headers, mOpts, sensors) + } + } + + export class FauxEventLogger extends Logger { + constructor(headers: string[], mOpts: RecordingConfig, sensors: Sensor[]) { + super(headers, mOpts, sensors) + } + + public static log(data: string[]) { + Logger.isEmpty = false + Logger.entries.push({ + id: this.entries.length, + data + }) + Logger.numberOfRows += 1 + } + } +} \ No newline at end of file diff --git a/pxt.json b/pxt.json index 98973d1..03783cd 100644 --- a/pxt.json +++ b/pxt.json @@ -44,14 +44,19 @@ "samples.ts", "liveDataViewer.ts", - "dataRecorder.ts", "tabularDataViewer.ts", + "sensorSelect.ts", - "measurementConfigSelect.ts", - "fauxDatalogger.ts", - "measurementOptions.ts", "dataViewSelect.ts", + "eventConfigSelect.ts", + + "recordingConfig.ts", + "recordingConfigSelection.ts", + "recordingModeSelection.ts", + "sensors.ts", + "fauxLoggers.ts", + "dataRecorder.ts", "generateGraph.ts" ], diff --git a/measurementOptions.ts b/recordingConfig.ts similarity index 63% rename from measurementOptions.ts rename to recordingConfig.ts index 2a67a94..32608cb 100644 --- a/measurementOptions.ts +++ b/recordingConfig.ts @@ -1,6 +1,5 @@ namespace microcode { - export type MeasurementOpts = { - sensor: Sensor, + export type RecordingConfig = { measurements: number, period: number, delay: number diff --git a/measurementConfigSelect.ts b/recordingConfigSelection.ts similarity index 68% rename from measurementConfigSelect.ts rename to recordingConfigSelection.ts index 03bdf13..c2b05c6 100644 --- a/measurementConfigSelect.ts +++ b/recordingConfigSelection.ts @@ -1,21 +1,13 @@ namespace microcode { - // How the use - const CONFIG_DELTAS = [ - [1, 10], // Quantity - [1, 10], // Milli-seconds - [1, 5], // Seconds - [1, 5], // Minutes - [1, 5], // Hours - [1, 5], // Days - [1, 5] // Delay - ] - + /** + * Is the user changing one of the config values, or not? + */ const enum GUI_STATE { WRITING, DEFAULT } - export class MeasurementConfigSelect extends Scene { + abstract class RecordingConfigSelection extends Scene { private guiState: GUI_STATE private guiRows: string[] private currentColumn: number @@ -23,25 +15,29 @@ namespace microcode { // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: private userSelection: number[] + private configDeltas: number[][] - constructor(app: App, selectedSensors: Sensor[]) { - super(app, "dataViewer") + constructor(app: App, + appName: string, + selectedSensors: Sensor[], + configDeltas: number[][], + defaultUserSelection: number[], + guiRows: string[] + ) { + super(app, appName) this.guiState = GUI_STATE.DEFAULT - this.guiRows = ["Measurements: ", - "Milli-Seconds: ", - "Seconds: ", - "Minutes: ", - "Hours: ", - "Days: ", - "Start Delay: " - ] + this.guiRows = guiRows + + this.userSelection = defaultUserSelection + this.configDeltas = configDeltas this.currentColumn = 0 this.selectedSensors = selectedSensors - // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: - this.userSelection = [10, 0, 1, 0, 0, 0, 0] + //-------------- + // User Control: + //-------------- control.onEvent( ControllerButtonEvent.Pressed, @@ -77,7 +73,7 @@ namespace microcode { controller.up.id, () => { if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + CONFIG_DELTAS[this.currentColumn][0], 0) + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][0], 0) } else { @@ -92,7 +88,7 @@ namespace microcode { controller.down.id, () => { if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - CONFIG_DELTAS[this.currentColumn][0], 0) + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][0], 0) } else { @@ -107,22 +103,22 @@ namespace microcode { controller.left.id, () => { if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - CONFIG_DELTAS[this.currentColumn][1], 0) + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][1], 0) } } ) - control.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.right.id, () => { if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + CONFIG_DELTAS[this.currentColumn][1], 0) + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][1], 0) } else if (this.guiState === GUI_STATE.DEFAULT) { this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.generateUserOptions(), this.selectedSensors)) + this.app.pushScene(new DataRecorder(this.app, this.generateRecordingOptions(), this.selectedSensors, RecordingMode.TIME)) } } ) @@ -134,7 +130,7 @@ namespace microcode { * turn that into a MeasurementOpts obj * @returns MeasurementOptions including the sensor information that gained from sensorSelect */ - private generateUserOptions(): MeasurementOpts { + private generateRecordingOptions(): RecordingConfig { const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] let period: number = 0 @@ -143,7 +139,6 @@ namespace microcode { } return { - sensor: this.selectedSensors[0], // Does not grant multiple sensors measurements: this.userSelection[0], period, delay: this.userSelection[6] @@ -168,8 +163,7 @@ namespace microcode { const pointerX = optionX + 20 const rowSize = Screen.HEIGHT / (this.userSelection.length + 1) - - screen.printCenter("Measurement Settings", 2) + screen.printCenter("Recording Settings", 2) for (let i = 0; i < this.userSelection.length; i++) { screen.print(this.guiRows[i], @@ -193,4 +187,43 @@ namespace microcode { ) } } + + + + export class MeasurementConfigSelect extends RecordingConfigSelection { + constructor(app: App, selectedSensors: Sensor[]) { + /** + * Values for user selection of: + * Measurement quantity + * Measurement period + * Measurement delay + * + * Internal counters will iterate by these values, + * upon the corresponding UI element selection. + * */ + const configDeltas = [ + [1, 10], // Quantity + [1, 10], // Milli-seconds + [1, 5], // Seconds + [1, 5], // Minutes + [1, 5], // Hours + [1, 5], // Days + [1, 5] // Delay + ] + + // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: + const defaultUserSelection = [10, 0, 1, 0, 0, 0, 0] + const guiRows = ["Measurements: ", + "Milli-Seconds: ", + "Seconds: ", + "Minutes: ", + "Hours: ", + "Days: ", + "Start Delay: " + ] + super(app, "measurementConfigSelect", selectedSensors, configDeltas, defaultUserSelection, guiRows) + } + + + } } \ No newline at end of file diff --git a/recordingModeSelection.ts b/recordingModeSelection.ts new file mode 100644 index 0000000..e8e386f --- /dev/null +++ b/recordingModeSelection.ts @@ -0,0 +1,54 @@ +namespace microcode { + export class RecordingModeSelection extends CursorScene { + private btns: Button[] + + constructor(app: App) { + super(app) + + const recordTimeBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "edit_program", + ariaId: "Measurement Mode", + x: -30, + y: 30, + onClick: () => { + this.app.popScene() + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + }, + }) + + const recordEventBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "edit_program", + ariaId: "Event Mode", + x: 30, + y: 30, + onClick: () => { + this.app.popScene() + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.EventConfigSelect)) + }, + }) + + this.btns = [recordTimeBtn, recordEventBtn] + this.navigator.addButtons(this.btns) + } + + update() { + Screen.fillRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE, + Screen.WIDTH, + Screen.HEIGHT, + 0xc + ) + + screen.printCenter("Select the Measurement Mode", 10) + + for (let i = 0; i < this.btns.length; ++i) { + this.btns[i].draw() + } + } + } +} \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index 8856633..255bd3e 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -241,6 +241,10 @@ namespace microcode { this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) } + if (this.nextSceneEnum === CursorSceneEnum.EventConfigSelect) { + this.app.pushScene(new EventConfigSelect(app, this.selectedSensors)) + } + else { this.app.pushScene(new MeasurementConfigSelect(app, this.selectedSensors)) } diff --git a/tooltips.ts b/tooltips.ts index 4a5ba3d..903d83e 100644 --- a/tooltips.ts +++ b/tooltips.ts @@ -177,6 +177,8 @@ namespace microcode { else if (id == "Meta Data") res = "Meta Data" else if (id == "View Data") res = "View Data" else if (id == "View Graph") res = "View Graph" + else if (id == "Measurement Mode") res = "Measurement Mode" + else if (id == "Event Mode") res = "Event Mode" return res From f50651b55b3613b2badbaa31b4bef5b435a34157 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 18 Mar 2024 01:25:51 +0000 Subject: [PATCH 064/109] Added documentation & EventConfigSelect recordingConfigSelection --- eventConfigSelect.ts | 20 ------------- pxt.json | 1 - recordingConfigSelection.ts | 59 +++++++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 40 deletions(-) delete mode 100644 eventConfigSelect.ts diff --git a/eventConfigSelect.ts b/eventConfigSelect.ts deleted file mode 100644 index 979b02c..0000000 --- a/eventConfigSelect.ts +++ /dev/null @@ -1,20 +0,0 @@ -namespace microcode { - const enum GUI_STATE { - WRITING, - DEFAULT - } - - export class EventConfigSelect extends Scene { - private guiState: GUI_STATE - private guiRows: string[] - private currentColumn: number - private selectedSensors: Sensor[] - - // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: - private userSelection: number[] - - constructor(app: App, selectedSensors: Sensor[]) { - super(app, "dataViewer") - } - } -} \ No newline at end of file diff --git a/pxt.json b/pxt.json index 03783cd..579117c 100644 --- a/pxt.json +++ b/pxt.json @@ -48,7 +48,6 @@ "sensorSelect.ts", "dataViewSelect.ts", - "eventConfigSelect.ts", "recordingConfig.ts", "recordingConfigSelection.ts", diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index c2b05c6..3cb03b1 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -7,16 +7,22 @@ namespace microcode { DEFAULT } + + /** + * Abstract for the screen that allows users to input measurement or event settings. + * Extended by MeasurementConfigSelection and EventConfigSelection + * + */ abstract class RecordingConfigSelection extends Scene { private guiState: GUI_STATE private guiRows: string[] private currentColumn: number private selectedSensors: Sensor[] - - // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: - private userSelection: number[] private configDeltas: number[][] + + protected userSelection: number[] + constructor(app: App, appName: string, selectedSensors: Sensor[], @@ -126,22 +132,14 @@ namespace microcode { /** - * Convert the .userSelection data into a single milli-second value, - * turn that into a MeasurementOpts obj - * @returns MeasurementOptions including the sensor information that gained from sensorSelect + * Convert the .userSelection data into a RecordingConfig object for use by the DataRecorder + * @returns RecordingConfig {measurements, period, delay} */ - private generateRecordingOptions(): RecordingConfig { - const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] - - let period: number = 0 - for (let i = 1; i < this.userSelection.length - 1; i++) { - period += this.userSelection[i] * timeConversionTableMs[i - 1] - } - + public generateRecordingOptions(): RecordingConfig { return { - measurements: this.userSelection[0], - period, - delay: this.userSelection[6] + measurements: 0, + period: 0, + delay: 0 } } @@ -188,8 +186,6 @@ namespace microcode { } } - - export class MeasurementConfigSelect extends RecordingConfigSelection { constructor(app: App, selectedSensors: Sensor[]) { /** @@ -221,9 +217,34 @@ namespace microcode { "Days: ", "Start Delay: " ] + super(app, "measurementConfigSelect", selectedSensors, configDeltas, defaultUserSelection, guiRows) } + /** + * Convert the .userSelection data into a RecordingConfig object for use by the DataRecorder + * @returns RecordingConfig {measurements, period, delay} + */ + public generateRecordingOptions(): RecordingConfig { + const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] + + let period: number = 0 + for (let i = 1; i < this.userSelection.length - 1; i++) { + period += this.userSelection[i] * timeConversionTableMs[i - 1] + } + + return { + measurements: this.userSelection[0], + period, + delay: this.userSelection[6] + } + } + } + + export class EventConfigSelect extends RecordingConfigSelection { + constructor(app: App, selectedSensors: Sensor[]) { + super(app, "eventConfigSelect", selectedSensors, [], [], []) + } } } \ No newline at end of file From f28f3012bd345d246e3b67e08f8ba746d9d666f6 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 18 Mar 2024 01:39:18 +0000 Subject: [PATCH 065/109] removing fauxDatalogger.ts since it is unneeded now. --- fauxDatalogger.ts | 61 ----------------------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 fauxDatalogger.ts diff --git a/fauxDatalogger.ts b/fauxDatalogger.ts deleted file mode 100644 index 1532128..0000000 --- a/fauxDatalogger.ts +++ /dev/null @@ -1,61 +0,0 @@ -// namespace microcode { -// /** -// * Internal representation of an logged entry -// */ -// interface DataEntry { -// id: number, -// data: string[] -// } - -// /** -// * Temporary replacement for the DataLogger extension -// * Allows for development of MicroData without such an extension. -// * The downside is that the FauxDatalogger stores the data in RAM. -// */ -// export class FauxDataLogger { -// static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] -// static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() -// static entries: DataEntry[] -// static numberOfRows: number -// static isEmpty: boolean = true -// static measurementOptions: MeasurementOpts -// static sensors: Sensor[] - -// constructor(headers: string[], mOpts: MeasurementOpts, sensors: Sensor[]) { -// FauxDataLogger.headers = headers -// FauxDataLogger.entries = [] -// FauxDataLogger.numberOfRows = 0 -// FauxDataLogger.measurementOptions = mOpts -// FauxDataLogger.sensors = sensors -// } - -// public static log(data: string[]) { -// FauxDataLogger.isEmpty = false -// FauxDataLogger.entries.push({ -// id: this.entries.length, -// data -// }) -// FauxDataLogger.numberOfRows += 1 -// } - -// public static getNumberOfMetadataRows(): number { -// return 5 + FauxDataLogger.headers.length -// } - -// public static getMetadata() { -// let metadata = [ -// {col1: "Date", col2: FauxDataLogger.dateStamp}, -// {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, -// {col1: "Columns", col2: FauxDataLogger.headers.length.toString()}, -// {col1: "Measurements", col2: FauxDataLogger.measurementOptions.measurements.toString()}, -// {col1: "Period", col2: FauxDataLogger.measurementOptions.period.toString()} -// ] - -// for (let i = 0; i < FauxDataLogger.headers.length; i++) { -// metadata.push({col1: "Col " + (i + 1).toString(), col2: FauxDataLogger.headers[i]}) -// } - -// return metadata -// } -// } -// } From ab895441f03c7e8ce0aec8176990f545e6c8d954 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Tue, 19 Mar 2024 22:05:39 +0000 Subject: [PATCH 066/109] Added variable column sizes to the tabular data viewer, headers of the column is now displayed at the top, each sensor now occupies its own row, so that each row follows the form (Sensor.name, time, event?, reading). Updated DataRecorder and fauxLogger to reflect these changes to how logged data is recorded. --- dataRecorder.ts | 29 ++++++++++------------- fauxLoggers.ts | 44 +++++++++++++++++++++++++--------- tabularDataViewer.ts | 56 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 33 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index a1b71f2..83b3fba 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -11,14 +11,8 @@ namespace microcode { constructor(app: App, measurementOpts: RecordingConfig, sensors: Sensor[], recordingMode: RecordingMode) { super(app, "dataRecorder") - - let headers: string[] = ["Milli-Sec"] - sensors.forEach(function(sensor) { - headers.push(sensor.name) - }) - - new FauxDataLogger(headers, measurementOpts, sensors) - + // Construct the static FauxDataLogger: + new FauxDataLogger(measurementOpts, sensors) // Get the specified behaviour from the passed RecordingMode Enum: if (recordingMode === RecordingMode.TIME) { @@ -123,14 +117,17 @@ namespace microcode { // datalogger.log(datalogger.createCV("col1", "hello")) - let data: string[] = [(input.runningTime() - this.loggingStartTime).toString()] - - // Collect the data to log: - for (let i = 0; i < this.sensors.length; i++) { - data.push(this.sensors[i].getReading().toString()) - } - - FauxDataLogger.log(data) + this.sensors.forEach(function(sensor) { + // Of the same format as FauxDataLogger.header + // May be worth creating a class for this purpose + const data: string[] = [ + sensor.name, + (input.runningTime() - this.loggingStartTime).toString(), + "N/A", + sensor.getReading().toString() + ] + FauxDataLogger.log(data) + }) this.measurementOpts.measurements -= 1 basic.pause(this.measurementOpts.period) diff --git a/fauxLoggers.ts b/fauxLoggers.ts index ae9cbd3..446ba1d 100644 --- a/fauxLoggers.ts +++ b/fauxLoggers.ts @@ -8,7 +8,8 @@ namespace microcode { } abstract class Logger { - static headers: string[] = ["DEFAULT", "DEFAULT", "DEFAULT"] + static headers: string[] + static headerStringLengths: number[] // Needed for column size so that values also fit; also pre-calculation since headers are fixed. static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() static entries: DataEntry[] static numberOfRows: number @@ -16,8 +17,23 @@ namespace microcode { static measurementOptions: RecordingConfig static sensors: Sensor[] - constructor(headers: string[], mOpts: RecordingConfig, sensors: Sensor[]) { - Logger.headers = headers + constructor(mOpts: RecordingConfig, sensors: Sensor[]) { + Logger.headers = [ + "Sensor", + "Milli-sec", + "Event", + "Reading" + ] + + // Additional characters added for space for lines either side and for width of data below + // For example sensor.name may be much longer than just "Sensor" + Logger.headerStringLengths = [ + ("Sensor".length + 4) * font.charWidth, + ("Milli-sec".length + 2) * font.charWidth, + ("Event".length + 6) * font.charWidth, + ("Reading".length + 2) * font.charWidth + ] + Logger.entries = [] Logger.numberOfRows = 0 Logger.measurementOptions = mOpts @@ -55,23 +71,29 @@ namespace microcode { } export class FauxDataLogger extends Logger { - constructor(headers: string[], mOpts: RecordingConfig, sensors: Sensor[]) { - super(headers, mOpts, sensors) - } - } + constructor(mOpts: RecordingConfig, sensors: Sensor[]) { + super(mOpts, sensors) - export class FauxEventLogger extends Logger { - constructor(headers: string[], mOpts: RecordingConfig, sensors: Sensor[]) { - super(headers, mOpts, sensors) + // Add initial entry for the headers, Logger.isEmpty remains false: + Logger.entries.push({ + id: Logger.entries.length, + data: Logger.headers + }) } public static log(data: string[]) { Logger.isEmpty = false Logger.entries.push({ - id: this.entries.length, + id: Logger.entries.length, data }) Logger.numberOfRows += 1 } } + + export class FauxEventLogger extends Logger { + constructor(mOpts: RecordingConfig, sensors: Sensor[]) { + super(mOpts, sensors) + } + } } \ No newline at end of file diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index c9637e4..06779ec 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -86,14 +86,14 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - if (this.xScrollOffset + TABULAR_MAX_COLS < FauxDataLogger.headers.length) { + if (this.xScrollOffset + TABULAR_MAX_COLS < FauxDataLogger.headers.length + 1) { this.xScrollOffset += 1 } } ) } - draw_grid(colBufferSize: number, rowBufferSize: number) { + drawGrid(colBufferSize: number, rowBufferSize: number) { for (let colOffset = 0; colOffset <= Screen.WIDTH; colOffset+=colBufferSize) { Screen.drawLine( Screen.LEFT_EDGE + colOffset, @@ -115,6 +115,42 @@ namespace microcode { } } + + /** + * Each header and its corresopnding rows of data have variable lengths, + * The small screen sizes exaggerates these differences, hence variable column sizing. + * Uses FauxDataLogger.headerStringLengths to get these lengths + * @param colBufferSizes FauxDataLogger.headerStringLengths spliced by this.xScrollOffset + * @param rowBufferSize remains constant + */ + drawGridOfVariableColSize(colBufferSizes: number[], rowBufferSize: number) { + let cumulativeColOffset = 0 + + colBufferSizes.forEach(function(headerLen) { + cumulativeColOffset += headerLen + + if (cumulativeColOffset < Screen.WIDTH) { + Screen.drawLine( + Screen.LEFT_EDGE + cumulativeColOffset, + Screen.TOP_EDGE, + Screen.LEFT_EDGE + cumulativeColOffset, + Screen.HEIGHT, + 0x0 + ) + } + }) + + for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=rowBufferSize) { + Screen.drawLine( + Screen.LEFT_EDGE, + Screen.TOP_EDGE + rowOffset, + Screen.WIDTH, + Screen.TOP_EDGE + rowOffset, + 0x0 + ) + } + } + draw() { Screen.fillRect( Screen.LEFT_EDGE, @@ -129,7 +165,7 @@ namespace microcode { const metadataColSize = Screen.WIDTH / 2 const metadataRowSize = Screen.HEIGHT / METADATA_MAX_ROWS - this.draw_grid(metadataColSize, metadataRowSize) + this.drawGrid(metadataColSize, metadataRowSize) const metadata = FauxDataLogger.getMetadata() for (let row = 0; row < METADATA_MAX_ROWS; row++) { @@ -152,23 +188,31 @@ namespace microcode { break; case DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW: - const tabularColSize = Screen.WIDTH / Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS) const tabularRowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS) - this.draw_grid(tabularColSize, tabularRowBufferSize) + this.drawGridOfVariableColSize(FauxDataLogger.headerStringLengths.slice(this.xScrollOffset), tabularRowBufferSize) for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS); row++) { const data = FauxDataLogger.entries[row + this.yScrollOffset].data; + let cumulativeColOffset = 0 for (let col = 0; col < Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS); col++) { const colID = col + this.xScrollOffset + const colOffset = (font.charWidth * data[colID].length) + 2 + + if (cumulativeColOffset + colOffset > Screen.WIDTH) { + break + } + Screen.print( data[colID], - Screen.LEFT_EDGE + (col * tabularColSize) + (tabularColSize / 2) - ((font.charWidth * data[colID].length) / 2), + Screen.LEFT_EDGE + cumulativeColOffset + (FauxDataLogger.headerStringLengths[colID] / 2) - ((font.charWidth * data[colID].length) / 2), Screen.TOP_EDGE + (row * tabularRowBufferSize) + (tabularRowBufferSize / 2) - 4, 0xb, simage.font8 ) + + cumulativeColOffset += FauxDataLogger.headerStringLengths[colID] } } break; From 4af89d8b688a41876e07eb2205d354f0ac397761 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Wed, 20 Mar 2024 17:47:50 +0000 Subject: [PATCH 067/109] Completely new UI system to incorporate the previous measurement setting selection with event selection, addition of colours and panels, displays the sensors selected in previous screen on left hand side. --- recordingConfigSelection.ts | 405 ++++++++++++++++++++++++++++++++---- 1 file changed, 363 insertions(+), 42 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 3cb03b1..080d4bf 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -1,12 +1,22 @@ namespace microcode { /** - * Is the user changing one of the config values, or not? + * PROMPT_SHARED_CONFIG: Ask if the user wants sensors to share measurement configs; so they only input 1 + * SELECTING_SENSOR: User is selecting a sensor to modify + * WRITING: User is modifying a setting + * DEFAULT: User is not changing any settings & PROMPT_SHARED_CONFIG has occured. */ const enum GUI_STATE { + PROMPT_SHARED_CONFIG, + SELECTING_SENSOR, WRITING, DEFAULT } + const enum WRITING_MODE { + MEASUREMENT, + EVENT, + } + /** * Abstract for the screen that allows users to input measurement or event settings. @@ -14,32 +24,71 @@ namespace microcode { * */ abstract class RecordingConfigSelection extends Scene { + // UI Control: private guiState: GUI_STATE + private writingMode: WRITING_MODE private guiRows: string[] private currentColumn: number - private selectedSensors: Sensor[] private configDeltas: number[][] + protected userSelection: number[] + /** That were passed via selectSensors */ + private sensors: Sensor[] + private selectedSensorIndex: number - protected userSelection: number[] + /** + * Sensor measurement control (unique per sensor) + * Number of measurements, period, event control, etc + * + * Each sensor is granted their config upon the progression from this screen. + * This could be improved via a Factory; where a sensor enum is passed. + * Or a builder design pattern + */ + private sensorConfigs: RecordingConfig[] + private sensorsShareConfigs: boolean + + private acceptShareConfigButton: Sprite + private declineShareConfigButton: Sprite constructor(app: App, appName: string, - selectedSensors: Sensor[], + sensors: Sensor[], configDeltas: number[][], defaultUserSelection: number[], guiRows: string[] ) { super(app, appName) - this.guiState = GUI_STATE.DEFAULT + this.guiState = GUI_STATE.PROMPT_SHARED_CONFIG + this.writingMode = WRITING_MODE.MEASUREMENT this.guiRows = guiRows - this.userSelection = defaultUserSelection this.configDeltas = configDeltas - this.currentColumn = 0 - this.selectedSensors = selectedSensors + + this.sensors = sensors + this.selectedSensorIndex = 0 + this.sensorConfigs = [] + this.sensorsShareConfigs = false + + + // Probably a much neater way of configuring this... + + this.acceptShareConfigButton = new Sprite({img: icons.get("tile_button_a")}) + this.acceptShareConfigButton.bindXfrm(new Affine()) + this.acceptShareConfigButton.xfrm.parent = new Affine() + this.acceptShareConfigButton.xfrm.worldPos.x = Screen.HALF_WIDTH + this.acceptShareConfigButton.xfrm.worldPos.y = Screen.HALF_HEIGHT + this.acceptShareConfigButton.xfrm.localPos.x = -35 + this.acceptShareConfigButton.xfrm.localPos.y = 8 + + this.declineShareConfigButton = new Sprite({img: icons.get("tile_button_b")}) + this.declineShareConfigButton.bindXfrm(new Affine()) + this.declineShareConfigButton.xfrm.parent = new Affine() + this.declineShareConfigButton.xfrm.worldPos.x = Screen.HALF_WIDTH + this.declineShareConfigButton.xfrm.worldPos.y = Screen.HALF_HEIGHT + this.declineShareConfigButton.xfrm.localPos.x = 34 + this.declineShareConfigButton.xfrm.localPos.y = 8 //-------------- // User Control: @@ -49,12 +98,23 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.A.id, () => { - if (this.guiState === GUI_STATE.DEFAULT) { - this.guiState = GUI_STATE.WRITING - } - - else { - this.guiState = GUI_STATE.DEFAULT + switch (this.guiState) { + case GUI_STATE.PROMPT_SHARED_CONFIG: + this.sensorsShareConfigs = true + this.guiState = GUI_STATE.SELECTING_SENSOR + break; + + case GUI_STATE.SELECTING_SENSOR: + this.guiState = GUI_STATE.DEFAULT + break; + + case GUI_STATE.DEFAULT: + this.guiState = GUI_STATE.WRITING + break; + + default: + this.guiState = GUI_STATE.DEFAULT + break; } } ) @@ -63,13 +123,31 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.B.id, () => { - if (this.guiState === GUI_STATE.DEFAULT) { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - } - - else { - this.guiState = GUI_STATE.DEFAULT + switch (this.guiState) { + case GUI_STATE.PROMPT_SHARED_CONFIG: + this.sensorsShareConfigs = false + this.guiState = GUI_STATE.SELECTING_SENSOR + break; + + case GUI_STATE.SELECTING_SENSOR: + this.app.popScene() + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + break; + + case GUI_STATE.WRITING: + this.guiState = GUI_STATE.SELECTING_SENSOR + break + + case GUI_STATE.DEFAULT: + // this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + + this.guiState = GUI_STATE.SELECTING_SENSOR + break; + + default: + this.guiState = GUI_STATE.DEFAULT + break; } } ) @@ -78,8 +156,15 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { + if (this.guiState === GUI_STATE.SELECTING_SENSOR) { + // Non-negative modulo: + this.selectedSensorIndex = (((this.selectedSensorIndex - 1) % this.sensors.length) + this.sensors.length) % this.sensors.length + } + if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][0], 0) + if (this.writingMode == WRITING_MODE.MEASUREMENT) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][0], 0) + } } else { @@ -93,13 +178,23 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { + if (this.guiState === GUI_STATE.SELECTING_SENSOR) { + this.selectedSensorIndex = (this.selectedSensorIndex + 1) % this.sensors.length + } + if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][0], 0) + if (this.writingMode === WRITING_MODE.MEASUREMENT) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][0], 0) + } + + else { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][0], 0) + } } else { // Non-negative modulo: - this.currentColumn = (((this.currentColumn + 1) % this.userSelection.length) + this.userSelection.length) % this.userSelection.length + this.currentColumn = (this.currentColumn + 1) % this.userSelection.length } } ) @@ -109,28 +204,52 @@ namespace microcode { controller.left.id, () => { if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][1], 0) + if (this.writingMode === WRITING_MODE.MEASUREMENT) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][1], 0) + } + } + + if (this.guiState == GUI_STATE.SELECTING_SENSOR) { + if (this.writingMode == WRITING_MODE.MEASUREMENT) { + this.writingMode = WRITING_MODE.EVENT + } + else { + this.writingMode = WRITING_MODE.MEASUREMENT + } } } ) - control.onEvent( + control.onEvent( ControllerButtonEvent.Pressed, controller.right.id, () => { if (this.guiState === GUI_STATE.WRITING) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][1], 0) + if (this.writingMode === WRITING_MODE.MEASUREMENT) { + this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][1], 0) + } + } + + if (this.guiState == GUI_STATE.SELECTING_SENSOR) { + if (this.writingMode == WRITING_MODE.MEASUREMENT) { + this.writingMode = WRITING_MODE.EVENT + } + else { + this.writingMode = WRITING_MODE.MEASUREMENT + } } else if (this.guiState === GUI_STATE.DEFAULT) { + // Pass the configs onto the sensors: + this.sensors.map((sensor, index) => sensor.setConfig(this.sensorConfigs[index])) + this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.generateRecordingOptions(), this.selectedSensors, RecordingMode.TIME)) + this.app.pushScene(new DataRecorder(this.app, this.generateRecordingOptions(), this.sensors, RecordingMode.TIME)) } } ) } - /** * Convert the .userSelection data into a RecordingConfig object for use by the DataRecorder * @returns RecordingConfig {measurements, period, delay} @@ -143,7 +262,6 @@ namespace microcode { } } - update() { Screen.fillRect( Screen.LEFT_EDGE, @@ -153,24 +271,100 @@ namespace microcode { 0xC ) + screen.printCenter("Recording Settings", 2) + + this.drawSensors() + + if (this.guiState != GUI_STATE.SELECTING_SENSOR && this.guiState != GUI_STATE.PROMPT_SHARED_CONFIG) { + if (this.writingMode == WRITING_MODE.MEASUREMENT) { + this.drawMeasurementSelectWindow() + } + else { + this.drawEventSelectWindow() + } + } + + // Drawn ontop of above grapics, as pop-up + if (this.guiState == GUI_STATE.PROMPT_SHARED_CONFIG) { + // Border: + // Slightly taller and wider than box for depth effect + screen.fillRect( + Screen.HALF_WIDTH - 51, + Screen.HALF_HEIGHT - 26, + 103, + 56, + 5 + ) + + // Body + screen.fillRect( + Screen.HALF_WIDTH - 50, + Screen.HALF_HEIGHT - 25, + 100, + 53, + 7 + ) + + screen.printCenter("Unique config", Screen.HALF_HEIGHT - 25 + 4, 16) + screen.printCenter("per sensor?", Screen.HALF_HEIGHT - 25 + 12, 16) + + // Draw button prompts: + screen.print( + "Yes", + Screen.HALF_WIDTH - 41, + Screen.HALF_HEIGHT + 14, + 16 + ) + + screen.print( + "No", + Screen.HALF_WIDTH + 31, + Screen.HALF_HEIGHT + 14, + 16 + ) + + this.acceptShareConfigButton.draw() + this.declineShareConfigButton.draw() + } + } + + private drawMeasurementSelectWindow() { let timeAsString; let rowOffset = 0; - const headerX = 2 - const optionX = (font.charWidth * this.guiRows[0].length) + 10 - const pointerX = optionX + 20 + const pointerX = Screen.WIDTH - 12 + const optionX = pointerX - 15 + const headerX = optionX - (font.charWidth * this.guiRows[0].length) - 8 const rowSize = Screen.HEIGHT / (this.userSelection.length + 1) - screen.printCenter("Recording Settings", 2) + // Sub-window: + // Outline: + screen.fillRect( + headerX - 4, + 12, + Screen.WIDTH - headerX + 4, + Screen.HEIGHT - 15, + 6 + ) + + screen.fillRect( + headerX - 2, + 14, + Screen.WIDTH - headerX + 2, + Screen.HEIGHT - 19, + 4 + ) for (let i = 0; i < this.userSelection.length; i++) { - screen.print(this.guiRows[i], + screen.print( + this.guiRows[i], headerX, 18 + rowOffset ) timeAsString = this.userSelection[i].toString() - screen.print(timeAsString, + screen.print( + timeAsString, optionX, 18 + rowOffset ) @@ -178,12 +372,139 @@ namespace microcode { } // Cursor arrow - screen.print("<--", + screen.print("<-", pointerX, 18 + (rowSize * this.currentColumn), 0 ) } + + private drawEventSelectWindow() { + const pointerY = Screen.HEIGHT - 83 + const yOffset = 18 + const rowSize = Screen.HEIGHT / (this.sensors.length + 1) + + // Sub-window: + // Outline: + screen.fillRect( + 74, + yOffset + ((this.selectedSensorIndex + 1) * rowSize) - 2, + 60, + font.charHeight + 9, + 16 + ) + + screen.fillRect( + 74, + yOffset + ((this.selectedSensorIndex + 1) * rowSize) - 2, + 58, + font.charHeight + 6, + 9 + ) + + const middleSensorRange = this.sensors[this.selectedSensorIndex].maximum - this.sensors[this.selectedSensorIndex].minimum + + // Write Event expression: + screen.print( + sensorEventSymbols[0] + " " + middleSensorRange.toString(), + 80, + yOffset + ((this.selectedSensorIndex + 1) * rowSize) - 1, + 16 + ) + + screen.print( + "^", + 80, + yOffset + ((this.selectedSensorIndex + 1) * rowSize) + 20 + ) + + // const sensorSprite = new Sprite({img: icons.get(this.sensors[this.selectedSensorIndex].iconName)}) + // sensorSprite.bindXfrm(new Affine()) + // sensorSprite.xfrm.parent = new Affine() + // sensorSprite.xfrm.worldPos.x = 100 + // sensorSprite.xfrm.worldPos.y = 16 + ((this.selectedSensorIndex + 1) * rowSize) + // sensorSprite.xfrm.localPos.x = 5 + // sensorSprite.xfrm.localPos.y = 0 + } + + private drawSensors() { + const headerX = 4 + const rowSize = Screen.HEIGHT / (this.sensors.length + 1) + + let writingModeColour = 5 // Measurement mode + + if (this.writingMode == WRITING_MODE.EVENT) { + writingModeColour = 9 + } + + // Box around header: + screen.fillRect( + 0, + 16, + 80, + font.charHeight + 9, + 16 + ) + + screen.fillRect( + 1, + 16, + 78, + font.charHeight + 6, + writingModeColour + ) + + // Box around selected: + screen.fillRect( + 0, + 18 + ((this.selectedSensorIndex + 1) * rowSize) - 2, + 56, + font.charHeight + 9, + 16 + ) + + screen.fillRect( + 1, + 18 + ((this.selectedSensorIndex + 1) * rowSize) - 2, + 54, + font.charHeight + 6, + writingModeColour + ) + + let headerText = "Record " + if (this.writingMode == WRITING_MODE.MEASUREMENT) { + headerText += "Data" + } + else { + headerText += "Event" + } + + // Header: + screen.print( + headerText, + headerX, + 17, + 16 + ) + + let color = 0 + for (let rowID = 0; rowID < this.sensors.length; rowID++) { + if (this.selectedSensorIndex === rowID) { + color = 16 + } + + else { + color = 0 + } + + screen.print( + this.sensors[rowID].name, + headerX, + 17 + ((rowID + 1) * rowSize), + color + ) + } + } } export class MeasurementConfigSelect extends RecordingConfigSelection { @@ -208,20 +529,20 @@ namespace microcode { ] // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: - const defaultUserSelection = [10, 0, 1, 0, 0, 0, 0] - const guiRows = ["Measurements: ", - "Milli-Seconds: ", + // const defaultUserSelection = [10, 0, 1, 0, 0, 0, 0] + const defaultUserSelection = [10, 30, 0, 0, 0, 0, 0] + const guiRows = ["Records: ", + "MilliSec: ", "Seconds: ", "Minutes: ", "Hours: ", "Days: ", - "Start Delay: " + "Delay: " ] super(app, "measurementConfigSelect", selectedSensors, configDeltas, defaultUserSelection, guiRows) } - /** * Convert the .userSelection data into a RecordingConfig object for use by the DataRecorder * @returns RecordingConfig {measurements, period, delay} From 38e9103fbccbf38aeba96876508223bccfd6b645 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Wed, 20 Mar 2024 17:48:37 +0000 Subject: [PATCH 068/109] Updated dependencies of new files and the use of the tile_button_b --- assets.ts | 1 + pxt.json | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/assets.ts b/assets.ts index cfb938b..1fd00ba 100644 --- a/assets.ts +++ b/assets.ts @@ -77,6 +77,7 @@ namespace microcode { if (name == "speaker") return icondb.speaker if (name == "tile_button_a") return icondb.tile_button_a + if (name == "tile_button_b") return icondb.tile_button_b if (name == "compass") return icondb.compass if (name == "settingsGear") return icondb.settingsGear diff --git a/pxt.json b/pxt.json index 579117c..3a77a49 100644 --- a/pxt.json +++ b/pxt.json @@ -42,23 +42,18 @@ "ruleEditor.ts", "editor.ts", "samples.ts", - "liveDataViewer.ts", "tabularDataViewer.ts", - "sensorSelect.ts", "dataViewSelect.ts", - "recordingConfig.ts", "recordingConfigSelection.ts", - "recordingModeSelection.ts", - "sensors.ts", "fauxLoggers.ts", "dataRecorder.ts", - "generateGraph.ts" + "generateGraph.ts", + "sensorEvent.ts" ], - "testFiles": [], "targetVersions": { "target": "6.1.10", From beaf6531fbfdbf3f818f9abad073ee791289a792 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Wed, 20 Mar 2024 17:50:42 +0000 Subject: [PATCH 069/109] Added a config, start time, icon and ariaID to all sensors via the abstract; allows each sensor to have independent read times & events. --- sensors.ts | 101 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 17 deletions(-) diff --git a/sensors.ts b/sensors.ts index 5897724..22bc398 100644 --- a/sensors.ts +++ b/sensors.ts @@ -4,33 +4,67 @@ namespace microcode { * Methods are seldom overidden */ export abstract class Sensor { - static BUFFER_LIMIT = 100; - static PLOT_SMOOTHING_CONSTANT = 8 + static readonly BUFFER_LIMIT: number = 100; + static readonly PLOT_SMOOTHING_CONSTANT: number = 8 public sensorFn: () => number public name: string + public iconName: string + public ariaID: string + + // Reading Statistics: public minimum: number public maximum: number public peakDataPoint: number[] - private numberOfDisplayModes: number; - private currentDisplayMode: number; - private dataBuffer: number[] + private startTime: number + + // Details regarding how the sensor should asynchronously record measurements/report events + private config: RecordingConfig + + // Potential to add different display options + // For example: view a magnometer as a line-graph or directionally + private numberOfDisplayModes: number + private currentDisplayMode: number constructor(sensorFn: () => number, name: string, sensorMinReading: number, sensorMaxReading: number, - numberOfDisplayModes: number + numberOfDisplayModes: number, + iconName: string, + ariaID: string ) { this.sensorFn = sensorFn this.name = name + this.iconName = iconName + this.ariaID = ariaID + this.minimum = sensorMinReading this.maximum = sensorMaxReading + this.peakDataPoint = [0, this.minimum] // [x, y] + this.numberOfDisplayModes = numberOfDisplayModes + this.numberOfDisplayModes = 1 // Default + this.dataBuffer = [] - this.peakDataPoint = [0, this.minimum] + this.startTime = 0 // This value will be set upon the first reading + } + + + /** + * It would be better for this config to be passed in upon sensor construction + * This requires a Sensor Factory + * + * Invoked at the end of recordingConfigSelection + * + * This method should be removed in future releases + * + * @param config Period, Measurement quantity, event handling, etc + */ + setConfig(config: RecordingConfig) { + this.config = config } cycleDisplayMode() { @@ -64,6 +98,28 @@ namespace microcode { } this.dataBuffer.push(this.getReading()); } + + private handleEvent(): void { + const reading = this.getReading().toString() + const data: string[] = [ + this.name, + (input.runningTime() - this.startTime).toString(), + this.config.sensorEvent.inequality + " " + reading, + reading + ] + FauxDataLogger.log(data) + } + + startPolling() { + this.startTime = input.runningTime() + let currentPollID = 0 + + while (currentPollID < this.config.measurements) { + this.config.sensorEvent.handleEvent(this.getReading(), this.handleEvent) + currentPollID += 1 + basic.pause(this.config.period) + } + } /** @@ -102,7 +158,7 @@ namespace microcode { */ export class LightSensor extends Sensor { constructor() { - super(function () {return input.lightLevel()}, "Light", 0, 255, 1) + super(function () {return input.lightLevel()}, "Light", 0, 255, 1, "led_light_sensor", "led_light_sensor") } } @@ -111,7 +167,7 @@ namespace microcode { */ export class TemperatureSensor extends Sensor { constructor() { - super(function () {return input.temperature()}, "Temp.", 0, 100, 1) + super(function () {return input.temperature()}, "Temp.", 0, 100, 1, "thermometer", "thermometer") } } @@ -121,7 +177,14 @@ namespace microcode { */ export class AccelerometerSensor extends Sensor { constructor(dim: Dimension) { - super(function () {return input.acceleration(dim)}, "Accel.", -1023, 1023, 1) + super(function () {return input.acceleration(dim)}, + "Accel. " + ['X', 'Y', 'Z'][dim], + -1023, + 1023, + 1, + "accelerometer", + "accelerometer " + + ['X', 'Y', 'Z'][dim] + ) } } @@ -140,7 +203,9 @@ namespace microcode { "Pin " + pin.toString(), 0, 1, - 1 + 1, + "pin_" + pin.toString(), + "Pin " + pin.toString() ) } } @@ -157,7 +222,9 @@ namespace microcode { "Magnet " + dim.toString(), 0, 1, - 1 + 1, + "magnet", + "S10" ) } } @@ -176,7 +243,7 @@ namespace microcode { name = "Roll" } - super(function () {return input.rotation(rot)}, name, 0, 100, 1) + super(function () {return input.rotation(rot)}, name, 0, 100, 1, "right_turn", name) } } @@ -188,7 +255,7 @@ namespace microcode { */ export class LogoPressSensor extends Sensor { constructor() { - super(function () {if(input.logoIsPressed()) {return 1} return 0}, "Logo Pressed", 0, 1, 1) + super(function () {if(input.logoIsPressed()) {return 1} return 0}, "Logo Pressed", 0, 1, 1, "finger_press", "Logo Press") } } @@ -198,7 +265,7 @@ namespace microcode { */ export class CompassHeadingSensor extends Sensor { constructor() { - super(function () {return input.compassHeading()}, "Compass", 0, 360, 1) + super(function () {return input.compassHeading()}, "Compass", 0, 360, 1, "compass", "Compass") } } @@ -208,7 +275,7 @@ namespace microcode { */ export class VolumeSensor extends Sensor { constructor() { - super(function () {return input.soundLevel()}, "Volume", 0, 255, 1) + super(function () {return input.soundLevel()}, "Volume", 0, 255, 1, "speaker", "Volume") } } @@ -218,7 +285,7 @@ namespace microcode { */ export class ButtonPressSensor extends Sensor { constructor() { - super(function () {return 1}, "Button Press", 0, 1, 1) + super(function () {return 1}, "Button Press", 0, 1, 1, "tile_button_a", "F3") control.onEvent(DAL.DEVICE_BUTTON_EVT_UP, DAL.DEVICE_ID_BUTTON_A, () => { return 1 From a95fedb30967144d32bda4068c9ffce3d8badb0e Mon Sep 17 00:00:00 2001 From: KierPalin Date: Wed, 20 Mar 2024 17:51:59 +0000 Subject: [PATCH 070/109] SensorEvent object added to recordingConfig, SensorEvent has additional documentation. --- recordingConfig.ts | 1 + sensorEvent.ts | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 sensorEvent.ts diff --git a/recordingConfig.ts b/recordingConfig.ts index 32608cb..9711867 100644 --- a/recordingConfig.ts +++ b/recordingConfig.ts @@ -3,5 +3,6 @@ namespace microcode { measurements: number, period: number, delay: number + sensorEvent?: SensorEvent }; } \ No newline at end of file diff --git a/sensorEvent.ts b/sensorEvent.ts new file mode 100644 index 0000000..017d08b --- /dev/null +++ b/sensorEvent.ts @@ -0,0 +1,50 @@ +namespace microcode { + /** + * Currently only events that check for inequalities are implemented, + * The only sensors that are incompatible with this are Buttons + * The following code may be generalised to support them though. + */ + + + /** + * Function invoked to check if a reading target is true + * Upon that the callback is invoked + * The callback handles the event via sensors.handleEvent() + * This private method will cause the event to be logged. + */ + type SensorEventFunction = (reading: number, target: number, callback: () => void) => void + + /** + * Inequality as string to function that performs said inequality + * Inequality presence => callback() + */ + export const sensorEventFunctionLookup: {[inequality: string]: SensorEventFunction} = { + "=": function(reading: number, target: number, callback: () => void) {if (reading === target) {callback()}}, + ">": function(reading: number, target: number, callback: () => void) {if (reading > target) {callback()}}, + "<": function(reading: number, target: number, callback: () => void) {if (reading < target) {callback()}}, + ">=": function(reading: number, target: number, callback: () => void) {if (reading >= target) {callback()}}, + "<=": function(reading: number, target: number, callback: () => void) {if (reading <= target) {callback()}}, + } + + export const sensorEventSymbols = ["=", ">", "<", ">=", "<="] + + /** + * Simple class that is optionally owned by the recordingConfig. + * Acts as a wrapper for the above InequalityFunctions + */ + export class SensorEvent { + public readonly inequality: string // Used to build Logged String + private readonly target: number + private readonly inequalityFunction: SensorEventFunction + + constructor(inequality: string, target: number) { + this.inequality = inequality + this.target = target + this.inequalityFunction = sensorEventFunctionLookup[inequality] + } + + public handleEvent(reading: number, callback: () => void): void { + this.inequalityFunction(reading, this.target, callback) + } + } +} \ No newline at end of file From 500bf52dc91006a6cbf1e9d8be97521fe85b7f27 Mon Sep 17 00:00:00 2001 From: KierPalin Date: Wed, 20 Mar 2024 17:55:09 +0000 Subject: [PATCH 071/109] Prototype 9 completion: more polished GUI for setting the recordingConfigs, independent sensor controls, new tabular data view GUI, improved documentation, redesign of many backend components. --- cursorscene.ts | 1 - fauxLoggers.ts | 1 + recordingModeSelection.ts | 2 +- sensorSelect.ts | 4 ---- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cursorscene.ts b/cursorscene.ts index 44dca5c..62ce97f 100644 --- a/cursorscene.ts +++ b/cursorscene.ts @@ -3,7 +3,6 @@ namespace microcode { LiveDataViewer, SensorSelect, MeasurementConfigSelect, - EventConfigSelect, RecordData, } diff --git a/fauxLoggers.ts b/fauxLoggers.ts index 446ba1d..ddd95b0 100644 --- a/fauxLoggers.ts +++ b/fauxLoggers.ts @@ -79,6 +79,7 @@ namespace microcode { id: Logger.entries.length, data: Logger.headers }) + Logger.numberOfRows += 1 } public static log(data: string[]) { diff --git a/recordingModeSelection.ts b/recordingModeSelection.ts index e8e386f..dd34edb 100644 --- a/recordingModeSelection.ts +++ b/recordingModeSelection.ts @@ -27,7 +27,7 @@ namespace microcode { y: 30, onClick: () => { this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.EventConfigSelect)) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) }, }) diff --git a/sensorSelect.ts b/sensorSelect.ts index 255bd3e..8856633 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -241,10 +241,6 @@ namespace microcode { this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) } - if (this.nextSceneEnum === CursorSceneEnum.EventConfigSelect) { - this.app.pushScene(new EventConfigSelect(app, this.selectedSensors)) - } - else { this.app.pushScene(new MeasurementConfigSelect(app, this.selectedSensors)) } From fcc8f38ebc540278b10cd599a3d808afa4cf6279 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 17:56:32 +0000 Subject: [PATCH 072/109] tabularDataViewer: added cursor, improved scrolling, added filtered mode - pressing a on a sensor will show a tabular view of the readings from only that sensor. --- tabularDataViewer.ts | 101 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index 06779ec..3907ab2 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -10,6 +10,7 @@ namespace microcode { export const enum DATA_VIEW_DISPLAY_MODE { METADATA_VIEW, TABULAR_DATA_VIEW, + FILTERED_DATA_VIEW, } /** @@ -21,6 +22,7 @@ namespace microcode { private yScrollOffset: number private numberOfMetadataRows: number + private currentRowIndex: number constructor(app: App, guiState: DATA_VIEW_DISPLAY_MODE) { super(app, "recordedDataViewer") @@ -28,6 +30,7 @@ namespace microcode { this.xScrollOffset = 0 this.yScrollOffset = 0 + this.currentRowIndex = 1 this.numberOfMetadataRows = FauxDataLogger.getNumberOfMetadataRows() } @@ -43,8 +46,23 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.B.id, () => { - app.popScene() - app.pushScene(new DataViewSelect(this.app)) + if(this.guiState == DATA_VIEW_DISPLAY_MODE.FILTERED_DATA_VIEW) { + this.guiState = DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW + } + else { + app.popScene() + app.pushScene(new DataViewSelect(this.app)) + } + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.A.id, + () => { + if (this.guiState == DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW) { + this.guiState = DATA_VIEW_DISPLAY_MODE.FILTERED_DATA_VIEW + } } ) @@ -52,7 +70,15 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - this.yScrollOffset = Math.max(this.xScrollOffset - 1, 0) + if (this.guiState === DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW) { + if (this.currentRowIndex <= 1) { + this.yScrollOffset = Math.max(this.yScrollOffset - 1, 0) + } + + else { + this.currentRowIndex = Math.max(this.currentRowIndex - 1, 1) + } + } } ) @@ -66,10 +92,14 @@ namespace microcode { } } - else { - if (this.yScrollOffset + 1 < FauxDataLogger.numberOfRows - TABULAR_MAX_ROWS) { + else if (this.guiState === DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW) { + if (this.currentRowIndex + 1 >= Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS)) { this.yScrollOffset += 1 } + + else { + this.currentRowIndex = Math.min(this.currentRowIndex + 1, FauxDataLogger.numberOfRows) + } } } ) @@ -149,6 +179,17 @@ namespace microcode { 0x0 ) } + + if (this.guiState == DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW) { + // Draw selected box: + Screen.drawRect( + Screen.LEFT_EDGE, + Screen.TOP_EDGE + (this.currentRowIndex * rowBufferSize), + colBufferSizes[0], + rowBufferSize, + 6 + ) + } } draw() { @@ -186,24 +227,63 @@ namespace microcode { ) } break; + + + case DATA_VIEW_DISPLAY_MODE.FILTERED_DATA_VIEW: + const filteredRowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows / FauxDataLogger.sensors.length, TABULAR_MAX_ROWS) + this.drawGridOfVariableColSize(FauxDataLogger.headerStringLengths.slice(this.xScrollOffset), filteredRowBufferSize) + + const filteredSensor: string = FauxDataLogger.entries[this.currentRowIndex].data[0]; + let filteredData: string[][] = [] + + FauxDataLogger.entries.forEach((entry) => { + if (entry.data[0] == filteredSensor) { + filteredData.push(entry.data) + } + }); + + for (let row = 0; row < Math.min(filteredData.length, TABULAR_MAX_ROWS); row++) { + let cumulativeColOffset = 0 + const data = filteredData[row + 1] + + for (let col = 0; col < Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS); col++) { + const colID = col + this.xScrollOffset + const colOffset = (font.charWidth * filteredData[colID].length) + 2 + + if (cumulativeColOffset + colOffset > Screen.WIDTH) { + break + } + + Screen.print( + data[colID], + Screen.LEFT_EDGE + cumulativeColOffset + (FauxDataLogger.headerStringLengths[colID] / 2) - ((font.charWidth * data[colID].length) / 2), + Screen.TOP_EDGE + (row * filteredRowBufferSize) + (filteredRowBufferSize / 2) - 4, + 0xb, + simage.font8 + ) + + cumulativeColOffset += FauxDataLogger.headerStringLengths[colID] + } + } + + break; case DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW: const tabularRowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS) - this.drawGridOfVariableColSize(FauxDataLogger.headerStringLengths.slice(this.xScrollOffset), tabularRowBufferSize) for (let row = 0; row < Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS); row++) { const data = FauxDataLogger.entries[row + this.yScrollOffset].data; - + let cumulativeColOffset = 0 for (let col = 0; col < Math.min(FauxDataLogger.headers.length, TABULAR_MAX_COLS); col++) { const colID = col + this.xScrollOffset const colOffset = (font.charWidth * data[colID].length) + 2 - + if (cumulativeColOffset + colOffset > Screen.WIDTH) { break } - + Screen.print( data[colID], Screen.LEFT_EDGE + cumulativeColOffset + (FauxDataLogger.headerStringLengths[colID] / 2) - ((font.charWidth * data[colID].length) / 2), @@ -211,10 +291,11 @@ namespace microcode { 0xb, simage.font8 ) - + cumulativeColOffset += FauxDataLogger.headerStringLengths[colID] } } + break; default: From 76d299bce4dce38963e5e03558c9d2a436920ed0 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 17:57:57 +0000 Subject: [PATCH 073/109] fauxDataLogger: removed abstract class; all data logging is under this class now, reordered headers to be (sensor name, time, reading, event) --- fauxDataLogger.ts | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 fauxDataLogger.ts diff --git a/fauxDataLogger.ts b/fauxDataLogger.ts new file mode 100644 index 0000000..b763925 --- /dev/null +++ b/fauxDataLogger.ts @@ -0,0 +1,74 @@ +namespace microcode { + /** + * Internal representation of an logged entry + */ + interface DataEntry { + id: number, + data: string[] + } + + export class FauxDataLogger { + static headers: string[] + static headerStringLengths: number[] // Needed for column size so that values also fit; also pre-calculation since headers are fixed. + static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() + static entries: DataEntry[] + static numberOfRows: number + static isEmpty: boolean = true + static sensors: Sensor[] + + constructor(sensors: Sensor[]) { + FauxDataLogger.headers = [ + "Sensor", + "ms", + "Reading", + "Event" + ] + + // Additional characters added for space for lines either side and for width of data below + // For example sensor.name may be much longer than just "Sensor" + FauxDataLogger.headerStringLengths = [ + ("Sensor".length + 4) * font.charWidth, + ("ms".length + 4) * font.charWidth, + ("Reading".length + 2) * font.charWidth, + ("Event".length + 6) * font.charWidth + ] + + FauxDataLogger.entries = [] + FauxDataLogger.numberOfRows = 0 + FauxDataLogger.sensors = sensors + + FauxDataLogger.entries.push({ + id: FauxDataLogger.entries.length, + data: FauxDataLogger.headers + }) + FauxDataLogger.numberOfRows += 1 + } + + public static getNumberOfMetadataRows(): number { + return 5 + FauxDataLogger.headers.length + } + + public static getMetadata() { + let metadata = [ + {col1: "Date", col2: FauxDataLogger.dateStamp}, + {col1: "Rows", col2: FauxDataLogger.numberOfRows.toString()}, + {col1: "Columns", col2: FauxDataLogger.headers.length.toString()} + ] + + for (let i = 0; i < FauxDataLogger.headers.length; i++) { + metadata.push({col1: "Col " + (i + 1).toString(), col2: FauxDataLogger.headers[i]}) + } + + return metadata + } + + public static log(data: string[]) { + FauxDataLogger.isEmpty = false + FauxDataLogger.entries.push({ + id: this.entries.length, + data + }) + FauxDataLogger.numberOfRows += 1 + } + } +} \ No newline at end of file From e99a8fdab02d67ec661d4019b61e85de5bd11f65 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 17:58:41 +0000 Subject: [PATCH 074/109] generateGraph: reworked to accommodate new fauxDataLogger logging schema. --- generateGraph.ts | 121 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/generateGraph.ts b/generateGraph.ts index 89c4623..23ecb7d 100644 --- a/generateGraph.ts +++ b/generateGraph.ts @@ -1,4 +1,10 @@ namespace microcode { + /** No information beyond this Y coordinate */ + const MAX_Y_SCOLL = -75 + + // //% promise + // export function downloadData(url:string) {basic.showString("hi :)")} + export class GraphGenerator extends Scene { private windowWidth: number private windowHeight: number @@ -7,6 +13,8 @@ namespace microcode { private windowTopBuffer: number private windowBotBuffer: number + private yScrollOffset: number + constructor(app: App) { super(app, "graphGeneration") this.color = 0 @@ -17,8 +25,29 @@ namespace microcode { this.windowWidthBuffer = 18 this.windowTopBuffer = 5 this.windowBotBuffer = 20 - } + this.yScrollOffset = 0 + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + this.yScrollOffset = Math.min(this.yScrollOffset + 20, 0) + this.update() // For fast response to the above change + } + ) + + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => { + this.yScrollOffset = Math.max(this.yScrollOffset - 20, MAX_Y_SCOLL) + this.update() // For fast response to the above change + } + ) + + // microcode.downloadData("a") + } /** * Request each sensor updates its buffers, @@ -40,28 +69,65 @@ namespace microcode { this.draw_axes() // Draw data lines: - const fromY = this.windowBotBuffer + const fromY = this.windowBotBuffer - 2 * this.yScrollOffset const fromX = this.windowWidthBuffer + 2 - for (let col = 1; col < FauxDataLogger.headers.length; col++) { - const minimum = FauxDataLogger.sensors[col - 1].minimum - const maximum = FauxDataLogger.sensors[col - 1].maximum - - for (let row = 0; row < FauxDataLogger.numberOfRows - 1; row++) { - const norm1 = ((+FauxDataLogger.entries[row].data[col] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) - const norm2 = ((+FauxDataLogger.entries[row + 1].data[col] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) - - const y1 = Math.round(screen.height - norm1) - fromY - const y2 = Math.round(screen.height - norm2) - fromY - - // Minimal data smoothing: - if (Math.abs(y1 - y2) <= Sensor.PLOT_SMOOTHING_CONSTANT) { - screen.drawLine(fromX + row, y1, fromX + row - 1, y1, color); - } - - screen.drawLine(fromX + row, y1, fromX + row - 1, y2, color); + for (let row = 1; row < FauxDataLogger.numberOfRows - FauxDataLogger.sensors.length; row++) { + const minimum = FauxDataLogger.sensors[(row - 1) % FauxDataLogger.sensors.length].minimum + const maximum = FauxDataLogger.sensors[(row - 1) % FauxDataLogger.sensors.length].maximum + + const norm1 = ((+FauxDataLogger.entries[row].data[2] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) + const norm2 = ((+FauxDataLogger.entries[row + FauxDataLogger.sensors.length].data[2] - minimum) / (Math.abs(minimum) + maximum)) * (screen.height - fromY) + + const y1 = Math.round(screen.height - norm1) - fromY + const y2 = Math.round(screen.height - norm2) - fromY + + // Minimal data smoothing: + if (Math.abs(y1 - y2) <= Sensor.PLOT_SMOOTHING_CONSTANT) { + screen.drawLine(fromX + row, y1, fromX + row - 1, y1, color); } - color = (color + 1) % 15 + + screen.drawLine(fromX + row, y1, fromX + row - 1, y2, color); + + color = 8 + (((row - 1) % FauxDataLogger.sensors.length) % 15) + } + + + const yStart = this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + let y = yStart + + // Write Sensor information, displayed below the plot: + for (let i = 0; i < FauxDataLogger.sensors.length; i++) { + // Colour used to represent this sensor, same colour as plotted & ticker: + y += (i * 12) + + screen.fillRect( + 2, + y, + 7, + 7, + color + ) + + // Name, reading / maximum + screen.print( + // FauxDataLogger.sensors[i].name + " " + FauxDataLogger.sensors[i].getReading() + "/" + FauxDataLogger.sensors[i].maximum, + FauxDataLogger.sensors[i].name, + 14, + y, + color + ) + + // Write the peak reading just below and with a slight xOffset from the above: + y += 12 + screen.print( + "Peak " + FauxDataLogger.sensors[i].peakDataPoint[1], + 44, + y, + color + ) + + color = (color + 3) % 15 } } @@ -72,19 +138,20 @@ namespace microcode { for (let i = 0; i < 2; i++) { screen.drawLine( this.windowWidthBuffer, - this.windowHeight - this.windowBotBuffer + i, + this.windowHeight - this.windowBotBuffer + i + this.yScrollOffset + this.yScrollOffset, this.windowWidth - this.windowWidthBuffer, - this.windowHeight - this.windowBotBuffer + i, + this.windowHeight - this.windowBotBuffer + i + this.yScrollOffset + this.yScrollOffset, 5 ); screen.drawLine( - this.windowWidthBuffer, - this.windowTopBuffer, - this.windowWidthBuffer, - this.windowHeight - this.windowBotBuffer, + this.windowWidthBuffer + i, + this.windowTopBuffer + this.yScrollOffset + this.yScrollOffset, + this.windowWidthBuffer + i, + this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset, 5 ); } } } -} \ No newline at end of file +} + From aeb9b589d3569a90e5d9cfaa02aa0a53c05f9da8 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 17:59:30 +0000 Subject: [PATCH 075/109] dataRecorder: complete rework to have coloured cards that show each sensor being recorded & their recording statistics. --- dataRecorder.ts | 232 ++++++++++++++++++++++++++++-------------------- 1 file changed, 138 insertions(+), 94 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 83b3fba..662c1ed 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -1,28 +1,29 @@ namespace microcode { - export enum RecordingMode { - EVENT, - TIME - } + const MAX_SENSORS_ON_SCREEN: number = 5 + const SENSOR_BOX_COLORS: number[] = [2,3,4,6,7,9] export class DataRecorder extends Scene { - /** State pattern; see the internal classes that implement these behaviours below this file */ - private recordingBehaviour: RecordingBehaviour + private sensors: Sensor[] - constructor(app: App, measurementOpts: RecordingConfig, sensors: Sensor[], recordingMode: RecordingMode) { - super(app, "dataRecorder") + // UI: + private currentSensorIndex: number + private sensorIndexOffset: number + private sensorBoxColor: number - // Construct the static FauxDataLogger: - new FauxDataLogger(measurementOpts, sensors) + constructor(app: App, sensors: Sensor[]) { + super(app, "dataRecorder") - // Get the specified behaviour from the passed RecordingMode Enum: - if (recordingMode === RecordingMode.TIME) { - this.recordingBehaviour = new TimeBasedRecording(measurementOpts, sensors) - } + new FauxDataLogger(sensors) - else { - this.recordingBehaviour = new EventBasedRecording() - } + this.sensors = sensors + this.sensorIndexOffset = 0 + this.currentSensorIndex = 0 + this.sensorBoxColor = 16 + // Start logging: + this.sensors.forEach((sensor) => { + sensor.log(this) + }) //--------------- // User Controls: @@ -37,9 +38,39 @@ namespace microcode { this.app.pushScene(new Home(this.app)) } ) + + // Scroll Up + control.onEvent( + ControllerButtonEvent.Pressed, + controller.up.id, + () => { + this.currentSensorIndex = Math.max(0, this.currentSensorIndex - 1) + + if (this.sensorIndexOffset > 0) { + this.sensorIndexOffset = Math.max(0, this.sensorIndexOffset - 1) + } + + this.update() + } + ) + + // Scroll Down + control.onEvent( + ControllerButtonEvent.Pressed, + controller.down.id, + () => { + this.currentSensorIndex = Math.min(this.currentSensorIndex + 1, this.sensors.length - 1) + + if (this.currentSensorIndex > 4) { + this.sensorIndexOffset = Math.min(this.sensorIndexOffset + 1, this.sensors.length - 5) + } + + this.update() + } + ) } - update() { + update(): void { Screen.fillRect( Screen.LEFT_EDGE, Screen.TOP_EDGE, @@ -48,89 +79,102 @@ namespace microcode { 0xc ) - this.recordingBehaviour.update() - } - } - - - //------------------------------------- - // Recording behaviour implementations: - //------------------------------------- - - interface RecordingBehaviour { - update(): void; - } - - /** - * A public recording behaviour. - * This - */ - export class EventBasedRecording implements RecordingBehaviour { - update(): void { - - } - } - - - /** - * Take N recordings on each of the passed sensors with the specified period, - * Makes use of the static FauxDataLogger that was setup in the parent constructor DataRecorder - * Internal Class unlike EventBasedRecording, since this class is only ever invoked via the DataRecorder - */ - class TimeBasedRecording implements RecordingBehaviour { - private loggingStartTime: number - private measurementOpts: RecordingConfig - private sensors: Sensor[] - - constructor(measurementOpts: RecordingConfig, sensors: Sensor[]) { - let headers: string[] = ["Milli-Sec"] - sensors.forEach(function(sensor) { - headers.push(sensor.name) - }) - this.loggingStartTime = input.runningTime() - this.measurementOpts = measurementOpts - this.sensors = sensors - } + // Check if all sensors have finished their work: + let recordingsComplete = true + for (let i = 0; i < this.sensors.length; i++) { + if (this.sensors[i].config.measurements > 0) { + recordingsComplete = false + break + } + } - update(): void { - if (this.measurementOpts.measurements === 0) { + if (recordingsComplete) { screen.printCenter("Data Logging Complete.", (screen.height / 2) - 10); screen.printCenter("Press B to back out.", screen.height / 2); } - else if (this.measurementOpts.delay > 0) { - screen.printCenter("Data logger starting in", (screen.height / 2) - 10); - screen.printCenter(this.measurementOpts.delay + " seconds...", screen.height / 2) - this.measurementOpts.delay -= 1 - - basic.pause(1000) - } - else { - const secondsLeft: number = (this.measurementOpts.measurements * this.measurementOpts.period) / 1000 - screen.printCenter("Recording data...", 10); - - screen.printCenter(this.measurementOpts.period / 1000 + " second period", 45) - screen.printCenter(this.measurementOpts.measurements.toString() + " measurements left", 65); - screen.printCenter(secondsLeft.toString() + " seconds left", 85); - - // datalogger.log(datalogger.createCV("col1", "hello")) - - this.sensors.forEach(function(sensor) { - // Of the same format as FauxDataLogger.header - // May be worth creating a class for this purpose - const data: string[] = [ - sensor.name, - (input.runningTime() - this.loggingStartTime).toString(), - "N/A", - sensor.getReading().toString() - ] - FauxDataLogger.log(data) - }) - - this.measurementOpts.measurements -= 1 - basic.pause(this.measurementOpts.period) + screen.printCenter("Recording data...", 4); + let y = 16 + + for (let i = this.sensorIndexOffset; i < this.sensors.length; i++) { + if (i - this.sensorIndexOffset > MAX_SENSORS_ON_SCREEN) { + break + } + + // Get the colour for this box + this.sensorBoxColor = SENSOR_BOX_COLORS[i % SENSOR_BOX_COLORS.length] + + if (i != this.currentSensorIndex) { + screen.fillRect( + 5, + y, + 142, + 16, + 16 + ) + + screen.fillRect( + 7, + y, + 145, + 14, + this.sensorBoxColor + ) + + screen.print( + this.sensors[i].name, + 12, + y + 2, + 15 + ) + } + + else { + screen.fillRect( + 5, + y, + 142, + 47, + 16 + ) + + screen.fillRect( + 7, + y, + 145, + 45, + this.sensorBoxColor + ) + + const sensor = this.sensors[i] + screen.print( + sensor.name, + 12, + y + 2, + 15 + ) + + const sensorInfo: string[] = [ + sensor.config.period / 1000 + " second period", + sensor.config.measurements.toString() + " measurements left", + ((sensor.config.measurements * sensor.config.period) / 1000).toString() + " seconds left" + ] + + sensorInfo.forEach((info) => { + y += 12 + screen.print( + info, + 24, + y, + 15 + ) + }); + } + + y += 14 + } } } } From e2bf079930f8e6a87bbea2bd96243cece3482334 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 18:02:56 +0000 Subject: [PATCH 076/109] sensors: added .log() to Sensor abstract. This logging runs in the background - enabling asynchronous logging for multiple sensors - where each has a unique number of recordings and period (delay unimplemented as of yet). Removed unused members and methods for displaying different screens & cycling through them. Some work do be done to neaten this file further. --- sensors.ts | 182 ++++++++++++++++++++++++----------------------------- 1 file changed, 81 insertions(+), 101 deletions(-) diff --git a/sensors.ts b/sensors.ts index 22bc398..d15b949 100644 --- a/sensors.ts +++ b/sensors.ts @@ -4,13 +4,14 @@ namespace microcode { * Methods are seldom overidden */ export abstract class Sensor { - static readonly BUFFER_LIMIT: number = 100; - static readonly PLOT_SMOOTHING_CONSTANT: number = 8 + public static readonly BUFFER_LIMIT: number = 100; + public static readonly PLOT_SMOOTHING_CONSTANT: number = 4 + public readonly name: string public sensorFn: () => number - public name: string public iconName: string public ariaID: string + public config: RecordingConfig // Reading Statistics: public minimum: number @@ -20,24 +21,16 @@ namespace microcode { private dataBuffer: number[] private startTime: number - // Details regarding how the sensor should asynchronously record measurements/report events - private config: RecordingConfig - - // Potential to add different display options - // For example: view a magnometer as a line-graph or directionally - private numberOfDisplayModes: number - private currentDisplayMode: number - constructor(sensorFn: () => number, name: string, sensorMinReading: number, sensorMaxReading: number, - numberOfDisplayModes: number, iconName: string, - ariaID: string + ariaID: string, + config?: RecordingConfig ) { - this.sensorFn = sensorFn this.name = name + this.sensorFn = sensorFn this.iconName = iconName this.ariaID = ariaID @@ -45,51 +38,17 @@ namespace microcode { this.maximum = sensorMaxReading this.peakDataPoint = [0, this.minimum] // [x, y] - this.numberOfDisplayModes = numberOfDisplayModes - this.numberOfDisplayModes = 1 // Default - this.dataBuffer = [] this.startTime = 0 // This value will be set upon the first reading - } - - /** - * It would be better for this config to be passed in upon sensor construction - * This requires a Sensor Factory - * - * Invoked at the end of recordingConfigSelection - * - * This method should be removed in future releases - * - * @param config Period, Measurement quantity, event handling, etc - */ - setConfig(config: RecordingConfig) { this.config = config } - cycleDisplayMode() { - this.currentDisplayMode = (this.currentDisplayMode + 1) % this.numberOfDisplayModes - } - - getBufferSize(): number { - return this.dataBuffer.length - } - - getReading(): number { - return this.sensorFn() - } - - getNthReading(n: number): number { - return this.dataBuffer[n] - } - - getDataBufferLength(): number { - return this.dataBuffer.length - } - - getNormalisedReading(): number{ - return this.sensorFn() / this.maximum - } + getBufferSize(): number {return this.dataBuffer.length} + getReading(): number {return this.sensorFn()} + getNthReading(n: number): number {return this.dataBuffer[n]} + getDataBufferLength(): number {return this.dataBuffer.length} + getNormalisedReading(): number{return this.sensorFn() / this.maximum} readIntoBuffer(): void { if (this.dataBuffer.length >= Sensor.BUFFER_LIMIT) { @@ -99,28 +58,28 @@ namespace microcode { this.dataBuffer.push(this.getReading()); } - private handleEvent(): void { - const reading = this.getReading().toString() - const data: string[] = [ - this.name, - (input.runningTime() - this.startTime).toString(), - this.config.sensorEvent.inequality + " " + reading, - reading - ] - FauxDataLogger.log(data) - } - - startPolling() { - this.startTime = input.runningTime() - let currentPollID = 0 + log(dataRecorder: DataRecorder) { + control.inBackground(() => { + if (this.startTime == 0) { + this.startTime = input.runningTime() + } - while (currentPollID < this.config.measurements) { - this.config.sensorEvent.handleEvent(this.getReading(), this.handleEvent) - currentPollID += 1 - basic.pause(this.config.period) - } + while (this.config.measurements > 0) { + FauxDataLogger.log([ + this.name, + (input.runningTime() - this.startTime).toString(), + this.getReading().toString(), + "N/A" + ]) + + this.config.measurements -= 1 + basic.pause(this.config.period) + + // Update the screen + // dataRecorder.update() + } + }) } - /** * Default draw mode: may be overriden to accommodate multiple draw modes @@ -143,12 +102,9 @@ namespace microcode { this.peakDataPoint = [i, this.dataBuffer[i]] } - // Minimal data smoothing: - if (Math.abs(y1 - y2) <= Sensor.PLOT_SMOOTHING_CONSTANT) { - screen.drawLine(fromX + i, y1, fromX + i - 1, y1, color); + for (let j = 0; j < Sensor.PLOT_SMOOTHING_CONSTANT; j++) { + screen.drawLine(fromX + i, y1 - (Sensor.PLOT_SMOOTHING_CONSTANT / 2) + j, fromX + i - 1, y2 - (Sensor.PLOT_SMOOTHING_CONSTANT / 2) + j, color); } - - screen.drawLine(fromX + i, y1, fromX + i - 1, y2, color); } } } @@ -157,8 +113,8 @@ namespace microcode { * Onboard Light Sensor; ranged between 0 and 255 */ export class LightSensor extends Sensor { - constructor() { - super(function () {return input.lightLevel()}, "Light", 0, 255, 1, "led_light_sensor", "led_light_sensor") + constructor(config: RecordingConfig) { + super(function () {return input.lightLevel()}, "Light", 0, 255, "led_light_sensor", "led_light_sensor", config) } } @@ -166,8 +122,8 @@ namespace microcode { * Onboard Thermometer; ranged between 0 and 100 */ export class TemperatureSensor extends Sensor { - constructor() { - super(function () {return input.temperature()}, "Temp.", 0, 100, 1, "thermometer", "thermometer") + constructor(config: RecordingConfig) { + super(function () {return input.temperature()}, "Temp.", 0, 100, "thermometer", "thermometer", config) } } @@ -176,14 +132,14 @@ namespace microcode { * Onboard Accelerometer for X, Y, Z dimensions; ranged between -1023, 1023 */ export class AccelerometerSensor extends Sensor { - constructor(dim: Dimension) { + constructor(dim: Dimension, config: RecordingConfig) { super(function () {return input.acceleration(dim)}, "Accel. " + ['X', 'Y', 'Z'][dim], -1023, 1023, - 1, "accelerometer", - "accelerometer " + + ['X', 'Y', 'Z'][dim] + "accelerometer " + + ['X', 'Y', 'Z'][dim], + config ) } } @@ -192,7 +148,7 @@ namespace microcode { * Onboard Touch Pin Sensor for TouchPin 0, 1, 2; ranged between 0 and 1 */ export class PinSensor extends Sensor { - constructor(pin: TouchPin) { + constructor(pin: TouchPin, config: RecordingConfig) { super(function () { let res: number = 0 input.onPinPressed(pin, function () { @@ -203,9 +159,9 @@ namespace microcode { "Pin " + pin.toString(), 0, 1, - 1, "pin_" + pin.toString(), - "Pin " + pin.toString() + "Pin " + pin.toString(), + config ) } } @@ -217,14 +173,14 @@ namespace microcode { * MIN & MAX RANGE UNVERIFIED */ export class MagnetSensor extends Sensor { - constructor(dim: Dimension) { + constructor(dim: Dimension, config: RecordingConfig) { super(function() {return input.magneticForce(dim)}, "Magnet " + dim.toString(), 0, 1, - 1, "magnet", - "S10" + "S10", + config ) } } @@ -236,14 +192,14 @@ namespace microcode { * MIN & MAX RANGE UNVERIFIED */ export class RotationSensor extends Sensor { - constructor(rot: Rotation) { + constructor(rot: Rotation, config: RecordingConfig) { let name: string = "Pitch" if (rot === Rotation.Roll) { name = "Roll" } - super(function () {return input.rotation(rot)}, name, 0, 100, 1, "right_turn", name) + super(function () {return input.rotation(rot)}, name, 0, 100, "right_turn", name, config) } } @@ -254,8 +210,16 @@ namespace microcode { * sensorMaxReading may change in future */ export class LogoPressSensor extends Sensor { - constructor() { - super(function () {if(input.logoIsPressed()) {return 1} return 0}, "Logo Pressed", 0, 1, 1, "finger_press", "Logo Press") + constructor(config: RecordingConfig) { + super( + function () {if(input.logoIsPressed()) {return 1} return 0}, + "Logo Pressed", + 0, + 1, + "finger_press", + "Logo Press", + config + ) } } @@ -264,8 +228,16 @@ namespace microcode { * Ranged between 0 and 360 degrees */ export class CompassHeadingSensor extends Sensor { - constructor() { - super(function () {return input.compassHeading()}, "Compass", 0, 360, 1, "compass", "Compass") + constructor(config: RecordingConfig) { + super( + function () {return input.compassHeading()}, + "Compass", + 0, + 360, + "compass", + "Compass", + config + ) } } @@ -274,8 +246,16 @@ namespace microcode { * Ranged between 0 and 255 */ export class VolumeSensor extends Sensor { - constructor() { - super(function () {return input.soundLevel()}, "Volume", 0, 255, 1, "speaker", "Volume") + constructor(config: RecordingConfig) { + super( + function () {return input.soundLevel()}, + "Volume", + 0, + 255, + "speaker", + "Volume", + config + ) } } @@ -284,8 +264,8 @@ namespace microcode { * Need to be transformed into an event based system */ export class ButtonPressSensor extends Sensor { - constructor() { - super(function () {return 1}, "Button Press", 0, 1, 1, "tile_button_a", "F3") + constructor(config: RecordingConfig) { + super(function () {return 1}, "Button ", 0, 1, "tile_button_a", "F3", config) control.onEvent(DAL.DEVICE_BUTTON_EVT_UP, DAL.DEVICE_ID_BUTTON_A, () => { return 1 From b002665d1123654ba75b9b0f3d9a8af53504441c Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 18:05:50 +0000 Subject: [PATCH 077/109] recordingConfigSelection: ability to select unique configs per sensor, removed pop-up prompt, added coloured boxes for which sensor has a config set, which has not and which is selected. Reworked backend functions, heavy documentation. --- recordingConfigSelection.ts | 538 ++++++++++++++---------------------- 1 file changed, 207 insertions(+), 331 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 080d4bf..f284b6f 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -1,94 +1,111 @@ namespace microcode { /** - * PROMPT_SHARED_CONFIG: Ask if the user wants sensors to share measurement configs; so they only input 1 * SELECTING_SENSOR: User is selecting a sensor to modify * WRITING: User is modifying a setting * DEFAULT: User is not changing any settings & PROMPT_SHARED_CONFIG has occured. */ const enum GUI_STATE { - PROMPT_SHARED_CONFIG, SELECTING_SENSOR, WRITING, DEFAULT } + /** + * The user may be writing to the UI elements for the + * recording config or the events + * + */ const enum WRITING_MODE { - MEASUREMENT, - EVENT, + RECORDING_SETTINGS, + EVENT_SETTINGS, } /** - * Abstract for the screen that allows users to input measurement or event settings. - * Extended by MeasurementConfigSelection and EventConfigSelection + * The Recording Settings is a sub-window on the right-hand-side. + * It consists of a list of rows that the user can manipulate to change the RecordingConfig + */ + type RecordingSettingsGUIColumn = { + /** The name of this recording setting (record, ms, second, minute, hour, etc) */ + name: string, + /** The current value that the user has selected for this row (minute = 2); all of (ms, second, minute, hour, day) will be converted into ms at the end */ + value: number, + /** How much the value should increment or decrement by when the user selects this element and presses up or down (typically 1) */ + smallDelta: number, + /** How much the value should increment or decrement by when the user selects this element and presses left or right (typically 5 or 10) */ + largeDelta: number + } + + + /** + * The (ms, second, minute, hour, day) ui elements kept in RecordingSettingsGUIColumn.value are converted into ms using this: + */ + const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] + + + /** + * Responsible for allowing the user to select the specific recording configurations for each passed sensor. + * The user may also choose to select an event for each sensor. * + * After submission the DataRecorder is loaded & these sensor configs excercised. */ - abstract class RecordingConfigSelection extends Scene { - // UI Control: + export class RecordingConfigSelection extends Scene { private guiState: GUI_STATE private writingMode: WRITING_MODE - private guiRows: string[] - private currentColumn: number - private configDeltas: number[][] - protected userSelection: number[] - /** That were passed via selectSensors */ - private sensors: Sensor[] - private selectedSensorIndex: number + /** Each sensor may have a unique configuration, the UI should track the state of each configuration. This grid is responsible for that. + * guiRows[n] corresponds to the nth sensor; its contents will be converted into a RecordingConfig and passed to the sensor at completion. + */ + private guiRows: RecordingSettingsGUIColumn[][] + private currentSensorRow: number + private currentConfigRow: number + + /** * Sensor measurement control (unique per sensor) * Number of measurements, period, event control, etc * - * Each sensor is granted their config upon the progression from this screen. + * Each sensor is granted its config upon progression from this screen, via SensorFactory.new() * This could be improved via a Factory; where a sensor enum is passed. * Or a builder design pattern */ private sensorConfigs: RecordingConfig[] - private sensorsShareConfigs: boolean - - private acceptShareConfigButton: Sprite - private declineShareConfigButton: Sprite - - constructor(app: App, - appName: string, - sensors: Sensor[], - configDeltas: number[][], - defaultUserSelection: number[], - guiRows: string[] - ) { - super(app, appName) - - this.guiState = GUI_STATE.PROMPT_SHARED_CONFIG - this.writingMode = WRITING_MODE.MEASUREMENT - this.guiRows = guiRows - this.userSelection = defaultUserSelection - this.configDeltas = configDeltas - this.currentColumn = 0 - - this.sensors = sensors - this.selectedSensorIndex = 0 - this.sensorConfigs = [] - this.sensorsShareConfigs = false + private sensorBlueprints: SensorBlueprint[] + /** Whether or not the user has manipulated the UI for a sensor. + * Selecting a sensor, but leaving its config as default counts as 'changing' it; since the user may purposefully set it as such. + */ + private configHasChanged: boolean[] - // Probably a much neater way of configuring this... + constructor(app: App, sensorBlueprints: SensorBlueprint[]){ + super(app, "measurementConfigSelect") + this.guiState = GUI_STATE.SELECTING_SENSOR + this.writingMode = WRITING_MODE.RECORDING_SETTINGS - this.acceptShareConfigButton = new Sprite({img: icons.get("tile_button_a")}) - this.acceptShareConfigButton.bindXfrm(new Affine()) - this.acceptShareConfigButton.xfrm.parent = new Affine() - this.acceptShareConfigButton.xfrm.worldPos.x = Screen.HALF_WIDTH - this.acceptShareConfigButton.xfrm.worldPos.y = Screen.HALF_HEIGHT - this.acceptShareConfigButton.xfrm.localPos.x = -35 - this.acceptShareConfigButton.xfrm.localPos.y = 8 + this.guiRows = [] + this.sensorConfigs = [] + this.configHasChanged = [] + this.sensorBlueprints = sensorBlueprints + + // Each sensor has a unique config; the user selects this using these UI elements: + for (let _ = 0; _ < this.sensorBlueprints.length; _++) { + this.guiRows.push([ + {name: "Records", value: 20, smallDelta: 1, largeDelta: 10}, + {name: "ms", value: 0, smallDelta: 1, largeDelta: 10}, + {name: "Seconds", value: 1, smallDelta: 1, largeDelta: 5}, + {name: "Minutes", value: 0, smallDelta: 1, largeDelta: 5}, + {name: "Hours", value: 0, smallDelta: 1, largeDelta: 5}, + {name: "Days", value: 0, smallDelta: 1, largeDelta: 5}, + {name: "Delay", value: 0, smallDelta: 1, largeDelta: 5}, + ]) + + this.configHasChanged.push(false) + this.sensorConfigs.push({measurements: 20, period: 1000, delay: 0}) + } - this.declineShareConfigButton = new Sprite({img: icons.get("tile_button_b")}) - this.declineShareConfigButton.bindXfrm(new Affine()) - this.declineShareConfigButton.xfrm.parent = new Affine() - this.declineShareConfigButton.xfrm.worldPos.x = Screen.HALF_WIDTH - this.declineShareConfigButton.xfrm.worldPos.y = Screen.HALF_HEIGHT - this.declineShareConfigButton.xfrm.localPos.x = 34 - this.declineShareConfigButton.xfrm.localPos.y = 8 + this.currentSensorRow = 0 + this.currentConfigRow = 0 //-------------- // User Control: @@ -99,18 +116,18 @@ namespace microcode { controller.A.id, () => { switch (this.guiState) { - case GUI_STATE.PROMPT_SHARED_CONFIG: - this.sensorsShareConfigs = true - this.guiState = GUI_STATE.SELECTING_SENSOR - break; - case GUI_STATE.SELECTING_SENSOR: - this.guiState = GUI_STATE.DEFAULT + this.guiState = GUI_STATE.DEFAULT + this.configHasChanged[this.currentSensorRow] = true break; case GUI_STATE.DEFAULT: this.guiState = GUI_STATE.WRITING break; + + case GUI_STATE.WRITING: + this.guiState = GUI_STATE.DEFAULT + break; default: this.guiState = GUI_STATE.DEFAULT @@ -124,11 +141,6 @@ namespace microcode { controller.B.id, () => { switch (this.guiState) { - case GUI_STATE.PROMPT_SHARED_CONFIG: - this.sensorsShareConfigs = false - this.guiState = GUI_STATE.SELECTING_SENSOR - break; - case GUI_STATE.SELECTING_SENSOR: this.app.popScene() this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) @@ -139,9 +151,6 @@ namespace microcode { break case GUI_STATE.DEFAULT: - // this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - this.guiState = GUI_STATE.SELECTING_SENSOR break; @@ -158,18 +167,19 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.SELECTING_SENSOR) { // Non-negative modulo: - this.selectedSensorIndex = (((this.selectedSensorIndex - 1) % this.sensors.length) + this.sensors.length) % this.sensors.length + this.currentSensorRow = (((this.currentSensorRow - 1) % this.sensorBlueprints.length) + this.sensorBlueprints.length) % this.sensorBlueprints.length } - if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode == WRITING_MODE.MEASUREMENT) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][0], 0) + else if (this.guiState === GUI_STATE.WRITING) { + if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { + this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) } } else { // Non-negative modulo: - this.currentColumn = (((this.currentColumn - 1) % this.userSelection.length) + this.userSelection.length) % this.userSelection.length + const numberOfMeasurementRows = this.guiRows[0].length + this.currentConfigRow = (((this.currentConfigRow - 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows } } ) @@ -179,22 +189,18 @@ namespace microcode { controller.down.id, () => { if (this.guiState === GUI_STATE.SELECTING_SENSOR) { - this.selectedSensorIndex = (this.selectedSensorIndex + 1) % this.sensors.length + this.currentSensorRow = (this.currentSensorRow + 1) % this.sensorBlueprints.length } - if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode === WRITING_MODE.MEASUREMENT) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][0], 0) - } - - else { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][0], 0) + else if (this.guiState === GUI_STATE.WRITING) { + if (this.writingMode === WRITING_MODE.RECORDING_SETTINGS) { + this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) } } else { - // Non-negative modulo: - this.currentColumn = (this.currentColumn + 1) % this.userSelection.length + const numberOfMeasurementRows = this.guiRows[0].length + this.currentConfigRow = (((this.currentConfigRow + 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows } } ) @@ -204,17 +210,17 @@ namespace microcode { controller.left.id, () => { if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode === WRITING_MODE.MEASUREMENT) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] - this.configDeltas[this.currentColumn][1], 0) + if (this.writingMode === WRITING_MODE.RECORDING_SETTINGS) { + this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) } } if (this.guiState == GUI_STATE.SELECTING_SENSOR) { - if (this.writingMode == WRITING_MODE.MEASUREMENT) { - this.writingMode = WRITING_MODE.EVENT + if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { + this.writingMode = WRITING_MODE.EVENT_SETTINGS } else { - this.writingMode = WRITING_MODE.MEASUREMENT + this.writingMode = WRITING_MODE.RECORDING_SETTINGS } } } @@ -225,43 +231,32 @@ namespace microcode { controller.right.id, () => { if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode === WRITING_MODE.MEASUREMENT) { - this.userSelection[this.currentColumn] = Math.max(this.userSelection[this.currentColumn] + this.configDeltas[this.currentColumn][1], 0) + if (this.writingMode === WRITING_MODE.RECORDING_SETTINGS) { + this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) } } if (this.guiState == GUI_STATE.SELECTING_SENSOR) { - if (this.writingMode == WRITING_MODE.MEASUREMENT) { - this.writingMode = WRITING_MODE.EVENT + if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { + this.writingMode = WRITING_MODE.EVENT_SETTINGS } else { - this.writingMode = WRITING_MODE.MEASUREMENT + this.writingMode = WRITING_MODE.RECORDING_SETTINGS } } else if (this.guiState === GUI_STATE.DEFAULT) { - // Pass the configs onto the sensors: - this.sensors.map((sensor, index) => sensor.setConfig(this.sensorConfigs[index])) + // Build the sensors according to their specific configuration: + this.setSensorConfigs() + const sensors: Sensor[] = this.sensorBlueprints.map((blueprint, index) => SensorFactory.new(blueprint, this.sensorConfigs[index])) this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.generateRecordingOptions(), this.sensors, RecordingMode.TIME)) + this.app.pushScene(new DataRecorder(this.app, sensors)) } } ) } - /** - * Convert the .userSelection data into a RecordingConfig object for use by the DataRecorder - * @returns RecordingConfig {measurements, period, delay} - */ - public generateRecordingOptions(): RecordingConfig { - return { - measurements: 0, - period: 0, - delay: 0 - } - } - update() { Screen.fillRect( Screen.LEFT_EDGE, @@ -272,123 +267,96 @@ namespace microcode { ) screen.printCenter("Recording Settings", 2) - this.drawSensors() - if (this.guiState != GUI_STATE.SELECTING_SENSOR && this.guiState != GUI_STATE.PROMPT_SHARED_CONFIG) { - if (this.writingMode == WRITING_MODE.MEASUREMENT) { + if (this.guiState == GUI_STATE.WRITING || this.guiState == GUI_STATE.DEFAULT) { + if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { this.drawMeasurementSelectWindow() } else { this.drawEventSelectWindow() } } - - // Drawn ontop of above grapics, as pop-up - if (this.guiState == GUI_STATE.PROMPT_SHARED_CONFIG) { - // Border: - // Slightly taller and wider than box for depth effect - screen.fillRect( - Screen.HALF_WIDTH - 51, - Screen.HALF_HEIGHT - 26, - 103, - 56, - 5 - ) - - // Body - screen.fillRect( - Screen.HALF_WIDTH - 50, - Screen.HALF_HEIGHT - 25, - 100, - 53, - 7 - ) - - screen.printCenter("Unique config", Screen.HALF_HEIGHT - 25 + 4, 16) - screen.printCenter("per sensor?", Screen.HALF_HEIGHT - 25 + 12, 16) - - // Draw button prompts: - screen.print( - "Yes", - Screen.HALF_WIDTH - 41, - Screen.HALF_HEIGHT + 14, - 16 - ) - - screen.print( - "No", - Screen.HALF_WIDTH + 31, - Screen.HALF_HEIGHT + 14, - 16 - ) - - this.acceptShareConfigButton.draw() - this.declineShareConfigButton.draw() - } } private drawMeasurementSelectWindow() { - let timeAsString; - let rowOffset = 0; - - const pointerX = Screen.WIDTH - 12 - const optionX = pointerX - 15 - const headerX = optionX - (font.charWidth * this.guiRows[0].length) - 8 - const rowSize = Screen.HEIGHT / (this.userSelection.length + 1) + const optionX = Screen.WIDTH - 17 + const headerX = optionX - (font.charWidth * this.guiRows[this.currentSensorRow][0].name.length) - 6 + const rowSize = Screen.HEIGHT / (this.guiRows[0].length + 1) // Sub-window: // Outline: screen.fillRect( - headerX - 4, - 12, - Screen.WIDTH - headerX + 4, - Screen.HEIGHT - 15, + headerX - 9, + 14, + Screen.WIDTH - headerX + 8, + Screen.HEIGHT, + 0 + ) + + screen.fillRect( + headerX - 7, + 15, + Screen.WIDTH - headerX + 10, + Screen.HEIGHT - 2, 6 ) + // Box around the current measurement row: screen.fillRect( - headerX - 2, - 14, - Screen.WIDTH - headerX + 2, - Screen.HEIGHT - 19, - 4 + headerX - 8, + 18 + (this.currentConfigRow * rowSize) - 3, + Screen.WIDTH - headerX + 4, + font.charHeight + 9, + 16 + ) + + screen.fillRect( + headerX - 6, + 18 + (this.currentConfigRow * rowSize) - 3, + Screen.WIDTH - headerX + 5, + font.charHeight + 6, + 5 ) - for (let i = 0; i < this.userSelection.length; i++) { + let color = 0 + let rowOffset = 0; + for (let configRow = 0; configRow < this.guiRows[0].length; configRow++) { + if (configRow == this.currentConfigRow) { + color = 16 + } + + else { + color = 0 + } + screen.print( - this.guiRows[i], - headerX, - 18 + rowOffset + this.guiRows[this.currentSensorRow][configRow].name, + headerX - 1, + 18 + rowOffset, + color ) - - timeAsString = this.userSelection[i].toString() + screen.print( - timeAsString, - optionX, - 18 + rowOffset + this.guiRows[this.currentSensorRow][configRow].value.toString(), + optionX - 3, + 18 + rowOffset, + color ) rowOffset += rowSize } - - // Cursor arrow - screen.print("<-", - pointerX, - 18 + (rowSize * this.currentColumn), - 0 - ) } private drawEventSelectWindow() { const pointerY = Screen.HEIGHT - 83 const yOffset = 18 - const rowSize = Screen.HEIGHT / (this.sensors.length + 1) + const rowSize = Screen.HEIGHT / (this.sensorBlueprints.length + 1) // Sub-window: // Outline: screen.fillRect( 74, - yOffset + ((this.selectedSensorIndex + 1) * rowSize) - 2, + yOffset + ((this.currentSensorRow + 1) * rowSize) - 2, 60, font.charHeight + 9, 16 @@ -396,176 +364,84 @@ namespace microcode { screen.fillRect( 74, - yOffset + ((this.selectedSensorIndex + 1) * rowSize) - 2, + yOffset + ((this.currentSensorRow + 1) * rowSize) - 2, 58, font.charHeight + 6, 9 ) - const middleSensorRange = this.sensors[this.selectedSensorIndex].maximum - this.sensors[this.selectedSensorIndex].minimum + // const middleSensorRange = this.sensorBlueprints[this.selectedSensorIndex].maximum - Math.abs(this.sensorBlueprints[this.selectedSensorIndex].minimum) // Write Event expression: screen.print( - sensorEventSymbols[0] + " " + middleSensorRange.toString(), - 80, - yOffset + ((this.selectedSensorIndex + 1) * rowSize) - 1, - 16 - ) - - screen.print( - "^", + sensorEventSymbols[0] + " 0", // + middleSensorRange.toString(), 80, - yOffset + ((this.selectedSensorIndex + 1) * rowSize) + 20 + yOffset + ((this.currentSensorRow + 1) * rowSize) - 1, + 15 // black ) - - // const sensorSprite = new Sprite({img: icons.get(this.sensors[this.selectedSensorIndex].iconName)}) - // sensorSprite.bindXfrm(new Affine()) - // sensorSprite.xfrm.parent = new Affine() - // sensorSprite.xfrm.worldPos.x = 100 - // sensorSprite.xfrm.worldPos.y = 16 + ((this.selectedSensorIndex + 1) * rowSize) - // sensorSprite.xfrm.localPos.x = 5 - // sensorSprite.xfrm.localPos.y = 0 } private drawSensors() { const headerX = 4 - const rowSize = Screen.HEIGHT / (this.sensors.length + 1) - - let writingModeColour = 5 // Measurement mode - - if (this.writingMode == WRITING_MODE.EVENT) { - writingModeColour = 9 - } - - // Box around header: - screen.fillRect( - 0, - 16, - 80, - font.charHeight + 9, - 16 - ) - - screen.fillRect( - 1, - 16, - 78, - font.charHeight + 6, - writingModeColour - ) - - // Box around selected: - screen.fillRect( - 0, - 18 + ((this.selectedSensorIndex + 1) * rowSize) - 2, - 56, - font.charHeight + 9, - 16 - ) - - screen.fillRect( - 1, - 18 + ((this.selectedSensorIndex + 1) * rowSize) - 2, - 54, - font.charHeight + 6, - writingModeColour - ) - - let headerText = "Record " - if (this.writingMode == WRITING_MODE.MEASUREMENT) { - headerText += "Data" - } - else { - headerText += "Event" - } + const rowSize = Screen.HEIGHT / (this.sensorBlueprints.length + 1) - // Header: - screen.print( - headerText, - headerX, - 17, - 16 - ) + let boxColor = 2 + for (let rowID = 0; rowID < this.sensorBlueprints.length; rowID++) { + const name = SensorFactory.new(this.sensorBlueprints[rowID], this.sensorConfigs[rowID]).name - let color = 0 - for (let rowID = 0; rowID < this.sensors.length; rowID++) { - if (this.selectedSensorIndex === rowID) { - color = 16 + // Select the color for the bounding box: + boxColor = 2 // red: unchanged + if (rowID == this.currentSensorRow) { + boxColor = 5 // yellow: selected } - else { - color = 0 + else if (this.configHasChanged[rowID]) { + boxColor = 7 // green: changed } + screen.fillRect( + 0, + 18 + (rowID * rowSize) - 3, + (name.length) * font.charWidth + 4, + font.charHeight + 9, + 16 + ) + + screen.fillRect( + 1, + 18 + (rowID * rowSize) - 3, + (name.length) * font.charWidth + 5, + font.charHeight + 6, + boxColor + ) + screen.print( - this.sensors[rowID].name, - headerX, - 17 + ((rowID + 1) * rowSize), - color + name, + headerX - 2, + 20 + (rowID * rowSize) + 1, + 15 // black ) } } - } - - export class MeasurementConfigSelect extends RecordingConfigSelection { - constructor(app: App, selectedSensors: Sensor[]) { - /** - * Values for user selection of: - * Measurement quantity - * Measurement period - * Measurement delay - * - * Internal counters will iterate by these values, - * upon the corresponding UI element selection. - * */ - const configDeltas = [ - [1, 10], // Quantity - [1, 10], // Milli-seconds - [1, 5], // Seconds - [1, 5], // Minutes - [1, 5], // Hours - [1, 5], // Days - [1, 5] // Delay - ] - - // [Quantity, Milli-seconds, Seconds, Minutes, Hours, Days, Start Delay]: - // const defaultUserSelection = [10, 0, 1, 0, 0, 0, 0] - const defaultUserSelection = [10, 30, 0, 0, 0, 0, 0] - const guiRows = ["Records: ", - "MilliSec: ", - "Seconds: ", - "Minutes: ", - "Hours: ", - "Days: ", - "Delay: " - ] - - super(app, "measurementConfigSelect", selectedSensors, configDeltas, defaultUserSelection, guiRows) - } /** - * Convert the .userSelection data into a RecordingConfig object for use by the DataRecorder - * @returns RecordingConfig {measurements, period, delay} + * Convert the .guiRows data into a RecordingConfig object for use by the DataRecorder + * Set the this.sensorConfigs[this.currentSensorRow] to this RecordingConfig object */ - public generateRecordingOptions(): RecordingConfig { - const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] - - let period: number = 0 - for (let i = 1; i < this.userSelection.length - 1; i++) { - period += this.userSelection[i] * timeConversionTableMs[i - 1] - } + private setSensorConfigs(): void { + for (let sensorRow = 0; sensorRow < this.guiRows.length; sensorRow++) { + + let period: number = 0 + for (let col = 1; col < this.guiRows[0].length - 1; col++) { + period += this.guiRows[sensorRow][col].value * timeConversionTableMs[col - 1] + } - return { - measurements: this.userSelection[0], - period, - delay: this.userSelection[6] + this.sensorConfigs[sensorRow] = { + measurements: this.guiRows[sensorRow][0].value, + period, + delay: this.guiRows[sensorRow][6].value + } } } } - - export class EventConfigSelect extends RecordingConfigSelection { - constructor(app: App, selectedSensors: Sensor[]) { - super(app, "eventConfigSelect", selectedSensors, [], [], []) - } - } } \ No newline at end of file From 8825da4a7df5bd0fa2f972b8bb8c97d491b86ee3 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 18:07:15 +0000 Subject: [PATCH 078/109] Foundation of Prototype 11: multiple sensor asynchronous recording, smoother livedataview plotting, independent sensor configurations, data recording screen rework, filtering option to tabular data view. --- fauxLoggers.ts | 100 ------------------------------------ home.ts | 4 +- liveDataViewer.ts | 43 +++++++++++----- pxt.json | 6 ++- recordingConfigSelection.ts | 1 - sensorFactory.ts | 52 +++++++++++++++++++ sensorSelect.ts | 41 ++++++++------- 7 files changed, 107 insertions(+), 140 deletions(-) delete mode 100644 fauxLoggers.ts create mode 100644 sensorFactory.ts diff --git a/fauxLoggers.ts b/fauxLoggers.ts deleted file mode 100644 index ddd95b0..0000000 --- a/fauxLoggers.ts +++ /dev/null @@ -1,100 +0,0 @@ -namespace microcode { - /** - * Internal representation of an logged entry - */ - interface DataEntry { - id: number, - data: string[] - } - - abstract class Logger { - static headers: string[] - static headerStringLengths: number[] // Needed for column size so that values also fit; also pre-calculation since headers are fixed. - static dateStamp = "13/03/2024" // Microbit does not have access to Date; new Date().toLocaleDateString() - static entries: DataEntry[] - static numberOfRows: number - static isEmpty: boolean = true - static measurementOptions: RecordingConfig - static sensors: Sensor[] - - constructor(mOpts: RecordingConfig, sensors: Sensor[]) { - Logger.headers = [ - "Sensor", - "Milli-sec", - "Event", - "Reading" - ] - - // Additional characters added for space for lines either side and for width of data below - // For example sensor.name may be much longer than just "Sensor" - Logger.headerStringLengths = [ - ("Sensor".length + 4) * font.charWidth, - ("Milli-sec".length + 2) * font.charWidth, - ("Event".length + 6) * font.charWidth, - ("Reading".length + 2) * font.charWidth - ] - - Logger.entries = [] - Logger.numberOfRows = 0 - Logger.measurementOptions = mOpts - Logger.sensors = sensors - } - - public static log(data: string[]) { - Logger.isEmpty = false - Logger.entries.push({ - id: this.entries.length, - data - }) - Logger.numberOfRows += 1 - } - - public static getNumberOfMetadataRows(): number { - return 5 + Logger.headers.length - } - - public static getMetadata() { - let metadata = [ - {col1: "Date", col2: Logger.dateStamp}, - {col1: "Rows", col2: Logger.numberOfRows.toString()}, - {col1: "Columns", col2: Logger.headers.length.toString()}, - {col1: "Measurements", col2: Logger.measurementOptions.measurements.toString()}, - {col1: "Period", col2: Logger.measurementOptions.period.toString()} - ] - - for (let i = 0; i < Logger.headers.length; i++) { - metadata.push({col1: "Col " + (i + 1).toString(), col2: Logger.headers[i]}) - } - - return metadata - } - } - - export class FauxDataLogger extends Logger { - constructor(mOpts: RecordingConfig, sensors: Sensor[]) { - super(mOpts, sensors) - - // Add initial entry for the headers, Logger.isEmpty remains false: - Logger.entries.push({ - id: Logger.entries.length, - data: Logger.headers - }) - Logger.numberOfRows += 1 - } - - public static log(data: string[]) { - Logger.isEmpty = false - Logger.entries.push({ - id: Logger.entries.length, - data - }) - Logger.numberOfRows += 1 - } - } - - export class FauxEventLogger extends Logger { - constructor(mOpts: RecordingConfig, sensors: Sensor[]) { - super(mOpts, sensors) - } - } -} \ No newline at end of file diff --git a/home.ts b/home.ts index 3aff348..3320653 100644 --- a/home.ts +++ b/home.ts @@ -58,8 +58,8 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - "Prototype 9", - Screen.RIGHT_EDGE - font.charWidth * "Prototype 9".length, + "Prototype 11", + Screen.RIGHT_EDGE - font.charWidth * "Prototype 11".length, Screen.BOTTOM_EDGE - font.charHeight - 2, 0xb, font diff --git a/liveDataViewer.ts b/liveDataViewer.ts index fe600ba..7524a58 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -35,10 +35,12 @@ namespace microcode { /* To plot */ private sensors: Sensor[] - constructor(app: App, sensors: Sensor[]) { + constructor(app: App, sensorBlueprints: SensorBlueprint[]) { super(app, "liveDataViewer") this.color = 0 - this.sensors = sensors + + const config: RecordingConfig = {measurements: 0, period: 0, delay: 0} + this.sensors = sensorBlueprints.map((blueprint) => SensorFactory.new(blueprint, config)) this.windowWidth = Screen.WIDTH this.windowHeight = Screen.HEIGHT @@ -60,10 +62,10 @@ namespace microcode { // Ensure selectedSensorIndex is set to the lowest current reading this.selectedSensorIndex = 0 - let minimumReading = sensors[0].getReading() - for (let i = 1; i < sensors.length; i++) { - if (sensors[i].getReading() < minimumReading) { - minimumReading = sensors[i].getReading() + let minimumReading = this.sensors[0].getReading() + for (let i = 1; i < this.sensors.length; i++) { + if (this.sensors[i].getReading() < minimumReading) { + minimumReading = this.sensors[i].getReading() this.selectedSensorIndex = i } } @@ -168,7 +170,6 @@ namespace microcode { if (this.currentZoomDepth != 0) { if (!this.oscilloscopeMovementMode && this.selectedXCoordinate - (Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) > 0) { this.selectedXCoordinate -= Math.round(Math.abs(this.sensors[this.selectedSensorIndex].getDataBufferLength() - this.selectedXCoordinate) / 2) - } else { this.selectedXCoordinate = Math.max(0, this.selectedXCoordinate - 1) @@ -233,22 +234,36 @@ namespace microcode { this.draw_axes(); + const yStart = this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + let y = yStart + // Write Sensor information, displayed below the plot: for (let i = 0; i < this.sensors.length; i++) { // Colour used to represent this sensor, same colour as plotted & ticker: + y += (i * 12) + screen.fillRect( 2, - this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), + y, 7, 7, color ) - - // Name, reading / maximum, peak - screen.print(this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maximum + - " Peak " + this.sensors[i].peakDataPoint[1], + + // Name, reading / maximum + screen.print( + this.sensors[i].name + " " + this.sensors[i].getReading() + "/" + this.sensors[i].maximum, 14, - this.windowHeight - this.windowBotBuffer + this.yScrollOffset + this.yScrollOffset + 15 + (i * 12), + y, + color + ) + + // Write the peak reading just below and with a slight xOffset from the above: + y += 12 + screen.print( + "Peak " + this.sensors[i].peakDataPoint[1], + 44, + y, color ) @@ -334,7 +349,7 @@ namespace microcode { this.sensors.forEach(function(sensor) { sensor.draw( this.windowWidthBuffer + 2 + this.xScrollOffset, - this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset, + this.windowBotBuffer - 2 * this.yScrollOffset, color ) color = (color + 3) % 15 diff --git a/pxt.json b/pxt.json index 3a77a49..541974e 100644 --- a/pxt.json +++ b/pxt.json @@ -42,6 +42,7 @@ "ruleEditor.ts", "editor.ts", "samples.ts", + "liveDataViewer.ts", "tabularDataViewer.ts", "sensorSelect.ts", @@ -49,10 +50,11 @@ "recordingConfig.ts", "recordingConfigSelection.ts", "sensors.ts", - "fauxLoggers.ts", + "fauxDataLogger.ts", "dataRecorder.ts", "generateGraph.ts", - "sensorEvent.ts" + "sensorEvent.ts", + "sensorFactory.ts" ], "testFiles": [], "targetVersions": { diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index f284b6f..11b3208 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -13,7 +13,6 @@ namespace microcode { /** * The user may be writing to the UI elements for the * recording config or the events - * */ const enum WRITING_MODE { RECORDING_SETTINGS, diff --git a/sensorFactory.ts b/sensorFactory.ts new file mode 100644 index 0000000..d9b4d65 --- /dev/null +++ b/sensorFactory.ts @@ -0,0 +1,52 @@ +namespace microcode { + export enum SensorID { + Light, + Temperature, + Accelerometer, + Pin, + Magnet, + Rotation, + LogoPress, + CompassHeading, + Volume, + ButtonPress + } + + + /** + * Specification of the sensor and its parameters. + * Passed into the SensorFactory along with the sensor's recording config. + */ + export class SensorBlueprint { + public readonly id: SensorID + public readonly dim?: Dimension + public readonly pin?: TouchPin + public readonly rot?: Rotation + + constructor(settings: {id: SensorID, dim?: Dimension, pin?: TouchPin, rot?: Rotation}) { + this.id = settings.id + this.dim = settings.dim + this.pin = settings.pin + this.rot = settings.rot + } + } + + export class SensorFactory { + public static new(blueprint: SensorBlueprint, config: RecordingConfig): Sensor { + switch (blueprint.id) { + case SensorID.Light: return new LightSensor(config) + case SensorID.Temperature: return new TemperatureSensor(config) + case SensorID.Accelerometer: return new AccelerometerSensor(blueprint.dim, config) + case SensorID.Pin: return new PinSensor(blueprint.pin, config) + case SensorID.Magnet: return new MagnetSensor(blueprint.dim, config) + case SensorID.Rotation: return new RotationSensor(blueprint.rot, config) + case SensorID.LogoPress: return new LogoPressSensor(config) + case SensorID.CompassHeading: return new CompassHeadingSensor(config) + case SensorID.Volume: return new VolumeSensor(config) + case SensorID.ButtonPress: return new ButtonPressSensor(config) + + default: return new LightSensor(config); + } + } + } +} \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index 8856633..2c8f1fd 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -7,13 +7,13 @@ namespace microcode { */ export class SensorSelect extends CursorSceneWithPriorPage { private btns: Button[] - private selectedSensors: Sensor[] + private selectedSensorBlueprints: SensorBlueprint[] private nextSceneEnum: CursorSceneEnum constructor(app: App, nextSceneEnum: CursorSceneEnum) { super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) this.btns = [] - this.selectedSensors = [] + this.selectedSensorBlueprints = [] this.nextSceneEnum = nextSceneEnum } @@ -28,7 +28,7 @@ namespace microcode { x: -60, y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Accelerometer, dim: Dimension.X})) }, dynamicBoundaryColorsOn: true, })) @@ -41,7 +41,7 @@ namespace microcode { x: -30, y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.Y)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Accelerometer, dim: Dimension.Y})) }, dynamicBoundaryColorsOn: true, })) @@ -54,7 +54,7 @@ namespace microcode { x: 0, y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.Z)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Accelerometer, dim: Dimension.Z})) }, dynamicBoundaryColorsOn: true, })) @@ -67,7 +67,7 @@ namespace microcode { x: 30, y: -40, onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Rotation, rot: Rotation.Pitch})) }, dynamicBoundaryColorsOn: true, })) @@ -80,7 +80,7 @@ namespace microcode { x: 60, y: -40, onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Rotation, rot: Rotation.Roll})) }, dynamicBoundaryColorsOn: true, })) @@ -95,7 +95,7 @@ namespace microcode { x: -60, y: -11, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P0)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Pin, pin: TouchPin.P0})) }, dynamicBoundaryColorsOn: true, })) @@ -108,7 +108,7 @@ namespace microcode { x: -30, y: -11, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P1)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Pin, pin: TouchPin.P0})) }, dynamicBoundaryColorsOn: true, })) @@ -122,7 +122,7 @@ namespace microcode { x: 0, y: -11, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P2)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Pin, pin: TouchPin.P0})) }, dynamicBoundaryColorsOn: true, })) @@ -136,7 +136,7 @@ namespace microcode { x: 30, y: -11, onClick: () => { - this.selectedSensors.push(new LightSensor()) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Light})) }, dynamicBoundaryColorsOn: true, })) @@ -149,7 +149,7 @@ namespace microcode { x: 60, y: -11, onClick: () => { - this.selectedSensors.push(new TemperatureSensor()) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Temperature})) }, dynamicBoundaryColorsOn: true, })) @@ -164,7 +164,7 @@ namespace microcode { x: -60, y: 18, onClick: () => { - this.selectedSensors.push(new MagnetSensor(Dimension.X)) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Magnet, dim: Dimension.X})) }, dynamicBoundaryColorsOn: true, })) @@ -177,7 +177,7 @@ namespace microcode { x: -30, y: 18, onClick: () => { - this.selectedSensors.push(new LogoPressSensor()) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.LogoPress})) }, dynamicBoundaryColorsOn: true, })) @@ -190,7 +190,7 @@ namespace microcode { x: 0, y: 18, onClick: () => { - this.selectedSensors.push(new VolumeSensor()) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Volume})) }, dynamicBoundaryColorsOn: true, })) @@ -203,7 +203,7 @@ namespace microcode { x: 30, y: 18, onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.CompassHeading})) }, dynamicBoundaryColorsOn: true, })) @@ -216,7 +216,7 @@ namespace microcode { x: 60, y: 18, onClick: () => { - this.selectedSensors.push(new ButtonPressSensor()) + this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.ButtonPress})) }, dynamicBoundaryColorsOn: true, })) @@ -231,18 +231,17 @@ namespace microcode { x: 60, y: 44, onClick: () => { - if (this.selectedSensors.length === 0) { + if (this.selectedSensorBlueprints.length === 0) { return } this.app.popScene() - if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) + this.app.pushScene(new LiveDataViewer(app, this.selectedSensorBlueprints)) } else { - this.app.pushScene(new MeasurementConfigSelect(app, this.selectedSensors)) + this.app.pushScene(new RecordingConfigSelection(app, this.selectedSensorBlueprints)) } } })) From 492ab230185173b0a3b22e6b2ea1ef0a1670df64 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 19:15:06 +0000 Subject: [PATCH 079/109] recordingModeSelection: removed: no longer useful --- recordingModeSelection.ts | 54 --------------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 recordingModeSelection.ts diff --git a/recordingModeSelection.ts b/recordingModeSelection.ts deleted file mode 100644 index dd34edb..0000000 --- a/recordingModeSelection.ts +++ /dev/null @@ -1,54 +0,0 @@ -namespace microcode { - export class RecordingModeSelection extends CursorScene { - private btns: Button[] - - constructor(app: App) { - super(app) - - const recordTimeBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "edit_program", - ariaId: "Measurement Mode", - x: -30, - y: 30, - onClick: () => { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - }, - }) - - const recordEventBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "edit_program", - ariaId: "Event Mode", - x: 30, - y: 30, - onClick: () => { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - }, - }) - - this.btns = [recordTimeBtn, recordEventBtn] - this.navigator.addButtons(this.btns) - } - - update() { - Screen.fillRect( - Screen.LEFT_EDGE, - Screen.TOP_EDGE, - Screen.WIDTH, - Screen.HEIGHT, - 0xc - ) - - screen.printCenter("Select the Measurement Mode", 10) - - for (let i = 0; i < this.btns.length; ++i) { - this.btns[i].draw() - } - } - } -} \ No newline at end of file From c4e0f05dc4526801eb3b3fdae3d5ead2ac464add Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Thu, 28 Mar 2024 21:30:11 +0000 Subject: [PATCH 080/109] recordingConfigSelection: slight adjustments to UI positioning to make elements fit better, added config and event selection options. --- recordingConfigSelection.ts | 194 +++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 69 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 11b3208..02b82b0 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -6,6 +6,7 @@ namespace microcode { */ const enum GUI_STATE { SELECTING_SENSOR, + SELECTING_WRITE_MODE, WRITING, DEFAULT } @@ -14,7 +15,7 @@ namespace microcode { * The user may be writing to the UI elements for the * recording config or the events */ - const enum WRITING_MODE { + const enum WRITE_MODE { RECORDING_SETTINGS, EVENT_SETTINGS, } @@ -39,8 +40,7 @@ namespace microcode { /** * The (ms, second, minute, hour, day) ui elements kept in RecordingSettingsGUIColumn.value are converted into ms using this: */ - const timeConversionTableMs: number[] = [1, 1000, 60000, 3600000, 86400000] - + const TIME_CONVERSION_TABLE: number[] = [1, 1000, 60000, 3600000, 86400000] /** * Responsible for allowing the user to select the specific recording configurations for each passed sensor. @@ -50,7 +50,7 @@ namespace microcode { */ export class RecordingConfigSelection extends Scene { private guiState: GUI_STATE - private writingMode: WRITING_MODE + private writingMode: WRITE_MODE /** Each sensor may have a unique configuration, the UI should track the state of each configuration. This grid is responsible for that. * guiRows[n] corresponds to the nth sensor; its contents will be converted into a RecordingConfig and passed to the sensor at completion. @@ -58,8 +58,7 @@ namespace microcode { private guiRows: RecordingSettingsGUIColumn[][] private currentSensorRow: number private currentConfigRow: number - - + private currentWriteModeRow: number /** * Sensor measurement control (unique per sensor) @@ -80,7 +79,7 @@ namespace microcode { constructor(app: App, sensorBlueprints: SensorBlueprint[]){ super(app, "measurementConfigSelect") this.guiState = GUI_STATE.SELECTING_SENSOR - this.writingMode = WRITING_MODE.RECORDING_SETTINGS + this.writingMode = WRITE_MODE.RECORDING_SETTINGS this.guiRows = [] this.sensorConfigs = [] @@ -105,6 +104,7 @@ namespace microcode { this.currentSensorRow = 0 this.currentConfigRow = 0 + this.currentWriteModeRow = 0 //-------------- // User Control: @@ -116,10 +116,14 @@ namespace microcode { () => { switch (this.guiState) { case GUI_STATE.SELECTING_SENSOR: - this.guiState = GUI_STATE.DEFAULT + this.guiState = GUI_STATE.SELECTING_WRITE_MODE this.configHasChanged[this.currentSensorRow] = true break; + case GUI_STATE.SELECTING_WRITE_MODE: + this.guiState = GUI_STATE.DEFAULT + break; + case GUI_STATE.DEFAULT: this.guiState = GUI_STATE.WRITING break; @@ -145,12 +149,16 @@ namespace microcode { this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) break; + case GUI_STATE.SELECTING_WRITE_MODE: + this.guiState = GUI_STATE.SELECTING_SENSOR + break; + case GUI_STATE.WRITING: this.guiState = GUI_STATE.SELECTING_SENSOR break case GUI_STATE.DEFAULT: - this.guiState = GUI_STATE.SELECTING_SENSOR + this.guiState = GUI_STATE.SELECTING_WRITE_MODE break; default: @@ -170,11 +178,16 @@ namespace microcode { } else if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { + if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) } } + else if (this.guiState == GUI_STATE.SELECTING_WRITE_MODE) { + // Non-negative modulo: + this.currentWriteModeRow = (((this.currentWriteModeRow - 1) % 2) + 2) % 2 + } + else { // Non-negative modulo: const numberOfMeasurementRows = this.guiRows[0].length @@ -192,11 +205,15 @@ namespace microcode { } else if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode === WRITING_MODE.RECORDING_SETTINGS) { + if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) } } + else if (this.guiState == GUI_STATE.SELECTING_WRITE_MODE) { + this.currentWriteModeRow = (this.currentWriteModeRow + 1) % 2 + } + else { const numberOfMeasurementRows = this.guiRows[0].length this.currentConfigRow = (((this.currentConfigRow + 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows @@ -209,17 +226,17 @@ namespace microcode { controller.left.id, () => { if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode === WRITING_MODE.RECORDING_SETTINGS) { + if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) } } - if (this.guiState == GUI_STATE.SELECTING_SENSOR) { - if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { - this.writingMode = WRITING_MODE.EVENT_SETTINGS + else if (this.guiState == GUI_STATE.SELECTING_SENSOR) { + if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { + this.writingMode = WRITE_MODE.EVENT_SETTINGS } else { - this.writingMode = WRITING_MODE.RECORDING_SETTINGS + this.writingMode = WRITE_MODE.RECORDING_SETTINGS } } } @@ -230,17 +247,17 @@ namespace microcode { controller.right.id, () => { if (this.guiState === GUI_STATE.WRITING) { - if (this.writingMode === WRITING_MODE.RECORDING_SETTINGS) { + if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) } } - if (this.guiState == GUI_STATE.SELECTING_SENSOR) { - if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { - this.writingMode = WRITING_MODE.EVENT_SETTINGS + else if (this.guiState == GUI_STATE.SELECTING_SENSOR) { + if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { + this.writingMode = WRITE_MODE.EVENT_SETTINGS } else { - this.writingMode = WRITING_MODE.RECORDING_SETTINGS + this.writingMode = WRITE_MODE.RECORDING_SETTINGS } } @@ -256,6 +273,27 @@ namespace microcode { ) } + + /** + * Convert the .guiRows data into a RecordingConfig object for use by the DataRecorder + * Set the this.sensorConfigs[this.currentSensorRow] to this RecordingConfig object + */ + private setSensorConfigs(): void { + for (let sensorRow = 0; sensorRow < this.guiRows.length; sensorRow++) { + + let period: number = 0 + for (let col = 1; col < this.guiRows[0].length - 1; col++) { + period += this.guiRows[sensorRow][col].value * TIME_CONVERSION_TABLE[col - 1] + } + + this.sensorConfigs[sensorRow] = { + measurements: this.guiRows[sensorRow][0].value, + period, + delay: this.guiRows[sensorRow][6].value + } + } + } + update() { Screen.fillRect( Screen.LEFT_EDGE, @@ -266,19 +304,67 @@ namespace microcode { ) screen.printCenter("Recording Settings", 2) - this.drawSensors() + this.drawSensorSelection() if (this.guiState == GUI_STATE.WRITING || this.guiState == GUI_STATE.DEFAULT) { - if (this.writingMode == WRITING_MODE.RECORDING_SETTINGS) { - this.drawMeasurementSelectWindow() + if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { + this.drawConfigSelectionWindow() } else { - this.drawEventSelectWindow() + this.drawEventSelectionWindow() } } + + else if (this.guiState == GUI_STATE.SELECTING_WRITE_MODE) { + this.drawWriteModeSelection() + } } - private drawMeasurementSelectWindow() { + + //---------------------------- + // Internal Drawing Functions: + //---------------------------- + + + private drawWriteModeSelection() { + this.currentWriteModeRow + const yPosText = (Screen.HEIGHT / 3) + const xPosText: number = Screen.WIDTH - 38 + const text: string[] = ["Config", "Events"] + + let boxColor = 1 // white + for (let row = 0; row < 2; row++) { + boxColor = 1 // white + if (row == this.currentWriteModeRow) { + boxColor = 6 // blue + } + + screen.fillRect( + xPosText - 1, + ((row + 1) * yPosText), + (text[row].length) * font.charWidth + 4, + font.charHeight + 9, + 15 // black + ) + + screen.fillRect( + xPosText - 3, + ((row + 1) * yPosText), + (text[row].length) * font.charWidth + 5, + font.charHeight + 6, + boxColor + ) + + screen.print( + text[row], + xPosText, + ((row + 1) * yPosText) + 2, + 15 // black + ) + } + } + + private drawConfigSelectionWindow() { const optionX = Screen.WIDTH - 17 const headerX = optionX - (font.charWidth * this.guiRows[this.currentSensorRow][0].name.length) - 6 const rowSize = Screen.HEIGHT / (this.guiRows[0].length + 1) @@ -305,7 +391,7 @@ namespace microcode { screen.fillRect( headerX - 8, 18 + (this.currentConfigRow * rowSize) - 3, - Screen.WIDTH - headerX + 4, + Screen.WIDTH - headerX + 7, font.charHeight + 9, 16 ) @@ -313,41 +399,31 @@ namespace microcode { screen.fillRect( headerX - 6, 18 + (this.currentConfigRow * rowSize) - 3, - Screen.WIDTH - headerX + 5, + Screen.WIDTH - headerX + 8, font.charHeight + 6, 5 ) - let color = 0 let rowOffset = 0; for (let configRow = 0; configRow < this.guiRows[0].length; configRow++) { - if (configRow == this.currentConfigRow) { - color = 16 - } - - else { - color = 0 - } - screen.print( this.guiRows[this.currentSensorRow][configRow].name, headerX - 1, 18 + rowOffset, - color + 15 // Black ) screen.print( this.guiRows[this.currentSensorRow][configRow].value.toString(), optionX - 3, 18 + rowOffset, - color + 15 // Black ) rowOffset += rowSize } } - private drawEventSelectWindow() { - const pointerY = Screen.HEIGHT - 83 + private drawEventSelectionWindow() { const yOffset = 18 const rowSize = Screen.HEIGHT / (this.sensorBlueprints.length + 1) @@ -380,27 +456,27 @@ namespace microcode { ) } - private drawSensors() { + private drawSensorSelection() { const headerX = 4 const rowSize = Screen.HEIGHT / (this.sensorBlueprints.length + 1) let boxColor = 2 - for (let rowID = 0; rowID < this.sensorBlueprints.length; rowID++) { - const name = SensorFactory.new(this.sensorBlueprints[rowID], this.sensorConfigs[rowID]).name + for (let row = 0; row < this.sensorBlueprints.length; row++) { + const name = SensorFactory.new(this.sensorBlueprints[row], this.sensorConfigs[row]).name // Select the color for the bounding box: boxColor = 2 // red: unchanged - if (rowID == this.currentSensorRow) { + if (row == this.currentSensorRow) { boxColor = 5 // yellow: selected } - else if (this.configHasChanged[rowID]) { + else if (this.configHasChanged[row]) { boxColor = 7 // green: changed } screen.fillRect( 0, - 18 + (rowID * rowSize) - 3, + 22 + (row * rowSize) - 3, (name.length) * font.charWidth + 4, font.charHeight + 9, 16 @@ -408,7 +484,7 @@ namespace microcode { screen.fillRect( 1, - 18 + (rowID * rowSize) - 3, + 22 + (row * rowSize) - 3, (name.length) * font.charWidth + 5, font.charHeight + 6, boxColor @@ -417,30 +493,10 @@ namespace microcode { screen.print( name, headerX - 2, - 20 + (rowID * rowSize) + 1, + 24 + (row * rowSize) + 1, 15 // black ) } } - - /** - * Convert the .guiRows data into a RecordingConfig object for use by the DataRecorder - * Set the this.sensorConfigs[this.currentSensorRow] to this RecordingConfig object - */ - private setSensorConfigs(): void { - for (let sensorRow = 0; sensorRow < this.guiRows.length; sensorRow++) { - - let period: number = 0 - for (let col = 1; col < this.guiRows[0].length - 1; col++) { - period += this.guiRows[sensorRow][col].value * timeConversionTableMs[col - 1] - } - - this.sensorConfigs[sensorRow] = { - measurements: this.guiRows[sensorRow][0].value, - period, - delay: this.guiRows[sensorRow][6].value - } - } - } } } \ No newline at end of file From f749e5155738452a521d64d36a1de4e047145e8e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 29 Mar 2024 12:52:06 +0000 Subject: [PATCH 081/109] sensorFactory removal: This pattern hindered access to important sensor attributes too much; creation of sensors is now done after sensor select, the configs are loaded into the sensors via sensor.setConfig(config: RecordingConfig). Refactored code where SensorBlueprint was used to just use Sensor. Implemented beginning of event selection to recordingConfigSelection, small UI adjustments. --- liveDataViewer.ts | 5 +- pxt.json | 3 +- recordingConfigSelection.ts | 158 ++++++++++++++++++++++++------------ sensorFactory.ts | 52 ------------ sensorSelect.ts | 40 ++++----- sensors.ts | 48 ++++++----- 6 files changed, 151 insertions(+), 155 deletions(-) delete mode 100644 sensorFactory.ts diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 7524a58..d8a4d12 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -35,12 +35,11 @@ namespace microcode { /* To plot */ private sensors: Sensor[] - constructor(app: App, sensorBlueprints: SensorBlueprint[]) { + constructor(app: App, sensors: Sensor[]) { super(app, "liveDataViewer") this.color = 0 - const config: RecordingConfig = {measurements: 0, period: 0, delay: 0} - this.sensors = sensorBlueprints.map((blueprint) => SensorFactory.new(blueprint, config)) + this.sensors = sensors this.windowWidth = Screen.WIDTH this.windowHeight = Screen.HEIGHT diff --git a/pxt.json b/pxt.json index 541974e..137d01c 100644 --- a/pxt.json +++ b/pxt.json @@ -53,8 +53,7 @@ "fauxDataLogger.ts", "dataRecorder.ts", "generateGraph.ts", - "sensorEvent.ts", - "sensorFactory.ts" + "sensorEvent.ts" ], "testFiles": [], "targetVersions": { diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 02b82b0..eadaf81 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -56,27 +56,24 @@ namespace microcode { * guiRows[n] corresponds to the nth sensor; its contents will be converted into a RecordingConfig and passed to the sensor at completion. */ private guiRows: RecordingSettingsGUIColumn[][] + + // These elements can be reduced in the future: private currentSensorRow: number private currentConfigRow: number private currentWriteModeRow: number - /** - * Sensor measurement control (unique per sensor) - * Number of measurements, period, event control, etc - * - * Each sensor is granted its config upon progression from this screen, via SensorFactory.new() - * This could be improved via a Factory; where a sensor enum is passed. - * Or a builder design pattern - */ + private currentEventColumn: number + private eventConfigs: number[] + + private sensors: Sensor[] private sensorConfigs: RecordingConfig[] - private sensorBlueprints: SensorBlueprint[] /** Whether or not the user has manipulated the UI for a sensor. * Selecting a sensor, but leaving its config as default counts as 'changing' it; since the user may purposefully set it as such. */ private configHasChanged: boolean[] - constructor(app: App, sensorBlueprints: SensorBlueprint[]){ + constructor(app: App, sensors: Sensor[]){ super(app, "measurementConfigSelect") this.guiState = GUI_STATE.SELECTING_SENSOR this.writingMode = WRITE_MODE.RECORDING_SETTINGS @@ -84,10 +81,11 @@ namespace microcode { this.guiRows = [] this.sensorConfigs = [] this.configHasChanged = [] - this.sensorBlueprints = sensorBlueprints + this.sensors = sensors // Each sensor has a unique config; the user selects this using these UI elements: - for (let _ = 0; _ < this.sensorBlueprints.length; _++) { + // This does create more objects than is strictly neccessary (multiple name:), though it is not presently an issue: + for (let _ = 0; _ < this.sensors.length; _++) { this.guiRows.push([ {name: "Records", value: 20, smallDelta: 1, largeDelta: 10}, {name: "ms", value: 0, smallDelta: 1, largeDelta: 10}, @@ -106,10 +104,24 @@ namespace microcode { this.currentConfigRow = 0 this.currentWriteModeRow = 0 + this.currentEventColumn = 0 + this.eventConfigs = [0, 0] // [x: (0 -> sensorEventSymbols.length), y: (sensor.min -> sensor.max)] + //-------------- // User Control: //-------------- + // Use Microbit A button to progress: + control.onEvent(DAL.DEVICE_BUTTON_EVT_DOWN, DAL.DEVICE_ID_BUTTON_A, () => { + // Build the sensors according to their specific configuration: + this.setSensorConfigs() + this.sensors.map((sensor, index) => sensor.setRecordingConfig(this.sensorConfigs[index])) + + this.app.popScene() + this.app.pushScene(new DataRecorder(this.app, this.sensors)) + }) + + control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, @@ -122,8 +134,9 @@ namespace microcode { case GUI_STATE.SELECTING_WRITE_MODE: this.guiState = GUI_STATE.DEFAULT + this.writingMode = [WRITE_MODE.RECORDING_SETTINGS, WRITE_MODE.EVENT_SETTINGS][this.currentWriteModeRow] break; - + case GUI_STATE.DEFAULT: this.guiState = GUI_STATE.WRITING break; @@ -174,13 +187,18 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.SELECTING_SENSOR) { // Non-negative modulo: - this.currentSensorRow = (((this.currentSensorRow - 1) % this.sensorBlueprints.length) + this.sensorBlueprints.length) % this.sensorBlueprints.length + this.currentSensorRow = (((this.currentSensorRow - 1) % this.sensors.length) + this.sensors.length) % this.sensors.length } - else if (this.guiState === GUI_STATE.WRITING) { + else if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) } + + else { + // Non-negative modulo: + this.eventConfigs[0] = (((this.eventConfigs[0] - 1) % sensorEventSymbols.length) + sensorEventSymbols.length) % sensorEventSymbols.length + } } else if (this.guiState == GUI_STATE.SELECTING_WRITE_MODE) { @@ -201,13 +219,17 @@ namespace microcode { controller.down.id, () => { if (this.guiState === GUI_STATE.SELECTING_SENSOR) { - this.currentSensorRow = (this.currentSensorRow + 1) % this.sensorBlueprints.length + this.currentSensorRow = (this.currentSensorRow + 1) % this.sensors.length } else if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) } + + else { + this.eventConfigs[0] = ((this.eventConfigs[0] + 1) % sensorEventSymbols.length) + } } else if (this.guiState == GUI_STATE.SELECTING_WRITE_MODE) { @@ -229,6 +251,16 @@ namespace microcode { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) } + + else { + const maxReading: number = this.sensors[this.currentSensorRow].maximum + // Non-negative modulo: + this.eventConfigs[1] = (((this.eventConfigs[1] - 1) % maxReading) + maxReading) % maxReading + } + } + + else if (this.guiState === GUI_STATE.DEFAULT) { + this.currentEventColumn = (((this.currentEventColumn + 1) % 2) + 2) % 2 } else if (this.guiState == GUI_STATE.SELECTING_SENSOR) { @@ -250,6 +282,14 @@ namespace microcode { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) } + + else { + this.eventConfigs[1] = ((this.eventConfigs[1] + 1) % this.sensors[this.currentSensorRow].minimum) + } + } + + else if (this.guiState === GUI_STATE.DEFAULT) { + this.currentEventColumn = (this.currentEventColumn + 1) % 2 } else if (this.guiState == GUI_STATE.SELECTING_SENSOR) { @@ -260,15 +300,6 @@ namespace microcode { this.writingMode = WRITE_MODE.RECORDING_SETTINGS } } - - else if (this.guiState === GUI_STATE.DEFAULT) { - // Build the sensors according to their specific configuration: - this.setSensorConfigs() - const sensors: Sensor[] = this.sensorBlueprints.map((blueprint, index) => SensorFactory.new(blueprint, this.sensorConfigs[index])) - - this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, sensors)) - } } ) } @@ -325,7 +356,6 @@ namespace microcode { // Internal Drawing Functions: //---------------------------- - private drawWriteModeSelection() { this.currentWriteModeRow const yPosText = (Screen.HEIGHT / 3) @@ -424,46 +454,68 @@ namespace microcode { } private drawEventSelectionWindow() { - const yOffset = 18 - const rowSize = Screen.HEIGHT / (this.sensorBlueprints.length + 1) + const xOffset = 12 - // Sub-window: - // Outline: + // Window: screen.fillRect( - 74, - yOffset + ((this.currentSensorRow + 1) * rowSize) - 2, - 60, - font.charHeight + 9, - 16 + xOffset, + Screen.HALF_HEIGHT - 22, + Screen.WIDTH - 24, + 44, + 15 ) screen.fillRect( - 74, - yOffset + ((this.currentSensorRow + 1) * rowSize) - 2, - 58, - font.charHeight + 6, - 9 + xOffset, + Screen.HALF_HEIGHT - 22, + Screen.WIDTH - 24, + 40, + 3 ) - // const middleSensorRange = this.sensorBlueprints[this.selectedSensorIndex].maximum - Math.abs(this.sensorBlueprints[this.selectedSensorIndex].minimum) - + // This temporary object creation is very inefficient; it can be rectified in the future by creating the sensors and then loading their configs at the end: + const sensor: Sensor = this.sensors[this.currentSensorRow] + const middleSensorRange: string = (sensor.maximum - Math.abs(sensor.minimum)).toString() + + // Box around selected element: + if (this.currentEventColumn == 0) { + for (let borderOffset = 0; borderOffset < 2; borderOffset) { + screen.drawRect( + xOffset + 6 + (sensor.name.length * font.charWidth) + 9 - borderOffset, + Screen.HALF_HEIGHT - 7 - borderOffset, + (sensorEventSymbols[this.eventConfigs[0]].length * font.charWidth) + 5 + borderOffset, + 12 + borderOffset, + 6 + ) + } + } + else { + for (let borderOffset = 0; borderOffset < 2; borderOffset) { + screen.drawRect( + xOffset + 6 + (sensor.name.length * font.charWidth) + 9 + (middleSensorRange.length * font.charWidth) + 7 - borderOffset, + Screen.HALF_HEIGHT - 7 - borderOffset, + (sensor.maximum.toString().length * font.charWidth) + 5 + borderOffset, + 12 + borderOffset, + 6 + ) + } + } + // Write Event expression: screen.print( - sensorEventSymbols[0] + " 0", // + middleSensorRange.toString(), - 80, - yOffset + ((this.currentSensorRow + 1) * rowSize) - 1, + sensor.name + " " + sensorEventSymbols[this.eventConfigs[0]] + " " + middleSensorRange, + xOffset * 2, + Screen.HALF_HEIGHT - 5, 15 // black ) } private drawSensorSelection() { const headerX = 4 - const rowSize = Screen.HEIGHT / (this.sensorBlueprints.length + 1) + const rowSize = Screen.HEIGHT / (this.sensors.length + 1) let boxColor = 2 - for (let row = 0; row < this.sensorBlueprints.length; row++) { - const name = SensorFactory.new(this.sensorBlueprints[row], this.sensorConfigs[row]).name - + for (let row = 0; row < this.sensors.length; row++) { // Select the color for the bounding box: boxColor = 2 // red: unchanged if (row == this.currentSensorRow) { @@ -477,7 +529,7 @@ namespace microcode { screen.fillRect( 0, 22 + (row * rowSize) - 3, - (name.length) * font.charWidth + 4, + (this.sensors[row].name.length) * font.charWidth + 4, font.charHeight + 9, 16 ) @@ -485,15 +537,15 @@ namespace microcode { screen.fillRect( 1, 22 + (row * rowSize) - 3, - (name.length) * font.charWidth + 5, + (this.sensors[this.currentSensorRow].name.length) * font.charWidth + 5, font.charHeight + 6, boxColor ) screen.print( - name, + this.sensors[this.currentSensorRow].name, headerX - 2, - 24 + (row * rowSize) + 1, + 24 + (row * rowSize) - 1, 15 // black ) } diff --git a/sensorFactory.ts b/sensorFactory.ts deleted file mode 100644 index d9b4d65..0000000 --- a/sensorFactory.ts +++ /dev/null @@ -1,52 +0,0 @@ -namespace microcode { - export enum SensorID { - Light, - Temperature, - Accelerometer, - Pin, - Magnet, - Rotation, - LogoPress, - CompassHeading, - Volume, - ButtonPress - } - - - /** - * Specification of the sensor and its parameters. - * Passed into the SensorFactory along with the sensor's recording config. - */ - export class SensorBlueprint { - public readonly id: SensorID - public readonly dim?: Dimension - public readonly pin?: TouchPin - public readonly rot?: Rotation - - constructor(settings: {id: SensorID, dim?: Dimension, pin?: TouchPin, rot?: Rotation}) { - this.id = settings.id - this.dim = settings.dim - this.pin = settings.pin - this.rot = settings.rot - } - } - - export class SensorFactory { - public static new(blueprint: SensorBlueprint, config: RecordingConfig): Sensor { - switch (blueprint.id) { - case SensorID.Light: return new LightSensor(config) - case SensorID.Temperature: return new TemperatureSensor(config) - case SensorID.Accelerometer: return new AccelerometerSensor(blueprint.dim, config) - case SensorID.Pin: return new PinSensor(blueprint.pin, config) - case SensorID.Magnet: return new MagnetSensor(blueprint.dim, config) - case SensorID.Rotation: return new RotationSensor(blueprint.rot, config) - case SensorID.LogoPress: return new LogoPressSensor(config) - case SensorID.CompassHeading: return new CompassHeadingSensor(config) - case SensorID.Volume: return new VolumeSensor(config) - case SensorID.ButtonPress: return new ButtonPressSensor(config) - - default: return new LightSensor(config); - } - } - } -} \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index 2c8f1fd..c76426a 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -7,13 +7,13 @@ namespace microcode { */ export class SensorSelect extends CursorSceneWithPriorPage { private btns: Button[] - private selectedSensorBlueprints: SensorBlueprint[] + private selectedSensors: Sensor[] private nextSceneEnum: CursorSceneEnum constructor(app: App, nextSceneEnum: CursorSceneEnum) { super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) this.btns = [] - this.selectedSensorBlueprints = [] + this.selectedSensors = [] this.nextSceneEnum = nextSceneEnum } @@ -28,7 +28,7 @@ namespace microcode { x: -60, y: -40, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Accelerometer, dim: Dimension.X})) + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) }, dynamicBoundaryColorsOn: true, })) @@ -41,7 +41,7 @@ namespace microcode { x: -30, y: -40, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Accelerometer, dim: Dimension.Y})) + this.selectedSensors.push(new AccelerometerSensor(Dimension.Y)) }, dynamicBoundaryColorsOn: true, })) @@ -54,7 +54,7 @@ namespace microcode { x: 0, y: -40, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Accelerometer, dim: Dimension.Z})) + this.selectedSensors.push(new AccelerometerSensor(Dimension.Z)) }, dynamicBoundaryColorsOn: true, })) @@ -67,7 +67,7 @@ namespace microcode { x: 30, y: -40, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Rotation, rot: Rotation.Pitch})) + this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) }, dynamicBoundaryColorsOn: true, })) @@ -80,7 +80,7 @@ namespace microcode { x: 60, y: -40, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Rotation, rot: Rotation.Roll})) + this.selectedSensors.push(new RotationSensor(Rotation.Roll)) }, dynamicBoundaryColorsOn: true, })) @@ -95,7 +95,7 @@ namespace microcode { x: -60, y: -11, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Pin, pin: TouchPin.P0})) + this.selectedSensors.push(new PinSensor(TouchPin.P0)) }, dynamicBoundaryColorsOn: true, })) @@ -108,7 +108,7 @@ namespace microcode { x: -30, y: -11, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Pin, pin: TouchPin.P0})) + this.selectedSensors.push(new PinSensor(TouchPin.P1)) }, dynamicBoundaryColorsOn: true, })) @@ -122,7 +122,7 @@ namespace microcode { x: 0, y: -11, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Pin, pin: TouchPin.P0})) + this.selectedSensors.push(new PinSensor(TouchPin.P2)) }, dynamicBoundaryColorsOn: true, })) @@ -136,7 +136,7 @@ namespace microcode { x: 30, y: -11, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Light})) + this.selectedSensors.push(new LightSensor()) }, dynamicBoundaryColorsOn: true, })) @@ -149,7 +149,7 @@ namespace microcode { x: 60, y: -11, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Temperature})) + this.selectedSensors.push(new TemperatureSensor()) }, dynamicBoundaryColorsOn: true, })) @@ -164,7 +164,7 @@ namespace microcode { x: -60, y: 18, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Magnet, dim: Dimension.X})) + this.selectedSensors.push(new MagnetSensor(Dimension.X)) }, dynamicBoundaryColorsOn: true, })) @@ -177,7 +177,7 @@ namespace microcode { x: -30, y: 18, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.LogoPress})) + this.selectedSensors.push(new LogoPressSensor()) }, dynamicBoundaryColorsOn: true, })) @@ -190,7 +190,7 @@ namespace microcode { x: 0, y: 18, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.Volume})) + this.selectedSensors.push(new VolumeSensor()) }, dynamicBoundaryColorsOn: true, })) @@ -203,7 +203,7 @@ namespace microcode { x: 30, y: 18, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.CompassHeading})) + this.selectedSensors.push(new CompassHeadingSensor()) }, dynamicBoundaryColorsOn: true, })) @@ -216,7 +216,7 @@ namespace microcode { x: 60, y: 18, onClick: () => { - this.selectedSensorBlueprints.push(new SensorBlueprint({id: SensorID.ButtonPress})) + this.selectedSensors.push(new ButtonPressSensor()) }, dynamicBoundaryColorsOn: true, })) @@ -231,17 +231,17 @@ namespace microcode { x: 60, y: 44, onClick: () => { - if (this.selectedSensorBlueprints.length === 0) { + if (this.selectedSensors.length === 0) { return } this.app.popScene() if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, this.selectedSensorBlueprints)) + this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) } else { - this.app.pushScene(new RecordingConfigSelection(app, this.selectedSensorBlueprints)) + this.app.pushScene(new RecordingConfigSelection(app, this.selectedSensors)) } } })) diff --git a/sensors.ts b/sensors.ts index d15b949..6fad41b 100644 --- a/sensors.ts +++ b/sensors.ts @@ -44,6 +44,10 @@ namespace microcode { this.config = config } + setRecordingConfig(config: RecordingConfig) { + this.config = config + } + getBufferSize(): number {return this.dataBuffer.length} getReading(): number {return this.sensorFn()} getNthReading(n: number): number {return this.dataBuffer[n]} @@ -113,8 +117,8 @@ namespace microcode { * Onboard Light Sensor; ranged between 0 and 255 */ export class LightSensor extends Sensor { - constructor(config: RecordingConfig) { - super(function () {return input.lightLevel()}, "Light", 0, 255, "led_light_sensor", "led_light_sensor", config) + constructor() { + super(function () {return input.lightLevel()}, "Light", 0, 255, "led_light_sensor", "led_light_sensor") } } @@ -122,8 +126,8 @@ namespace microcode { * Onboard Thermometer; ranged between 0 and 100 */ export class TemperatureSensor extends Sensor { - constructor(config: RecordingConfig) { - super(function () {return input.temperature()}, "Temp.", 0, 100, "thermometer", "thermometer", config) + constructor() { + super(function () {return input.temperature()}, "Temp.", 0, 100, "thermometer", "thermometer") } } @@ -132,14 +136,13 @@ namespace microcode { * Onboard Accelerometer for X, Y, Z dimensions; ranged between -1023, 1023 */ export class AccelerometerSensor extends Sensor { - constructor(dim: Dimension, config: RecordingConfig) { + constructor(dim: Dimension) { super(function () {return input.acceleration(dim)}, "Accel. " + ['X', 'Y', 'Z'][dim], -1023, 1023, "accelerometer", "accelerometer " + + ['X', 'Y', 'Z'][dim], - config ) } } @@ -148,7 +151,7 @@ namespace microcode { * Onboard Touch Pin Sensor for TouchPin 0, 1, 2; ranged between 0 and 1 */ export class PinSensor extends Sensor { - constructor(pin: TouchPin, config: RecordingConfig) { + constructor(pin: TouchPin) { super(function () { let res: number = 0 input.onPinPressed(pin, function () { @@ -160,8 +163,7 @@ namespace microcode { 0, 1, "pin_" + pin.toString(), - "Pin " + pin.toString(), - config + "Pin " + pin.toString() ) } } @@ -173,14 +175,13 @@ namespace microcode { * MIN & MAX RANGE UNVERIFIED */ export class MagnetSensor extends Sensor { - constructor(dim: Dimension, config: RecordingConfig) { + constructor(dim: Dimension) { super(function() {return input.magneticForce(dim)}, "Magnet " + dim.toString(), 0, 1, "magnet", - "S10", - config + "Magnet" ) } } @@ -192,14 +193,14 @@ namespace microcode { * MIN & MAX RANGE UNVERIFIED */ export class RotationSensor extends Sensor { - constructor(rot: Rotation, config: RecordingConfig) { + constructor(rot: Rotation) { let name: string = "Pitch" if (rot === Rotation.Roll) { name = "Roll" } - super(function () {return input.rotation(rot)}, name, 0, 100, "right_turn", name, config) + super(function () {return input.rotation(rot)}, name, 0, 100, "right_turn", name) } } @@ -210,15 +211,14 @@ namespace microcode { * sensorMaxReading may change in future */ export class LogoPressSensor extends Sensor { - constructor(config: RecordingConfig) { + constructor() { super( function () {if(input.logoIsPressed()) {return 1} return 0}, "Logo Pressed", 0, 1, "finger_press", - "Logo Press", - config + "Logo Press" ) } } @@ -228,15 +228,14 @@ namespace microcode { * Ranged between 0 and 360 degrees */ export class CompassHeadingSensor extends Sensor { - constructor(config: RecordingConfig) { + constructor() { super( function () {return input.compassHeading()}, "Compass", 0, 360, "compass", - "Compass", - config + "Compass" ) } } @@ -246,15 +245,14 @@ namespace microcode { * Ranged between 0 and 255 */ export class VolumeSensor extends Sensor { - constructor(config: RecordingConfig) { + constructor() { super( function () {return input.soundLevel()}, "Volume", 0, 255, "speaker", - "Volume", - config + "Volume" ) } } @@ -264,8 +262,8 @@ namespace microcode { * Need to be transformed into an event based system */ export class ButtonPressSensor extends Sensor { - constructor(config: RecordingConfig) { - super(function () {return 1}, "Button ", 0, 1, "tile_button_a", "F3", config) + constructor() { + super(function () {return 1}, "Button ", 0, 1, "tile_button_a", "F3") control.onEvent(DAL.DEVICE_BUTTON_EVT_UP, DAL.DEVICE_ID_BUTTON_A, () => { return 1 From f3372a3a82918e147b2b68397e5d3216e339ff86 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 29 Mar 2024 13:09:05 +0000 Subject: [PATCH 082/109] recordingConfigSelection: bug fix for sensor drawing printing same value. --- recordingConfigSelection.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index eadaf81..493bcf6 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -537,13 +537,13 @@ namespace microcode { screen.fillRect( 1, 22 + (row * rowSize) - 3, - (this.sensors[this.currentSensorRow].name.length) * font.charWidth + 5, + (this.sensors[row].name.length) * font.charWidth + 5, font.charHeight + 6, boxColor ) screen.print( - this.sensors[this.currentSensorRow].name, + this.sensors[row].name, headerX - 2, 24 + (row * rowSize) - 1, 15 // black From 492a43c7b55403efa641fd28ffee88cc3c308937 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Fri, 29 Mar 2024 13:38:23 +0000 Subject: [PATCH 083/109] recordingConfigSelection: Reworked so that the GUI elements used to select period, measurement quantity and delay & the smallDelta + largeDelta are only stored once. The user inputs are stored seperately within guiValues: number[][]. --- recordingConfigSelection.ts | 75 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 493bcf6..68906eb 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -25,11 +25,9 @@ namespace microcode { * The Recording Settings is a sub-window on the right-hand-side. * It consists of a list of rows that the user can manipulate to change the RecordingConfig */ - type RecordingSettingsGUIColumn = { + type RecordingConfigGUIRows = { /** The name of this recording setting (record, ms, second, minute, hour, etc) */ name: string, - /** The current value that the user has selected for this row (minute = 2); all of (ms, second, minute, hour, day) will be converted into ms at the end */ - value: number, /** How much the value should increment or decrement by when the user selects this element and presses up or down (typically 1) */ smallDelta: number, /** How much the value should increment or decrement by when the user selects this element and presses left or right (typically 5 or 10) */ @@ -52,10 +50,8 @@ namespace microcode { private guiState: GUI_STATE private writingMode: WRITE_MODE - /** Each sensor may have a unique configuration, the UI should track the state of each configuration. This grid is responsible for that. - * guiRows[n] corresponds to the nth sensor; its contents will be converted into a RecordingConfig and passed to the sensor at completion. - */ - private guiRows: RecordingSettingsGUIColumn[][] + private guiRows: RecordingConfigGUIRows[] + private guiValues: number[][] // These elements can be reduced in the future: private currentSensorRow: number @@ -78,24 +74,32 @@ namespace microcode { this.guiState = GUI_STATE.SELECTING_SENSOR this.writingMode = WRITE_MODE.RECORDING_SETTINGS - this.guiRows = [] + this.guiRows = [ + {name: "Records", smallDelta: 1, largeDelta: 10}, + {name: "ms", smallDelta: 1, largeDelta: 10}, + {name: "Seconds", smallDelta: 1, largeDelta: 5}, + {name: "Minutes", smallDelta: 1, largeDelta: 5}, + {name: "Hours", smallDelta: 1, largeDelta: 5}, + {name: "Days", smallDelta: 1, largeDelta: 5}, + {name: "Delay", smallDelta: 1, largeDelta: 5}, + ] + + this.guiValues = [] this.sensorConfigs = [] this.configHasChanged = [] this.sensors = sensors - // Each sensor has a unique config; the user selects this using these UI elements: - // This does create more objects than is strictly neccessary (multiple name:), though it is not presently an issue: for (let _ = 0; _ < this.sensors.length; _++) { - this.guiRows.push([ - {name: "Records", value: 20, smallDelta: 1, largeDelta: 10}, - {name: "ms", value: 0, smallDelta: 1, largeDelta: 10}, - {name: "Seconds", value: 1, smallDelta: 1, largeDelta: 5}, - {name: "Minutes", value: 0, smallDelta: 1, largeDelta: 5}, - {name: "Hours", value: 0, smallDelta: 1, largeDelta: 5}, - {name: "Days", value: 0, smallDelta: 1, largeDelta: 5}, - {name: "Delay", value: 0, smallDelta: 1, largeDelta: 5}, + // Defaults for each sensor: + this.guiValues.push([ + 10, // Records + 0, // ms + 1, // Seconds + 0, // Minutes + 0, // Hours + 0, // Days + 0 // Delay ]) - this.configHasChanged.push(false) this.sensorConfigs.push({measurements: 20, period: 1000, delay: 0}) } @@ -192,7 +196,7 @@ namespace microcode { else if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { - this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) + this.guiValues[this.currentSensorRow][this.currentConfigRow] = this.guiValues[this.currentSensorRow][this.currentConfigRow] + this.guiRows[this.currentConfigRow].smallDelta } else { @@ -208,7 +212,7 @@ namespace microcode { else { // Non-negative modulo: - const numberOfMeasurementRows = this.guiRows[0].length + const numberOfMeasurementRows = this.guiRows.length this.currentConfigRow = (((this.currentConfigRow - 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows } } @@ -224,7 +228,7 @@ namespace microcode { else if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { - this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].smallDelta, 0) + this.guiValues[this.currentSensorRow][this.currentConfigRow] = Math.max(this.guiValues[this.currentSensorRow][this.currentConfigRow] - this.guiRows[this.currentConfigRow].smallDelta, 0) } else { @@ -237,7 +241,7 @@ namespace microcode { } else { - const numberOfMeasurementRows = this.guiRows[0].length + const numberOfMeasurementRows = this.guiRows.length this.currentConfigRow = (((this.currentConfigRow + 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows } } @@ -249,7 +253,7 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { - this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value - this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) + this.guiValues[this.currentSensorRow][this.currentConfigRow] = Math.max(this.guiValues[this.currentSensorRow][this.currentConfigRow] - this.guiRows[this.currentConfigRow].largeDelta, 0) } else { @@ -280,7 +284,7 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { - this.guiRows[this.currentSensorRow][this.currentConfigRow].value = Math.max(this.guiRows[this.currentSensorRow][this.currentConfigRow].value + this.guiRows[this.currentSensorRow][this.currentConfigRow].largeDelta, 0) + this.guiValues[this.currentSensorRow][this.currentConfigRow] = this.guiValues[this.currentSensorRow][this.currentConfigRow] + this.guiRows[this.currentConfigRow].largeDelta } else { @@ -310,17 +314,16 @@ namespace microcode { * Set the this.sensorConfigs[this.currentSensorRow] to this RecordingConfig object */ private setSensorConfigs(): void { - for (let sensorRow = 0; sensorRow < this.guiRows.length; sensorRow++) { - + for (let sensorRow = 0; sensorRow < this.sensors.length; sensorRow++) { let period: number = 0 - for (let col = 1; col < this.guiRows[0].length - 1; col++) { - period += this.guiRows[sensorRow][col].value * TIME_CONVERSION_TABLE[col - 1] + for (let col = 1; col < this.guiRows.length - 1; col++) { + period += this.guiValues[sensorRow][col] * TIME_CONVERSION_TABLE[col - 1] } this.sensorConfigs[sensorRow] = { - measurements: this.guiRows[sensorRow][0].value, + measurements: this.guiValues[sensorRow][0], period, - delay: this.guiRows[sensorRow][6].value + delay: this.guiValues[sensorRow][6] } } } @@ -396,8 +399,8 @@ namespace microcode { private drawConfigSelectionWindow() { const optionX = Screen.WIDTH - 17 - const headerX = optionX - (font.charWidth * this.guiRows[this.currentSensorRow][0].name.length) - 6 - const rowSize = Screen.HEIGHT / (this.guiRows[0].length + 1) + const headerX = optionX - (font.charWidth * this.guiRows[0].name.length) - 6 + const rowSize = Screen.HEIGHT / (this.guiRows.length + 1) // Sub-window: // Outline: @@ -435,16 +438,16 @@ namespace microcode { ) let rowOffset = 0; - for (let configRow = 0; configRow < this.guiRows[0].length; configRow++) { + for (let configRow = 0; configRow < this.guiRows.length; configRow++) { screen.print( - this.guiRows[this.currentSensorRow][configRow].name, + this.guiRows[configRow].name, headerX - 1, 18 + rowOffset, 15 // Black ) screen.print( - this.guiRows[this.currentSensorRow][configRow].value.toString(), + this.guiValues[this.currentSensorRow][configRow].toString(), optionX - 3, 18 + rowOffset, 15 // Black From 90df18a0107b9ac9d92fb98dfd164311899fff36 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 31 Mar 2024 14:19:26 +0100 Subject: [PATCH 084/109] recordingConfigSelection: added tutorial text, small UI adjustments. --- recordingConfigSelection.ts | 102 +++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 6 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 68906eb..28f8081 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -5,6 +5,7 @@ namespace microcode { * DEFAULT: User is not changing any settings & PROMPT_SHARED_CONFIG has occured. */ const enum GUI_STATE { + TUTORIAL, SELECTING_SENSOR, SELECTING_WRITE_MODE, WRITING, @@ -39,6 +40,7 @@ namespace microcode { * The (ms, second, minute, hour, day) ui elements kept in RecordingSettingsGUIColumn.value are converted into ms using this: */ const TIME_CONVERSION_TABLE: number[] = [1, 1000, 60000, 3600000, 86400000] + const MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN: number = 3 /** * Responsible for allowing the user to select the specific recording configurations for each passed sensor. @@ -64,6 +66,9 @@ namespace microcode { private sensors: Sensor[] private sensorConfigs: RecordingConfig[] + private tutorialText: string[] + private tutorialTextIndexOffset: number + /** Whether or not the user has manipulated the UI for a sensor. * Selecting a sensor, but leaving its config as default counts as 'changing' it; since the user may purposefully set it as such. */ @@ -71,7 +76,7 @@ namespace microcode { constructor(app: App, sensors: Sensor[]){ super(app, "measurementConfigSelect") - this.guiState = GUI_STATE.SELECTING_SENSOR + this.guiState = GUI_STATE.TUTORIAL this.writingMode = WRITE_MODE.RECORDING_SETTINGS this.guiRows = [ @@ -111,6 +116,18 @@ namespace microcode { this.currentEventColumn = 0 this.eventConfigs = [0, 0] // [x: (0 -> sensorEventSymbols.length), y: (sensor.min -> sensor.max)] + this.tutorialText = [ + "This screen is where\nyou configure your\nsensors.", + "Use A & B to move\nthrough menus.", + "Use UP and DOWN to\nscroll through\nmenus. Try it now!", + "The current sensor\nwill be yellow Press\nA to select it!", + "Configured sensors\nare green.", + "Unconfigured sensors\nare red.", + "Press A to configure\nsome sensors!", + ] + this.tutorialTextIndexOffset = 0 + + //-------------- // User Control: //-------------- @@ -131,6 +148,10 @@ namespace microcode { controller.A.id, () => { switch (this.guiState) { + case GUI_STATE.TUTORIAL: + this.guiState = GUI_STATE.SELECTING_SENSOR + break; + case GUI_STATE.SELECTING_SENSOR: this.guiState = GUI_STATE.SELECTING_WRITE_MODE this.configHasChanged[this.currentSensorRow] = true @@ -161,9 +182,13 @@ namespace microcode { controller.B.id, () => { switch (this.guiState) { - case GUI_STATE.SELECTING_SENSOR: + case GUI_STATE.TUTORIAL: this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + break; + + case GUI_STATE.SELECTING_SENSOR: + this.guiState = GUI_STATE.TUTORIAL break; case GUI_STATE.SELECTING_WRITE_MODE: @@ -189,7 +214,10 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.up.id, () => { - if (this.guiState === GUI_STATE.SELECTING_SENSOR) { + if (this.guiState === GUI_STATE.TUTORIAL) { + this.tutorialTextIndexOffset = Math.max(this.tutorialTextIndexOffset - 1, 0) + } + else if (this.guiState === GUI_STATE.SELECTING_SENSOR) { // Non-negative modulo: this.currentSensorRow = (((this.currentSensorRow - 1) % this.sensors.length) + this.sensors.length) % this.sensors.length } @@ -222,7 +250,11 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.down.id, () => { - if (this.guiState === GUI_STATE.SELECTING_SENSOR) { + if (this.guiState === GUI_STATE.TUTORIAL) { + this.tutorialTextIndexOffset = Math.min(this.tutorialTextIndexOffset + 1, this.tutorialText.length - MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN) + } + + else if (this.guiState === GUI_STATE.SELECTING_SENSOR) { this.currentSensorRow = (this.currentSensorRow + 1) % this.sensors.length } @@ -340,6 +372,10 @@ namespace microcode { screen.printCenter("Recording Settings", 2) this.drawSensorSelection() + if (this.guiState == GUI_STATE.TUTORIAL) { + this.drawTutorialWindow() + } + if (this.guiState == GUI_STATE.WRITING || this.guiState == GUI_STATE.DEFAULT) { if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { this.drawConfigSelectionWindow() @@ -351,7 +387,7 @@ namespace microcode { else if (this.guiState == GUI_STATE.SELECTING_WRITE_MODE) { this.drawWriteModeSelection() - } + } } @@ -456,6 +492,60 @@ namespace microcode { } } + private drawTutorialWindow() { + const headerX = Screen.HALF_WIDTH + const headerY = Screen.HALF_HEIGHT - 60 + 8 + + // Sub-window: + // Outline: + screen.fillRect( + Screen.HALF_WIDTH - 70, + Screen.HALF_HEIGHT - 60, + 140, + 120, + 15 // Black + ) + + screen.fillRect( + Screen.HALF_WIDTH - 70 + 3, + Screen.HALF_HEIGHT - 60 + 3, + 140 - 6, + 120 - 6, + 3 // Pink + ) + + const tutorialTextLength = ("Tutorial".length * font.charWidth) + + screen.print( + "Tutorial", + headerX - (tutorialTextLength / 2), + headerY, + 15 // Black + ) + + // Underline the title: + screen.fillRect( + headerX - (tutorialTextLength / 2) - 4, + Screen.HALF_HEIGHT - 60 + 17, + tutorialTextLength + 4, + 1, + 15 // Black + ) + + let tutorialTextYOffset = 25 + const limit = Math.min(this.tutorialText.length, this.tutorialTextIndexOffset + MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN) + this.tutorialText.slice(this.tutorialTextIndexOffset, limit).forEach((text) => { + screen.print( + text, + headerX - 55, + tutorialTextYOffset, + 15 // Black + ) + + tutorialTextYOffset += (text.split("\n").length * font.charHeight * 1.33) + 3 // .match() and matchAll() are not present; .split() is memory inefficient + }) + } + private drawEventSelectionWindow() { const xOffset = 12 From 527b8bc75818f0b41953b9b51d4609d80183afb2 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 31 Mar 2024 14:26:46 +0100 Subject: [PATCH 085/109] recordingConfigSelection: bulletpoints, documentation --- recordingConfigSelection.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 28f8081..db9d815 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -56,6 +56,7 @@ namespace microcode { private guiValues: number[][] // These elements can be reduced in the future: + // Better to complete the UI features, then reduce. Reduction to occur prior to the start of prototype 12 private currentSensorRow: number private currentConfigRow: number private currentWriteModeRow: number @@ -481,7 +482,7 @@ namespace microcode { 18 + rowOffset, 15 // Black ) - + screen.print( this.guiValues[this.currentSensorRow][configRow].toString(), optionX - 3, @@ -541,6 +542,14 @@ namespace microcode { tutorialTextYOffset, 15 // Black ) + + // Bullet point: + screen.fillCircle( + headerX - 61, + tutorialTextYOffset + 4, + 2, + 15 // Black + ) tutorialTextYOffset += (text.split("\n").length * font.charHeight * 1.33) + 3 // .match() and matchAll() are not present; .split() is memory inefficient }) From 43b7283d7f2cd135d9a918b1208871edd5db9013 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Mon, 1 Apr 2024 22:33:45 +0100 Subject: [PATCH 086/109] recordingConfigSelection: added coloured keywords to the tooltips, bullet pointing. --- recordingConfigSelection.ts | 84 ++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index db9d815..01ecb3d 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -42,6 +42,13 @@ namespace microcode { const TIME_CONVERSION_TABLE: number[] = [1, 1000, 60000, 3600000, 86400000] const MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN: number = 3 + + type TutorialTip = { + text: string, + keywords?: string[], + keywordColors?: number[], + } + /** * Responsible for allowing the user to select the specific recording configurations for each passed sensor. * The user may also choose to select an event for each sensor. @@ -67,7 +74,7 @@ namespace microcode { private sensors: Sensor[] private sensorConfigs: RecordingConfig[] - private tutorialText: string[] + private tutorialTextTips: TutorialTip[] private tutorialTextIndexOffset: number /** Whether or not the user has manipulated the UI for a sensor. @@ -117,14 +124,16 @@ namespace microcode { this.currentEventColumn = 0 this.eventConfigs = [0, 0] // [x: (0 -> sensorEventSymbols.length), y: (sensor.min -> sensor.max)] - this.tutorialText = [ - "This screen is where\nyou configure your\nsensors.", - "Use A & B to move\nthrough menus.", - "Use UP and DOWN to\nscroll through\nmenus. Try it now!", - "The current sensor\nwill be yellow Press\nA to select it!", - "Configured sensors\nare green.", - "Unconfigured sensors\nare red.", - "Press A to configure\nsome sensors!", + + // Optional keyword colouring: + this.tutorialTextTips = [ + {text: "This screen is where\nyou configure your\nsensors."}, + {text: "Use A & B to move\nthrough menus.", keywords: [" A ", " B "], keywordColors: [6, 2]}, // Red and Blue to copy controller colours + {text: "Use UP and DOWN to\nscroll through\nmenus. Try it now!"}, + {text: "The current sensor\nwill be yellow Press\nA to select it!", keywords: [" yellow ", "A "], keywordColors: [5, 6]}, // Yellow and Red + {text: "Configured sensors\nare green.", keywords: [" green"], keywordColors: [7]}, // Green + {text: "Unconfigured sensors\nare red.", keywords: [" red"], keywordColors: [2]}, // Red + {text: "Press A to configure\nsome sensors!", keywords: [" A "], keywordColors: [6]}, // Blue ] this.tutorialTextIndexOffset = 0 @@ -252,7 +261,7 @@ namespace microcode { controller.down.id, () => { if (this.guiState === GUI_STATE.TUTORIAL) { - this.tutorialTextIndexOffset = Math.min(this.tutorialTextIndexOffset + 1, this.tutorialText.length - MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN) + this.tutorialTextIndexOffset = Math.min(this.tutorialTextIndexOffset + 1, this.tutorialTextTips.length - MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN) } else if (this.guiState === GUI_STATE.SELECTING_SENSOR) { @@ -397,7 +406,6 @@ namespace microcode { //---------------------------- private drawWriteModeSelection() { - this.currentWriteModeRow const yPosText = (Screen.HEIGHT / 3) const xPosText: number = Screen.WIDTH - 38 const text: string[] = ["Config", "Events"] @@ -516,7 +524,6 @@ namespace microcode { ) const tutorialTextLength = ("Tutorial".length * font.charWidth) - screen.print( "Tutorial", headerX - (tutorialTextLength / 2), @@ -533,16 +540,61 @@ namespace microcode { 15 // Black ) + // Print the tutorial tips as bulletpoints: + // Some tutorials have coloured keywords, the tip is printed in all black first, then the keyword is printed ontop: + let tutorialTextYOffset = 25 - const limit = Math.min(this.tutorialText.length, this.tutorialTextIndexOffset + MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN) - this.tutorialText.slice(this.tutorialTextIndexOffset, limit).forEach((text) => { + const tipsOnScreen = Math.min(this.tutorialTextTips.length, this.tutorialTextIndexOffset + MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN) + + this.tutorialTextTips.slice(this.tutorialTextIndexOffset, tipsOnScreen).forEach((tip) => { screen.print( - text, + tip.text, headerX - 55, tutorialTextYOffset, 15 // Black ) + // Keyword highlighting: + if (tip.keywords != null) { + for (let id = 0; id < tip.keywords.length; id++) { + let keyword = tip.keywords[id] + + const keywordIndex = tip.text.indexOf(keyword) + const stringBeforeKeyword = tip.text.split(keyword, keywordIndex)[0] + const newlinesBeforeKeyword = stringBeforeKeyword.split("\n", keywordIndex) + + // Find the position of the last newline before the keyword: + let newlineBeforeKeywordIndex = 0 + for (let i = keywordIndex; i > 0; i--) { + if (stringBeforeKeyword.charAt(i) == "\n") { + newlineBeforeKeywordIndex = i + break + } + } + + // Qty of characters between the last newline before the keyword is the xOffset: + let xOffset = (keywordIndex - newlineBeforeKeywordIndex) * font.charWidth + + // Account for newline char: + if (newlineBeforeKeywordIndex != 0) { + xOffset -= 1 * font.charWidth + } + + // Number of newlines before the keyword are pushed infront: + for (let _ = 0; _ < newlinesBeforeKeyword.length - 1; _++) { + keyword = "\n" + keyword + } + + // Print them directly ontop of the word in black, but with the specified colouring: + screen.print( + keyword, + headerX - 55 + xOffset, + tutorialTextYOffset, + tip.keywordColors[id], + ) + } + } + // Bullet point: screen.fillCircle( headerX - 61, @@ -551,7 +603,7 @@ namespace microcode { 15 // Black ) - tutorialTextYOffset += (text.split("\n").length * font.charHeight * 1.33) + 3 // .match() and matchAll() are not present; .split() is memory inefficient + tutorialTextYOffset += (tip.text.split("\n").length * font.charHeight * 1.33) + 3 // .match() and matchAll() are not present; .split() is memory inefficient }) } From f3b4c66021583c47e01131e5b2f45a4a22d211e6 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 2 Apr 2024 01:39:52 +0100 Subject: [PATCH 087/109] recordingConfigSelection: added confirmation screen. --- recordingConfigSelection.ts | 131 ++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 13 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 01ecb3d..26ae8ac 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -8,6 +8,7 @@ namespace microcode { TUTORIAL, SELECTING_SENSOR, SELECTING_WRITE_MODE, + CONFIRM_CONFIGURATION, WRITING, DEFAULT } @@ -142,17 +143,6 @@ namespace microcode { // User Control: //-------------- - // Use Microbit A button to progress: - control.onEvent(DAL.DEVICE_BUTTON_EVT_DOWN, DAL.DEVICE_ID_BUTTON_A, () => { - // Build the sensors according to their specific configuration: - this.setSensorConfigs() - this.sensors.map((sensor, index) => sensor.setRecordingConfig(this.sensorConfigs[index])) - - this.app.popScene() - this.app.pushScene(new DataRecorder(this.app, this.sensors)) - }) - - control.onEvent( ControllerButtonEvent.Pressed, controller.A.id, @@ -171,7 +161,16 @@ namespace microcode { this.guiState = GUI_STATE.DEFAULT this.writingMode = [WRITE_MODE.RECORDING_SETTINGS, WRITE_MODE.EVENT_SETTINGS][this.currentWriteModeRow] break; - + + case GUI_STATE.CONFIRM_CONFIGURATION: + // Build the sensors according to their specific configuration: + this.setSensorConfigs() + this.sensors.map((sensor, index) => sensor.setRecordingConfig(this.sensorConfigs[index])) + + this.app.popScene() + this.app.pushScene(new DataRecorder(this.app, this.sensors)) + break; + case GUI_STATE.DEFAULT: this.guiState = GUI_STATE.WRITING break; @@ -198,10 +197,23 @@ namespace microcode { break; case GUI_STATE.SELECTING_SENSOR: + // Upon entering check if all sensors are set: set the gui to allow the user to confirm their selection if so: this.guiState = GUI_STATE.TUTORIAL break; case GUI_STATE.SELECTING_WRITE_MODE: + for (let i = 0; i < this.configHasChanged.length; i++) { + if (this.configHasChanged[i]) { + this.guiState = GUI_STATE.CONFIRM_CONFIGURATION + } + else { + this.guiState = GUI_STATE.SELECTING_SENSOR + break; + } + } + break; + + case GUI_STATE.CONFIRM_CONFIGURATION: this.guiState = GUI_STATE.SELECTING_SENSOR break; @@ -386,7 +398,11 @@ namespace microcode { this.drawTutorialWindow() } - if (this.guiState == GUI_STATE.WRITING || this.guiState == GUI_STATE.DEFAULT) { + else if (this.guiState == GUI_STATE.CONFIRM_CONFIGURATION) { + this.drawConfirmationWindow() + } + + else if (this.guiState == GUI_STATE.WRITING || this.guiState == GUI_STATE.DEFAULT) { if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { this.drawConfigSelectionWindow() } @@ -501,6 +517,95 @@ namespace microcode { } } + private drawConfirmationWindow() { + const headerX = Screen.HALF_WIDTH + + // Sub-window: + // Outline: + screen.fillRect( + Screen.HALF_WIDTH - 60, + Screen.HALF_HEIGHT - 50, + 120, + 100, + 15 // Black + ) + + screen.fillRect( + Screen.HALF_WIDTH - 60 + 3, + Screen.HALF_HEIGHT - 50 + 3, + 120 - 6, + 100 - 6, + 4 // Orange + ) + + const tutorialTextLength = ("Confirm Settings?".length * font.charWidth) + screen.print( + "Confirm Settings?", + headerX - (tutorialTextLength / 2), + Screen.HALF_HEIGHT - 60 + 18, + 15 // Black + ) + + // Underline the title: + screen.fillRect( + headerX - (tutorialTextLength / 2) - 2, + Screen.HALF_HEIGHT - 60 + 27, + tutorialTextLength + 2, + 2, + 15 // Black + ) + + // A & B Options: + + // Blue Yes Button: + screen.fillRect( + Screen.HALF_WIDTH - 34, + Screen.HALF_HEIGHT + 13, + 13, + 12, + 6 // Blue + ) + + screen.print( + "A", + Screen.HALF_WIDTH - 30, + Screen.HALF_HEIGHT + 15, + 1, + simage.font8 + ) + + screen.print( + "Done", + Screen.HALF_WIDTH - 39, + Screen.HALF_HEIGHT + 27, + 1 + ) + + // Red No Button: + screen.fillRect( + Screen.HALF_WIDTH + 26, + Screen.HALF_HEIGHT + 13, + 13, + 12, + 2 // Red + ) + + screen.print( + "B", + Screen.HALF_WIDTH + 30, + Screen.HALF_HEIGHT + 15, + 1, + simage.font8 + ) + + screen.print( + "Back", + Screen.HALF_WIDTH + 21, + Screen.HALF_HEIGHT + 27, + 1 + ) + } + private drawTutorialWindow() { const headerX = Screen.HALF_WIDTH const headerY = Screen.HALF_HEIGHT - 60 + 8 From 88d3b61dbc79d4ec3bf76d11a3ec58084287de66 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:24:07 +0100 Subject: [PATCH 088/109] tabularDataViewer: fixed scrolling bug, fixed incorrect filter selection, made the last column always expand to the rest of the screen width. --- tabularDataViewer.ts | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index 3907ab2..5268e7f 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -71,12 +71,12 @@ namespace microcode { controller.up.id, () => { if (this.guiState === DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW) { - if (this.currentRowIndex <= 1) { - this.yScrollOffset = Math.max(this.yScrollOffset - 1, 0) + if (this.currentRowIndex > 1) { + this.currentRowIndex = Math.max(this.currentRowIndex - 1, 1) } else { - this.currentRowIndex = Math.max(this.currentRowIndex - 1, 1) + this.yScrollOffset = Math.max(this.yScrollOffset - 1, 0) } } } @@ -93,12 +93,13 @@ namespace microcode { } else if (this.guiState === DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW) { - if (this.currentRowIndex + 1 >= Math.min(FauxDataLogger.numberOfRows, TABULAR_MAX_ROWS)) { - this.yScrollOffset += 1 + const limit = Math.min(FauxDataLogger.numberOfRows - 1, TABULAR_MAX_ROWS - 1) + if (this.currentRowIndex < limit) { + this.currentRowIndex = Math.min(this.currentRowIndex + 1, FauxDataLogger.numberOfRows - 1) } - else { - this.currentRowIndex = Math.min(this.currentRowIndex + 1, FauxDataLogger.numberOfRows) + else if (this.currentRowIndex + this.yScrollOffset < FauxDataLogger.numberOfRows - 1) { + this.yScrollOffset = Math.min(this.yScrollOffset + 1, FauxDataLogger.numberOfRows - 1) } } } @@ -116,7 +117,7 @@ namespace microcode { ControllerButtonEvent.Pressed, controller.right.id, () => { - if (this.xScrollOffset + TABULAR_MAX_COLS < FauxDataLogger.headers.length + 1) { + if (this.xScrollOffset + TABULAR_MAX_COLS < FauxDataLogger.headers.length) { this.xScrollOffset += 1 } } @@ -156,10 +157,17 @@ namespace microcode { drawGridOfVariableColSize(colBufferSizes: number[], rowBufferSize: number) { let cumulativeColOffset = 0 - colBufferSizes.forEach(function(headerLen) { - cumulativeColOffset += headerLen + // colBufferSizes.forEach(function(headerLen) { + for (let col = 0; col < colBufferSizes.length; col++) { + // The last column should use all remaining space, if it is lesser than that remaining space: + if (col == colBufferSizes.length - 1 && colBufferSizes[col] < cumulativeColOffset) { + cumulativeColOffset += Screen.WIDTH - cumulativeColOffset + } + else { + cumulativeColOffset += colBufferSizes[col] + } - if (cumulativeColOffset < Screen.WIDTH) { + if (cumulativeColOffset <= Screen.WIDTH) { Screen.drawLine( Screen.LEFT_EDGE + cumulativeColOffset, Screen.TOP_EDGE, @@ -168,7 +176,7 @@ namespace microcode { 0x0 ) } - }) + } for (let rowOffset = 0; rowOffset <= Screen.HEIGHT; rowOffset+=rowBufferSize) { Screen.drawLine( @@ -233,7 +241,7 @@ namespace microcode { const filteredRowBufferSize = Screen.HEIGHT / Math.min(FauxDataLogger.numberOfRows / FauxDataLogger.sensors.length, TABULAR_MAX_ROWS) this.drawGridOfVariableColSize(FauxDataLogger.headerStringLengths.slice(this.xScrollOffset), filteredRowBufferSize) - const filteredSensor: string = FauxDataLogger.entries[this.currentRowIndex].data[0]; + const filteredSensor: string = FauxDataLogger.entries[this.currentRowIndex + this.yScrollOffset].data[0]; let filteredData: string[][] = [] FauxDataLogger.entries.forEach((entry) => { From db06990b2b32a756261435b45aa5965cf4e20ee9 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:38:33 +0100 Subject: [PATCH 089/109] recordingConfigSelection: event configuration - ability to modif number of events recorded. --- recordingConfigSelection.ts | 261 +++++++++++++++++++++++++----------- 1 file changed, 179 insertions(+), 82 deletions(-) diff --git a/recordingConfigSelection.ts b/recordingConfigSelection.ts index 26ae8ac..3c95c1a 100644 --- a/recordingConfigSelection.ts +++ b/recordingConfigSelection.ts @@ -42,6 +42,7 @@ namespace microcode { */ const TIME_CONVERSION_TABLE: number[] = [1, 1000, 60000, 3600000, 86400000] const MAX_NUMBER_OF_TUTORIAL_PARAGRAPHS_ON_SCREEN: number = 3 + const MAX_NUMBER_OF_SENSORS_ON_SCREEN: number = 6 type TutorialTip = { @@ -60,20 +61,22 @@ namespace microcode { private guiState: GUI_STATE private writingMode: WRITE_MODE - private guiRows: RecordingConfigGUIRows[] - private guiValues: number[][] + private guiRecordingConfigRows: RecordingConfigGUIRows[] + private guiRecordingConfigValues: number[][] + private guiEventConfigText: string[] + private guiEventConfigValues: number[][] + // These elements can be reduced in the future: // Better to complete the UI features, then reduce. Reduction to occur prior to the start of prototype 12 private currentSensorRow: number private currentConfigRow: number private currentWriteModeRow: number - private currentEventColumn: number - private eventConfigs: number[] private sensors: Sensor[] - private sensorConfigs: RecordingConfig[] + private sensorRecordingConfigs: RecordingConfig[] + private sensorEventConfigs: EventConfig[] private tutorialTextTips: TutorialTip[] private tutorialTextIndexOffset: number @@ -81,14 +84,15 @@ namespace microcode { /** Whether or not the user has manipulated the UI for a sensor. * Selecting a sensor, but leaving its config as default counts as 'changing' it; since the user may purposefully set it as such. */ - private configHasChanged: boolean[] + private recordingConfigHasChanged: boolean[] + private eventConfigHasChanged: boolean[] constructor(app: App, sensors: Sensor[]){ super(app, "measurementConfigSelect") this.guiState = GUI_STATE.TUTORIAL this.writingMode = WRITE_MODE.RECORDING_SETTINGS - this.guiRows = [ + this.guiRecordingConfigRows = [ {name: "Records", smallDelta: 1, largeDelta: 10}, {name: "ms", smallDelta: 1, largeDelta: 10}, {name: "Seconds", smallDelta: 1, largeDelta: 5}, @@ -97,15 +101,20 @@ namespace microcode { {name: "Days", smallDelta: 1, largeDelta: 5}, {name: "Delay", smallDelta: 1, largeDelta: 5}, ] + this.guiRecordingConfigValues = [] - this.guiValues = [] - this.sensorConfigs = [] - this.configHasChanged = [] + this.guiEventConfigText = ["choose inequality", "compared against", "number of events"] + this.guiEventConfigValues = [] + + this.sensorRecordingConfigs = [] + this.sensorEventConfigs = [] + this.recordingConfigHasChanged = [] + this.eventConfigHasChanged = [] this.sensors = sensors for (let _ = 0; _ < this.sensors.length; _++) { // Defaults for each sensor: - this.guiValues.push([ + this.guiRecordingConfigValues.push([ 10, // Records 0, // ms 1, // Seconds @@ -114,31 +123,31 @@ namespace microcode { 0, // Days 0 // Delay ]) - this.configHasChanged.push(false) - this.sensorConfigs.push({measurements: 20, period: 1000, delay: 0}) + this.guiEventConfigValues.push([0, 0, 10]) // [x: (0 -> sensorEventSymbols.length), y: (sensor.min -> sensor.max), times: (0 -> _)] + + this.recordingConfigHasChanged.push(false) + this.eventConfigHasChanged.push(false) + this.sensorRecordingConfigs.push({measurements: 20, period: 1000, delay: 0}) } this.currentSensorRow = 0 this.currentConfigRow = 0 this.currentWriteModeRow = 0 - this.currentEventColumn = 0 - this.eventConfigs = [0, 0] // [x: (0 -> sensorEventSymbols.length), y: (sensor.min -> sensor.max)] - // Optional keyword colouring: this.tutorialTextTips = [ {text: "This screen is where\nyou configure your\nsensors."}, {text: "Use A & B to move\nthrough menus.", keywords: [" A ", " B "], keywordColors: [6, 2]}, // Red and Blue to copy controller colours {text: "Use UP and DOWN to\nscroll through\nmenus. Try it now!"}, - {text: "The current sensor\nwill be yellow Press\nA to select it!", keywords: [" yellow ", "A "], keywordColors: [5, 6]}, // Yellow and Red + {text: "The current sensor\nwill be yellow Press\nA to select it!", keywords: [" yellow ", "A "], keywordColors: [5, 6]}, // Yellow and Red + {text: "A sensor can record\nevents or data."}, {text: "Configured sensors\nare green.", keywords: [" green"], keywordColors: [7]}, // Green - {text: "Unconfigured sensors\nare red.", keywords: [" red"], keywordColors: [2]}, // Red - {text: "Press A to configure\nsome sensors!", keywords: [" A "], keywordColors: [6]}, // Blue + {text: "Unconfigured sensors\nare red.", keywords: [" red"], keywordColors: [2]}, // Red + {text: "Press A to configure\nsome sensors!", keywords: [" A "], keywordColors: [6]}, // Blue ] this.tutorialTextIndexOffset = 0 - //-------------- // User Control: //-------------- @@ -154,18 +163,38 @@ namespace microcode { case GUI_STATE.SELECTING_SENSOR: this.guiState = GUI_STATE.SELECTING_WRITE_MODE - this.configHasChanged[this.currentSensorRow] = true + this.recordingConfigHasChanged[this.currentSensorRow] = true break; case GUI_STATE.SELECTING_WRITE_MODE: - this.guiState = GUI_STATE.DEFAULT this.writingMode = [WRITE_MODE.RECORDING_SETTINGS, WRITE_MODE.EVENT_SETTINGS][this.currentWriteModeRow] + + if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { + this.guiState = GUI_STATE.DEFAULT + this.recordingConfigHasChanged[this.currentSensorRow] = true + } + + // If the writingMode is for events then the user should be able to use UP, DOWN, LEFT, RIGHT to move immediately - without an A press: + else { + this.guiState = GUI_STATE.WRITING + this.eventConfigHasChanged[this.currentSensorRow] = true + } break; case GUI_STATE.CONFIRM_CONFIGURATION: // Build the sensors according to their specific configuration: - this.setSensorConfigs() - this.sensors.map((sensor, index) => sensor.setRecordingConfig(this.sensorConfigs[index])) + this.createSensorConfigs() + + // Pass each sensor its config: + this.sensors.map((sensor, index) => { + if (this.eventConfigHasChanged[index]) { + sensor.setEventConfig(this.sensorEventConfigs[index]) + } + + else { + sensor.setRecordingConfig(this.sensorRecordingConfigs[index]) + } + }) this.app.popScene() this.app.pushScene(new DataRecorder(this.app, this.sensors)) @@ -176,7 +205,13 @@ namespace microcode { break; case GUI_STATE.WRITING: - this.guiState = GUI_STATE.DEFAULT + // Pressing A or B in the event configuration mode confirms and moves to the prior screen (it is saved so they may return to modify these settings): + if (this.writingMode == WRITE_MODE.EVENT_SETTINGS) { + this.guiState = GUI_STATE.SELECTING_WRITE_MODE + } + else { + this.guiState = GUI_STATE.DEFAULT + } break; default: @@ -202,8 +237,8 @@ namespace microcode { break; case GUI_STATE.SELECTING_WRITE_MODE: - for (let i = 0; i < this.configHasChanged.length; i++) { - if (this.configHasChanged[i]) { + for (let i = 0; i < this.recordingConfigHasChanged.length; i++) { + if (this.recordingConfigHasChanged[i]) { this.guiState = GUI_STATE.CONFIRM_CONFIGURATION } else { @@ -218,7 +253,7 @@ namespace microcode { break; case GUI_STATE.WRITING: - this.guiState = GUI_STATE.SELECTING_SENSOR + this.guiState = GUI_STATE.SELECTING_WRITE_MODE break case GUI_STATE.DEFAULT: @@ -246,12 +281,27 @@ namespace microcode { else if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode == WRITE_MODE.RECORDING_SETTINGS) { - this.guiValues[this.currentSensorRow][this.currentConfigRow] = this.guiValues[this.currentSensorRow][this.currentConfigRow] + this.guiRows[this.currentConfigRow].smallDelta + this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] = this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] + this.guiRecordingConfigRows[this.currentConfigRow].smallDelta } else { - // Non-negative modulo: - this.eventConfigs[0] = (((this.eventConfigs[0] - 1) % sensorEventSymbols.length) + sensorEventSymbols.length) % sensorEventSymbols.length + switch (this.currentEventColumn) { + case 0: + this.guiEventConfigValues[this.currentSensorRow][0] = (this.guiEventConfigValues[this.currentSensorRow][0] + 1) % sensorEventSymbols.length + break; + + case 1: + this.guiEventConfigValues[this.currentSensorRow][1] = (this.guiEventConfigValues[this.currentSensorRow][1] + 1) % this.sensors[this.currentSensorRow].maximum + break; + + case 2: + const maxEvents = 100 + this.guiEventConfigValues[this.currentSensorRow][2] = (this.guiEventConfigValues[this.currentSensorRow][2] + 1) % maxEvents + break; + + default: + break; + } } } @@ -262,7 +312,7 @@ namespace microcode { else { // Non-negative modulo: - const numberOfMeasurementRows = this.guiRows.length + const numberOfMeasurementRows = this.guiRecordingConfigRows.length this.currentConfigRow = (((this.currentConfigRow - 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows } } @@ -282,11 +332,28 @@ namespace microcode { else if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { - this.guiValues[this.currentSensorRow][this.currentConfigRow] = Math.max(this.guiValues[this.currentSensorRow][this.currentConfigRow] - this.guiRows[this.currentConfigRow].smallDelta, 0) + this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] = Math.max(this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] - this.guiRecordingConfigRows[this.currentConfigRow].smallDelta, 0) } else { - this.eventConfigs[0] = ((this.eventConfigs[0] + 1) % sensorEventSymbols.length) + switch (this.currentEventColumn) { + case 0: + // Non-negative modulo is required for the first column - since it is an index into the sensorEventSymbols[] + const numberOfCols = sensorEventSymbols.length + this.guiEventConfigValues[this.currentSensorRow][0] = (((this.guiEventConfigValues[this.currentSensorRow][0] - 1) % numberOfCols) + numberOfCols) % numberOfCols + break; + case 1: + // May be negative: + this.guiEventConfigValues[this.currentSensorRow][1] = (this.guiEventConfigValues[this.currentSensorRow][1] - 1) % this.sensors[this.currentSensorRow].minimum + break; + case 2: + // Non-negative modulo is required for the 3rd column - since you cannot have negative event counts: + const maxEvents = 100 + this.guiEventConfigValues[this.currentSensorRow][2] = (((this.guiEventConfigValues[this.currentSensorRow][2] - 1) % maxEvents) + maxEvents) % maxEvents + break; + default: + break; + } } } @@ -295,7 +362,7 @@ namespace microcode { } else { - const numberOfMeasurementRows = this.guiRows.length + const numberOfMeasurementRows = this.guiRecordingConfigRows.length this.currentConfigRow = (((this.currentConfigRow + 1) % numberOfMeasurementRows) + numberOfMeasurementRows) % numberOfMeasurementRows } } @@ -307,18 +374,16 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { - this.guiValues[this.currentSensorRow][this.currentConfigRow] = Math.max(this.guiValues[this.currentSensorRow][this.currentConfigRow] - this.guiRows[this.currentConfigRow].largeDelta, 0) + this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] = Math.max(this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] - this.guiRecordingConfigRows[this.currentConfigRow].largeDelta, 0) } else { - const maxReading: number = this.sensors[this.currentSensorRow].maximum - // Non-negative modulo: - this.eventConfigs[1] = (((this.eventConfigs[1] - 1) % maxReading) + maxReading) % maxReading + this.currentEventColumn = (((this.currentEventColumn - 1) % 3) + 3) % 3 } } else if (this.guiState === GUI_STATE.DEFAULT) { - this.currentEventColumn = (((this.currentEventColumn + 1) % 2) + 2) % 2 + this.currentEventColumn = (((this.currentEventColumn + 1) % 3) + 3) % 3 } else if (this.guiState == GUI_STATE.SELECTING_SENSOR) { @@ -338,11 +403,11 @@ namespace microcode { () => { if (this.guiState === GUI_STATE.WRITING) { if (this.writingMode === WRITE_MODE.RECORDING_SETTINGS) { - this.guiValues[this.currentSensorRow][this.currentConfigRow] = this.guiValues[this.currentSensorRow][this.currentConfigRow] + this.guiRows[this.currentConfigRow].largeDelta + this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] = this.guiRecordingConfigValues[this.currentSensorRow][this.currentConfigRow] + this.guiRecordingConfigRows[this.currentConfigRow].largeDelta } else { - this.eventConfigs[1] = ((this.eventConfigs[1] + 1) % this.sensors[this.currentSensorRow].minimum) + this.currentEventColumn = (this.currentEventColumn + 1) % 3 } } @@ -364,20 +429,29 @@ namespace microcode { /** - * Convert the .guiRows data into a RecordingConfig object for use by the DataRecorder - * Set the this.sensorConfigs[this.currentSensorRow] to this RecordingConfig object + * Generates the RecordingConfig and the EventConfig (if chosen) places it within this.sensorConfigs[sensor] for each sensor */ - private setSensorConfigs(): void { + private createSensorConfigs(): void { for (let sensorRow = 0; sensorRow < this.sensors.length; sensorRow++) { let period: number = 0 - for (let col = 1; col < this.guiRows.length - 1; col++) { - period += this.guiValues[sensorRow][col] * TIME_CONVERSION_TABLE[col - 1] + for (let col = 1; col < this.guiRecordingConfigRows.length - 1; col++) { + period += this.guiRecordingConfigValues[sensorRow][col] * TIME_CONVERSION_TABLE[col - 1] } - this.sensorConfigs[sensorRow] = { - measurements: this.guiValues[sensorRow][0], - period, - delay: this.guiValues[sensorRow][6] + if (this.eventConfigHasChanged[sensorRow]) { + this.sensorEventConfigs[sensorRow] = { + measurements: this.guiEventConfigValues[sensorRow][2], + inequality: sensorEventSymbols[this.guiEventConfigValues[sensorRow][0]], + comparator: this.guiEventConfigValues[sensorRow][1], + } + } + + else { + this.sensorRecordingConfigs[sensorRow] = { + measurements: this.guiRecordingConfigValues[sensorRow][0], + period, + delay: this.guiRecordingConfigValues[sensorRow][6] + } } } } @@ -426,11 +500,11 @@ namespace microcode { const xPosText: number = Screen.WIDTH - 38 const text: string[] = ["Config", "Events"] - let boxColor = 1 // white + let boxColor = 6 // Blue: Default for unselected for (let row = 0; row < 2; row++) { - boxColor = 1 // white + boxColor = 6 // Blue if (row == this.currentWriteModeRow) { - boxColor = 6 // blue + boxColor = 5 // Yellow: selected } screen.fillRect( @@ -460,8 +534,8 @@ namespace microcode { private drawConfigSelectionWindow() { const optionX = Screen.WIDTH - 17 - const headerX = optionX - (font.charWidth * this.guiRows[0].name.length) - 6 - const rowSize = Screen.HEIGHT / (this.guiRows.length + 1) + const headerX = optionX - (font.charWidth * this.guiRecordingConfigRows[0].name.length) - 6 + const rowSize = Screen.HEIGHT / (this.guiRecordingConfigRows.length + 1) // Sub-window: // Outline: @@ -487,7 +561,7 @@ namespace microcode { 18 + (this.currentConfigRow * rowSize) - 3, Screen.WIDTH - headerX + 7, font.charHeight + 9, - 16 + 15 // Black ) screen.fillRect( @@ -495,20 +569,20 @@ namespace microcode { 18 + (this.currentConfigRow * rowSize) - 3, Screen.WIDTH - headerX + 8, font.charHeight + 6, - 5 + 5 // Yellow ) let rowOffset = 0; - for (let configRow = 0; configRow < this.guiRows.length; configRow++) { + for (let configRow = 0; configRow < this.guiRecordingConfigRows.length; configRow++) { screen.print( - this.guiRows[configRow].name, + this.guiRecordingConfigRows[configRow].name, headerX - 1, 18 + rowOffset, 15 // Black ) screen.print( - this.guiValues[this.currentSensorRow][configRow].toString(), + this.guiRecordingConfigValues[this.currentSensorRow][configRow].toString(), optionX - 3, 18 + rowOffset, 15 // Black @@ -713,56 +787,79 @@ namespace microcode { } private drawEventSelectionWindow() { - const xOffset = 12 + const xOffset = 8 // Window: screen.fillRect( xOffset, - Screen.HALF_HEIGHT - 22, - Screen.WIDTH - 24, - 44, + Screen.HALF_HEIGHT - 32, + Screen.WIDTH - 20, + 55, 15 ) screen.fillRect( xOffset, - Screen.HALF_HEIGHT - 22, - Screen.WIDTH - 24, - 40, + Screen.HALF_HEIGHT - 32, + Screen.WIDTH - 23, + 52, 3 ) + // Prompt text: + screen.printCenter( + this.guiEventConfigText[this.currentEventColumn], + Screen.HALF_HEIGHT - 32 + 6, + 15 + ) + // This temporary object creation is very inefficient; it can be rectified in the future by creating the sensors and then loading their configs at the end: const sensor: Sensor = this.sensors[this.currentSensorRow] - const middleSensorRange: string = (sensor.maximum - Math.abs(sensor.minimum)).toString() + const inequalitySymbol: string = sensorEventSymbols[this.guiEventConfigValues[this.currentSensorRow][0]] + const inequalityOperand: string = this.guiEventConfigValues[this.currentSensorRow][1].toString() + const eventMeasurements: string = this.guiEventConfigValues[this.currentSensorRow][2].toString() + + const borderOffset = 0 // Box around selected element: - if (this.currentEventColumn == 0) { - for (let borderOffset = 0; borderOffset < 2; borderOffset) { + switch (this.currentEventColumn) { + case 0: screen.drawRect( - xOffset + 6 + (sensor.name.length * font.charWidth) + 9 - borderOffset, + xOffset + 8 + (sensor.name.length * font.charWidth) + 9 - borderOffset, Screen.HALF_HEIGHT - 7 - borderOffset, - (sensorEventSymbols[this.eventConfigs[0]].length * font.charWidth) + 5 + borderOffset, + (inequalitySymbol.length * font.charWidth) + 5 + borderOffset, 12 + borderOffset, 6 ) - } - } - else { - for (let borderOffset = 0; borderOffset < 2; borderOffset) { + break; + + case 1: screen.drawRect( - xOffset + 6 + (sensor.name.length * font.charWidth) + 9 + (middleSensorRange.length * font.charWidth) + 7 - borderOffset, + xOffset + 8 + (sensor.name.length * font.charWidth) + 16 + (inequalitySymbol.length * font.charWidth), Screen.HALF_HEIGHT - 7 - borderOffset, - (sensor.maximum.toString().length * font.charWidth) + 5 + borderOffset, + (inequalityOperand.length * font.charWidth) + 5 + borderOffset, 12 + borderOffset, 6 ) - } + break; + + case 2: + screen.drawRect( + xOffset + 8 + (sensor.name.length * font.charWidth) + 16 + (inequalitySymbol.length * font.charWidth) + (inequalityOperand.length * font.charWidth) + 23, + Screen.HALF_HEIGHT - 7 - borderOffset, + (eventMeasurements.length * font.charWidth) + 5 + borderOffset, + 12 + borderOffset, + 6 + ) + break; + + default: + break; } // Write Event expression: screen.print( - sensor.name + " " + sensorEventSymbols[this.eventConfigs[0]] + " " + middleSensorRange, + "(" + sensor.name + " " + inequalitySymbol + " " + inequalityOperand + ") * " + eventMeasurements, xOffset * 2, Screen.HALF_HEIGHT - 5, 15 // black @@ -781,7 +878,7 @@ namespace microcode { boxColor = 5 // yellow: selected } - else if (this.configHasChanged[row]) { + else if (this.recordingConfigHasChanged[row]) { boxColor = 7 // green: changed } From edad8909e107e47a87f9e3fdef60adb33555c96b Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:39:11 +0100 Subject: [PATCH 090/109] liveDataViewer: fixed bug where (x,y) for oscilloscope when zoomed in was too far away, removed unncessary code. --- liveDataViewer.ts | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/liveDataViewer.ts b/liveDataViewer.ts index d8a4d12..89f68be 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -216,7 +216,7 @@ namespace microcode { if (this.requestDataMode) { this.sensors.forEach(function(sensor) { - sensor.readIntoBuffer() + sensor.readIntoBufferOnce() }) } @@ -241,6 +241,7 @@ namespace microcode { // Colour used to represent this sensor, same colour as plotted & ticker: y += (i * 12) + // Colour block to the left of the name: screen.fillRect( 2, y, @@ -269,7 +270,6 @@ namespace microcode { color = (color + 3) % 15 } - // The data from the sensors will shift to the left over time as the buffer is filled // Shift the selected coordinate appropriately; so that the Circle around the selected point is accurate if (this.requestDataMode && this.selectedXCoordinate != null && this.sensors[this.selectedSensorIndex].getBufferSize() == Sensor.BUFFER_LIMIT) { @@ -294,6 +294,22 @@ namespace microcode { 5, 1 ) + + screen.print( + "x =" + this.selectedXCoordinate.toString(), + this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, + y + 5, + color, + simage.font5, + ) + + screen.print( + "y =" + this.sensors[this.selectedSensorIndex].getReading().toString(), + this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, + y + 15, + color, + simage.font5, + ) } // Draw the latest reading on the right-hand side as a Ticker if at no-zoom: @@ -319,30 +335,6 @@ namespace microcode { }) } - // Check because they may become null my scrolling off the screen: - else if (this.selectedXCoordinate != null && this.selectedYCoordinate != null) { - const fromY = this.windowBotBuffer - this.yScrollOffset - this.yScrollOffset - const sensorRange = (this.sensors[this.selectedSensorIndex].maximum + Math.abs(this.sensors[this.selectedSensorIndex].minimum)) - const norm = ((this.selectedYCoordinate / sensorRange) * (Screen.HEIGHT - fromY)) - const y = Math.round(Screen.HEIGHT - norm) - fromY - - screen.print( - "x =" + this.selectedXCoordinate.toString(), - this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, - y - 5, - color, - simage.font5, - ) - - screen.print( - "y =" + this.sensors[this.selectedSensorIndex].getReading().toString(), - this.windowWidthBuffer + this.selectedXCoordinate + this.xScrollOffset + 10, - y - 15, - color, - simage.font5, - ) - } - // Draw data lines: color = 8; this.sensors.forEach(function(sensor) { From 4a15e095afcf477a32e655fcba099372fdc9feb6 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:39:58 +0100 Subject: [PATCH 091/109] dataRecorder: added support for different text info depending on whether or not the sensor was recording data or recording events. --- dataRecorder.ts | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/dataRecorder.ts b/dataRecorder.ts index 662c1ed..844e63a 100644 --- a/dataRecorder.ts +++ b/dataRecorder.ts @@ -22,7 +22,7 @@ namespace microcode { // Start logging: this.sensors.forEach((sensor) => { - sensor.log(this) + sensor.log() }) //--------------- @@ -156,11 +156,24 @@ namespace microcode { 15 ) - const sensorInfo: string[] = [ - sensor.config.period / 1000 + " second period", - sensor.config.measurements.toString() + " measurements left", - ((sensor.config.measurements * sensor.config.period) / 1000).toString() + " seconds left" - ] + let sensorInfo: string[] + if (sensor.loggingMode == SensorLoggingMode.RECORDING) { + const config = sensor.config as RecordingConfig + sensorInfo = [ + config.period / 1000 + " second period", + config.measurements.toString() + " measurements left", + ((sensor.config.measurements * config.period) / 1000).toString() + " seconds left" + ] + } + + else { + const config = sensor.config as EventConfig + sensorInfo = [ + config.measurements.toString() + " events left", + "Logging " + config.inequality + " " + config.comparator + " events", + sensor.lastLoggedEventDescription + ] + } sensorInfo.forEach((info) => { y += 12 From 23edae728df8abdb3d33abe9e05de2e69a4a4ceb Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:42:03 +0100 Subject: [PATCH 092/109] sensors & sensorEvents: added event logging, added event facts via .lastLoggedEventDescription. This class has oppotunity for cleaning up/improvement. --- sensorEvent.ts | 49 +++++++++---------------------- sensors.ts | 80 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 51 deletions(-) diff --git a/sensorEvent.ts b/sensorEvent.ts index 017d08b..7ab1bd5 100644 --- a/sensorEvent.ts +++ b/sensorEvent.ts @@ -1,50 +1,29 @@ namespace microcode { /** + * Used to lookup the implemented events via sensorEventFunctionLookup[] + * * Currently only events that check for inequalities are implemented, * The only sensors that are incompatible with this are Buttons * The following code may be generalised to support them though. */ + export const sensorEventSymbols = ["=", ">", "<", ">=", "<="] - + /** - * Function invoked to check if a reading target is true - * Upon that the callback is invoked - * The callback handles the event via sensors.handleEvent() - * This private method will cause the event to be logged. + * Type for value bound to inequality key within sensorEventFunctionLookup + * + * One of these is optionally held by a sensor - see by sensor.setRecordingConfig */ - type SensorEventFunction = (reading: number, target: number, callback: () => void) => void + export type SensorEventFunction = (reading: number, comparator: number) => boolean /** - * Inequality as string to function that performs said inequality - * Inequality presence => callback() + * Get aa function that performs that inequality check & logs it with an event description if the event has triggered. */ export const sensorEventFunctionLookup: {[inequality: string]: SensorEventFunction} = { - "=": function(reading: number, target: number, callback: () => void) {if (reading === target) {callback()}}, - ">": function(reading: number, target: number, callback: () => void) {if (reading > target) {callback()}}, - "<": function(reading: number, target: number, callback: () => void) {if (reading < target) {callback()}}, - ">=": function(reading: number, target: number, callback: () => void) {if (reading >= target) {callback()}}, - "<=": function(reading: number, target: number, callback: () => void) {if (reading <= target) {callback()}}, - } - - export const sensorEventSymbols = ["=", ">", "<", ">=", "<="] - - /** - * Simple class that is optionally owned by the recordingConfig. - * Acts as a wrapper for the above InequalityFunctions - */ - export class SensorEvent { - public readonly inequality: string // Used to build Logged String - private readonly target: number - private readonly inequalityFunction: SensorEventFunction - - constructor(inequality: string, target: number) { - this.inequality = inequality - this.target = target - this.inequalityFunction = sensorEventFunctionLookup[inequality] - } - - public handleEvent(reading: number, callback: () => void): void { - this.inequalityFunction(reading, this.target, callback) - } + "=": function(reading: number, comparator: number) {return reading == comparator}, + ">": function(reading: number, comparator: number) {return reading > comparator}, + "<": function(reading: number, comparator: number) {return reading < comparator}, + ">=": function(reading: number, comparator: number) {return reading >= comparator}, + "<=": function(reading: number, comparator: number) {return reading <= comparator} } } \ No newline at end of file diff --git a/sensors.ts b/sensors.ts index 6fad41b..7c65bad 100644 --- a/sensors.ts +++ b/sensors.ts @@ -1,4 +1,12 @@ namespace microcode { + export enum SensorLoggingMode { + RECORDING, + EVENTS + } + + + const EVENT_POLLING_PERIOD_MS = 100 + /** * Abstraction for all available sensors, * Methods are seldom overidden @@ -11,15 +19,18 @@ namespace microcode { public sensorFn: () => number public iconName: string public ariaID: string - public config: RecordingConfig + public startTime: number + + public config: RecordingConfig | EventConfig + public loggingMode: SensorLoggingMode // Reading Statistics: public minimum: number public maximum: number public peakDataPoint: number[] + public lastLoggedEventDescription: string private dataBuffer: number[] - private startTime: number constructor(sensorFn: () => number, name: string, @@ -33,19 +44,27 @@ namespace microcode { this.sensorFn = sensorFn this.iconName = iconName this.ariaID = ariaID + this.startTime = 0 // This value will be set upon the first reading + + this.config = config + this.loggingMode = null this.minimum = sensorMinReading this.maximum = sensorMaxReading this.peakDataPoint = [0, this.minimum] // [x, y] + this.lastLoggedEventDescription = "" this.dataBuffer = [] - this.startTime = 0 // This value will be set upon the first reading + } + setRecordingConfig(config: RecordingConfig) { this.config = config + this.loggingMode = SensorLoggingMode.RECORDING } - setRecordingConfig(config: RecordingConfig) { + setEventConfig(config: EventConfig) { this.config = config + this.loggingMode = SensorLoggingMode.EVENTS } getBufferSize(): number {return this.dataBuffer.length} @@ -54,7 +73,7 @@ namespace microcode { getDataBufferLength(): number {return this.dataBuffer.length} getNormalisedReading(): number{return this.sensorFn() / this.maximum} - readIntoBuffer(): void { + readIntoBufferOnce(): void { if (this.dataBuffer.length >= Sensor.BUFFER_LIMIT) { this.dataBuffer.shift(); this.peakDataPoint[0] -= 1 @@ -62,27 +81,56 @@ namespace microcode { this.dataBuffer.push(this.getReading()); } - log(dataRecorder: DataRecorder) { + /** + * Spawns an independent background fiber to log sensor data according to its .config + */ + log() { control.inBackground(() => { if (this.startTime == 0) { this.startTime = input.runningTime() } - while (this.config.measurements > 0) { + if (this.loggingMode == SensorLoggingMode.EVENTS) { + this.logEvents(this.config as EventConfig) + } + + else { + this.logData(this.config as RecordingConfig) + } + }) + } + + private logData(config: RecordingConfig) { + while (config.measurements > 0) { + FauxDataLogger.log([ + this.name, + (input.runningTime() - this.startTime).toString(), + this.getReading().toString(), + "N/A" + ]) + basic.pause(config.period) + config.measurements -= 1 + } + } + + private logEvents(config: EventConfig) { + let sensorEventFunction = sensorEventFunctionLookup[config.inequality] + + while (config.measurements > 0) { + const reading = this.getReading() + + if (sensorEventFunction(reading, config.comparator)) { FauxDataLogger.log([ this.name, (input.runningTime() - this.startTime).toString(), - this.getReading().toString(), - "N/A" + reading.toString(), + reading + " " + config.inequality + " " + config.comparator ]) - - this.config.measurements -= 1 - basic.pause(this.config.period) - - // Update the screen - // dataRecorder.update() + config.measurements -= 1 } - }) + + basic.pause(EVENT_POLLING_PERIOD_MS) + } } /** From 458e1c3c61d61174baa066856fad02355a268cdd Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:43:33 +0100 Subject: [PATCH 093/109] Prototype 11 completion: this demo will receive some minor additions (documentation, small rewrites but with the same output). Prototype 12 is for 2 weeks time - focused upon DataLogger and Jacdac. --- button.ts | 2 +- recordingConfig.ts | 7 ++++++- sensorSelect.ts | 12 +++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/button.ts b/button.ts index 4060c7a..308b02f 100644 --- a/button.ts +++ b/button.ts @@ -198,7 +198,7 @@ namespace microcode { private iconId: string | SImage private _ariaId: string public onClick?: (button: Button) => void - private selected: boolean + public selected: boolean private dynamicBoundaryColorsOn: boolean private boundaryColor: number diff --git a/recordingConfig.ts b/recordingConfig.ts index 9711867..c4b910d 100644 --- a/recordingConfig.ts +++ b/recordingConfig.ts @@ -3,6 +3,11 @@ namespace microcode { measurements: number, period: number, delay: number - sensorEvent?: SensorEvent + }; + + export type EventConfig = { + measurements: number, + inequality: string, + comparator: number }; } \ No newline at end of file diff --git a/sensorSelect.ts b/sensorSelect.ts index c76426a..dc047c8 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -28,7 +28,12 @@ namespace microcode { x: -60, y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // if (this.btns[0].selected) { + // delete this.selectedSensors[this.selectedSensors.findIndex((sensor) => sensor.iconName == "accelerometer")] + // } + // else { + this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) + // } }, dynamicBoundaryColorsOn: true, })) @@ -249,6 +254,11 @@ namespace microcode { this.navigator.addButtons(this.btns) } + + private handleNewSensor() { + + } + draw() { Screen.fillRect( Screen.LEFT_EDGE, From f99c30c15291fe1fdfc95718355c5f96b40899ed Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 16:51:02 +0100 Subject: [PATCH 094/109] ruleEditor & pxt.json: renaming in endeavour to allow importing from MakeCode. --- ruleeditor.ts | 544 -------------------------------------------------- 1 file changed, 544 deletions(-) delete mode 100644 ruleeditor.ts diff --git a/ruleeditor.ts b/ruleeditor.ts deleted file mode 100644 index 83b5455..0000000 --- a/ruleeditor.ts +++ /dev/null @@ -1,544 +0,0 @@ -namespace microcode { - type ButtonRuleRep = { [name: string]: Button[] } - - function repNames() { - return ["sensors", "filters", "actuators", "modifiers"] - } - - export class RuleEditor implements IComponent, IPlaceable { - private xfrm_: Affine - innerWidth: number - handleBtn: Button - whenInsertBtn: Button - doInsertBtn: Button - arrow: Sprite - ruleButtons: ButtonRuleRep - bounds: Bounds - whenBounds: Bounds - queuedCursorMove: CursorDir - - //% blockCombine block="xfrm" callInDebugger - public get xfrm() { - return this.xfrm_ - } - - constructor( - private editor: Editor, - private page: PageEditor, - public ruledef: RuleDefn, - public index: number - ) { - this.xfrm_ = new Affine() - this.xfrm_.parent = page.xfrm - this.handleBtn = new Button({ - parent: this, - icon: "rule_handle", - ariaId: "rule", - x: 0, - y: 0, - style: ButtonStyles.Transparent, - onClick: () => this.showRuleHandleMenu(), - }) - this.arrow = new Sprite({ - parent: this, - img: icons.get("rule_arrow"), - }) - this.ruleButtons = { - sensors: [], - filters: [], - actuators: [], - modifiers: [], - } - this.instantiateProgramTiles() - } - - private destroyWhenInsertButton() { - this.whenInsertBtn = undefined - } - - private needsWhenInsert() { - if ( - this.ruledef["sensors"].length == 0 || - this.getSuggestions("filters", this.ruledef["filters"].length) - .length - ) { - this.whenInsertBtn = new Button({ - parent: this, - style: ButtonStyles.Transparent, - icon: "when_insertion_point", - ariaId: - this.ruledef["sensors"].length == 0 - ? "when" - : undefined, - x: 0, - y: 0, - onClick: () => this.showWhenInsertMenu(), - }) - } else { - this.destroyWhenInsertButton() - } - } - - private destroyDoInsertButton() { - this.doInsertBtn = undefined - } - - private needsDoInsert() { - if ( - this.ruledef["actuators"].length == 0 || - this.getSuggestions( - "modifiers", - this.ruledef["modifiers"].length - ).length - ) { - this.doInsertBtn = new Button({ - parent: this, - style: ButtonStyles.Transparent, - icon: "do_insertion_point", - ariaId: - this.ruledef["actuators"].length == 0 - ? "do" - : undefined, - x: 0, - y: 0, - onClick: () => this.showDoInsertMenu(), - }) - } else { - this.destroyDoInsertButton() - } - } - - private destroyProgramTiles() { - let changed = false - repNames().forEach(name => { - if (this.ruleButtons[name].length) { - this.ruleButtons[name] = [] - changed = true - } - }) - // TODO: do we really need this? - if (changed) this.editor.changed() - } - - private processSection(name: string, rule: RuleRep) { - const tiles = rule[name] - tiles.forEach((tile, index) => { - const button = new Button({ - parent: this, - style: buttonStyle(tile), - icon: getIcon(tile), - ariaId: tidToString(getTid(tile)), - x: 0, - y: 0, - onClick: () => this.editTile(name, index), - }) - if (name == "filters" && index == 0) { - const sensor = this.ruledef.sensors[0] - // TODO: this logic should be part of the SensorTileDefn - if ( - (jdKind(sensor) == JdKind.Radio && - sensor != Tid.TID_SENSOR_LINE) || - jdKind(sensor) == JdKind.Variable - ) { - const plus = new Button({ - parent: this, - style: buttonStyle(tile), - icon: "arith_equals", - ariaId: "arith_equals", - x: 0, - y: 0, - }) - this.ruleButtons[name].push(plus) - } - } - this.ruleButtons[name].push(button) - if (index < tiles.length - 1) { - if ( - (jdKind(tile) == JdKind.Literal || - jdKind(tile) == JdKind.Variable) && - (jdKind(tiles[index + 1]) == JdKind.Literal || - jdKind(tiles[index + 1]) == JdKind.Variable || - jdKind(tiles[index + 1]) == JdKind.RandomToss) - ) { - const plus = new Button({ - parent: this, - style: buttonStyle(tile), - icon: "arith_plus", - ariaId: "arith_plus", - x: 0, - y: 0, - }) - this.ruleButtons[name].push(plus) - } - } - }) - return tiles.length > 0 - } - private instantiateProgramTiles() { - this.destroyProgramTiles() - const rule = this.ruledef.getRuleRep() - let changed = false - Object.keys(rule).forEach(name => { - changed = this.processSection(name, rule) || changed - }) - this.needsWhenInsert() - this.needsDoInsert() - if (changed) this.page.changed() - } - - private showRuleHandleMenu() { - const btns: PickerButtonDef[] = [ - { - icon: "plus", - ariaId: "add_rule", - }, - { - icon: "delete", - ariaId: "delete_rule", - }, - ] - this.editor.picker.setGroup(btns) - this.editor.picker.show({ - onClick: index => - this.handleRuleHandleMenuSelection( - btns[index].icon as string - ), - }) - } - - private nextEmpty(name: string, index: number) { - return ( - (name == "sensors" && - this.ruledef.filters.length == 0 && - this.whenInsertBtn) || - (name == "filters" && - index == this.ruledef.filters.length - 1 && - (this.whenInsertBtn || - this.ruledef.actuators.length == 0)) || - (name == "actuators" && - this.ruledef.modifiers.length == 0 && - this.doInsertBtn) || - (name == "modifiers" && - index == this.ruledef.modifiers.length - 1 && - this.doInsertBtn) - ) - } - - private deleteIncompatibleTiles(name: string, index: number) { - const doit = (name: string, index: number) => { - const ruleTiles = this.ruledef.getRuleRep()[name] - - while (index < ruleTiles.length) { - const suggestions = this.getSuggestions(name, index) - const compatible = suggestions.find( - t => getTid(t) == getTid(ruleTiles[index]) - ) - if (compatible) index++ - else { - ruleTiles.splice(index, ruleTiles.length - index) - return false - } - } - return true - } - doit(name, index) - if (name === "filters") { - // a change in the the when section may affect the do section - let ok = doit("actuators", 0) - if (ok) doit("modifiers", 0) - else this.ruledef.getRuleRep()["modifiers"] = [] - } - } - - private editTile(name: string, index: number) { - const ruleTiles = this.ruledef.getRuleRep()[name] - const tileUpdated = (tile: Tile) => { - const editedAdded = !!tile - if (tile) { - if (index >= ruleTiles.length) { - reportEvent("tile.add", { tid: getTid(tile) }) - ruleTiles.push(tile) - } else { - reportEvent("tile.update", { tid: getTid(tile) }) - ruleTiles[index] = tile - if (name == "sensors") - this.deleteIncompatibleTiles("filters", 0) - else if (name == "actuators") - this.deleteIncompatibleTiles("modifiers", 0) - else this.deleteIncompatibleTiles(name, index + 1) - } - } else { - ruleTiles.splice(index, 1) - reportEvent("tile.delete") - if (name == "filters" || name == "modifiers") - this.deleteIncompatibleTiles(name, index) - } - Language.ensureValid(this.ruledef) - this.editor.saveAndCompileProgram() - this.instantiateProgramTiles() - if (editedAdded && this.nextEmpty(name, index)) { - // Queue a move to the right - this.queuedCursorMove = CursorDir.Right - } - this.page.changed() - } - const newFieldEditor = (tile: ModifierEditor, del = false) => { - const newOne = del ? tile : tile.getNewInstance() - const fieldEditor = getFieldEditor(newOne) - this.editor.captureBackground() - fieldEditor.editor( - newOne.getField(), - this.editor.picker, - () => { - this.editor.releaseBackground() - tileUpdated(newOne) - }, - del - ? () => { - this.editor.releaseBackground() - tileUpdated(undefined) - } - : undefined - ) - } - if ( - index < ruleTiles.length && - ruleTiles[index] instanceof ModifierEditor - ) { - newFieldEditor(ruleTiles[index] as ModifierEditor, true) - return - } - const suggestions = this.getSuggestions(name, index) - const btns: PickerButtonDef[] = suggestions.map(tile => { - return { - icon: getIcon(tile), - } - }) - // special case for field editor - if ( - suggestions.length == 1 && - suggestions[0] instanceof ModifierEditor - ) { - let theOne = - index > 0 && ruleTiles[index - 1] instanceof ModifierEditor - ? (ruleTiles[index - 1] as ModifierEditor) - : (suggestions[0] as ModifierEditor) - newFieldEditor(theOne) - return - } - let onDelete = undefined - let selectedButton = -1 - if (index < ruleTiles.length) { - onDelete = () => { - tileUpdated(undefined) - } - const selected = btns.indexOf( - btns.find(b => b.icon === getIcon(getTid(ruleTiles[index]))) // TODO - ) - if (selected >= 0) { - selectedButton = selected - } - } - if (btns.length) { - this.editor.picker.setGroup(btns) - this.editor.picker.show({ - title: accessibility.ariaToTooltip(name), - navigator: () => new PickerNavigator(this.editor.picker), - onClick: idx => { - let theOne = suggestions[idx] - if (theOne instanceof ModifierEditor) { - // there is more work to do l - theOne = - index > 0 && - ruleTiles[index - 1] instanceof ModifierEditor - ? (ruleTiles[index - 1] as ModifierEditor) - : theOne - newFieldEditor(theOne) - } - tileUpdated(theOne) - }, - onDelete, - selected: selectedButton, - }) - } - return - } - - private handleRuleHandleMenuSelection(iconId: string) { - if (iconId === "plus") { - reportEvent("rule.add") - this.page.insertRuleAt(this.index) - } else if (iconId === "delete") { - reportEvent("rule.delete") - this.page.deleteRuleAt(this.index) - } - } - - private showWhenInsertMenu() { - if (this.ruledef.sensors.length) { - this.editTile("filters", this.ruledef.filters.length) - } else { - this.editTile("sensors", 0) - } - } - - private showDoInsertMenu() { - if (this.ruledef.actuators.length) { - this.editTile("modifiers", this.ruledef.modifiers.length) - } else { - this.editTile("actuators", 0) - } - } - - private getSuggestions(name: string, index: number) { - return Language.getTileSuggestions(this.ruledef, name, index) - } - - public getRuleButtons() { - // TODO: can this be done lazily instead? - const btns: Button[] = [] - btns.push(this.handleBtn) - this.ruleButtons.sensors.forEach(b => btns.push(b)) - this.ruleButtons.filters.forEach(b => btns.push(b)) - - if (this.whenInsertBtn) btns.push(this.whenInsertBtn) - - this.ruleButtons.actuators.forEach(b => btns.push(b)) - this.ruleButtons.modifiers.forEach(b => btns.push(b)) - - if (this.doInsertBtn) btns.push(this.doInsertBtn) - - return btns - } - - public isEmpty() { - return this.ruledef.isEmpty() - } - - update() { - if (this.queuedCursorMove) { - switch (this.queuedCursorMove) { - case CursorDir.Right: - control.raiseEvent(KEY_DOWN, controller.right.id) - break - // Add other cases as needed - } - this.queuedCursorMove = undefined - } - } - - public layout() { - const ruleRep = this.ruleButtons - const v = new Vec2() - this.whenBounds = new Bounds() - - const whenTiles = ruleRep.sensors.concat(ruleRep.filters) - const doTiles = ruleRep.actuators.concat(ruleRep.modifiers) - if (this.whenInsertBtn) whenTiles.push(this.whenInsertBtn) - if (this.doInsertBtn) doTiles.push(this.doInsertBtn) - - const firstWhenTile = whenTiles[0] - const lastWhenTile = whenTiles[whenTiles.length - 1] - - this.handleBtn.xfrm.localPos = v - v.x += this.handleBtn.width - this.whenBounds.left = v.x - - v.x += firstWhenTile.width >> 1 - v.x += 2 - - const layoutButtons = (btns: Button[]) => { - btns.forEach((btn, index) => { - if (index) { - v.x += btns[index - 1].width >> 1 - v.x += btn.width >> 1 - v.x += 1 - } - btn.xfrm.localPos = v - }) - } - - layoutButtons(whenTiles) - - v.x += lastWhenTile.bounds.width >> 1 - this.whenBounds.right = v.x - - v.x += this.arrow.bounds.width >> 1 - v.x += 1 - - this.arrow.xfrm.localPos.x = v.x - v.x += this.arrow.bounds.width - v.x += 2 - - layoutButtons(doTiles) - - if (this.doInsertBtn) { - this.doInsertBtn.xfrm.localPos = v - } - - this.bounds = undefined - - const updateSizeFromButtons = (btns: Button[]) => { - btns.forEach(btn => { - if (!this.bounds) { - this.bounds = btn.bounds - .clone() - .translate(btn.xfrm.localPos) - } else { - this.bounds.add( - Bounds.Translate(btn.bounds, btn.xfrm.localPos) - ) - } - }) - } - - updateSizeFromButtons(whenTiles) - updateSizeFromButtons(doTiles) - - if (!this.bounds) { - this.bounds = new Bounds() - } else { - this.bounds.grow(1) - } - - // Ensure that the rule "tray" is at least as wide as the screen - this.innerWidth = this.bounds.width - this.bounds.width = Math.max(this.bounds.width, Screen.WIDTH) - - this.whenBounds.left = this.bounds.left - this.whenBounds.top = this.bounds.top - this.whenBounds.height = this.bounds.height - } - - isOffScreen(): boolean { - const y = this.xfrm.worldPos.y - const b = this.bounds - return ( - y + b.top > Screen.BOTTOM_EDGE || y + b.bottom < Screen.TOP_EDGE - ) - } - - draw() { - if (this.isOffScreen()) return - - this.drawBackground() - this.handleBtn.draw() - if (this.whenInsertBtn) this.whenInsertBtn.draw() - this.arrow.draw() - if (this.doInsertBtn) this.doInsertBtn.draw() - repNames().forEach(name => { - const buttons = this.ruleButtons[name] - for (let i = 0; i < buttons.length; ++i) { - const btn = buttons[i] - if (!btn.isOffScreenX()) btn.draw() - } - }) - } - - private drawBackground() { - Screen.fillBoundsXfrm(this.xfrm, this.bounds, 11) - Screen.fillBoundsXfrm(this.xfrm, this.whenBounds, 13) - Screen.outlineBoundsXfrm(this.xfrm, this.bounds, 1, 12) - } - } -} From 08b7584d6004ddcace82f11874eb451c6089b8a0 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Wed, 3 Apr 2024 17:03:29 +0100 Subject: [PATCH 095/109] adding ruleEditor. --- ruleEditor.ts | 544 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 544 insertions(+) create mode 100644 ruleEditor.ts diff --git a/ruleEditor.ts b/ruleEditor.ts new file mode 100644 index 0000000..75f7485 --- /dev/null +++ b/ruleEditor.ts @@ -0,0 +1,544 @@ +namespace microcode { + type ButtonRuleRep = { [name: string]: Button[] } + + function repNames() { + return ["sensors", "filters", "actuators", "modifiers"] + } + + export class RuleEditor implements IComponent, IPlaceable { + private xfrm_: Affine + innerWidth: number + handleBtn: Button + whenInsertBtn: Button + doInsertBtn: Button + arrow: Sprite + ruleButtons: ButtonRuleRep + bounds: Bounds + whenBounds: Bounds + queuedCursorMove: CursorDir + + //% blockCombine block="xfrm" callInDebugger + public get xfrm() { + return this.xfrm_ + } + + constructor( + private editor: Editor, + private page: PageEditor, + public ruledef: RuleDefn, + public index: number + ) { + this.xfrm_ = new Affine() + this.xfrm_.parent = page.xfrm + this.handleBtn = new Button({ + parent: this, + icon: "rule_handle", + ariaId: "rule", + x: 0, + y: 0, + style: ButtonStyles.Transparent, + onClick: () => this.showRuleHandleMenu(), + }) + this.arrow = new Sprite({ + parent: this, + img: icons.get("rule_arrow"), + }) + this.ruleButtons = { + sensors: [], + filters: [], + actuators: [], + modifiers: [], + } + this.instantiateProgramTiles() + } + + private destroyWhenInsertButton() { + this.whenInsertBtn = undefined + } + + private needsWhenInsert() { + if ( + this.ruledef["sensors"].length == 0 || + this.getSuggestions("filters", this.ruledef["filters"].length) + .length + ) { + this.whenInsertBtn = new Button({ + parent: this, + style: ButtonStyles.Transparent, + icon: "when_insertion_point", + ariaId: + this.ruledef["sensors"].length == 0 + ? "when" + : undefined, + x: 0, + y: 0, + onClick: () => this.showWhenInsertMenu(), + }) + } else { + this.destroyWhenInsertButton() + } + } + + private destroyDoInsertButton() { + this.doInsertBtn = undefined + } + + private needsDoInsert() { + if ( + this.ruledef["actuators"].length == 0 || + this.getSuggestions( + "modifiers", + this.ruledef["modifiers"].length + ).length + ) { + this.doInsertBtn = new Button({ + parent: this, + style: ButtonStyles.Transparent, + icon: "do_insertion_point", + ariaId: + this.ruledef["actuators"].length == 0 + ? "do" + : undefined, + x: 0, + y: 0, + onClick: () => this.showDoInsertMenu(), + }) + } else { + this.destroyDoInsertButton() + } + } + + private destroyProgramTiles() { + let changed = false + repNames().forEach(name => { + if (this.ruleButtons[name].length) { + this.ruleButtons[name] = [] + changed = true + } + }) + // TODO: do we really need this? + if (changed) this.editor.changed() + } + + private processSection(name: string, rule: RuleRep) { + const tiles = rule[name] + tiles.forEach((tile, index) => { + const button = new Button({ + parent: this, + style: buttonStyle(tile), + icon: getIcon(tile), + ariaId: tidToString(getTid(tile)), + x: 0, + y: 0, + onClick: () => this.editTile(name, index), + }) + if (name == "filters" && index == 0) { + const sensor = this.ruledef.sensors[0] + // TODO: this logic should be part of the SensorTileDefn + if ( + (jdKind(sensor) == JdKind.Radio && + sensor != Tid.TID_SENSOR_LINE) || + jdKind(sensor) == JdKind.Variable + ) { + const plus = new Button({ + parent: this, + style: buttonStyle(tile), + icon: "arith_equals", + ariaId: "arith_equals", + x: 0, + y: 0, + }) + this.ruleButtons[name].push(plus) + } + } + this.ruleButtons[name].push(button) + if (index < tiles.length - 1) { + if ( + (jdKind(tile) == JdKind.Literal || + jdKind(tile) == JdKind.Variable) && + (jdKind(tiles[index + 1]) == JdKind.Literal || + jdKind(tiles[index + 1]) == JdKind.Variable || + jdKind(tiles[index + 1]) == JdKind.RandomToss) + ) { + const plus = new Button({ + parent: this, + style: buttonStyle(tile), + icon: "arith_plus", + ariaId: "arith_plus", + x: 0, + y: 0, + }) + this.ruleButtons[name].push(plus) + } + } + }) + return tiles.length > 0 + } + private instantiateProgramTiles() { + this.destroyProgramTiles() + const rule = this.ruledef.getRuleRep() + let changed = false + Object.keys(rule).forEach(name => { + changed = this.processSection(name, rule) || changed + }) + this.needsWhenInsert() + this.needsDoInsert() + if (changed) this.page.changed() + } + + private showRuleHandleMenu() { + const btns: PickerButtonDef[] = [ + { + icon: "plus", + ariaId: "add_rule", + }, + { + icon: "delete", + ariaId: "delete_rule", + }, + ] + this.editor.picker.setGroup(btns) + this.editor.picker.show({ + onClick: index => + this.handleRuleHandleMenuSelection( + btns[index].icon as string + ), + }) + } + + private nextEmpty(name: string, index: number) { + return ( + (name == "sensors" && + this.ruledef.filters.length == 0 && + this.whenInsertBtn) || + (name == "filters" && + index == this.ruledef.filters.length - 1 && + (this.whenInsertBtn || + this.ruledef.actuators.length == 0)) || + (name == "actuators" && + this.ruledef.modifiers.length == 0 && + this.doInsertBtn) || + (name == "modifiers" && + index == this.ruledef.modifiers.length - 1 && + this.doInsertBtn) + ) + } + + private deleteIncompatibleTiles(name: string, index: number) { + const doit = (name: string, index: number) => { + const ruleTiles = this.ruledef.getRuleRep()[name] + + while (index < ruleTiles.length) { + const suggestions = this.getSuggestions(name, index) + const compatible = suggestions.find( + t => getTid(t) == getTid(ruleTiles[index]) + ) + if (compatible) index++ + else { + ruleTiles.splice(index, ruleTiles.length - index) + return false + } + } + return true + } + doit(name, index) + if (name === "filters") { + // a change in the the when section may affect the do section + let ok = doit("actuators", 0) + if (ok) doit("modifiers", 0) + else this.ruledef.getRuleRep()["modifiers"] = [] + } + } + + private editTile(name: string, index: number) { + const ruleTiles = this.ruledef.getRuleRep()[name] + const tileUpdated = (tile: Tile) => { + const editedAdded = !!tile + if (tile) { + if (index >= ruleTiles.length) { + reportEvent("tile.add", { tid: getTid(tile) }) + ruleTiles.push(tile) + } else { + reportEvent("tile.update", { tid: getTid(tile) }) + ruleTiles[index] = tile + if (name == "sensors") + this.deleteIncompatibleTiles("filters", 0) + else if (name == "actuators") + this.deleteIncompatibleTiles("modifiers", 0) + else this.deleteIncompatibleTiles(name, index + 1) + } + } else { + ruleTiles.splice(index, 1) + reportEvent("tile.delete") + if (name == "filters" || name == "modifiers") + this.deleteIncompatibleTiles(name, index) + } + Language.ensureValid(this.ruledef) + this.editor.saveAndCompileProgram() + this.instantiateProgramTiles() + if (editedAdded && this.nextEmpty(name, index)) { + // Queue a move to the right + this.queuedCursorMove = CursorDir.Right + } + this.page.changed() + } + const newFieldEditor = (tile: ModifierEditor, del = false) => { + const newOne = del ? tile : tile.getNewInstance() + const fieldEditor = getFieldEditor(newOne) + this.editor.captureBackground() + fieldEditor.editor( + newOne.getField(), + this.editor.picker, + () => { + this.editor.releaseBackground() + tileUpdated(newOne) + }, + del + ? () => { + this.editor.releaseBackground() + tileUpdated(undefined) + } + : undefined + ) + } + if ( + index < ruleTiles.length && + ruleTiles[index] instanceof ModifierEditor + ) { + newFieldEditor(ruleTiles[index] as ModifierEditor, true) + return + } + const suggestions = this.getSuggestions(name, index) + const btns: PickerButtonDef[] = suggestions.map(tile => { + return { + icon: getIcon(tile), + } + }) + // special case for field editor + if ( + suggestions.length == 1 && + suggestions[0] instanceof ModifierEditor + ) { + let theOne = + index > 0 && ruleTiles[index - 1] instanceof ModifierEditor + ? (ruleTiles[index - 1] as ModifierEditor) + : (suggestions[0] as ModifierEditor) + newFieldEditor(theOne) + return + } + let onDelete = undefined + let selectedButton = -1 + if (index < ruleTiles.length) { + onDelete = () => { + tileUpdated(undefined) + } + const selected = btns.indexOf( + btns.find(b => b.icon === getIcon(getTid(ruleTiles[index]))) // TODO + ) + if (selected >= 0) { + selectedButton = selected + } + } + if (btns.length) { + this.editor.picker.setGroup(btns) + this.editor.picker.show({ + title: accessibility.ariaToTooltip(name), + navigator: () => new PickerNavigator(this.editor.picker), + onClick: idx => { + let theOne = suggestions[idx] + if (theOne instanceof ModifierEditor) { + // there is more work to do l + theOne = + index > 0 && + ruleTiles[index - 1] instanceof ModifierEditor + ? (ruleTiles[index - 1] as ModifierEditor) + : theOne + newFieldEditor(theOne) + } + tileUpdated(theOne) + }, + onDelete, + selected: selectedButton, + }) + } + return + } + + private handleRuleHandleMenuSelection(iconId: string) { + if (iconId === "plus") { + reportEvent("rule.add") + this.page.insertRuleAt(this.index) + } else if (iconId === "delete") { + reportEvent("rule.delete") + this.page.deleteRuleAt(this.index) + } + } + + private showWhenInsertMenu() { + if (this.ruledef.sensors.length) { + this.editTile("filters", this.ruledef.filters.length) + } else { + this.editTile("sensors", 0) + } + } + + private showDoInsertMenu() { + if (this.ruledef.actuators.length) { + this.editTile("modifiers", this.ruledef.modifiers.length) + } else { + this.editTile("actuators", 0) + } + } + + private getSuggestions(name: string, index: number) { + return Language.getTileSuggestions(this.ruledef, name, index) + } + + public getRuleButtons() { + // TODO: can this be done lazily instead? + const btns: Button[] = [] + btns.push(this.handleBtn) + this.ruleButtons.sensors.forEach(b => btns.push(b)) + this.ruleButtons.filters.forEach(b => btns.push(b)) + + if (this.whenInsertBtn) btns.push(this.whenInsertBtn) + + this.ruleButtons.actuators.forEach(b => btns.push(b)) + this.ruleButtons.modifiers.forEach(b => btns.push(b)) + + if (this.doInsertBtn) btns.push(this.doInsertBtn) + + return btns + } + + public isEmpty() { + return this.ruledef.isEmpty() + } + + update() { + if (this.queuedCursorMove) { + switch (this.queuedCursorMove) { + case CursorDir.Right: + control.raiseEvent(KEY_DOWN, controller.right.id) + break + // Add other cases as needed + } + this.queuedCursorMove = undefined + } + } + + public layout() { + const ruleRep = this.ruleButtons + const v = new Vec2() + this.whenBounds = new Bounds() + + const whenTiles = ruleRep.sensors.concat(ruleRep.filters) + const doTiles = ruleRep.actuators.concat(ruleRep.modifiers) + if (this.whenInsertBtn) whenTiles.push(this.whenInsertBtn) + if (this.doInsertBtn) doTiles.push(this.doInsertBtn) + + const firstWhenTile = whenTiles[0] + const lastWhenTile = whenTiles[whenTiles.length - 1] + + this.handleBtn.xfrm.localPos = v + v.x += this.handleBtn.width + this.whenBounds.left = v.x + + v.x += firstWhenTile.width >> 1 + v.x += 2 + + const layoutButtons = (btns: Button[]) => { + btns.forEach((btn, index) => { + if (index) { + v.x += btns[index - 1].width >> 1 + v.x += btn.width >> 1 + v.x += 1 + } + btn.xfrm.localPos = v + }) + } + + layoutButtons(whenTiles) + + v.x += lastWhenTile.bounds.width >> 1 + this.whenBounds.right = v.x + + v.x += this.arrow.bounds.width >> 1 + v.x += 1 + + this.arrow.xfrm.localPos.x = v.x + v.x += this.arrow.bounds.width + v.x += 2 + + layoutButtons(doTiles) + + if (this.doInsertBtn) { + this.doInsertBtn.xfrm.localPos = v + } + + this.bounds = undefined + + const updateSizeFromButtons = (btns: Button[]) => { + btns.forEach(btn => { + if (!this.bounds) { + this.bounds = btn.bounds + .clone() + .translate(btn.xfrm.localPos) + } else { + this.bounds.add( + Bounds.Translate(btn.bounds, btn.xfrm.localPos) + ) + } + }) + } + + updateSizeFromButtons(whenTiles) + updateSizeFromButtons(doTiles) + + if (!this.bounds) { + this.bounds = new Bounds() + } else { + this.bounds.grow(1) + } + + // Ensure that the rule "tray" is at least as wide as the screen + this.innerWidth = this.bounds.width + this.bounds.width = Math.max(this.bounds.width, Screen.WIDTH) + + this.whenBounds.left = this.bounds.left + this.whenBounds.top = this.bounds.top + this.whenBounds.height = this.bounds.height + } + + isOffScreen(): boolean { + const y = this.xfrm.worldPos.y + const b = this.bounds + return ( + y + b.top > Screen.BOTTOM_EDGE || y + b.bottom < Screen.TOP_EDGE + ) + } + + draw() { + if (this.isOffScreen()) return + + this.drawBackground() + this.handleBtn.draw() + if (this.whenInsertBtn) this.whenInsertBtn.draw() + this.arrow.draw() + if (this.doInsertBtn) this.doInsertBtn.draw() + repNames().forEach(name => { + const buttons = this.ruleButtons[name] + for (let i = 0; i < buttons.length; ++i) { + const btn = buttons[i] + if (!btn.isOffScreenX()) btn.draw() + } + }) + } + + private drawBackground() { + Screen.fillBoundsXfrm(this.xfrm, this.bounds, 11) + Screen.fillBoundsXfrm(this.xfrm, this.whenBounds, 13) + Screen.outlineBoundsXfrm(this.xfrm, this.bounds, 1, 12) + } + } +} \ No newline at end of file From bb6962a7f0130b8a67a2d60897e3b370e25ac2f4 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 7 Apr 2024 16:29:19 +0100 Subject: [PATCH 096/109] assets: adjusted MiroData logo: adjusting t --- assets.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets.ts b/assets.ts index 1fd00ba..137cca0 100644 --- a/assets.ts +++ b/assets.ts @@ -100,9 +100,9 @@ namespace microcode { ...1bbbbbbbbbb1bbbbbbbbbf1bbbbbf..............................................1bbbbf..bbbbbbf....................1bbbbbf............................... ...1bbbbbbbbbbbbbbbbbbbbf.bbbbff..............................................1bbbb....bbbbbbf...................1bbbbbf............................... ...1bbbbbbbbbbbbbbbbbbbbf..ffff.....1111111......1111...111.......1111111.....1bbbb.....1bbbbf....11111111.......1bbbbbb11111111....11111111........... - ...1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...1bbbb.....1bbbbf...1bbbbbbbbbf.....1bbbbbbbbbbbbfff..1bbbbbbbbbf......... - ...1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbb.....1bbbbf..1bbbbbbbbbbbbf...1bbbbbbbbbbbbf...1bbbbbbbbbbbbf....... - ...1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbb.....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbff........1bbbbbbbbbbbbbf....... + ...1bbbbbbbbbbbbbbbbbbbbf.1111....111bbbbbbb1...11bbbb.11bbb....111bbbbbbb1...1bbbb.....1bbbbf...1bbbbbbbbbf.....1bbbbbbbbbbbbbbf..1bbbbbbbbbf......... + ...1bbbbbbbbbbbbbbbbbbbbf11bbbb..11bbbbbbbbbbb..1bbbbbb1bbbbb..11bbbbbbbbbbb..1bbbb.....1bbbbf..1bbbbbbbbbbbbf...1bbbbbbbbbbbbbbf.1bbbbbbbbbbbbf....... + ...1bbbbbbfbbbbbfbbbbbbbf1bbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbbbbbbbbbbf.1bbbb.....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbbbbbbbbbf.1bbbbbbbbbbbbbf....... ...1bbbbbbf.bbbff1bbbbbbf1bbbbbf11bbbbbbbbbbbbb.1bbbbbbbbbbbbf11bbbbbbbbbbbbb.1bbbb.....1bbbbf.1bbbbbbbbbbbbbf...1bbbbbbf........1bbbbbbbbbbbbbbf...... ...1bbbbbbf..fff.1bbbbbbf1bbbbbf1bbbbbfffbbbbbbf1bbbbbfffbbbff1bbbbbfffbbbbbbfbbbbb.....1bbbbf.1bbbbffffbbbbbf...1bbbbbbf........1bbbbffffbbbbbbf...... ...1bbbbbbf......1bbbbbbf1bbbbbf1bbbbff...bbbbff1bbbbbf...fff.1bbbbff...bbbbbfbbbbb.....1bbbbf.1bbbff...1bbbbf...1bbbbbbf........1bbbbf...1bbbbbf...... From e964f348b3861816fa3390965d9c2fd3945eddab Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 7 Apr 2024 16:29:43 +0100 Subject: [PATCH 097/109] sensorSelect: implemented toggling sensors --- sensorSelect.ts | 162 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 32 deletions(-) diff --git a/sensorSelect.ts b/sensorSelect.ts index dc047c8..941ecb1 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -1,4 +1,22 @@ namespace microcode { + const SENSOR_LOOKUP_TABLE: {[ariaID: string]: Sensor} = { + "accelerometer X": new AccelerometerSensor(Dimension.X), + "accelerometer Y": new AccelerometerSensor(Dimension.Y), + "accelerometer Z": new AccelerometerSensor(Dimension.Z), + "Pitch": new RotationSensor(Rotation.Pitch), + "Roll": new RotationSensor(Rotation.Roll), + "Pin 0": new PinSensor(TouchPin.P0), + "Pin 1": new PinSensor(TouchPin.P1), + "Pin 2": new PinSensor(TouchPin.P2), + "led_light_sensor": new LightSensor(), + "thermometer": new TemperatureSensor(), + "S10": new MagnetSensor(Dimension.X), + "Logo Press": new LogoPressSensor(), + "Volume": new VolumeSensor(), + "Compass": new CompassHeadingSensor(), + "F3": new ButtonPressSensor() + } + /** * Responsible for allowing the user to select any number of sensors. * These sensors are passed to either the measurement screen or the live data view @@ -7,13 +25,13 @@ namespace microcode { */ export class SensorSelect extends CursorSceneWithPriorPage { private btns: Button[] - private selectedSensors: Sensor[] + private selectedSensorNames: string[] private nextSceneEnum: CursorSceneEnum constructor(app: App, nextSceneEnum: CursorSceneEnum) { super(app, function () {app.popScene(); app.pushScene(new Home(this.app))}) this.btns = [] - this.selectedSensors = [] + this.selectedSensorNames = [] this.nextSceneEnum = nextSceneEnum } @@ -28,12 +46,13 @@ namespace microcode { x: -60, y: -40, onClick: () => { - // if (this.btns[0].selected) { - // delete this.selectedSensors[this.selectedSensors.findIndex((sensor) => sensor.iconName == "accelerometer")] - // } - // else { - this.selectedSensors.push(new AccelerometerSensor(Dimension.X)) - // } + const index = this.selectedSensorNames.indexOf("accelerometer X") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("accelerometer X") + } }, dynamicBoundaryColorsOn: true, })) @@ -46,7 +65,13 @@ namespace microcode { x: -30, y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.Y)) + const index = this.selectedSensorNames.indexOf("accelerometer Y") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("accelerometer Y") + } }, dynamicBoundaryColorsOn: true, })) @@ -59,7 +84,13 @@ namespace microcode { x: 0, y: -40, onClick: () => { - this.selectedSensors.push(new AccelerometerSensor(Dimension.Z)) + const index = this.selectedSensorNames.indexOf("accelerometer Z") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("accelerometer Z") + } }, dynamicBoundaryColorsOn: true, })) @@ -72,7 +103,13 @@ namespace microcode { x: 30, y: -40, onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Pitch)) + const index = this.selectedSensorNames.indexOf("Pitch") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Pitch") + } }, dynamicBoundaryColorsOn: true, })) @@ -85,7 +122,13 @@ namespace microcode { x: 60, y: -40, onClick: () => { - this.selectedSensors.push(new RotationSensor(Rotation.Roll)) + const index = this.selectedSensorNames.indexOf("Roll") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Roll") + } }, dynamicBoundaryColorsOn: true, })) @@ -100,7 +143,13 @@ namespace microcode { x: -60, y: -11, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P0)) + const index = this.selectedSensorNames.indexOf("Pin 0") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Pin 0") + } }, dynamicBoundaryColorsOn: true, })) @@ -113,7 +162,13 @@ namespace microcode { x: -30, y: -11, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P1)) + const index = this.selectedSensorNames.indexOf("Pin 1") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Pin 1") + } }, dynamicBoundaryColorsOn: true, })) @@ -127,7 +182,13 @@ namespace microcode { x: 0, y: -11, onClick: () => { - this.selectedSensors.push(new PinSensor(TouchPin.P2)) + const index = this.selectedSensorNames.indexOf("Pin 2") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Pin 2") + } }, dynamicBoundaryColorsOn: true, })) @@ -141,7 +202,13 @@ namespace microcode { x: 30, y: -11, onClick: () => { - this.selectedSensors.push(new LightSensor()) + const index = this.selectedSensorNames.indexOf("led_light_sensor") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("led_light_sensor") + } }, dynamicBoundaryColorsOn: true, })) @@ -154,7 +221,13 @@ namespace microcode { x: 60, y: -11, onClick: () => { - this.selectedSensors.push(new TemperatureSensor()) + const index = this.selectedSensorNames.indexOf("thermometer") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("thermometer") + } }, dynamicBoundaryColorsOn: true, })) @@ -169,7 +242,13 @@ namespace microcode { x: -60, y: 18, onClick: () => { - this.selectedSensors.push(new MagnetSensor(Dimension.X)) + const index = this.selectedSensorNames.indexOf("S10") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("S10") + } }, dynamicBoundaryColorsOn: true, })) @@ -182,7 +261,13 @@ namespace microcode { x: -30, y: 18, onClick: () => { - this.selectedSensors.push(new LogoPressSensor()) + const index = this.selectedSensorNames.indexOf("Logo Press") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Logo Press") + } }, dynamicBoundaryColorsOn: true, })) @@ -195,7 +280,13 @@ namespace microcode { x: 0, y: 18, onClick: () => { - this.selectedSensors.push(new VolumeSensor()) + const index = this.selectedSensorNames.indexOf("Volume") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Volume") + } }, dynamicBoundaryColorsOn: true, })) @@ -208,7 +299,13 @@ namespace microcode { x: 30, y: 18, onClick: () => { - this.selectedSensors.push(new CompassHeadingSensor()) + const index = this.selectedSensorNames.indexOf("Compass") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("Compass") + } }, dynamicBoundaryColorsOn: true, })) @@ -221,7 +318,13 @@ namespace microcode { x: 60, y: 18, onClick: () => { - this.selectedSensors.push(new ButtonPressSensor()) + const index = this.selectedSensorNames.indexOf("F3") + if (index != -1) { + this.selectedSensorNames.splice(index, 1) + } + else { + this.selectedSensorNames.push("F3") + } }, dynamicBoundaryColorsOn: true, })) @@ -236,29 +339,24 @@ namespace microcode { x: 60, y: 44, onClick: () => { - if (this.selectedSensors.length === 0) { + if (this.selectedSensorNames.length === 0) { return } - + const sensors = this.selectedSensorNames.map((name) => SENSOR_LOOKUP_TABLE[name]) this.app.popScene() if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, this.selectedSensors)) + this.app.pushScene(new LiveDataViewer(app, sensors)) } else { - this.app.pushScene(new RecordingConfigSelection(app, this.selectedSensors)) + this.app.pushScene(new RecordingConfigSelection(app, sensors)) } } })) this.navigator.addButtons(this.btns) } - - - private handleNewSensor() { - - } - + draw() { Screen.fillRect( Screen.LEFT_EDGE, From 2af090601cd20b3174aa74502735ada38ed331a8 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Sun, 7 Apr 2024 16:30:30 +0100 Subject: [PATCH 098/109] sensors & home: bumped to prototype 12 & fixed pin names (pin 101 -> pin 1). --- home.ts | 4 ++-- sensors.ts | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/home.ts b/home.ts index 3320653..503944a 100644 --- a/home.ts +++ b/home.ts @@ -58,8 +58,8 @@ namespace microcode { private drawVersion() { const font = simage.font5 Screen.print( - "Prototype 11", - Screen.RIGHT_EDGE - font.charWidth * "Prototype 11".length, + "Prototype 12", + Screen.RIGHT_EDGE - font.charWidth * "Prototype 12".length, Screen.BOTTOM_EDGE - font.charHeight - 2, 0xb, font diff --git a/sensors.ts b/sensors.ts index 7c65bad..d70692e 100644 --- a/sensors.ts +++ b/sensors.ts @@ -207,11 +207,12 @@ namespace microcode { }) return res }, - "Pin " + pin.toString(), + // Pins are 0, 1, 2 = 100, 101, 102 + "Pin " + (pin % 100), 0, 1, - "pin_" + pin.toString(), - "Pin " + pin.toString() + "pin_" + (pin % 100), + "Pin " + (pin % 100) ) } } From b79657bb8e322221a5dcb312643bf90d404e5564 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 15:13:23 +0100 Subject: [PATCH 099/109] Updated app -> this.app for pertinent cases, was raised as an error in MakeCode. Added basic.showString() when home.ts is loaded for testing MakeCode. --- dataViewSelect.ts | 12 ++++++------ home.ts | 3 +++ liveDataViewer.ts | 4 ++-- sensorSelect.ts | 4 ++-- sensors.ts | 6 ++++-- tabularDataViewer.ts | 4 ++-- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/dataViewSelect.ts b/dataViewSelect.ts index 00d1b1b..1f628c5 100644 --- a/dataViewSelect.ts +++ b/dataViewSelect.ts @@ -40,8 +40,8 @@ namespace microcode { x: -50, y: 30, onClick: () => { - app.popScene() - app.pushScene(new TabularDataViewer(this.app, DATA_VIEW_DISPLAY_MODE.METADATA_VIEW)) + this.app.popScene() + this.app.pushScene(new TabularDataViewer(this.app, DATA_VIEW_DISPLAY_MODE.METADATA_VIEW)) }, boundaryColor: 7, }) @@ -54,8 +54,8 @@ namespace microcode { x: 0, y: 30, onClick: () => { - app.popScene() - app.pushScene(new TabularDataViewer(this.app, DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW)) + this.app.popScene() + this.app.pushScene(new TabularDataViewer(this.app, DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW)) }, boundaryColor: 7, }) @@ -68,8 +68,8 @@ namespace microcode { x: 50, y: 30, onClick: () => { - app.popScene() - app.pushScene(new GraphGenerator(this.app)) + this.app.popScene() + this.app.pushScene(new GraphGenerator(this.app)) }, boundaryColor: 7, }) diff --git a/home.ts b/home.ts index 503944a..d36850d 100644 --- a/home.ts +++ b/home.ts @@ -11,6 +11,9 @@ namespace microcode { /* override */ startup() { super.startup() + // MicroData loading test: + basic.showString("MicroData Home") + this.liveDataBtn = new Button({ parent: null, style: ButtonStyles.Transparent, diff --git a/liveDataViewer.ts b/liveDataViewer.ts index 89f68be..ddd2a7e 100644 --- a/liveDataViewer.ts +++ b/liveDataViewer.ts @@ -112,8 +112,8 @@ namespace microcode { controller.B.id, () => { if (this.windowHeight <= Screen.HEIGHT && this.windowWidth <= Screen.WIDTH) { - app.popScene() - app.pushScene(new Home(app)) + this.app.popScene() + this.app.pushScene(new Home(this.app)) } else { diff --git a/sensorSelect.ts b/sensorSelect.ts index 941ecb1..71072e2 100644 --- a/sensorSelect.ts +++ b/sensorSelect.ts @@ -345,11 +345,11 @@ namespace microcode { const sensors = this.selectedSensorNames.map((name) => SENSOR_LOOKUP_TABLE[name]) this.app.popScene() if (this.nextSceneEnum === CursorSceneEnum.LiveDataViewer) { - this.app.pushScene(new LiveDataViewer(app, sensors)) + this.app.pushScene(new LiveDataViewer(this.app, sensors)) } else { - this.app.pushScene(new RecordingConfigSelection(app, sensors)) + this.app.pushScene(new RecordingConfigSelection(this.app, sensors)) } } })) diff --git a/sensors.ts b/sensors.ts index d70692e..152bfb5 100644 --- a/sensors.ts +++ b/sensors.ts @@ -91,7 +91,7 @@ namespace microcode { } if (this.loggingMode == SensorLoggingMode.EVENTS) { - this.logEvents(this.config as EventConfig) + this.logEvent(this.config as EventConfig) } else { @@ -101,6 +101,8 @@ namespace microcode { } private logData(config: RecordingConfig) { + // datalogger. + while (config.measurements > 0) { FauxDataLogger.log([ this.name, @@ -113,7 +115,7 @@ namespace microcode { } } - private logEvents(config: EventConfig) { + private logEvent(config: EventConfig) { let sensorEventFunction = sensorEventFunctionLookup[config.inequality] while (config.measurements > 0) { diff --git a/tabularDataViewer.ts b/tabularDataViewer.ts index 5268e7f..566c683 100644 --- a/tabularDataViewer.ts +++ b/tabularDataViewer.ts @@ -50,8 +50,8 @@ namespace microcode { this.guiState = DATA_VIEW_DISPLAY_MODE.TABULAR_DATA_VIEW } else { - app.popScene() - app.pushScene(new DataViewSelect(this.app)) + this.app.popScene() + this.app.pushScene(new DataViewSelect(this.app)) } } ) From c44c70de6c045e098a5b1c709295582feb7c762b Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 15:18:42 +0100 Subject: [PATCH 100/109] home.ts: temporarily removed this.app.pushScene() to test dependencies in MakeCode. --- home.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/home.ts b/home.ts index d36850d..f34d765 100644 --- a/home.ts +++ b/home.ts @@ -12,7 +12,7 @@ namespace microcode { super.startup() // MicroData loading test: - basic.showString("MicroData Home") + basic.showString("Home") this.liveDataBtn = new Button({ parent: null, @@ -22,8 +22,8 @@ namespace microcode { x: -50, y: 30, onClick: () => { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + // this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) }, }) @@ -35,8 +35,8 @@ namespace microcode { x: 0, y: 30, onClick: () => { - this.app.popScene() - this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + // this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) }, }) @@ -48,8 +48,8 @@ namespace microcode { x: 50, y: 30, onClick: () => { - this.app.popScene() - this.app.pushScene(new DataViewSelect(this.app)) + // this.app.popScene() + // this.app.pushScene(new DataViewSelect(this.app)) }, }) From 97664cadc60a82bbb0ee8033a3e76a2746803883 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 15:33:33 +0100 Subject: [PATCH 101/109] home.ts: temporarily commented .draw() for MakeCode testing. --- home.ts | 86 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/home.ts b/home.ts index f34d765..e071b65 100644 --- a/home.ts +++ b/home.ts @@ -78,51 +78,51 @@ namespace microcode { Screen.HEIGHT, 0xc ) - this.yOffset = Math.min(0, this.yOffset + 2) - const t = control.millis() - const dy = this.yOffset == 0 ? (Math.idiv(t, 800) & 1) - 1 : 0 - const margin = 2 - const OFFSET = (Screen.HEIGHT >> 1) - wordLogo.height - margin - const y = Screen.TOP_EDGE + OFFSET //+ dy - Screen.drawTransparentImage( - wordLogo, - Screen.LEFT_EDGE + ((Screen.WIDTH - wordLogo.width) >> 1)// + dy - , - y + this.yOffset - ) - Screen.drawTransparentImage( - microbitLogo, - Screen.LEFT_EDGE + - ((Screen.WIDTH - microbitLogo.width) >> 1) + dy - , - y - wordLogo.height + this.yOffset + margin - ) - if (!this.yOffset) { - const tagline = resolveTooltip("tagline") - Screen.print( - tagline, - Screen.LEFT_EDGE + - ((Screen.WIDTH + wordLogo.width) >> 1) - + dy - - - microcode.font.charWidth * tagline.length, - Screen.TOP_EDGE + - OFFSET + - wordLogo.height + - dy + - this.yOffset + - 1, - 0xb, - microcode.font - ) - } + // this.yOffset = Math.min(0, this.yOffset + 2) + // const t = control.millis() + // const dy = this.yOffset == 0 ? (Math.idiv(t, 800) & 1) - 1 : 0 + // const margin = 2 + // const OFFSET = (Screen.HEIGHT >> 1) - wordLogo.height - margin + // const y = Screen.TOP_EDGE + OFFSET //+ dy + // Screen.drawTransparentImage( + // wordLogo, + // Screen.LEFT_EDGE + ((Screen.WIDTH - wordLogo.width) >> 1)// + dy + // , + // y + this.yOffset + // ) + // Screen.drawTransparentImage( + // microbitLogo, + // Screen.LEFT_EDGE + + // ((Screen.WIDTH - microbitLogo.width) >> 1) + dy + // , + // y - wordLogo.height + this.yOffset + margin + // ) + // if (!this.yOffset) { + // const tagline = resolveTooltip("tagline") + // Screen.print( + // tagline, + // Screen.LEFT_EDGE + + // ((Screen.WIDTH + wordLogo.width) >> 1) + // + dy + // - + // microcode.font.charWidth * tagline.length, + // Screen.TOP_EDGE + + // OFFSET + + // wordLogo.height + + // dy + + // this.yOffset + + // 1, + // 0xb, + // microcode.font + // ) + // } - this.recordDataBtn.draw() - this.liveDataBtn.draw() - this.viewBtn.draw() + // this.recordDataBtn.draw() + // this.liveDataBtn.draw() + // this.viewBtn.draw() - this.drawVersion() - super.draw() + // this.drawVersion() + // super.draw() } } } From 40ed2ccc5c01e4a09567dbe58cc6944df990758d Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 15:44:46 +0100 Subject: [PATCH 102/109] home.ts: temporarily commented .draw() for MakeCode testing. --- home.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/home.ts b/home.ts index e071b65..5ef10a7 100644 --- a/home.ts +++ b/home.ts @@ -69,7 +69,7 @@ namespace microcode { ) } - private yOffset = -Screen.HEIGHT >> 1 + // private yOffset = -Screen.HEIGHT >> 1 draw() { Screen.fillRect( Screen.LEFT_EDGE, @@ -117,12 +117,12 @@ namespace microcode { // ) // } - // this.recordDataBtn.draw() - // this.liveDataBtn.draw() - // this.viewBtn.draw() + this.recordDataBtn.draw() + this.liveDataBtn.draw() + this.viewBtn.draw() - // this.drawVersion() - // super.draw() + this.drawVersion() + super.draw() } } } From 0bf360fdbb019a055376e5929d983a5112fc6c46 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 15:49:26 +0100 Subject: [PATCH 103/109] home.ts: temporarily commented .draw() for MakeCode testing. --- home.ts | 82 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/home.ts b/home.ts index 5ef10a7..235e400 100644 --- a/home.ts +++ b/home.ts @@ -14,48 +14,48 @@ namespace microcode { // MicroData loading test: basic.showString("Home") - this.liveDataBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "linear_graph_1", - ariaId: "linear_graph", - x: -50, - y: 30, - onClick: () => { - // this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - }, - }) + // this.liveDataBtn = new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "linear_graph_1", + // ariaId: "linear_graph", + // x: -50, + // y: 30, + // onClick: () => { + // // this.app.popScene() + // // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + // }, + // }) - this.recordDataBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "edit_program", - ariaId: "Record", - x: 0, - y: 30, - onClick: () => { - // this.app.popScene() - // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - }, - }) + // this.recordDataBtn = new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "edit_program", + // ariaId: "Record", + // x: 0, + // y: 30, + // onClick: () => { + // // this.app.popScene() + // // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + // }, + // }) - this.viewBtn = new Button({ - parent: null, - style: ButtonStyles.Transparent, - icon: "largeDisk", - ariaId: "View", - x: 50, - y: 30, - onClick: () => { - // this.app.popScene() - // this.app.pushScene(new DataViewSelect(this.app)) - }, - }) + // this.viewBtn = new Button({ + // parent: null, + // style: ButtonStyles.Transparent, + // icon: "largeDisk", + // ariaId: "View", + // x: 50, + // y: 30, + // onClick: () => { + // // this.app.popScene() + // // this.app.pushScene(new DataViewSelect(this.app)) + // }, + // }) - const btns: Button[] = [this.liveDataBtn, this.recordDataBtn, this.viewBtn] + // const btns: Button[] = [this.liveDataBtn, this.recordDataBtn, this.viewBtn] - this.navigator.addButtons(btns) + // this.navigator.addButtons(btns) } private drawVersion() { @@ -117,9 +117,9 @@ namespace microcode { // ) // } - this.recordDataBtn.draw() - this.liveDataBtn.draw() - this.viewBtn.draw() + // this.recordDataBtn.draw() + // this.liveDataBtn.draw() + // this.viewBtn.draw() this.drawVersion() super.draw() From dd1cef15f2b225a41267880a56b85b05be47cc9f Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 17:01:37 +0100 Subject: [PATCH 104/109] home.ts: temporarily commented .draw() for MakeCode testing. --- home.ts | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/home.ts b/home.ts index 235e400..2b0e2a1 100644 --- a/home.ts +++ b/home.ts @@ -69,7 +69,7 @@ namespace microcode { ) } - // private yOffset = -Screen.HEIGHT >> 1 + private yOffset = -Screen.HEIGHT >> 1 draw() { Screen.fillRect( Screen.LEFT_EDGE, @@ -79,10 +79,10 @@ namespace microcode { 0xc ) // this.yOffset = Math.min(0, this.yOffset + 2) - // const t = control.millis() - // const dy = this.yOffset == 0 ? (Math.idiv(t, 800) & 1) - 1 : 0 - // const margin = 2 - // const OFFSET = (Screen.HEIGHT >> 1) - wordLogo.height - margin + const t = control.millis() + const dy = this.yOffset == 0 ? (Math.idiv(t, 800) & 1) - 1 : 0 + const margin = 2 + const OFFSET = (Screen.HEIGHT >> 1) - wordLogo.height - margin // const y = Screen.TOP_EDGE + OFFSET //+ dy // Screen.drawTransparentImage( // wordLogo, @@ -98,31 +98,31 @@ namespace microcode { // y - wordLogo.height + this.yOffset + margin // ) // if (!this.yOffset) { - // const tagline = resolveTooltip("tagline") - // Screen.print( - // tagline, - // Screen.LEFT_EDGE + - // ((Screen.WIDTH + wordLogo.width) >> 1) - // + dy - // - - // microcode.font.charWidth * tagline.length, - // Screen.TOP_EDGE + - // OFFSET + - // wordLogo.height + - // dy + - // this.yOffset + - // 1, - // 0xb, - // microcode.font - // ) + const tagline = resolveTooltip("tagline") + Screen.print( + tagline, + Screen.LEFT_EDGE + + ((Screen.WIDTH + wordLogo.width) >> 1) + + dy + - + microcode.font.charWidth * tagline.length, + Screen.TOP_EDGE + + OFFSET + + wordLogo.height + + dy + + this.yOffset + + 1, + 0xb, + microcode.font + ) // } // this.recordDataBtn.draw() // this.liveDataBtn.draw() // this.viewBtn.draw() - this.drawVersion() - super.draw() + // this.drawVersion() + // super.draw() } } } From d65a1d8255aee61c415c686da476c0b6b62acf19 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 17:29:34 +0100 Subject: [PATCH 105/109] home.ts: MakeCode testing. --- home.ts | 120 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/home.ts b/home.ts index 2b0e2a1..f34d765 100644 --- a/home.ts +++ b/home.ts @@ -14,48 +14,48 @@ namespace microcode { // MicroData loading test: basic.showString("Home") - // this.liveDataBtn = new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "linear_graph_1", - // ariaId: "linear_graph", - // x: -50, - // y: 30, - // onClick: () => { - // // this.app.popScene() - // // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) - // }, - // }) + this.liveDataBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "linear_graph_1", + ariaId: "linear_graph", + x: -50, + y: 30, + onClick: () => { + // this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.LiveDataViewer)) + }, + }) - // this.recordDataBtn = new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "edit_program", - // ariaId: "Record", - // x: 0, - // y: 30, - // onClick: () => { - // // this.app.popScene() - // // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) - // }, - // }) + this.recordDataBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "edit_program", + ariaId: "Record", + x: 0, + y: 30, + onClick: () => { + // this.app.popScene() + // this.app.pushScene(new SensorSelect(this.app, CursorSceneEnum.MeasurementConfigSelect)) + }, + }) - // this.viewBtn = new Button({ - // parent: null, - // style: ButtonStyles.Transparent, - // icon: "largeDisk", - // ariaId: "View", - // x: 50, - // y: 30, - // onClick: () => { - // // this.app.popScene() - // // this.app.pushScene(new DataViewSelect(this.app)) - // }, - // }) + this.viewBtn = new Button({ + parent: null, + style: ButtonStyles.Transparent, + icon: "largeDisk", + ariaId: "View", + x: 50, + y: 30, + onClick: () => { + // this.app.popScene() + // this.app.pushScene(new DataViewSelect(this.app)) + }, + }) - // const btns: Button[] = [this.liveDataBtn, this.recordDataBtn, this.viewBtn] + const btns: Button[] = [this.liveDataBtn, this.recordDataBtn, this.viewBtn] - // this.navigator.addButtons(btns) + this.navigator.addButtons(btns) } private drawVersion() { @@ -78,26 +78,26 @@ namespace microcode { Screen.HEIGHT, 0xc ) - // this.yOffset = Math.min(0, this.yOffset + 2) + this.yOffset = Math.min(0, this.yOffset + 2) const t = control.millis() const dy = this.yOffset == 0 ? (Math.idiv(t, 800) & 1) - 1 : 0 const margin = 2 const OFFSET = (Screen.HEIGHT >> 1) - wordLogo.height - margin - // const y = Screen.TOP_EDGE + OFFSET //+ dy - // Screen.drawTransparentImage( - // wordLogo, - // Screen.LEFT_EDGE + ((Screen.WIDTH - wordLogo.width) >> 1)// + dy - // , - // y + this.yOffset - // ) - // Screen.drawTransparentImage( - // microbitLogo, - // Screen.LEFT_EDGE + - // ((Screen.WIDTH - microbitLogo.width) >> 1) + dy - // , - // y - wordLogo.height + this.yOffset + margin - // ) - // if (!this.yOffset) { + const y = Screen.TOP_EDGE + OFFSET //+ dy + Screen.drawTransparentImage( + wordLogo, + Screen.LEFT_EDGE + ((Screen.WIDTH - wordLogo.width) >> 1)// + dy + , + y + this.yOffset + ) + Screen.drawTransparentImage( + microbitLogo, + Screen.LEFT_EDGE + + ((Screen.WIDTH - microbitLogo.width) >> 1) + dy + , + y - wordLogo.height + this.yOffset + margin + ) + if (!this.yOffset) { const tagline = resolveTooltip("tagline") Screen.print( tagline, @@ -115,14 +115,14 @@ namespace microcode { 0xb, microcode.font ) - // } + } - // this.recordDataBtn.draw() - // this.liveDataBtn.draw() - // this.viewBtn.draw() + this.recordDataBtn.draw() + this.liveDataBtn.draw() + this.viewBtn.draw() - // this.drawVersion() - // super.draw() + this.drawVersion() + super.draw() } } } From a169ffa28dcc66315d6b1d35b650a8b7a3f3723e Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 17:52:20 +0100 Subject: [PATCH 106/109] home.ts & app.ts: Increased basic.pause() interval delay to 10ms to comabt loading issue. Reverted home.ts back. Continuing MakeCode testing. --- app.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.ts b/app.ts index 937c721..8cbc80e 100644 --- a/app.ts +++ b/app.ts @@ -12,11 +12,11 @@ namespace microcode { constructor() { // One interval delay to ensure all static constructors have executed. - basic.pause(5) + basic.pause(10) reportEvent("app.start") this.sceneManager = new SceneManager() this.pushScene(new Home(this)) - // this.pushScene(new SensorSelect(this)) + // this.pushScene(new SensorSelect(this, CursorSceneEnum.LiveDataViewer)) } public saveBuffer(slot: string, buf: Buffer) { From 25a1208d0399ffb6b3e022ab01df6dc58d3a337b Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 18:07:19 +0100 Subject: [PATCH 107/109] home.ts & app.ts: Increased basic.pause() interval delay to 10ms to comabt loading issue. Removed elements of home.ts buttons. Continuing MakeCode testing. --- app.ts | 2 +- home.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app.ts b/app.ts index 8cbc80e..2598676 100644 --- a/app.ts +++ b/app.ts @@ -12,7 +12,7 @@ namespace microcode { constructor() { // One interval delay to ensure all static constructors have executed. - basic.pause(10) + basic.pause(30) reportEvent("app.start") this.sceneManager = new SceneManager() this.pushScene(new Home(this)) diff --git a/home.ts b/home.ts index f34d765..2a909ae 100644 --- a/home.ts +++ b/home.ts @@ -16,7 +16,7 @@ namespace microcode { this.liveDataBtn = new Button({ parent: null, - style: ButtonStyles.Transparent, + // style: ButtonStyles.Transparent, icon: "linear_graph_1", ariaId: "linear_graph", x: -50, @@ -29,7 +29,7 @@ namespace microcode { this.recordDataBtn = new Button({ parent: null, - style: ButtonStyles.Transparent, + // style: ButtonStyles.Transparent, icon: "edit_program", ariaId: "Record", x: 0, @@ -42,7 +42,7 @@ namespace microcode { this.viewBtn = new Button({ parent: null, - style: ButtonStyles.Transparent, + // style: ButtonStyles.Transparent, icon: "largeDisk", ariaId: "View", x: 50, From 66f69a7a4175f02bc4783dd05af375f6719daa47 Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 19:39:27 +0100 Subject: [PATCH 108/109] main.ts: removing pause(1) for MakeCode test. --- main.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main.ts b/main.ts index 2d23a03..7dc499f 100644 --- a/main.ts +++ b/main.ts @@ -1,2 +1 @@ -basic.pause(1) -const app = new microcode.App() +const app = new microcode.App() \ No newline at end of file From 678cd6882a6fa69b0ae56e3541eebc45194110fd Mon Sep 17 00:00:00 2001 From: Kier Palin Date: Tue, 16 Apr 2024 19:41:46 +0100 Subject: [PATCH 109/109] main.ts: removed for MakeCode test. --- main.ts | 1 - 1 file changed, 1 deletion(-) delete mode 100644 main.ts diff --git a/main.ts b/main.ts deleted file mode 100644 index 7dc499f..0000000 --- a/main.ts +++ /dev/null @@ -1 +0,0 @@ -const app = new microcode.App() \ No newline at end of file