Implement an applet FIFO
This commit is contained in:
parent
653f15af82
commit
67c630c066
5 changed files with 112 additions and 90 deletions
79
Ryujinx.HLE/HOS/Applets/AppletFifo.cs
Normal file
79
Ryujinx.HLE/HOS/Applets/AppletFifo.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,9 +7,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||
{
|
||||
event EventHandler AppletStateChanged;
|
||||
|
||||
ResultCode Start();
|
||||
ResultCode Start(AppletFifo<byte[]> inData, AppletFifo<byte[]> outData);
|
||||
ResultCode GetResult();
|
||||
ResultCode PushInData(IStorage data);
|
||||
ResultCode PopOutData(out IStorage data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
internal class PlayerSelect : IApplet
|
||||
{
|
||||
private Horizon _system;
|
||||
private Queue<IStorage> _inputQueue;
|
||||
private Queue<IStorage> _outputQueue;
|
||||
private Horizon _system;
|
||||
|
||||
private AppletFifo<byte[]> _inputData;
|
||||
private AppletFifo<byte[]> _outputData;
|
||||
|
||||
public event EventHandler AppletStateChanged;
|
||||
|
||||
public PlayerSelect(Horizon system)
|
||||
{
|
||||
_system = system;
|
||||
_inputQueue = new Queue<IStorage>();
|
||||
_outputQueue = new Queue<IStorage>();
|
||||
_system = system;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -35,40 +36,18 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||
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()
|
||||
{
|
||||
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);
|
||||
// UserID Low (long) High (long)
|
||||
|
||||
currentUser.UserId.Write(writer);
|
||||
|
||||
return ms.ToArray();
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,13 +11,19 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
{
|
||||
private IApplet _applet;
|
||||
|
||||
private AppletFifo<byte[]> _inData;
|
||||
private AppletFifo<byte[]> _outData;
|
||||
|
||||
private KEvent _stateChangedEvent;
|
||||
|
||||
public ILibraryAppletAccessor(AppletId appletId, Horizon 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;
|
||||
}
|
||||
|
||||
|
@ -46,7 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// Start()
|
||||
public ResultCode Start(ServiceCtx context)
|
||||
{
|
||||
return (ResultCode)_applet.Start();
|
||||
return (ResultCode)_applet.Start(_inData, _outData);
|
||||
}
|
||||
|
||||
[Command(30)]
|
||||
|
@ -60,7 +66,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// PushInData(object<nn::am::service::IStorage>)
|
||||
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;
|
||||
}
|
||||
|
@ -69,14 +79,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// PopOutData() -> object<nn::am::service::IStorage>
|
||||
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, storage);
|
||||
}
|
||||
MakeObject(context, new IStorage(data));
|
||||
|
||||
return result;
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue