Skip to content

Commit a6851c5

Browse files
committed
checkpoint: keyboard copro code works -ish with dvhstx text mode
1 parent f356fba commit a6851c5

21 files changed

+9688
-1
lines changed

library.deps

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, Adafruit LSM303DLHC, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC, Adafruit SHARP Memory Display, Adafruit SPIFlash, BSEC Software Library, WiiChuck, Adafruit DPS310, Adafruit AHTX0, RotaryEncoder, Adafruit MCP9808 Library, LSM303, Adafruit Protomatter, Adafruit IS31FL3741 Library, Sensirion I2C SCD4x, Adafruit TestBed, Bounce2, Adafruit AHRS, Adafruit DRV2605 Library, STM32duino VL53L4CD, PicoDVI - Adafruit Fork, Adafruit MMA8451 Library, Adafruit TSC2007, GFX Library for Arduino, Adafruit PyCamera Library, Adafruit ADG72x, Adafruit BNO055, Adafruit SHT4x Library, Adafruit VCNL4200 Library, Adafruit GC9A01A
1+
depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, Adafruit LSM303DLHC, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC, Adafruit SHARP Memory Display, Adafruit SPIFlash, BSEC Software Library, WiiChuck, Adafruit DPS310, Adafruit AHTX0, RotaryEncoder, Adafruit MCP9808 Library, LSM303, Adafruit Protomatter, Adafruit IS31FL3741 Library, Sensirion I2C SCD4x, Adafruit TestBed, Bounce2, Adafruit AHRS, Adafruit DRV2605 Library, STM32duino VL53L4CD, PicoDVI - Adafruit Fork, Adafruit MMA8451 Library, Adafruit TSC2007, GFX Library for Arduino, Adafruit PyCamera Library, Adafruit ADG72x, Adafruit BNO055, Adafruit SHT4x Library, Adafruit VCNL4200 Library, Adafruit GC9A01A, Adafruit DVI HSTX

