Skip to content

Commit

Permalink
Change pins on wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
pipe01 committed Jan 30, 2025
1 parent d136d07 commit 8d01e61
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 67 deletions.
2 changes: 2 additions & 0 deletions frontend/wasm/infiniemu.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const module: EmscriptenModuleFactory<EmscriptenModule & {
_pins_set(pin: Pins, pinNumber: number): void;
_pins_clear(pin: Pins, pinNumber: number): void;
_pins_read_all(pin: Pins): number;
_pins_get_voltage(pin: Pins, pinNumber: number): number;
_pins_set_voltage(pin: Pins, pinNumber: number, mv: number): void;

_spinorflash_get_buffer(flash: SPINorFlash): Pointer;
_spinorflash_get_buffer_size(flash: SPINorFlash): number;
Expand Down
5 changes: 3 additions & 2 deletions frontend/wasm/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type MessageToWorkerType = { messageId?: number } & (
{ type: "stop", data: void } |
{ type: "doTouch", data: { gesture: number, x: number, y: number } } |
{ type: "clearTouch", data: void } |
{ type: "setPin", data: { pin: number, value: boolean } } |
{ type: "setPinVoltage", data: { pin: number, value: number } } |
{ type: "setProgram", data: ArrayBuffer } |
{ type: "readDir", data: string } |
{ type: "readFile", data: string } |
Expand All @@ -36,8 +36,9 @@ export type MessageFromWorkerType = { replyToId?: number } & (
{ type: "rttData", data: string } |
{ type: "lcdSleeping", data: boolean } |
{ type: "cpuSleeping", data: boolean } |
{ type: "performance", data: { loopTime: number, cps: number, totalSRAM: number, pins: number } } |
{ type: "performance", data: { loopTime: number, cps: number, totalSRAM: number } } |
{ type: "backupData", data: ArrayBuffer } |
{ type: "commandOutput", data: string } |
{ type: "pins", data: (number | boolean)[] } |
{ type: "aborted", data: any }
);
41 changes: 35 additions & 6 deletions frontend/wasm/src/components/Emulator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,31 @@ template(v-if="!isReady")
.card.mt-3(v-if="isStarted")
.card-body
h3.card-title Console
.text-danger(v-if="!foundRTT") Couldn't find Segger RTT block in memory
.text-danger(v-if="!foundRTT") Couldn't find Segger RTT block in memory. This probably means that your program doesn't have RTT/logging enabled.

Console(:lines="consoleLines" canRunCommands style="height: 400px" @runCommand="sendMessage(worker, 'runCommand', $event)")

.card.mt-3(v-if="isStarted")
.card-body
h3.card-title Pins
table.table.table-bordered.table-striped
thead
tr
th Pin
th Name
th Mode
th Value
tbody
tr(v-for="(value, index) in pins")
td {{ pinetimePins[index].number }}
td {{ pinetimePins[index].name }}
td {{ pinetimePins[index].dir == "i" ? "Input" : pinetimePins[index].dir == "o" ? "Output" : "Input & Output" }}{{ pinetimePins[index].analog ? " (analog)" : "" }}
td
input(v-if="!pinetimePins[index].analog" type="checkbox" :disabled="!pinetimePins[index].canChange" :checked="value" @change="setPin(pinetimePins[index].number, $event.target.checked)")
template(v-else)
input(type="range" :disabled="!pinetimePins[index].canChange" :value="value" min="0" max="4000" @input="setPin(pinetimePins[index].number, $event.target.value / 1000)")
span {{ (value / 1000).toFixed(2) }} V

.col(style="flex-grow: 0")
Display(:width="240" :height="240" :off="isLcdOff" @got-canvas="onGotCanvas"
@button-down="onButtonDown" @start-swipe="onStartSwipe" @end-swipe="clearTouch"
Expand All @@ -36,7 +57,6 @@ template(v-if="!isReady")
div Loop time: {{ performance.loopTime.value.toFixed(0) }} ms
div CPU: {{ isCpuSleeping ? "Sleeping" : "Running" }}
div RAM size: {{ numberFmt.format(performance.sramSize.value) }} bytes
div {{ pins.toString(2) }}

.card.mt-3(v-if="isRunning")
.card-body
Expand Down Expand Up @@ -76,7 +96,7 @@ import Console, { type Line } from "@/components/Console.vue";
import FileBrowser from "@/components/FileBrowser.vue";
import { sendMessage, sendMessageAndWait, useAverage } from "@/utils";
import { type MessageFromWorkerType } from "@/common";
import { PinetimePins } from "@/pinetime";
import { pinetimePins } from "@/pinetime";
const props = defineProps<{
programFile: ArrayBuffer,
Expand All @@ -94,6 +114,8 @@ const GESTURE_SINGLETAP = 0x05;
const GESTURE_DOUBLETAP = 0x0B;
const GESTURE_LONGPRESS = 0x0C;
const HIGH_VOLTAGE = 3;
const numberFmt = new Intl.NumberFormat();
const isReady = ref(false);
Expand All @@ -108,7 +130,7 @@ const isCpuSleeping = ref(false);
const foundRTT = ref(false);
const pins = ref(0);
const pins = ref<(number | boolean)[]>([]);
const consoleLines = ref<Line[]>([]);
Expand Down Expand Up @@ -177,7 +199,10 @@ worker.onmessage = async (event) => {
performance.cps.value = data.cps;
performance.loopTime.value = data.loopTime;
performance.sramSize.value = data.totalSRAM;
pins.value = data.pins;
break;
case "pins":
pins.value = data;
break;
case "rttFound":
Expand Down Expand Up @@ -225,7 +250,7 @@ function onFileLoadEnd() {
}
function onButtonDown(isDown: boolean) {
sendMessage(worker, "setPin", { pin: PinetimePins.Button, value: isDown });
sendMessage(worker, "setPinVoltage", { pin: 13, value: isDown ? HIGH_VOLTAGE : 0 });
}
const swipeCenter = (direction: Direction) => {
Expand Down Expand Up @@ -266,4 +291,8 @@ function onStartTouch(x: number, y: number, isLongPress = false) {
function reset() {
sendMessage(worker, "reset", undefined);
}
function setPin(index: number, value: boolean | number) {
sendMessage(worker, "setPinVoltage", { pin: index, value: typeof value === "boolean" ? (value ? HIGH_VOLTAGE : 0) : value });
}
</script>
64 changes: 41 additions & 23 deletions frontend/wasm/src/pinetime.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
// https://github.com/InfiniTimeOrg/InfiniTime/blob/7b39d81c8c03d14a950b844e2b8cb15107df92bf/src/drivers/PinMap.h
export enum PinetimePins {
Charging = 12,
Cst816sReset = 10,
Button = 13,
ButtonEnable = 15,
Cst816sIrq = 28,
PowerPresent = 19,
Bma421Irq = 8,
Motor = 16,
LcdBacklightLow = 14,
LcdBacklightMedium = 22,
LcdBacklightHigh = 23,
SpiSck = 2,
SpiMosi = 3,
SpiMiso = 4,
SpiFlashCsn = 5,
SpiLcdCsn = 25,
LcdDataCommand = 18,
LcdReset = 26,
TwiScl = 7,
TwiSda = 6,
};
// From the perspective of the MCU
export type PinDirection = "i" | "o" | "io";

export function isInput(dir: PinDirection) {
return dir == "i" || dir == "io";
}

export function isOutput(dir: PinDirection) {
return dir == "o" || dir == "io";
}

export type Pin = { number: number; name: string; } & (
{ dir: "i"; canChange?: boolean; analog?: false; pull?: "up" | "down" } |
{ dir: "i"; canChange?: boolean; analog: true, intialValue?: number } |
{ dir: "o"; } |
{ dir: "io"; canChange?: boolean; }
);

export const pinetimePins: Pin[] = [
{ number: 2, name: "SpiSck", dir: "o" },
{ number: 3, name: "SpiMosi", dir: "o" },
{ number: 4, name: "SpiMiso", dir: "i" },
{ number: 5, name: "SpiFlashCsn", dir: "o" },
{ number: 6, name: "TwiSda", dir: "io" },
{ number: 7, name: "TwiScl", dir: "io" },
{ number: 8, name: "Bma421Irq", dir: "i" },
{ number: 10, name: "Cst816sReset", dir: "o" },
{ number: 12, name: "Charging", dir: "i", canChange: true, pull: "up" },
{ number: 13, name: "Button", dir: "i", canChange: true },
{ number: 14, name: "LcdBacklightLow", dir: "o" },
{ number: 15, name: "ButtonEnable", dir: "o" },
{ number: 16, name: "Motor", dir: "o" },
{ number: 18, name: "LcdDataCommand", dir: "o" },
{ number: 19, name: "PowerPresent", dir: "i", canChange: true, pull: "up" },
{ number: 22, name: "LcdBacklightMedium", dir: "o" },
{ number: 23, name: "LcdBacklightHigh", dir: "o" },
{ number: 25, name: "SpiLcdCsn", dir: "o" },
{ number: 26, name: "LcdReset", dir: "o" },
{ number: 28, name: "Cst816sIrq", dir: "i" },
{ number: 31, name: "BatteryVoltage", dir: "i", canChange: true, analog: true, intialValue: 3.9 / 2 },
];
33 changes: 26 additions & 7 deletions frontend/wasm/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { CPU, CST816S, Commander, LFS, NRF52832, Pinetime, Pins, Pointer, Program, RTT, SPINorFlash, ST7789 } from "../infiniemu.js"
import createModule from "../infiniemu.js"
import type { FileInfo, MessageFromWorkerType, MessageToWorkerType } from "./common";
import { pinetimePins } from "./pinetime.js";
import { getZipOrNested, isFile, joinLFSPaths } from "./utils";

const iterations = 100000;
Expand Down Expand Up @@ -115,6 +116,20 @@ class Emulator {
this.displayBuffer = numberToPointer(Module._malloc(240 * 240 * 2));
this.rgbaBuffer = numberToPointer(Module._malloc(240 * 240 * 4));
this.rttReadBuffer = numberToPointer(Module._malloc(this.rttReadBufferSize));

this.reset();

for (const pin of pinetimePins) {
if (pin.dir == "i" && pin.analog && pin.intialValue) {
this.Module._pins_set_voltage(this.pins, pin.number, pin.intialValue * 1000);
}
else if (pin.dir == "i" && !pin.analog && pin.pull) {
if (pin.pull == "up")
this.Module._pins_set(this.pins, pin.number);
else
this.Module._pins_clear(this.pins, pin.number);
}
}
}

private doLoop(cycles: number) {
Expand Down Expand Up @@ -169,8 +184,14 @@ class Emulator {
loopTime: end - start,
cps: (this.cycleCount - cycleCountStart) / ((end - start) / 1000),
totalSRAM: this.Module._nrf52832_get_sram_size(this.nrf52),
pins: this.Module._pins_read_all(this.pins),
});

const allPins = this.Module._pins_read_all(this.pins);
sendMessage("pins", pinetimePins.map(pin => {
if (pin.dir == "i" && pin.analog)
return this.Module._pins_get_voltage(this.pins, pin.number);
return (allPins & (1 << pin.number)) != 0;
}));
}

private sendScreenUpdate() {
Expand Down Expand Up @@ -219,11 +240,9 @@ class Emulator {
this.Module._cst816s_release_touch(this.touch);
}

changePin(pin: number, isSet: boolean) {
if (isSet)
this.Module._pins_set(this.pins, pin);
else
this.Module._pins_clear(this.pins, pin);
changePin(pin: number, volts: number) {
console.log("Setting pin", pin, "to", volts, "V");
this.Module._pins_set_voltage(this.pins, pin, volts * 1000);
}

private useLFS<T>(fn: (lfs: LFS) => T) {
Expand Down Expand Up @@ -515,7 +534,7 @@ async function handleMessage(msg: MessageToWorkerType) {
emulator.clearTouch();
break;

case "setPin":
case "setPinVoltage":
emulator.changePin(data.pin, data.value);
break;

Expand Down
2 changes: 1 addition & 1 deletion include/pins.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void pins_reset(pins_t *);
void pins_set(pins_t *, int pin);
void pins_clear(pins_t *, int pin);
void pins_toggle(pins_t *, int pin);
void pins_change(pins_t *, int pin, uint16_t value); // value is 0 or 1 if digital, millivolts if analog
void pins_set_voltage(pins_t *pins, int pin, uint16_t mv);

bool pins_is_analog(pins_t *, int pin);
void pins_set_analog(pins_t *, int pin, bool analog);
Expand Down
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ set(WASM_EXPORTS
pinetime_new pinetime_step pinetime_loop pinetime_reset
pinetime_get_st7789 st7789_read_screen_rgba st7789_is_sleeping st7789_get_write_count st7789_is_sleeping
pinetime_get_cst816s cst816s_do_touch cst816s_release_touch
pinetime_get_nrf52832 nrf52832_get_sram_size nrf52832_get_pins pins_set pins_clear pins_read_all
pinetime_get_nrf52832 nrf52832_get_sram_size nrf52832_get_pins pins_set_voltage pins_set pins_clear pins_read_all pins_get_voltage
pinetime_get_spinorflash spinorflash_get_buffer spinorflash_get_buffer_size
nrf52832_get_cpu cpu_is_sleeping cpu_mem
program_new program_load_binary program_load_elf program_write_variable
Expand Down
15 changes: 6 additions & 9 deletions src/peripherals/nrf52832/saadc.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ PPI_TASK_HANDLER(saadc_task_handler)
case TASK_ID(TASKS_START):
if (!saadc->running)
{
printf("SAADC started\n");
saadc->running = true;
ppi_fire_event(current_ppi, INSTANCE_SAADC, EVENT_ID(EVENTS_STARTED), saadc->inten.STARTED);
}
Expand All @@ -199,7 +198,6 @@ PPI_TASK_HANDLER(saadc_task_handler)
case TASK_ID(TASKS_SAMPLE):
if (saadc->running)
{
printf("SAADC sample\n");
int16_t reading = get_reading(saadc, saadc->sample_counter);
dma_write(saadc->dma, saadc->result.ptr + (saadc->sample_counter * 2), 2, (uint8_t *)&reading);

Expand All @@ -217,7 +215,6 @@ PPI_TASK_HANDLER(saadc_task_handler)
case TASK_ID(TASKS_STOP):
if (saadc->running)
{
printf("SAADC stopped\n");
saadc->running = false;
ppi_fire_event(current_ppi, INSTANCE_SAADC, EVENT_ID(EVENTS_STOPPED), saadc->inten.STOPPED);
}
Expand All @@ -241,8 +238,6 @@ OPERATION(saadc)
OP_IGNORE_LOAD_DATA
OP_ASSERT_SIZE(op, WORD);

printf("read saadc offset 0x%x\n", offset);

switch (offset)
{
OP_TASK(TASKS_START)
Expand Down Expand Up @@ -315,8 +310,9 @@ OPERATION(saadc)
*value = saadc->channels[ch_idx].pselp;
else if (*value != saadc->channels[ch_idx].pselp)
{
pins_set_analog(saadc->pins, saadc->channels[ch_idx].pselp, false);
pins_set_analog(saadc->pins, *value, true);
// TODO: Check for zero
pins_set_analog(saadc->pins, pins_table[saadc->channels[ch_idx].pselp - 1], false);
pins_set_analog(saadc->pins, pins_table[*value - 1], true);

saadc->channels[ch_idx].pselp = *value;
}
Expand All @@ -327,8 +323,9 @@ OPERATION(saadc)
*value = saadc->channels[ch_idx].pseln;
else if (*value != saadc->channels[ch_idx].pseln)
{
pins_set_analog(saadc->pins, saadc->channels[ch_idx].pseln, false);
pins_set_analog(saadc->pins, *value, true);
// TODO: Check for zero
pins_set_analog(saadc->pins, pins_table[saadc->channels[ch_idx].pseln - 1], false);
pins_set_analog(saadc->pins, pins_table[*value - 1], true);

saadc->channels[ch_idx].pseln = *value;
}
Expand Down
23 changes: 5 additions & 18 deletions src/pins.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

typedef struct
{
Expand Down Expand Up @@ -43,40 +44,25 @@ void pins_free(pins_t *pins)

void pins_reset(pins_t *pins)
{
memset(pins->pins, 0, sizeof(pins->pins));
pins->pin_states = 0;
pins->latch = 0;

pins_set_analog(pins, 31, true);
pins_change(pins, 31, 3000);
}

static inline void pins_set_voltage(pins_t *pins, int pin, uint16_t mv)
void pins_set_voltage(pins_t *pins, int pin, uint16_t mv)
{
assert(pin >= 0 && pin < PINS_COUNT);

bool is_set = mv >= pins->high_threshold_mv;

if (pins_is_set(pins, pin) == is_set)
return;
bool was_set = pins_is_set(pins, pin);

pin_t *p = &pins->pins[pin];

pins->pin_states = (pins->pin_states & ~(1 << pin)) | (is_set << pin);
pins->pins[pin].voltage = mv;

if (p->sense != SENSE_DISABLED && ((is_set && (p->sense == SENSE_HIGH)) || (!is_set && (p->sense == SENSE_LOW))))
if (was_set != is_set && p->sense != SENSE_DISABLED && ((is_set && (p->sense == SENSE_HIGH)) || (!is_set && (p->sense == SENSE_LOW))))
pins->latch |= 1 << pin;
}

void pins_change(pins_t *pins, int pin, uint16_t value)
{
if (pins->pins[pin].analog)
pins_set_voltage(pins, pin, value);
else
pins_set_voltage(pins, pin, value ? pins->high_voltage_mv : 0);
}

void pins_set(pins_t *pins, int pin)
{
pins_set_voltage(pins, pin, pins->high_voltage_mv);
Expand Down Expand Up @@ -110,6 +96,7 @@ void pins_set_analog(pins_t *pins, int pin, bool analog)
{
assert(pin >= 0 && pin < PINS_COUNT);

printf("Setting pin %d to %s\n", pin, analog ? "analog" : "digital");
pins->pins[pin].analog = analog;
}

Expand Down

0 comments on commit 8d01e61

Please sign in to comment.