Implement an applet FIFO

This commit is contained in:
jduncanator 2019-11-04 15:16:46 +11:00
commit 67c630c066
5 changed files with 112 additions and 90 deletions

View file

@ -0,0 +1,79 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Applets
{
internal class AppletFifo<T> : IEnumerable<T>
{
private ConcurrentQueue<T> _dataQueue;
public int Count => _dataQueue.Count;
public AppletFifo()
{
_dataQueue = new ConcurrentQueue<T>();
}
public void Push(T item)
{
_dataQueue.Enqueue(item);
}
public T Pop()
{
if (_dataQueue.TryDequeue(out T result))
{
return result;
}
throw new InvalidOperationException("FIFO empty.");
}
public bool TryPop(out T result)
{
return _dataQueue.TryDequeue(out result);
}
public T Peek()
{
if (_dataQueue.TryPeek(out T result))
{
return result;
}
throw new InvalidOperationException("FIFO empty.");
}
public bool TryPeek(out T result)
{
return _dataQueue.TryPeek(out result);
}
public void Clear()
{
_dataQueue.Clear();
}
public T[] ToArray()
{
return _dataQueue.ToArray();
}
public void CopyTo(T[] array, int arrayIndex)
{
_dataQueue.CopyTo(array, arrayIndex);
}
public IEnumerator<T> GetEnumerator()
{
return _dataQueue.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _dataQueue.GetEnumerator();
}
}
}

View file

@ -7,9 +7,7 @@ namespace Ryujinx.HLE.HOS.Applets
{ {
event EventHandler AppletStateChanged; event EventHandler AppletStateChanged;
ResultCode Start(); ResultCode Start(AppletFifo<byte[]> inData, AppletFifo<byte[]> outData);
ResultCode GetResult(); ResultCode GetResult();
ResultCode PushInData(IStorage data);
ResultCode PopOutData(out IStorage data);
} }
} }

View file

@ -1,29 +1,30 @@
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
namespace Ryujinx.HLE.HOS.Applets namespace Ryujinx.HLE.HOS.Applets
{ {
internal class PlayerSelect : IApplet internal class PlayerSelect : IApplet
{ {
private Horizon _system; private Horizon _system;
private Queue<IStorage> _inputQueue;
private Queue<IStorage> _outputQueue; private AppletFifo<byte[]> _inputData;
private AppletFifo<byte[]> _outputData;
public event EventHandler AppletStateChanged; public event EventHandler AppletStateChanged;
public PlayerSelect(Horizon system) public PlayerSelect(Horizon system)
{ {
_system = system; _system = system;
_inputQueue = new Queue<IStorage>();
_outputQueue = new Queue<IStorage>();
} }
public ResultCode Start() public ResultCode Start(AppletFifo<byte[]> inData, AppletFifo<byte[]> outData)
{ {
_outputQueue.Enqueue(new IStorage(BuildResponse())); _inputData = inData;
_outputData = outData;
// TODO(jduncanator): Parse PlayerSelectConfig from input data
_outputData.Push(BuildResponse());
AppletStateChanged?.Invoke(this, null); AppletStateChanged?.Invoke(this, null);
@ -35,40 +36,18 @@ namespace Ryujinx.HLE.HOS.Applets
return ResultCode.Success; return ResultCode.Success;
} }
public ResultCode PushInData(IStorage data)
{
_inputQueue.Enqueue(data);
return ResultCode.Success;
}
public ResultCode PopOutData(out IStorage data)
{
if (_outputQueue.Count > 0)
{
data = _outputQueue.Dequeue();
}
else
{
data = null;
}
return ResultCode.Success;
}
private byte[] BuildResponse() private byte[] BuildResponse()
{ {
UserProfile currentUser = _system.State.Account.LastOpenedUser; UserProfile currentUser = _system.State.Account.LastOpenedUser;
using (MemoryStream ms = new MemoryStream()) using (MemoryStream stream = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{ {
BinaryWriter writer = new BinaryWriter(ms);
writer.Write((ulong)PlayerSelectResult.Success); writer.Write((ulong)PlayerSelectResult.Success);
// UserID Low (long) High (long)
currentUser.UserId.Write(writer); currentUser.UserId.Write(writer);
return ms.ToArray(); return stream.ToArray();
} }
} }
} }

View file

@ -1,41 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using System;
namespace Ryujinx.HLE.HOS.Applets
{
internal class StubApplet : IApplet
{
public event EventHandler AppletStateChanged;
public ResultCode Start()
{
Logger.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
public ResultCode PushInData(IStorage data)
{
Logger.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
public ResultCode PopOutData(out IStorage data)
{
Logger.PrintStub(LogClass.ServiceAm);
data = null;
return ResultCode.Success;
}
public ResultCode GetResult()
{
Logger.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
}
}

View file

@ -11,12 +11,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
{ {
private IApplet _applet; private IApplet _applet;
private AppletFifo<byte[]> _inData;
private AppletFifo<byte[]> _outData;
private KEvent _stateChangedEvent; private KEvent _stateChangedEvent;
public ILibraryAppletAccessor(AppletId appletId, Horizon system) public ILibraryAppletAccessor(AppletId appletId, Horizon system)
{ {
_stateChangedEvent = new KEvent(system); _stateChangedEvent = new KEvent(system);
_applet = AppletManager.Create(appletId, system);
_applet = AppletManager.Create(appletId, system);
_inData = new AppletFifo<byte[]>();
_outData = new AppletFifo<byte[]>();
_applet.AppletStateChanged += OnAppletStateChanged; _applet.AppletStateChanged += OnAppletStateChanged;
} }
@ -46,7 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// Start() // Start()
public ResultCode Start(ServiceCtx context) public ResultCode Start(ServiceCtx context)
{ {
return (ResultCode)_applet.Start(); return (ResultCode)_applet.Start(_inData, _outData);
} }
[Command(30)] [Command(30)]
@ -60,7 +66,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// PushInData(object<nn::am::service::IStorage>) // PushInData(object<nn::am::service::IStorage>)
public ResultCode PushInData(ServiceCtx context) public ResultCode PushInData(ServiceCtx context)
{ {
Logger.PrintStub(LogClass.ServiceAm); var data = GetObject<IStorage>(context, 0);
Logger.PrintWarning(LogClass.ServiceAm, $"PushInData size: {data.Data.Length} bytes");
_inData.Push(data.Data);
return ResultCode.Success; return ResultCode.Success;
} }
@ -69,14 +79,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// PopOutData() -> object<nn::am::service::IStorage> // PopOutData() -> object<nn::am::service::IStorage>
public ResultCode PopOutData(ServiceCtx context) public ResultCode PopOutData(ServiceCtx context)
{ {
ResultCode result = (ResultCode)_applet.PopOutData(out IStorage storage); byte[] data = _outData.Pop();
if (result == ResultCode.Success && storage != null) MakeObject(context, new IStorage(data));
{
MakeObject(context, storage);
}
return result; return ResultCode.Success;
} }
} }
} }