├── .gitignore ├── Makefile ├── .editorconfig ├── tx-msdos ├── tx.wpj ├── src │ ├── main.c │ ├── int14.h │ ├── int13.h │ ├── xmodem-send.h │ ├── int13.c │ ├── int14.c │ └── xmodem-send.c ├── Makefile └── tx.tgt ├── image-msdos ├── image.wpj ├── src │ ├── image.h │ ├── main.c │ ├── int13.h │ ├── int13.c │ └── image.c ├── Makefile └── image.tgt ├── rx-unix ├── Makefile └── src │ └── main.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | */build/ 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS=rx-unix tx-msdos image-msdos 2 | 3 | all: $(SUBDIRS) 4 | 5 | $(SUBDIRS): 6 | $(MAKE) -C $@ 7 | 8 | .PHONY: all $(SUBDIRS) 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{c,h}] 4 | charset = utf-8 5 | trim_trailing_whitespace = false 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_size = 2 9 | indent_style = space 10 | 11 | # Tab indentation (no size specified) 12 | [Makefile] 13 | indent_style = tab 14 | -------------------------------------------------------------------------------- /tx-msdos/tx.wpj: -------------------------------------------------------------------------------- 1 | 40 2 | projectIdent 3 | 0 4 | VpeMain 5 | 1 6 | WRect 7 | -20 8 | 0 9 | 10276 10 | 9991 11 | 2 12 | MProject 13 | 3 14 | MCommand 15 | 0 16 | 4 17 | MCommand 18 | 0 19 | 1 20 | 5 21 | WFileName 22 | 6 23 | tx.tgt 24 | 6 25 | WVList 26 | 1 27 | 7 28 | VComponent 29 | 8 30 | WRect 31 | 0 32 | 0 33 | 5712 34 | 4359 35 | 0 36 | 0 37 | 9 38 | WFileName 39 | 6 40 | tx.tgt 41 | 0 42 | 4 43 | 7 44 | -------------------------------------------------------------------------------- /image-msdos/image.wpj: -------------------------------------------------------------------------------- 1 | 40 2 | projectIdent 3 | 0 4 | VpeMain 5 | 1 6 | WRect 7 | -20 8 | 0 9 | 10276 10 | 9991 11 | 2 12 | MProject 13 | 3 14 | MCommand 15 | 0 16 | 4 17 | MCommand 18 | 0 19 | 1 20 | 5 21 | WFileName 22 | 6 23 | tx.tgt 24 | 6 25 | WVList 26 | 1 27 | 7 28 | VComponent 29 | 8 30 | WRect 31 | 0 32 | 0 33 | 5712 34 | 4359 35 | 0 36 | 0 37 | 9 38 | WFileName 39 | 6 40 | tx.tgt 41 | 0 42 | 4 43 | 7 44 | -------------------------------------------------------------------------------- /image-msdos/src/image.h: -------------------------------------------------------------------------------- 1 | /** 2 | * image - disk-send 3 | * 4 | * Sergey Kiselev 5 | * Thomas Cherryhomes 6 | * 7 | * Licensed under GPL Version 3.0 8 | */ 9 | 10 | #ifndef IMAGE_H 11 | #define IMAGE_H 12 | 13 | #define SECTOR_SIZE 512 14 | 15 | /** 16 | * Copy disk to image file - main entrypoint. 17 | */ 18 | void disk_to_image(FILE *output); 19 | 20 | #endif /* IMAGE_H */ 21 | -------------------------------------------------------------------------------- /tx-msdos/src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * main routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #include 12 | #include 13 | #include "int14.h" 14 | #include "xmodem-send.h" 15 | 16 | #define BUFFER_SIZE 512 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | int14_init(); 21 | printf("serial port initialized.\n"); 22 | 23 | xmodem_send(); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tx-msdos/src/int14.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * BIOS INT 14H (RS-232C) routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #ifndef INT14_H 12 | #define INT14_H 13 | 14 | /** 15 | * Initialize port 16 | */ 17 | unsigned char int14_init(void); 18 | 19 | /** 20 | * Send byte 21 | */ 22 | void int14_send_byte(unsigned char b); 23 | 24 | /** 25 | * Get Port Status 26 | */ 27 | short int14_get_status(void); 28 | 29 | /** 30 | * Is data waiting? 31 | * Return 0 if nothing, 1 if data waiting. 32 | */ 33 | unsigned short int14_data_waiting(void); 34 | 35 | /** 36 | * Read byte 37 | */ 38 | unsigned char int14_read_byte(void); 39 | 40 | #endif /* INT14_H */ 41 | -------------------------------------------------------------------------------- /image-msdos/src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * image - disk-send 3 | * 4 | * main routines 5 | * 6 | * Sergey Kiselev 7 | * Thomas Cherryhomes 8 | * 9 | * Licensed under GPL Version 3.0 10 | */ 11 | 12 | #include 13 | #include 14 | #include "image.h" 15 | 16 | int main(int argc, char* argv[]) 17 | { 18 | FILE *output; 19 | 20 | if (argc != 2) { 21 | printf("Usage: %s \n\n", argv[0]); 22 | exit(1); 23 | } 24 | 25 | if ((output = fopen(argv[1], "wb")) == NULL) { 26 | printf("%s: Failed to open file '%s' for writing\n\n", argv[0], argv[1]); 27 | exit(1); 28 | } 29 | 30 | disk_to_image(output); 31 | 32 | fclose(output); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /tx-msdos/src/int13.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * BIOS INT 13H (Disk) routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #ifndef INT13_H 12 | #define INT13_H 13 | 14 | typedef struct { 15 | short c; /* Cylinders */ 16 | short h; /* Heads */ 17 | short s; /* Sectors per Track */ 18 | } DiskGeometry; 19 | 20 | #define AH_READ_DISK_SECTORS 0x02 21 | #define AH_GET_DRIVE_PARAMETERS 0x08 22 | 23 | /** 24 | * Get disk Geometry 25 | */ 26 | unsigned char int13_disk_geometry(DiskGeometry* geometry); 27 | 28 | /** 29 | * Read sector given CHS 30 | */ 31 | unsigned char int13_read_sector(short c, unsigned char h, unsigned char s, char* buf); 32 | 33 | #endif /* INT13_H */ 34 | -------------------------------------------------------------------------------- /image-msdos/src/int13.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * BIOS INT 13H (Disk) routines 5 | * 6 | * Sergey Kiselev 7 | * Thomas Cherryhomes 8 | * 9 | * Licensed under GPL Version 3.0 10 | */ 11 | 12 | #ifndef INT13_H 13 | #define INT13_H 14 | 15 | typedef struct { 16 | short c; /* Cylinders */ 17 | short h; /* Heads */ 18 | short s; /* Sectors per Track */ 19 | } DiskGeometry; 20 | 21 | #define AH_READ_DISK_SECTORS 0x02 22 | #define AH_GET_DRIVE_PARAMETERS 0x08 23 | 24 | /** 25 | * Get disk Geometry 26 | */ 27 | unsigned char int13_disk_geometry(DiskGeometry* geometry); 28 | 29 | /** 30 | * Read sectors given CHS 31 | */ 32 | unsigned char int13_read_sectors(short c, unsigned char h, unsigned char s, unsigned char n, char* buf); 33 | 34 | #endif /* INT13_H */ 35 | -------------------------------------------------------------------------------- /tx-msdos/src/xmodem-send.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * XMODEM-512 (512K block) routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #ifndef XMODEM_H 12 | #define XMODEM_H 13 | 14 | typedef enum _state {START, BLOCK, CHECK, REBLOCK, END} ProtocolState; 15 | 16 | /** 17 | * XMODEM-512 send file - main entrypoint. 18 | */ 19 | void xmodem_send(void); 20 | 21 | /** 22 | * Send CRC START (0x43) character and delay for 3 seconds, waiting for SOH. 23 | */ 24 | void xmodem_state_start(); 25 | 26 | /** 27 | * Send an XMODEM-512 block with CRC 28 | */ 29 | void xmodem_state_block(void); 30 | 31 | /** 32 | * Wait for ack/nak/cancel from receiver 33 | */ 34 | void xmodem_state_check(void); 35 | 36 | /** 37 | * Set next sector (in response to ACK) 38 | */ 39 | void xmodem_set_next_sector(void); 40 | 41 | #endif /* XMODEM_H */ 42 | -------------------------------------------------------------------------------- /rx-unix/Makefile: -------------------------------------------------------------------------------- 1 | TARGET_EXEC ?= rx 2 | 3 | BUILD_DIR ?= ./build 4 | SRC_DIRS ?= ./src 5 | 6 | CC=gcc 7 | 8 | SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s) 9 | OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) 10 | DEPS := $(OBJS:.o=.d) 11 | 12 | CFLAGS=-O2 13 | LDFLAGS= 14 | 15 | INC_DIRS := $(shell find $(SRC_DIRS) -type d) 16 | INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 17 | 18 | CPPFLAGS ?= $(INC_FLAGS) -MMD -MP 19 | 20 | $(BUILD_DIR)/$(TARGET_EXEC): $(OBJS) 21 | $(CC) $(OBJS) -o $@ $(LDFLAGS) 22 | 23 | # assembly 24 | $(BUILD_DIR)/%.s.o: %.s 25 | $(MKDIR_P) $(dir $@) 26 | $(AS) $(ASFLAGS) -c $< -o $@ 27 | 28 | # c source 29 | $(BUILD_DIR)/%.c.o: %.c 30 | $(MKDIR_P) $(dir $@) 31 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 32 | 33 | # c++ source 34 | $(BUILD_DIR)/%.cpp.o: %.cpp 35 | $(MKDIR_P) $(dir $@) 36 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ 37 | 38 | 39 | .PHONY: clean 40 | 41 | clean: 42 | $(RM) -r $(BUILD_DIR) 43 | 44 | -include $(DEPS) 45 | 46 | MKDIR_P ?= mkdir -p 47 | -------------------------------------------------------------------------------- /tx-msdos/Makefile: -------------------------------------------------------------------------------- 1 | TARGET_EXEC ?= tx.com 2 | 3 | BUILD_DIR ?= ./build 4 | SRC_DIRS ?= ./src 5 | 6 | CC=owcc 7 | LINK=wlink 8 | 9 | SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s) 10 | OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) 11 | DEPS := $(OBJS:.o=.d) 12 | 13 | CFLAGS=-bdos -mcmodel=t -s -march=i86 -Wall -Wextra 14 | LDFLAGS= 15 | 16 | INC_DIRS := $(shell find $(SRC_DIRS) -type d) 17 | INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 18 | 19 | CPPFLAGS ?= $(INC_FLAGS) 20 | 21 | $(BUILD_DIR)/$(TARGET_EXEC): $(OBJS) 22 | $(LINK) system com name $@ file {$(OBJS)} 23 | 24 | # assembly 25 | $(BUILD_DIR)/%.s.o: %.s 26 | $(MKDIR_P) $(dir $@) 27 | $(AS) $(ASFLAGS) -c $< -o $@ 28 | 29 | # c source 30 | $(BUILD_DIR)/%.c.o: %.c 31 | $(MKDIR_P) $(dir $@) 32 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 33 | 34 | # c++ source 35 | $(BUILD_DIR)/%.cpp.o: %.cpp 36 | $(MKDIR_P) $(dir $@) 37 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ 38 | 39 | 40 | .PHONY: clean 41 | 42 | clean: 43 | $(RM) -r $(BUILD_DIR) 44 | 45 | -include $(DEPS) 46 | 47 | MKDIR_P ?= mkdir -p 48 | -------------------------------------------------------------------------------- /image-msdos/Makefile: -------------------------------------------------------------------------------- 1 | TARGET_EXEC ?= image.com 2 | 3 | BUILD_DIR ?= ./build 4 | SRC_DIRS ?= ./src 5 | 6 | CC=owcc 7 | LINK=wlink 8 | 9 | SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s) 10 | OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) 11 | DEPS := $(OBJS:.o=.d) 12 | 13 | CFLAGS=-bdos -mcmodel=t -s -march=i86 -Wall -Wextra 14 | LDFLAGS= 15 | 16 | INC_DIRS := $(shell find $(SRC_DIRS) -type d) 17 | INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 18 | 19 | CPPFLAGS ?= $(INC_FLAGS) 20 | 21 | $(BUILD_DIR)/$(TARGET_EXEC): $(OBJS) 22 | $(LINK) system com name $@ file {$(OBJS)} 23 | 24 | # assembly 25 | $(BUILD_DIR)/%.s.o: %.s 26 | $(MKDIR_P) $(dir $@) 27 | $(AS) $(ASFLAGS) -c $< -o $@ 28 | 29 | # c source 30 | $(BUILD_DIR)/%.c.o: %.c 31 | $(MKDIR_P) $(dir $@) 32 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 33 | 34 | # c++ source 35 | $(BUILD_DIR)/%.cpp.o: %.cpp 36 | $(MKDIR_P) $(dir $@) 37 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ 38 | 39 | 40 | .PHONY: clean 41 | 42 | clean: 43 | $(RM) -r $(BUILD_DIR) 44 | 45 | -include $(DEPS) 46 | 47 | MKDIR_P ?= mkdir -p 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | disk-xfer and image 2 | --------- 3 | 4 | ## disk-xfer 5 | A simple pair of programs to image copy an MS-DOS hard drive to an image file on a remote computer over serial port. 6 | 7 | I wrote this because I needed a quick tool to back up a Conner CP-30104H disk from a GRiDCASE 1537, and nothing else was working. 8 | 9 | If you find it useful, that's awesome. 10 | 11 | to use: 12 | 13 | Start tx on source machine: 14 | 15 | ``` 16 | C> tx 17 | ``` 18 | 19 | Start rx on destination machine: 20 | 21 | ``` 22 | $ rx diskimage.img 23 | ``` 24 | 25 | If everything is connected correctly, tx will send the data over the COM1: serial port to the destination machine in the requested image file. 26 | 27 | ## image 28 | 29 | Image utility can be used to create an image of the HDD (the first HDD at this point). The image is written to the file specified by the command line argument. 30 | 31 | Usage example: 32 | 33 | ``` 34 | C> image D:\hdd.img 35 | ``` 36 | 37 | This will create an image of the first HDD and write it to D:\hdd.img file. Note that D: needs to have enough space to write the image. 38 | -------------------------------------------------------------------------------- /tx-msdos/tx.tgt: -------------------------------------------------------------------------------- 1 | 40 2 | targetIdent 3 | 0 4 | MProject 5 | 1 6 | MComponent 7 | 0 8 | 2 9 | WString 10 | 3 11 | EXE 12 | 3 13 | WString 14 | 5 15 | dc6en 16 | 1 17 | 0 18 | 0 19 | 4 20 | MCommand 21 | 0 22 | 5 23 | MCommand 24 | 0 25 | 6 26 | MItem 27 | 6 28 | tx.com 29 | 7 30 | WString 31 | 3 32 | EXE 33 | 8 34 | WVList 35 | 0 36 | 9 37 | WVList 38 | 0 39 | -1 40 | 1 41 | 1 42 | 0 43 | 10 44 | WPickList 45 | 5 46 | 11 47 | MItem 48 | 3 49 | *.c 50 | 12 51 | WString 52 | 4 53 | COBJ 54 | 13 55 | WVList 56 | 0 57 | 14 58 | WVList 59 | 0 60 | -1 61 | 1 62 | 1 63 | 0 64 | 15 65 | MItem 66 | 11 67 | src\int13.c 68 | 16 69 | WString 70 | 4 71 | COBJ 72 | 17 73 | WVList 74 | 0 75 | 18 76 | WVList 77 | 0 78 | 11 79 | 1 80 | 1 81 | 0 82 | 19 83 | MItem 84 | 11 85 | src\int14.c 86 | 20 87 | WString 88 | 4 89 | COBJ 90 | 21 91 | WVList 92 | 0 93 | 22 94 | WVList 95 | 0 96 | 11 97 | 1 98 | 1 99 | 0 100 | 23 101 | MItem 102 | 10 103 | src\main.c 104 | 24 105 | WString 106 | 4 107 | COBJ 108 | 25 109 | WVList 110 | 0 111 | 26 112 | WVList 113 | 0 114 | 11 115 | 1 116 | 1 117 | 0 118 | 27 119 | MItem 120 | 17 121 | src\xmodem-send.c 122 | 28 123 | WString 124 | 4 125 | COBJ 126 | 29 127 | WVList 128 | 0 129 | 30 130 | WVList 131 | 0 132 | 11 133 | 1 134 | 1 135 | 0 136 | -------------------------------------------------------------------------------- /image-msdos/image.tgt: -------------------------------------------------------------------------------- 1 | 40 2 | targetIdent 3 | 0 4 | MProject 5 | 1 6 | MComponent 7 | 0 8 | 2 9 | WString 10 | 3 11 | EXE 12 | 3 13 | WString 14 | 5 15 | dc6en 16 | 1 17 | 0 18 | 0 19 | 4 20 | MCommand 21 | 0 22 | 5 23 | MCommand 24 | 0 25 | 6 26 | MItem 27 | 6 28 | tx.com 29 | 7 30 | WString 31 | 3 32 | EXE 33 | 8 34 | WVList 35 | 0 36 | 9 37 | WVList 38 | 0 39 | -1 40 | 1 41 | 1 42 | 0 43 | 10 44 | WPickList 45 | 5 46 | 11 47 | MItem 48 | 3 49 | *.c 50 | 12 51 | WString 52 | 4 53 | COBJ 54 | 13 55 | WVList 56 | 0 57 | 14 58 | WVList 59 | 0 60 | -1 61 | 1 62 | 1 63 | 0 64 | 15 65 | MItem 66 | 11 67 | src\int13.c 68 | 16 69 | WString 70 | 4 71 | COBJ 72 | 17 73 | WVList 74 | 0 75 | 18 76 | WVList 77 | 0 78 | 11 79 | 1 80 | 1 81 | 0 82 | 19 83 | MItem 84 | 11 85 | src\int14.c 86 | 20 87 | WString 88 | 4 89 | COBJ 90 | 21 91 | WVList 92 | 0 93 | 22 94 | WVList 95 | 0 96 | 11 97 | 1 98 | 1 99 | 0 100 | 23 101 | MItem 102 | 10 103 | src\main.c 104 | 24 105 | WString 106 | 4 107 | COBJ 108 | 25 109 | WVList 110 | 0 111 | 26 112 | WVList 113 | 0 114 | 11 115 | 1 116 | 1 117 | 0 118 | 27 119 | MItem 120 | 17 121 | src\xmodem-send.c 122 | 28 123 | WString 124 | 4 125 | COBJ 126 | 29 127 | WVList 128 | 0 129 | 30 130 | WVList 131 | 0 132 | 11 133 | 1 134 | 1 135 | 0 136 | -------------------------------------------------------------------------------- /tx-msdos/src/int13.c: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * BIOS INT 13H (Disk) routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #include 12 | #include "int13.h" 13 | 14 | union REGS regs; 15 | 16 | /** 17 | * Get disk Geometry 18 | */ 19 | unsigned char int13_disk_geometry(DiskGeometry* geometry) 20 | { 21 | // BIOS call to get disk geometry. 22 | regs.h.ah=AH_GET_DRIVE_PARAMETERS; 23 | regs.h.dl=0x80; 24 | int86(0x13,®s,®s); 25 | 26 | // Unpack disk geometry. 27 | geometry->c=regs.h.ch; // Get lower 8 bits of cylinder count. 28 | geometry->c|=((regs.h.cl)&0xC0)<<2; // Get upper two bits of cylinder count. 29 | geometry->h=regs.h.dh; 30 | geometry->s=regs.h.cl&0x3F; // mask off high order bits of cylinder count (upper 2-bits) 31 | 32 | // 0 if successful, 1 if not. 33 | return regs.x.cflag; 34 | } 35 | 36 | /** 37 | * Read sector given CHS 38 | */ 39 | unsigned char int13_read_sector(short c, unsigned char h, unsigned char s, char* buf) 40 | { 41 | // Perform the read. 42 | regs.h.ah=AH_READ_DISK_SECTORS; 43 | regs.h.al=1; // 1 sector. 44 | regs.h.dh=h; 45 | regs.h.dl=0x80; // first hd 46 | regs.x.bx=(short)buf; 47 | regs.h.ch=c&0xFF; // cyl low 48 | regs.h.cl=s; 49 | regs.h.cl|=((c >> 2)&0xC0); // sector / cyl high */ 50 | int86(0x13,®s,®s); 51 | 52 | // 0 if successful, 1 if not. 53 | return regs.x.cflag; 54 | } 55 | -------------------------------------------------------------------------------- /image-msdos/src/int13.c: -------------------------------------------------------------------------------- 1 | /** 2 | * image - disk-send 3 | * 4 | * BIOS INT 13H (Disk) routines 5 | * 6 | * Sergey Kiselev 7 | * Thomas Cherryhomes 8 | * 9 | * Licensed under GPL Version 3.0 10 | */ 11 | 12 | #include 13 | #include "int13.h" 14 | 15 | union REGS regs; 16 | 17 | /** 18 | * Get disk Geometry 19 | */ 20 | unsigned char int13_disk_geometry(DiskGeometry* geometry) 21 | { 22 | // BIOS call to get disk geometry. 23 | regs.h.ah=AH_GET_DRIVE_PARAMETERS; 24 | regs.h.dl=0x80; 25 | int86(0x13,®s,®s); 26 | 27 | // Unpack disk geometry. 28 | geometry->c=regs.h.ch; // Get lower 8 bits of cylinder count. 29 | geometry->c|=((regs.h.cl)&0xC0)<<2; // Get upper two bits of cylinder count. 30 | geometry->h=regs.h.dh; 31 | geometry->s=regs.h.cl&0x3F; // mask off high order bits of cylinder count (upper 2-bits) 32 | 33 | // 0 if successful, 1 if not. 34 | return regs.x.cflag; 35 | } 36 | 37 | /** 38 | * Read sectors given CHS 39 | */ 40 | unsigned char int13_read_sectors(short c, unsigned char h, unsigned char s, unsigned char n, char* buf) 41 | { 42 | // Perform the read. 43 | regs.h.ah=AH_READ_DISK_SECTORS; 44 | regs.h.al=n; // n sectors. 45 | regs.h.dh=h; 46 | regs.h.dl=0x80; // first hd 47 | regs.x.bx=(short)buf; 48 | regs.h.ch=c&0xFF; // cyl low 49 | regs.h.cl=s; 50 | regs.h.cl|=((c >> 2)&0xC0); // sector / cyl high */ 51 | int86(0x13,®s,®s); 52 | 53 | // 0 if successful, 1 if not. 54 | return regs.x.cflag; 55 | } 56 | -------------------------------------------------------------------------------- /tx-msdos/src/int14.c: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * BIOS INT 14H (RS-232C) routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #include 12 | #include "int14.h" 13 | 14 | static union REGS regs; 15 | 16 | /** 17 | * Initialize port 18 | */ 19 | unsigned char int14_init(void) 20 | { 21 | regs.x.dx=0; 22 | regs.h.ah=0x04; // Extended initialize (for FOSSIL) 23 | regs.h.cl=8; // 19200 bps 24 | regs.h.ch=3; // 8 bits 25 | regs.h.bh=0; // No parity 26 | regs.h.bl=0; // 1 stop bit 27 | regs.h.al=0; // no break 28 | int86(0x14,®s,®s); 29 | 30 | if (regs.x.ax!=0x1954) 31 | return 1; 32 | 33 | // Set RTS/CTS flow control 34 | regs.h.ah = 0x0f; 35 | regs.h.al = 0x02; 36 | regs.x.dx = 0; 37 | int86(0x14,®s,®s); 38 | 39 | return 0; 40 | } 41 | 42 | /** 43 | * Send byte 44 | */ 45 | void int14_send_byte(unsigned char b) 46 | { 47 | regs.x.dx = 0; 48 | regs.h.al = b; 49 | regs.h.ah = 0x01; 50 | int86(0x14,®s,®s); 51 | } 52 | 53 | /** 54 | * Get Port Status 55 | */ 56 | short int14_get_status(void) 57 | { 58 | // Get port status 59 | regs.x.dx = 0; 60 | regs.h.al = 0; 61 | regs.h.ah = 3; 62 | int86(0x14,®s,®s); 63 | return regs.x.ax; 64 | } 65 | 66 | /** 67 | * Is data waiting? 68 | * Return 0 if nothing, 1 if data waiting. 69 | */ 70 | unsigned short int14_data_waiting(void) 71 | { 72 | return (int14_get_status()&0x100); 73 | } 74 | 75 | /** 76 | * Read byte 77 | */ 78 | unsigned char int14_read_byte(void) 79 | { 80 | regs.x.dx=0; 81 | regs.h.ah=0x02; 82 | int86(0x14,®s,®s); 83 | return regs.h.al; 84 | } 85 | -------------------------------------------------------------------------------- /image-msdos/src/image.c: -------------------------------------------------------------------------------- 1 | /** 2 | * image - disk-send 3 | * 4 | * Sergey Kiselev 5 | * Thomas Cherryhomes 6 | * 7 | * Licensed under GPL Version 3.0 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "image.h" 14 | #include "int13.h" 15 | 16 | short cylinder=0; 17 | unsigned char head=0; 18 | char* buf; 19 | DiskGeometry geometry; 20 | 21 | /** 22 | * Copy disk to image file - main entrypoint. 23 | */ 24 | void disk_to_image(FILE *output) 25 | { 26 | if (int13_disk_geometry(&geometry) == 1) { 27 | fprintf(stderr, "Could not retrieve disk geometry for device 0x80. Aborting.\n"); 28 | return; 29 | } 30 | 31 | /* Note: cylinders and heads values are 0 based, while sectors value is 1 based */ 32 | printf("Disk geometry: C: %4d, H: %2d, S: %2d\n", geometry.c, geometry.h, geometry.s); 33 | 34 | /* Read one cylinder/head at the time */ 35 | buf = malloc(geometry.s * SECTOR_SIZE); 36 | 37 | /* Disable buffering on stdout, so that the progress is shown right away */ 38 | setbuf(stdout, NULL); 39 | 40 | while (1) { 41 | printf("C: %4d, H: %2d\b\b\b\b\b\b\b\b\b\b\b\b\b\b", cylinder, head); 42 | if (int13_read_sectors(cylinder, head, 1, geometry.s, buf) == 0) { 43 | if (fwrite(buf, SECTOR_SIZE, geometry.s, output) != geometry.s) { 44 | fprintf(stderr, "\nError: Short write. Destination drive full?\n"); 45 | break; 46 | } 47 | } else { 48 | fprintf(stderr, "\nError: Could not read the source drive.\n"); 49 | break; 50 | } 51 | 52 | /* increment head and cyclinder as needed */ 53 | head++; 54 | if (head > geometry.h) { 55 | head=0; 56 | cylinder++; 57 | if (cylinder > geometry.c) { 58 | printf("\nDisk image written successfully\n"); 59 | break; /* end of the disk */ 60 | } 61 | } 62 | } 63 | free(buf); 64 | } 65 | -------------------------------------------------------------------------------- /tx-msdos/src/xmodem-send.c: -------------------------------------------------------------------------------- 1 | /** 2 | * tx - disk-send 3 | * 4 | * XMODEM-512 (512K block) routines 5 | * 6 | * Thomas Cherryhomes 7 | * 8 | * Licensed under GPL Version 3.0 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "xmodem-send.h" 15 | #include "int14.h" 16 | #include "int13.h" 17 | 18 | #define START_DELAY_TIME_MS 3000 // approx 3 secs. 19 | #define BYTE_XMODEM_START 0x43 // C (for CRC) 20 | 21 | ProtocolState state=START; 22 | unsigned char block_num=1; 23 | short cylinder=0; 24 | unsigned char head=0; 25 | unsigned char sector=1; 26 | char* buf; 27 | DiskGeometry geometry; 28 | 29 | /** 30 | * Calculate 16-bit CRC 31 | */ 32 | unsigned short xmodem_calc_crc(char* ptr, short count) 33 | { 34 | unsigned short crc; 35 | char i; 36 | 37 | crc=0; 38 | while (--count >= 0) 39 | { 40 | crc = crc ^ (unsigned short) *ptr++ << 8; 41 | i=8; 42 | do { 43 | if (crc & 0x8000) 44 | crc = crc << 1 ^ 0x1021; 45 | else 46 | crc = crc << 1; 47 | } while (--i); 48 | } 49 | return crc; 50 | } 51 | 52 | /** 53 | * XMODEM-512 send file - main entrypoint. 54 | */ 55 | void xmodem_send(void) 56 | { 57 | buf=malloc(512); 58 | 59 | if (int13_disk_geometry(&geometry)==1) 60 | { 61 | printf("Could not retrieve disk geometry for device 0x80. Aborting.\n"); 62 | free(buf); 63 | return; 64 | } 65 | 66 | while (state!=END) 67 | { 68 | switch (state) 69 | { 70 | case START: 71 | xmodem_state_start(); 72 | break; 73 | case BLOCK: 74 | xmodem_state_block(); 75 | break; 76 | case CHECK: 77 | xmodem_state_check(); 78 | break; 79 | case REBLOCK: 80 | break; 81 | case END: 82 | break; 83 | } 84 | } 85 | 86 | free(buf); 87 | 88 | } 89 | 90 | /** 91 | * Send CRC START (0x43) character and delay for 3 seconds, waiting for SOH. 92 | */ 93 | void xmodem_state_start() 94 | { 95 | short wait_time=START_DELAY_TIME_MS; 96 | 97 | while (wait_time>0) 98 | { 99 | delay(1); 100 | wait_time--; 101 | if (int14_data_waiting()!=0) 102 | { 103 | if (int14_read_byte()=='C') 104 | { 105 | state=BLOCK; 106 | printf("Starting Transfer.\n"); 107 | return; 108 | } 109 | } 110 | } 111 | printf("Trying Again...\n"); 112 | } 113 | 114 | /** 115 | * Send an XMODEM-512 block with CRC 116 | */ 117 | void xmodem_state_block(void) 118 | { 119 | short i=0; 120 | unsigned short calced_crc; 121 | if (int13_read_sector(cylinder,head,sector,buf)==0) 122 | { 123 | printf("Sending Cylinder: %4d, Head: %2d, Sector: %2d...",cylinder,head,sector); 124 | 125 | int14_send_byte(0x01); // SOH 126 | int14_send_byte(block_num); // block # (mod 256) 127 | int14_send_byte(0xFF-block_num); // 0xFF - BLOCK # (simple checksum) 128 | 129 | for (i=0;i<512;i++) // Send the data 130 | int14_send_byte(buf[i]); 131 | 132 | calced_crc=xmodem_calc_crc(buf,512); 133 | int14_send_byte((calced_crc>>8)); // CRC Hi 134 | int14_send_byte(calced_crc&0xFF); // CRC Lo 135 | 136 | state=CHECK; 137 | } 138 | else 139 | { 140 | printf("Could not read C: %4d, H: %2d, S: %2d from drive. Cancelling.\n",cylinder,head,sector); 141 | int14_send_byte(0x18); // CANCEL 142 | state=END; 143 | } 144 | } 145 | 146 | /** 147 | * Wait for ack/nak/cancel from receiver 148 | */ 149 | void xmodem_state_check(void) 150 | { 151 | unsigned char b; 152 | if (int14_data_waiting()!=0) 153 | { 154 | b=int14_read_byte(); 155 | switch (b) 156 | { 157 | case 0x06: // ACK 158 | printf("ACK!\n"); 159 | block_num++; 160 | block_num&=0xff; 161 | state=BLOCK; 162 | xmodem_set_next_sector(); // so if we're at end, it can be overridden. 163 | break; 164 | case 0x15: // NAK 165 | printf("NAK!\n"); 166 | state=BLOCK; // Resend. 167 | break; 168 | case 0x18: // CAN 169 | printf("CANCEL!\n"); 170 | state=END; // end. 171 | break; 172 | default: 173 | printf("Unknown Byte: 0x%02d: %c",b,b); 174 | } 175 | } 176 | } 177 | 178 | /** 179 | * Set next sector (in response to ACK) 180 | */ 181 | void xmodem_set_next_sector(void) 182 | { 183 | if (sector>=geometry.s) 184 | { 185 | sector=1; 186 | if (head>=geometry.h) 187 | { 188 | head=0; 189 | if (cylinder>geometry.c) 190 | state=END; 191 | else 192 | cylinder++; 193 | } 194 | else 195 | head++; 196 | } 197 | else 198 | sector++; 199 | } 200 | -------------------------------------------------------------------------------- /rx-unix/src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * rx - Receive image from tx 3 | * 4 | * Thomas Cherryhomes 5 | * 6 | * Released under GPL version 3.0 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include // needed for memset 15 | 16 | typedef enum _state {START, BLOCK, CHECK, REBLOCK, END} ProtocolState; 17 | 18 | #define BUFFER_SIZE 517 // 512 + 5 XMODEM-CRC block overhead. 19 | 20 | ProtocolState state=START; 21 | int serial_fd; 22 | int outfile_fd; 23 | unsigned char b; 24 | long block_num=1; 25 | 26 | unsigned char* buf; 27 | 28 | /** 29 | * Calculate 16-bit CRC 30 | */ 31 | unsigned short xmodem_calc_crc(char* ptr, short count) 32 | { 33 | unsigned short crc; 34 | char i; 35 | 36 | crc=0; 37 | while (--count >= 0) 38 | { 39 | crc = crc ^ (unsigned short) *ptr++ << 8; 40 | i=8; 41 | do { 42 | if (crc & 0x8000) 43 | crc = crc << 1 ^ 0x1021; 44 | else 45 | crc = crc << 1; 46 | } while (--i); 47 | } 48 | return crc; 49 | } 50 | 51 | /** 52 | * Send byte 53 | */ 54 | void xmodem_send_byte(unsigned char b) 55 | { 56 | write(serial_fd,&b,1); 57 | } 58 | 59 | /** 60 | * xmodem start, send C, switch to BLOCK state 61 | */ 62 | void xmodem_state_start(void) 63 | { 64 | printf("Sending Ready to Start."); 65 | b='C'; // Xmodem CRC start byte. 66 | write(serial_fd,&b,1); // Write to serial port. 67 | state=BLOCK; // Ready to start feeding blocks. 68 | } 69 | 70 | /** 71 | * xmodem block - Get XMODEM block into buffer. 72 | */ 73 | void xmodem_state_block(void) 74 | { 75 | int i=0; 76 | printf("Receiving next block # %d...",block_num); 77 | for (i=0;i