Mesen-S/Core/BsxStream.cpp
2020-02-22 12:11:51 -05:00

277 lines
5.2 KiB
C++

#include "stdafx.h"
#include "BsxStream.h"
#include "Console.h"
#include "MemoryManager.h"
#include "../Utilities/FolderUtilities.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/Serializer.h"
BsxStream::BsxStream()
{
}
void BsxStream::Reset(Console* console, int64_t resetDate)
{
_console = console;
_memoryManager = console->GetMemoryManager().get();
_file.close();
_channel = 0;
_prefix = 0;
_data = 0;
_status = 0;
_prefixLatch = false;
_dataLatch = false;
_firstPacket = false;
_fileOffset = 0;
_fileIndex = 0;
_queueLength = 0;
_prefixQueueLength = 0;
_dataQueueLength = 0;
_activeChannel = 0;
_activeFileIndex = 0;
_resetDate = resetDate;
_resetMasterClock = 0;
_tm = {};
}
uint16_t BsxStream::GetChannel()
{
return _channel;
}
bool BsxStream::NeedUpdate()
{
return _queueLength > 0;
}
bool BsxStream::FillQueues()
{
if(_queueLength > 0) {
_queueLength--;
if(_prefixLatch && _prefixQueueLength < 0x80) {
_prefixQueueLength++;
}
if(_dataLatch && _dataQueueLength < 0x80) {
_dataQueueLength++;
}
}
return NeedUpdate();
}
void BsxStream::OpenStreamFile()
{
_file.close();
string filename = "BSX" + HexUtilities::ToHex(_activeChannel) + "-" + std::to_string(_activeFileIndex) + ".bin";
string folder = FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "Satellaview");
_file.open(FolderUtilities::CombinePath(folder, filename), ios::binary);
}
bool BsxStream::LoadStreamFile()
{
_activeChannel = _channel;
_activeFileIndex = _fileIndex;
OpenStreamFile();
if(_file) {
_firstPacket = true;
_file.seekg(0, ios::end);
_queueLength = (uint16_t)std::ceil(_file.tellg() / 22.0);
_file.seekg(0, ios::beg);
_fileIndex++;
return true;
} else {
if(_fileIndex > 0) {
//Go back to file #0 and try again
_fileIndex = 0;
if(LoadStreamFile()) {
return true;
}
}
//Couldn't load data for the specified channel
_prefix |= 0x0F;
return false;
}
}
uint8_t BsxStream::GetPrefixCount()
{
if(!_prefixLatch || !_dataLatch) {
//Stream is disabled
return 0;
}
if(_prefixQueueLength == 0 && _dataQueueLength == 0) {
//Queue is empty, try to load in new data
_fileOffset = 0;
if(_channel == 0) {
//Time channel
_queueLength = 1;
_firstPacket = true;
} else {
LoadStreamFile();
}
}
return _prefixQueueLength;
}
uint8_t BsxStream::GetPrefix()
{
if(!_prefixLatch) {
return 0;
}
if(_prefixQueueLength > 0) {
_prefix = 0;
if(_firstPacket) {
_prefix |= 0x10;
_firstPacket = false;
}
_prefixQueueLength--;
if(_queueLength == 0 && _prefixQueueLength == 0) {
//Last packet
_prefix |= 0x80;
}
}
_status |= _prefix;
return _prefix;
}
uint8_t BsxStream::GetData()
{
if(!_dataLatch) {
return 0;
}
if(_dataQueueLength > 0) {
if(_channel == 0) {
//Return Time
_data = GetTime();
} else if(_file) {
//Read byte from stream file
char byte;
_file.get(byte);
_data = (uint8_t)byte;
}
_fileOffset++;
if(_fileOffset % 22 == 0) {
//Finished reading current packet
_dataQueueLength--;
}
}
return _data;
}
uint8_t BsxStream::GetStatus(bool reset)
{
uint8_t status = _status;
if(reset) {
_status = 0;
}
return status;
}
void BsxStream::SetChannelLow(uint8_t value)
{
if((_channel & 0xFF) != 0xFF) {
_fileIndex = 0;
}
_channel = (_channel & 0xFF00) | value;
}
void BsxStream::SetChannelHigh(uint8_t value)
{
if((_channel >> 8) != (value & 0x3F)) {
_fileIndex = 0;
}
_channel = (_channel & 0xFF) | ((value & 0x3F) << 8);
}
void BsxStream::SetPrefixLatch(uint8_t value)
{
_prefixLatch = (value != 0);
_prefixQueueLength = 0;
}
void BsxStream::SetDataLatch(uint8_t value)
{
_dataLatch = (value != 0);
_dataQueueLength = 0;
}
void BsxStream::InitTimeStruct()
{
time_t dateTime = _resetDate + ((_memoryManager->GetMasterClock() - _resetMasterClock) / _console->GetMasterClockRate());
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
localtime_s(&_tm, &dateTime);
#else
localtime_r(&dateTime, &_tm);
#endif
_tm.tm_wday++;
_tm.tm_mon++;
_tm.tm_year += 1900;
}
uint8_t BsxStream::GetTime()
{
if(_fileOffset == 0) {
InitTimeStruct();
}
switch(_fileOffset) {
case 0: return 0x00; //Data Group ID / Repetition
case 1: return 0x00; //Data Group Link / Continuity
case 2: return 0x00; //Data Group Size (24-bit)
case 3: return 0x00;
case 4: return 0x10;
case 5: return 0x01; //Must be 0x01
case 6: return 0x01; //Amount of packets (1)
case 7: return 0x00; //Offset (24-bit)
case 8: return 0x00;
case 9: return 0x00;
case 10: return _tm.tm_sec;
case 11: return _tm.tm_min;
case 12: return _tm.tm_hour;
case 13: return _tm.tm_wday;
case 14: return _tm.tm_mday;
case 15: return _tm.tm_mon;
case 16: return _tm.tm_year >> 0;
case 17: return _tm.tm_year >> 8;
default: return 0x00;
}
}
void BsxStream::Serialize(Serializer& s)
{
s.Stream(
_channel, _prefix, _data, _status, _prefixLatch, _dataLatch, _firstPacket, _fileOffset, _fileIndex,
_queueLength, _prefixQueueLength, _dataQueueLength, _resetDate, _resetMasterClock, _activeChannel, _activeFileIndex
);
if(!s.IsSaving()) {
InitTimeStruct();
OpenStreamFile();
if(_file) {
//Seek back to the previous location
_file.seekg(_fileOffset, ios::beg);
}
}
}