From ce56fd259aa226c30f7b34d98d91f3020dd9d001 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Tue, 15 Jun 2021 21:36:00 +0200 Subject: [PATCH] Split disk access into seperate file --- Inc/control.h | 25 +-- Inc/disk.h | 16 ++ Makefile | 1 + Src/control.c | 526 +----------------------------------------------- Src/disk.c | 541 ++++++++++++++++++++++++++++++++++++++++++++++++++ Src/main.c | 1 + 6 files changed, 571 insertions(+), 539 deletions(-) create mode 100644 Inc/disk.h create mode 100644 Src/disk.c diff --git a/Inc/control.h b/Inc/control.h index 56ebcff..825802b 100644 --- a/Inc/control.h +++ b/Inc/control.h @@ -1,33 +1,10 @@ #ifndef CONTROL_H #define CONTROL_H -#include "stm32f4xx_hal.h" -#include "fatfs.h" -#include - -struct DirtyBlock { - uint32_t block; - struct DirtyBlock* next; - uint8_t size; - uint8_t* data; -}; - -typedef struct { - FATFS *fs; - FIL *file; - uint8_t command; - uint8_t ready; - uint32_t counter; - uint32_t lba; - uint8_t* buffer; - uint8_t* directory; - unsigned int size; - struct DirtyBlock* dirty_block; -} Storage; +#include "stdint.h" typedef struct { uint8_t memory_config; - Storage storage; } Control; uint16_t read_address(); diff --git a/Inc/disk.h b/Inc/disk.h new file mode 100644 index 0000000..5389679 --- /dev/null +++ b/Inc/disk.h @@ -0,0 +1,16 @@ +#ifndef DISKL_H +#define DISKL_H + +#include "stdint.h" + +uint8_t disk_read_byte(); +void disk_write_byte(uint8_t value); +void disk_receive_command(uint8_t command); +uint8_t disk_is_ready(); + +void disk_init(); +void disk_free(); + +void disk_set_lba_part(uint8_t value, uint8_t part); + +#endif diff --git a/Makefile b/Makefile index 87f2f33..ac7e54e 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ C_SOURCES = \ Src/main.c \ Src/firmware.c \ Src/restart.c \ +Src/disk.c \ Src/control.c \ Src/profiling.c \ Src/io.c \ diff --git a/Src/control.c b/Src/control.c index 44ef6df..d6a6261 100644 --- a/Src/control.c +++ b/Src/control.c @@ -2,8 +2,8 @@ #include #include #include -#include #include "control.h" +#include "disk.h" #include "io.h" #include "bsp_driver_sd.h" #include "profiling.h" @@ -20,10 +20,6 @@ extern UART_HandleTypeDef huart2; extern uint8_t ack[1]; extern uint8_t nack[1]; -#define CPM_RECORD_SIZE 128 -#define CPM_RECORDS_PER_BLOCK 128 -#define CPM_BLOCK_SIZE CPM_RECORD_SIZE*CPM_RECORDS_PER_BLOCK - uint8_t get_device(uint16_t address) { uint8_t page = address >> 12; if (control.memory_config == 0) { @@ -113,26 +109,12 @@ void handle_io_read() { // Read byte from disk case 0x08: - if (control.storage.ready && control.storage.command == 0x20) { - if (control.storage.counter < control.storage.size) { - write_data(control.storage.buffer[control.storage.counter]); - } else { - write_data(0x00); - } - - control.storage.counter++; - - if (control.storage.counter >= CPM_RECORD_SIZE) { - control.storage.ready = 0; - } - } else { - write_data(0x00); - } + write_data(disk_read_byte()); break; // Check if disk is ready case 0x0f: - write_data(0x08*control.storage.ready); + write_data(0x08*disk_is_ready()); break; default: { @@ -166,391 +148,27 @@ void handle_io_write() { // Write byte to disk case 0x08: - // @todo What if for whatever reason we write less then a record to disk? - if (control.storage.ready && control.storage.command == 0x30) { - control.storage.buffer[control.storage.counter] = value; - control.storage.counter++; - - if (control.storage.counter >= CPM_RECORD_SIZE) { - char filename[128] = {0}; - uint32_t offset = 0; - if (control.storage.lba == 0) { - snprintf(filename, 128, "0:loader.bin"); - offset = control.storage.lba - 0; - } else if (control.storage.lba >= 1 && control.storage.lba < 45) { - snprintf(filename, 128, "0:cpm22.bin"); - offset = control.storage.lba - 1; - } else if (control.storage.lba >= 45 && control.storage.lba < 51) { - snprintf(filename, 128, "0:bios.bin"); - offset = control.storage.lba - 45; - } else if (control.storage.lba >= 256 && control.storage.lba < 384) { - offset = control.storage.lba - 256; - - for (uint8_t index = 0; index < 4; ++index) { - char name[8]; - for (int j = 0; j < 8; ++j) { - char c = control.storage.buffer[index*32 + 1 + j]; - if (c == ' ') { - c = 0x00; - } - name[j] = c; - } - - char ext[3]; - for (int j = 0; j < 3; ++j) { - char c = control.storage.buffer[index*32 + 9 + j]; - if (c == ' ') { - c = 0x00; - } - ext[j] = c; - } - - char temp_filename[128]; - snprintf(temp_filename, 128, "0:A/%.8s.%.3s", name, ext); - - uint8_t user = control.storage.buffer[index*32 + 0]; - uint8_t user_old = control.storage.directory[offset*128 + index*32 + 0]; - - FIL file; - if (user != user_old) { - printf("User has changed for %s: %i -> %i\n\r", temp_filename, user_old, user); - - // @todo For some reason we keep getting a file entry that changes - // from 0 -> 0xe5 with no name - if (user == 0xe5) { - printf("Index: %i\n\r", index); - printf("Deleting file\n\r"); - FRESULT fr = f_unlink(temp_filename); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } else if (user_old == 0xe5) { - printf("Creating file\n\r"); - - FRESULT fr = f_open(&file, temp_filename, FA_READ | FA_CREATE_ALWAYS); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - f_sync(&file); - f_close(&file); - } - } - - for (uint8_t i = 0; i < 8; ++i) { - uint16_t allocation = control.storage.buffer[index*32 + 16 + i*2]; - allocation += control.storage.buffer[index*32 + 17 + i*2] << 8; - - if (allocation == 0) { - break; - } - - struct DirtyBlock* prev = NULL; - struct DirtyBlock* current = control.storage.dirty_block; - while (current) { - if (allocation == current->block) { - printf("Found dirty block\n\r"); - - FRESULT fr = f_open(&file, temp_filename, FA_WRITE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - offset = i*CPM_RECORDS_PER_BLOCK; - fr = f_lseek(&file, offset * CPM_RECORD_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_write(&file, current->data, current->size * CPM_RECORD_SIZE, &control.storage.size); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_sync(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_close(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - if (prev) { - prev->next = current->next; - } else { - control.storage.dirty_block = NULL; - } - - free(current->data); - free(current); - - break; - } - - prev = current; - current = current->next; - } - } - } - - printf("Write to directory (offset: %li)\n\r", offset); - memcpy(control.storage.directory + offset*CPM_RECORD_SIZE, control.storage.buffer, CPM_RECORD_SIZE); - } else if (control.storage.lba >= 384) { - uint32_t block = (control.storage.lba - 256) / CPM_RECORDS_PER_BLOCK; - - uint8_t found = 0; - for (int entry = 0; entry < 127; ++entry) { - uint8_t user = control.storage.directory[entry*32 + 0]; - if (user == 0xe5) { - continue; - } - - for (int i = 0; i < 8; ++i) { - uint16_t allocation = control.storage.directory[entry*32 + 16 + 2*i]; - allocation += control.storage.directory[entry*32 + 17 + 2*i] << 8; - - if (allocation == block) { - found = 1; - offset = (control.storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK) + i*CPM_RECORDS_PER_BLOCK; - - char name[8]; - for (int j = 0; j < 8; ++j) { - char c = control.storage.directory[entry*32 + 1 + j]; - if (c == ' ') { - c = 0x00; - } - name[j] = c; - } - - char ext[3]; - for (int j = 0; j < 3; ++j) { - char c = control.storage.directory[entry*32 + 9 + j]; - if (c == ' ') { - c = 0x00; - } - ext[j] = c; - } - - snprintf(filename, 128, "0:A/%.8s.%.3s", name, ext); - - break; - } - } - - if (found) { - break; - } - } - - if (!found) { - printf("Write to unlinked block\n\r"); - - // Check if we already have a dirty block for this block - struct DirtyBlock* dirty_block = control.storage.dirty_block; - while (dirty_block) { - if (dirty_block->block == block) { - printf("Found existing dirty block\n\r"); - break; - } - } - - // @todo It appears that it updates the file entry after every block written - // So we might not need a linked list, altough it probably is more robust this way - if (!dirty_block) { - printf("Creating new dirty block\n\r"); - dirty_block = malloc(sizeof(struct DirtyBlock)); - dirty_block->block = block; - dirty_block->next = control.storage.dirty_block; - control.storage.dirty_block = dirty_block; - dirty_block->size = 0; - dirty_block->data = malloc(CPM_BLOCK_SIZE); - } - - offset = (control.storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK); - memcpy(dirty_block->data + offset * CPM_RECORD_SIZE, control.storage.buffer, CPM_RECORD_SIZE); - - if (offset+1 > dirty_block->size) { - dirty_block->size = offset+1; - } - } - } - - if (filename[0]) { - FIL file; - // @0todo Cache the currently opened file so we are not opening it every 128 bytes - FRESULT fr = f_open(&file, filename, FA_WRITE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_lseek(&file, offset * CPM_RECORD_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_write(&file, control.storage.buffer, control.storage.counter, &control.storage.size); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_sync(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_close(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } - - control.storage.ready = 0; - } - } + disk_write_byte(value); break; case 0x0b: { - uint32_t temp = control.storage.lba & 0xFFFF00; - control.storage.lba = temp + value; + disk_set_lba_part(value, 0); break; } case 0x0c: { - uint32_t temp = control.storage.lba & 0xFF00FF; - control.storage.lba = temp + (value << 8); + disk_set_lba_part(value, 1); break; } case 0x0d: { - uint32_t temp = control.storage.lba & 0x00FFFF; - control.storage.lba = temp + (value << 16); + disk_set_lba_part(value, 2); break; } // Receive disk command case 0x0f: { - control.storage.command = value; - control.storage.counter = 0; - control.storage.size = 0; - - if (control.storage.command == 0x20) { - char filename[128] = {0}; - uint32_t offset = 0; - if (control.storage.lba == 0) { - snprintf(filename, 128, "0:loader.bin"); - offset = control.storage.lba - 0; - } else if (control.storage.lba >= 1 && control.storage.lba < 45) { - snprintf(filename, 128, "0:cpm22.bin"); - offset = control.storage.lba - 1; - } else if (control.storage.lba >= 45 && control.storage.lba < 51) { - snprintf(filename, 128, "0:bios.bin"); - offset = control.storage.lba - 45; - } else if (control.storage.lba >= 256 && control.storage.lba < 384) { - offset = control.storage.lba - 256; - control.storage.size = 128; - for (int i = 0; i < CPM_RECORD_SIZE; ++i) { - control.storage.buffer[i] = control.storage.directory[offset*CPM_RECORD_SIZE + i]; - } - } else if (control.storage.lba >= 384) { - uint32_t block = (control.storage.lba - 256) / CPM_RECORDS_PER_BLOCK; - - uint8_t found = 0; - for (int entry = 0; entry < 127; ++entry) { - uint8_t user = control.storage.directory[entry*32 + 0]; - if (user == 0xe5) { - continue; - } - - for (int i = 0; i < 8; ++i) { - uint16_t allocation = control.storage.directory[entry*32 + 16 + 2*i]; - allocation += control.storage.directory[entry*32 + 17 + 2*i] << 8; - - if (allocation == 0) { - break; - } - - if (allocation == block) { - found = 1; - offset = (control.storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK) + i*CPM_RECORDS_PER_BLOCK; - - char name[8]; - for (int j = 0; j < 8; ++j) { - char c = control.storage.directory[entry*32 + 1 + j]; - if (c == ' ') { - c = 0x00; - } - name[j] = c; - } - - char ext[3]; - for (int j = 0; j < 3; ++j) { - char c = control.storage.directory[entry*32 + 9 + j]; - if (c == ' ') { - c = 0x00; - } - ext[j] = c; - } - - snprintf(filename, 128, "0:A/%.8s.%.3s", name, ext); - - break; - } - } - - if (found) { - break; - } - } - } - - // @todo Maybe add a mechanism to read dirty blocks? - - if (filename[0]) { - FIL file; - // @todo Cache the currently opened file so we are not opening it every 128 bytes - FRESULT fr = f_open(&file, filename, FA_READ); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_lseek(&file, offset * CPM_RECORD_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_read(&file, control.storage.buffer, CPM_RECORD_SIZE, &control.storage.size); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_close(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } - - control.storage.ready = 1; - } else if (control.storage.command == 0x30) { - // We don't need to prepare enything - control.storage.ready = 1; - } + disk_receive_command(value); break; } @@ -594,135 +212,13 @@ void control_cycle() { set_clock(0); } -void get_disk_entries(char* diskpath) { - printf("Scanning: %s\n\r", diskpath); - - // Clear all entries - for (int i = 0; i < 0x4000; ++i) { - if (i % 32 == 0) { - control.storage.directory[i] = 0xe5; - } else { - control.storage.directory[i] = 0x00; - } - } - - DIR dir; - FILINFO fno; - FRESULT fr = f_opendir(&dir, diskpath); - if (fr == FR_OK) { - uint16_t end = 1; - uint8_t index = 0; - for (;;) { - fr = f_readdir(&dir, &fno); - if (fr != FR_OK || fno.fname[0] == 0) { - break; - } - - if (!(fno.fattrib & AM_DIR)) { - printf("File: %s\n\r", fno.fname); - control.storage.directory[index*32 + 0] = 0x00; - - // Calculate the number of records - uint32_t size = (fno.fsize + CPM_RECORD_SIZE - 1) / CPM_RECORD_SIZE; - - control.storage.directory[index*32 + 16] = end & 0xFF; - control.storage.directory[index*32 + 17] = (end >> 8) & 0xFF; - end++; - - int i = 1; - while (size >= 0x80) { - size -= 0x80; - control.storage.directory[index*32 + 16 + i*2] = end & 0xFF; - control.storage.directory[index*32 + 17 + i*2] = (end >> 8) & 0xFF; - end++; - i++; - } - - control.storage.directory[index*32 + 12] = (i-1) & 0xFF; - control.storage.directory[index*32 + 13] = 0x00; - control.storage.directory[index*32 + 14] = ((i-1) >> 8) & 0xFF; - - // Store the size in the number of records - control.storage.directory[index*32 + 15] = size; - /* free(entries[index].filename); */ - - uint8_t name_len = 9; - for (uint8_t i = 0; i < 8; ++i) { - char c = ' '; - - if (name_len == 9 && fno.fname[i] != '.') { - c = fno.fname[i]; - } else if (name_len == 9){ - name_len = i+1; - } - - control.storage.directory[index*32 + 1+i] = c; - } - - uint8_t done = 0; - for (uint8_t i = 0; i < 3; ++i) { - char c = ' '; - - if (!done && fno.fname[name_len+i] != 0) { - c = fno.fname[name_len+i]; - } else { - done = 1; - } - - control.storage.directory[index*32 + 9+i] = c; - } - - index++; - } - } - } else { - printf("File error: %i\n\r", fr); - return; - } - - - fr = f_closedir(&dir); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } -} - // @todo Properly reset everything void control_reset() { - free(control.storage.buffer); - free(control.storage.directory); - - f_close(control.storage.file); - free(control.storage.file); - - f_mount(0, "0:", 0); - free(control.storage.fs); - - while (control.storage.dirty_block) { - struct DirtyBlock* next = control.storage.dirty_block->next; - free(control.storage.dirty_block->data); - free(control.storage.dirty_block); - control.storage.dirty_block = next; - } - - Control temp = {0, {NULL, NULL, 0, 0, 0, 0, NULL, NULL, 0, NULL}}; + Control temp = {0}; control = temp; - control.storage.buffer = (uint8_t*)malloc(CPM_RECORD_SIZE); - control.storage.directory = (uint8_t*)malloc(0x4000); - - control.storage.fs = (FATFS*)malloc(sizeof(FATFS)); - control.storage.file = (FIL*)malloc(sizeof(FIL)); - - printf("Status: %i\n\r", disk_status(0)); - - FRESULT fr = f_mount(control.storage.fs, "0:", 0); - if (fr) { - printf("File error: %i\n\r", fr); - } - - get_disk_entries("0:A"); + disk_free(); + disk_init(); set_reset(1); for (int i = 0; i <= 10; ++i) { diff --git a/Src/disk.c b/Src/disk.c new file mode 100644 index 0000000..7229c04 --- /dev/null +++ b/Src/disk.c @@ -0,0 +1,541 @@ +#include +#include +#include +#include "fatfs.h" +#include "disk.h" + +#define CPM_RECORD_SIZE 128 +#define CPM_RECORDS_PER_BLOCK 128 +#define CPM_BLOCK_SIZE CPM_RECORD_SIZE*CPM_RECORDS_PER_BLOCK + +struct DirtyBlock { + uint32_t block; + struct DirtyBlock* next; + uint8_t size; + uint8_t* data; +}; + +typedef struct { + FATFS *fs; + uint8_t command; + uint8_t ready; + uint32_t counter; + uint32_t lba; + uint8_t* buffer; + uint8_t* directory; + unsigned int size; + struct DirtyBlock* dirty_block; +} Storage; + +Storage storage; + +uint8_t disk_read_byte() { + uint8_t value = 0x00; + if (storage.ready && storage.command == 0x20) { + if (storage.counter < storage.size) { + value = storage.buffer[storage.counter]; + } + + storage.counter++; + + if (storage.counter >= CPM_RECORD_SIZE) { + storage.ready = 0; + } + } + + return value; +} + +void disk_write_byte(uint8_t value) { + // @todo What if for whatever reason we write less then a record to disk? + if (storage.ready && storage.command == 0x30) { + storage.buffer[storage.counter] = value; + storage.counter++; + + if (storage.counter >= CPM_RECORD_SIZE) { + char filename[128] = {0}; + uint32_t offset = 0; + if (storage.lba == 0) { + snprintf(filename, 128, "0:loader.bin"); + offset = storage.lba - 0; + } else if (storage.lba >= 1 && storage.lba < 45) { + snprintf(filename, 128, "0:cpm22.bin"); + offset = storage.lba - 1; + } else if (storage.lba >= 45 && storage.lba < 51) { + snprintf(filename, 128, "0:bios.bin"); + offset = storage.lba - 45; + } else if (storage.lba >= 256 && storage.lba < 384) { + offset = storage.lba - 256; + + for (uint8_t index = 0; index < 4; ++index) { + char name[8]; + for (int j = 0; j < 8; ++j) { + char c = storage.buffer[index*32 + 1 + j]; + if (c == ' ') { + c = 0x00; + } + name[j] = c; + } + + char ext[3]; + for (int j = 0; j < 3; ++j) { + char c = storage.buffer[index*32 + 9 + j]; + if (c == ' ') { + c = 0x00; + } + ext[j] = c; + } + + char temp_filename[128]; + snprintf(temp_filename, 128, "0:A/%.8s.%.3s", name, ext); + + uint8_t user = storage.buffer[index*32 + 0]; + uint8_t user_old = storage.directory[offset*128 + index*32 + 0]; + + FIL file; + if (user != user_old) { + // @todo For some reason we keep getting a file entry that changes + // from 0 -> 0xe5 with no name + if (user == 0xe5) { + FRESULT fr = f_unlink(temp_filename); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + } else if (user_old == 0xe5) { + FRESULT fr = f_open(&file, temp_filename, FA_READ | FA_CREATE_ALWAYS); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + f_sync(&file); + f_close(&file); + } + } + + for (uint8_t i = 0; i < 8; ++i) { + uint16_t allocation = storage.buffer[index*32 + 16 + i*2]; + allocation += storage.buffer[index*32 + 17 + i*2] << 8; + + if (allocation == 0) { + break; + } + + struct DirtyBlock* prev = NULL; + struct DirtyBlock* current = storage.dirty_block; + while (current) { + if (allocation == current->block) { + FRESULT fr = f_open(&file, temp_filename, FA_WRITE); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + offset = i*CPM_RECORDS_PER_BLOCK; + fr = f_lseek(&file, offset * CPM_RECORD_SIZE); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_write(&file, current->data, current->size * CPM_RECORD_SIZE, &storage.size); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_sync(&file); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_close(&file); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + if (prev) { + prev->next = current->next; + } else { + storage.dirty_block = NULL; + } + + free(current->data); + free(current); + + break; + } + + prev = current; + current = current->next; + } + } + } + + memcpy(storage.directory + offset*CPM_RECORD_SIZE, storage.buffer, CPM_RECORD_SIZE); + } else if (storage.lba >= 384) { + uint32_t block = (storage.lba - 256) / CPM_RECORDS_PER_BLOCK; + + uint8_t found = 0; + for (int entry = 0; entry < 127; ++entry) { + uint8_t user = storage.directory[entry*32 + 0]; + if (user == 0xe5) { + continue; + } + + for (int i = 0; i < 8; ++i) { + uint16_t allocation = storage.directory[entry*32 + 16 + 2*i]; + allocation += storage.directory[entry*32 + 17 + 2*i] << 8; + + if (allocation == block) { + found = 1; + offset = (storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK) + i*CPM_RECORDS_PER_BLOCK; + + char name[8]; + for (int j = 0; j < 8; ++j) { + char c = storage.directory[entry*32 + 1 + j]; + if (c == ' ') { + c = 0x00; + } + name[j] = c; + } + + char ext[3]; + for (int j = 0; j < 3; ++j) { + char c = storage.directory[entry*32 + 9 + j]; + if (c == ' ') { + c = 0x00; + } + ext[j] = c; + } + + snprintf(filename, 128, "0:A/%.8s.%.3s", name, ext); + + break; + } + } + + if (found) { + break; + } + } + + if (!found) { + // Check if we already have a dirty block for this block + struct DirtyBlock* dirty_block = storage.dirty_block; + while (dirty_block) { + if (dirty_block->block == block) { + break; + } + } + + // @todo It appears that it updates the file entry after every block written + // So we might not need a linked list, altough it probably is more robust this way + if (!dirty_block) { + dirty_block = malloc(sizeof(struct DirtyBlock)); + dirty_block->block = block; + dirty_block->next = storage.dirty_block; + storage.dirty_block = dirty_block; + dirty_block->size = 0; + dirty_block->data = malloc(CPM_BLOCK_SIZE); + } + + offset = (storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK); + memcpy(dirty_block->data + offset * CPM_RECORD_SIZE, storage.buffer, CPM_RECORD_SIZE); + + if (offset+1 > dirty_block->size) { + dirty_block->size = offset+1; + } + } + } + + if (filename[0]) { + FIL file; + // @0todo Cache the currently opened file so we are not opening it every 128 bytes + FRESULT fr = f_open(&file, filename, FA_WRITE); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_lseek(&file, offset * CPM_RECORD_SIZE); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_write(&file, storage.buffer, storage.counter, &storage.size); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_sync(&file); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_close(&file); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + } + + storage.ready = 0; + } + } +} + +void disk_receive_command(uint8_t command) { + storage.command = command; + storage.counter = 0; + storage.size = 0; + + if (storage.command == 0x20) { + char filename[128] = {0}; + uint32_t offset = 0; + if (storage.lba == 0) { + snprintf(filename, 128, "0:loader.bin"); + offset = storage.lba - 0; + } else if (storage.lba >= 1 && storage.lba < 45) { + snprintf(filename, 128, "0:cpm22.bin"); + offset = storage.lba - 1; + } else if (storage.lba >= 45 && storage.lba < 51) { + snprintf(filename, 128, "0:bios.bin"); + offset = storage.lba - 45; + } else if (storage.lba >= 256 && storage.lba < 384) { + offset = storage.lba - 256; + storage.size = 128; + for (int i = 0; i < CPM_RECORD_SIZE; ++i) { + storage.buffer[i] = storage.directory[offset*CPM_RECORD_SIZE + i]; + } + } else if (storage.lba >= 384) { + uint32_t block = (storage.lba - 256) / CPM_RECORDS_PER_BLOCK; + + uint8_t found = 0; + for (int entry = 0; entry < 127; ++entry) { + uint8_t user = storage.directory[entry*32 + 0]; + if (user == 0xe5) { + continue; + } + + for (int i = 0; i < 8; ++i) { + uint16_t allocation = storage.directory[entry*32 + 16 + 2*i]; + allocation += storage.directory[entry*32 + 17 + 2*i] << 8; + + if (allocation == 0) { + break; + } + + if (allocation == block) { + found = 1; + offset = (storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK) + i*CPM_RECORDS_PER_BLOCK; + + char name[8]; + for (int j = 0; j < 8; ++j) { + char c = storage.directory[entry*32 + 1 + j]; + if (c == ' ') { + c = 0x00; + } + name[j] = c; + } + + char ext[3]; + for (int j = 0; j < 3; ++j) { + char c = storage.directory[entry*32 + 9 + j]; + if (c == ' ') { + c = 0x00; + } + ext[j] = c; + } + + snprintf(filename, 128, "0:A/%.8s.%.3s", name, ext); + + break; + } + } + + if (found) { + break; + } + } + } + + // @todo Maybe add a mechanism to read dirty blocks? + + if (filename[0]) { + FIL file; + // @todo Cache the currently opened file so we are not opening it every 128 bytes + FRESULT fr = f_open(&file, filename, FA_READ); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_lseek(&file, offset * CPM_RECORD_SIZE); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_read(&file, storage.buffer, CPM_RECORD_SIZE, &storage.size); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_close(&file); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + } + + storage.ready = 1; + } else if (storage.command == 0x30) { + // We don't need to prepare enything + storage.ready = 1; + } +} + +uint8_t disk_is_ready() { + return storage.ready; +} + +void disk_get_entries() { + // Clear all entries + for (int i = 0; i < 0x4000; ++i) { + if (i % 32 == 0) { + storage.directory[i] = 0xe5; + } else { + storage.directory[i] = 0x00; + } + } + + DIR dir; + FILINFO fno; + FRESULT fr = f_opendir(&dir, "0:A"); + if (fr == FR_OK) { + uint16_t end = 1; + uint8_t index = 0; + for (;;) { + fr = f_readdir(&dir, &fno); + if (fr != FR_OK || fno.fname[0] == 0) { + break; + } + + if (!(fno.fattrib & AM_DIR)) { + printf("File: %s\n\r", fno.fname); + storage.directory[index*32 + 0] = 0x00; + + // Calculate the number of records + uint32_t size = (fno.fsize + CPM_RECORD_SIZE - 1) / CPM_RECORD_SIZE; + + storage.directory[index*32 + 16] = end & 0xFF; + storage.directory[index*32 + 17] = (end >> 8) & 0xFF; + end++; + + int i = 1; + while (size >= 0x80) { + size -= 0x80; + storage.directory[index*32 + 16 + i*2] = end & 0xFF; + storage.directory[index*32 + 17 + i*2] = (end >> 8) & 0xFF; + end++; + i++; + } + + storage.directory[index*32 + 12] = (i-1) & 0xFF; + storage.directory[index*32 + 13] = 0x00; + storage.directory[index*32 + 14] = ((i-1) >> 8) & 0xFF; + + // Store the size in the number of records + storage.directory[index*32 + 15] = size; + /* free(entries[index].filename); */ + + uint8_t name_len = 9; + for (uint8_t i = 0; i < 8; ++i) { + char c = ' '; + + if (name_len == 9 && fno.fname[i] != '.') { + c = fno.fname[i]; + } else if (name_len == 9){ + name_len = i+1; + } + + storage.directory[index*32 + 1+i] = c; + } + + uint8_t done = 0; + for (uint8_t i = 0; i < 3; ++i) { + char c = ' '; + + if (!done && fno.fname[name_len+i] != 0) { + c = fno.fname[name_len+i]; + } else { + done = 1; + } + + storage.directory[index*32 + 9+i] = c; + } + + index++; + } + } + } else { + printf("File error: %i\n\r", fr); + return; + } + + + fr = f_closedir(&dir); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + +} + +void disk_init() { + storage.command = 0; + storage.ready = 0; + storage.counter = 0; + storage.lba = 0; + storage.size = 0; + storage.dirty_block = NULL; + + storage.buffer = (uint8_t*)malloc(CPM_RECORD_SIZE); + storage.directory = (uint8_t*)malloc(0x4000); + + storage.fs = (FATFS*)malloc(sizeof(FATFS)); + + FRESULT fr = f_mount(storage.fs, "0:", 0); + if (fr) { + printf("File error: %i\n\r", fr); + } + + disk_get_entries(); +} + +void disk_free() { + free(storage.buffer); + free(storage.directory); + + f_mount(0, "0:", 0); + free(storage.fs); + + while (storage.dirty_block) { + struct DirtyBlock* next = storage.dirty_block->next; + free(storage.dirty_block->data); + free(storage.dirty_block); + storage.dirty_block = next; + } +} + +void disk_set_lba_part(uint8_t value, uint8_t part) { + uint32_t temp = storage.lba & ~(0xFF << 8*part); + storage.lba = temp + (value << 8*part); +} diff --git a/Src/main.c b/Src/main.c index b19819f..bd233d4 100644 --- a/Src/main.c +++ b/Src/main.c @@ -26,6 +26,7 @@ #include #include #include +#include "fatfs.h" #include "restart.h" #include "control.h" #include "firmware.h"