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;
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue