home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.elysium.pl
/
ftp.elysium.pl.tar
/
ftp.elysium.pl
/
games
/
C64_CDROM_96
/
fcopypc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2008-03-13
|
19KB
|
937 lines
//
// (C) 1993-1996 The Whiz-zards Association
//
// Fcopy C64<->PC
//
// Written by M. Edzes
//
#include <stdio.h>
#include <conio.h>
#include <bios.h>
#include <dos.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
/* Technical data for C64 Fcopy program.
Cable:
11 wires. 1 GND, 2*5 data lines.
The PC printer port interface has four adresses, of which the lowest
two I know the usage.
The base port adress of the LPT1..N port can be found in the BIOS data
space at adress 0x0400:0x0080 .. 0x0400:0x0087.
Every 2 byte word is a port base adress. Usually, LPT1 resides at 0x378.
The 0x378 port is the 8 bit printer output, of which the lower 5 bits
are connected to the lower 5 input bits of port $dc01 on the C64.
The lower 5 bits of the C64 $dc00 output port have been connected to the
printer error input lines, which are the upper 5 bits of 0x379, where the
HIGHEST BIT (bit 7) IS INVERTED!!!
This is all.
Now for the c64diskfile structure:
A file consists of 683 (number of sector) * 261 (sizeof sector) + 5
(file header size) = .... bytes.
You may use the class c64diskfile definition for your own use, it's
very easy.
In your program you can open a new file by:
c64diskfile filevariable(accesstype mode)
, where mode is either READ or WRITE. Now, use
filevariable.setname(char *filename) // ONLY sets the filename. No other
action. Do this BEFORE open.
filevariable.open() // obvious. Will only open files in READ mode if
the SIZE and FORMATHEADER are correct. Returns
true if successful. Sets the filepos at track=1,
sector=0.
filevariable.close(int error) // if error is true the file will be
deleted (if it was opened WRITE),
otherwise not.
filevariable.exists() // obvious. Returns true on success, does NOT check
the fileheader.
filevariable.positiontr(int trk) // Sets the current filepos to track trk
, sector 0. Only neccesary if not
reading succesive tracks (dir)
filevariable.getid(unsigned char id1,unsigned char id2)
// Gets id out of formatheader.
filevariable.putid(unsigned char id1,unsigned char id2)
// Writes an id into the file, and
changes filepos to track=1,sector=0.
filevariable.gettrack(int trk,unsigned char *buffer)
filevariable.puttrack(int trk,unsigned char *buffer)
// Read or write a C64 track from/to the file
trk is ONLY used to calculate the number of
sectors to read/write. Filepos will be up-
dated accordingly. NO PREPOSITIONING!
accesstype filevariable.getmode()
// returns READ or WRITE.
*/
class Joyconnection
{
int lptportout;
int lptportin;
enum dirs {FROM64,TO64};
dirs direction;
public:
Joyconnection(int prt) {lptportout=prt;lptportin=prt+1;};
~Joyconnection() {outportb(lptportout,0xff);};
void abort() {outportb(lptportout,0xff);};
int putblock(unsigned char *,int);
int getblock(unsigned char *,int);
int init();
private:
int putbyte(unsigned char);
int getbyte(unsigned char&);
};
#define C64FHEADER "TWA!"
struct c64fheader {
// char hdr[sizeof(C64FHEADER)];
unsigned char id1;
unsigned char id2;
};
struct c64sector {
unsigned char track; // actual track (redundant)
unsigned char sector; // actual sector (redundant)
unsigned char scrncode; // one of "+-CHI?FL" etc.
unsigned char header; // mostly 0x07
unsigned char data[256];
unsigned char chksum; // header exored with all databytes.
};
enum accesstype {READ,WRITE};
class c64diskfile
{
FILE *fpd64, *fpf64;
char fnamed64[80],fnamef64[80];
c64fheader fhdr;
accesstype mode;
public:
c64diskfile(accesstype m) {mode=m;fpd64=NULL;fpf64=NULL;};
~c64diskfile() {
if(fpd64!=NULL) fclose(fpd64);
if(fpf64!=NULL) fclose(fpf64);
};
void setname(char *s) {
strncpy(fnamed64,s,sizeof(fnamed64)-4);
strncpy(fnamef64,s,sizeof(fnamef64)-4);
strcat(fnamed64,".D64");
strcat(fnamef64,".F64");
};
accesstype getmode() {return mode;};
int exists();
int open();
void close(int);
void positiontr(int);
void gettrack(int,unsigned char *);
void puttrack(int,unsigned char *);
void getid(unsigned char&,unsigned char&);
void putid(unsigned char&,unsigned char&);
};
int calcsectors(int tr)
{
int se=21;
if(tr>17) se-=2;
if(tr>24) se--;
if(tr>30) se--;
return se;
}
int Joyconnection::putblock(unsigned char *s,int n)
{
int i;
unsigned char chk;
unsigned char *p;
int err;
do {
i=0;
chk='\0';
err=0;
p=s;
while(i<n && !err) {
i++;
chk+=*p;
err=putbyte(*(p++));
}
if(!err) err=putbyte(chk);
if(!err) err=getbyte(chk);
delay(1);
if(!err) err=chk;
if(err) {
err=init();
if(!err) err=-1;
}
} while((err!=0) && (err!=-2));
return err;
}
int Joyconnection::getblock(unsigned char *s,int n)
{
int i=0;
unsigned char *p;
unsigned char chk,ctmp;
int err;
do {
i=0;
chk='\0';
err=0;
p=s;
while(i<n && !err) {
i++;
err=getbyte(ctmp);
*(p++)=ctmp;
chk+=ctmp;
}
if(!err) err=getbyte(ctmp);
if(!err) {
if(chk-ctmp) {
err=putbyte(0xff);
if(!err) err=-1;
} else {
err=putbyte(0);
}
}
if(err) {
err=init();
if(!err) err=-1;
}
} while((err!=0) && (err!=-2));
return err;
}
int Joyconnection::putbyte(unsigned char c)
{
unsigned char a,b;
if(direction==FROM64) {
while(!(inportb(lptportin)&0x80)); // Wait for starting 0 1 0 0 0
outportb(lptportout,0x1f);
while(inportb(lptportin)&0x40); // Wait for 0 0 0 0 0
direction=TO64;
}
a=inportb(lptportin);
b=(c>>4);
outportb(lptportout,b); // o 0 d7 d6 d5 d4
while(inportb(lptportin)==a); // i 0 ~(d7 d6 d5 d4)
if((((a=inportb(lptportin))>>3)^b)==0xf) {
b=(c&((char)0xf))|0x10;
outportb(lptportout,b);
while(inportb(lptportin)==a);
if(((inportb(lptportin)>>'\3')^b)=='\17') return 0;
}
return -1;
}
int Joyconnection::getbyte(unsigned char& c)
{
unsigned char a,b;
if(direction==TO64) {
outportb(lptportout,0x8); // send starting 0 1 0 0 0
while(inportb(lptportin)&0x80);
outportb(lptportout,0); // send 0 0 0 0 0
direction=FROM64;
}
while(!(inportb(lptportin)&0x80)); // C64 sending?
a=inportb(lptportin);
outportb(lptportout,(a>>3)^0xf); // ackhi, 1 x x x x
while(inportb(lptportin)==a);
if(!((b=inportb(lptportin))&0x80)) {
outportb(lptportout,(b>>3)^0xf); // acklo, 0 x x x x
c=((a<<1)&0xf0)|((b>>3)&0xf);
return 0;
}
return -1;
}
int Joyconnection::init()
{
unsigned char cycle;
int chk;
int err=0;
do {
if(kbhit()) {
switch(getch()) {
case 'Q':
case 'q': err=-2;
outportb(lptportout,0xff);
exit(err);
}
}
chk=0;
for(cycle=0;cycle<32;cycle++) {
outportb(lptportout,cycle);
gotoxy(1,1);
cprintf("!%02x!",cycle);
delay(1);
if(((inportb(lptportin)>>3)^0xf)!=cycle) chk=1;
}
if(!chk) {
outportb(lptportout,0x1a);
delay(1);
if((inportb(lptportin)>>3)!=0x1f) chk=1;
}
} while(chk && !err);
gotoxy(1,1);
cprintf(" ");
direction=TO64;
return err;
}
int c64diskfile::exists()
{
int exists=1;
if((fpd64==NULL)&&(fpf64==NULL)) {
exists=0;
fpd64=fopen(fnamed64,"rb");
if(fpd64 != NULL) {
fclose(fpd64);
fpd64=NULL;
exists=1;
} else {
fpf64=fopen(fnamef64,"rb");
if(fpf64 != NULL) {
fclose(fpf64);
fpf64=NULL;
exists=2;
}
}
}
return exists;
}
int c64diskfile::open()
{
int success=0;
if(fpd64==NULL) {
if(mode==READ) {
fpd64=fopen(fnamed64,"rb");
if(fpd64!=NULL) {
fseek(fpd64,0L,SEEK_END);
if(ftell(fpd64)==(683L*256L)) {
fseek(fpd64,0L,SEEK_SET);
if(fpf64==NULL) {
fhdr.id1='M';
fhdr.id2='G';
fpf64=fopen(fnamef64,"rb");
if(fpf64!=NULL) {
fseek(fpf64,0L,SEEK_END);
if(ftell(fpf64)==((long)sizeof(c64fheader)+683L*3L)) {
fseek(fpf64,0L,SEEK_SET);
fread(&fhdr,sizeof(fhdr),1,fpf64);
} else {
fclose(fpf64);
fpf64=NULL;
}
}
}
// Get Disk ID from F64 file.
// if(strncmp(fhdr.hdr,C64FHEADER,sizeof(C64FHEADER))==0) success=1;
success=1;
}
}
if(!success) {
fclose(fpd64);
fclose(fpf64);
fpd64=NULL;
fpf64=NULL;
}
} else {
fpd64=fopen(fnamed64,"wb");
if(fpd64!=NULL) {
fpf64=fopen(fnamef64,"wb");
if(fpf64!=NULL) {
success=1;
// strncpy(fhdr.hdr,C64FHEADER,sizeof(C64FHEADER));
fwrite(&fhdr,sizeof(fhdr),1,fpf64);
} else {
fclose(fpd64);
fpd64=NULL;
}
}
}
}
return (success);
}
void c64diskfile::close(int error)
{
if(fpd64!=NULL) {
fclose(fpd64);
if(error&&(mode==WRITE)) { remove(fnamed64); }
fpd64=NULL;
}
if(fpf64!=NULL) {
fclose(fpf64);
if(error&&(mode==WRITE)) { remove(fnamef64); }
fpf64=NULL;
}
}
void c64diskfile::positiontr(int track)
{
int i=1,se=0;
while(i<track) {
se+=calcsectors(i++);
}
fseek(fpd64,256L*(long)se,SEEK_SET);
fseek(fpf64,(long)sizeof(c64fheader)+3L*(long)se,SEEK_SET);
}
void c64diskfile::gettrack(int track,unsigned char *buf)
{
int se;
unsigned char chk;
int i;
for (se=0;se<calcsectors(track);se++) {
*(buf++)=track;
*(buf++)=se;
if (fpf64 != NULL) {
fread(buf,3,1,fpf64);
buf+=2;
*(buf+256)=*buf;
}
else {
*(buf++)=0x2b;
*(buf++)=0x07;
}
fread(buf,256,1,fpd64);
if (fpf64 != NULL)
buf+=257;
else {
chk = '\0';
for(i=0;i<256;i++)
chk ^= *(buf++);
*(buf++) = chk;
}
}
}
void c64diskfile::puttrack(int track,unsigned char *buf)
{
int se;
for (se=0;se<calcsectors(track);se++) {
buf+=2;
fwrite(buf,2,1,fpf64);
buf+=2;
fwrite(buf,256,1,fpd64);
buf+=256;
fwrite(buf,1,1,fpf64);
buf++;
}
}
void c64diskfile::getid(unsigned char& id1,unsigned char& id2)
{
id1=fhdr.id1;
id2=fhdr.id2;
}
void c64diskfile::putid(unsigned char& id1,unsigned char& id2)
{
fhdr.id1=id1;
fhdr.id2=id2;
fseek(fpf64,0L,SEEK_SET);
fseek(fpd64,0L,SEEK_SET);
fwrite(&fhdr,sizeof(fhdr),1,fpf64);
}
void setupscreen()
{
int i;
clrscr();
cputs("The C64 <-> PC Fcopy program !");
for(i=1;i<36;i++) {
gotoxy(i+3,2);
cprintf("%c",i/10+'0');
gotoxy(i+3,3);
cprintf("%c",i-(i/10)*10+'0');
}
for(i=0;i<21;i++) {
gotoxy(1,i+4);
cprintf("%2d",i);
}
}
int setupfile(c64diskfile& cf)
{
int abort=0,success=0;
char fname[80];
int i;
while(!abort && !success) {
gotoxy(5,10);
cputs("Enter PC filename : ");
_setcursortype(_NORMALCURSOR);
i=0;
while((fname[i++]=getchar())!='\n');
fname[--i]='\0';
if(i==0) {
abort=1;
} else {
cf.setname(fname);
if(cf.getmode()==WRITE) {
i=1;
if(cf.exists()) {
gotoxy(5,11);
cputs("Filename exists. Overwrite y/n ? ");
i=0;
while(i==0) {
switch(tolower(getche())) {
case 'y' : cf.close(-1);
i=1;
break;
case 'n' : i=2;
break;
}
}
}
if(i==1) {
if(!cf.open()) {
gotoxy(5,12);
cprintf("Could not open file %s.D64 or %s.F64 for writing",fname,fname);
while(!kbhit()); getch();
} else {
success=1;
}
}
} else {
if(!cf.open()) {
gotoxy(5,11);
cprintf("Could not open file or illegal format in %s",fname);
while(!kbhit()); getch();
} else {
success=1;
}
}
}
_setcursortype(_NOCURSOR);
gotoxy(5,12); clreol();
gotoxy(5,11); clreol();
gotoxy(5,10); clreol();
}
if(abort) cf.close(-1);
return abort;
}
int getdisk(Joyconnection joy)
{
int abort=0;
unsigned char track,sector,scrncode,oldtrack,oldsector,id1,id2;
int tr,se;
unsigned char dbuffer[22*sizeof(c64sector)];
unsigned char *pdb;
c64diskfile cf(WRITE);
setupscreen();
abort=setupfile(cf);
if(!abort) {
track='S'; // scan has been modified
joy.putblock(&track,1);
oldtrack=0;
oldsector=0;
tr=1;
while(tr<36 && !abort) {
if(kbhit()) if(tolower(getch())=='q') abort=0xff;
joy.putblock(&(unsigned char)abort,1);
if(!abort) {
se=calcsectors(tr);
pdb=dbuffer;
sector='\0';
while(sector<se-1) {
joy.getblock(pdb,sizeof(c64sector));
track=*pdb;
sector=*(pdb+1);
gotoxy(track+3,sector+4);
scrncode=*(pdb+2);
cprintf("%c",scrncode);
if((track==oldtrack)&&(sector==oldsector)) {
memmove(pdb-sizeof(c64sector),pdb,sizeof(c64sector));
} else {
pdb+=sizeof(c64sector);
oldtrack=track;
oldsector=sector;
}
}
cf.puttrack(tr,dbuffer);
tr++;
}
}
if(!abort) {
joy.getblock(&id1,1);
joy.getblock(&id2,1);
cf.putid(id1,id2);
}
}
cf.close(abort);
return(abort);
}
int putdisk(Joyconnection joy)
{
int abort=0;
unsigned char track,sector,scrncode,retry,id1,id2;
int tr,se;
unsigned char dbuffer[sizeof(c64sector)*21];
unsigned char *pdb;
c64diskfile cf(READ);
setupscreen();
abort=setupfile(cf);
if(!abort) {
gotoxy(5,10);
cputs("Insert Destination disk in the C64 drive (Space)");
do {
switch(tolower(getch())) {
case ' ':abort=0;
break;
case 'q':abort=-1;
break;
default :abort=1;
}
} while(abort==1);
gotoxy(5,10); clreol();
}
if(!abort) {
track='M'; // multi has been modified
joy.putblock(&track,1);
cf.getid(id1,id2); // get the two id bytes
joy.putblock(&id1,1);
joy.putblock(&id2,1);
tr=1;
while(tr<36 && !abort) {
if(kbhit()) {
if(tolower(getch())=='q') abort=0xff;
}
joy.putblock(&(unsigned char)abort,1);
if(!abort) {
pdb=dbuffer;
se=calcsectors(tr);
cf.gettrack(tr,dbuffer);
highvideo();
while(se-- >0) {
joy.putblock(pdb,sizeof(c64sector));
track=*pdb;
sector=*(pdb+1);
gotoxy(track+3,sector+4);
scrncode=*(pdb+2);
cprintf("%c",scrncode);
pdb+=sizeof(c64sector);
}
normvideo();
do {
joy.getblock(&retry,1);
if(retry) {
gotoxy(1,1);
_setcursortype(_NORMALCURSOR);
cprintf("Error writing track %d. Retry,Ignore or Quit ? ",tr);
do {
switch(tolower(getch())) {
case 'q': retry='Q';
abort=1;
break;
case 'r': retry='R';
break;
case 'i': retry='I';
break;
default : retry=0;
}
} while(retry==0);
gotoxy(1,1);
clreol();
_setcursortype(_NOCURSOR);
joy.putblock(&retry,1);
}
} while(retry);
}
tr++;
}
}
cf.close(abort);
return(abort);
}
void c64puts(unsigned char *s,int n)
{
unsigned char c;
while(n--) {
c=*(s++);
if(c==0xa0) c=0x20;
if(c<0x20) c|=0x80;
putch(c);
}
}
void printdir(unsigned char *dbuffer)
{
unsigned char blocks[5],*pdb,track,sector;
int tr,se,row,i,blfree;
static char c64filetype[][4] = {
"DEL",
"SEQ",
"PRG",
"USR",
"REL",
"EL?",
"EQ?",
"RG?",
"SR?",
"EL?",
"L??",
"Q??",
"G?B",
"R?L",
"L?O",
"H?C"
};
gotoxy(45,1);
highvideo();
cputs(" ");
c64puts(dbuffer+0x90+4,23);
normvideo();
// parse sectors.
track=18;
sector=1;
se=21;
row=2;
while(track==18) {
pdb=dbuffer+sizeof(c64sector)*sector+4;
track=*(pdb++);
sector=*(pdb++);
for(i=0;i<8;i++) {
if(row==25) {
while(!kbhit());
getch();
while(--row>2) {
gotoxy(45,row);
clreol();
}
}
if(*pdb!='\0') {
gotoxy(45,row++);
cprintf("%5d ",(int) (*(unsigned int *)(pdb+0x1c)));
c64puts(pdb+3,16);
cprintf(" %s%c",c64filetype[*pdb&0xf],((*pdb&0x40)?'<':' '));
}
pdb+=32;
}
if(--se<0) track=0; // cyclic directories never stop.
}
blfree=0;
for(tr=1;tr<36;tr++) {
blfree+=(int)(*(dbuffer+4+tr*4));
if(tr==17) tr++;
}
gotoxy(45,row);
cprintf("%5d BLOCKS FREE.",blfree);
while(!kbhit());
getch();
}
void showc64dir(Joyconnection joy)
{
unsigned char track,sector,oldtrack,oldsector;
int se,i,row;
unsigned char dbuffer[sizeof(c64sector)*22];
unsigned char *pdb;
track='D';
joy.putblock(&track,1);
se=calcsectors(18);
track='\0';
joy.putblock(&track,1); // No abort
oldtrack=0;
oldsector=0;
pdb=dbuffer;
sector='\0';
while(sector<se-1) {
joy.getblock(pdb,sizeof(c64sector));
track=*pdb;
sector=*(pdb+1);
if((track==oldtrack)&&(sector==oldsector)) {
memmove(pdb-sizeof(c64sector),pdb,sizeof(c64sector));
} else {
pdb+=sizeof(c64sector);
oldtrack=track;
oldsector=sector;
}
}
printdir(dbuffer);
}
void showc64filedir()
{
unsigned char dbuffer[sizeof(c64sector)*21];
int abort,se;
c64diskfile cf(READ);
setupscreen();
abort=setupfile(cf);
if(!abort) {
cf.positiontr(18);
cf.gettrack(18,dbuffer);
printdir(dbuffer);
}
}
void toggleretries(int& r,Joyconnection j)
{
unsigned char tmp='T';
j.putblock(&tmp,1);
if(r==1) {
r=5;
} else {
r=1;
}
}
#define BIOSLPT1ADR 0x408L
int main(int argc,char *argv[])
{
int lpt=1;
int port=0;
char c;
int quit;
int retries=1;
normvideo();
while(argc--) {
if(strnicmp(argv[0],"lpt",3)==0) {
lpt=(*argv[3]-'0');
}
}
if((lpt<5) && (lpt>0)) {
port=*(long far*)(BIOSLPT1ADR+(lpt-1)*2);
}
if(!port) {
printf("No LPT%c port found!\n",lpt+'0');
} else {
Joyconnection j(port);
_setcursortype(_NOCURSOR);
clrscr();
gotoxy(1,3);
cprintf("Waiting for connection...\r\n");
cprintf("Press 'q' to quit\r\n");
if(j.init()) {
cprintf("abandoning program.");
} else {
quit=0;
while(!quit) {
setupscreen();
gotoxy(5,5);
cprintf("(c) 1993 The Whiz-zards Association");
gotoxy(5,7);
cprintf(" 1 - Backup C64 disk to PC\r\n");
gotoxy(5,8);
cprintf(" 2 - Restore C64 disk from PC\r\n");
gotoxy(5,9);
cprintf(" 3 - Show C64 directory\r\n");
gotoxy(5,10);
cprintf(" 4 - Show PC directory\r\n");
gotoxy(5,11);
cprintf(" 5 - Show C64 directory from PC file");
gotoxy(5,12);
cprintf(" 6 - Read retries on C64 (now %d)",retries);
gotoxy(5,14);
cprintf(" Q - Quit\r\n");
gotoxy(5,15);
cprintf("Pressing 'Q' during an option aborts.");
gotoxy(5,16);
cprintf("Please enter your choice : ");
_setcursortype(_NORMALCURSOR);
c=tolower(getche());
_setcursortype(_NOCURSOR);
switch(tolower(c)) {
case '1': getdisk(j);
break;
case '2': putdisk(j);
break;
case '3': showc64dir(j);
break;
case '4': clrscr();
system("dir");
getch();
break;
case '5': showc64filedir();
break;
case '6': toggleretries(retries,j);
break;
case 'q': quit=1;
break;
}
}
}
j.abort();
}
return(0);
}