├── assets
├── wechat_qrcode.png
└── paypal_button.svg
├── demo
├── Sandwych.SmartConfig.AndroidDemoApp
│ ├── Resources
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── menu
│ │ │ └── menu_main.xml
│ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ ├── device_list_row.xml
│ │ │ └── content_main.xml
│ │ └── AboutResources.txt
│ ├── DeviceListViewHolder.cs
│ ├── Properties
│ │ ├── AndroidManifest.xml
│ │ └── AssemblyInfo.cs
│ ├── Assets
│ │ └── AboutAssets.txt
│ ├── DeviceListViewAdapter.cs
│ ├── MainActivity.cs
│ └── Sandwych.SmartConfig.AndroidDemoApp.csproj
└── Sandwych.SmartConfig.CliDemoApp
│ ├── Sandwych.SmartConfig.CliDemoApp.csproj
│ └── Program.cs
├── src
└── Sandwych.SmartConfig
│ ├── Sandwych.SmartConfig.csproj
│ ├── Esptouch
│ ├── EspOptionNames.cs
│ ├── EspWellKnownConstants.cs
│ ├── Protocol
│ │ ├── EspDevicePacketInterpreter.cs
│ │ ├── EspProcedureEncoder.cs
│ │ └── EspDatumFrameEncoder.cs
│ └── EspSmartConfigProvider.cs
│ ├── SmartConfigTimerEventHandler.cs
│ ├── Constants.cs
│ ├── ISmartConfigContextFactory.cs
│ ├── Protocol
│ ├── IProcedureEncoder.cs
│ ├── IDevicePacketInterpreter.cs
│ ├── FrameDataConverter.cs
│ └── Segment.cs
│ ├── ISmartConfigDevice.cs
│ ├── Airkiss
│ ├── AirkissOptionNames.cs
│ ├── AirkissWellknownConstants.cs
│ ├── Protocol
│ │ ├── AirkissPrefixCodeFrameEncoder.cs
│ │ ├── AirkissSeqEntryFrameEncoder.cs
│ │ ├── AirkissDevicePacketInterpreter.cs
│ │ ├── AirkissMagicCodeFrameEncoder.cs
│ │ └── AirkissProcedureEncoder.cs
│ └── AirkissSmartConfigProvider.cs
│ ├── DeviceDiscoveredEventArgs.cs
│ ├── ISmartConfigProvider.cs
│ ├── Networking
│ ├── IDatagramBroadcaster.cs
│ ├── IDatagramReceiver.cs
│ ├── IDatagramClient.cs
│ ├── DatagramReceiveResult.cs
│ ├── DefaultDatagramClient.cs
│ ├── DatagramReceiver.cs
│ └── DatagramBroadcaster.cs
│ ├── Util
│ ├── BytesHelper.cs
│ ├── LinqExtensions.cs
│ ├── TaskExtensions.cs
│ ├── AsyncExtensions.cs
│ └── Crc.cs
│ ├── ISmartConfigJob.cs
│ ├── SmartConfigExtensions.cs
│ ├── StandardOptionNames.cs
│ ├── SmartConfigArguments.cs
│ ├── SmartConfigDevice.cs
│ ├── SmartConfigTimerEventArgs.cs
│ ├── AbstractSmartConfigProvider.cs
│ ├── SmartConfigContext.cs
│ ├── Directory.Build.props
│ ├── SmartConfigStarter.cs
│ └── SmartConfigJob.cs
├── NuGet.config
├── test
└── Sandwych.SmartConfig.Test
│ ├── Util
│ ├── LinqExtensions.cs
│ ├── BytesHelperTests.cs
│ └── Crc8Tests.cs
│ ├── Sandwych.SmartConfig.Test.csproj
│ ├── Airkiss
│ └── Protocol
│ │ ├── AirkissPrefixCodeFrameEncoderTests.cs
│ │ ├── AirkissMagicCodeFrameEncoderTests.cs
│ │ ├── AirkissDevicePacketInterpreterTests.cs
│ │ ├── AirkissSeqEntryFrameEncoderTests.cs
│ │ └── AirkissProcedureEncoderTests.cs
│ └── Esptouch
│ └── Protocol
│ ├── EspDatumFrameEncoderTests.cs
│ └── EspProcedureEncoderTests.cs
├── LICENSE.md
├── Common.props
├── appveyor.yml
├── Sandwych.SmartConfig.sln
├── Sandwych.SmartConfig.Demo.sln
├── README.zh_cn.md
├── README.md
├── .gitignore
└── .editorconfig
/assets/wechat_qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/assets/wechat_qrcode.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2C3E50
4 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Sandwych.SmartConfig.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WiFi SmartConfig Demo App
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Esptouch/EspOptionNames.cs:
--------------------------------------------------------------------------------
1 | namespace Sandwych.SmartConfig.Esptouch
2 | {
3 | public static class EspOptionNames
4 | {
5 | public const string DatumPeriodTimeout = "esp.datum_period";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldrev/sandwych-smartconfig/HEAD/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigTimerEventHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Sandwych.SmartConfig
6 | {
7 | public delegate void SmartConfigTimerEventHandler(object sender, SmartConfigTimerEventArgs e);
8 | }
9 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2c3e50
4 | #1B3147
5 | #3498db
6 |
7 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Constants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Sandwych.SmartConfig
6 | {
7 | internal class Constants
8 | {
9 | public static readonly byte[] EmptyBuffer = new byte[] { };
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/ISmartConfigContextFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Sandwych.SmartConfig
6 | {
7 | public interface ISmartConfigContextFactory
8 | {
9 | SmartConfigContext CreateContext();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Protocol/IProcedureEncoder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Sandwych.SmartConfig.Protocol
4 | {
5 | public interface IProcedureEncoder
6 | {
7 | IEnumerable Encode(SmartConfigContext context, SmartConfigArguments args);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/ISmartConfigDevice.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Net.NetworkInformation;
3 |
4 | namespace Sandwych.SmartConfig
5 | {
6 | public interface ISmartConfigDevice
7 | {
8 | PhysicalAddress MacAddress { get; }
9 | IPAddress IPAddress { get; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/AirkissOptionNames.cs:
--------------------------------------------------------------------------------
1 | namespace Sandwych.SmartConfig.Airkiss
2 | {
3 | public static class AirkissOptionNames
4 | {
5 | public const string RandomNumber = "airkiss.random";
6 | public const string PrefixCodeTimeout = "airkiss.prefix_timeout";
7 | public const string MagicCodeTimeout = "airkiss.magic_timeout";
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/DeviceDiscoveredEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Sandwych.SmartConfig
4 | {
5 | public class DeviceDiscoveredEventArgs : EventArgs
6 | {
7 | public DeviceDiscoveredEventArgs(ISmartConfigDevice device)
8 | {
9 | this.Device = device;
10 | }
11 |
12 | public ISmartConfigDevice Device { get; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/ISmartConfigProvider.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 |
3 | namespace Sandwych.SmartConfig
4 | {
5 | public interface ISmartConfigProvider : ISmartConfigContextFactory
6 | {
7 | string Name { get; }
8 |
9 | IProcedureEncoder CreateProcedureEncoder();
10 |
11 | IDevicePacketInterpreter CreateDevicePacketInterpreter();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/AirkissWellknownConstants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Sandwych.SmartConfig.Airkiss
6 | {
7 | public class AirkissWellknownConstants
8 | {
9 | public static IReadOnlyList GuideCodes { get; } = new ushort[] { 1, 2, 3, 4 };
10 | public const int DevicePacketLength = 7;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Networking/IDatagramBroadcaster.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace Sandwych.SmartConfig.Networking
6 | {
7 | public interface IDatagramBroadcaster : IDisposable
8 | {
9 | Task BroadcastAsync(
10 | SmartConfigContext context, SmartConfigArguments args, CancellationToken cancelToken);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Networking/IDatagramReceiver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace Sandwych.SmartConfig.Networking
7 | {
8 | public interface IDatagramReceiver : IDisposable
9 | {
10 | Task ListenAsync(
11 | SmartConfigContext context, IPAddress localAddress, CancellationToken cancelToken);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Util/BytesHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Sandwych.SmartConfig.Util
2 | {
3 | public static class BytesHelper
4 | {
5 | public static ushort CombineUshort(byte high4bit, byte low4bit) =>
6 | (ushort)(((high4bit << 4) & 0xF0) | (low4bit & 0x0F));
7 |
8 | public static (byte high, byte low) Bisect(this byte b) =>
9 | ((byte)(b >> 4), (byte)(b & 0x0F));
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Protocol/IDevicePacketInterpreter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.NetworkInformation;
4 | using System.Text;
5 |
6 | namespace Sandwych.SmartConfig.Protocol
7 | {
8 | public interface IDevicePacketInterpreter
9 | {
10 | bool Validate(SmartConfigContext context, byte[] packet);
11 |
12 | PhysicalAddress ParseMacAddress(byte[] packet);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.CliDemoApp/Sandwych.SmartConfig.CliDemoApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 | sccli
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/ISmartConfigJob.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace Sandwych.SmartConfig
6 | {
7 | public interface ISmartConfigJob : IDisposable
8 | {
9 | TimeSpan Timeout { get; }
10 |
11 | Task ExecuteAsync(SmartConfigContext context,
12 | SmartConfigArguments args,
13 | CancellationToken cancelToken);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Networking/IDatagramClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Sandwych.SmartConfig.Networking
8 | {
9 | public interface IDatagramClient : IDisposable
10 | {
11 | void Bind(IPEndPoint localEndPoint);
12 | Task SendAsync(byte[] datagram, int bytes, IPEndPoint target);
13 |
14 | Task ReceiveAsync();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Esptouch/EspWellKnownConstants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Sandwych.SmartConfig.Esptouch
5 | {
6 | public static class EspWellKnownConstants
7 | {
8 |
9 | public static IReadOnlyList GuideCodes { get; } = new ushort[] { 515, 514, 513, 512 };
10 |
11 | public const String EspTouchVersion = "v0.3.7.2";
12 |
13 | public const byte EspDevicePacketMagic = 0x18;
14 | public const int EspDevicePacketLength = 11;
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Sandwych.SmartConfig
8 | {
9 | public static class SmartConfigExtensions
10 | {
11 | public static async Task ExecuteAsync(
12 | this ISmartConfigJob self, SmartConfigContext context, SmartConfigArguments args)
13 | {
14 | await self.ExecuteAsync(context, args, CancellationToken.None);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/StandardOptionNames.cs:
--------------------------------------------------------------------------------
1 | namespace Sandwych.SmartConfig
2 | {
3 | public static class StandardOptionNames
4 | {
5 | public const string BroadcastingTargetPort = "std.btp";
6 | public const string ListeningPort = "std.lp";
7 | public const string EncryptionKey = "std.enc_key";
8 |
9 | public const string FrameInterval = "std.frame_interval";
10 | public const string SegmentInterval = "std.segment_interval";
11 | public const string GuideCodeTimeout = "std.guide_period";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Util/LinqExtensions.cs:
--------------------------------------------------------------------------------
1 | //https://stackoverflow.com/questions/438188/split-a-collection-into-n-parts-with-linq
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Sandwych.SmartConfig.Util
6 | {
7 | public static class LinqExtensions
8 | {
9 | public static IEnumerable> Partition(
10 | this IEnumerable source, int partitionSize)
11 | {
12 | int i = 0;
13 | return source.GroupBy(x => i++ / partitionSize);
14 | }
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Networking/DatagramReceiveResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Text;
5 |
6 | namespace Sandwych.SmartConfig.Networking
7 | {
8 | public struct DatagramReceiveResult
9 | {
10 | public byte[] Buffer { get; }
11 | public IPEndPoint RemoteEndPoint { get; }
12 |
13 | public DatagramReceiveResult(byte[] buffer, IPEndPoint remote)
14 | {
15 | this.Buffer = buffer;
16 | this.RemoteEndPoint = remote;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigArguments.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Net.NetworkInformation;
5 | using System.Text;
6 |
7 | namespace Sandwych.SmartConfig
8 | {
9 | public class SmartConfigArguments
10 | {
11 | public string Password { get; set; } = string.Empty;
12 | public string Ssid { get; set; }
13 | public PhysicalAddress Bssid { get; set; }
14 | public IPAddress LocalAddress { get; set; }
15 | public bool? IsHiddenSsid { get; set; } = null;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigDevice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Net.NetworkInformation;
5 | using System.Text;
6 |
7 | namespace Sandwych.SmartConfig
8 | {
9 | public class SmartConfigDevice : ISmartConfigDevice
10 | {
11 | public PhysicalAddress MacAddress { get; }
12 | public IPAddress IPAddress { get; }
13 |
14 | public SmartConfigDevice(PhysicalAddress mac, IPAddress ip)
15 | {
16 | this.MacAddress = mac;
17 | this.IPAddress = ip;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/DeviceListViewHolder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Android.App;
7 | using Android.Content;
8 | using Android.OS;
9 | using Android.Runtime;
10 | using Android.Views;
11 | using Android.Widget;
12 |
13 | namespace Sandwych.SmartConfig.AndroidDemoApp
14 | {
15 | public class DeviceListViewHolder
16 | {
17 | public ImageView Image { get; set; }
18 | public TextView IPAddressView { get; set; }
19 | public TextView MacAddressView { get; set; }
20 |
21 | }
22 | }
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigTimerEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Sandwych.SmartConfig
6 | {
7 | public class SmartConfigTimerEventArgs : EventArgs
8 | {
9 | public TimeSpan Timeout { get; }
10 | public TimeSpan ExecutedTime { get; }
11 | public TimeSpan LeftTime => Timeout - ExecutedTime;
12 |
13 | public SmartConfigTimerEventArgs (TimeSpan timeout, TimeSpan elapsed)
14 | {
15 | this.Timeout = timeout;
16 | this.ExecutedTime = elapsed;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Util/LinqExtensions.cs:
--------------------------------------------------------------------------------
1 | //https://stackoverflow.com/questions/438188/split-a-collection-into-n-parts-with-linq
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace Sandwych.SmartConfig.Test.Util
8 | {
9 | public static class LinqExtensions
10 | {
11 | public static IEnumerable> Partition(
12 | this IEnumerable source, int partitionSize)
13 | {
14 | int i = 0;
15 | return source.GroupBy(x => i++ / partitionSize);
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Protocol/FrameDataConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Sandwych.Esptouch.Protocol
5 | {
6 | public static class FrameDataConverter
7 | {
8 |
9 | public static IReadOnlyList ValueToFilledByteArray(int value)
10 | {
11 | if (value > 0x1FF || value < 0)
12 | {
13 | throw new ArgumentOutOfRangeException(nameof(value));
14 | }
15 |
16 | var result = new List(value);
17 | for (int i = 0; i < value; i++)
18 | {
19 | result[i] = (byte)'1';
20 | }
21 | return result;
22 | }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Assets/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories) and given a Build Action of "AndroidAsset".
3 |
4 | These files will be deployed with your package and will be accessible using Android's
5 | AssetManager, like this:
6 |
7 | public class ReadAsset : Activity
8 | {
9 | protected override void OnCreate (Bundle bundle)
10 | {
11 | base.OnCreate (bundle);
12 |
13 | InputStream input = Assets.Open ("my_asset.txt");
14 | }
15 | }
16 |
17 | Additionally, some Android functions will automatically load asset files:
18 |
19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Util/BytesHelperTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Sandwych.SmartConfig.Util;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace Sandwych.SmartConfig.Test.Util
8 | {
9 | public class BytesHelperTests
10 | {
11 | [Test]
12 | public void CombineUshortShouldWorks()
13 | {
14 | Assert.AreEqual((ushort)0x43, BytesHelper.CombineUshort(0x4, 0x3));
15 | }
16 |
17 | [Test]
18 | public void BisectUshortShouldWorks()
19 | {
20 | Assert.AreEqual(0x9, BytesHelper.Bisect(0x98).high);
21 | Assert.AreEqual(0x8, BytesHelper.Bisect(0x98).low);
22 | Assert.AreEqual(0x3, BytesHelper.Bisect(0x43).low);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Sandwych.SmartConfig.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Esptouch/Protocol/EspDevicePacketInterpreter.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.NetworkInformation;
6 | using System.Text;
7 |
8 | namespace Sandwych.SmartConfig.Esptouch.Protocol
9 | {
10 | public sealed class EspDevicePacketInterpreter : IDevicePacketInterpreter
11 | {
12 | public PhysicalAddress ParseMacAddress(byte[] packet)
13 | {
14 | var macSpan = new ArraySegment(packet, 1, 6);
15 | return new PhysicalAddress(macSpan.ToArray());
16 | }
17 |
18 | public bool Validate(SmartConfigContext context, byte[] packet)
19 | {
20 | return packet.Length == EspWellKnownConstants.EspDevicePacketLength && packet[0] == EspWellKnownConstants.EspDevicePacketMagic;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/AbstractSmartConfigProvider.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using System.Collections.Generic;
3 |
4 | namespace Sandwych.SmartConfig
5 | {
6 | public abstract class AbstractSmartConfigProvider : ISmartConfigProvider
7 | {
8 | public abstract string Name { get; }
9 |
10 | public abstract IDevicePacketInterpreter CreateDevicePacketInterpreter();
11 |
12 | public SmartConfigContext CreateContext()
13 | {
14 | var ctx = new SmartConfigContext(this);
15 | foreach(var e in this.GetDefaultOptions())
16 | {
17 | ctx.Options[e.key] = e.value;
18 | }
19 | return ctx;
20 | }
21 |
22 | public abstract IProcedureEncoder CreateProcedureEncoder();
23 |
24 | public abstract IEnumerable<(string key, object value)> GetDefaultOptions();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Airkiss/Protocol/AirkissPrefixCodeFrameEncoderTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Sandwych.SmartConfig.Airkiss.Protocol;
3 | using Sandwych.SmartConfig.Util;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 |
9 | namespace Sandwych.SmartConfig.Test.Airkiss.Protocol
10 | {
11 | public class AirkissPrefixCodeFrameEncoderTests
12 | {
13 |
14 | [Test]
15 | public void EncodingShouldBeOk()
16 | {
17 | var buf = Encoding.ASCII.GetBytes("lixiaoxiong");
18 | var frames = AirkissPrefixCodeFrameEncoder.Encode(buf.Length).ToArray();
19 |
20 | Assert.AreEqual(72 - 8, frames[0]);
21 | Assert.AreEqual(99 - 8, frames[1]);
22 | Assert.AreEqual(106 - 8, frames[2]);
23 | Assert.AreEqual(120 - 8, frames[3]);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/Protocol/AirkissPrefixCodeFrameEncoder.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using Sandwych.SmartConfig.Util;
3 | using System.Collections.Generic;
4 |
5 | namespace Sandwych.SmartConfig.Airkiss.Protocol
6 | {
7 | public static class AirkissPrefixCodeFrameEncoder
8 | {
9 | public static IEnumerable Encode(int passwordLength)
10 | {
11 | var frames = new ushort[4];
12 | var blen = (byte)passwordLength;
13 | var lenCrc8 = Crc8.ComputeOnceOnly(blen);
14 | frames[0] = BytesHelper.CombineUshort(0x04, blen.Bisect().high);
15 | frames[1] = BytesHelper.CombineUshort(0x05, blen.Bisect().low);
16 | frames[2] = BytesHelper.CombineUshort(0x06, lenCrc8.Bisect().high);
17 | frames[3] = BytesHelper.CombineUshort(0x07, lenCrc8.Bisect().low);
18 | return frames;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/Protocol/AirkissSeqEntryFrameEncoder.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using Sandwych.SmartConfig.Util;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace Sandwych.SmartConfig.Airkiss.Protocol
7 | {
8 | public static class AirkissSeqEntryFrameEncoder
9 | {
10 | public static IEnumerable Encode(int index, IEnumerable bytes)
11 | {
12 | var frames = new List(2 + bytes.Count());
13 |
14 | var crc = new Crc8();
15 | crc.Update((byte)(index & 0x7F));
16 | crc.Update(bytes);
17 |
18 | frames.Add((ushort)(0x80 | (crc.Value & 0x7F)));
19 | frames.Add((ushort)(0x80 | index));
20 |
21 | foreach (var b in bytes)
22 | {
23 | frames.Add((ushort)(0x100 | b));
24 | }
25 | return frames;
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/Protocol/AirkissDevicePacketInterpreter.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.NetworkInformation;
6 | using System.Text;
7 |
8 | namespace Sandwych.SmartConfig.Airkiss.Protocol
9 | {
10 | public class AirkissDevicePacketInterpreter : IDevicePacketInterpreter
11 | {
12 | public PhysicalAddress ParseMacAddress(byte[] packet)
13 | {
14 | var macSpan = new ArraySegment(packet, 1, 6);
15 | return new PhysicalAddress(macSpan.ToArray());
16 | }
17 |
18 | public bool Validate(SmartConfigContext context, byte[] packet)
19 | {
20 | var randomValue = context.GetOption(AirkissOptionNames.RandomNumber);
21 | return (packet.Length == AirkissWellknownConstants.DevicePacketLength && packet[0] == randomValue);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/Protocol/AirkissMagicCodeFrameEncoder.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using Sandwych.SmartConfig.Util;
3 | using System.Collections.Generic;
4 |
5 | namespace Sandwych.SmartConfig.Airkiss.Protocol
6 | {
7 | public static class AirkissMagicCodeFrameEncoder
8 | {
9 |
10 | public static IEnumerable Encode(int totalLength, byte ssidCrc)
11 | {
12 | ushort[] frames = new ushort[4];
13 | var blen = (byte)totalLength;
14 | var firstFrame = BytesHelper.CombineUshort(0x00, blen.Bisect().high);
15 | frames[0] = firstFrame != 0 ? firstFrame : (ushort)0x08;
16 | frames[1] = BytesHelper.CombineUshort(0x01, blen.Bisect().low);
17 | frames[2] = BytesHelper.CombineUshort(0x02, ssidCrc.Bisect().high);
18 | frames[3] = BytesHelper.CombineUshort(0x03, ssidCrc.Bisect().low);
19 | return frames;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Util/TaskExtensions.cs:
--------------------------------------------------------------------------------
1 | // https://stackoverflow.com/questions/41899842/how-to-cancel-and-raise-an-exception-on-task-whenall-if-any-exception-is-raised
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace Sandwych.SmartConfig.Util
9 | {
10 | public static class TaskExtensions
11 | {
12 | public static Task CancelOnFaulted(this Task task, CancellationTokenSource cts)
13 | {
14 | task.ContinueWith(x => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
15 | return task;
16 | }
17 |
18 | public static Task CancelOnFaulted(this Task task, CancellationTokenSource cts)
19 | {
20 | task.ContinueWith(x => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
21 | return task;
22 | }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Airkiss/Protocol/AirkissMagicCodeFrameEncoderTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Sandwych.SmartConfig.Airkiss.Protocol;
3 | using Sandwych.SmartConfig.Util;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 |
9 | namespace Sandwych.SmartConfig.Test.Airkiss.Protocol
10 | {
11 | public class AirkissMagicCodeFrameEncoderTests
12 | {
13 |
14 | [Test]
15 | public void EncodingShouldBeOk()
16 | {
17 | var buf = Encoding.ASCII.GetBytes("MMKD");
18 |
19 | var crc = Crc8.ComputeOnceOnly(buf, 0, buf.Length);
20 | var magicCodeFrames = AirkissMagicCodeFrameEncoder.Encode(16, crc);
21 | var frames = magicCodeFrames.ToArray();
22 |
23 | Assert.AreEqual(1, frames[0]);
24 | Assert.AreEqual(16, frames[1]);
25 | Assert.AreEqual(44, frames[2]);
26 | Assert.AreEqual(51, frames[3]);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Sandwych.SmartConfig
5 | {
6 | public class SmartConfigContext
7 | {
8 | public IDictionary Options { get; } = new Dictionary();
9 |
10 | public T GetOption(string name) => (T)this.Options[name];
11 |
12 | public void SetOption(string name, T value)
13 | {
14 | this.Options[name] = value;
15 | }
16 |
17 | public ISmartConfigProvider Provider { get; internal set; }
18 |
19 | public SmartConfigContext(ISmartConfigProvider provider)
20 | {
21 | this.Provider = provider;
22 | }
23 |
24 | public event EventHandler DeviceDiscoveredEvent;
25 |
26 | public void ReportDevice(ISmartConfigDevice device)
27 | {
28 | this.DeviceDiscoveredEvent?.Invoke(this, new DeviceDiscoveredEventArgs(device));
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using Android.App;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("Sandwych.SmartConfig.AndroidDemoApp")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("Sandwych.SmartConfig.AndroidDemoApp")]
14 | [assembly: AssemblyCopyright("Copyright © 2018")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: ComVisible(false)]
18 |
19 | // Version information for an assembly consists of the following four values:
20 | //
21 | // Major Version
22 | // Minor Version
23 | // Build Number
24 | // Revision
25 | [assembly: AssemblyVersion("1.0.0.0")]
26 | [assembly: AssemblyFileVersion("1.0.0.0")]
27 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Esptouch/Protocol/EspProcedureEncoder.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Protocol;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Sandwych.SmartConfig.Esptouch.Protocol
6 | {
7 | public sealed class EspProcedureEncoder : IProcedureEncoder
8 | {
9 | public IEnumerable Encode(SmartConfigContext context, SmartConfigArguments args)
10 | {
11 | var guideTimeout = context.GetOption(StandardOptionNames.GuideCodeTimeout);
12 | var datumTimeout = context.GetOption(EspOptionNames.DatumPeriodTimeout);
13 | var frameInterval = context.GetOption(StandardOptionNames.FrameInterval);
14 |
15 | var datumEncoder = new EspDatumFrameEncoder();
16 | var segFrames = new Segment[]
17 | {
18 | new Segment(EspWellKnownConstants.GuideCodes, frameInterval, guideTimeout),
19 | new Segment(datumEncoder.Encode(context, args), frameInterval, datumTimeout)
20 | };
21 | return segFrames;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2014 Sandwych.SmartConfig contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Li 'oldrev' Wei
5 | Li Wei
6 | true
7 | portable
8 | false
9 | false
10 | false
11 | false
12 | false
13 | false
14 | false
15 | true
16 | 0
17 | 1.1.1.$(BuildNumber)
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Airkiss/Protocol/AirkissDevicePacketInterpreterTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.NetworkInformation;
4 | using System.Text;
5 | using NUnit.Framework;
6 | using Sandwych.SmartConfig.Airkiss;
7 | using Sandwych.SmartConfig.Airkiss.Protocol;
8 |
9 | namespace Sandwych.SmartConfig.Test.Airkiss.Protocol
10 | {
11 | public class AirkissDevicePacketInterpreterTests
12 | {
13 |
14 | [Test]
15 | public void CanParseMacAddress()
16 | {
17 | var interpreter = new AirkissDevicePacketInterpreter();
18 | var packet = new byte[] { 0x53, 0xc8, 0x2b, 0x96, 0xa1, 0x57, 0x70 };
19 | var provider = new AirkissSmartConfigProvider();
20 | var ctx = provider.CreateContext();
21 | ctx.SetOption(AirkissOptionNames.RandomNumber, 0x53);
22 | Assert.True(interpreter.Validate(ctx, packet));
23 | var mac = interpreter.ParseMacAddress(packet);
24 | var expectedMac = new PhysicalAddress(new byte[] { 0xc8, 0x2b, 0x96, 0xa1, 0x57, 0x70 });
25 | Assert.AreEqual(expectedMac, mac);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Protocol/Segment.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Sandwych.SmartConfig.Protocol
5 | {
6 | public struct Segment
7 | {
8 | public IEnumerable Frames { get; }
9 | public TimeSpan FrameInterval { get; }
10 | public TimeSpan BroadcastingPeriod { get; }
11 | public int BroadcastingMaxTimes { get; }
12 |
13 | public Segment(
14 | IEnumerable frames,
15 | TimeSpan frameInterval,
16 | int broadcastingMaxTimes)
17 | {
18 | this.Frames = frames;
19 | this.FrameInterval = frameInterval;
20 | this.BroadcastingPeriod = TimeSpan.MaxValue;
21 | this.BroadcastingMaxTimes = broadcastingMaxTimes;
22 | }
23 |
24 | public Segment(
25 | IEnumerable frames,
26 | TimeSpan frameInterval,
27 | TimeSpan broadcastingPeriod)
28 | {
29 | this.Frames = frames;
30 | this.FrameInterval = frameInterval;
31 | this.BroadcastingPeriod = broadcastingPeriod;
32 | this.BroadcastingMaxTimes = 0;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Esptouch/EspSmartConfigProvider.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Esptouch.Protocol;
2 | using Sandwych.SmartConfig.Protocol;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace Sandwych.SmartConfig.Esptouch
7 | {
8 | public class EspSmartConfigProvider : AbstractSmartConfigProvider
9 | {
10 | public override string Name => "Esptouch";
11 |
12 | public override IDevicePacketInterpreter CreateDevicePacketInterpreter()
13 | => new EspDevicePacketInterpreter();
14 |
15 | public override IEnumerable<(string key, object value)> GetDefaultOptions()
16 | {
17 | yield return (StandardOptionNames.BroadcastingTargetPort, 7001);
18 | yield return (StandardOptionNames.ListeningPort, 18266);
19 | yield return (StandardOptionNames.FrameInterval, TimeSpan.Zero);
20 | yield return (StandardOptionNames.SegmentInterval, TimeSpan.FromMilliseconds(8));
21 | yield return (StandardOptionNames.GuideCodeTimeout, TimeSpan.FromSeconds(2));
22 | yield return (EspOptionNames.DatumPeriodTimeout, TimeSpan.FromSeconds(4));
23 | }
24 |
25 | public override IProcedureEncoder CreateProcedureEncoder()
26 | => new EspProcedureEncoder();
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Networking/DefaultDatagramClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.NetworkInformation;
7 | using System.Net.Sockets;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace Sandwych.SmartConfig.Networking
12 | {
13 | public class DefaultDatagramClient : IDatagramClient
14 | {
15 | private readonly UdpClient _udp;
16 |
17 | public DefaultDatagramClient()
18 | {
19 | _udp = new UdpClient(AddressFamily.InterNetwork);
20 | _udp.EnableBroadcast = true;
21 | }
22 |
23 | public void Bind(IPEndPoint localEndPoint)
24 | {
25 | _udp.Client.Bind(localEndPoint);
26 | }
27 |
28 | public async Task SendAsync(byte[] datagram, int bytes, IPEndPoint target)
29 | {
30 | await _udp.SendAsync(datagram, bytes, target);
31 | }
32 |
33 | public async Task ReceiveAsync()
34 | {
35 | var result = await _udp.ReceiveAsync();
36 | return new DatagramReceiveResult(result.Buffer, result.RemoteEndPoint);
37 | }
38 |
39 | public void Dispose()
40 | {
41 | _udp.Dispose();
42 | }
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Visual Studio 2019
2 |
3 | # Do not build feature branch with open Pull Requests
4 | skip_branch_with_pr: true
5 | branches:
6 | only:
7 | - master
8 | - dev
9 | - release
10 |
11 | init:
12 | - git config --global core.autocrlf true
13 | install:
14 | - ps: $env:BuildNumber= $env:APPVEYOR_BUILD_NUMBER
15 | - ps: $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = true
16 | - ps: $env:NUGET_XMLDOC_MODE = "skip"
17 | - ps: $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
18 | - ps: $IsReleaseBranch = ($env:APPVEYOR_REPO_BRANCH -eq "master" -Or $env:APPVEYOR_REPO_BRANCH -eq "release")
19 | build_script:
20 | # Ensure we are not using the myget feed for dependencies
21 | - dotnet --version
22 | - dotnet pack Sandwych.SmartConfig.sln -c Release
23 | test_script:
24 | - dotnet test .\test\Sandwych.SmartConfig.Test\Sandwych.SmartConfig.Test.csproj -c Release
25 | artifacts:
26 | - path: 'src\**\*.nupkg'
27 | deploy:
28 | - provider: NuGet
29 | on:
30 | branch: release
31 | server: https://www.nuget.org/api/v2/package
32 | api_key:
33 | secure: 76dWrCJVCm1+cBO+WmjmZIvpAw7sf416N/UJWHMbshmC7BOBabuC4Mm6PP2MWdGk
34 | skip_symbols: true
35 | artifact: /.*\.nupkg/
36 | - provider: NuGet
37 | on:
38 | branch: master
39 | server: https://www.nuget.org/api/v2/package
40 | api_key:
41 | secure: 76dWrCJVCm1+cBO+WmjmZIvpAw7sf416N/UJWHMbshmC7BOBabuC4Mm6PP2MWdGk
42 | skip_symbols: true
43 | artifact: /.*\.nupkg/
44 |
--------------------------------------------------------------------------------
/test/Sandwych.SmartConfig.Test/Util/Crc8Tests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System.Text;
3 |
4 | using Sandwych.SmartConfig.Util;
5 | using System.Linq;
6 |
7 | namespace Sandwych.Esptouch.Test.Util
8 | {
9 | public class Crc8Tests
10 | {
11 | [Test]
12 | public void CheckCrcTable()
13 | {
14 | Assert.AreEqual(256, Crc8.Table.Count);
15 |
16 | Assert.AreEqual(0x0, Crc8.Table.First());
17 | Assert.AreEqual(0x5E, Crc8.Table[1]);
18 | Assert.AreEqual(0xC2, Crc8.Table[8]);
19 | Assert.AreEqual(0x35, Crc8.Table.Last());
20 | }
21 |
22 | [Test]
23 | public void ComputeOnceShouldWork()
24 | {
25 | Assert.AreEqual(0xC3, Crc8.ComputeOnceOnly(Encoding.UTF8.GetBytes("MMKD")));
26 |
27 | var buf = new byte[2] { 0x0B, 0x01 };
28 | Assert.AreEqual(0x7D, Crc8.ComputeOnceOnly(buf));
29 | }
30 |
31 | [Test]
32 | public void UpdateShouldWork()
33 | {
34 | var crc = new Crc8();
35 |
36 | crc.Reset();
37 | var buf = new byte[2] { 0x0B, 0x01 };
38 | Assert.AreEqual(0x7D, crc.Update(buf));
39 | Assert.AreEqual(0x7D, crc.Value);
40 |
41 | crc.Reset();
42 | buf = new byte[2] { 0xC3, 0x02 };
43 | crc.Update(buf[0]);
44 | crc.Update(buf[1]);
45 | Assert.AreEqual(0x5D, crc.Value);
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Util/AsyncExtensions.cs:
--------------------------------------------------------------------------------
1 | // https://stackoverflow.com/questions/19404199/how-to-to-make-udpclient-receiveasync-cancelable
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace Sandwych.SmartConfig.Util
9 | {
10 | public static class AsyncExtensions
11 | {
12 | public static async Task WithCancellation(this Task task, CancellationToken cancellationToken)
13 | {
14 | var tcs = new TaskCompletionSource();
15 | using (cancellationToken.Register(s => ((TaskCompletionSource)s).TrySetResult(true), tcs))
16 | {
17 | if (task != await Task.WhenAny(task, tcs.Task))
18 | {
19 | throw new OperationCanceledException(cancellationToken);
20 | }
21 | }
22 | }
23 |
24 |
25 | public static async Task WithCancellation(this Task task, CancellationToken cancellationToken)
26 | {
27 | var tcs = new TaskCompletionSource();
28 | using (cancellationToken.Register(s => ((TaskCompletionSource)s).TrySetResult(true), tcs))
29 | {
30 | if (task != await Task.WhenAny(task, tcs.Task))
31 | {
32 | throw new OperationCanceledException(cancellationToken);
33 | }
34 | }
35 |
36 | return task.Result;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/layout/device_list_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
16 |
24 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Airkiss/AirkissSmartConfigProvider.cs:
--------------------------------------------------------------------------------
1 | using Sandwych.SmartConfig.Airkiss.Protocol;
2 | using Sandwych.SmartConfig.Protocol;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace Sandwych.SmartConfig.Airkiss
7 | {
8 | public class AirkissSmartConfigProvider : AbstractSmartConfigProvider
9 | {
10 | public override string Name => "Airkiss";
11 |
12 | public override IDevicePacketInterpreter CreateDevicePacketInterpreter() => new AirkissDevicePacketInterpreter();
13 |
14 | public override IEnumerable<(string key, object value)> GetDefaultOptions()
15 | {
16 | yield return (StandardOptionNames.BroadcastingTargetPort, 10001); // The port to broadcast doesn't matter
17 | yield return (StandardOptionNames.ListeningPort, 10000);
18 | yield return (StandardOptionNames.FrameInterval, TimeSpan.Zero);
19 | yield return (StandardOptionNames.SegmentInterval, TimeSpan.FromMilliseconds(5));
20 | yield return (StandardOptionNames.GuideCodeTimeout, TimeSpan.FromSeconds(2));
21 |
22 | yield return (AirkissOptionNames.MagicCodeTimeout, TimeSpan.FromMilliseconds(500));
23 | yield return (AirkissOptionNames.PrefixCodeTimeout, TimeSpan.FromMilliseconds(500));
24 |
25 | var randomValue = (byte)(Environment.TickCount % 256);
26 | yield return (AirkissOptionNames.RandomNumber, randomValue);
27 | }
28 |
29 | public override IProcedureEncoder CreateProcedureEncoder()
30 | => new AirkissProcedureEncoder();
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Sandwych.SmartConfig
5 | Sandwych.SmartConfig
6 | Pure C# Implementation of Various WiFi SmartConfig Protocols: AirKiss and ESPTouch
7 | Sandwych.SmartConfig
8 | smartconfig, airkiss, esptouch, esp8266, esp32, xamarin
9 | https://github.com/oldrev/sandwych-smartconfig
10 | © Li 'oldrev' Wei. All rights reserved.
11 | MIT
12 | true
13 | true
14 | true
15 | snupkg
16 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
17 |
18 |
19 | true
20 | true
21 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/Resources/AboutResources.txt:
--------------------------------------------------------------------------------
1 | Images, layout descriptions, binary blobs and string dictionaries can be included
2 | in your application as resource files. Various Android APIs are designed to
3 | operate on the resource IDs instead of dealing with images, strings or binary blobs
4 | directly.
5 |
6 | For example, a sample Android app that contains a user interface layout (main.xml),
7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
8 | would keep its resources in the "Resources" directory of the application:
9 |
10 | Resources/
11 | drawable/
12 | icon.png
13 |
14 | layout/
15 | main.xml
16 |
17 | values/
18 | strings.xml
19 |
20 | In order to get the build system to recognize Android resources, set the build action to
21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but
22 | instead operate on resource IDs. When you compile an Android application that uses resources,
23 | the build system will package the resources for distribution and generate a class called "R"
24 | (this is an Android convention) that contains the tokens for each one of the resources
25 | included. For example, for the above Resources layout, this is what the R class would expose:
26 |
27 | public class R {
28 | public class drawable {
29 | public const int icon = 0x123;
30 | }
31 |
32 | public class layout {
33 | public const int main = 0x456;
34 | }
35 |
36 | public class strings {
37 | public const int first_string = 0xabc;
38 | public const int second_string = 0xbcd;
39 | }
40 | }
41 |
42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
43 | to reference the layout/main.xml file, or R.strings.first_string to reference the first
44 | string in the dictionary file values/strings.xml.
--------------------------------------------------------------------------------
/Sandwych.SmartConfig.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.4.33213.308
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandwych.SmartConfig", "src\Sandwych.SmartConfig\Sandwych.SmartConfig.csproj", "{E851B517-D7A0-417E-BCB9-492081B26E6F}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandwych.SmartConfig.Test", "test\Sandwych.SmartConfig.Test\Sandwych.SmartConfig.Test.csproj", "{3022E137-2800-4BC5-962A-190E7DB47E3A}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F6D0B71-67C9-4BA3-8C15-63DC63D36612}"
11 | ProjectSection(SolutionItems) = preProject
12 | .editorconfig = .editorconfig
13 | Common.props = Common.props
14 | LICENSE.md = LICENSE.md
15 | README.md = README.md
16 | README.zh_cn.md = README.zh_cn.md
17 | EndProjectSection
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {E851B517-D7A0-417E-BCB9-492081B26E6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {E851B517-D7A0-417E-BCB9-492081B26E6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {E851B517-D7A0-417E-BCB9-492081B26E6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {E851B517-D7A0-417E-BCB9-492081B26E6F}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {3022E137-2800-4BC5-962A-190E7DB47E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {3022E137-2800-4BC5-962A-190E7DB47E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {3022E137-2800-4BC5-962A-190E7DB47E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {3022E137-2800-4BC5-962A-190E7DB47E3A}.Release|Any CPU.Build.0 = Release|Any CPU
33 | EndGlobalSection
34 | GlobalSection(SolutionProperties) = preSolution
35 | HideSolutionNode = FALSE
36 | EndGlobalSection
37 | GlobalSection(ExtensibilityGlobals) = postSolution
38 | SolutionGuid = {C19C547C-046A-4F18-B697-8B4E43F6438B}
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/demo/Sandwych.SmartConfig.AndroidDemoApp/DeviceListViewAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Android.App;
7 | using Android.Content;
8 | using Android.OS;
9 | using Android.Runtime;
10 | using Android.Views;
11 | using Android.Widget;
12 |
13 | namespace Sandwych.SmartConfig.AndroidDemoApp
14 | {
15 | public class DeviceListViewAdapter : BaseAdapter
16 | {
17 | private readonly IList _devices;
18 |
19 | public DeviceListViewAdapter(IList devices)
20 | {
21 | _devices = devices;
22 | }
23 |
24 | public override ISmartConfigDevice this[int position] => _devices[position];
25 |
26 | public override int Count => throw new NotImplementedException();
27 |
28 | public override long GetItemId(int position) => position;
29 |
30 | public override View GetView(int position, View convertView, ViewGroup parent)
31 | {
32 | var view = convertView;
33 |
34 | if (view == null)
35 | {
36 | view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.device_list_row, parent, false);
37 |
38 | /*
39 | var image = view.FindViewById(Resource.Id.photoImageView);
40 | var name = view.FindViewById(Resource.Id.ipad);
41 | var department = view.FindViewById(Resource.Id.departmentTextView);
42 |
43 | view.Tag = new DeviceListViewHolder()
44 | {
45 | Image = image,
46 | Name = name,
47 | Department = department
48 | };
49 | var holder = (DeviceListViewHolder)view.Tag;
50 | holder.Photo.SetImageDrawable(ImageManager.Get(parent.Context, users[position].ImageUrl));
51 | holder.Name.Text = users[position].Name;
52 | holder.Department.Text = users[position].Department;
53 | return view;
54 | */
55 | }
56 |
57 | return view;
58 | }
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/src/Sandwych.SmartConfig/SmartConfigStarter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Sandwych.SmartConfig
8 | {
9 | public static class SmartConfigStarter
10 | {
11 | public static async Task StartAsync(SmartConfigArguments args,
12 | CancellationToken cancelToken,
13 | Action