From 28c563341f152350edb98dbd7a37aafdd92d84bd Mon Sep 17 00:00:00 2001 From: dschmenk Date: Fri, 31 May 2013 11:14:36 -0700 Subject: [PATCH] break larger transfers into smaller blocks Serial protocol is more stable with smaller transfers between synchronization. Add ability to write ProDOS disks. --- src/A2PI.PO | Bin 143360 -> 143360 bytes src/a2pid.c | 72 +++++++++++++++----- src/dskwrite.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 16 deletions(-) create mode 100755 src/dskwrite.c diff --git a/src/A2PI.PO b/src/A2PI.PO index 414095778f2882dd5f50a43ee0235029a94f774d..9f26945277f7b9a703fe1764efa4726465646235 100755 GIT binary patch delta 1161 zcmYL{e@s(X6vumC`})Jd)?Q0Naqc<+WiWwkM##)aHh+;d>L5(WmPn#Fh`O;YQL;=! zBXtb-CU~IG0@8LqvGQZoicq9bKq$qGJX}W>69Suzj2|rzt88Xl*sI3u{&DU--}5== z+;ekFrsXBm^7cwe_@VZf!#0Z^h(w_ST$bdcO(3D;kj0TeZ#j#cj;wP@;S|F_X~o;Z z=D1U#qR@SqxTHhPjvPowf>T>nge;(_E=5lGuDV9i9pwDl>ys`UY%@eEN`jN-ASZTN zV83CPP!|kF3cU)i8>5jAGK}M>2BJ+HPz9u#E}?9=YpOu8@KIgVD-ZP8wxnN6*7>Fr z+QsDYV!4u3`FPFqEX)9sq)&cYeM0EO)2j)9Z zpkLuo*XPI%qg^`{Y3AjamV=Zn9A0vMjNWvdb|Ol0c9C?zSGWI=uuEhR3VPy%E*E<= zXb`UUyh~@Y7h_vtu_qUGz#dn=#J8mFf*)KO6a~YsM5KYBs{<8)t@o&)yx14DyE{;D zeOOt$&%8RCyk*3m<7M~=ua%d0n>d>I1N@@*HvfD4VQ$8%PPFD~zr9bg0?#m&fNl3S z@hOSraJ-Lf7!R<$`W&{8@7Cv9SMy4^DpW${ZqPk{1Ye50maGszzgotK*}egKn(ode_U}UW@5papBMNS zJ{>3$-fwzfmO^Uq3~k;)`@L`R8lv{Q!`sEiZPbXDaLa`DvyonOY#r;;_pv?tUUE0U ziuB5|XII}v4#1}2*M!fY9nO^wE?pIqW@sKxMKsI|?@;=dtg9xHHpLyB6?4^uh6GPE zT7P4Q;QiR zW=x=&k4ZA%co}2DYlJ1}oZ1{_mwHpUFjgjzPgNtHm9aAK2xre}F+t&cGBSc`e(Mn< zc7EfIm-AE3GPhU9{bCa_55+bm6BK8#%p-Bj^SD?$plTDjlT*hoV{Xo@CKgruZ!IS5 zES4~J*!h=)smJCBL2a$W;q{nHeHxR+m;BfOu?tCYMrM< z!6Q0VYXf|_uywrw^Xt#c_Ju~ZOZCz=18%9s1@dA7(6bP${0w`mxQ*6oqQL}&bjR|7 zlA^!A;=IY+2&9W0A1<>Ll+cJSwV->gpOhV E0qx}*$^ZZW delta 1127 zcmXw1e@s(X6z+YmwA4w~UZH>xcQcULSp}9D%6?$7X(CzYP~wDS$yg>%+%RlQglx`0 zqy}+M&?9I8>7%9KQ^3~egib2O@#{HmwglNgQ&)+);Z)r@P0z9zG+&zbw!`N7Sk2Mp>E>mT z_S#@){WfIdq25X%0-LM}XdJSwW2g=i8WPbdFg2V(x$s>>ElPrS8{?k)*@C%6%Ni0t zIkVA4ljVoiTFSp>)kQZ>LsjH4K%;S;Ef{e)q$Syta+dRONM+hTW}bU&)cTCEGv@dC z=|(G(ElV#%P{;va+Hw&GV>T(m&9HX{_yP8E6f*H8UArQc$&2P17`*;AN{5*4Ni+xx z-5;X|u(#(^bOmnrysF7ymy$bjDDD|}*7G5Hi7)jaN_pfV;o-=QIi+Kf^uvMP6xpSw zSC9Ikt@jN&C%Fcs-h9Nv4sW4ye9?Rz++ID>!-&_2qT#XkYqTFO-`poF+P*l{1BSlD z4FM_iP`DBL&G4T1t3BFi&o_Vd1KA~wxbp-iq!a9+Ekb)J-B<<1eI)U&W zg;zp)f`h&&7j4~4jR-_sB6QFhE1>=HPOqiU*=xB;1j(teXsiBfeH(cTl7?QC|9t0A zzN&w*jV2s)4w(=Q{-F%*_@ezu1Ic_K=J;u`j?l1aH~}p{_V9KYYle3tGt3Tms<*G0 zUt3Wq__HIQ5r~>!PGlXeo@)%(Z&7m!i;8K&%mvIeW5$LV7W50rsZH3RW>~yRKC&)G zv#Z@IAzfVURLhx9RU7uJooZo3bmw)jP_&RHFLT4fh7WAmbHZnc3_b8v`Gg8_ic>JZ z)0~!Brn8;QBf8`NIBmYA>r(jAOrxz>oM)p+i_SIM!D3IDl4-%7Ka`9evoW&T*@C0& zSTsG2sSV}dJ79evHN}RxN^&wB4Wm7b<^&z%z_J5(TxO&~*Xe-I0~^*h;n3RS>K)-x z-71T!s|j~B;{%ap#0tHE_1aP_oE6vE>xdo`t6a`61+)~ema^y=N2|-lu#^2$;myC# zPE33|apx|dwbVgfeYAzz>cnwHPpZRS^|~Sj(}t_fCv|p3S@;FCp+7l9F8<9aF3BCW psH{~!ze=S1>QN^ae;RGW;(a)@60ecje3*3~t6k}?T|oyk{{`type = type; a2req->addr = addr; a2req->count = count; + a2req->xfer = 0; a2req->buffer = buffer; a2req->next = NULL; if (a2reqlist == NULL) @@ -485,7 +492,7 @@ void main(int argc, char **argv) struct uinput_user_dev uidev; struct termios oldtio,newtio; char iopkt[16]; - int i, lastbtn; + int i, c, lastbtn; int a2fd, kbdfd, moufd, srvfd, reqfd, maxfd; struct sockaddr_in servaddr; fd_set readset, openset; @@ -662,7 +669,7 @@ void main(int argc, char **argv) { if (read(a2fd, iopkt, 3) == 3) { - // printf("a2pi: Event [0x%02X] [0x%02X] [0x%02X]\n", iopkt[0], iopkt[1], iopkt[2]); + //printf("a2pi: Event [0x%02X] [0x%02X] [0x%02X]\n", iopkt[0], iopkt[1], iopkt[2]); switch (iopkt[0]) { case 0x80: /* sync */ @@ -688,15 +695,18 @@ void main(int argc, char **argv) case 0x90: /* acknowledge read bytes request*/ if (a2reqlist) /* better have an outstanding request */ { - // printf("a2pid: read %d bytes from 0x%04X\n", a2reqlist->count, a2reqlist->addr); + //printf("a2pid: read %d of %d bytes from 0x%04X\n", a2reqlist->xfer, a2reqlist->count, a2reqlist->addr); newtio.c_cc[VMIN] = 1; /* blocking read until 1 char received */ tcsetattr(a2fd, TCSANOW, &newtio); - if (writeword(a2fd, a2reqlist->addr, 0x91) && writeword(a2fd, a2reqlist->count, 0x91)) + c = a2reqlist->count - a2reqlist->xfer > MAX_XFER + ? MAX_XFER + : a2reqlist->count - a2reqlist->xfer; + if (writeword(a2fd, a2reqlist->addr + a2reqlist->xfer, 0x91) && writeword(a2fd, c, 0x91)) { - for (i = 0; i < a2reqlist->count; i++) + for (i = 0; i < c; i++) { if (read(a2fd, iopkt, 1) == 1) - a2reqlist->buffer[i] = iopkt[0]; + a2reqlist->buffer[a2reqlist->xfer++] = iopkt[0]; else { stop = TRUE; @@ -715,12 +725,17 @@ void main(int argc, char **argv) case 0x92: /* acknowledge write bytes */ if (a2reqlist) /* better have an outstanding request */ { - // printf("a2pid: wrote %d bytes to 0x%04X\n", a2reqlist->count, a2reqlist->addr); + //printf("a2pid: wrote %d of %d bytes to 0x%04X\n", a2reqlist->xfer, a2reqlist->count, a2reqlist->addr); newtio.c_cc[VMIN] = 1; /* blocking read until 1 char received */ tcsetattr(a2fd, TCSANOW, &newtio); - if (writeword(a2fd, a2reqlist->addr, 0x93) && writeword(a2fd, a2reqlist->count, 0x93)) + c = a2reqlist->count - a2reqlist->xfer > MAX_XFER + ? MAX_XFER + : a2reqlist->count - a2reqlist->xfer; + if (writeword(a2fd, a2reqlist->addr + a2reqlist->xfer, 0x93) && writeword(a2fd, c, 0x93)) { - if (write(a2fd, a2reqlist->buffer, a2reqlist->count) != a2reqlist->count) + if (write(a2fd, a2reqlist->buffer + a2reqlist->xfer, c) == c) + a2reqlist->xfer += c; + else stop = TRUE; } else @@ -734,7 +749,7 @@ void main(int argc, char **argv) case 0x94: /* acknowledge call */ if (a2reqlist) /* better have an outstanding request */ { - // printf("a2pid: call address 0x%04X\n", a2reqlist->addr); + //printf("a2pid: call address 0x%04X\n", a2reqlist->addr); newtio.c_cc[VMIN] = 1; /* blocking read until 1 char received */ tcsetattr(a2fd, TCSANOW, &newtio); if (!writeword(a2fd, a2reqlist->addr, 0x95)) @@ -747,8 +762,21 @@ void main(int argc, char **argv) break; case 0x9E: /* request complete ok */ case 0x9F: /* request complete error */ - // printf("a2pid: finish request 0x%02X:0x%02X\n", (unsigned char)iopkt[0], (unsigned char)iopkt[1]); - finreq(a2fd, (unsigned char)iopkt[0], (unsigned char)iopkt[1]); + if (a2reqlist) /* better have an outstanding request */ + { + //printf("a2pid: complete request 0x%02X:0x%02X\n", (unsigned char)iopkt[0], (unsigned char)iopkt[1]); + if ((a2reqlist->type == 0x90 || a2reqlist->type == 0x92) + && (a2reqlist->count > a2reqlist->xfer)) + { + iopkt[0] = a2reqlist->type; + write(a2fd, iopkt, 1); + } + else + { + //printf("a2pid: finish request 0x%02X:0x%02X\n", (unsigned char)iopkt[0], (unsigned char)iopkt[1]); + finreq(a2fd, (unsigned char)iopkt[0], (unsigned char)iopkt[1]); + } + } break; default: prlog("a2pid: Unknown Event\n"); @@ -799,6 +827,12 @@ void main(int argc, char **argv) databuf = malloc(count); addreq(a2fd, reqfd, 0x90, addr, count, databuf); } + else + { + iopkt[0] = 0x9E; + iopkt[1] = 0x00; + write(reqfd, iopkt, 2); + } } break; case 0x92: /* write bytes */ @@ -812,6 +846,12 @@ void main(int argc, char **argv) if (read(reqfd, databuf, count) == count) addreq(a2fd, reqfd, 0x92, addr, count, databuf); } + else + { + iopkt[0] = 0x9E; + iopkt[1] = 0x00; + write(reqfd, iopkt, 2); + } } break; case 0x94: /* call */ diff --git a/src/dskwrite.c b/src/dskwrite.c new file mode 100755 index 0000000..dcde389 --- /dev/null +++ b/src/dskwrite.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int a2open(char *ipaddr) +{ + struct sockaddr_in piaddr; + int res; + int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd < 0) + { + perror("Cannot create socket"); + return -1; + } + memset(&piaddr, 0, sizeof(piaddr)); + piaddr.sin_family = AF_INET; + piaddr.sin_port = htons(6502); + res = inet_pton(AF_INET, ipaddr, &piaddr.sin_addr); + if (res < 0) + { + perror("First parameter is not a valid address family"); + close(fd); + return -1; + } + else if (res == 0) + { + perror("Char string (second parameter does not contain valid ipaddress)"); + close(fd); + return -1; + } + if (connect(fd, (struct sockaddr *)&piaddr, sizeof(piaddr)) < 0) + { + perror("Connect failed"); + close(fd); + return -1; + } + return fd; +} +void a2close(int fd) +{ + char closepkt; + closepkt = 0xFF; + write(fd, &closepkt, 1); + shutdown(fd, SHUT_RDWR); + close(fd); +} +int a2read(int fd, int address, int count, char *buffer) +{ + char readpkt[8]; + readpkt[0] = 0x90; // read + readpkt[1] = address; + readpkt[2] = address >> 8; + readpkt[3] = count; + readpkt[4] = count >> 8; + write(fd, readpkt, 5); + read(fd, buffer, count); + read(fd, readpkt, 2); + return ((unsigned char)readpkt[0] == 0x9E); +} +int a2write(int fd, int address, int count, char *buffer) +{ + char writepkt[8]; + writepkt[0] = 0x92; // write + writepkt[1] = address; + writepkt[2] = address >> 8; + writepkt[3] = count; + writepkt[4] = count >> 8; + write(fd, writepkt, 5); + write(fd, buffer, count); + read(fd, writepkt, 2); + return ((unsigned char)writepkt[0] == 0x9E); +} +int a2call(int fd, int address, int *result) +{ + char callpkt[4]; + callpkt[0] = 0x94; // call + callpkt[1] = address; + callpkt[2] = address >> 8; + write(fd, callpkt, 3); + read(fd, callpkt, 2); + if (result) + *result = (unsigned char)callpkt[1]; + return ((unsigned char)callpkt[0] == 0x9E); +} +char online[] = { +// ORG $300 + 0x20, 0x00, 0xBF, // JSR $BF00 (PRODOS) + 0xC5, // DB ON_LINE + 0x08, 0x03, // DW PARAMS + 0x60, // RTS + 0xEA, +// PARAMS @ $308 + 0x02, // PARAM_COUNT + 0x60, // UNIT_NUM = DRIVE 0, SLOT 6 + 0x00, 0x20 // DATA_BUFFER = $2000 +}; +char writeblk[] = { +// ORG $300 + 0x20, 0x00, 0xBF, // JSR $BF00 (PRODOS) + 0x81, // DB WRITE_BLOCK + 0x08, 0x03, // DW PARAMS + 0x60, // RTS + 0xEA, +// PARAMS @ $308 + 0x03, // PARAM_COUNT + 0x60, // UNIT_NUM = DRIVE 0, SLOT 6 + 0x00, 0x20, // DATA_BUFFER = $2000 + 0x00, 0x00 // BLOCK_NUM +}; +#define ORG 0x0300 +#define BLOCK_NUM 0x030C +#define DATA_BUFFER 0x2000 +char dsk[280][512]; + +int main(int argc, char **argv) +{ + FILE *dskfile; + char count[2], volname[21]; + int i, result, fd; + int pifd = a2open(argc > 2 ? argv[2] : "127.0.0.1"); + if (pifd < 0) + { + perror("Unable to connect to Apple II Pi"); + exit(EXIT_FAILURE); + } + if (argc < 2) + { + perror("Usage: dskwrite [ip address]\n"); + exit(EXIT_FAILURE); + } + a2write(pifd, ORG, sizeof(online), online); + a2call(pifd, ORG, &result); + if (result == 0) + { + a2read(pifd, DATA_BUFFER, 16, volname); + volname[(volname[0] & 0x0F) + 1] = '\0'; + printf("Are you sure you want to overwrite volume :%s?", volname + 1); + fflush(stdout); + fgets(count, 2, stdin); + if (count[0] != 'y' && count[0] != 'Y') + { + a2close(pifd); + exit(EXIT_FAILURE); + } + } + if ((dskfile = fopen(argv[1], "rb"))) + { + fread(dsk, 1, 280*512, dskfile); + fclose(dskfile); + } + else + { + perror("Unable to read .PO file\n"); + a2close(pifd); + exit(EXIT_FAILURE); + } + a2write(pifd, ORG, sizeof(writeblk), writeblk); + for (i = 0; i < 280; i++) + { + printf("Writing block #%d\r", i); + fflush(stdout); + count[0] = i; + count[1] = i >> 8; + a2write(pifd, DATA_BUFFER, 512, dsk[i]); + a2write(pifd, BLOCK_NUM, 2, count); + a2call(pifd, ORG, &result); + } + a2close(pifd); + return EXIT_SUCCESS; +} \ No newline at end of file