diff --git a/Inc/control.h b/Inc/control.h index 19b2d8e..acf8571 100644 --- a/Inc/control.h +++ b/Inc/control.h @@ -2,17 +2,43 @@ #define CONTROL_H #include "stm32f4xx_hal.h" +#include "fatfs.h" +#include + +enum Type { + TYPE_NONE, + TYPE_FILE, + TYPE_DIR +}; typedef struct { - uint8_t dirty; - uint8_t action; + // Block and size are in blocks of 128 + uint32_t start; + uint32_t size; + char* filename; + char name[8]; + char ext[3]; +} DiskEntry; + +typedef struct { + uint8_t entry_count; + uint8_t current; + DiskEntry entries[127]; + uint32_t end; +} Disk; + +typedef struct { + FATFS *fs; + FIL *file; + uint8_t command; uint8_t ready; - uint8_t lba_1; - uint8_t lba_2; - uint8_t lba_3; - uint32_t lba; uint32_t counter; + uint32_t lba; + uint32_t offset; uint8_t* buffer; + unsigned int size; + enum Type type; + Disk A; } Storage; typedef struct { diff --git a/Src/control.c b/Src/control.c index c6ff0e7..56c3519 100644 --- a/Src/control.c +++ b/Src/control.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "control.h" #include "io.h" #include "bsp_driver_sd.h" @@ -19,12 +20,9 @@ extern UART_HandleTypeDef huart2; extern uint8_t ack[1]; extern uint8_t nack[1]; -// @todo For some reason increasing SD_PAGES does not work -#define SD_PAGES 1 -#define CPM_PAGE_SIZE 128 - -#define SD_PAGE_SIZE 512 -#define CPM_PAGES (SD_PAGE_SIZE/CPM_PAGE_SIZE*SD_PAGES) +#define CPM_RECORD_SIZE 128 +#define CPM_RECODS_PER_BLOCK 128 +#define CPM_BLOCK_SIZE CPM_RECORD_SIZE*CPM_RECODS_PER_BLOCK uint8_t get_device(uint16_t address) { uint8_t page = address >> 12; @@ -37,20 +35,6 @@ uint8_t get_device(uint16_t address) { return 0xFF; } -uint32_t calculate_lba() { - uint32_t temp = (control.storage.lba_1) + (control.storage.lba_2 << 8) + (control.storage.lba_3 << 16); - if (temp/CPM_PAGES != control.storage.lba/CPM_PAGES) { - control.storage.dirty |= 1; - } - - /* printf("LBA [1]: %li\n\r", control.storage.lba_1); */ - /* printf("LBA [2]: %li\n\r", control.storage.lba_2); */ - /* printf("LBA [3]: %li\n\r", control.storage.lba_3); */ - /* printf("LBA: %li\n\r", control.storage.lba); */ - - return temp; -} - void control_program_eeprom(uint8_t* data, uint16_t length) { // Take control of the bus send_busrq(1); @@ -127,31 +111,100 @@ void handle_io_read() { /* write_data(0x00); */ /* break; */ + // Read byte from disk case 0x08: - if (control.storage.ready && control.storage.action == 0x20) { - write_data(control.storage.buffer[control.storage.counter + (control.storage.lba % CPM_PAGES)*CPM_PAGE_SIZE]); - control.storage.counter++; + if (control.storage.ready && control.storage.command == 0x20) { + if (control.storage.counter < control.storage.size) { + write_data(control.storage.buffer[control.storage.counter]); + control.storage.counter++; + } else { + write_data(0x00); + } - if (control.storage.counter >= CPM_PAGE_SIZE) { + if (control.storage.counter >= control.storage.size) { control.storage.ready = 0; - control.storage.action = 0; + control.storage.command = 0; } } else { write_data(0x00); } - break; + // Check if disk is ready case 0x0f: - // Check if we need to read and in that case to the read - if (control.storage.action && !control.storage.ready) { - if (!control.storage.dirty || BSP_SD_ReadBlocks((uint32_t*)control.storage.buffer, control.storage.lba/CPM_PAGES, SD_PAGES, SD_DATATIMEOUT) == MSD_OK) { - // Indicate that we are ready to read/write - control.storage.ready = 1; - control.storage.dirty = 0; - } else { - // If we failed to read we will try again next time - /* printf("READ FAIL!\n\r"); */ + if (control.storage.command == 0x20 && !control.storage.ready) { + switch (control.storage.type) { + case TYPE_NONE: + control.storage.size = 0; + control.storage.ready = 1; + break; + + case TYPE_FILE: { + FRESULT fr = f_lseek(control.storage.file, control.storage.offset * CPM_RECORD_SIZE); + if (fr) { + printf("File error: %i\n\r", fr); + } else { + control.storage.ready = 1; + } + + fr = f_read(control.storage.file, control.storage.buffer, CPM_RECORD_SIZE, &control.storage.size); + if (fr) { + printf("File error: %i\n\r", fr); + } else { + control.storage.ready = 1; + } + + break; + } + + case TYPE_DIR: { + for (int i = 0; i < 128; i += 32) { + control.storage.buffer[i] = 0xe5; + } + + for (int i = 0; i < 4; ++i) { + if (4*control.storage.offset + i >= control.storage.A.entry_count) { + break; + } + + control.storage.buffer[32*i + 0] = 0x00; + for (int j = 0; j < 8; ++j) { + control.storage.buffer[32*i + 1 + j] = control.storage.A.entries[4*control.storage.offset + i].name[j]; + } + + for (int j = 0; j < 3; ++j) { + control.storage.buffer[32*i + 9 + j] = control.storage.A.entries[4*control.storage.offset + i].ext[j]; + } + + uint16_t extents = 0x00; + uint16_t records = control.storage.A.entries[4*control.storage.offset + i].size; + + while (records >= 0x80) { + extents++; + records -= 0x80; + } + + control.storage.buffer[32*i + 12] = extents & 0xFF; // Extent low + control.storage.buffer[32*i + 13] = 0x00; // Reserved 0x00 + control.storage.buffer[32*i + 14] = (extents >> 8) & 0xFF; // Extent high + control.storage.buffer[32*i + 15] = records; + + for (int j = 0; j < 16; ++j) { + control.storage.buffer[32*i + 16 + j] = 0x00; + } + + for (int j = 0; j < (extents+1); ++j) { + control.storage.buffer[32*i + 16 + j*2] = control.storage.A.entries[4*control.storage.offset + i].start + j; + control.storage.buffer[32*i + 17 + j*2] = 0x00; + } + } + + control.storage.size = 128; + control.storage.ready = 1; + + break; + } + } } @@ -187,41 +240,88 @@ void handle_io_write() { printf("%c", value); break; + // Write byte to disk case 0x08: - if (control.storage.ready && control.storage.action == 0x30) { - control.storage.buffer[control.storage.counter + (control.storage.lba % CPM_PAGES)*CPM_PAGE_SIZE] = value; - control.storage.counter++; + break; - if (control.storage.counter >= CPM_PAGE_SIZE) { - // @todo We need to figure out some way to actually prevent write fails from occuring - if (BSP_SD_WriteBlocks((uint32_t*)control.storage.buffer, control.storage.lba/CPM_PAGES, SD_PAGES, SD_DATATIMEOUT) != MSD_OK) { - printf("WRITE FAIL!!\n\r"); - } - control.storage.ready = 0; - control.storage.action = 0; + case 0x0b: { + uint32_t temp = control.storage.lba & 0xFFFF00; + control.storage.lba = temp + value; + break; + } + + case 0x0c: { + uint32_t temp = control.storage.lba & 0xFF00FF; + control.storage.lba = temp + (value << 8); + break; + } + + case 0x0d: { + uint32_t temp = control.storage.lba & 0x00FFFF; + control.storage.lba = temp + (value << 16); + break; + } + + // Receive disk command + case 0x0f: { + control.storage.ready = 0; + control.storage.counter = 0; + control.storage.command = value; + FRESULT fr = 0; + + if (control.storage.type == TYPE_FILE) { + fr = f_close(control.storage.file); + if (fr) { + printf("File error: %i\n\r", fr); } } - break; - case 0x0b: - control.storage.lba_1 = value; - break; + // @todo We need to make it easier to set this up + if (control.storage.lba == 0) { + // bootloader + control.storage.offset = control.storage.lba - 0; + fr = f_open(control.storage.file, "0:loader.bin", FA_READ); + control.storage.type = TYPE_FILE; + } else if (control.storage.lba >= 1 && control.storage.lba < 45) { + // cpm + control.storage.offset = control.storage.lba - 1; + fr = f_open(control.storage.file, "0:cpm22.bin", FA_READ); + control.storage.type = TYPE_FILE; + } else if (control.storage.lba >= 45 && control.storage.lba < 51) { + // bios + control.storage.offset = control.storage.lba - 45; + fr = f_open(control.storage.file, "0:bios.bin", FA_READ); + control.storage.type = TYPE_FILE; + } else if (control.storage.lba >= 256 && control.storage.lba < (256+32)) { + // @todo Max out at end of disk A + control.storage.offset = control.storage.lba - 256; + control.storage.type = TYPE_DIR; + } else if (control.storage.lba > (256+32)) { + control.storage.type = TYPE_NONE; - case 0x0c: - control.storage.lba_2 = value; - break; + for (uint8_t i = 0; i < control.storage.A.entry_count; ++i) { + if (control.storage.lba >= (control.storage.A.entries[i].start-1)*CPM_RECODS_PER_BLOCK+384 && control.storage.lba < ((control.storage.A.entries[i].start-1)*CPM_RECODS_PER_BLOCK+384 + control.storage.A.entries[i].size)) { + control.storage.offset = control.storage.lba - (control.storage.A.entries[i].start-1)*CPM_RECODS_PER_BLOCK - 384; - case 0x0d: - control.storage.lba_3 = value; - break; + char buf[128]; + snprintf(buf, 128, "0:A/%s", control.storage.A.entries[i].filename); + fr = f_open(control.storage.file, buf, FA_READ); - case 0x0f: - if (value == 0x20 || value == 0x30) { - control.storage.lba = calculate_lba(); - control.storage.action = value; - control.storage.counter = 0; + control.storage.type = TYPE_FILE; + break; + } + } + } else { + // Empty + printf("Unknown %li\n\r", control.storage.lba); + control.storage.type = TYPE_NONE; + } + + if (fr) { + printf("File error: %i\n\r", fr); } break; + } default: printf("IO Write: %.2X @ %.2X\n\r", value, address); @@ -266,9 +366,88 @@ void control_cycle() { // @todo Properly reset everything void control_reset() { free(control.storage.buffer); - Control temp = {0, {1, 0, 0, 0, 0, 0, 0, 0, NULL}}; + + // @todo Pretty sure this is not actually correct, + // since the pointer is always not NULL once we malloc, + // even if we do not have a file open/disk mounted + if (control.storage.file) { + f_close(control.storage.file); + free(control.storage.file); + } + if (control.storage.fs) { + f_mount(0, "0:", 0); + free(control.storage.fs); + } + + Control temp = {0, {NULL, NULL, 0, 0, 0, 0, 0, NULL, 0, TYPE_NONE, {0}}}; control = temp; - control.storage.buffer = (uint8_t*)malloc(SD_PAGES*SD_PAGE_SIZE); + + control.storage.buffer = (uint8_t*)malloc(CPM_RECORD_SIZE); + + control.storage.fs = (FATFS*)malloc(sizeof(FATFS)); + control.storage.file = (FIL*)malloc(sizeof(FIL)); + FRESULT fr = f_mount(control.storage.fs, "0:", 0); + if (fr) { + printf("File error: %i\n\r", fr); + } + + DIR dir; + FILINFO fno; + fr = f_opendir(&dir, "0:A"); + control.storage.A.end = 1; + if (fr == FR_OK) { + for (;;) { + fr = f_readdir(&dir, &fno); + if (fr != FR_OK || fno.fname[0] == 0) { + break; + } + + if (!(fno.fattrib & AM_DIR)) { + uint8_t index = control.storage.A.entry_count; + control.storage.A.entries[index].start = control.storage.A.end; + + // Calculate the number of records + uint32_t size = (fno.fsize + CPM_RECORD_SIZE - 1) / CPM_RECORD_SIZE; + + // Increment the end by the number of blocks + control.storage.A.end += (size + CPM_RECODS_PER_BLOCK) / CPM_RECODS_PER_BLOCK; + + // Store the size in the number of records + control.storage.A.entries[index].size = size; + + control.storage.A.entries[index].filename = strdup(fno.fname); + + 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.A.entries[index].name[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.A.entries[index].ext[i] = c; + } + + control.storage.A.entry_count++; + + } + } + } set_reset(1); for (int i = 0; i <= 10; ++i) { diff --git a/Src/main.c b/Src/main.c index 9d2dea8..b19819f 100644 --- a/Src/main.c +++ b/Src/main.c @@ -19,7 +19,6 @@ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" -#include "fatfs.h" #include "usb_device.h" /* Private includes ----------------------------------------------------------*/ diff --git a/Src/sd_diskio.c b/Src/sd_diskio.c index 40424fc..0d35ab1 100644 --- a/Src/sd_diskio.c +++ b/Src/sd_diskio.c @@ -49,7 +49,7 @@ * BSP_SD_Init() elsewhere in the application. */ /* USER CODE BEGIN disableSDInit */ -/* #define DISABLE_SD_INIT */ +#define DISABLE_SD_INIT /* USER CODE END disableSDInit */ /* Private variables ---------------------------------------------------------*/