/**************************************************************** * zx80save.c * ZX80-Programme direkt vom ZX80 aufnehmen * ======================================== * * 02.05.99 Bodo Wenzel V1.0, quick-and-dirty * 2002-04-28 Bodo Wenzel V1.1, auch Linux-Version, keine * Atari-Version mehr * 2002-05-06 Bodo Wenzel V1.2, echte Maschinen mit MIC- * Verstaerker liefern andere Signale ****************************************************************/ #include #include #include #include #if defined(__TOS__) #error "Sorry, Atari-Version nicht weitergepflegt." #include #elif defined(__MSDOS__) #include #elif defined(__unix__) #include #include #include #else #error "Anpassungen noetig!" #endif void quit(char *msg, int ret) { /*------------------------*/ puts(msg); exit(ret); } /* Das Verfahren ist durchaus verschieden geloest, daher in den * einzelnen "Abteilungen" erklaert. * Die Gemeinsamkeiten sind: * Empfangsfreie Zeit vor Aufzeichnung: 1 Sekunde * Abbruch ohne Empfang: 10 Sekunden */ #define SILENT (1) #define TIMEOUT (10) #if defined(__TOS__) /* V1.1/1.2: dies funktionierte mit dem direkten Videosignal, bei Bedarf * leicht verstaerkt. Mit dem hochverstaerkten MIC-Signal sind hier sicher * Anpassungen noetig... */ /* Der MFP des STs, der die serielle Schnittstelle beinhaltet, hat * ein hochinteressantes Feature: er synchronisiert sich auf die * Flanken zwischen den Bits! Daher wird hier 4800-8N1 eingestellt * und der MFP erhoeht automatisch auf etwa 6800 baud! Dadurch ist * die Erkennung der Bits sehr zuverlaessig! */ int serinit(void) { /*-------------*/ Rsconf(2, 0, 0x88, 0x01, 0x05, 0); return 1; } void rxdflush(void) { /*---------------*/ clock_t t; for (;;) { t = clock() + SILENT * CLK_TCK; while (!Bconstat(1)) if (clock() >= t) return; (void)Bconin(1); } } int rxdbyte(void) { /*-------------*/ clock_t t; int d, i, j; for (d = 0, i = 0; i < 8; i++) { d <<= 1; for (j = 0; j < 2; j++) { t = clock() + TIMEOUT * CLK_TCK; while (!Bconstat(1)) if (clock() >= t) return -1; if ((Bconin(1) & 0xFF) >= 0xC0) break; d |= 0x01; } } return d; } #endif #if defined(__MSDOS__) /* WICHTIG: damit keine Bits "verloren" gehen, muss unbedingt * ein Hardware- oder Software-FIFO verwendet werden! * * Die Schnittstelle wird auf 4800-7N1 eingestellt. Da je nach * Timing verschiedene Pegel an einzelnen Bits aufgenommen * werden, erfolgt der Vergleich ueber die MSBs. */ int com; int serinit(char *par) { /*------------------*/ com = -1; if (*par == '\0') com = 1; else if (sscanf(par, "%d", &com) != 1) return 0; if (com < 1 || com > 4) return 0; com--; bioscom(0, 0xC2, com); if ((bioscom(3, 0, com) & 0x6000) != 0) return 1; return 0; } void rxdflush(void) { /*---------------*/ clock_t t; /* Dummy fuer Handshakepegel */ bioscom(1, 0, com); for (t = clock() + CLK_TCK / 4; clock() < t; ); for (;;) { t = clock() + SILENT * CLK_TCK; while ((bioscom(3, 0, com) & 0x0100) == 0) if (clock() >= t) return; (void)bioscom(2, 0, com); } } int rxdbyte(void) { /*-------------*/ clock_t t; int d, i, j; for (d = 0, i = 0; i < 8; i++) { d <<= 1; for (j = 0; j < 2; j++) { t = clock() + TIMEOUT * CLK_TCK; while ((bioscom(3, 0, com) & 0x0100) == 0) if (clock() >= t) return -1; if ((bioscom(2, 0, com) & 0x7F) >= 0x60) break; d |= 0x01; } } return d; } #endif #if defined(__unix__) /* Die Schnittstelle wird auf 4800-7N1 eingestellt. Da je nach * Timing verschiedene Pegel an einzelnen Bits aufgenommen * werden, erfolgt der Vergleich ueber die MSBs. */ int fd; struct termios old_attr; void serexit(void) { /*--------------*/ tcsetattr(fd, TCSADRAIN, &old_attr); close(fd); } int serinit(char *port) { /*-------------------*/ struct termios attr; fd = open(port, O_RDWR | O_NOCTTY); if (fd < 0) return 0; tcgetattr(fd, &attr); old_attr = attr; atexit(serexit); cfmakeraw(&attr); cfsetospeed(&attr, B4800); cfsetispeed(&attr, B4800); attr.c_cflag &= ~CSIZE; attr.c_cflag |= CS7; if (tcsetattr(fd, TCSANOW, &attr) != 0) return 0; return 1; } void rxdflush(void) { /*---------------*/ int c; clock_t t; fd_set rfds; struct timeval tv; /* Dummy fuer Handshakepegel */ c = 0; (void)write(fd, &c, 1); for (t = clock() + CLK_TCK / 4; clock() < t; ); for (;;) { FD_ZERO(&rfds); FD_SET(fd, &rfds); tv.tv_sec = SILENT; tv.tv_usec = 0; if (select(fd + 1, &rfds, NULL, NULL, &tv) == 0) return; if (read(fd, &c, 1) != 1) return; } } int rxdbyte(void) { /*-------------*/ fd_set rfds; struct timeval tv; int d, i, j, c; for (d = 0, i = 0; i < 8; i++) { d <<= 1; for (j = 0; j < 2; j++) { FD_ZERO(&rfds); FD_SET(fd, &rfds); tv.tv_sec = TIMEOUT; tv.tv_usec = 0; if (select(fd + 1, &rfds, NULL, NULL, &tv) == 0) return -1; if (read(fd, &c, 1) != 1) return -1; c &= 0x7F; if (c >= 0x60) break; d |= 0x01; } } return d; } #endif typedef unsigned char uchar; #define START (0x4000) #define E_LINE (0x400A) #define BUFLEN (0xC000L - START) uchar *buffer; int main(int argc, char *argv[]) { /*----------------------------*/ int b; long i, l, dd, d; FILE *f; #if defined(__TOS__) if (argc < 2) quit("Aufruf: ZX80SAVE ", 1); #endif #if defined(__MSDOS__) if (argc < 2) quit("Aufruf: ZX80SAVE []", 1); #endif #if defined(__unix__) setbuf(stdout, NULL); if (argc < 3) quit("Aufruf: zx80save ", 1); #endif if ((buffer = (uchar *)malloc((size_t)BUFLEN)) == NULL) quit("Speicherueberlauf", 4); #if defined(__TOS__) if (!serinit()) quit("Kann Schnittstelle nicht initialisieren!", 3); #endif #if defined(__MSDOS__) if (!serinit(argc >= 3 ? argv[2] : "")) quit("Kann Schnittstelle nicht initialisieren!", 3); #endif #if defined(__unix__) if (!serinit(argv[2])) quit("Kann Schnittstelle nicht initialisieren!", 3); #endif rxdflush(); for (i = 0; i < E_LINE - START + 2; i++) { if ((b = rxdbyte()) < 0) break; buffer[(size_t)i] = b; } l = buffer[E_LINE - START + 1]; l <<= 8; l |= buffer[E_LINE - START]; l -= START; if (l < 0 || l > BUFLEN) quit("Uebertragungsfehler!", 5); printf("%ld Bytes:\n", l); dd = l >> 6; for (d = 0; d < l; d += dd) putchar('-'); putchar('\r'); for (d = 0; i < l; i++) { if (i > d) { d += dd; putchar('*'); } if ((b = rxdbyte()) < 0) break; buffer[(size_t)i] = b; } putchar('\n'); if (i != l || buffer[(size_t)l - 1] != 0x80) quit("Uebertragungsfehler!", 5); if ((f = fopen(argv[1], "wb")) == NULL) quit("Kann Datei nicht oeffnen!", 2); if (fwrite(buffer, sizeof(uchar), (size_t)l, f) != l) quit("Schreibfehler mit Datei!", 2); fclose(f); return 0; } /* === Ende =================================================== */