Skip to content

Commit

Permalink
Merge pull request #5 from i-am-shodan/feature/fixesForRm2
Browse files Browse the repository at this point in the history
Enable display updates on RM2 devices
  • Loading branch information
parzivail authored Jul 31, 2021
2 parents 713bf39 + 91f0856 commit e69e0dc
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 38 deletions.
118 changes: 118 additions & 0 deletions ReMarkable.NET/Unix/Driver/Display/RM2ShimDisplayDriver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using ReMarkable.NET.Unix.Driver.Display.EinkController;
using ReMarkable.NET.Unix.Driver.Display.Framebuffer;
using ReMarkable.NET.Unix.Stream;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace ReMarkable.NET.Unix.Driver.Display
{
/// <summary>
/// Provides methods for interacting with the rm2fb client used on a rm2 device
/// </summary>
public sealed class RM2ShimDisplayDriver : IDisposable, IDisplayDriver
{
// Because of the way dotnet works we need to manually invoke functions normally hooked by rm2fb

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("librm2fb_client.so.1.0.1", EntryPoint = "close", SetLastError = true)]
private static extern int Close(IntPtr handle);

[DllImport("librm2fb_client.so.1.0.1", EntryPoint = "open", SetLastError = false)]
[SuppressMessage("Globalization", "CA2101:Specify marshaling for P/Invoke string arguments", Justification =
"Specifying a marshaling breaks rM compatability")]
private static extern SafeUnixHandle Open(string path, uint flags, UnixFileMode mode);

[DllImport("librm2fb_client.so.1.0.1", EntryPoint = "ioctl", SetLastError = false)]
public static extern int Ioctl(SafeHandle handle, IoctlDisplayCommand code, ref FbUpdateData data);

/// <summary>
/// The device handle through which IOCTL commands can be issued
/// </summary>
private readonly SafeUnixHandle _handle;

/// <inheritdoc />
public IFramebuffer Framebuffer { get; }

/// <inheritdoc />
public int VirtualHeight { get; }

/// <inheritdoc />
public int VirtualWidth { get; }

/// <inheritdoc />
public int VisibleHeight { get; }

/// <inheritdoc />
public int VisibleWidth { get; }

/// <summary>
/// Creates a new <see cref="RM2ShimDisplayDriver" />
/// </summary>
/// <param name="devicePath">The device handle location</param>
public RM2ShimDisplayDriver()
{
var devicePath = "/dev/fb0";

_handle = Open(devicePath, 0, UnixFileMode.WriteOnly);

VisibleWidth = 1404;
VisibleHeight = 1872;
VirtualWidth = 1404;
VirtualHeight = 1872;
Framebuffer = new HardwareFramebuffer(devicePath, VisibleWidth, VisibleHeight, VirtualWidth, VirtualHeight);
}

/// <inheritdoc />
public void Dispose()
{
_handle?.Dispose();
((HardwareFramebuffer)Framebuffer)?.Dispose();
}

/// <inheritdoc />
public void Draw(Image<Rgb24> image, Rectangle srcArea, Point destPoint, Rectangle refreshArea = default,
WaveformMode waveformMode = WaveformMode.Auto, DisplayTemp displayTemp = DisplayTemp.Papyrus, UpdateMode updateMode = UpdateMode.Partial)
{
Framebuffer.Write(image, srcArea, destPoint);

if (refreshArea == default)
{
refreshArea.Location = destPoint;
refreshArea.Size = srcArea.Size;
}

Refresh(refreshArea, waveformMode, displayTemp, updateMode);
}

/// <inheritdoc />
public void Refresh(Rectangle rectangle, WaveformMode mode, DisplayTemp displayTemp, UpdateMode updateMode)
{
Framebuffer.ConstrainRectangle(ref rectangle);
var data = new FbUpdateData
{
UpdateRegion = new FbRect
{
X = (uint)rectangle.X,
Y = (uint)rectangle.Y,
Width = (uint)rectangle.Width,
Height = (uint)rectangle.Height
},
WaveformMode = mode,
DisplayTemp = displayTemp,
UpdateMode = updateMode,
UpdateMarker = 0,
DitherMode = 0,
QuantBit = 0,
Flags = 0
};

var retCode = Ioctl(_handle, IoctlDisplayCommand.SendUpdate, ref data);
if (retCode == -1)
throw new UnixException();
}
}
}
50 changes: 24 additions & 26 deletions ReMarkable.NET/Unix/Driver/InputDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,31 @@ public static class InputDevices
/// </summary>
static InputDevices()
{
#if DEBUG
// Load emulated input devices
var deviceContainer = Type.GetType("RmEmulator.EmulatedDevices, RmEmulator");
if (deviceContainer != null)
switch (DeviceType.GetDevice())
{
deviceContainer.ReadStaticField("PhysicalButtons", out PhysicalButtons);
deviceContainer.ReadStaticField("Touchscreen", out Touchscreen);
deviceContainer.ReadStaticField("Digitizer", out Digitizer);

return;
}
#endif
// Load hardware input devices
var deviceMap = DeviceUtils.GetInputDeviceEventHandlers();

if (deviceMap.ContainsKey("30370000.snvs:snvs-powerkey"))
{
// rM2
PhysicalButtons = new HardwarePhysicalButtonDriver(deviceMap["30370000.snvs:snvs-powerkey"]);
Touchscreen = new HardwareTouchscreenDriver(deviceMap["cyttsp5_mt"], 767, 1023, 32);
Digitizer = new HardwareDigitizerDriver(deviceMap["Wacom I2C Digitizer"], 20967, 15725);
}
else
{
PhysicalButtons = new HardwarePhysicalButtonDriver(deviceMap["gpio-keys"]);
Touchscreen = new HardwareTouchscreenDriver(deviceMap["cyttsp5_mt"], 767, 1023, 32);
Digitizer = new HardwareDigitizerDriver(deviceMap["Wacom I2C Digitizer"], 20967, 15725);
case Device.Emulator:
// Load emulated input devices
var deviceContainer = Type.GetType("RmEmulator.EmulatedDevices, RmEmulator");
if (deviceContainer != null)
{
deviceContainer.ReadStaticField("PhysicalButtons", out PhysicalButtons);
deviceContainer.ReadStaticField("Touchscreen", out Touchscreen);
deviceContainer.ReadStaticField("Digitizer", out Digitizer);
}
break;
case Device.RM1:
var rm1DeviceMap = DeviceUtils.GetInputDeviceEventHandlers();
PhysicalButtons = new HardwarePhysicalButtonDriver(rm1DeviceMap["gpio-keys"]);
Touchscreen = new HardwareTouchscreenDriver(rm1DeviceMap["cyttsp5_mt"], 767, 1023, 32);
Digitizer = new HardwareDigitizerDriver(rm1DeviceMap["Wacom I2C Digitizer"], 20967, 15725);
break;
case Device.RM2:
// rM2
var rm2DeviceMap = DeviceUtils.GetInputDeviceEventHandlers();
PhysicalButtons = new HardwarePhysicalButtonDriver(rm2DeviceMap["30370000.snvs:snvs-powerkey"]);
Touchscreen = new HardwareTouchscreenDriver(rm2DeviceMap["pt_mt"], 1403, 1871, 32, false);
Digitizer = new HardwareDigitizerDriver(rm2DeviceMap["Wacom I2C Digitizer"], 20967, 15725);
break;
}
}
}
Expand Down
27 changes: 17 additions & 10 deletions ReMarkable.NET/Unix/Driver/OutputDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,25 @@ public static class OutputDevices
/// </summary>
static OutputDevices()
{
#if DEBUG
// Load emulated input devices
var deviceContainer = Type.GetType("RmEmulator.EmulatedDevices, RmEmulator");
if (deviceContainer != null)
switch (DeviceType.GetDevice())
{
deviceContainer.ReadStaticField("Display", out Display);

return;
case Device.Emulator:
// Load emulated input devices
var deviceContainer = Type.GetType("RmEmulator.EmulatedDevices, RmEmulator");
if (deviceContainer != null)
{
deviceContainer.ReadStaticField("Display", out Display);
}
break;
case Device.RM1:
// Load hardware output devices
Display = new HardwareDisplayDriver("/dev/fb0");
break;
case Device.RM2:
// Load hardware output devices
Display = new RM2ShimDisplayDriver();
break;
}
#endif
// Load hardware output devices
Display = new HardwareDisplayDriver("/dev/fb0");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ public sealed class HardwareTouchscreenDriver : UnixInputDriver, ITouchscreenDri
/// <inheritdoc />
public int Width { get; }

public HardwareTouchscreenDriver(string devicePath, int width, int height, int maxFingers) : base(devicePath)
/// <summary>
/// Whether the width value should be left or right biased
/// </summary>
private readonly bool invertWidth;

public HardwareTouchscreenDriver(string devicePath, int width, int height, int maxFingers, bool shouldInvertWidth = true) : base(devicePath)
{
Width = width;
Height = height;
MaxFingers = maxFingers;
Fingers = new FingerState[maxFingers];
invertWidth = shouldInvertWidth;
}

/// <inheritdoc />
Expand Down Expand Up @@ -121,7 +127,7 @@ private void ProcessAbsoluteTouch(TouchscreenEventAbsCode code, int value)
Fingers[_slot].PreviousDevicePosition.X = Fingers[_slot].DevicePosition.X;
Fingers[_slot].PreviousRawPosition.X = Fingers[_slot].RawPosition.X;

float pos = Width - 1 - value;
float pos = invertWidth ? Width - 1 - value : value;
_position.X = (int)(pos / Width * OutputDevices.Display.VisibleWidth);

Fingers[_slot].DevicePosition.X = _position.X;
Expand Down
61 changes: 61 additions & 0 deletions ReMarkable.NET/Util/DeviceType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using ReMarkable.NET.Unix.Driver;
using System.Runtime.InteropServices;

namespace ReMarkable.NET.Util
{
/// <summary>
/// Possible Remarkable or emulated device types
/// </summary>
public enum Device
{
Emulator,
RM1,
RM2
}

public class DeviceType
{
private static Device ?result = null;

/// <summary>
/// Gets the device that in currently in use
/// </summary>
/// <returns>DeviceType</returns>
public static Device GetDevice()
{
if (result != null)
{
return result.Value;
}

var ret = Device.Emulator;

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
ret = Device.Emulator;
}
else
{
try
{
var deviceMap = DeviceUtils.GetInputDeviceEventHandlers();

if (deviceMap.ContainsKey("30370000.snvs:snvs-powerkey")) // rm2 has a power button
{
ret = Device.RM2;
}
else if (deviceMap.ContainsKey("cyttsp5_mt")) // rm1 touch screen driver
{
ret = Device.RM1;
}
}
catch
{
}
}

result = ret;
return ret;
}
}
}

0 comments on commit e69e0dc

Please sign in to comment.