Files
HxCFloppyEmulator/libhxcfe/sources/loaders/kryofluxstream_loader/kryofluxstream_writer.c
T

424 lines
11 KiB
C

/*
//
// Copyright (C) 2006-2025 Jean-François DEL NERO
//
// This file is part of the HxCFloppyEmulator library
//
// HxCFloppyEmulator may be used and distributed without restriction provided
// that this copyright statement is not removed from the file and that any
// derivative work contains the original copyright notice and the associated
// disclaimer.
//
// HxCFloppyEmulator 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.
//
// HxCFloppyEmulator 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 HxCFloppyEmulator; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
*/
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : kryofluxstream_writer.c
// Contains: Kryoflux Stream floppy image writer
//
// Written by: Jean-François DEL NERO
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "types.h"
#include "internal_libhxcfe.h"
#include "libhxcfe.h"
#include "kryofluxstream_format.h"
#include "kryofluxstream_loader.h"
#include "kryofluxstream_writer.h"
#include "libhxcadaptor.h"
#include "misc/env.h"
#include "stream_analyzer/fluxStreamAnalyzer.h"
int nextbyte(FILE *f,int i,unsigned char * trackbuffer)
{
i = (i + 1) & 0xFF;
if(!(i&0xFF))
{
fwrite(trackbuffer,256,1,f);
}
return i;
}
int alignOOB(FILE * f)
{
int i,j;
unsigned char buffer[8];
j = 0;
i = ftell(f);
while(i&0xF)
{
if((0x10-(i&0xF))>=3)
{
memset(buffer,0x00,8);
buffer[0] = 0xA;
buffer[1] = 0x9;
buffer[2] = 0x8;
fwrite(&buffer,3,1,f);
i=i+3;
j += 3;
}
else
{
if((0x10-(i&0xF))==2)
{
memset(buffer,0x00,8);
buffer[0] = 0x9;
buffer[1] = 0x8;
fwrite(&buffer,2,1,f);
i=i+2;
j += 2;
}
else
{
memset(buffer,0x00,8);
buffer[0] = 0x8;
fwrite(&buffer,1,1,f);
i++;
j += 1;
}
}
};
return j;
}
uint32_t write_kf_stream_track(HXCFE_IMGLDR * imgldr_ctx,char * filepath,HXCFE_SIDE * track,int tracknum,int sidenum,unsigned int revolution,double sck)
{
char fullp[512];
char fullp2[512];
char fileext[16];
unsigned char trackbuffer[256];
uint32_t value;
int streampos,streamsize;
unsigned int i;
uint32_t totalcelllen;
uint32_t iclk;
int SRcntdown;
s_oob_header oobh;
s_oob_StreamRead oobsr;
s_oob_StreamEnd oobse;
s_oob_DiskIndex oobdi;
FILE *f;
streamconv * strconv;
char * envstr;
char kfinfobuffer[256];
time_t curtimecnt;
struct tm * curtime;
strconv = initStreamConvert(imgldr_ctx->hxcfe,track, (float)(1E9/sck) * 1000.0, 0x00FFFFFF,-1,-1,revolution+1,5000000);
if(!strconv)
return 0;
hxc_getpathfolder(filepath,fullp,SYS_PATH_TYPE);
hxc_getfilenamewext(filepath,fullp2,SYS_PATH_TYPE);
strcat(fullp,fullp2);
sprintf(fileext,"%.2d.%d.raw",tracknum,sidenum);
strcat(fullp,fileext);
imgldr_ctx->hxcfe->hxc_printf(MSG_DEBUG,"write_kf_stream_track : Creating %s (trk %d, side %d, rev %d)",fullp,tracknum,sidenum,revolution);
time(&curtimecnt);
curtime = localtime(&curtimecnt);
f = hxc_fopen(fullp,"wb");
if(f)
{
streamsize = 0;
StreamConvert_getNextPulse(strconv);
streampos = 0;
// KFInfo : host datetime
snprintf(kfinfobuffer,sizeof(kfinfobuffer)-1,"host_date=%04d.%02d.%02d, host_time=%02d:%02d:%02d",curtime->tm_year+1900,curtime->tm_mon+1,curtime->tm_mday,curtime->tm_hour,curtime->tm_min,curtime->tm_sec);
kfinfobuffer[sizeof(kfinfobuffer)-1] = 0;
memset(&oobh,0,sizeof(s_oob_header));
oobh.Sign = 0xD;
oobh.Size = strlen(kfinfobuffer)+1;
oobh.Type = OOBTYPE_String;
fwrite(&oobh,sizeof(s_oob_header),1,f);
fwrite(kfinfobuffer,1,oobh.Size,f);
// KFInfo : software information and clocks
envstr = hxcfe_getEnvVar(imgldr_ctx->hxcfe,"LIBVERSION",0);
if(envstr)
{
snprintf(kfinfobuffer,sizeof(kfinfobuffer)-1,"name=%s, version=%s, sck=%.7f, ick=%.7f","libhxcfe",envstr,sck,(double)(sck/8));
kfinfobuffer[sizeof(kfinfobuffer)-1] = 0;
memset(&oobh,0,sizeof(s_oob_header));
oobh.Sign = 0xD;
oobh.Size = strlen(kfinfobuffer)+1;
oobh.Type = OOBTYPE_String;
fwrite(&oobh,sizeof(s_oob_header),1,f);
fwrite(kfinfobuffer,1,oobh.Size,f);
}
memset(&oobh,0,sizeof(s_oob_header));
oobh.Sign = 0xD;
oobh.Size = sizeof(s_oob_StreamRead);
oobh.Type = OOBTYPE_Stream_Read;
fwrite(&oobh,sizeof(s_oob_header),1,f);
memset(&oobsr,0,sizeof(s_oob_StreamRead));
oobsr.StreamPosition = streampos;
oobsr.TrTime = 0x0;
fwrite(&oobsr,sizeof(s_oob_StreamRead),1,f);
SRcntdown = 0x7FF4;
iclk = 0;
if(!strconv->stream_end_event) // If no pulse, don't process the track.
{
StreamConvert_getNextPulse(strconv);
totalcelllen = 0;
i = 0;
do
{
streamsize = 0;
value = StreamConvert_getNextPulse(strconv);
totalcelllen += value;
// Encode cell value...
if( ( (value >= 0xE) && (value < 0x100) ) )
{
trackbuffer[i] = (unsigned char)value;
i = nextbyte(f,i,trackbuffer);
streamsize = 1;
}
else
{
if( (value <= 0xD) || (value >= 0x100 && value < 0x800) )
{
trackbuffer[i] = (unsigned char)( value >> 8 );
i = nextbyte(f,i,trackbuffer);
trackbuffer[i] = (unsigned char)( value & 0xFF );
i = nextbyte(f,i,trackbuffer);
streamsize = 2;
}
else
{
if(value < 0x10000)
{
trackbuffer[i] = 0x0C; // Value16
i = nextbyte(f,i,trackbuffer);
trackbuffer[i] = (unsigned char)( value >> 8 );
i = nextbyte(f,i,trackbuffer);
trackbuffer[i] = (unsigned char)( value & 0xFF );
i = nextbyte(f,i,trackbuffer);
streamsize = 3;
}
else
{
streamsize = 0;
do
{
trackbuffer[i] = 0x0B; // Overflow16
i = nextbyte(f,i,trackbuffer);
streamsize++;
value -= 0x10000;
}while(value>= 0x10000);
trackbuffer[i] = 0x0C; // Value16
i = nextbyte(f,i,trackbuffer);
trackbuffer[i] = (unsigned char)( value >> 8 );
i = nextbyte(f,i,trackbuffer);
trackbuffer[i] = (unsigned char)( value & 0xFF );
i = nextbyte(f,i,trackbuffer);
streamsize+=3;
}
}
}
// Index pulse ?
if( strconv->index_event )
{
if(i)
{
fwrite(trackbuffer,i,1,f);
}
streamsize += alignOOB(f);
i=0;
memset(&oobh,0,sizeof(s_oob_header));
oobh.Sign = 0xD;
oobh.Size = sizeof(s_oob_DiskIndex);
oobh.Type = OOBTYPE_Index;
fwrite(&oobh,sizeof(s_oob_header),1,f);
memset(&oobdi,0,sizeof(s_oob_DiskIndex));
oobdi.StreamPosition = streampos + streamsize;
iclk = iclk + ((totalcelllen/16) * 2);
oobdi.SysClk = iclk;
totalcelllen = 0;
fwrite(&oobdi,sizeof(s_oob_DiskIndex),1,f);
imgldr_ctx->hxcfe->hxc_printf(MSG_DEBUG,"write_kf_stream_track : Index added (Stream pos : %d, Sysclk : %d)",oobdi.StreamPosition,oobdi.SysClk);
}
SRcntdown--;
// Time to add a Stream Read OOB ?
if(!SRcntdown)
{
if(i)
{
fwrite(trackbuffer,i,1,f);
}
i=0;
streamsize += alignOOB(f);
i=0;
memset(&oobh,0,sizeof(s_oob_header));
oobh.Sign = 0xD;
oobh.Size = sizeof(s_oob_StreamRead);
oobh.Type = OOBTYPE_Stream_Read;
fwrite(&oobh,sizeof(s_oob_header),1,f);
memset(&oobsr,0,sizeof(s_oob_StreamRead));
oobsr.StreamPosition = streampos + streamsize;
oobsr.TrTime = 0x0;
fwrite(&oobsr,sizeof(s_oob_StreamRead),1,f);
SRcntdown = 0x7FF4;
}
streampos += streamsize;
}while(!strconv->stream_end_event);
if(i)
{
fwrite(trackbuffer,i,1,f);
i = 0;
}
}
else
{
imgldr_ctx->hxcfe->hxc_printf(MSG_WARNING,"write_kf_stream_track : No pulse in this track !");
}
// Finish the stream
memset(&oobh,0,sizeof(s_oob_header));
oobh.Sign = 0xD;
oobh.Size = sizeof(s_oob_StreamEnd);
oobh.Type = OOBTYPE_Stream_End;
fwrite(&oobh,sizeof(s_oob_header),1,f);
memset(&oobse,0,sizeof(s_oob_StreamEnd));
oobse.StreamPosition = streampos;
oobse.Result = 0x0;
fwrite(&oobse,sizeof(s_oob_StreamEnd),1,f);
memset(trackbuffer,0x0D,7);
fwrite(&trackbuffer,7,1,f);
imgldr_ctx->hxcfe->hxc_printf(MSG_WARNING,"write_kf_stream_track : End of the track ! (StreamPosition : %d)",oobse.StreamPosition);
hxc_fclose(f);
}
else
{
imgldr_ctx->hxcfe->hxc_printf(MSG_ERROR,"write_kf_stream_track : Can't create %s !",fullp);
}
return 0;
}
int KryoFluxStream_libWrite_DiskFile(HXCFE_IMGLDR* imgldr_ctx,HXCFE_FLOPPY * floppy,char * filename)
{
int i,j, nbrevolutions;
int track_step;
char * tmp_str;
double sck;
nbrevolutions = hxcfe_getEnvVarValue( imgldr_ctx->hxcfe, "KFRAWEXPORT_NUMBER_OF_REVOLUTIONS" );
track_step = 1;
if( hxcfe_getEnvVarValue( imgldr_ctx->hxcfe, "KFRAWEXPORT_DOUBLE_STEP" ) == 1 )
track_step = 2;
sck = DEFAULT_KF_SCLOCK;
tmp_str = hxcfe_getEnvVar( imgldr_ctx->hxcfe, "KFRAWEXPORT_SAMPLE_FREQUENCY", NULL);
if( tmp_str )
{
sck = atof(tmp_str);
if( !( sck >= (4 * 1000000) && sck <= (250 * 1000000) ) )
{
sck = (double)DEFAULT_KF_SCLOCK;
}
}
for(j=0;j<floppy->floppyNumberOfSide;j++)
{
for(i=0;i<floppy->floppyNumberOfTrack;i++)
{
hxcfe_imgCallProgressCallback(imgldr_ctx,i + (j*floppy->floppyNumberOfTrack),floppy->floppyNumberOfTrack*floppy->floppyNumberOfSide );
write_kf_stream_track(imgldr_ctx, filename,floppy->tracks[i]->sides[j],i*track_step,j,nbrevolutions,sck);
}
}
return HXCFE_NOERROR;
}