/************************************************************************ * Copyright (C) 2001 Thomas Schulz * * */ static char rcsid[] = "$Id: mgrtrans.c,v 1.17 2001/11/20 23:08:35 thosch Exp $"; /* * * * IC35 manager transactions * * * ************************************************************************* * * * ??? is "fixme" mark: sections of code needing fixes * * * communication phases * mconnect * mdisconnect * MMCard info * mmc_status * mmc_label * MMCard directory ops * mmc_opendir * mmc_createdir * mmc_readdir * mmc_closedir * mmctstampstr * mmctstampunixtime * MMCard file operations * mmc_delfile * mmc_openfile * mmc_statfile * mmc_readfile * mmc_writefile * mmc_closefile * IC35 database backup,restore * readdatabase * writedatabase * * ************************************************************************/ #include /* fprintf(), .. */ #include /* memcpy(), strlen() ..*/ #include /* malloc(), .. */ #include /* usleep() */ #include /* size_t, .. */ #include /* time_t, localtime()..*/ #include #include "util.h" /* ERR,OK, uchar, .. */ #include "comio.h" /* com_init(), .. */ #include "genproto.h" /* welcome() */ #include "mgrproto.h" /* manager protocol */ #include "mgrtrans.h" NOTUSED(rcsid); /* ==================================== */ /* communication phases */ /* ==================================== */ /* welcome phase * ------------- * opens comm.device and does welcome handshake */ static int mgrwelcome( char * devname ) { int rval; LPRINTF(( L_INFO, "welcome(%s) ..", devname )); if ( com_init( devname ) != OK ) { error( "welcome failed: com_init(%s) failed", devname ); return ERR; } message( "welcome, start IC35 !" ); if ( (rval = welcome( 0x40 )) != OK ) { error( "welcome %s", rval == ERR_intr ? "aborted" : "failed: no response" ); return ERR; } message( "connected" ); LPRINTF(( L_INFO, "welcome(%s) OK", devname )); return OK; } /* identify * -------- * communication PC <-> IC35: * reset-phase -> 09 * <- 90 * ident-phase -> 10 * <- 90 "DCS_SDK" 00 */ static int identify( char rtext[7+1] ) { int rlen; char rbuff[7+1]; /* for "DCS_SDK\x00" */ LPRINTF(( L_INFO, "identify .." )); if ( Mcmdrsp( MCMDreset, MRSPgotcmd ) != OK ) { error( "identify failed: reset-phase" ); return ERR; } if ( Mcmdrsp( MCMDident, MRSPgotcmd ) != OK || (rlen = com_recv( rbuff, sizeof(rbuff) )) <= 0 ) { error( "identify failed: ident-phase" ); return ERR; } if ( rtext != NULL ) strncat( strcpy( rtext, "" ), rbuff, rlen ); LPRINTF(( L_INFO, "identify OK" )); return OK; } /* init IC35, optionally get status data * ------------------------------------- * communication PC <-> IC35: * optional: * -> FF * <- [block of 16400 bytes] * mandatory: * -> 50 * <- 90 or timeout 0.1 sec * IC35 may send response, but anyway needs time to get ready */ #define STATSIZE 16400 static int status( char * fname ) { uchar cmd; char * rbuff; int rlen = -1; FILE * fp; int old_tmo; uchar rsp; LPRINTF(( L_INFO, "status(%s) ..", fname ? fname : "NULL" )); if ( fname && *fname ) { if ( (rbuff = malloc( STATSIZE )) != NULL ) { cmd = MCMDstatus; com_send( &cmd, 1 ); if ( (rlen = com_recv( rbuff, STATSIZE )) < 0 ) { error( "status failed: receive" ); free( rbuff ); return ERR; } if ( (fp = fopen( fname, "w")) != NULL ) { fwrite( rbuff, 1, rlen, fp ); fclose( fp ); } else { message( "cannot open statfile: %s", fname ); } free( rbuff ); } else { message( "cannot read statdata: no memory (%d)", STATSIZE ); } } cmd = MCMDinit; com_send( &cmd, 1 ); /* -> 50 */ old_tmo = com_settimeout( 100 ); com_recv( &rsp, 1 ); /* <- 90 or wait 100 msec */ com_settimeout( old_tmo ); if ( rlen >= 0 ) /* received status block */ LPRINTF(( L_INFO, "status received %d bytes statdata", rlen )); else LPRINTF(( L_INFO, "status OK" )); return OK; } /* open com-device and connect with IC35 * ------------------------------------- */ int mconnect( char * devname, char * statfname ) { int rval; char idtext[8]; LPRINTF(( L_INFO, "mconnect(%s,%s) ..", devname, statfname ? statfname : "NULL" )); if ( (rval = mgrwelcome( devname )) == OK && (rval = identify( idtext )) == OK ) { message( "identity \"%s\"", idtext ); if ( statfname && *statfname ) message( "statdata %s", statfname ); rval = status( statfname ); } if ( rval != OK ) mdisconnect(); LPRINTF(( L_INFO, "mconnect(%s,%s) %s", devname, statfname ? statfname : "NULL", rval == OK ? "OK" : "ERR" )); return rval; } /* disconnect from IC35 and close com-device * ----------------------------------------- * communication PC <-> IC35: * -> 09 * timeout * -> 09 * <- 90 * -> 01 * timeout * -> 01 * <- 90 * until response '\x90' is received, send '\x09' or '\x01' * respectively will be retried up to 5 times. */ int mdisconnect( void ) { uchar cmd, rsp; int rval; message( "disconnect" ); if ( (rval = Mcmdrsp( cmd = MCMDreset, rsp = MRSPgotcmd )) != OK || (rval = Mcmdrsp( cmd = MCMDdisconn, rsp = MRSPgotcmd )) != OK ) message( "disconnect sent '\\x%02X', failed receive '\\x%02X'", cmd, rsp ); com_exit(); LPRINTF(( L_INFO, "disconnect done." )); return rval; } /* ==================================== */ /* IC35 MMCard info */ /* ==================================== */ /* local: convert mstat to text * ---------------------------- */ static char * _mstatxt( long mstat ) { static char mstatxt[2+11+1]; /* "(-nnnnnnnnnn)"\0 */ if ( mstat >= 0 ) sprintf( mstatxt, "(%04hX)", (ushort)mstat ); else sprintf( mstatxt, "(%ld)", mstat ); return mstatxt; } /* get MMCard status * ----------------- * returns: * 1 OK, MMCard found * 0 OK, MMCard not detected * -1 ERR, communication failed */ int mmc_status( int mmcnum ) { long mstat; if ( mmcnum != 1 && mmcnum != 2 ) { error( "mmc_status: bad MMCard number %d", mmcnum ); return ERR; } LPRINTF(( L_INFO, "mmc_status(%d) ..", mmcnum )); if ( (mstat = MMCgetstatus( mmcnum )) < 0 || !( mstat == 0xFFFF || mstat == 0x0001 ) ) { error( "mmc_status failed %s", _mstatxt(mstat) ); return ERR; } LPRINTF(( L_INFO, "mmc_status(%d) = %04X", mmcnum, mstat )); return mstat == 0xFFFF ? 0 : mstat; } /* get MMCard label * ---------------- */ int mmc_label( int mmcnum, char label[11+1] ) { long mstat; if ( mmcnum != 1 && mmcnum != 2 ) { error( "mmc_label: bad MMCard number %d", mmcnum ); return ERR; } LPRINTF(( L_INFO, "mmc_label(%d) ..", mmcnum )); if ( (mstat = MMCgetlabel( mmcnum, label )) != 0x0001 ) { error( "mmc_label failed %s", _mstatxt(mstat) ); return ERR; } LPRINTF(( L_INFO, "mmc_label(%d) = \"%s\"", mmcnum, label )); return OK; } /* ==================================== */ /* IC35 MMCard directory ops */ /* ==================================== */ struct mmcdir { /* MMC directory descriptor */ uchar fdiden[FIDENSZ];/* MMC dir/file access ident */ MMCDIRENT dirent; /* decoded directory entry */ ushort ndirent; /* number of directory entries */ ushort dirindex; /* current directory index */ }; /* local: convert FILE_INFO to MMCDIRENT * ------------------------------------- */ static void _mmc_finfo2dirent( FILE_INFO * finfo, MMCDIRENT * dirent ) { if ( finfo == NULL || dirent == NULL ) return; strncat( strcpy( dirent->name, "" ), finfo->FileName, 8 ); if ( strlen( finfo->ExtName ) != 0 ) { strcat( dirent->name, "." ); strncat( dirent->name, finfo->ExtName, 3 ); } dirent->attr = finfo->Attribute; dirent->tstamp = finfo->ModifyDate << 16 | finfo->ModifyTime; dirent->size = finfo->FileSize; } /* open MMC directory * ------------------ */ MMCDIR * mmc_opendir( char * dirpath ) { MMCDIR * dirp; long mstat; if ( (dirp = malloc( sizeof(*dirp) )) == NULL ) { error( "mmc_opendir failed: no memory (%d)", sizeof(*dirp) ); return NULL; } LPRINTF(( L_INFO, "mmc_opendir(%s) ..", dirpath )); if ( (mstat = MMCdiropen( dirpath, dirp->fdiden )) != 0x0001 ) { error( "mmc_opendir(%s) diropen failed %s", dirpath, _mstatxt(mstat) ); return NULL; } if ( (mstat = MMCdirgetlen( dirp->fdiden, &dirp->ndirent )) != 0x0001 ) { error( "mmc_opendir(%s) dirgetlen failed %s", dirpath,_mstatxt(mstat) ); return NULL; } dirp->dirindex = 0; LPRINTF(( L_INFO, "mmc_opendir(%s) OK, ndirent=%d", dirpath, dirp->ndirent )); return dirp; } /* open MMC directory * ------------------ */ MMCDIR * mmc_createdir( char * dirpath ) { MMCDIR * dirp; long mstat; if ( (dirp = malloc( sizeof(*dirp) )) == NULL ) { error( "mmc_createdir failed: no memory (%d)", sizeof(*dirp) ); return NULL; } LPRINTF(( L_INFO, "mmc_createdir(%s) ..", dirpath )); if ( (mstat = MMCdircreate( dirpath, dirp->fdiden )) != 0x0001 ) { error( "mmc_createdir(%s) dircreate failed %s", dirpath, _mstatxt(mstat) ); return NULL; } if ( (mstat = MMCdirgetlen( dirp->fdiden, &dirp->ndirent )) != 0x0001 ) { error( "mmc_createdir(%s) dirgetlen failed %s", dirpath,_mstatxt(mstat) ); return NULL; } dirp->dirindex = 0; LPRINTF(( L_INFO, "mmc_createdir(%s) OK, ndirent=%d", dirpath, dirp->ndirent )); return dirp; } /* read MMC directory * ------------------ */ MMCDIRENT * mmc_readdir( MMCDIR * dirp ) { long mstat; FILE_INFO mmcdirent; if ( dirp == NULL ) return NULL; if ( dirp->dirindex >= dirp->ndirent ) { LPRINTF(( L_INFO, "mmc_readdir: eodir (%d)", dirp->dirindex )); return NULL; } ++dirp->dirindex; LPRINTF(( L_INFO, "mmc_readdir index=%d ..", dirp->dirindex )); if ( (mstat = MMCdirread( dirp->fdiden, dirp->dirindex, &mmcdirent )) != 0x0001 ) { error( "mmc_readdir failed %s", _mstatxt(mstat) ); return NULL; } _mmc_finfo2dirent( &mmcdirent, &dirp->dirent ); LPRINTF(( L_INFO, "mmc_readdir OK" )); return &dirp->dirent; } /* close MMC directory * ------------------- */ int mmc_closedir( MMCDIR * dirp ) { if ( dirp == NULL ) return OK; LPRINTF(( L_INFO, "mmc_closedir .." )); if ( MMCdirclose( dirp->fdiden ) < 0 ) { error( "mmc_closedir failed" ); return ERR; } free( dirp ); LPRINTF(( L_INFO, "mmc_closedir OK" )); return OK; } /* convert MMC timestamp * --------------------- * the timestamp of MMCard dir/file is encoded like DOS: * 3322222 2222 21111 11111 100000 00000 bit- .. * 1098765 4321 09876 54321 098765 43210 .. number * yyyyyyy mmmm ddddd hhhhh mmmmmm sssss bit fields * the bit field meanings are: * yyyyyyy years since 1980 * mmmm month 1..12 * ddddd day 1..31 * hhhhh hour 00..24 * mmmmmm minute 00..59 * sssss second/2 00..31 * mmctstampstr() returns: * (char*) timestamp string: yyyy-mm-dd hh:mm:ss * mmctstampunixtime() returns: * (time_t) timestamp converted to Unix time */ static struct tm * _mmctstamptm( ulong tstamp ) { static struct tm mmctm; mmctm.tm_year = ((tstamp & 0xFE000000) >> (4+5+5+6+5)) + 80; mmctm.tm_mon = ((tstamp & 0x01E00000) >> ( 5+5+6+5)) - 1; mmctm.tm_mday = (tstamp & 0x001F0000) >> ( 5+6+5); mmctm.tm_hour = (tstamp & 0x0000F800) >> ( 6+5); mmctm.tm_min = (tstamp & 0x000007E0) >> ( 5); mmctm.tm_sec = (tstamp & 0x0000001F) * 2; return &mmctm; } char * mmctstampstr( ulong tstamp ) { static char ymdhms[19+1]; struct tm * ptm; ptm = _mmctstamptm( tstamp ); sprintf( ymdhms, "%04u-%02u-%02u %02u:%02u:%02u", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec ); return ymdhms; } time_t mmctstampunixtime( ulong tstamp ) { struct tm * ptm; ptm = _mmctstamptm( tstamp ); ptm->tm_isdst = -1; return mktime( ptm ); } /* ==================================== */ /* IC35 MMCard file operations */ /* ==================================== */ struct mmcfile { /* MMC file descriptor */ uchar fdiden[FIDENSZ];/* MMC dir/file access ident */ MMCDIRENT filestat; /* decoded file status */ ulong size; /* file size */ ulong offset; /* current offset in file */ }; /* delete MMC file * --------------- */ int mmc_delfile( char * filepath ) { long mstat; LPRINTF(( L_INFO, "mmc_delfile(%s) ..", filepath )); if ( (mstat = MMCfiledel( filepath )) != 0x0001 ) { error( "mmc_delfile(%s) failed %s", filepath, _mstatxt(mstat) ); return ERR; } LPRINTF(( L_INFO, "mmc_delfile(%s) OK", filepath )); return OK; } /* open MMC file * ------------- */ MMCFILE * mmc_openfile( char * filepath, ushort mode ) { MMCFILE * fp; long mstat; if ( (fp = malloc( sizeof(*fp) )) == NULL ) { error( "mmc_openfile failed: no memory (%d)", sizeof(*fp) ); return NULL; } LPRINTF(( L_INFO, "mmc_openfile(%s) ..", filepath )); if ( (mstat = MMCfileopen( filepath, mode, fp->fdiden, &fp->size )) != 0x0001 ) { error( "mmc_openfile(%s) failed %s", filepath, _mstatxt(mstat) ); return NULL; } fp->offset = 0; LPRINTF(( L_INFO, "mmc_openfile(%s) OK, size=%lu", filepath, fp->size )); return fp; } /* get MMC file status * ------------------- */ MMCDIRENT * mmc_statfile( MMCFILE * fp ) { long mstat; FILE_INFO mmcdirent; if ( fp == NULL ) return NULL; LPRINTF(( L_INFO, "mmc_statfile .." )); if ( (mstat = MMCfilestat( fp->fdiden, &mmcdirent )) != 0x0001 ) { error( "mmc_statfile failed %s", _mstatxt(mstat) ); return NULL; } _mmc_finfo2dirent( &mmcdirent, &fp->filestat ); LPRINTF(( L_INFO, "mmc_statfile OK" )); return &fp->filestat; } /* read data from MMC file * ----------------------- */ int mmc_readfile( MMCFILE * fp, uchar * buff, size_t blen ) { long mstat; ushort rlen; if ( fp == NULL ) return ERR; if ( fp->offset >= fp->size ) { LPRINTF(( L_INFO, "mmc_readfile: eofile (%d)", fp->offset )); return 0; } LPRINTF(( L_INFO, "mmc_readfile(buff,%d) ..", blen )); if ( fp->offset + blen > fp->size ) blen = fp->size - fp->offset; if ( (mstat = MMCfileread( fp->fdiden, buff, blen, &rlen )) != 0x0001 ) { error( "mmc_readfile failed %s", _mstatxt(mstat) ); return ERR; } fp->offset += rlen; LPRINTF(( L_INFO, "mmc_readfile(buff,%d) = %d", blen, rlen )); return rlen; } /* write data to MMC file * ---------------------- */ int mmc_writefile( MMCFILE * fp, uchar * data, size_t dlen ) { long mstat; if ( fp == NULL ) return ERR; LPRINTF(( L_INFO, "mmc_writefile(data,%d) ..", dlen )); if ( (mstat = MMCfilewrite( fp->fdiden, data, dlen )) != 0x0001 ) { error( "mmc_writefile failed %s", _mstatxt(mstat) ); return ERR; } if ( fp->offset == fp->size ) fp->size += dlen; fp->offset += dlen; LPRINTF(( L_INFO, "mmc_writefile(data,%d) OK", dlen )); return dlen; } /* close MMC file * -------------- */ int mmc_closefile( MMCFILE * fp ) { if ( fp == NULL ) return OK; LPRINTF(( L_INFO, "mmc_closefile .." )); if ( MMCfileclose( fp->fdiden ) < 0 ) { error( "mmc_closefile failed" ); return ERR; } free( fp ); LPRINTF(( L_INFO, "mmc_closefile OK" )); return OK; } /* ==================================== */ /* IC35 database backup,restore */ /* ==================================== */ #define HEADBLKSZ 136 #define DATABLKSZ 16384 #define INFOBLKSZ 4 #define NDATABLKS 26 #define NINFOBLKS 2 /* get database info * ----------------- */ static int _getdbinfo( uchar * buff, size_t blen ) { if ( Mcmdrsp( MCMDinfo, MRSPgotcmd ) != OK ) return ERR; return com_recv( buff, blen ); } /* textify protocol errorcode * -------------------------- */ static char * _dbetext( int len ) { static char etext[24+1]; switch ( len ) { case ERR_recv: return "recv.error/timeout"; case ERR_acknak: return "ack/nak handshake failed"; case ERR_chksum: return "checksum error"; default: sprintf( etext, "%s (%d)", len < 0 ? "error" : "bad length", len ); return etext; } } /* IC35 database backup to file * ============================ * communication PC <-> IC35: * backup command * -> 13 command backup * <- 90 response gotcmd * on receive error / timeout retry sending command * headblock * <- [136-byte-block] cc_cc headblock * -> 60 positive acknowledge * <- A0 response gotack * or on checksum mismatch: * -> 62 negative acknowlegde * <- A0 reponse gotnak * and receive headblock again * datablocks * <- [16384-byte-block] cc_cc datablock * -> 60 positive acknowledge * <- A0 response gotack * repeat receive for 26 datablocks of 16384 bytes. for each datablock * do retry on checksum mismatch like above for headblock. * database info * -> 18 command getinfo * <- 90 response gotcmd * <- 30 31 32 38 infoblock-1 * -> 18 command getinfo * <- 90 response gotcmd * <- 30 31 32 38 infoblock-2 */ /* read IC35 database to file * -------------------------- */ static int _readdatabase( char * fname, FILE * fp, uchar * buff ) { ulong frlen; int rlen; int i; LPRINTF(( L_INFO, "readdatabase %s ..", fname )); /* send backup command and wait for IC35 response */ if ( Mcmdrsp( MCMDbackup, MRSPgotcmd ) != OK ) { error( "readdatabase backup command failed" ); return ERR; } /* receive head-,data-blocks from IC35 and write to file */ frlen = 0; for ( i = 0; i <= NDATABLKS; ++i ) { char btext[24+1]; size_t blen; if ( i == 0 ) { fprintf( stderr, "read database -> %s head ", fname ); strcpy( btext, "headblock" ); blen = HEADBLKSZ; } else { sprintf( btext, "datablock-%d", i ); blen = DATABLKSZ; } if ( (rlen = Mrecvblk( buff, blen )) != blen ) { fprintf( stderr, "\n" ); error( "readdatabase %s %s", btext, _dbetext( rlen ) ); return ERR; } frlen += rlen; fprintf( stderr, "\rread database -> %s %ldk ", fname, (frlen+511)/1024 ); if ( fwrite( buff, sizeof(buff[0]), rlen, fp ) != rlen ) { fprintf( stderr, "\n" ); error( "readdatabase %s %s: write error %s (%d)", btext, fname, strerror(errno), errno ); return ERR; } } /* receive database info from IC35 and write to file */ fprintf( stderr, "\nread database -> %s info ", fname ); for ( i = 1; i <= NINFOBLKS; ++i ) { if ( (rlen = _getdbinfo( buff, INFOBLKSZ )) != INFOBLKSZ ) { fprintf( stderr, "\n" ); error( "readdatabase info-%d recv.error/timeout", i ); return ERR; } if ( fwrite( buff, sizeof(buff[0]), rlen, fp ) != rlen ) { fprintf( stderr, "\n" ); error( "readdatabase info-%d %s: write error %s (%d)", i, fname, strerror(errno), errno ); return ERR; } } fprintf( stderr, "\n" ); LPRINTF(( L_INFO, "readdatabase %s OK", fname )); return OK; } /* read IC35 database: init,free resources * --------------------------------------- */ int readdatabase( char * fname ) { uchar * buff; FILE * fp; int rval; if ( (buff = malloc( DATABLKSZ )) != NULL ) { if ( fname && *fname && (fp = fopen( fname, "w" )) != NULL ) { rval = _readdatabase( fname, fp, buff ); fclose( fp ); } else { error( "readdatabase cannot open %s", fname ? fname : "(NULL)" ); rval = ERR; } free( buff ); } else { error( "readdatabase failed: no memory (%d)", DATABLKSZ ); rval = ERR; } return rval; } /* IC35 database restore from file * =============================== * communication PC <-> IC35: * database info * -> 18 command getinfo * <- 90 response gotcmd * <- 30 31 32 38 infoblock-1 * -> 18 command getinfo * <- 90 response gotcmd * <- 30 31 32 38 infoblock-2 * check both infoblocks matching with tail of database file, * on mismatch abort and do not write database to IC35. * restore commands * -> 14 command restore-1 * <- 90 response gotcmd * -> 70 command restore-2 * <- C0 response restore-2 * on receive error / timeout retry sending command-1/2. * headblock * -> [136-byte-block] headblock * <- cc_cc response checksum * -> 60 positive acknowledge * <- A0 response gotack * or on checksum mismatch: * -> 62 negative acknowlegde * <- A0 reponse gotnak * and send headblock again. * datablocks * -> [16384-byte-block] datablock * <- cc_cc response checksum * -> 60 positive acknowledge * <- A0 response gotack * repeat send for 26 datablocks of 16384 bytes. for each datablock do * retry on checksum mismatch like above for headblock. * after all data is written to IC35, wait 3.25 sec to * avoid failure in mdisconnect(). * warning: IC35 does NOT restore phonetype and date+time, * they must be set manually after restore from file ! */ /* write IC35 database from file * ----------------------------- */ static int _writedatabase( char * fname, FILE * fp, uchar * buff ) { ulong fwlen; int wlen; int i; LPRINTF(( L_INFO, "writedatabase %s ..", fname )); /* check info from IC35 matching info in database file */ fprintf( stderr, "write database <> %s info ", fname ); fseek( fp, -2*INFOBLKSZ, SEEK_END ); for ( i = 1; i <= NINFOBLKS; ++i ) { uchar info[INFOBLKSZ]; if ( (wlen = _getdbinfo( buff, INFOBLKSZ )) != INFOBLKSZ ) { fprintf( stderr, "\n" ); error( "writedatabase info-%d recv.error/timeout", i ); return ERR; } if ( fread( info, sizeof(info[0]), INFOBLKSZ, fp ) != INFOBLKSZ ) { fprintf( stderr, "\n" ); error( "writedatabase info-%d %s: read error %s (%d)", i, fname, strerror(errno), errno ); return ERR; } if ( memcmp( buff, info, INFOBLKSZ ) != 0 ) { char * hextext; int j; fprintf( stderr, "\n" ); if ( (hextext = malloc( INFOBLKSZ*3 + 1 )) != NULL ) { strcpy( hextext, "" ); for ( j = 0; j < INFOBLKSZ; ++j ) sprintf( hextext+strlen(hextext), "%02X ", buff[j] ); message( "%s IC35", hextext ); strcpy( hextext, "" ); for ( j = 0; j < INFOBLKSZ; ++j ) sprintf( hextext+strlen(hextext), "%02X ", info[j] ); message( "%s %s", hextext, fname ); free( hextext ); } error( "writedatabase info-%d mismatch", i ); } } rewind( fp ); /* send restore commands and wait for IC35 responses */ fprintf( stderr, "\n" ); if ( Mcmdrsp( MCMDrestinit, MRSPgotcmd ) < 0 || Mcmdrsp( MCMDrestdata, MRSPrestdata ) < 0 ) { error( "writedatabase restore command failed" ); return ERR; } /* read headblock,datablocks from file and send to IC35 */ fwlen = 0; for ( i = 0; i <= NDATABLKS; ++i ) { char btext[24+1]; size_t blen; if ( i == 0 ) { fprintf( stderr, "write database <- %s head ", fname ); strcpy( btext, "headblock" ); blen = HEADBLKSZ; } else { sprintf( btext, "datablock-%d", i ); blen = DATABLKSZ; } if ( fread( buff, sizeof(buff[0]), blen, fp ) != blen ) { fprintf( stderr, "\n" ); error( "writedatabase %s %s: read error %s (%d)", btext, fname, strerror(errno), errno ); return ERR; } if ( (wlen = Msendblk( buff, blen )) != blen ) { fprintf( stderr, "\n" ); error( "writedatabase %s %s", btext, _dbetext( wlen ) ); return ERR; } fwlen += wlen; fprintf( stderr, "\rwrite database <- %s %ldk ", fname, (fwlen+511)/1024 ); } fprintf( stderr, "\n" ); usleep( 3250000 ); /* wait 3.25 sec for IC35 doing restore */ LPRINTF(( L_INFO, "writedatabase %s OK", fname )); return OK; } /* write IC35 database: init,free resources * ---------------------------------------- */ int writedatabase( char * fname ) { uchar * buff; FILE * fp; int rval; if ( (buff = malloc( DATABLKSZ )) != NULL ) { if ( fname && *fname && (fp = fopen( fname, "r" )) != NULL ) { rval = _writedatabase( fname, fp, buff ); fclose( fp ); } else { error( "writedatabase cannot open %s", fname ? fname : "(NULL)" ); rval = ERR; } free( buff ); } else { error( "writedatabase failed: no memory (%d)", DATABLKSZ ); rval = ERR; } return rval; }