runcpm-rp2350-hstx-usb/keyboard-copro/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
// SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
// pio-usb is required for rp2040 host
6+
#include "pio_usb.h"
7+
#include "Adafruit_TinyUSB.h"
8+
#include "pico/stdlib.h"
9+
#include "Adafruit_dvhstx.h"
10+
11+
DVHSTXText3 display(DVHSTX_PINOUT_DEFAULT);
12+
13+
// Pin D+ for host, D- = D+ + 1
14+
#ifndef PIN_USB_HOST_DP
15+
#define PIN_USB_HOST_DP 16
16+
#endif
17+
18+
// Pin for enabling Host VBUS. comment out if not used
19+
#ifndef PIN_5V_EN
20+
#define PIN_5V_EN 18
21+
#endif
22+
23+
#ifndef PIN_5V_EN_STATE
24+
#define PIN_5V_EN_STATE 1
25+
#endif
26+
27+
// USB Host object
28+
Adafruit_USBH_Host USBHost;
29+
30+
// Serial output for RunCPM
31+
SerialPIO pio_serial(1 /* RX of the sibling board */, SerialPIO::NOPIN);
32+
33+
void setup() {
34+
// ensure text generation interrupt takes place on core0
35+
display.begin();
36+
display.println("Hello hstx\n");
37+
}
38+
39+
void loop() {
40+
}
41+
42+
void setup1() {
43+
while(!display) ;
44+
delay(10);
45+
display.println("Hello hstx in setup1\n");
46+
// override tools menu CPU frequency setting
47+
//set_sys_clock_khz(264'000, true);
48+
49+
Serial.begin(115200);
50+
#if 0
51+
while ( !Serial ) delay(10); // wait for native usb
52+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
53+
#endif
54+
55+
#ifdef PIN_5V_EN
56+
pinMode(PIN_5V_EN, OUTPUT);
57+
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
58+
#endif
59+
60+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
61+
pio_cfg.pin_dp = PIN_USB_HOST_DP;
62+
pio_cfg.tx_ch = dma_claim_unused_channel(true);
63+
dma_channel_unclaim(pio_cfg.tx_ch);
64+
65+
USBHost.configure_pio_usb(1, &pio_cfg);
66+
67+
// run host stack on controller (rhport) 1
68+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
69+
// host bit-banging processing works done in core1 to free up core0 for other works
70+
USBHost.begin(1);
71+
72+
// this `begin` is a void function, no way to check for failure!
73+
pio_serial.begin(115200);
74+
display.println("end of setup1\n");
75+
display.show_cursor();
76+
}
77+
78+
int old_ascii = -1;
79+
uint32_t repeat_timeout;
80+
// this matches Linux default of 500ms to first repeat, 1/20s thereafter
81+
const uint32_t default_repeat_time = 50;
82+
const uint32_t initial_repeat_time = 500;
83+
84+
void send_ascii(uint8_t code, uint32_t repeat_time=default_repeat_time) {
85+
old_ascii = code;
86+
repeat_timeout = millis() + repeat_time;
87+
if (code >= 32 && code < 127) {
88+
display.printf("%c", code);
89+
} else {
90+
display.printf("\\x%02x", code);
91+
}
92+
pio_serial.write(code);
93+
}
94+
95+
void loop1()
96+
{
97+
static bool last_serial;
98+
if (!last_serial && Serial) {
99+
last_serial = true;
100+
Serial.println("Hello host serial");
101+
}
102+
uint32_t now = millis();
103+
uint32_t deadline = repeat_timeout - now;
104+
if (old_ascii >= 0 && deadline > INT32_MAX) {
105+
send_ascii(old_ascii);
106+
deadline = repeat_timeout - now;
107+
} else if (old_ascii < 0) {
108+
deadline = UINT32_MAX;
109+
}
110+
tuh_task_ext(deadline, false);
111+
}
112+
113+
// Invoked when device with hid interface is mounted
114+
// Report descriptor is also available for use.
115+
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
116+
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
117+
// it will be skipped therefore report_desc = NULL, desc_len = 0
118+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
119+
(void)desc_report;
120+
(void)desc_len;
121+
uint16_t vid, pid;
122+
tuh_vid_pid_get(dev_addr, &vid, &pid);
123+
124+
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
125+
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
126+
127+
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
128+
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
129+
Serial.printf("HID Keyboard\r\n");
130+
if (!tuh_hid_receive_report(dev_addr, instance)) {
131+
Serial.printf("Error: cannot request to receive report\r\n");
132+
}
133+
}
134+
}
135+
136+
// Invoked when device with hid interface is un-mounted
137+
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
138+
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
139+
}
140+
141+
#define FLAG_ALPHABETIC (1)
142+
#define FLAG_SHIFT (2)
143+
#define FLAG_NUMLOCK (4)
144+
#define FLAG_CTRL (8)
145+
#define FLAG_LUT (16)
146+
147+
const char * const lut[] = {
148+
"!@#$%^&*()", /* 0 - shifted numeric keys */
149+
"\r\x1b\10\t -=[]\\#;'`,./", /* 1 - symbol keys */
150+
"\n\x1b\177\t _+{}|~:\"~<>?", /* 2 - shifted */
151+
"\12\13\10\22", /* 3 - arrow keys RLDU */
152+
"/*-+\n1234567890.", /* 4 - keypad w/numlock */
153+
"/*-+\n\xff\2\xff\4\xff\3\xff\1\xff\xff.", /* 5 - keypad w/o numlock */
154+
};
155+
156+
struct keycode_mapper {
157+
uint8_t first, last, code, flags;
158+
} keycode_to_ascii[] = {
159+
{ HID_KEY_A, HID_KEY_Z, 'a', FLAG_ALPHABETIC, },
160+
161+
{ HID_KEY_1, HID_KEY_9, 0, FLAG_SHIFT | FLAG_LUT, },
162+
{ HID_KEY_1, HID_KEY_9, '1', 0, },
163+
{ HID_KEY_0, HID_KEY_0, ')', FLAG_SHIFT, },
164+
{ HID_KEY_0, HID_KEY_0, '0', 0, },
165+
166+
{ HID_KEY_ENTER, HID_KEY_ENTER, '\n', FLAG_CTRL },
167+
{ HID_KEY_ENTER, HID_KEY_SLASH, 2, FLAG_SHIFT | FLAG_LUT, },
168+
{ HID_KEY_ENTER, HID_KEY_SLASH, 1, FLAG_LUT, },
169+
170+
{ HID_KEY_F1, HID_KEY_F1, 0x1e, 0, }, // help key on xerox 820 kbd
171+
172+
{ HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_UP, 3, FLAG_LUT },
173+
174+
{ HID_KEY_KEYPAD_DIVIDE, HID_KEY_KEYPAD_DECIMAL, 4, FLAG_NUMLOCK | FLAG_LUT },
175+
{ HID_KEY_KEYPAD_DIVIDE, HID_KEY_KEYPAD_DECIMAL, 5, FLAG_LUT },
176+
};
177+
178+
179+
bool report_contains(const hid_keyboard_report_t &report, uint8_t key) {
180+
for (int i = 0; i < 6; i++) {
181+
if (report.keycode[i] == key) return true;
182+
}
183+
return false;
184+
}
185+
186+
hid_keyboard_report_t old_report;
187+
188+
static bool caps, num;
189+
static uint8_t old_leds;
190+
void process_event(uint8_t dev_addr, uint8_t instance, const hid_keyboard_report_t &report) {
191+
bool alt = report.modifier & 0x44;
192+
bool shift = report.modifier & 0x22;
193+
bool ctrl = report.modifier & 0x11;
194+
uint8_t code = 0;
195+
196+
if (report.keycode[0] == 1 && report.keycode[1] == 1) {
197+
// keyboard says it has exceeded max kro
198+
return;
199+
}
200+
201+
// something was pressed or release, so cancel any key repeat
202+
old_ascii = -1;
203+
204+
for (auto keycode : report.keycode) {
205+
if (keycode == 0) continue;
206+
if (report_contains(old_report, keycode)) continue;
207+
208+
/* key is newly pressed */
209+
if (keycode == HID_KEY_NUM_LOCK) {
210+
Serial.println("toggle numlock");
211+
num = !num;
212+
} else if (keycode == HID_KEY_CAPS_LOCK) {
213+
Serial.println("toggle capslock");
214+
caps = !caps;
215+
} else {
216+
for (const auto &mapper : keycode_to_ascii) {
217+
if (!(keycode >= mapper.first && keycode <= mapper.last))
218+
continue;
219+
if (mapper.flags & FLAG_SHIFT && !shift)
220+
continue;
221+
if (mapper.flags & FLAG_NUMLOCK && !num)
222+
continue;
223+
if (mapper.flags & FLAG_CTRL && !ctrl)
224+
continue;
225+
if (mapper.flags & FLAG_LUT) {
226+
code = lut[mapper.code][keycode - mapper.first];
227+
} else {
228+
code = keycode - mapper.first + mapper.code;
229+
}
230+
if (mapper.flags & FLAG_ALPHABETIC) {
231+
if (shift ^ caps) {
232+
code ^= ('a' ^ 'A');
233+
}
234+
}
235+
if (ctrl) code &= 0x1f;
236+
if (alt) code ^= 0x80;
237+
send_ascii(code, initial_repeat_time);
238+
break;
239+
}
240+
}
241+
}
242+
243+
uint8_t leds = (caps << 1) | num;
244+
if (leds != old_leds) {
245+
old_leds = leds;
246+
Serial.printf("Send LEDs report %d (dev:instance = %d:%d)\r\n", leds, dev_addr, instance);
247+
// no worky
248+
auto r = tuh_hid_set_report(dev_addr, instance/*idx*/, 0/*report_id*/, HID_REPORT_TYPE_OUTPUT/*report_type*/, &old_leds, sizeof(old_leds));
249+
Serial.printf("set_report() -> %d\n", (int)r);
250+
}
251+
old_report = report;
252+
}
253+
254+
// Invoked when received report from device via interrupt endpoint
255+
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
256+
if ( len != sizeof(hid_keyboard_report_t) ) {
257+
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
258+
} else {
259+
process_event(dev_addr, instance, *(hid_keyboard_report_t*)report);
260+
}
261+
// continue to request to receive report
262+
if (!tuh_hid_receive_report(dev_addr, instance)) {
263+
Serial.printf("Error: cannot request to receive report\r\n");
264+
}
265+
}

runcpm-rp2350-hstx-usb/runcpm-pico/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2017 Mockba the Borg
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries
3+
4+
SPDX-License-Identifier: MIT
5+
-->
6+
7+
This is a port of runcpm to the raspberry pi pico.
8+
9+
It is based on:
10+
* [RunCPM](https://github.com/MockbaTheBorg/RunCPM/)
11+
* [RunCPM_RPi_Pico](https://github.com/guidol70/RunCPM_RPi_Pico)
12+
13+
It works on a Raspberry Pi Pico (or Pico W). It uses the internal flash
14+
for storage, and can be mounted as USB storage.
15+
16+
If your Pico is placed on the Pico DV carrier board, you also get a 100x30
17+
character screen to enjoy your CP/M output on!
18+
19+
First, build for your device. You must
20+
* Use the Philhower Pico Core
21+
* In the Tools menu, select
22+
* A flash size option that includes at least 512kB for filesystem
23+
* USB Stack: Adafruit TinyUSB
24+
25+
After it boots the first time, you need to
26+
* Format the flash device on your host computer
27+
* Create the folder "<DEVICE>/A/0"
28+
* Put something useful in that folder, such as [Zork](http://www.retroarchive.org/cpm/games/zork123_80.zip)
29+
* Files must respect the "8.3" naming convention (8 letters filename + 3 letters extension) and be all uppercase
30+
* Safely eject the drive, then reset the emulator.
31+
* Now at the "A0>" prompt you can run "ZORK1".

0 commit comments

Comments
 (0)