diff --git a/ChangeLog b/ChangeLog index af5b8e5..c2eed0e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 2022-11-09: -- added preliminary SER file implemenations, not yet tested +- added preliminary SER file implementations, writing seems to work also + with timestamps; reading not yet tested - adding save of videodump files for debugging purposes - adding make target checkdumpfile to test and gain some basic information on videodumpfiles diff --git a/ser.cc b/ser.cc index 9201cff..a07f506 100644 --- a/ser.cc +++ b/ser.cc @@ -29,18 +29,62 @@ SER::SER() { header.DateTime = 0; header.DateTimeUTC = 0; - fd = NULL; + FileDesc = NULL; Frame = NULL; + FramePointer = 0; + Reading = 1; + NumberOfTimeStamps = 0; + TimeStamps = NULL; } /* Class destructor. Free resources. */ SER::~SER() { - /* Close file if necessary */ - if(fd) { - fclose(fd); + + if(FileDesc) { + + /* Update header if necessary */ + if(!Reading) { + + int err; + long offset = (long)&header.FrameCount - (long)&header; + header.FrameCount = FramePointer; + + /* goto file beginning */ + if((err = fseek(FileDesc, offset, SEEK_SET)) == -1) { + fprintf(stderr, "Error: failed seek SER file FrameCount (%d, %s)\n", err, strerror(errno)); + } + else { + /* write framecount in header data */ + if((err = fwrite(&header.FrameCount, sizeof(header.FrameCount), 1, FileDesc)) != 1) { + fprintf(stderr, "Error: failed writing SER file FrameCount (%d, %s)\n", + err, strerror(errno)); + } + } + + /* goto file end */ + if((err = fseek(FileDesc, 0, SEEK_END)) == -1) { + fprintf(stderr, "Error: failed seek SER file end (%d, %s)\n", err, strerror(errno)); + } + else { + /* write timestamp data */ + if((err = fwrite(TimeStamps, sizeof(header.DateTime), FramePointer, FileDesc)) != FramePointer) { + fprintf(stderr, "Error: failed writing SER file TimeStamps (%d, %s)\n", + err, strerror(errno)); + } + } + } + + /* Close file if necessary */ + fclose(FileDesc); + } + + /* Free timestamps */ + if(TimeStamps) { + free(TimeStamps); } + /* Free frame memory if necessary */ if(Frame) { free(Frame); @@ -79,6 +123,7 @@ int SER::setTelescope(char *name) { for reading, otherwise we try to create the file. */ int SER::setFile(char *name) { + FILE *file; /* try opening file for reading */ @@ -93,13 +138,15 @@ int SER::setFile(char *name) { } else { fprintf(stdout, "Debug: created file '%s' for writing SER file\n", name); - fd = file; + FileDesc = file; + Reading = 0; return 0; } } fprintf(stdout, "Debug: opened file '%s' for reading SER file\n", name); - fd = file; + FileDesc = file; + Reading = 1; return 0; } @@ -113,22 +160,64 @@ int SER::writeHeader(void) { /* adjust time stamps for header */ setDateTime(); - if(fd == NULL) { + if(FileDesc == NULL) { fprintf(stderr, "Error: writing header, SER file not yet specified\n"); return -1; } /* goto file beginning */ - if((err = fseek(fd, 0, SEEK_SET)) == -1) { + if((err = fseek(FileDesc, 0, SEEK_SET)) == -1) { fprintf(stderr, "Error: failed seek SER file beginning (%d, %s)\n", err, strerror(errno)); return -1; } /* write header data */ - if((err = fwrite(&header, sizeof(header), 1, fd)) != 1) { + if((err = fwrite(&header, sizeof(header), 1, FileDesc)) != 1) { fprintf(stderr, "Error: failed writing SER header (%d, %s)\n", err, strerror(errno)); return -1; } + + /* reset space for timestamps */ + NumberOfTimeStamps = 16; + if(TimeStamps) { + free(TimeStamps); + } + /* allocate some memory for the upcoming timestamps */ + if((TimeStamps = (int64_t *)malloc(sizeof(header.DateTime) * NumberOfTimeStamps)) == NULL) { + fprintf(stderr, "Error: failed to allocate %d bytes for timestamps\n", + sizeof(header.DateTime) * NumberOfTimeStamps); + return -1; + } + + FramePointer = 0; + return 0; +} + +/* + The function reads the file header of the SER file. + */ +int SER::readHeader(void) { + + int err; + + if(FileDesc == NULL) { + fprintf(stderr, "Error: reading header, SER file not yet specified\n"); + return -1; + } + + /* goto file beginning */ + if((err = fseek(FileDesc, 0, SEEK_SET)) == -1) { + fprintf(stderr, "Error: failed seek SER file beginning (%d, %s)\n", err, strerror(errno)); + return -1; + } + + /* read header data */ + if((err = fread(&header, sizeof(header), 1, FileDesc)) != 1) { + fprintf(stderr, "Error: failed reading SER header (%d, %s)\n", err, strerror(errno)); + return -1; + } + + FramePointer = 0; return 0; } @@ -138,17 +227,29 @@ int SER::writeHeader(void) { */ int SER::appendFrame(void *data) { - if(fd == NULL) { + if(FileDesc == NULL) { fprintf(stderr, "Error: appending frame, SER file not yet specified\n"); return -1; } /* write frame data */ - if(fwrite(data, FrameSize, 1, fd) != 1) { + if(fwrite(data, FrameSize, 1, FileDesc) != 1) { fprintf(stderr, "Error: failed write SER frame (%s)\n", strerror(errno)); return -1; } + + /* ensure we have enough memory allocated for timestamps */ + if(FramePointer >= NumberOfTimeStamps) { + NumberOfTimeStamps *= 2; + if((TimeStamps = (int64_t *)realloc(TimeStamps, sizeof(header.DateTime) * NumberOfTimeStamps)) == NULL) { + fprintf(stderr, "Error: failed to re-allocate %d bytes for timestamps\n", + sizeof(header.DateTime) * NumberOfTimeStamps); + return -1; + } + } + /* save timestamp for this frame */ + TimeStamps[FramePointer++] = currentDateTime(); return 0; } @@ -254,15 +355,59 @@ void * SER::allocFrame(void) { */ int SER::readFrame(void *data) { + int err; + /* read frame data */ - if(fread(data, FrameSize, 1, fd) != FrameSize) { - fprintf(stderr, "Error: failed reading SER frame (%s)\n", strerror(errno)); + if((err = fread(data, FrameSize, 1, FileDesc)) != 1) { + fprintf(stderr, "Error: failed reading SER frame (%d, %s)\n", err, strerror(errno)); return -1; } + + /* goto next frame */ + FramePointer++; + + /* reached end of file? */ + if(FramePointer >= getNumberOfFrames()) { + + /* goto first frame beginning */ + if((err = fseek(FileDesc, sizeof(header), SEEK_SET)) == -1) { + fprintf(stderr, "Error: failed seeking SER file frame #%d (%d, %s)\n", + 0, err, strerror(errno)); + return -1; + } + + /* start over at beginning */ + FramePointer = 0; + } return 0; } +/* + The function reads a single frame at the given file position. + Frame size is determined by internal header data. + */ +int SER::readFrame(void *data, int frame) { + + int err; + + /* goto frame beginning */ + if((err = fseek(FileDesc, sizeof(header) + frame * FrameSize, SEEK_SET)) == -1) { + fprintf(stderr, "Error: failed seeking SER file frame #%d (%d, %s)\n", + frame, err, strerror(errno)); + return -1; + } + + /* read frame data */ + if((err = fread(data, FrameSize, 1, FileDesc)) != 1) { + fprintf(stderr, "Error: failed reading SER frame (%d, %s)\n", err, strerror(errno)); + return -1; + } + + FramePointer = frame + 1; + return 0; +} + /* Sets the number of frames in the header. */ @@ -277,6 +422,18 @@ int32_t SER::getNumberOfFrames(void) { return header.FrameCount; } +/* + Sets the current timestamps in the header. + */ +int64_t SER::setDateTime(void) { + + int64_t hundred_nano_seconds = currentDateTime(); + + header.DateTime = hundred_nano_seconds; + header.DateTimeUTC = hundred_nano_seconds + differenceLocalUTC(); + return header.DateTime; +} + /* Timestamps in SER ----------------- @@ -288,18 +445,17 @@ int32_t SER::getNumberOfFrames(void) { maximum value represents 100 nanoseconds before the beginning of January 1 of the year 10000. */ -int64_t SER::setDateTime() { +int64_t SER::currentDateTime(void) { int64_t hundred_nano_seconds; struct timeval current_time; + struct timezone current_zone; /* get time since 01.01.1970 00:00 */ - gettimeofday(¤t_time, NULL); - hundred_nano_seconds = (62135769600L + current_time.tv_sec) * 10000000L + + gettimeofday (¤t_time, ¤t_zone); + hundred_nano_seconds = (62135596800L + current_time.tv_sec) * 10000000L + current_time.tv_usec * 10L; - header.DateTime = hundred_nano_seconds; - header.DateTimeUTC = hundred_nano_seconds + differenceLocalUTC(); - return header.DateTime; + return hundred_nano_seconds; } /* @@ -307,16 +463,16 @@ int64_t SER::setDateTime() { */ int64_t SER::differenceLocalUTC(void) { - time_t abs_ts,loc_ts,gmt_ts; - struct tm loc_time_info,gmt_time_info; + time_t abs_ts, loc_ts, gmt_ts; + struct tm loc_time_info, gmt_time_info; /* Absolute time stamp.*/ time (&abs_ts); /* Now get once the local time for this time stamp, and once the GMT (UTC without summer time) time stamp.*/ - localtime_r (&abs_ts,&loc_time_info); - gmtime_r (&abs_ts,&gmt_time_info); + localtime_r (&abs_ts, &loc_time_info); + gmtime_r (&abs_ts, &gmt_time_info); /* Convert them back.*/ loc_ts = mktime (&loc_time_info); @@ -325,5 +481,7 @@ int64_t SER::differenceLocalUTC(void) { /* Unfortunately, GMT still has summer time. Get rid of it:*/ if (gmt_time_info.tm_isdst == 1) gmt_ts -= 3600; - return (loc_ts-gmt_ts) * 10000000L; + fprintf(stdout, "Debug: difference between local time and UTC is %ld hours\n", + (loc_ts - gmt_ts) / 3600); + return ((int64_t)gmt_ts - (int64_t)loc_ts) * 10000000L; } diff --git a/ser.h b/ser.h index c460ab5..d327195 100644 --- a/ser.h +++ b/ser.h @@ -11,6 +11,9 @@ ser->setColorID(SER_COLORID_RGB); ser->setPixelDepth(8); ser->setFile((char *)"test.ser"); + ser->setObserver((char *)"Steffen Pohle"); + ser->setTelescope((char *)"Sky-Watcher EVOSTAR 102"); + ser->setInstrument((char *)"Svbony SV305"); ser->setNumberOfFrames(1); ser->writeHeader(); uint8_t * data = (uint8_t *) ser->allocFrame(); @@ -72,13 +75,18 @@ class SER { struct SER_Header header; /* internal data */ - FILE *fd; + FILE * FileDesc; int NumberOfPlanes; int BytesPerPixel; size_t FrameSize; void * Frame; + int FramePointer; + int Reading; + int64_t * TimeStamps; + int NumberOfTimeStamps; void updateHeaderData(void); + int64_t differenceLocalUTC(void); public: SER(); @@ -97,13 +105,15 @@ class SER { int32_t getNumberOfFrames(void); void setNumberOfFrames(int32_t); int64_t setDateTime(void); - int64_t differenceLocalUTC(void); + int64_t currentDateTime(void); size_t getFrameSize(void); int setFile(char *); int writeHeader(void); + int readHeader(void); int appendFrame(void *); int readFrame(void *); + int readFrame(void *, int); void * allocFrame(void); };