Skip to content

Commit

Permalink
add commands to reprogram and wipe idprom
Browse files Browse the repository at this point in the history
  • Loading branch information
delan committed Jul 18, 2023
1 parent dc29ac7 commit 703d8bb
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 39 deletions.
41 changes: 41 additions & 0 deletions src/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,47 @@
#define SUNK_CAPSLOCK 0x77
#define SUNK_SCROLLLOCK 0x17
#define SUNK_POWER 0x30
#define SUNK_SHIFT_L 0x63
#define SUNK_SPACE 0x79
#define SUNK_RETURN 0x59
#define SUNK_DASH 0x28
#define SUNK_DOT 0x6C
#define SUNK_1 0x1E
#define SUNK_2 0x1F
#define SUNK_3 0x20
#define SUNK_4 0x21
#define SUNK_5 0x22
#define SUNK_6 0x23
#define SUNK_7 0x24
#define SUNK_8 0x25
#define SUNK_9 0x26
#define SUNK_0 0x27
#define SUNK_Q 0x36
#define SUNK_W 0x37
#define SUNK_E 0x38
#define SUNK_R 0x39
#define SUNK_T 0x3A
#define SUNK_Y 0x3B
#define SUNK_U 0x3C
#define SUNK_I 0x3D
#define SUNK_O 0x3E
#define SUNK_P 0x3F
#define SUNK_A 0x4D
#define SUNK_S 0x4E
#define SUNK_D 0x4F
#define SUNK_F 0x50
#define SUNK_G 0x51
#define SUNK_H 0x52
#define SUNK_J 0x53
#define SUNK_K 0x54
#define SUNK_L 0x55
#define SUNK_Z 0x64
#define SUNK_X 0x65
#define SUNK_C 0x66
#define SUNK_V 0x67
#define SUNK_B 0x68
#define SUNK_N 0x69
#define SUNK_M 0x6A

// sources:
// SPARC Keyboard Specification Version1 https://sparc.org/wp-content/uploads/2014/01/KBD.pdf.gz
Expand Down
40 changes: 1 addition & 39 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ extern "C" {
#include "menu.h"
#include "settings.h"
#include "state.h"
#include "sunk.h"
#include "view.h"
#include "splash.xbm"
#include "logo.xbm"
Expand Down Expand Up @@ -351,45 +352,6 @@ void loop1() {
buzzer.update();
}

void sunkSend(bool make, uint8_t code) {
static int activeCount = 0;
if (make) {
activeCount += 1;
buzzer.click();
} else {
activeCount -= 1;
code |= SUNK_BREAK_BIT;
}

#ifdef SUNK_ENABLE
#ifdef SUNK_VERBOSE
Sprintf("sun keyboard: tx command %02Xh\n", code);
#endif
Serial1.write(code);
#endif

if (activeCount <= 0) {
activeCount = 0;
#ifdef SUNK_ENABLE
#ifdef SUNK_VERBOSE
Sprintf("sun keyboard: idle\n");
#endif
Serial1.write(SUNK_IDLE);
#endif
}

switch (code) {
case SUNK_POWER:
Sprintf("sun power: high\n");
digitalWrite(POWER_KEY, HIGH);
break;
case SUNK_POWER | SUNK_BREAK_BIT:
Sprintf("sun power: low\n");
digitalWrite(POWER_KEY, LOW);
break;
}
}

// Invoked when device with hid interface is mounted
// Report descriptor is also available for use.
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
Expand Down
105 changes: 105 additions & 0 deletions src/menu.cc
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
#include "config.h"
#include "menu.h"

#include <string>
#include <string_view>

#include "buzzer.h"
#include "bindings.h"
#include "display.h"
#include "hostid.h"
#include "settings.h"
#include "state.h"
#include "sunk.h"
#include "view.h"

MenuView MENU_VIEW{};
WaitView WAIT_VIEW{};

template<typename... Args>
static void drawMenuItem(int16_t &marqueeX, size_t i, bool on, const char *fmt, Args... args);
Expand All @@ -19,6 +24,8 @@ enum class MenuItem : size_t {
ForceClick,
ClickDuration,
Hostid,
ReprogramIdprom,
WipeIdprom,
};

using MenuItemPainter = void (*)(int16_t &marqueeX, size_t i, bool on);
Expand All @@ -45,6 +52,12 @@ static const MenuItemPainter MENU_ITEM_PAINTERS[] = {
settings.hostid()[4],
settings.hostid()[5]);
},
[](int16_t &marqueeX, size_t i, bool on) {
drawMenuItem(marqueeX, i, on, "Reprogram idprom");
},
[](int16_t &marqueeX, size_t i, bool on) {
drawMenuItem(marqueeX, i, on, "Wipe idprom (AAh)");
},
};

