From: Leo C Date: Mon, 30 May 2016 15:33:27 +0000 (+0200) Subject: New command(s): attach (and detach) - not fully working. X-Git-Tag: hexrel-6.7.1~7 X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/commitdiff_plain/cb4fb1ed02b59f798368a76f2596d7c24125e68a New command(s): attach (and detach) - not fully working. --- diff --git a/avr/Tupfile b/avr/Tupfile index 9bb0d11..be74c2d 100644 --- a/avr/Tupfile +++ b/avr/Tupfile @@ -7,7 +7,7 @@ FATFS = $(TOP)/fatfs/src/ff.c SRC = main.c SRC += cli.c cli_readline.c command.c command_tbl.c SRC += cmd_help.c cmd_run.c cmd_boot.c cmd_misc.c -SRC += cmd_date.c cmd_mem.c cmd_gpio.c +SRC += cmd_date.c cmd_mem.c cmd_gpio.c cmd_attach.c SRC += cmd_loadihex.c cmd_loadcpm3.c cmd_sd.c cmd_fat.c SRC += env.c xmalloc.c con-utils.c print-utils.c getopt-min.c SRC += timer.c serial.c i2c.c bcd.c pcf8583.c mmc.c diff --git a/avr/cmd_attach.c b/avr/cmd_attach.c new file mode 100644 index 0000000..e1a3b2c --- /dev/null +++ b/avr/cmd_attach.c @@ -0,0 +1,157 @@ +/* + * (C) Copyright 2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* + * attach chanels to devices + */ + +#include "common.h" +#include +#include + +#include "command.h" +#include "z180-serv.h" +#include "getopt-min.h" +//#include "print-utils.h" +//#include "con-utils.h" +//#include "timer.h" +//#include "z80-if.h" +//#include "debug.h" + + +static const FLASH char * const FLASH rc_messages[] = { + FSTR("OK"), + FSTR("Unknown error"), + FSTR("Disk number out of range 0..7"), + FSTR("Disk allready attached"), + FSTR("Disk not attached"), + FSTR("File not found"), + FSTR("Not enough memory"), + FSTR("Error opening file"), + FSTR("File allready attached to other drive"), + }; + +static +void printerror(int rc, uint8_t unit, char *fn) +{ + if (rc < 0 || (unsigned) rc >= ARRAY_SIZE(rc_messages)) + rc = 1; + +#if GCC_BUG_61443 * 0 + printf_P(PSTR("rc=%u FR_"), rc); + my_puts_P(rc_names[rc]); + my_puts_P(PSTR("\n")); +#else + printf_P(PSTR("Attachment of '%s' to dsk%d failed: %S!\n"), + fn, unit, rc_messages[rc]); +#endif +} + +/* + * attach [[options] [unit [diskfile]]] + * + * detach unit + * attach -d unit + * + * attach -o reattach unit + * attach -o reattach unit diskfile + * + * attach unit diskfile + * + */ + +command_ret_t do_attach(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + uint8_t unit; + char *filename = NULL; + bool detach = false; + drv_opt_t options = 0; + int res; + + (void) cmdtp; (void) flag; + + + if (argv[0][0] == 'd') + /* we are called as 'detach' */ + detach = true; + + if (argc == 1) { + /* no arguments */ + drv_list(); + return CMD_RET_SUCCESS; + } + + /* reset getopt() */ + optind = 1; + + int opt; + while ((opt = getopt(argc, argv, PSTR("drwo:"))) != -1) { + switch (opt) { + case 'd': + detach = true; + break; + case 'r': + options |= DRV_OPT_RO; + break; + case 'w': + options &= ~DRV_OPT_RO; + break; + case 'o': + { + static const FLASH char delim[] = {", "}; + char *p = strtok_P(optarg, delim); + while (p != NULL) { + if (!strcmp_P(p, PSTR("ro"))) + options |= DRV_OPT_RO; + else if (!strcmp_P(p, PSTR("rw"))) + options &= ~DRV_OPT_RO; + else if (!strcmp_P(p, PSTR("debug"))) + options |= DRV_OPT_DEBUG; + else if (!strcmp_P(p, PSTR("nodebug"))) + options &= ~DRV_OPT_DEBUG; + else if (!strcmp_P(p, PSTR("reattach"))) + options |= DRV_OPT_REATTATCH; + else + return CMD_RET_USAGE; + + p = strtok_P(NULL, delim); + } + } + break; + default: /* '?' */ + return CMD_RET_USAGE; + } + } + + /* remaining arguments */ + argc -= optind; + if ( !((detach && argc == 1) || + ((options & DRV_OPT_REATTATCH) && argc == 1) || + argc == 2) ) + return CMD_RET_USAGE; + + if ((strlen(argv[optind]) != 4) || + strncmp_P(argv[optind], PSTR("dsk"), 3) || + (unit = argv[optind][3] - '0') >= CONFIG_CPM_MAX_DRIVE) { + + printf_P(PSTR("Unknown device: '%s'\n"), argv[optind]); + return CMD_RET_FAILURE; + } + + if (detach) { + res = drv_detach(unit); + return CMD_RET_SUCCESS; + } + + if (argc == 2) + filename = argv[++optind]; + + res = drv_attach(unit, filename, options); + if (res) + printerror(res, unit, filename); + + return res ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c index 0d98296..73f2cf3 100644 --- a/avr/cmd_boot.c +++ b/avr/cmd_boot.c @@ -21,7 +21,7 @@ #include "env.h" #include "con-utils.h" #include "z80-if.h" -#include "z180-serv.h" +#include "z180-serv.h" /* restart_z180_serv() */ #include "debug.h" /* ugly hack to get Z180 loadfile into flash memory */ diff --git a/avr/command_tbl.c b/avr/command_tbl.c index 5dcbf1f..944c1c4 100644 --- a/avr/command_tbl.c +++ b/avr/command_tbl.c @@ -37,6 +37,7 @@ extern command_ret_t do_fat_ls(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_fat_rw(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); extern command_ret_t do_source(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +extern command_ret_t do_attach(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #ifdef CONFIG_SYS_LONGHELP const FLASH char sd_help_text[] = @@ -349,6 +350,22 @@ CMD_TBL_ITEM( " - Write file to 'path/filename' on logical drive 'd' from RAM\n" " starting at address 'addr'.\n" ), +CMD_TBL_ITEM( + attach, CONFIG_SYS_MAXARGS, 1, do_attach, + "attach filesystem image file to CP/M drive", + "[options] [dsk ]\n" + " - attach drive number to diskfile \n" + "attach -d dsk\n" + " - detach drive\n" + "attach\n" + " - without arguments, list current assignments" +), +CMD_TBL_ITEM( + detach, 2, 1, do_attach, + "detach file from CP/M drive", + "dsk]\n" + " - same as attach -d dsk" +), CMD_TBL_ITEM( help, CONFIG_SYS_MAXARGS, 1, do_help, diff --git a/avr/z180-serv.c b/avr/z180-serv.c index e2a39d3..1bf76b4 100644 --- a/avr/z180-serv.c +++ b/avr/z180-serv.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-2.0 */ +#include "z180-serv.h" #include "common.h" #include #include @@ -18,13 +19,12 @@ #include "z80-if.h" #include "debug.h" #include "print-utils.h" -#include "z180-serv.h" #include "timer.h" #include "time.h" #include "bcd.h" #include "rtc.h" -#define DEBUG_CPM_SDIO 0 /* set to 1 to debug */ +#define DEBUG_CPM_SDIO 1 /* set to 1 to debug */ #define debug_cpmsd(fmt, args...) \ debug_cond(DEBUG_CPM_SDIO, fmt, ##args) @@ -207,22 +207,120 @@ void do_msg_get_set_time(uint8_t subf, int len, uint8_t * msg) /* ---------------------------------------------------------------------------*/ -/* TODO: Variable Disk Format */ -#define CONFIG_CPM_DISKSIZE (8*1024*1024L) - -struct cpm_drive_s { - uint8_t drv; - uint8_t device; - char *img_name; - bool dirty; - FIL fd; -}; - static uint8_t disk_buffer[CONFIG_CPM_BLOCK_SIZE]; static struct cpm_drive_s drv_table[CONFIG_CPM_MAX_DRIVE]; static int handle_cpm_drv_to; +int drv_list(void) +{ + for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++) { + struct cpm_drive_s * p = &drv_table[i]; + if (p->img_name) { + printf_P(PSTR(" dsk%d: %2s %3s attached to %s\n"), i, + p->opt&DRV_OPT_RO ? "RO":"RW", p->opt&DRV_OPT_DEBUG ? "DBG":"", + p->img_name); + } + } + return 0; +} + +int drv_detach(uint8_t drv) +{ + if (drv < CONFIG_CPM_MAX_DRIVE) { + struct cpm_drive_s *p = &drv_table[drv]; + + debug_cpmsd("## detach dsk%d: %s\n", drv, + p->img_name ? p->img_name : "-"); + + if (p->img_name) { + f_close(&p->fd); + p->opt = 0; + p->dirty = false; + free(p->img_name); + p->img_name = NULL; + } + } + return 0; +} + +static int drv_find_file_attached(const char *fn) +{ + for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++) { + struct cpm_drive_s *p = &drv_table[i]; + if (p->img_name && !strcmp(fn, p->img_name)) { + return i; + } + } + return -1; +} + +int drv_attach(uint8_t drv, const char *filename, drv_opt_t options) +{ + int res; + + if (drv >= CONFIG_CPM_MAX_DRIVE) + return AT_RANGE; + + struct cpm_drive_s *p = &drv_table[drv]; + + if (options & DRV_OPT_REATTATCH) { + if (filename) { + return AT_ERROR; + } + + if (!p->img_name) { + return AT_NOT; + } + + p->opt = options & ~DRV_OPT_REATTATCH; + + /* TODO: change options */ + + } else { + + if (p->img_name) + return AT_ALREADY; + if (drv_find_file_attached(filename) >= 0) + return AT_OTHER; + + p->opt = options & ~DRV_OPT_REATTATCH; + + /* new attachment */ + + if ((p->img_name = strdup(filename)) == NULL) + return AT_NOMEM; + + res = f_open(&p->fd, p->img_name, + FA_WRITE | FA_READ); + + if (!res && f_size(&p->fd) < CONFIG_CPM_DISKSIZE) { + unsigned int bw; + + debug_cpmsd(" expanding image file from %ld to %ld\n", + f_size(&p->fd), CONFIG_CPM_DISKSIZE); + + res = f_lseek(&p->fd, CONFIG_CPM_DISKSIZE-CONFIG_CPM_BLOCK_SIZE); + if (!res) { + memset(disk_buffer, 0xe5, CONFIG_CPM_BLOCK_SIZE); + res = f_write(&p->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &bw); + if (res || bw < CONFIG_CPM_BLOCK_SIZE) { + debug_cpmsd(" failed! res: %d, bytes written: %u\n", res, bw); + } + p->dirty = true; + bg_setstat(handle_cpm_drv_to, 1); + } + } + if (res) { + drv_detach(drv); + return AT_OPEN; + } + } + + return AT_OK; +} + + int cpm_drv_to(int state) { static uint32_t ts; @@ -294,13 +392,13 @@ void do_msg_cpm_login(uint8_t subf, int len, uint8_t * msg) /* Get relative drive number */ drv = msg[1]; - if ( drv>= CONFIG_CPM_MAX_DRIVE) { + if ( drv >= CONFIG_CPM_MAX_DRIVE) { return msg_cpm_result(subf, 0x02, res); } -/* - uint32_t dph = ((uint32_t)msg[4] << 16) + ((uint16_t)msg[3] << 8) + msg[2]; -*/ + + drv_table[drv].dph = ((uint32_t)msg[4] << 16) + ((uint16_t)msg[3] << 8) + msg[2]; + if (drv_table[drv].img_name != NULL) { debug_cpmsd("## %7lu close: '%s'\n", get_timer(0), drv_table[drv].img_name); diff --git a/include/getopt-min.h b/include/getopt-min.h index 6495ebf..e42aa78 100644 --- a/include/getopt-min.h +++ b/include/getopt-min.h @@ -7,5 +7,6 @@ int getopt( /* returns letter, '?', EOF */ const FLASH char * optstring ); /* allowed args, e.g. "ab:c" */ extern int optind; +extern char *optarg; #endif /* GETOPT_MIN_H */ diff --git a/include/z180-serv.h b/include/z180-serv.h index 424318f..5385ecd 100644 --- a/include/z180-serv.h +++ b/include/z180-serv.h @@ -7,7 +7,47 @@ #ifndef Z180_SERV_H #define Z180_SERV_H +#include +#include "ff.h" + void setup_z180_serv(void); void restart_z180_serv(void); + +/* CP/M drive interface */ + +/* TODO: Variable Disk Format */ +#define CONFIG_CPM_DISKSIZE (8*1024*1024L) + +typedef uint8_t drv_opt_t; + +#define DRV_OPT_RO (1<<0) /* Drive is write protected */ +#define DRV_OPT_DEBUG (1<<1) /* Debug this drive */ +#define DRV_OPT_REATTATCH (1<<7) /* Change existing attachment */ + +struct cpm_drive_s { + drv_opt_t opt; + bool dirty; + uint32_t dph; + char *img_name; + FIL fd; +}; + +/* Return codes */ + +#define AT_OK 0 +#define AT_ERROR 1 +#define AT_RANGE 2 +#define AT_ALREADY 3 +#define AT_NOT 4 +#define AT_NOFILE 5 +#define AT_NOMEM 6 +#define AT_OPEN 7 +#define AT_OTHER 8 + + +int drv_list(void); +int drv_detach(uint8_t drv); +int drv_attach(uint8_t drv, const char *filename, drv_opt_t options); + #endif /* Z180_SERV_H */