/* mzcom - software for RS232 communication with MZ800. Copyright (C) Michal Hucik This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Foobar is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Foobar; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Version: 08.01.2008 License: GPL Author : Michal Hucik - ORDOZ hucik@ordoz.com */ #include #include #include #include #include #include #include #include #define VERSION 1 //0000000001 #define MZF_ROOT "./mzf" #define MAX_MZ_COMMAND_LENGHT 256 #define MAX_MZ_REPLY_LENGHT 256 #define MAX_MZFS 1024 #define MAX_DIRS 1024 #define MZC_SERIAL_DEVICE "/dev/ttyUSB0" #define MZ_DIRNAME_LENGTH 16 #define MZ_FNAME_LENGTH 16 #define PATH_DEPTH 32 struct mzfstr { char path[NAME_MAX+1]; unsigned char atrb; unsigned char name[MZ_FNAME_LENGTH+2]; // + 0x0d + 0x00 unsigned char size[2]; unsigned char dtaddr[2]; unsigned char exaddr[2]; }; struct dirstr { char name[NAME_MAX+1]; }; struct pathstr { char name[NAME_MAX+1]; }; struct mzfstr mzfs[MAX_MZFS]; struct dirstr dirs[MAX_DIRS]; struct pathstr path_elements[PATH_DEPTH]; int num_mzf; int num_dir; int num_path_elements; struct termios oldtio; int RS232fd; /* Conversion chars from Sharp ASCII (from MZF header) to ASCII */ char Sharp2Ascii(unsigned char byte) { if(byte == 0x0d) return(0x00); if(byte < 0x20) return(' '); if(byte <= 0x5d) return(byte); switch (byte) { case 0xa1:return('a'); case 0x9a:return('b'); case 0x9f:return('c'); case 0x9c:return('d'); case 0x92:return('e'); case 0xaa:return('f'); case 0x97:return('g'); case 0x98:return('h'); case 0xa6:return('i'); case 0xaf:return('j'); case 0xa9:return('k'); case 0xb8:return('l'); case 0xb3:return('m'); case 0xb0:return('n'); case 0xb7:return('o'); case 0x9e:return('p'); case 0xa0:return('q'); case 0x9d:return('r'); case 0xa4:return('s'); case 0x96:return('t'); case 0xa5:return('u'); case 0xab:return('v'); case 0xa3:return('w'); case 0x9b:return('x'); case 0xbd:return('y'); case 0xa2:return('z'); }; return(' '); }; int cmpmzfstr(struct mzfstr *a, struct mzfstr *b) { return( strcmp(a->name, b->name) ); }; /* Scan local directory MZF_ROOT/$dirpath/ Informations from MZF headers save into 'mzfs'. List of directories save into 'dirs'. */ int ReadMZFdir(char *dirpath) { FILE *f; DIR *dp; struct dirent **namelist; struct stat buf; char path[PATH_MAX+1]; char *ext; int i,n,j; char byte; struct mzfstr *thismzf; struct dirstr *thisdir; num_mzf=0; num_dir=0; if(strlen(dirpath) != 0) { num_dir++; thisdir=&dirs[0]; strcpy(thisdir->name, ".."); }; snprintf(path, sizeof(path), "%s/%s/", MZF_ROOT, dirpath); n = scandir(path, &namelist, 0, alphasort); if (n < 0) { fprintf(stderr, "Error: scandir '%s'.\n", path); return( -1); }; for( j=1; j < n; j++) { snprintf(path, sizeof(path), "%s/%s/%s", MZF_ROOT, dirpath, namelist[j]->d_name); if(stat(path, &buf)) { fprintf(stderr, "stat error (%s).\n",path); return(-1); }; if(S_ISREG(buf.st_mode)) { if((ext=strrchr(namelist[j]->d_name,'.'))) { if(strcasecmp(ext,".mzf") == 0) { //printf("Found: %s\n", path); if(NULL == (f=fopen(path, "rb"))) { fprintf(stderr, "fopen error (%s).\n",path); return(-1); }; thismzf=&mzfs[num_mzf]; strncpy(thismzf->path, path, sizeof(thismzf->path)); thismzf->name[0]=0x00; for(i=0;i<24;i++) { if(feof(f)) { fprintf(stderr, "wrong MZF header (%s).\n",path); return(-1); }; byte=fgetc(f); if(i==0) thismzf->atrb=byte; if(i>0 && i<17) { thismzf->name[strlen(thismzf->name)+1]=0x00; thismzf->name[strlen(thismzf->name)]=Sharp2Ascii(byte); }; if(i==18) thismzf->size[0]=byte; if(i==19) thismzf->size[1]=byte; if(i==20) thismzf->dtaddr[0]=byte; if(i==21) thismzf->dtaddr[1]=byte; if(i==22) thismzf->exaddr[0]=byte; if(i==23) thismzf->exaddr[1]=byte; }; //printf("%.2X %s\n%.2X%.2X %.2X%.2X %.2X%.2X\n",thismzf->atrb, thismzf->name, thismzf->size[1], thismzf->size[0], thismzf->dtaddr[1], thismzf->dtaddr[0], thismzf->exaddr[1], thismzf->exaddr[0]); fclose(f); num_mzf++; if(num_mzf > MAX_MZFS) { fprintf(stderr, "Error: MAX_MZFS exceed (%i).\n", MAX_MZFS); return(-1); }; }; }; } else if (S_ISDIR(buf.st_mode)) { if(( strcmp(namelist[j]->d_name, ".") == 0) || (strcmp(namelist[j]->d_name, "..") == 0)) continue; //printf("Found directory: %s\n", path); thisdir=&dirs[num_dir]; strncpy(thisdir->name,namelist[j]->d_name,sizeof(thisdir->name)); num_dir++; if(num_dir > MAX_DIRS) { fprintf(stderr, "Error: MAX_DIRS exceed (%i).\n", MAX_DIRS); return(-1); }; }; }; free(namelist); qsort(&mzfs, num_mzf, sizeof(mzfs[0]), cmpmzfstr); printf("\nFound total %i MZFs and %i DIRs.\n", num_mzf, num_dir); return(0); }; /* Initialize serial device MZC_SERIAL_DEVICE */ int SetSerial() { struct termios newtio; long baudrate; baudrate = B57600; if((RS232fd = open(MZC_SERIAL_DEVICE, O_RDWR| O_NOCTTY)) <0) { perror("Could not open serial device device"); return (-1); }; if(tcgetattr(RS232fd, &oldtio) < 0) { perror("Could not get term attributes"); return (-1); }; /* 8 bits, baud rate and local control */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag = CS8 | CLOCAL|baudrate|CREAD; newtio.c_lflag = 0; newtio.c_oflag = 0; newtio.c_iflag = IGNPAR; newtio.c_cc[VMIN] = 2; newtio.c_cc[VTIME] = 10; cfsetospeed( &newtio, baudrate); cfsetispeed( &newtio, baudrate); tcflush( RS232fd, TCIFLUSH); if (tcsetattr(RS232fd, TCSANOW, &newtio) < 0) { perror("Could not set term attributes"); return (-1); }; return(0); }; /* Wait for txt command from MZ. All commands are ended 0x0d. */ int ReadCommand(char* command) { char byte[1]; printf("Waiting for command from MZ...\n"); command[0]=0x00; while(1) { read(RS232fd, byte, 1); //printf("Received num: %.2X, zn: %c\n",byte[0],byte[0]); if(byte[0] == 0x0d) return(0); if(strlen(command)= '0' && (c) <= '9' ? (c) - '0' : -1; if (d != -1) return (d); d = (c) >= 'A' && (c) <= 'Z' ? (c) - 55 : -1; if (d != -1) return (d); d = (c) >= 'a' && (c) <= 'z' ? (c) - 87 : -1; if (d != -1) { return (d); } else { return (-1); }; }; /* Reply on command: GET DIR XXXX YY Send directory list to MZ. XXXX - position in dirs array YY - count items */ void DirList(char* command) { char cfrom[5]; char clength[3]; int from, length, i, j; char reply[MZ_DIRNAME_LENGTH+2]; struct dirstr *thisdir; strncpy(cfrom, command+strlen("GET DIR "),4); cfrom[4]=0x00; strncpy(clength, command+strlen("GET DIR XXXX "),2); clength[2]=0x00; from=hexatoi( cfrom); length=hexatoi( clength); printf("Sending dir list from %i, length %i.\n", from, length); for(i=from; i<(from+length); i++) { memset(reply, 0x00, sizeof(reply)); if(i <= num_dir-1) { thisdir=&dirs[i]; strncpy(reply, thisdir->name, MZ_DIRNAME_LENGTH); }; //printf("Dirname (%2i): %s\n", i, reply); reply[strlen(reply)]=0x0d; PostData(reply, MZ_DIRNAME_LENGTH+1); }; }; /* Reply on command: GET MZF XXXX YY Send MZF filelist to MZ. XXXX - position in mzfss array YY - count items */ void MzfList(char* command) { char cfrom[5]; char clength[3]; int from, length, i, j; char reply[1+MZ_FNAME_LENGTH+1+2+2+2]; // atrb(1), name(16), 0x0d, size, from, exec struct mzfstr *thismzf; strncpy(cfrom, command+strlen("GET MZF "),4); cfrom[4]=0x00; strncpy(clength, command+strlen("GET MZF XXXX "),2); clength[2]=0x00; from=hexatoi( cfrom); length=hexatoi( clength); printf("Sending MZF filelist from %i, length %i.\n", from, length); for(i=from; i<(from+length); i++) { memset(reply, 0x00, sizeof(reply)); reply[1]=0x0d; if(i <= num_mzf-1) { thismzf=&mzfs[i]; sprintf(reply, "%c%s%c", thismzf->atrb, thismzf->name, 0x0d); reply[18]=thismzf->size[0]; reply[19]=thismzf->size[1]; reply[20]=thismzf->dtaddr[0]; reply[21]=thismzf->dtaddr[1]; reply[22]=thismzf->exaddr[0]; reply[23]=thismzf->exaddr[1]; }; PostData(reply, sizeof(reply)); }; }; char newpath[NAME_MAX+1]; void CreatePath() { int i; struct pathstr *thispathstr; newpath[0]=0x00; for(i=0; iname, sizeof(newpath)-strlen(newpath)-1); strncat( newpath, "/", sizeof(newpath)-strlen(newpath)-1); }; if( strlen(newpath) >1 ) { newpath[ strlen(newpath)-1]=0x00; }; }; void ChangeDir(char* command) { char dir_hid[5]; int dir_id; struct dirstr *thisdir; struct pathstr *thispathstr; strncpy(dir_hid, command+strlen("CD "),4); dir_hid[4]=0x00; dir_id=hexatoi( dir_hid); if(dir_id>=num_dir) { fprintf(stderr, "Bad dir_id!\n"); return; }; thisdir = &dirs[ dir_id]; if(!strlen( thisdir->name)) { fprintf(stderr, "Empty dirname!\n"); return; }; printf("Decoding change directory command: CD %s\n", thisdir->name); if( strcmp(thisdir->name,"..") == 0) { if(num_path_elements==0) return; thispathstr=&path_elements[num_path_elements--]; thispathstr->name[0]=0x00; } else { if(num_path_elements>=PATH_DEPTH-1) { fprintf(stderr, "Error: PATH_DEPTH exceed (%i).\n", PATH_DEPTH); return; }; thispathstr=&path_elements[num_path_elements++]; strncpy(thispathstr->name, thisdir->name, sizeof(thispathstr->name)); }; CreatePath(); printf("New path: %s\n", newpath); ReadMZFdir( newpath); }; int LoadMzf(char* command) { char mzf_hid[5]; int mzf_id; struct mzfstr *thismzf; char byte[1]; FILE *f; strncpy(mzf_hid, command+strlen("LOAD "),4); mzf_hid[4]=0x00; mzf_id=hexatoi( mzf_hid); if(mzf_id>=num_mzf) return; thismzf = &mzfs[ mzf_id]; if(!strlen( thismzf->name)) return; printf("Decoding command to: LOAD \"%s\" - (%s)\n", thismzf->name, thismzf->path); if( NULL == ( f = fopen( thismzf->path, "rb"))) { perror("Could not open file"); return(-1); }; // fseek( f, 128, SEEK_SET); while (! feof(f)) { byte[0]=fgetc( f); //printf("%X\n", byte[0]); write( RS232fd, byte, 1); }; fclose( f); return(0); }; int main() { char command[MAX_MZ_COMMAND_LENGHT+1]; char reply[MAX_MZ_REPLY_LENGHT+2]; if(ReadMZFdir("") !=0) return(-1); if(SetSerial() !=0) return(-1); PostData(0x00,1); // send startbit, if MZ is already waiting for ping-pong reply while(1) { if(ReadCommand(command) !=0) return(-1); printf("Received MZ command: %s\n",command); /* ping - pong command (10 chars) This is test from MZ before real communication. */ if( strcmp(command,"Hello PC!") == 0) { PostReply("Hello MZ!"); /* get PC mzCom version (10 chars) */ } else if( strcmp(command,"VERSION") == 0) { sprintf(reply,"%.10i", VERSION); PostReply(reply); /* shutdown mzCom (no reply) */ } else if( strcmp(command,"SO LONG!") == 0) { printf("Exiting...\n"); if( tcsetattr( RS232fd, TCSANOW, &oldtio) < 0) { perror("Could not set previous term attributes"); return (-1); }; close( RS232fd); return(0); /* total MZFs in directory (2 bytes word) */ } else if( strcmp(command,"NUM MZF") == 0) { printf("Post binary reply to MZ: %.2X %.2X\n", num_mzf&0xFF, num_mzf>>8); sprintf(reply,"%c%c", num_mzf&0xFF, num_mzf>>8); PostData(reply,2); /* total subdirs in directory (2 bytes word) */ } else if( strcmp(command,"NUM DIR") == 0) { printf("Post binary reply to MZ: %.2X %.2X\n", num_dir&0xFF, num_dir>>8); sprintf(reply,"%c%c", num_dir&0xFF, num_dir>>8); PostData(reply,2); /* GET DIR XXXX YY: get dir list XXXX - from, YY - count */ } else if( strncmp(command,"GET DIR ",strlen("GET DIR ")) == 0) { DirList(command); /* GET MZF XXXX YY: get mzf list XXXX - from, YY - count */ } else if( strncmp(command,"GET MZF ",strlen("GET MZF ")) == 0) { MzfList(command); /* CD XXXX: enter to directory dirs[XXXX] */ } else if( strncmp(command,"CD ",strlen("CD ")) == 0) { ChangeDir(command); /* LOAD XXXX: load file mzfs[XXXX] */ } else if( strncmp(command,"LOAD ",strlen("LOAD ")) == 0) { LoadMzf(command); }; }; return(0); };