static const size_t MENU_ITEM_COUNT = sizeof(MENU_ITEM_PAINTERS) / sizeof(MENU_ITEM_PAINTERS[0]);
Expand Down Expand Up @@ -77,6 +90,16 @@ static void drawMenuItem(int16_t &marqueeX, size_t i, bool on, const char *fmt,
}
}

unsigned decodeHex(unsigned char digit) {
if (digit >= '0' && digit <= '9')
return digit - '0';
if (digit >= 'A' && digit <= 'F')
return digit - 'A' + 10;
if (digit >= 'a' && digit <= 'f')
return digit - 'a' + 10;
return 0;
}

void MenuView::open() {
if (isOpen)
return;
Expand Down Expand Up @@ -146,6 +169,66 @@ void MenuView::sel(uint8_t usbkSelector) {
case (size_t)MenuItem::Hostid:
HOSTID_VIEW.open(settings.hostid());
break;
case (size_t)MenuItem::ReprogramIdprom: {
WAIT_VIEW.open("Reprogramming...");

unsigned hostid24 =
decodeHex(settings.hostid()[0]) << 20
| decodeHex(settings.hostid()[1]) << 16
| decodeHex(settings.hostid()[2]) << 12
| decodeHex(settings.hostid()[3]) << 8
| decodeHex(settings.hostid()[4]) << 4
| decodeHex(settings.hostid()[5]);

unsigned i = 0;
// https://funny.computer.daz.cat/sun/nvram-hostid-faq.txt
// version 1
sunkSend("1 %x mkp\n", i++);

// hostid byte 1/4 (system type)
sunkSend("real-machine-type %x mkp\n", i++);

// ethernet address oui (always 08:00:20)
sunkSend("8 %x mkp\n", i++);
sunkSend("0 %x mkp\n", i++);
sunkSend("20 %x mkp\n", i++);

// set ethernet address lower half such that hostid bytes 2/3/4
// cancels it out in the checksum
sunkSend("%x %x mkp\n", hostid24 >> 16 & 0xFF, i++);
sunkSend("%x %x mkp\n", hostid24 >> 8 & 0xFF, i++);
sunkSend("%x %x mkp\n", hostid24 >> 0 & 0xFF, i++);

// set date of manufacture such that the system type byte
// cancels it out in the checksum
sunkSend("real-machine-type %x mkp\n", i++);
sunkSend("0 %x mkp\n", i++);
sunkSend("0 %x mkp\n", i++);
sunkSend("0 %x mkp\n", i++);

// hostid bytes 2/3/4
sunkSend("%x %x mkp\n", hostid24 >> 16 & 0xFF, i++);
sunkSend("%x %x mkp\n", hostid24 >> 8 & 0xFF, i++);
sunkSend("%x %x mkp\n", hostid24 >> 0 & 0xFF, i++);

// 01h ^ 08h ^ 20h = 29h
// sunkSend("0 %x 0 do i idprom@ xor loop f mkp\n", i++);
sunkSend("29 %x mkp\n", i++);

// only needed for SS1000, but harmless otherwise
sunkSend("update-system-idprom\n");

sunkSend(".idprom\n");
sunkSend("banner\n");

WAIT_VIEW.close();
} break;
case (size_t)MenuItem::WipeIdprom: {
WAIT_VIEW.open("Wiping...");
for (unsigned i = 0; i < 0xF; i++)
sunkSend("aa %x mkp\n", i);
WAIT_VIEW.close();
} break;
default:
close();
}
Expand All @@ -168,3 +251,25 @@ void MenuView::sel(uint8_t usbkSelector) {
break;
}
}

void WaitView::handlePaint() {
display.setCursor(8, 8);
display.print(message);
}

void WaitView::handleKey(const UsbkChanges &) {}

void WaitView::open(const char *message) {
if (isOpen)
return;
isOpen = true;
this->message = message;
View::push(&WAIT_VIEW);
}

void WaitView::close() {
if (!isOpen)
return;
View::pop();
isOpen = false;
}
10 changes: 10 additions & 0 deletions src/menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ struct MenuView : View {
void sel(uint8_t usbkSelector);
};

struct WaitView : View {
bool isOpen = false;
const char *message = "";

void handlePaint() override;
void handleKey(const UsbkChanges &) override;
void open(const char *message);
void close();
};

extern MenuView MENU_VIEW;

#endif
47 changes: 47 additions & 0 deletions src/sunk.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "sunk.h"

#include <cstdint>

#include <Arduino.h>

#include "bindings.h"
#include "buzzer.h"

