Skip to content

Commit

Permalink
Merge develop
Browse files Browse the repository at this point in the history
  • Loading branch information
twostarsmco committed Feb 5, 2020
2 parents 41e2e19 + 4838821 commit 31f5ade
Show file tree
Hide file tree
Showing 23 changed files with 317 additions and 69 deletions.
13 changes: 13 additions & 0 deletions Common/Command/CommandBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;

namespace Command
{
/// <summary>
/// A common abstract class for each commands in macro.
/// </summary>
[JsonConverter(typeof(Converter.CommandBaseConverter))]
public abstract class CommandBase
{
public override abstract string ToString();
}
}
70 changes: 70 additions & 0 deletions Common/Command/Converter/CommandBaseConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Command.Converter
{
public class CommandBaseConverter : JsonConverter
{

public override bool CanConvert(Type objectType)
{
return objectType == typeof(Command.CommandBase);
}


/// <summary>
/// This class is write-only.
/// </summary>
public override bool CanWrite => false;

/// <summary>
/// Throws NotImplementedException. This class is read-only.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("This class is read-only.");
}


/// <summary>
/// Deserialize JSON object as child class of CommandBase.
/// This method first scans "CommandType" property of given JSON object,
/// then calls ReadJson method on appropriate Converter class corresponding to "CommandType".
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jobject = JObject.Load(reader);

JsonConverter converter;
switch ((string)jobject["CommandType"])
{
case "Wait":
converter = new WaitConverter();
break;

case "Button":
converter = new OperateButtonConverter();
break;

case "Stick":
converter = new OperateStickConverter();
break;

default:
throw new JsonReaderException("Invalid CommandType specified");
}
var newReader = jobject.CreateReader(); //As JsonReader cannot be used twice, create new one and pass it.
return converter.ReadJson(newReader, objectType, existingValue, serializer);
}

}
}
56 changes: 56 additions & 0 deletions Common/Command/Converter/OperateButtonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;


namespace Command.Converter
{
public class OperateButtonConverter : JsonConverter
{

public override bool CanConvert(Type objectType)
{
return objectType == typeof(OperateButton);
}


/// <summary>
/// This class is write-only.
/// </summary>
public override bool CanRead => false;


/// <summary>
/// Throws NotImplementedException. This class is write-only.
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jobject = JObject.Load(reader);
return new OperateButton(
(ButtonID)Enum.Parse(typeof(ButtonID), (string)jobject["ButtonID"], ignoreCase: true),
(ButtonState)(byte)jobject["TargetState"]);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var operation = (OperateButton)value;
if (operation == null) throw new ArgumentException("value is not OperateButton", "value");

writer.WriteStartObject();
writer.WritePropertyName("CommandType");
writer.WriteValue("Button");
writer.WritePropertyName("ButtonID");
writer.WriteValue(operation.ButtonID.ToString());
writer.WritePropertyName("TargetState");
writer.WriteValue(operation.TargetState);
writer.WriteEndObject();
}


}
}
42 changes: 42 additions & 0 deletions Common/Command/Converter/OperateStickConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Command.Converter
{
public class OperateStickConverter : JsonConverter
{

public override bool CanConvert(Type objectType)
{
return objectType == typeof(Command.OperateStick);
}


public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jobject = JObject.Load(reader);
return new OperateStick(
(StickID)Enum.Parse(typeof(StickID), (string)jobject["StickID"], ignoreCase: true),
(byte)jobject["X"], (byte)jobject["Y"]);
}


public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var operation = (Command.OperateStick)value;
if (operation == null) throw new ArgumentException("value is not OperateButton", "value");

writer.WriteStartObject();
writer.WritePropertyName("CommandType");
writer.WriteValue("Stick");
writer.WritePropertyName("StickID");
writer.WriteValue(operation.StickID.ToString());
writer.WritePropertyName("X");
writer.WriteValue(operation.TargetXAngle);
writer.WritePropertyName("Y");
writer.WriteValue(operation.TargetYAngle);
writer.WriteEndObject();
}
}
}
36 changes: 36 additions & 0 deletions Common/Command/Converter/WaitConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Command.Converter
{
public class WaitConverter : JsonConverter
{

public override bool CanConvert(Type objectType)
{
return objectType == typeof(Command.Wait);
}


public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jobject = JObject.Load(reader);
return new Wait((int)jobject["WaitTime"]);
}


public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var operation = (Command.Wait)value;
if (operation == null) throw new ArgumentException("value is not OperateButton", "value");

writer.WriteStartObject();
writer.WritePropertyName("CommandType");
writer.WriteValue("Wait");
writer.WritePropertyName("WaitTime");
writer.WriteValue(operation.WaitTime);
writer.WriteEndObject();
}
}
}
27 changes: 0 additions & 27 deletions Common/Command/JsonConverters.cs

