Skip to content

Commit

Permalink
unforgivable many changes at once
Browse files Browse the repository at this point in the history
* fix broken ttys[] & realloc() in find_ttys()
* add support for tpdd2 banks
* update several docs
* add drive firmwares
* little better directory display on debug console

* refactor a bunch of the constants
* tpdd2 mem read/write commands more closely emulate a real drive reading/writing cpu ram[], sector buffer within ram[], or rom[]
* tpdd2 mem read from rom addresses acually return data from a copy of the actual tpdd2 rom
* get rid of the seperate b[] in get_opr_cmd() and several others, just use gb[] for everything
* store the initial working directory on startup to apply to disk image file if needed
* more accurate error responses (matching a real drive) in several places
* impliment the tpdd1 & tpdd2 condition bit fields more like the drive does
* in update_cwd(), see if the new working directory is writable by the user,
  if not, set the wp bit in the condition variable
  • Loading branch information
bkw777 committed Feb 13, 2024
1 parent 49ffe87 commit 6f86966
Show file tree
Hide file tree
Showing 14 changed files with 1,094 additions and 823 deletions.
Binary file added Brother_FB-100.rom
Binary file not shown.
27 changes: 26 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ APP_NAME := DeskLink2
APP_LIB_DIR := $(PREFIX)/lib/$(NAME)
APP_DOC_DIR := $(PREFIX)/share/doc/$(NAME)
APP_VERSION := $(shell git describe --long 2>&-)
#FB100_ROM := Brother_FB-100.rom # no use yet
TPDD2_ROM := TANDY_26-3814.rom

DEFAULT_BASIC_BYTE_MS := 8 # ms-per-byte in -b file.100
DEFAULT_MODEL := 1 # 1=tpdd1 2=tpdd2 (TS-DOS FOO.<> dirs requires tpdd1)
DEFAULT_BAUD := 19200
DEFAULT_RTSCTS := false
DEFAULT_UPCASE := false
DEFAULT_DOTPOS := 6 # default 6.2 filenames compatible with Floppy/TS-DOS/etc.
DEFAULT_ATTR := 0x46 # default attribute 'F' compatible with Floppy/TS-DOS/etc.
RAW_ATTR := 0x20 # attr for "raw" mode, 0x00, 0x20, 0x46 are all plausible.
DEFAULT_DME_ROOT_LABEL := "0: "
DEFAULT_DME_PARENT_LABEL := "^ "

CLIENT_LOADERS := \
clients/teeny/TINY.100 \
Expand All @@ -33,13 +46,14 @@ CLIENT_LOADERS := \
# clients/power-dos/POWR-D.100

LIB_OTHER := \
$(TPDD2_ROM) \
clients/ts-dos/DOS100.CO \
clients/ts-dos/DOS200.CO \
clients/ts-dos/DOSNEC.CO \
clients/ts-dos/SAR100.CO \
clients/ts-dos/SAR200.CO \
clients/ts-dos/Sardine_American_English.pdd1 \
clients/disk_power/Disk_Power.K85.pdd1
clients/disk_power/Disk_Power.K85.pdd1 \

