Rename variables sectorbuf and verbose to avoid clashes in rbutil. Cleanup exports...
[Rockbox.git] / apps / plugins / zxbox / sptape.c
blobf0e04de2fb8878a5aab33318fde100674d06368d
1 /*
2 * Copyright (C) 1996-1998 Szeredi Miklos
3 * Email: mszeredi@inf.bme.hu
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version. See the file COPYING.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "zxmisc.h"
22 #include "sptape.h"
23 #include "tapefile.h"
25 #include "spperif.h"
26 #include "z80.h"
27 #include "interf.h"
28 #include "spconf.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/types.h>
36 #define MAXLINELEN 256
38 int spt_auto_stop = 1;
40 static int playing = 0;
41 static int paused = 0;
43 static char tapename[MAXFILENAME];
44 static int tapetype;
46 #define EARBIT 0x40
48 #define IMPBUFLEN 1024
50 static int ingroup;
51 static int segtype;
53 static int lastdatak;
55 static int currseg;
57 static void stop_playing(void)
59 if(playing) close_tapefile();
60 playing = 0;
63 static void pause_playing(void)
65 if(playing) {
66 paused = 1;
67 playing = 0;
71 static void unpause_playing(void)
73 if(paused) {
74 paused = 0;
75 playing = 1;
76 segtype = SEG_END;
80 #define MAXDESCLEN 256
82 static void put_seg_desc(void)
84 if(segtype != SEG_VIRTUAL) {
85 if(segtype > SEG_END) {
86 if(!ingroup) {
87 long len;
88 int i, ml;
89 char *me;
91 len = get_seglen();
93 me = msgbuf;
94 rb->snprintf(me,MAXDESCLEN, "%4d: ", currseg);
95 me = me+rb->strlen(me);
96 if(segtype >= SEG_DATA && len) {
97 rb->snprintf(me,MAXDESCLEN, "%5ld bytes, ", len);
98 me = me+rb->strlen(me);
101 ml = 0;
102 for(i = 0; seg_desc[i]; i++) {
103 if(seg_desc[i] == '\n') {
104 *me = '\0';
105 put_msg(msgbuf);
107 me = msgbuf;
108 rb->snprintf(me,MAXDESCLEN, " ");
109 me = me+rb->strlen(me);
110 ml = 0;
112 else {
113 if(ml < MAXDESCLEN) *me++ = seg_desc[i];
114 ml++;
117 *me = '\0';
118 put_msg(msgbuf);
120 else {
121 rb->snprintf(msgbuf,MAXDESCLEN, "%4d:", currseg);
122 put_tmp_msg(msgbuf);
125 else put_msg(seg_desc);
127 #ifdef DEBUG_TAPE
128 else fprintf(stderr, "virtual segment\n");
129 #endif
132 static void get_next_segment(void)
134 int propseg;
136 do {
137 propseg = 1;
139 segtype = next_segment();
140 currseg = segment_pos();
142 put_seg_desc();
144 switch(segtype) {
145 case SEG_ERROR:
146 case SEG_END:
147 stop_playing();
148 break;
150 case SEG_STOP:
151 pause_playing();
152 put_msg(" * Tape paused; Press Ctrl-o to restart * ");
153 break;
155 case SEG_SKIP:
156 propseg = 0;
157 break;
159 case SEG_GRP_BEG:
160 ingroup = 1;
161 propseg = 0;
162 break;
164 case SEG_GRP_END:
165 ingroup = 0;
166 propseg = 0;
167 break;
169 } while(!propseg);
171 lastdatak = 0;
175 void play_tape(void)
177 static dbyte impbuf[IMPBUFLEN];
179 static int clevel;
180 static dbyte *impbufp;
181 static int impbufrem;
182 static long imprem;
184 static int cleared_buffers = 1;
186 int tsn;
187 dbyte *ibp;
188 byte *tsp;
189 int ibr;
190 long ir;
191 int cl;
192 signed char *op;
193 int ov;
194 int ca;
196 tsp = sp_tape_impinfo;
197 op = sp_tape_sound;
198 tsn = TMNUM;
200 if(!playing) {
201 if(cleared_buffers) return;
203 sp_playing_tape = 0;
205 if(!clevel) {
206 ca = CHKTICK;
207 clevel = ~clevel;
209 else {
210 ca = 0;
211 cleared_buffers = 1;
213 imprem = CHKTICK * TMNUM;
215 else if(!sp_playing_tape) {
216 sp_playing_tape = 1;
217 cleared_buffers = 0;
219 impbufrem = 0;
220 imprem = 0;
221 clevel = get_level() ? ~(0) : 0;
222 if(clevel) ca = 0;
223 else ca = 1;
225 else ca = 0;
227 #ifdef DEBUG_TAPE
228 if(((clevel ? 1 : 0) ^
229 (DANM(ula_inport) & EARBIT ? 1 : 0) ^
230 (DANM(imp_change) ? 1 : 0) ^
231 (ca ? 1 : 0)) == 0)
232 fprintf(stderr, "Levels don't match %i %i\n", imprem, impbufrem);
233 #endif
235 cl = clevel;
236 ibr = impbufrem;
237 ir = imprem;
238 ibp = impbufp;
240 if(cl) ov = CHKTICK/2;
241 else ov = -(CHKTICK/2);
243 do {
244 if(ir > 0) {
245 *tsp++ = ca;
246 *op++ = ov;
247 ir -= CHKTICK;
248 tsn--;
249 if(!tsn) goto done;
251 if(cl) ov = CHKTICK/2;
252 else ov = -(CHKTICK/2);
254 while(ir > 0) {
255 *tsp++ = 0;
256 *op++ = ov;
257 ir -= CHKTICK;
258 tsn--;
259 if(!tsn) goto done;
261 ca = 0;
263 if(ibr) {
264 if(!ca) {
265 if(cl) {
266 ov += ir;
267 ca = (CHKTICK/2) - ov + 1;
269 else {
270 ov -= ir;
271 ca = ov + (CHKTICK/2) + 1;
274 else {
275 ca = 0;
276 if(cl) ov += ir;
277 else ov -= ir;
279 ir += *ibp++;
280 ibr--;
281 cl = ~cl;
283 else {
284 ibp = impbuf;
285 do {
286 ibr = next_imps(impbuf, IMPBUFLEN, CHKTICK * tsn);
287 if(ibr) break;
288 get_next_segment();
289 if(!playing) {
290 if(!cl) {
291 if(ca) ca = 0;
292 else ca = CHKTICK;
293 cl = ~cl;
295 ir = tsn*CHKTICK;
296 ov = -(CHKTICK/2);
297 break;
299 } while(1);
302 } while(1);
304 done:
306 clevel = cl;
307 impbufrem = ibr;
308 imprem = ir;
309 impbufp = ibp;
311 if(segtype >= SEG_DATA) {
312 int datak;
314 datak = (int) (get_segpos() / 1000);
315 if(datak > lastdatak) {
316 if(ingroup) rb->snprintf(msgbuf,MAXDESCLEN, "%4d: ", currseg);
317 else rb->snprintf(msgbuf,MAXDESCLEN, " ");
318 rb->snprintf(msgbuf+rb->strlen(msgbuf),MAXDESCLEN, "%3dk", datak);
319 put_tmp_msg(msgbuf);
321 lastdatak = datak;
328 2168
329 2168 (9-10)
332 735 (2-4)
335 855 (3-5)
337 1710
338 1710 (7-9)
340 945 (4-5)
342 hosszu: 7..9
343 rovid: 2..5
347 #define MICBIT 0x08
350 #define RC_NONE 0
351 #define RC_LEADER 1
352 #define RC_SYNC 2
353 #define RC_DATA 3
355 #define MAXLEN TMNUM
357 #define LEADER_MIN 9
358 #define LEADER_MAX 10
359 #define SYNC_MIN 2
360 #define SYNC_MAX 4
362 #define BIT0_MIN 3
363 #define BIT0_MAX 5
364 #define BIT1_MIN 7
365 #define BIT1_MAX 9
367 #define LEADER_MIN_COUNT 512
368 #if 0
369 static int rec_segment;
370 static int rec_state = RC_NONE;
371 static byte *recbuf = NULL;
372 static const char *waitchars = "-\\|/";
373 #endif
374 static int recording = 0;
378 void rec_tape(void)
380 #if 0
381 static byte lastmic = 0;
382 static int lastlen = 0;
383 static int whole;
384 static int leadercount;
385 static byte data;
386 static byte parity;
387 static int bitnum;
388 static int bytecount;
389 static int recbufsize;
390 static int firsthalf;
391 static int frameswait = 0;
393 int tsl;
394 byte *fep;
395 int thishalf;
398 if(!recording) return;
400 for(fep = sp_fe_outport_time, tsl = TMNUM; tsl; fep++, tsl--) {
401 lastlen++;
402 if((*fep & MICBIT) == lastmic) {
403 if(lastlen < MAXLEN) continue;
405 else lastmic = ~lastmic & MICBIT;
407 switch(rec_state) {
408 case RC_NONE:
409 if(lastlen >= LEADER_MIN && lastlen <= LEADER_MAX) {
410 rec_state = RC_LEADER;
412 leadercount = 0;
413 break;
415 if((frameswait++ & 15)) break;
416 frameswait &= 0x3F;
417 sprintf(msgbuf, " %s: WAITING %c",
418 tapename, waitchars[(frameswait >> 4)]);
419 put_tmp_msg(msgbuf);
420 break;
421 case RC_LEADER:
422 if(lastlen >= LEADER_MIN && lastlen <= LEADER_MAX) {
423 leadercount++;
424 if(leadercount == LEADER_MIN_COUNT) {
425 sprintf(msgbuf, " %s: LEADER", tapename);
426 put_tmp_msg(msgbuf);
428 break;
430 if(leadercount >= LEADER_MIN_COUNT &&
431 lastlen >= SYNC_MIN && lastlen <= SYNC_MAX) rec_state = RC_SYNC;
432 else rec_state = RC_NONE;
433 break;
434 case RC_SYNC:
435 if(lastlen >= SYNC_MIN && lastlen <= SYNC_MAX) {
436 rec_state = RC_DATA;
437 whole = 0;
438 data = 0;
439 bitnum = 0;
440 bytecount = 0;
441 recbuf = NULL;
442 recbufsize = 0;
443 parity = 0;
445 sprintf(msgbuf, " %s: DATA", tapename);
446 put_tmp_msg(msgbuf);
448 else rec_state = RC_NONE;
449 break;
450 case RC_DATA:
451 thishalf = -1;
452 if(lastlen >= BIT0_MIN && lastlen <= BIT0_MAX) thishalf = 0;
453 else if(lastlen >= BIT1_MIN && lastlen <= BIT1_MAX) thishalf = 1;
455 if(thishalf < 0 || (whole && firsthalf != thishalf)) {
456 char filename[11];
457 int filesize;
458 int filetype;
460 sprintf(msgbuf, "%s: %03d", tapename, rec_segment);
461 if(bytecount >= 1) {
462 sprintf(msgbuf+strlen(msgbuf),
463 " %02X %5d %3s", recbuf[0], bytecount-2,
464 parity == 0 ? "OK" : "ERR");
465 if(recbuf[0] == 0 && bytecount - 2 >= 17) {
466 filetype = recbuf[1];
467 strncpy(filename, (char*) recbuf+2, 10);
468 filename[10] = '\0';
469 filesize = recbuf[12] + (recbuf[13] << 8);
471 sprintf(msgbuf+strlen(msgbuf),
472 " %02X %10s %5i", filetype, filename, filesize);
475 put_msg(msgbuf);
477 putc(bytecount & 0xFF, tapefp);
478 putc((bytecount >> 8) & 0xFF, tapefp);
480 fwrite(recbuf, 1, (size_t) bytecount, tapefp);
481 fflush(tapefp);
483 rec_segment++;
484 free(recbuf);
485 recbuf = NULL;
486 rec_state = RC_NONE;
487 break;
490 if(!whole) {
491 whole = 1;
492 firsthalf = thishalf;
494 else {
495 whole = 0;
496 data |= thishalf;
497 bitnum++;
499 if(bitnum == 8) {
500 bitnum = 0;
501 if(recbufsize <= bytecount) {
502 recbufsize += 1024;
503 recbuf = realloc(recbuf, (size_t) recbufsize);
504 if(recbuf == NULL) {
505 //fprintf(stderr, "Out of memory\n");
506 exit(1);
509 recbuf[bytecount] = data;
510 parity = parity ^ data;
511 data = 0;
512 bytecount++;
514 if(!(bytecount & 1023)) {
515 sprintf(msgbuf, " %s: DATA %i kB",
516 tapename, bytecount >> 10);
517 put_tmp_msg(msgbuf);
520 data <<= 1;
522 break;
525 lastlen = 0;
527 #endif
530 static void stop_recording(void)
532 #if 0
533 if(recording) {
534 recording = 0;
535 free(recbuf);
536 recbuf = NULL;
538 rb->close(tapefp);
540 #endif
543 static void restart_playing(void)
545 int res;
546 struct tape_options tapeopt;
548 if(tapetype < 0) {
549 tapetype = TAP_TZX;
550 res = open_tapefile(tapename, tapetype);
551 if(!res) {
552 tapetype = TAP_TAP;
553 res = open_tapefile(tapename, tapetype);
556 else res = open_tapefile(tapename, tapetype);
558 if(!res) {
559 put_msg(seg_desc);
560 return;
563 INITTAPEOPT(tapeopt);
564 #ifndef DEBUG_Z80
565 tapeopt.blanknoise = 1;
566 #endif
567 set_tapefile_options(&tapeopt);
569 if(currseg) {
570 res = goto_segment(currseg);
571 if(!res) {
572 put_msg(seg_desc);
573 return;
577 playing = 1;
578 segtype = SEG_END;
582 void pause_play(void)
584 if(playing) {
585 pause_playing();
586 put_msg(" * Tape paused * ");
587 goto_segment(currseg);
589 else unpause_playing();
593 void start_play_file_type(char *name, int seg, int type)
595 int filetype = FT_TAPEFILE;
597 rb->strncpy(tapename, name, MAXFILENAME-10);
598 tapename[MAXFILENAME-10] = '\0';
600 currseg = seg;
601 tapetype = type;
603 spcf_find_file_type(tapename, &filetype, &tapetype);
604 if(currseg < 0) currseg = 0;
606 ingroup = 0;
607 restart_playing();
610 void start_play(void)
612 char *name;
613 int t;
614 int seg;
616 if(playing || paused || recording) {
617 put_msg(" * Stop the tape first! * ");
618 return;
621 put_msg("Enter tape file path:");
622 name = spif_get_tape_fileinfo(&seg, &t);
623 if(name == NULL) return;
625 start_play_file_type(name, seg, -1);
629 void stop_play(void)
632 if(playing || paused) {
633 put_msg(" * Stopped playing * ");
635 if(playing) stop_playing();
636 if(paused) paused = 0;
638 else if(recording) {
639 #if 0
640 sprintf(msgbuf, " * Stopped recording tape `%s' * ", tapename);
641 put_msg(msgbuf);
642 #endif
643 stop_recording();
647 void start_rec(void)
649 #if 0
650 char *name;
652 if(playing || paused || recording) return;
654 put_msg("Enter tape file to record (default: '.tap'):");
656 name = spif_get_filename();
657 if(name == NULL) return;
659 strncpy(tapename, name, MAXFILENAME-10);
660 tapename[MAXFILENAME-10] = '\0';
662 if(!check_ext(tapename, "tap")) add_extension(tapename, "tap");
664 tapefp = fopen(tapename, "ab");
665 if(tapefp == NULL) {
666 sprintf(msgbuf, "Could not open tape file `%s', %s",
667 tapename, strerror(errno));
668 put_msg(msgbuf);
669 return;
672 recording = 1;
673 rec_segment = 0;
674 rec_state = RC_NONE;
676 sprintf(msgbuf,
677 "Recordind tape file `%s'. To stop press Ctrl-s", tapename);
678 put_msg(msgbuf);
679 #endif
682 #include "spkey_p.h"
684 #define CF 0x01
685 #define ZF 0x40
687 void qload(void)
689 byte type, parity;
690 dbyte length, dest, dtmp;
691 int verify, success, firstbyte;
692 int nextdata;
694 if(recording) {
695 put_msg("Can't quick load tape, because recording");
696 return;
699 do {
700 if(!playing) {
701 if(paused) unpause_playing();
702 else {
703 start_play();
706 if(!playing) {
707 put_msg("Not quick loading tape");
708 return;
710 while(playing && (segtype != SEG_DATA || get_segpos() > 0))
711 get_next_segment();
713 } while(!playing);
715 dtmp = AFBK;
716 AFBK = AF;
717 AF = dtmp;
719 type = RA;
720 verify = !(RF & CF);
721 length = DE;
722 firstbyte = !(RF & ZF);
723 dest = IX;
725 parity = 0;
726 success = 0;
728 do {
729 nextdata = next_byte();
730 if(nextdata < 0) break;
732 parity ^= nextdata;
734 if(!length) {
735 if(!parity) success = 1;
736 break;
739 if(firstbyte) {
740 firstbyte = 0;
741 if(nextdata != type) break;
743 else {
744 if(!verify) {
745 if(dest >= 0x4000) DANM(mem)[dest] = nextdata;
747 else {
748 if(DANM(mem)[dest] != nextdata) break;
750 dest++;
751 length--;
753 } while(1);
755 if(success) RF |= (CF | ZF);
756 else RF &= ~(CF | ZF);
757 IX = dest;
758 DE = length;
760 PC = SA_LD_RET;
761 DANM(iff1) = DANM(iff2) = 1;
762 DANM(haltstate) = 1;
764 sp_init_screen_mark();
766 if(spt_auto_stop) pause_playing();