This file was deleted.

56 changes: 45 additions & 11 deletions Common/Command/Macro.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,35 @@ public class Macro //: ICommand
/// <summary>
/// A sequence of ICommand this instance represents.
/// </summary>
public IReadOnlyList<ICommand> Commands;
public IReadOnlyList<CommandBase> Commands;


/// <summary>
///
/// </summary>
/// <param name="commands">A sequence of ICommand to execute.</param>
public Macro(IList<ICommand> commands)//, string location)
public Macro(IList<CommandBase> commands)//, string location)
{
this.Commands = commands.ToArray() ?? new ICommand[] { };
this.Commands = commands.ToArray() ?? new CommandBase[] { };
}


/// <summary>
/// The title of this macro. Give it a good name.
/// </summary>
public string Title { get; set; } = "";


/// <summary>
/// The description of this macro.
/// Write usage, prerequisite, cautions etc. here.
/// </summary>
public string Description { get; set; }
public string Description { get; set; } = "";

//TODO: implement macro that calls another macro
public IList<ICommand> Flatten()
public IList<CommandBase> Flatten()
{
List<ICommand> commandsFlat = new List<ICommand>();
List<CommandBase> commandsFlat = new List<CommandBase>();
foreach (var command in this.Commands)
{
commandsFlat.Add(command);
Expand All @@ -50,18 +56,46 @@ public override string ToString()
return string.Join("\r\n", this.Commands.Select(command => command.ToString()));
}


/// <summary>
/// Generates JSON string from this instance.
/// </summary>
/// <param name="settings">Specifies the way JSON string is structured.
/// If not specified, default setting is used.
/// Beware that some non-default setting may generate incompatible JSON string.
/// Refer to docs of Newtonsoft.Json.JsonSerializerSettings for details.
/// </param>
/// <returns></returns>
public string ToJSON(JsonSerializerSettings settings = null)
{
settings = settings ?? new JsonSerializerSettings() { Formatting = Formatting.Indented };
settings = settings ?? new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
MissingMemberHandling = MissingMemberHandling.Ignore,
TypeNameHandling = TypeNameHandling.None
};

settings.TypeNameHandling = TypeNameHandling.Auto;
return JsonConvert.SerializeObject(this, settings);
}

public static Macro FromJSON(string json)

/// <summary>
/// Create an instance of this class from given JSON string.
/// </summary>
/// <param name="json">A JSON string to generate from.</param>
/// <param name="settings">Specifies the way JSON string is deserialized.
/// If not specified, default setting is used.
/// Beware that some non-default setting may generate incompatible JSON string.
/// Refer to docs of Newtonsoft.Json.JsonSerializerSettings for details.</param>
/// <returns></returns>
public static Macro FromJSON(string json, JsonSerializerSettings settings = null)
{
return JsonConvert.DeserializeObject<Macro>(
json, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
settings = settings ?? new JsonSerializerSettings()
{
MissingMemberHandling = MissingMemberHandling.Ignore,
TypeNameHandling = TypeNameHandling.None
};
return JsonConvert.DeserializeObject<Macro>(json, settings);
}
}
}
3 changes: 3 additions & 0 deletions Common/Command/OperateButton.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using Newtonsoft.Json;

using Command.Converter;

namespace Command
{
/// <summary>
/// A class that represents an operation of pressing, or releasing a button.
/// </summary>
[JsonConverter(typeof(OperateButtonConverter))]
public class OperateButton : OperateCommandBase
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion Common/Command/OperateCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Command
/// An abstract class that represents an operation
/// that involves sending array of bytes to Arduino.
/// </summary>
public abstract class OperateCommandBase: ICommand
public abstract class OperateCommandBase: CommandBase
{
public byte TargetControlID { get; private set; }

Expand Down
1 change: 1 addition & 0 deletions Common/Command/OperateStick.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Command
{
[JsonConverter(typeof(Converter.OperateStickConverter))]
public class OperateStick : OperateCommandBase
{
private byte[] commandBytes;
Expand Down
7 changes: 5 additions & 2 deletions Common/Command/Wait.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Command
using Newtonsoft.Json;

namespace Command
{
/// <summary>
/// A command that halts the execution of following command
/// for specified duration of time.
/// </summary>
public class Wait : ICommand
[JsonConverter(typeof(Converter.WaitConverter))]
public class Wait : CommandBase
{
/// <summary>
/// The number of milliseconds to wait
Expand Down

0 comments on commit 31f5ade

Please sign in to comment.