CLIENT_DOCS := \
clients/teeny/teenydoc.txt \
Expand Down Expand Up @@ -81,6 +95,17 @@ DEFINES := \
-DAPP_VERSION=\"$(APP_VERSION)\" \
-DAPP_LIB_DIR=\"$(APP_LIB_DIR)\" \
-DTTY_PREFIX=\"$(TTY_PREFIX)\" \
-DDEFAULT_DME_ROOT_LABEL=\"$(DEFAULT_DME_ROOT_LABEL)\" \
-DDEFAULT_DME_PARENT_LABEL=\"$(DEFAULT_DME_PARENT_LABEL)\" \
-DTPDD2_ROM=\"$(TPDD2_ROM)\" \
-DDEFAULT_BASIC_BYTE_MS=$(DEFAULT_BASIC_BYTE_MS) \
-DDEFAULT_MODEL=$(DEFAULT_MODEL) \
-DDEFAULT_BAUD=$(DEFAULT_BAUD) \
-DDEFAULT_RTSCTS=$(DEFAULT_RTSCTS) \
-DDEFAULT_UPCASE=$(DEFAULT_UPCASE) \
-DDEFAULT_DOTPOS=$(DEFAULT_DOTPOS) \
-DDEFAULT_ATTR=$(DEFAULT_ATTR) \
-DRAW_ATTR=$(RAW_ATTR) \
# -DPRINT_8BIT \
# -DNADSBOX_EXTENSIONS \
Expand Down
64 changes: 19 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Examples:
dl -b TS-DOS.100
dl -b ~/Documents/LivingM100SIG/Lib-03-TELCOM/XMDPW5.100
dl -vb rxcini.DO && dl -vu
dl -vun -m 1 -i Sardine_American_English.pdd1
dl -vun -i Sardine_American_English.pdd1
$
```
Expand Down Expand Up @@ -129,54 +129,23 @@ You can override the bundled versions of these files without touching the /usr/l
[More details](ref/ur2.txt)

## Sector Access / Disk Images
For a TPDD1 disk image
`$ dl -v -m 1 -i disk_image.pdd1`

For a TPDD2 disk image
`$ dl -v -m 2 -i disk_image.pdd2`
`$ dl -i disk_image.pdd1`
or
`$ dl -i disk_image.pdd2`

This is support for disk image files that allow use of raw sector access commands on a virtual disk image file.

Limitations: Only supports using the disk image for sector access. It doesn't provide access to the files in a disk image as files, just as raw sectors.

Useful working examples: Sardine_American_English.pdd1, Disk_Power_KC-85.pdd1

Those examples are both TPDD1 disks, but both TPDD1 and TPDD2 are supported.
There are just no known raw data applications like Sardine that use TPDD2 sector access to provide a TPDD2 example here.
You can still view or edit the raw sectors of any ordinary TPDD2 disk image such as the TPDD2 Utility Disk included with [pdd.sh](https://github.com/bkw777/pdd.sh) just to see that it works.

Example, using Sardine with a Model 100 with [Ultimate ROM II](http://www.club100.org/library/librom.html):
One way to use Sardine is to let Ultimate ROM II load & unload the program from disk into ram on the fly instead of installing permanently in ram like normal. Sardine uses raw sector access commands to read a special dictionary data disk.
For this to work, UR-II has to be able to load `SAR100.CO` from a normal filesystem disk using normal file/filesystem access, and then `SAR100.CO` needs to be able to use TPDD1 FDC-mode commands to read raw sectors from the special dictionary data disk.
This uses both the **magic files** and **disk image file** features.

To try it out,

1: Run dl with the following commandline arguments,
```
$ dl -vun -m 1 -i Sardine_American_English.pdd1
```

This set of flags tells dl2 to strictly emulate a TPDD1, disable some TPDD2 features and TS-DOS directory support which confuses `SAR100.CO`, and use the Sardine American English dictionary disk image file for any sector-access commands.
Both `SAR100.CO` and `Sardine_American_English.pdd1` are bundled with dl2, installed in /usr/local/lib/dl, so you don't have to do anything for SAR100.CO, and for the disk image you don't have to specify the full path.

2: Enter the UR-2 menu.
Notice the "SARDIN" entry with the word "OFF" under it.
Hit enter on SARDIN.
If you get a prompt about HIMEM, answer Y.
This loads SAR100.CO into ram.
Now notice the SARDIN entry changed from "OFF" to "ON" under it.

3: Enter T-Word and start a new document and type some text.

4: Press GRPH+F to invoke Sardine to spell-check the document.
This will invoke the SAR100.CO previously loaded, which will try to use TPDD1 FDC-mode sector access commands, wich dl2 will respond to with data from the .pdd1 file.
If the file exists, it's size is used to set the emulation mode to tpdd1 vs tpdd2.
If the file doesn't exist or is zero bytes, then the last 5 characters in the filename are used, ".pdd1" or ".pdd2", case insensitive.

Another example, [installing Disk Power for Kyotronic KC-85](clients/disk_power/Disk_Power.txt)
One example usage is the [Sardine](ref/Sardine.md) spell checker.
Another is [installing Disk Power for Kyotronic KC-85](clients/disk_power/Disk_Power.txt)

Disk image files may be created 2 ways:
* One method is you may use the **dd** command in [pdd.sh](https://github.com/bkw777/pdd.sh) to read a real disk from a real drive, and output a disk image file.
* Another method is you may run `dl -v -m 1 -i filename.pdd1` or `dl -v -m 2 -i filename.pdd2`, where filename.pddN either doesn't exist or is zero bytes, and then use a client (like TS-DOS or pdd.sh) to format the "disk". The format command will cause dl2 to generate the empty disk image.
There are 2 ways to create disk image files so far:
* One way is to use [pdd.sh](https://github.com/bkw777/pdd.sh) to read a real disk from a real drive, and output a disk image file.
* Another way is to run `dl -i filename`, where the file either doesn't exist or is zero bytes, and then use a client (like TS-DOS or pdd.sh) to format the "disk". When dl2 gets the format command, it will create the disk image.

More details about the disk image format [disk_image_files.txt](ref/disk_image_files.txt)

Expand All @@ -195,6 +164,7 @@ Sadly, `..` can not be used, but here are a few examples that do work.

`$ ROOT_LABEL=/ PARENT_LABEL=^ dl`
`$ ROOT_LABEL='-root-' PARENT_LABEL='-back-' dl`
`$ ROOT_LABEL='-top-' PARENT_LABEL='-up-' dl`
`$ ROOT_LABEL='0:' PARENT_LABEL='^:' dl`
or you can confuse someone...
`$ ROOT_LABEL='C:\' PARENT_LABEL='UP:' dl`
Expand All @@ -209,9 +179,13 @@ See [co2ba](co2ba.md)
## OS Compatibility
Tested on Linux, [Mac](ref/mac.md), [FreeBSD](ref/freebsd.md), and [Windows](ref/windows.md).

## TODO
* support big-endian platforms
* file/filesystem access on disk images - currently can only use for sector access
## TODO - not all necessarily serious
* Store the actual attr byte given by clients when they save a file, rather than faking with hardwired DEFAULT_ATTR=0x46. Store in xattr so that it stays part of the file when it is copied/moved/renamed.
* File/filesystem access on disk images - Currently can only use disk images for sector access.
* Verify if the code works on a big-endian platform - There are a lot of 2-byte values and a lot of direct byte manipulations because the protocol & drive uses MSB-first everywhere while most platforms today do not.
* Figure out and emulate more of the special memory addresses accessible in tpdd2 mode. We already do some.
* Fake sector 0 based on the files in the current share path so that if a client tries to read the FCB table directly it works.
* Fake entire disk image in ram based on current share path files. Option to save the image as long as we're there.

## History / Credits
[DeskLink for ms-dos](https://ftp.whtech.com/club100/com/dl-arc.exe.gz) 1987 Travelling Software
Expand Down
Binary file added TANDY_26-3814.rom
Binary file not shown.
4 changes: 2 additions & 2 deletions clients/disk_power/Disk_Power.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ pdd.sh so that dl2 can act as a virtual drive for sector access to it.

Installation: Just run the following command:

$ dl -vb Disk_Power.K85 && dl -vue -m 1 -i Disk_Power.K85.pdd1
$ dl -vb Disk_Power.K85 && dl -vun -i Disk_Power.K85.pdd1

(dl2 will get both files from /usr/local/lib/dl)
(both files are bundled with dl2 and will be loaded from /usr/local/lib/dl)

When the installer on the KC-85 prompts to insert the disk, just hit [Enter].

Expand Down
144 changes: 82 additions & 62 deletions constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,16 @@
#define REQ_SYSINFO 0x33 // TPDD2 Get System Information
#define REQ_EXEC 0x34 // TPDD2 Execute Program

// TPDD return block formats
// TPDD return block formats {fmt,len}
#define RET_READ 0x10
#define RET_DIRENT 0x11
#define RET_STD 0x12 // shared return format for: error open close delete status write
#define RET_VERSION 0x14 // TPDD2
#define RET_CONDITION 0x15 // TPDD2
#define RET_CACHE 0x38 // TPDD2 shared return format for: cache mem_write cond_list
static const unsigned char RET_DIRENT[2] = {0x11,0x1C};
static const unsigned char RET_STD[2] = {0x12,0x01}; // shared return format for: error open close delete status write
static const unsigned char RET_VERSION[2] = {0x14,0x0F}; // TPDD2
static const unsigned char RET_CONDITION[2] = {0x15,0x01}; // TPDD2
static const unsigned char RET_CACHE[2] = {0x38,0x01}; // TPDD2 shared return format for: cache mem_write cond_list
#define RET_MEM_READ 0x39 // TPDD2
#define RET_SYSINFO 0x3A // TPDD2
#define RET_EXEC 0x3B // TPDD2

static const unsigned char RET_SYSINFO[2] = {0x3A,0x06}; // TPDD2
static const unsigned char RET_EXEC[2] = {0x3B,0x03}; // TPDD2

// directory entry request types
#define DIRENT_SET_NAME 0x00
Expand All @@ -57,15 +56,19 @@
#define F_OPEN_READ 0x03

// TPDD Operation-mode error codes
// Normal
#define ERR_SUCCESS 0x00 // 'Operation Complete'
// File
#define ERR_NO_FILE 0x10 // 'File Not Found'
#define ERR_EXISTS 0x11 // 'File Exists'
// Sequence
#define ERR_NO_FNAME 0x30 // 'Missing Filename'
#define ERR_DIR_SEARCH 0x31 // 'Directory Search Error'
#define ERR_BANK 0x35 // 'Bank Error'
#define ERR_PARAM 0x36 // 'Parameter Error'
#define ERR_FMT_MISMATCH 0x37 // 'Open Format Mismatch'
#define ERR_EOF 0x3F // 'End of File'
// Disk I/O
#define ERR_NO_START 0x40 // 'No Start Mark'
#define ERR_ID_CRC 0x41 // 'ID CRC Check Error'
#define ERR_SECTOR_LEN 0x42 // 'Sector Length Error'
Expand All @@ -77,14 +80,22 @@
#define ERR_SECTOR_NUM 0x4A // 'Sector Number Error'
#define ERR_READ_TIMEOUT 0x4B // 'Read Data Timeout'
#define ERR_SECTOR_NUM2 0x4D // 'Sector Number Error'
// Protect
#define ERR_WRITE_PROTECT 0x50 // 'Write-Protected Disk'
#define ERR_DISK_NOINIT 0x5E // 'Disk Not Formatted'
#define ERR_WP_TPDD1_DISK 0x5F // TPDD2 'Write Protect to 26-3808 Diskette'
// File Territory
#define ERR_DIR_FULL 0x60 // 'Disk Full or Max File Size Exceeded or Directory Full' / TPDD2 'Directory Full'
#define ERR_DISK_FULL 0x61 // 'Disk Full'
#define ERR_FILE_LEN 0x6E // 'File Too Long' (real drive limits to 65534, we exceed for REXCPM)
#define ERR_NO_DISK 0x70 // 'No Disk'
#define ERR_DISK_CHG 0x71 // 'Disk Not Inserted or Disk Change Error' / TPDD2 'Disk Change Error'
#define ERR_DEFECTIVE 0x83 // 'Defective Disk' (real drive needs a power-cycle to clear this error)
// Diskette Condition
#define ERR_NO_DISK 0x70 // 'Disk Not Inserted'
#define ERR_DISK_CHG 0x71 // 'Disk Change Error'
// Sensor
#define ERR_NO_INDEX_SIGNAL 0x80
#define ERR_ABNORMAL_TRACK_ZERO 0x81
#define ERR_ABNORMAL_INDEX_SIGNAL 0x82
#define ERR_DEFECTIVE 0x83 // 'Defective Disk' - real drive needs a power-cycle to clear this error - not in the manual

// TPDD1 FDC-mode commands
#define FDC_SET_MODE 'M' // set Operation-mode or FDC-mode
Expand All @@ -98,7 +109,7 @@
#define FDC_WRITE_ID_NV 'C' // write sector ID without verify
#define FDC_WRITE_SECTOR 'W' // write sector data
#define FDC_WRITE_SECTOR_NV 'X' // write sector data without verify
#define FDC_CMDS {FDC_SET_MODE,FDC_CONDITION,FDC_FORMAT,FDC_FORMAT_NV,FDC_READ_ID,FDC_READ_SECTOR,FDC_SEARCH_ID,FDC_WRITE_ID,FDC_WRITE_ID_NV,FDC_WRITE_SECTOR,FDC_WRITE_SECTOR_NV,0x00}
static const char FDC_CMDS[] = {FDC_SET_MODE,FDC_CONDITION,FDC_FORMAT,FDC_FORMAT_NV,FDC_READ_ID,FDC_READ_SECTOR,FDC_SEARCH_ID,FDC_WRITE_ID,FDC_WRITE_ID_NV,FDC_WRITE_SECTOR,FDC_WRITE_SECTOR_NV,0x00};

// TPDD1 FDC-mode error codes
// There is no documentation for FDC error codes.
Expand All @@ -120,41 +131,38 @@
#define ERR_FDC_NO_DISK 209 // 'Disk Not Inserted'
#define ERR_FDC_INTERRUPTED 216 // 'Operation Interrupted'

// TPDD1 FDC Condition bits
#define FDC_COND_NOTINS 0x80 // bit 7 : disk not inserted
#define FDC_COND_CHANGED 0x40 // bit 6 : disk changed
#define FDC_COND_WPROT 0x20 // bit 5 : disk write-protected
#define FDC_COND_b4 0x10
#define FDC_COND_b3 0x08
#define FDC_COND_b2 0x04
#define FDC_COND_b1 0x02
#define FDC_COND_b0 0x01
#define FDC_COND_NONE 0x00 // no conditions

// TPDD1 FDC Logical Sector Length Codes
#define FDC_LOGICAL_SIZE_CODES {64,80,128,256,512,1024,1280}
static const unsigned short FDC_LOGICAL_SECTOR_SIZE[7] = {64,80,128,256,512,1024,1280};

// TPDD1 Condition bits
#define PDD1_COND_BIT_NOTINS 7 // disk not inserted
#define PDD1_COND_BIT_CHANGED 6 // disk changed
#define PDD1_COND_BIT_WPROT 5 // disk write-protected
#define PDD1_COND_BIT_4 4
#define PDD1_COND_BIT_3 3
#define PDD1_COND_BIT_2 2
#define PDD1_COND_BIT_1 1
#define PDD1_COND_BIT_0 0
#define PDD1_COND_NONE 0x00 // no conditions

// TPDD2 Condition bits
#define PDD2_COND_b7 0x80
#define PDD2_COND_b6 0x40
#define PDD2_COND_b5 0x20
#define PDD2_COND_b4 0x10
#define PDD2_COND_CHANGED 0x08 // bit 3 : disk changed
#define PDD2_COND_NOTINS 0x04 // bit 2 : disk not inserted
#define PDD2_COND_WPROT 0x02 // bit 1 : write protected disk
#define PDD2_COND_POWER 0x01 // bit 0 : low power
#define PDD2_COND_NONE 0x00 // no conditions
#define PDD2_COND_BIT_7 7
#define PDD2_COND_BIT_6 6
#define PDD2_COND_BIT_5 5
#define PDD2_COND_BIT_4 4
#define PDD2_COND_BIT_CHANGED 3 // disk changed
#define PDD2_COND_BIT_NOTINS 2 // disk not inserted
#define PDD2_COND_BIT_WPROT 1 // disk write protected
#define PDD2_COND_BIT_POWER 0 // low power
#define PDD2_COND_NONE 0x00 // no conditions

// lengths & addresses
#define PDD1_TRACKS 40
#define PDD1_SECTORS 2
#define PDD2_TRACKS 80
#define PDD2_SECTORS 2
#define TPDD_DATA_MAX 260 // largest theoretical packet is 256+3
#define DIRENTS 40
#define REQ_RW_DATA_MAX 128 // largest chunk size in req_read() req_write()
#define LEN_RET_STD 0x01
#define LEN_RET_DME 0x0B
#define LEN_RET_DIRENT 0x1C
#define TPDD_FILENAME_LEN 24
#define LOCAL_FILENAME_MAX 256
#define SECTOR_ID_LEN 12
Expand All @@ -167,38 +175,55 @@
#define SMT_OFFSET 1240
#define PDD1_SMT 0x80
#define PDD2_SMT 0xC0
#define RAM_ADDR 0x8000
#define RAM_LEN 0x0800
#define PDD2_ID_ADDR (RAM_ADDR+0x0004)
#define PDD2_MEM_READ_MAX 252 // real drive absolute limit
#define PDD2_MEM_WRITE_MAX 127 // real drive absolute limit
#define TPDD_MSG_MAX 256 // largest theoretical packet is 256+3, largest actual is 252+3

// cpu memory map
#define IOPORT_ADDR 0x00
#define IOPORT_LEN 0x1F
#define CPURAM_ADDR 0x80
#define CPURAM_LEN 0x7F
#define GA_ADDR 0x4000
#define GA_LEN 0x03
#define RAM_ADDR 0x8000
#define RAM_LEN 0x0800
#define ROM_ADDR 0xF000
#define ROM_LEN 0x1000

// sector cache
#define PDD2_ID_REL 0x04
#define PDD2_ID_ADDR (RAM_ADDR+PDD2_ID_REL)
#define PDD2_DATA_REL 0x13
#define PDD2_DATA_ADDR (RAM_ADDR+PDD2_DATA_REL)
#define PDD2_CACHE_LEN (PDD2_DATA_REL+SECTOR_DATA_LEN)
#define PDD2_CACHE_LEN_MSB ((PDD2_CACHE_LEN>>0x08)&0xFF) // 0x05
#define PDD2_CACHE_LEN_LSB (PDD2_CACHE_LEN&0xFF) // 0x13

// TPDD2 version data: 41 10 01 00 50 05 00 02 00 28 00 E1 00 00 00
#define VERSION_MSB 0x41
#define VERSION_LSB 0x10
#define SIDES 0x01
#define TRACKS_MSB 0x00
#define TRACKS_LSB 0x50
#define SECTOR_SIZE_MSB 0x05
#define SECTOR_SIZE_LSB 0x00
#define TRACKS_MSB ((PDD2_TRACKS>>0x08)&0xFF)
#define TRACKS_LSB (PDD2_TRACKS&0xFF)
#define SECTOR_SIZE_MSB ((SECTOR_DATA_LEN>>0x08)&0xFF)
#define SECTOR_SIZE_LSB (SECTOR_DATA_LEN&0xFF)
#define SECTORS_PER_TRACK 0x02
#define DIRENTS_MSB 0x00
#define DIRENTS_LSB 0x28
#define MAX_FD 0x00
#define MODEL 0xE1 // E1 = TPDD2
#define DIRENTS_MSB ((DIRENTS>>0x08)&0xFF)
#define DIRENTS_LSB (DIRENTS&0xFF)
#define MAX_FD 0x00 // it's 0 but it means the highest fd# is 0, meaning max 1 open file
#define MODEL_CODE 0xE1 // E1 = TPDD2
#define VERSION_R0 0x00
#define VERSION_R1 0x00
#define VERSION_R2 0x00

// TPDD2 sysinfo data: 80 13 05 00 10 E1
#define SECTOR_CACHE_START_MSB 0x80
#define SECTOR_CACHE_START_LSB 0x13
//#define SECTOR_CACHE_LEN_MSB 0x05 // SECTOR_SIZE_MSB
//#define SECTOR_CACHE_LEN_LSB 0x00 // SECTOR_SIZE_LSB
#define SYSINFO_CPU 0x10 // 0x10 = HD6301
//#define MODEL 0xE1

#define PDD2_CACHE_ADDR (SECTOR_CACHE_START_MSB*256+SECTOR_CACHE_START_LSB)
#define SECTOR_CACHE_START_MSB ((PDD2_DATA_ADDR>>0x08)&0xFF) // 0x80
#define SECTOR_CACHE_START_LSB (PDD2_DATA_ADDR&0xFF) // 0x13
// sysinfo[2] = SECTOR_SIZE_MSB
// sysinfo[3] = SECTOR_SIZE_LSB
#define SYSINFO_CPU_CODE 0x10 // 0x10 = HD6301
// sysinfo[5] = MODEL_CODE

// flags
#define FE_FLAGS_NONE 0
Expand All @@ -220,9 +245,4 @@
#define OPR_CMD_SYNC 0x5A
#define FDC_CMD_EOL 0x0D

// terminal emulation
#define SSO "\033[7m" // set standout
#define RSO "\033[m" // reset standout
#define D8C "\033 F" // disable 8-bit vtxx control bytes (0x80-0x9F)

#endif // PDD_CONSTANTS_H
Loading

0 comments on commit 6f86966

Please sign in to comment.