2018-10-09 03:26:28 -04:00
///////////////////////////////////////////////////////////////////////////////////
2023-11-19 00:43:20 -05:00
// Copyright (C) 2015-2021 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2018 beta-tester <alpha-beta-release@gmx.net> //
// Copyright (C) 2020 Felix Schneider <felix@fx-schneider.de> //
// Copyright (C) 2021, 2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021 Andreas Baulig <free.geronimo@hotmail.de> //
// Copyright (C) 2021 Christoph Berg <myon@debian.org> //
// Copyright (C) 2022 CRD716 <crd716@gmail.com> //
// Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai> //
2018-10-09 03:26:28 -04:00
// //
// 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 as version 3 of the License, or //
2019-04-11 08:32:15 -04:00
// (at your option) any later version. //
2018-10-09 03:26:28 -04:00
// //
// This program 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 V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
# include <boost/crc.hpp>
# include <boost/cstdint.hpp>
# include <QDebug>
# include <QDateTime>
2015-08-13 23:00:28 -04:00
# include "dsp/dspcommands.h"
2016-05-12 04:31:57 -04:00
# include "util/message.h"
2015-07-28 17:54:17 -04:00
2018-10-09 03:26:28 -04:00
# include "filerecord.h"
2015-07-28 17:54:17 -04:00
2021-05-21 05:06:10 -04:00
FileRecord : : FileRecord ( quint32 sampleRate , quint64 centerFrequency ) :
2020-08-06 04:46:49 -04:00
FileRecordInterface ( ) ,
m_fileBase ( " test " ) ,
2021-05-21 05:06:10 -04:00
m_sampleRate ( sampleRate ) ,
m_centerFrequency ( centerFrequency ) ,
2015-07-28 17:54:17 -04:00
m_recordOn ( false ) ,
m_recordStart ( false ) ,
2020-08-06 04:46:49 -04:00
m_byteCount ( 0 ) ,
2022-09-15 15:59:42 -04:00
m_msShift ( 0 )
2015-07-28 17:54:17 -04:00
{
2020-08-03 18:29:15 -04:00
setObjectName ( " FileRecord " ) ;
2015-07-28 17:54:17 -04:00
}
2020-08-06 04:46:49 -04:00
FileRecord : : FileRecord ( const QString & fileBase ) :
FileRecordInterface ( ) ,
m_fileBase ( fileBase ) ,
2016-05-12 04:31:57 -04:00
m_sampleRate ( 0 ) ,
m_centerFrequency ( 0 ) ,
m_recordOn ( false ) ,
m_recordStart ( false ) ,
2022-09-15 15:59:42 -04:00
m_byteCount ( 0 )
2016-05-12 04:31:57 -04:00
{
2016-10-08 04:35:07 -04:00
setObjectName ( " FileRecord " ) ;
2016-05-12 04:31:57 -04:00
}
2016-10-02 04:30:58 -04:00
FileRecord : : ~ FileRecord ( )
2015-07-28 17:54:17 -04:00
{
stopRecording ( ) ;
}
2020-08-06 04:46:49 -04:00
void FileRecord : : setFileName ( const QString & fileBase )
2015-07-28 17:54:17 -04:00
{
2016-05-12 04:31:57 -04:00
if ( ! m_recordOn )
{
2020-08-06 04:46:49 -04:00
m_fileBase = fileBase ;
2016-05-12 04:31:57 -04:00
}
2015-07-28 17:54:17 -04:00
}
2019-05-28 02:56:36 -04:00
void FileRecord : : genUniqueFileName ( uint deviceUID , int istream )
2018-05-11 03:08:20 -04:00
{
2019-05-28 02:56:36 -04:00
if ( istream < 0 ) {
setFileName ( QString ( " rec%1_%2.sdriq " ) . arg ( deviceUID ) . arg ( QDateTime : : currentDateTimeUtc ( ) . toString ( " yyyy-MM-ddTHH_mm_ss_zzz " ) ) ) ;
} else {
setFileName ( QString ( " rec%1_%2_%3.sdriq " ) . arg ( deviceUID ) . arg ( istream ) . arg ( QDateTime : : currentDateTimeUtc ( ) . toString ( " yyyy-MM-ddTHH_mm_ss_zzz " ) ) ) ;
}
2018-05-11 03:08:20 -04:00
}
2018-11-12 10:58:20 -05:00
void FileRecord : : feed ( const SampleVector : : const_iterator & begin , const SampleVector : : const_iterator & end , bool positiveOnly )
2015-07-28 17:54:17 -04:00
{
2021-03-06 15:55:21 -05:00
QMutexLocker mutexLocker ( & m_mutex ) ;
2018-11-12 10:58:20 -05:00
( void ) positiveOnly ;
2021-03-06 15:55:21 -05:00
2015-07-28 17:54:17 -04:00
// if no recording is active, send the samples to /dev/null
if ( ! m_recordOn )
return ;
if ( begin < end ) // if there is something to put out
{
if ( m_recordStart )
{
writeHeader ( ) ;
m_recordStart = false ;
}
m_sampleFile . write ( reinterpret_cast < const char * > ( & * ( begin ) ) , ( end - begin ) * sizeof ( Sample ) ) ;
m_byteCount + = end - begin ;
}
}
2016-10-02 04:30:58 -04:00
void FileRecord : : start ( )
2015-07-28 17:54:17 -04:00
{
}
2016-10-02 04:30:58 -04:00
void FileRecord : : stop ( )
2015-07-28 17:54:17 -04:00
{
stopRecording ( ) ;
}
2021-01-18 04:55:15 -05:00
bool FileRecord : : startRecording ( )
2015-07-28 17:54:17 -04:00
{
2021-03-06 15:55:21 -05:00
QMutexLocker mutexLocker ( & m_mutex ) ;
2020-08-06 04:46:49 -04:00
if ( m_recordOn ) {
stopRecording ( ) ;
}
2023-01-02 10:42:34 -05:00
# ifdef ANDROID
if ( ! m_sampleFile . isOpen ( ) )
# else
2015-07-28 17:54:17 -04:00
if ( ! m_sampleFile . is_open ( ) )
2023-01-02 10:42:34 -05:00
# endif
2015-07-28 17:54:17 -04:00
{
2016-10-08 04:35:07 -04:00
qDebug ( ) < < " FileRecord::startRecording " ;
2023-01-02 10:42:34 -05:00
# ifdef ANDROID
// FIXME: No idea how to write to a file where the filename doesn't come from the file picker
m_currentFileName = m_fileBase + " .sdriq " ;
m_sampleFile . setFileName ( m_currentFileName ) ;
if ( ! m_sampleFile . open ( QIODevice : : ReadWrite ) )
{
qWarning ( ) < < " FileRecord::startRecording: failed to open file: " < < m_currentFileName < < " error " < < m_sampleFile . error ( ) ;
return false ;
}
# else
m_currentFileName = m_fileBase + " . " + QDateTime : : currentDateTimeUtc ( ) . toString ( " yyyy-MM-ddTHH_mm_ss_zzz " ) + " .sdriq " ; // Don't use QString::arg on Android, as filename can contain %2
2022-10-27 22:46:02 -04:00
m_sampleFile . open ( m_currentFileName . toStdString ( ) . c_str ( ) , std : : ios : : binary ) ;
2021-01-18 04:55:15 -05:00
if ( ! m_sampleFile . is_open ( ) )
{
2022-10-27 23:18:33 -04:00
qWarning ( ) < < " FileRecord::startRecording: failed to open file: " < < m_currentFileName ;
2021-01-18 04:55:15 -05:00
return false ;
}
2023-01-02 10:42:34 -05:00
# endif
2015-07-28 17:54:17 -04:00
m_recordOn = true ;
m_recordStart = true ;
m_byteCount = 0 ;
}
2021-01-18 04:55:15 -05:00
return true ;
2015-07-28 17:54:17 -04:00
}
2021-01-18 04:55:15 -05:00
bool FileRecord : : stopRecording ( )
2015-07-28 17:54:17 -04:00
{
2021-03-06 15:55:21 -05:00
QMutexLocker mutexLocker ( & m_mutex ) ;
2023-01-02 10:42:34 -05:00
# ifdef ANDROID
if ( m_sampleFile . isOpen ( ) )
# else
2015-07-28 17:54:17 -04:00
if ( m_sampleFile . is_open ( ) )
2023-01-02 10:42:34 -05:00
# endif
2015-07-28 17:54:17 -04:00
{
2016-10-08 04:35:07 -04:00
qDebug ( ) < < " FileRecord::stopRecording " ;
2015-07-28 17:54:17 -04:00
m_sampleFile . close ( ) ;
m_recordOn = false ;
m_recordStart = false ;
2023-01-02 10:42:34 -05:00
# ifdef ANDROID
# else
2021-01-18 04:55:15 -05:00
if ( m_sampleFile . bad ( ) )
{
2022-10-27 23:18:33 -04:00
qWarning ( ) < < " FileRecord::stopRecording: an error occurred while writing to " < < m_currentFileName ;
2021-01-18 04:55:15 -05:00
return false ;
}
2023-01-02 10:42:34 -05:00
# endif
2015-07-28 17:54:17 -04:00
}
2021-01-18 04:55:15 -05:00
return true ;
2015-07-28 17:54:17 -04:00
}
2016-10-02 04:30:58 -04:00
bool FileRecord : : handleMessage ( const Message & message )
2015-07-28 17:54:17 -04:00
{
2015-08-17 02:29:34 -04:00
if ( DSPSignalNotification : : match ( message ) )
{
2021-03-08 17:41:00 -05:00
QMutexLocker mutexLocker ( & m_mutex ) ;
2015-08-17 02:29:34 -04:00
DSPSignalNotification & notif = ( DSPSignalNotification & ) message ;
2021-03-07 05:30:05 -05:00
quint32 sampleRate = notif . getSampleRate ( ) ;
qint64 centerFrequency = notif . getCenterFrequency ( ) ;
qDebug ( ) < < " FileRecord::handleMessage: DSPSignalNotification: inputSampleRate: " < < sampleRate
< < " centerFrequency: " < < centerFrequency ;
2020-08-06 04:46:49 -04:00
2021-03-07 05:30:05 -05:00
if ( m_recordOn & & ( m_sampleRate ! = sampleRate ) ) {
2020-08-06 04:46:49 -04:00
startRecording ( ) ;
}
2021-03-07 05:30:05 -05:00
m_sampleRate = sampleRate ;
m_centerFrequency = centerFrequency ;
2020-08-06 04:46:49 -04:00
return true ;
2015-08-17 02:29:34 -04:00
}
2015-07-28 17:54:17 -04:00
else
{
return false ;
}
}
2016-10-02 04:30:58 -04:00
void FileRecord : : writeHeader ( )
2015-07-28 17:54:17 -04:00
{
2018-10-09 03:26:28 -04:00
Header header ;
header . sampleRate = m_sampleRate ;
header . centerFrequency = m_centerFrequency ;
2021-08-04 09:38:42 -04:00
qint64 ts = QDateTime : : currentMSecsSinceEpoch ( ) ;
header . startTimeStamp = ( quint64 ) ( ts + m_msShift ) ;
2018-10-09 03:26:28 -04:00
header . sampleSize = SDR_RX_SAMP_SZ ;
header . filler = 0 ;
2018-10-10 08:05:21 -04:00
writeHeader ( m_sampleFile , header ) ;
2015-07-28 17:54:17 -04:00
}
2018-10-09 03:26:28 -04:00
bool FileRecord : : readHeader ( std : : ifstream & sampleFile , Header & header )
2015-07-28 17:54:17 -04:00
{
2018-10-09 03:26:28 -04:00
sampleFile . read ( ( char * ) & header , sizeof ( Header ) ) ;
boost : : crc_32_type crc32 ;
crc32 . process_bytes ( & header , 28 ) ;
return header . crc32 = = crc32 . checksum ( ) ;
2015-07-28 17:54:17 -04:00
}
2018-10-10 08:05:21 -04:00
2023-01-02 10:42:34 -05:00
bool FileRecord : : readHeader ( QFile & sampleFile , Header & header )
{
sampleFile . read ( ( char * ) & header , sizeof ( Header ) ) ;
boost : : crc_32_type crc32 ;
crc32 . process_bytes ( & header , 28 ) ;
return header . crc32 = = crc32 . checksum ( ) ;
}
2018-10-10 08:05:21 -04:00
void FileRecord : : writeHeader ( std : : ofstream & sampleFile , Header & header )
{
boost : : crc_32_type crc32 ;
crc32 . process_bytes ( & header , 28 ) ;
header . crc32 = crc32 . checksum ( ) ;
sampleFile . write ( ( const char * ) & header , sizeof ( Header ) ) ;
2018-11-12 10:58:20 -05:00
}
2023-01-02 10:42:34 -05:00
void FileRecord : : writeHeader ( QFile & sampleFile , Header & header )
{
boost : : crc_32_type crc32 ;
crc32 . process_bytes ( & header , 28 ) ;
header . crc32 = crc32 . checksum ( ) ;
sampleFile . write ( ( const char * ) & header , sizeof ( Header ) ) ;
}