Memory card work: Show "CHECKING" when we've seen the card and

havn't finished checking it out yet (eg. write check).  This improves responsiveness:
a slow card will indicate that we see the card immediately, and it helps
diagnostics since we can easily tell if the machine sees a card.  Allow re-
establishing a memory card removed after finalization, as long as it has the
same serial number.
This commit is contained in:
Glenn Maynard
2005-02-06 05:08:46 +00:00
parent e4117354ae
commit ca4589a8c3
7 changed files with 211 additions and 81 deletions
+2
View File
@@ -122,8 +122,10 @@ XToThemedString( HoldNoteScore, NUM_HOLD_NOTE_SCORES );
static const CString MemoryCardStateNames[NUM_MEMORY_CARD_STATES] = { static const CString MemoryCardStateNames[NUM_MEMORY_CARD_STATES] = {
"ready", "ready",
"checking",
"late", "late",
"error", "error",
"removed",
"none", "none",
}; };
XToString( MemoryCardState ); XToString( MemoryCardState );
+2
View File
@@ -173,8 +173,10 @@ enum ProfileSlot
enum MemoryCardState enum MemoryCardState
{ {
MEMORY_CARD_STATE_READY, MEMORY_CARD_STATE_READY,
MEMORY_CARD_STATE_CHECKING,
MEMORY_CARD_STATE_TOO_LATE, MEMORY_CARD_STATE_TOO_LATE,
MEMORY_CARD_STATE_WRITE_ERROR, MEMORY_CARD_STATE_WRITE_ERROR,
MEMORY_CARD_STATE_REMOVED,
MEMORY_CARD_STATE_NO_CARD, MEMORY_CARD_STATE_NO_CARD,
NUM_MEMORY_CARD_STATES, NUM_MEMORY_CARD_STATES,
MEMORY_CARD_STATE_INVALID, MEMORY_CARD_STATE_INVALID,
+9 -9
View File
@@ -109,19 +109,14 @@ void GameState::Reset()
{ {
EndGame(); EndGame();
/* Don't do the OS mount for cards during the attract screens. Only do OS mounts in
* the time between BeginGame and PlayersFinalized. I think we do that anyway (except
* for background write tests, which happen anyway unless the memory card thread is
* paused). Can we remove this? */
MEMCARDMAN->LockCards();
ASSERT( THEME ); ASSERT( THEME );
m_timeGameStarted.SetZero(); m_timeGameStarted.SetZero();
m_pCurStyle = NULL; m_pCurStyle = NULL;
FOREACH_PlayerNumber( p ) FOREACH_PlayerNumber( p )
m_bSideIsJoined[p] = false; m_bSideIsJoined[p] = false;
m_bPlayersFinalized = false; MEMCARDMAN->SetPlayersFinalized( false );
MEMCARDMAN->UnlockCards();
// m_iCoins = 0; // don't reset coin count! // m_iCoins = 0; // don't reset coin count!
m_MasterPlayerNumber = PLAYER_INVALID; m_MasterPlayerNumber = PLAYER_INVALID;
m_mapEnv.clear(); m_mapEnv.clear();
@@ -161,6 +156,11 @@ void GameState::Reset()
ResetMusicStatistics(); ResetMusicStatistics();
ResetStageStatistics(); ResetStageStatistics();
FOREACH_PlayerNumber( pn )
if( PROFILEMAN->ProfileWasLoadedFromMemoryCard(pn) )
PROFILEMAN->UnloadProfile( pn );
SONGMAN->FreeAllLoadedFromProfiles(); SONGMAN->FreeAllLoadedFromProfiles();
SONGMAN->UpdateBest(); SONGMAN->UpdateBest();
SONGMAN->UpdateShuffled(); SONGMAN->UpdateShuffled();
@@ -230,10 +230,10 @@ void GameState::BeginGame()
void GameState::PlayersFinalized() void GameState::PlayersFinalized()
{ {
if( m_bPlayersFinalized ) if( MEMCARDMAN->GetPlayersFinalized() )
return; return;
m_bPlayersFinalized = true; MEMCARDMAN->SetPlayersFinalized( true );
MEMCARDMAN->LockCards(); MEMCARDMAN->LockCards();
-1
View File
@@ -47,7 +47,6 @@ public:
const Game* m_pCurGame; const Game* m_pCurGame;
const Style* m_pCurStyle; const Style* m_pCurStyle;
bool m_bSideIsJoined[NUM_PLAYERS]; // left side, right side bool m_bSideIsJoined[NUM_PLAYERS]; // left side, right side
bool m_bPlayersFinalized;
PlayMode m_PlayMode; // many screens display different info depending on this value PlayMode m_PlayMode; // many screens display different info depending on this value
int m_iCoins; // not "credits" int m_iCoins; // not "credits"
PlayerNumber m_MasterPlayerNumber; // used in Styles where one player controls both sides PlayerNumber m_MasterPlayerNumber; // used in Styles where one player controls both sides
+170 -62
View File
@@ -11,7 +11,6 @@
#include "ScreenManager.h" #include "ScreenManager.h"
#include "ProfileManager.h" #include "ProfileManager.h"
#include "Foreach.h" #include "Foreach.h"
#include "GameState.h"
#include "RageUtil_WorkerThread.h" #include "RageUtil_WorkerThread.h"
MemoryCardManager* MEMCARDMAN = NULL; // global and accessable from anywhere in our program MemoryCardManager* MEMCARDMAN = NULL; // global and accessable from anywhere in our program
@@ -241,10 +240,12 @@ MemoryCardManager::MemoryCardManager()
m_bCardsLocked = false; m_bCardsLocked = false;
FOREACH_PlayerNumber( p ) FOREACH_PlayerNumber( p )
{ {
m_bTooLate[p] = false;
m_bMounted[p] = false; m_bMounted[p] = false;
m_State[p] = MEMORY_CARD_STATE_NO_CARD;
} }
m_bPlayersFinalized = false;
/* These can play at any time. Preload them, so we don't cause a skip in gameplay. */ /* These can play at any time. Preload them, so we don't cause a skip in gameplay. */
m_soundReady.Load( THEME->GetPathS("MemoryCardManager","ready"), true ); m_soundReady.Load( THEME->GetPathS("MemoryCardManager","ready"), true );
m_soundError.Load( THEME->GetPathS("MemoryCardManager","error"), true ); m_soundError.Load( THEME->GetPathS("MemoryCardManager","error"), true );
@@ -269,7 +270,7 @@ void MemoryCardManager::Update( float fDelta )
const vector<UsbStorageDevice> vOld = m_vStorageDevices; // copy const vector<UsbStorageDevice> vOld = m_vStorageDevices; // copy
if( !g_pWorker->StorageDevicesChanged( m_vStorageDevices ) ) if( !g_pWorker->StorageDevicesChanged( m_vStorageDevices ) )
return; return;
const vector<UsbStorageDevice> &vNew = m_vStorageDevices; /* const vector<UsbStorageDevice> &vNew = m_vStorageDevices;
vector<UsbStorageDevice> vConnects; // fill these in below vector<UsbStorageDevice> vConnects; // fill these in below
vector<UsbStorageDevice> vDisconnects; // fill these in below vector<UsbStorageDevice> vDisconnects; // fill these in below
@@ -305,35 +306,9 @@ void MemoryCardManager::Update( float fDelta )
vector<UsbStorageDevice>::iterator iter = find( vDisconnects.begin(), vDisconnects.end(), assigned_device ); vector<UsbStorageDevice>::iterator iter = find( vDisconnects.begin(), vDisconnects.end(), assigned_device );
if( iter != vDisconnects.end() ) if( iter != vDisconnects.end() )
{
UnmountCard( p );
assigned_device.MakeBlank(); assigned_device.MakeBlank();
m_soundDisconnect.Play();
if( PROFILEMAN->ProfileWasLoadedFromMemoryCard(p) )
PROFILEMAN->UnloadProfile( p );
}
} }
*/
// Update the status of already-assigned cards. It may contain updated info
// like WriteTest results and a new sName.
FOREACH_PlayerNumber( p )
{
UsbStorageDevice &assigned_device = m_Device[p];
if( assigned_device.IsBlank() ) // no card assigned to this player
continue;
vector<UsbStorageDevice>::iterator iter = find( m_vStorageDevices.begin(), m_vStorageDevices.end(), assigned_device );
if( iter != m_vStorageDevices.end() )
{
// play write test error sound if write test failed since we last checked
if( assigned_device.bNeedsWriteTest && !iter->bNeedsWriteTest && !iter->bWriteTestSucceeded )
m_soundError.Play();
assigned_device = *iter;
}
}
// make a list of unassigned // make a list of unassigned
vector<UsbStorageDevice> vUnassignedDevices = m_vStorageDevices; // copy vector<UsbStorageDevice> vUnassignedDevices = m_vStorageDevices; // copy
@@ -354,18 +329,32 @@ void MemoryCardManager::Update( float fDelta )
} }
} }
// try to assign each device to a player // Try to assign each device to a player. If a player already has a device
// assigned, and the device still exists, keep him on the same card.
FOREACH_PlayerNumber( p ) FOREACH_PlayerNumber( p )
{ {
LOG->Trace( "Looking for a card for Player %d", p+1 );
UsbStorageDevice &assigned_device = m_Device[p]; UsbStorageDevice &assigned_device = m_Device[p];
if( !assigned_device.IsBlank() ) // they already have an assigned card if( !assigned_device.IsBlank() )
{ {
LOG->Trace( "Player %d already has a card: '%s'", p+1, assigned_device.sOsMountDir.c_str() ); /* The player has a card assigned. If it's been removed, clear it. */
continue; // skip vector<UsbStorageDevice>::iterator it = find( m_vStorageDevices.begin(), m_vStorageDevices.end(), assigned_device );
if( it != m_vStorageDevices.end() )
{
/* The player has a card, and it's still plugged in. Update any changed
* state, such as m_State. */
LOG->Trace( "Player %d already has a card: '%s'", p+1, assigned_device.sOsMountDir.c_str() );
assigned_device = *it;
continue;
}
/* The assigned card has been removed; clear it and re-search. */
LOG->Trace( "Player %i: disconnected bus %d port %d device %d path %s",
p+1, assigned_device.iBus, assigned_device.iPort, assigned_device.iLevel, assigned_device.sOsMountDir.c_str() );
assigned_device.MakeBlank();
} }
LOG->Trace( "Looking for a card for Player %d", p+1 );
FOREACH( UsbStorageDevice, vUnassignedDevices, d ) FOREACH( UsbStorageDevice, vUnassignedDevices, d )
{ {
// search for card dir match // search for card dir match
@@ -386,39 +375,106 @@ void MemoryCardManager::Update( float fDelta )
PREFSMAN->m_iMemoryCardUsbLevel[p] != d->iLevel ) PREFSMAN->m_iMemoryCardUsbLevel[p] != d->iLevel )
continue; // not a match continue; // not a match
LOG->Trace( "device match: iScsiIndex: %d, iBus: %d, iLevel: %d, iPort: %d, sOsMountDir: %s", LOG->Trace( "Player %i: device match: iScsiIndex: %d, iBus: %d, iLevel: %d, iPort: %d, sOsMountDir: %s",
d->iScsiIndex, d->iBus, d->iLevel, d->iPort, d->sOsMountDir.c_str() ); p+1, d->iScsiIndex, d->iBus, d->iLevel, d->iPort, d->sOsMountDir.c_str() );
assigned_device = *d; // save a copy assigned_device = *d; // save a copy
vUnassignedDevices.erase( d ); // remove the device so we don't match it for another player vUnassignedDevices.erase( d ); // remove the device so we don't match it for another player
m_bTooLate[p] = GAMESTATE->m_bPlayersFinalized; // the device is too late if inserted when cards were locked
// play sound
if( m_bTooLate[p] )
m_soundTooLate.Play();
else if( !d->bNeedsWriteTest && !d->bWriteTestSucceeded )
m_soundError.Play();
else
m_soundReady.Play();
break; break;
} }
} }
SCREENMAN->RefreshCreditsMessages(); CheckStateChanges();
} }
MemoryCardState MemoryCardManager::GetCardState( PlayerNumber pn ) void MemoryCardManager::CheckStateChanges()
{ {
UsbStorageDevice &d = m_Device[pn]; /* Deal with assignment changes. */
if( d.IsBlank() ) FOREACH_PlayerNumber( p )
return MEMORY_CARD_STATE_NO_CARD; {
else if( m_bTooLate[pn] ) UsbStorageDevice &new_device = m_Device[p];
return MEMORY_CARD_STATE_TOO_LATE;
else if( !d.bNeedsWriteTest && !d.bWriteTestSucceeded ) MemoryCardState state = MEMORY_CARD_STATE_INVALID;
return MEMORY_CARD_STATE_WRITE_ERROR;
else if( m_bPlayersFinalized )
return MEMORY_CARD_STATE_READY; {
if( m_FinalDevice[p].m_State == UsbStorageDevice::STATE_NONE )
{
/* We didn't have a card when we finalized, so we won't accept anything.
* If anything is inserted (even if it's still checking), say TOO LATE. */
if( new_device.m_State == UsbStorageDevice::STATE_NONE )
state = MEMORY_CARD_STATE_NO_CARD;
else
state = MEMORY_CARD_STATE_TOO_LATE;
}
else
{
/* We had a card inserted when we finalized. */
if( new_device.m_State == UsbStorageDevice::STATE_NONE )
state = MEMORY_CARD_STATE_REMOVED;
if( new_device.m_State == UsbStorageDevice::STATE_READY )
{
if( m_FinalDevice[p].sSerial != new_device.sSerial )
{
/* A different card is inserted than we had when we finalized;
* ignore it. */
state = MEMORY_CARD_STATE_REMOVED;
}
}
/* Otherwise, the card is checking or has an error. Use the regular logic. */
}
}
if( state == MEMORY_CARD_STATE_INVALID )
{
switch( new_device.m_State )
{
case UsbStorageDevice::STATE_NONE:
state = MEMORY_CARD_STATE_NO_CARD;
break;
case UsbStorageDevice::STATE_CHECKING:
state = MEMORY_CARD_STATE_CHECKING;
break;
case UsbStorageDevice::STATE_WRITE_ERROR:
state = MEMORY_CARD_STATE_WRITE_ERROR;
break;
case UsbStorageDevice::STATE_READY:
state = MEMORY_CARD_STATE_READY;
break;
}
}
MemoryCardState LastState = m_State[p];
if( m_State[p] != state )
{
// play sound
switch( state )
{
case MEMORY_CARD_STATE_NO_CARD:
case MEMORY_CARD_STATE_REMOVED:
if( LastState == MEMORY_CARD_STATE_READY )
m_soundDisconnect.Play();
break;
case MEMORY_CARD_STATE_READY:
m_soundReady.Play();
break;
case MEMORY_CARD_STATE_TOO_LATE:
m_soundTooLate.Play();
break;
case MEMORY_CARD_STATE_WRITE_ERROR:
m_soundError.Play();
break;
}
m_State[p] = state;
}
}
SCREENMAN->RefreshCreditsMessages();
} }
void MemoryCardManager::LockCards() void MemoryCardManager::LockCards()
@@ -434,8 +490,8 @@ void MemoryCardManager::UnlockCards()
m_bCardsLocked = false; m_bCardsLocked = false;
// clear too late flag // clear too late flag
FOREACH_PlayerNumber( p ) // FOREACH_PlayerNumber( p )
m_bTooLate[p] = false; // m_State[p] = MEMORY_CARD_STATE_NO_CARD;
g_pWorker->SetMountThreadState( ThreadedMemoryCardWorker::detect_and_mount ); g_pWorker->SetMountThreadState( ThreadedMemoryCardWorker::detect_and_mount );
} }
@@ -518,7 +574,7 @@ void MemoryCardManager::FlushAndReset()
UsbStorageDevice &d = m_Device[p]; UsbStorageDevice &d = m_Device[p];
if( d.IsBlank() ) // no card assigned if( d.IsBlank() ) // no card assigned
continue; // skip continue; // skip
if( (!d.bNeedsWriteTest && !d.bWriteTestSucceeded) || m_bTooLate[p] ) if( d.m_State == UsbStorageDevice::STATE_WRITE_ERROR )
continue; // skip continue; // skip
g_pWorker->Flush( &m_Device[p] ); g_pWorker->Flush( &m_Device[p] );
} }
@@ -526,6 +582,58 @@ void MemoryCardManager::FlushAndReset()
g_pWorker->Reset(); // forces cards to be re-detected g_pWorker->Reset(); // forces cards to be re-detected
} }
void MemoryCardManager::SetPlayersFinalized( bool bOn )
{
m_bPlayersFinalized = bOn;
if( !bOn )
{
m_bPlayersFinalized = false;
/* If a memory card was inserted too late last game, allow it now. */
CheckStateChanges();
return;
}
// g_pWorker->SetTimeout( 10 );
// ASSERT( g_pWorker->TimeoutEnabled() );
/* XXX: wait */
FOREACH_PlayerNumber( p )
{
/* If the card in this player's slot is ready, then use it. */
// XXX: share code with Update(): keep updating until timed out or
// STATE_READY or STATE_NONE
UsbStorageDevice &d = m_Device[p];
/* Set the final state. */
switch( d.m_State )
{
case UsbStorageDevice::STATE_READY:
m_State[p] = MEMORY_CARD_STATE_READY;
m_FinalDevice[p] = d;
break;
case UsbStorageDevice::STATE_NONE:
m_State[p] = MEMORY_CARD_STATE_NO_CARD;
break;
case UsbStorageDevice::STATE_CHECKING:
case UsbStorageDevice::STATE_WRITE_ERROR:
m_State[p] = MEMORY_CARD_STATE_WRITE_ERROR;
break;
default:
FAIL_M( ssprintf("%i", d.m_State) );
}
/* If there is no card ready when we finalize, the final device must be blank. */
if( m_State[p] != MEMORY_CARD_STATE_READY )
m_FinalDevice[p] = UsbStorageDevice();
}
}
bool MemoryCardManager::PathIsMemCard( CString sDir ) const bool MemoryCardManager::PathIsMemCard( CString sDir ) const
{ {
FOREACH_PlayerNumber( p ) FOREACH_PlayerNumber( p )
+14 -3
View File
@@ -17,7 +17,7 @@ public:
void Update( float fDelta ); void Update( float fDelta );
MemoryCardState GetCardState( PlayerNumber pn ); MemoryCardState GetCardState( PlayerNumber pn ) const { return m_State[pn]; }
void LockCards(); // prevent removing or changing of memory cards void LockCards(); // prevent removing or changing of memory cards
void UnlockCards(); void UnlockCards();
@@ -26,6 +26,10 @@ public:
void FlushAndReset(); // force all files to be flushed to mounted memory cards void FlushAndReset(); // force all files to be flushed to mounted memory cards
/* If bOn is true, and a card is still initializing, block until it's ready. */
void SetPlayersFinalized( bool bOn );
bool GetPlayersFinalized() const { return m_bPlayersFinalized; }
bool PathIsMemCard( CString sDir ) const; bool PathIsMemCard( CString sDir ) const;
bool IsNameAvailable( PlayerNumber pn ) const; bool IsNameAvailable( PlayerNumber pn ) const;
@@ -34,13 +38,20 @@ public:
protected: protected:
void PauseMountingThread(); // call this before mouting, reading, or writing to memory card void PauseMountingThread(); // call this before mouting, reading, or writing to memory card
void UnPauseMountingThread(); // call this when done mouting, reading, or writing to memory card void UnPauseMountingThread(); // call this when done mouting, reading, or writing to memory card
void CheckStateChanges();
vector<UsbStorageDevice> m_vStorageDevices; // all currently connected vector<UsbStorageDevice> m_vStorageDevices; // all currently connected
bool m_bCardsLocked; bool m_bCardsLocked;
bool m_bTooLate[NUM_PLAYERS]; // card was inserted after lock
bool m_bMounted[NUM_PLAYERS]; // card is currently mounted bool m_bMounted[NUM_PLAYERS]; // card is currently mounted
UsbStorageDevice m_Device[NUM_PLAYERS]; // device in the memory card slot, NULL if none
UsbStorageDevice m_Device[NUM_PLAYERS]; // device in the memory card slot, blank if none
UsbStorageDevice m_FinalDevice[NUM_PLAYERS]; // device in the memory card slot when we finalized, blank if none
MemoryCardState m_State[NUM_PLAYERS];
bool m_bPlayersFinalized;
RageSound m_soundReady; RageSound m_soundReady;
RageSound m_soundError; RageSound m_soundError;
+10 -2
View File
@@ -18,6 +18,8 @@
#define CREDITS_CARD_TOO_LATE THEME->GetMetric ("ScreenSystemLayer","CreditsCardTooLate") #define CREDITS_CARD_TOO_LATE THEME->GetMetric ("ScreenSystemLayer","CreditsCardTooLate")
#define CREDITS_CARD_NO_NAME THEME->GetMetric ("ScreenSystemLayer","CreditsCardNoName") #define CREDITS_CARD_NO_NAME THEME->GetMetric ("ScreenSystemLayer","CreditsCardNoName")
#define CREDITS_CARD_READY THEME->GetMetric ("ScreenSystemLayer","CreditsCardReady") #define CREDITS_CARD_READY THEME->GetMetric ("ScreenSystemLayer","CreditsCardReady")
#define CREDITS_CARD_CHECKING THEME->GetMetric ("ScreenSystemLayer","CreditsCardChecking")
#define CREDITS_CARD_REMOVED THEME->GetMetric ("ScreenSystemLayer","CreditsCardRemoved")
#define CREDITS_FREE_PLAY THEME->GetMetric ("ScreenSystemLayer","CreditsFreePlay") #define CREDITS_FREE_PLAY THEME->GetMetric ("ScreenSystemLayer","CreditsFreePlay")
#define CREDITS_CREDITS THEME->GetMetric ("ScreenSystemLayer","CreditsCredits") #define CREDITS_CREDITS THEME->GetMetric ("ScreenSystemLayer","CreditsCredits")
#define CREDITS_NOT_PRESENT THEME->GetMetric ("ScreenSystemLayer","CreditsNotPresent") #define CREDITS_NOT_PRESENT THEME->GetMetric ("ScreenSystemLayer","CreditsNotPresent")
@@ -123,7 +125,7 @@ void ScreenSystemLayer::RefreshCreditsMessages()
bool bShowCreditsMessage; bool bShowCreditsMessage;
if( GAMESTATE->m_bIsOnSystemMenu ) if( GAMESTATE->m_bIsOnSystemMenu )
bShowCreditsMessage = true; bShowCreditsMessage = true;
else if( GAMESTATE->m_bPlayersFinalized ) else if( MEMCARDMAN->GetPlayersFinalized() )
bShowCreditsMessage = !GAMESTATE->IsPlayerEnabled( p ); bShowCreditsMessage = !GAMESTATE->IsPlayerEnabled( p );
else else
bShowCreditsMessage = !GAMESTATE->m_bSideIsJoined[p]; bShowCreditsMessage = !GAMESTATE->m_bSideIsJoined[p];
@@ -154,6 +156,12 @@ void ScreenSystemLayer::RefreshCreditsMessages()
case MEMORY_CARD_STATE_TOO_LATE: case MEMORY_CARD_STATE_TOO_LATE:
sCredits = CREDITS_CARD_TOO_LATE; sCredits = CREDITS_CARD_TOO_LATE;
break; break;
case MEMORY_CARD_STATE_CHECKING:
sCredits = CREDITS_CARD_CHECKING;
break;
case MEMORY_CARD_STATE_REMOVED:
sCredits = CREDITS_CARD_REMOVED;
break;
case MEMORY_CARD_STATE_READY: case MEMORY_CARD_STATE_READY:
if( PROFILEMAN->LastLoadWasFromLastGood(p) && pProfile ) if( PROFILEMAN->LastLoadWasFromLastGood(p) && pProfile )
sCredits = pProfile->GetDisplayName() + CREDITS_LOADED_FROM_LAST_GOOD_APPEND; sCredits = pProfile->GetDisplayName() + CREDITS_LOADED_FROM_LAST_GOOD_APPEND;
@@ -170,7 +178,7 @@ void ScreenSystemLayer::RefreshCreditsMessages()
sCredits = CREDITS_CARD_NO_NAME; sCredits = CREDITS_CARD_NO_NAME;
break; break;
default: default:
ASSERT(0); FAIL_M( ssprintf("%i",mcs) );
} }
} }
else // bShowCreditsMessage else // bShowCreditsMessage