Merge pull request #4893 from wwylele/nfc-state

NFC: extract frontend-facing tag state
This commit is contained in:
James Rowe 2019-09-13 08:59:51 -06:00 committed by GitHub
commit 7bfd829c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 16 deletions

View file

@ -53,7 +53,7 @@ void Module::Interface::Initialize(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (nfc->nfc_tag_state != TagState::NotInitialized) { if (nfc->nfc_tag_state != TagState::NotInitialized) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
return; return;
@ -99,13 +99,14 @@ void Module::Interface::StartTagScanning(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (nfc->nfc_tag_state != TagState::NotScanning && if (nfc->nfc_tag_state != TagState::NotScanning &&
nfc->nfc_tag_state != TagState::TagOutOfRange) { nfc->nfc_tag_state != TagState::TagOutOfRange) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
return; return;
} }
nfc->nfc_tag_state = TagState::Scanning; nfc->nfc_tag_state = TagState::Scanning;
nfc->SyncTagState();
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_NFC, "(STUBBED) called, in_val={:04x}", in_val); LOG_WARNING(Service_NFC, "(STUBBED) called, in_val={:04x}", in_val);
@ -116,7 +117,7 @@ void Module::Interface::GetTagInfo(Kernel::HLERequestContext& ctx) {
if (nfc->nfc_tag_state != TagState::TagInRange && if (nfc->nfc_tag_state != TagState::TagInRange &&
nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) { nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
@ -163,7 +164,7 @@ void Module::Interface::StopTagScanning(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (nfc->nfc_tag_state == TagState::NotInitialized || if (nfc->nfc_tag_state == TagState::NotInitialized ||
nfc->nfc_tag_state == TagState::NotScanning) { nfc->nfc_tag_state == TagState::NotScanning) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
return; return;
@ -192,13 +193,14 @@ void Module::Interface::ResetTagScanState(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) { if (nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
return; return;
} }
nfc->nfc_tag_state = TagState::TagInRange; nfc->nfc_tag_state = TagState::TagInRange;
nfc->SyncTagState();
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
@ -208,7 +210,7 @@ void Module::Interface::GetTagInRangeEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x0B, 0, 0); IPC::RequestParser rp(ctx, 0x0B, 0, 0);
if (nfc->nfc_tag_state != TagState::NotScanning) { if (nfc->nfc_tag_state != TagState::NotScanning) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
@ -225,7 +227,7 @@ void Module::Interface::GetTagOutOfRangeEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x0C, 0, 0); IPC::RequestParser rp(ctx, 0x0C, 0, 0);
if (nfc->nfc_tag_state != TagState::NotScanning) { if (nfc->nfc_tag_state != TagState::NotScanning) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
@ -243,7 +245,7 @@ void Module::Interface::GetTagState(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushEnum(nfc->nfc_tag_state.load()); rb.PushEnum(nfc->nfc_tag_state);
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
} }
@ -261,7 +263,7 @@ void Module::Interface::Unknown0x1A(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (nfc->nfc_tag_state != TagState::TagInRange) { if (nfc->nfc_tag_state != TagState::TagInRange) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
return; return;
@ -277,7 +279,7 @@ void Module::Interface::GetIdentificationBlock(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1B, 0, 0); IPC::RequestParser rp(ctx, 0x1B, 0, 0);
if (nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) { if (nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) {
LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state.load())); LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast<int>(nfc->nfc_tag_state));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
@ -304,15 +306,29 @@ std::shared_ptr<Module> Module::Interface::GetModule() const {
void Module::Interface::LoadAmiibo(const AmiiboData& amiibo_data) { void Module::Interface::LoadAmiibo(const AmiiboData& amiibo_data) {
std::lock_guard lock(HLE::g_hle_lock); std::lock_guard lock(HLE::g_hle_lock);
nfc->amiibo_data = amiibo_data; nfc->amiibo_data = amiibo_data;
nfc->nfc_tag_state = Service::NFC::TagState::TagInRange; nfc->amiibo_in_range = true;
nfc->tag_in_range_event->Signal(); nfc->SyncTagState();
} }
void Module::Interface::RemoveAmiibo() { void Module::Interface::RemoveAmiibo() {
std::lock_guard lock(HLE::g_hle_lock); std::lock_guard lock(HLE::g_hle_lock);
nfc->nfc_tag_state = Service::NFC::TagState::TagOutOfRange; nfc->amiibo_in_range = false;
nfc->tag_out_of_range_event->Signal(); nfc->SyncTagState();
nfc->amiibo_data = {}; }
void Module::SyncTagState() {
if (amiibo_in_range &&
(nfc_tag_state == TagState::TagOutOfRange || nfc_tag_state == TagState::Scanning)) {
// TODO (wwylele): Should TagOutOfRange->TagInRange transition only happen on the same tag
// detected on Scanning->TagInRange?
nfc_tag_state = TagState::TagInRange;
tag_in_range_event->Signal();
} else if (!amiibo_in_range && nfc_tag_state == TagState::TagInRange) {
nfc_tag_state = TagState::TagOutOfRange;
// TODO (wwylele): If a tag is removed during TagDataLoaded/Unknown6, should this event
// signals early?
tag_out_of_range_event->Signal();
}
} }
Module::Interface::Interface(std::shared_ptr<Module> nfc, const char* name, u32 max_session) Module::Interface::Interface(std::shared_ptr<Module> nfc, const char* name, u32 max_session)

View file

@ -231,12 +231,16 @@ public:
}; };
private: private:
// Sync nfc_tag_state with amiibo_in_range and signal events on state change.
void SyncTagState();
std::shared_ptr<Kernel::Event> tag_in_range_event; std::shared_ptr<Kernel::Event> tag_in_range_event;
std::shared_ptr<Kernel::Event> tag_out_of_range_event; std::shared_ptr<Kernel::Event> tag_out_of_range_event;
std::atomic<TagState> nfc_tag_state = TagState::NotInitialized; TagState nfc_tag_state = TagState::NotInitialized;
CommunicationStatus nfc_status = CommunicationStatus::NfcInitialized; CommunicationStatus nfc_status = CommunicationStatus::NfcInitialized;
AmiiboData amiibo_data{}; AmiiboData amiibo_data{};
bool amiibo_in_range = false;
}; };
void InstallInterfaces(Core::System& system); void InstallInterfaces(Core::System& system);