From: Christian Groessler Date: Wed, 19 Feb 2014 23:56:22 +0000 (+0100) Subject: add utility program to write files to cassette X-Git-Tag: V2.15~141^2~9 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=8178c71de1da66a8093a7a308541a5a1b75441fc;p=cc65 add utility program to write files to cassette --- diff --git a/util/atari/w2cas.c b/util/atari/w2cas.c new file mode 100644 index 000000000..38c2f0fdf --- /dev/null +++ b/util/atari/w2cas.c @@ -0,0 +1,186 @@ +/* w2cas.c -- write file to cassette + * + * This program writes a boot file (typically linked with + * 'atari-cassette.cfg') to the cassette. + * Only files < 32K are supported, since the loading of + * larger files requires a special loader inside the program. + * + * Christian Groessler, chris@groessler.org, 2014 + */ + +#include +#include +#include +#include +#include <6502.h> +#include +#include + +static int verbose = 1; +static char C_dev[] = "C:"; + +static struct __iocb *findfreeiocb(void) +{ + struct __iocb *iocb = &IOCB; /* first IOCB (#0) */ + int i; + + for (i = 0; i < 8; i++) { + if (iocb->handler == 0xff) + return iocb; + iocb++; + } + return NULL; +} + +int main(int argc, char **argv) +{ + char *filename, *x; + char buf[20]; + FILE *file; + unsigned char *buffer; + size_t filen, buflen = 32768l + 1; + struct regs regs; + struct __iocb *iocb = findfreeiocb(); + int iocb_num; + + if (! iocb) { + fprintf(stderr, "couldn't find a free iocb\n"); + if (_dos_type != 1) + cgetc(); + return 1; + } + iocb_num = (iocb - &IOCB) * 16; + if (verbose) + printf("using iocb index $%02X ($%04X)\n", iocb_num, iocb); + + if (argc < 2) { + printf("\nfilename: "); + x = fgets(buf, 19, stdin); + printf("\n"); + if (! x) + return 1; + if (*x && *(x + strlen(x) - 1) == '\n') + *(x + strlen(x) - 1) = 0; + filename = x; + } + else { + filename = *(argv+1); + } + + /* allocate buffer */ + buffer = malloc(buflen); + if (! buffer) { + buflen = _heapmaxavail() - 8; /* get as much as we can */ + buffer = malloc(buflen); + if (! buffer) { + fprintf(stderr, "cannot alloc %ld bytes -- aborting...\n", (long)buflen); + if (_dos_type != 1) + cgetc(); + return 1; + } + } + if (verbose) + printf("buffer size: %ld bytes\n", (long)buflen); + + /* open file */ + file = fopen(filename, "rb"); + if (! file) { + free(buffer); + fprintf(stderr, "cannot open '%s': %s\n", filename, strerror(errno)); + if (_dos_type != 1) + cgetc(); + return 1; + } + + /* read file -- file length must be < 32K */ + if (verbose) + printf("reading input file...\n"); + filen = fread(buffer, 1, buflen, file); + if (! filen) { + fprintf(stderr, "read error\n"); + file_err: + fclose(file); + free(buffer); + if (_dos_type != 1) + cgetc(); + return 1; + } + if (filen > 32767l) { + fprintf(stderr, "file is too large (must be < 32768)\n"); + goto file_err; + } + if (filen == buflen) { /* we have a buffer < 32768 and the file fits into it (and is most probably larger) */ + fprintf(stderr, "not enough memory\n"); + goto file_err; + } + if (verbose) + printf("file size: %ld bytes\n", (long)filen); + + /* close input file */ + fclose(file); + + /* open cassette */ + if (verbose) + printf("opening cassette...\n"); + iocb->buffer = C_dev; + iocb->aux1 = 8; /* open for output */ + iocb->aux2 = 128; /* short breaks and no stop between data blocks */ + iocb->command = IOCB_OPEN; + regs.x = iocb_num; + regs.pc = 0xe456; /* CIOV */ + + _sys(®s); + if (regs.y != 1) { + fprintf(stderr, "CIO call to open cassette returned %d\n", regs.y); + free(buffer); + if (_dos_type != 1) + cgetc(); + return 1; + } + + /* write file */ + if (verbose) + printf("writing to cassette...\n"); + iocb->buffer = buffer; + iocb->buflen = filen; + iocb->command = IOCB_PUTCHR; + regs.x = iocb_num; + regs.pc = 0xe456; /* CIOV */ + + _sys(®s); + if (regs.y != 1) { + fprintf(stderr, "CIO call to write file returned %d\n", regs.y); + free(buffer); + + iocb->command = IOCB_CLOSE; + regs.x = iocb_num; + regs.pc = 0xe456; /* CIOV */ + _sys(®s); + + if (_dos_type != 1) + cgetc(); + return 1; + } + + /* free buffer */ + free(buffer); + + /* close cassette */ + iocb->command = IOCB_CLOSE; + regs.x = iocb_num; + regs.pc = 0xe456; /* CIOV */ + _sys(®s); + + if (regs.y != 1) { + fprintf(stderr, "CIO call to close cassette returned %d\n", regs.y); + if (_dos_type != 1) + cgetc(); + return 1; + } + + /* all is fine */ + printf("success\n"); + if (_dos_type != 1) + cgetc(); + return 0; +}