void sunkSend(bool make, uint8_t code) {
static int activeCount = 0;
if (make) {
activeCount += 1;
buzzer.click();
} else {
activeCount -= 1;
code |= SUNK_BREAK_BIT;
}

#ifdef SUNK_ENABLE
#ifdef SUNK_VERBOSE
Sprintf("sun keyboard: tx command %02Xh\n", code);
#endif
Serial1.write(code);
#endif

if (activeCount <= 0) {
activeCount = 0;
#ifdef SUNK_ENABLE
#ifdef SUNK_VERBOSE
Sprintf("sun keyboard: idle\n");
#endif
Serial1.write(SUNK_IDLE);
#endif
}

switch (code) {
case SUNK_POWER:
Sprintf("sun power: high\n");
digitalWrite(POWER_KEY, HIGH);
break;
case SUNK_POWER | SUNK_BREAK_BIT:
Sprintf("sun power: low\n");
digitalWrite(POWER_KEY, LOW);
break;
}
}
63 changes: 63 additions & 0 deletions src/sunk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef USB3SUN_SUNK_H
#define USB3SUN_SUNK_H

#include "config.h"

#include <Arduino.h>

#include <cstddef>

#include "bindings.h"

// internal flags (not part of real keycode)
#define SUNK_SEND_SHIFT 0x100

const uint16_t ASCII_TO_SUNK[128] = {
/* 00h */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 08h */ 0, 0, SUNK_RETURN, 0, 0, 0, 0, 0,
/* 10h */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 18h */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 20h */ SUNK_SPACE, 0, 0, 0, 0, 0, 0, 0,
/* 28h */ 0, 0, 0, 0, 0, SUNK_DASH, SUNK_DOT, 0,
/* 30h */ SUNK_0, SUNK_1, SUNK_2, SUNK_3, SUNK_4, SUNK_5, SUNK_6, SUNK_7,
/* 38h */ SUNK_8, SUNK_9, 0, 0, 0, 0, 0, 0,
/* 40h */ SUNK_2 | SUNK_SEND_SHIFT, SUNK_A, SUNK_B, SUNK_C, SUNK_D, SUNK_E, SUNK_F, SUNK_G,
/* 48h */ SUNK_H, SUNK_I, SUNK_J, SUNK_K, SUNK_L, SUNK_M, SUNK_N, SUNK_O,
/* 50h */ SUNK_P, SUNK_Q, SUNK_R, SUNK_S, SUNK_T, SUNK_U, SUNK_V, SUNK_W,
/* 58h */ SUNK_X, SUNK_Y, SUNK_Z, 0, 0, 0, 0, 0,
/* 60h */ 0, SUNK_A, SUNK_B, SUNK_C, SUNK_D, SUNK_E, SUNK_F, SUNK_G,
/* 68h */ SUNK_H, SUNK_I, SUNK_J, SUNK_K, SUNK_L, SUNK_M, SUNK_N, SUNK_O,
/* 70h */ SUNK_P, SUNK_Q, SUNK_R, SUNK_S, SUNK_T, SUNK_U, SUNK_V, SUNK_W,
/* 78h */ SUNK_X, SUNK_Y, SUNK_Z, 0, 0, 0, 0, 0,
};

void sunkSend(bool make, uint8_t code);

template <typename... Args>
void sunkSend(const char *fmt, Args... args) {
char result[256];
size_t len = snprintf(result, sizeof(result) / sizeof(*result), fmt, args...);
if (len >= sizeof(result) / sizeof(*result)) {
Sprintf("sunk: macro buffer overflow");
return;
}
for (auto i = 0; i < len; i++) {
if (result[i] >= sizeof(ASCII_TO_SUNK) / sizeof(*ASCII_TO_SUNK) || ASCII_TO_SUNK[result[i]] == 0) {
Sprintf("sunk: octet %02Xh not in ASCII_TO_SUNK\n", result[i]);
return;
}
}
Sprintf("sunk: sending macro <");
Sprintf(fmt, args...);
Sprintf(">\n");
for (auto i = 0; i < len; i++) {
if (!!(ASCII_TO_SUNK[result[i]] & SUNK_SEND_SHIFT))
sunkSend(true, SUNK_SHIFT_L);
sunkSend(true, ASCII_TO_SUNK[result[i]] & 0xFF);
sunkSend(false, ASCII_TO_SUNK[result[i]] & 0xFF);
if (!!(ASCII_TO_SUNK[result[i]] & SUNK_SEND_SHIFT))
sunkSend(false, SUNK_SHIFT_L);
}
}

#endif

0 comments on commit 703d8bb

Please sign in to comment.