├── .gitattributes
├── .gitignore
├── .idea
└── .idea.MU3Input
│ └── .idea
│ ├── .gitignore
│ ├── .name
│ ├── indexLayout.xml
│ └── vcs.xml
├── DllExport.bat
├── MU3Input.sln
├── MU3Input
├── AimeIO.cs
├── Config.cs
├── Extensions.cs
├── FodyWeavers.xml
├── IO
│ ├── HidIO.cs
│ ├── IO.cs
│ ├── KeyboardIO.cs
│ ├── MixedIO.cs
│ ├── TcpIO.cs
│ ├── UdpIO.cs
│ └── UsbmuxIO.cs
├── IOTest.Designer.cs
├── IOTest.cs
├── IOTest.resx
├── Kernel32.cs
├── MU3IO.cs
├── MU3Input.csproj
├── Properties
│ └── AssemblyInfo.cs
├── SimpleRawHid.cs
├── User32.cs
└── Utils.cs
├── README.md
├── SegaToolsPatch
└── 0001-Add-led-code.patch
├── Test
├── App.config
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── Test.csproj
└── mu3controller
├── .gitignore
├── .idea
├── .gitignore
├── misc.xml
├── modules.xml
├── untitled1.iml
└── vcs.xml
├── include
└── README
├── lib
├── NDEF
│ ├── Due.h
│ ├── LICENSE.txt
│ ├── MifareClassic.cpp
│ ├── MifareClassic.h
│ ├── MifareUltralight.cpp
│ ├── MifareUltralight.h
│ ├── Ndef.cpp
│ ├── Ndef.h
│ ├── NdefMessage.cpp
│ ├── NdefMessage.h
│ ├── NdefRecord.cpp
│ ├── NdefRecord.h
│ ├── NfcAdapter.cpp
│ ├── NfcAdapter.h
│ ├── NfcDriver.h
│ ├── NfcTag.cpp
│ ├── NfcTag.h
│ ├── README.md
│ ├── examples
│ │ ├── CleanTag
│ │ │ └── CleanTag.ino
│ │ ├── EraseTag
│ │ │ └── EraseTag.ino
│ │ ├── FormatTag
│ │ │ └── FormatTag.ino
│ │ ├── P2P_Receive
│ │ │ └── P2P_Receive.ino
│ │ ├── P2P_Receive_LCD
│ │ │ └── P2P_Receive_LCD.ino
│ │ ├── P2P_Send
│ │ │ └── P2P_Send.ino
│ │ ├── ReadTag
│ │ │ └── ReadTag.ino
│ │ ├── ReadTagExtended
│ │ │ └── ReadTagExtended.ino
│ │ ├── WriteTag
│ │ │ └── WriteTag.ino
│ │ └── WriteTagMultipleRecords
│ │ │ └── WriteTagMultipleRecords.ino
│ ├── keywords.txt
│ └── tests
│ │ ├── NdefMemoryTest
│ │ └── NdefMemoryTest.ino
│ │ ├── NdefMessageTest
│ │ └── NdefMessageTest.ino
│ │ ├── NdefUnitTest
│ │ └── NdefUnitTest.ino
│ │ └── NfcTagTest
│ │ └── NfcTagTest.ino
├── PN532
│ ├── PN532.cpp
│ ├── PN532.h
│ ├── PN532Interface.h
│ ├── PN532_debug.h
│ ├── README.md
│ ├── emulatetag.cpp
│ ├── emulatetag.h
│ ├── examples
│ │ ├── FeliCa_card_detection
│ │ │ └── FeliCa_card_detection.pde
│ │ ├── FeliCa_card_read
│ │ │ └── FeliCa_card_read.pde
│ │ ├── android_hce
│ │ │ └── android_hce.ino
│ │ ├── emulate_tag_ndef
│ │ │ └── emulate_tag_ndef.ino
│ │ ├── iso14443a_uid
│ │ │ └── iso14443a_uid.pde
│ │ ├── mifareclassic_formatndef
│ │ │ └── mifareclassic_formatndef.pde
│ │ ├── mifareclassic_memdump
│ │ │ └── mifareclassic_memdump.pde
│ │ ├── mifareclassic_ndeftoclassic
│ │ │ └── mifareclassic_ndeftoclassic.pde
│ │ ├── mifareclassic_updatendef
│ │ │ └── mifareclassic_updatendef.pde
│ │ ├── p2p_raw
│ │ │ └── p2p_raw.ino
│ │ ├── p2p_with_ndef_library
│ │ │ └── p2p_with_ndef_library.ino
│ │ └── readMifare
│ │ │ └── readMifare.pde
│ ├── license.txt
│ ├── llcp.cpp
│ ├── llcp.h
│ ├── mac_link.cpp
│ ├── mac_link.h
│ ├── snep.cpp
│ └── snep.h
├── PN532_HSU
│ ├── PN532_HSU.cpp
│ └── PN532_HSU.h
└── README
├── platformio.ini
├── src
├── components
│ ├── card_reader.cpp
│ ├── card_reader.hpp
│ ├── comio.hpp
│ ├── keyboard.cpp
│ ├── keyboard.hpp
│ ├── led_board.cpp
│ ├── led_board.hpp
│ ├── manager.cpp
│ ├── manager.hpp
│ ├── ongeki_hardware.cpp
│ ├── ongeki_hardware.hpp
│ ├── raw_hid.cpp
│ ├── raw_hid.hpp
│ ├── serial.cpp
│ └── serial.hpp
├── eeprom_address.h
├── main.cpp
└── stdinclude.hpp
└── test
└── README
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.idea/.idea.MU3Input/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 | # Rider 忽略的文件
5 | /projectSettingsUpdater.xml
6 | /contentModel.xml
7 | /modules.xml
8 | /.idea.MU3Input.iml
9 | # 基于编辑器的 HTTP 客户端请求
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/.idea/.idea.MU3Input/.idea/.name:
--------------------------------------------------------------------------------
1 | MU3Input
--------------------------------------------------------------------------------
/.idea/.idea.MU3Input/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.MU3Input/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/MU3Input.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.31911.260
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MU3Input", "MU3Input\MU3Input.csproj", "{A90797A6-C546-4233-A183-453AF52319D0}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{678BBC0E-4096-4064-BD0A-D2B311141111}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Release|x64 = Release|x64
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {A90797A6-C546-4233-A183-453AF52319D0}.Debug|x64.ActiveCfg = Debug|x64
17 | {A90797A6-C546-4233-A183-453AF52319D0}.Debug|x64.Build.0 = Debug|x64
18 | {A90797A6-C546-4233-A183-453AF52319D0}.Release|x64.ActiveCfg = Release|x64
19 | {A90797A6-C546-4233-A183-453AF52319D0}.Release|x64.Build.0 = Release|x64
20 | {678BBC0E-4096-4064-BD0A-D2B311141111}.Debug|x64.ActiveCfg = Debug|x64
21 | {678BBC0E-4096-4064-BD0A-D2B311141111}.Debug|x64.Build.0 = Debug|x64
22 | {678BBC0E-4096-4064-BD0A-D2B311141111}.Release|x64.ActiveCfg = Release|x64
23 | EndGlobalSection
24 | GlobalSection(SolutionProperties) = preSolution
25 | HideSolutionNode = FALSE
26 | EndGlobalSection
27 | GlobalSection(ExtensibilityGlobals) = postSolution
28 | SolutionGuid = {6671AB3E-3857-4E77-8258-F50F9C854AE4}
29 | EndGlobalSection
30 | EndGlobal
31 |
--------------------------------------------------------------------------------
/MU3Input/AimeIO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace MU3Input
8 | {
9 | public static class AimiIO
10 | {
11 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_get_api_version")]
12 | public static ushort GetVersion() => 0x0200;
13 |
14 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_init")]
15 | public static uint Init()
16 | {
17 | if (Process.GetCurrentProcess().ProcessName != "amdaemon" &&
18 | Process.GetCurrentProcess().ProcessName != "Debug" &&
19 | Process.GetCurrentProcess().ProcessName != "Test")
20 | return 1;
21 |
22 | return 0;
23 | }
24 |
25 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_nfc_poll")]
26 | public static uint Poll(byte unitNumber)
27 | {
28 | return 0;
29 | }
30 |
31 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_nfc_get_felica_id")]
32 | public static unsafe uint GetFelicaId(byte unitNumber, ulong* id)
33 | {
34 | if (Mu3IO.IO == null || Mu3IO.IO.Aime.Scan != 2)
35 | {
36 | return 1;
37 | }
38 | else
39 | {
40 | *id = Mu3IO.IO.Aime.IDm;
41 | return 0;
42 | }
43 | }
44 |
45 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_nfc_get_felica_pm")]
46 | public static unsafe uint GetFelicaPm(byte unitNumber, ulong* pm)
47 | {
48 | if (Mu3IO.IO == null || Mu3IO.IO.Aime.Scan != 2)
49 | {
50 | return 1;
51 | }
52 | else
53 | {
54 | *pm = Mu3IO.IO.Aime.PMm;
55 | return 0;
56 | }
57 | }
58 |
59 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_nfc_get_felica_system_code")]
60 | public static unsafe uint GetFelicaSystemCode(byte unitNumber, ushort* systemCode)
61 | {
62 | if (Mu3IO.IO == null || Mu3IO.IO.Aime.Scan != 2)
63 | {
64 | return 1;
65 | }
66 | else
67 | {
68 | *systemCode = Mu3IO.IO.Aime.SystemCode;
69 | return 0;
70 | }
71 | }
72 |
73 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_nfc_get_aime_id")]
74 | public static unsafe uint GetAimeId(byte unitNumber, byte* id, ulong size)
75 | {
76 | if (Mu3IO.IO == null || Mu3IO.IO.Aime.Scan != 1) return 1;
77 | Aime aime = Mu3IO.IO.Aime;
78 | for(int i = 0; i < 10; i++)
79 | {
80 | id[i]=aime.ID[i];
81 | }
82 |
83 | return 0;
84 | }
85 |
86 | [DllExport(CallingConvention = CallingConvention.Cdecl, ExportName = "aime_io_led_set_color")]
87 | public static void SetColor(byte unitNumber, byte r, byte g, byte b)
88 | {
89 |
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/MU3Input/Config.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using Newtonsoft.Json.Linq;
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 |
9 | namespace MU3Input
10 | {
11 | public class Config
12 | {
13 | public static Config Instance;
14 | private static string configPath;
15 | static Config()
16 | {
17 | var location = typeof(Mu3IO).Assembly.Location;
18 | string directoryName = Path.GetDirectoryName(location);
19 | configPath = Path.Combine(directoryName, "mu3input_config.json");
20 | if (File.Exists(configPath))
21 | {
22 | Instance = JsonConvert.DeserializeObject(File.ReadAllText(configPath), new JsonSerializerSettings());
23 | }
24 | else
25 | {
26 | Instance = new Config();
27 | Instance.IO = new List()
28 | {
29 | new IOConfig()
30 | {
31 | Type = IOType.Udp,
32 | Param = 4354,
33 | Part = ControllerPart.All
34 | }
35 | };
36 | Instance.Save(configPath);
37 | }
38 | }
39 | public void Save()
40 | {
41 | Save(configPath);
42 | }
43 | public void Save(string path)
44 | {
45 | File.WriteAllText(path, JsonConvert.SerializeObject(this, new JsonSerializerSettings()
46 | {
47 | Formatting = Formatting.Indented,
48 | }));
49 | }
50 | private Config() { }
51 | public List IO { get; set; }
52 | }
53 | public class IOConfig
54 | {
55 | [JsonConverter(typeof(StringEnumConverter))]
56 | public IOType Type { get; set; }
57 | public JToken Param { get; set; }
58 | [JsonConverter(typeof(StringEnumConverter))]
59 | public ControllerPart Part { get; set; }
60 | }
61 |
62 |
63 | public enum IOType
64 | {
65 | Hid, Udp, Tcp, Usbmux, Keyboard
66 | }
67 |
68 | [Flags]
69 | public enum ControllerPart
70 | {
71 | None = 0,
72 | L1 = 1 << 0,
73 | L2 = 1 << 1,
74 | L3 = 1 << 2,
75 | LSide = 1 << 3,
76 | LMenu = 1 << 4,
77 | R1 = 1 << 5,
78 | R2 = 1 << 6,
79 | R3 = 1 << 7,
80 | RSide = 1 << 8,
81 | RMenu = 1 << 9,
82 | Lever = 1 << 10,
83 | Aime = 1 << 11,
84 | LKeyBoard = L1 | L2 | L3,
85 | RKeyBoard = R1 | R2 | R3,
86 | Side = LSide | RSide,
87 | Menu = LMenu | RMenu,
88 | KeyBoard = LKeyBoard | RKeyBoard,
89 | Left = LKeyBoard | LSide | LMenu,
90 | Right = RKeyBoard | RSide | RMenu,
91 | GameButtons = KeyBoard | Side,
92 | Buttons = GameButtons | Menu,
93 | GamePlay = GameButtons | Lever,
94 | All = GamePlay | Menu | Aime,
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/MU3Input/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MU3Input
5 | {
6 | public static class Extensions
7 | {
8 | public static T ToStructure(this byte[] bytes) where T : struct
9 | {
10 | var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
11 | try
12 | {
13 | return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
14 | }
15 | finally
16 | {
17 | handle.Free();
18 | }
19 | }
20 | public static byte[] ToBcd(this BigInteger value)
21 | {
22 | var length = value.ToString().Length / 2 + value.ToString().Length % 2;
23 | byte[] ret = new byte[length];
24 | for (int i = length - 1; i >= 0; i--)
25 | {
26 | ret[i] = (byte)(value % 10);
27 | value /= 10;
28 | ret[i] |= (byte)((value % 10) << 4);
29 | value /= 10;
30 | }
31 | return ret;
32 | }
33 | public static byte[] ToBcd(this ulong value)
34 | {
35 | var length = value.ToString().Length / 2 + value.ToString().Length % 2;
36 | byte[] ret = new byte[length];
37 | for (int i = length - 1; i >= 0; i--)
38 | {
39 | ret[i] = (byte)(value % 10);
40 | value /= 10;
41 | ret[i] |= (byte)((value % 10) << 4);
42 | value /= 10;
43 | }
44 | return ret;
45 | }
46 |
47 | }
48 | }
--------------------------------------------------------------------------------
/MU3Input/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/MU3Input/IO/HidIO.cs:
--------------------------------------------------------------------------------
1 | using SimpleHID.Raw;
2 |
3 | using System;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Threading;
7 | using System.Windows.Forms;
8 |
9 | using static MU3Input.KeyboardIO;
10 |
11 | namespace MU3Input
12 | {
13 | // ReSharper disable once InconsistentNaming
14 | public class HidIO : IO
15 | {
16 | private HidIOConfig config;
17 | protected int _openCount = 0;
18 | private byte[] _inBuffer = new byte[64];
19 | private readonly SimpleRawHID _hid = new SimpleRawHID();
20 | private const ushort VID = 0x2341;
21 | private const ushort PID = 0x8036;
22 | protected OutputData data;
23 | private bool reconnecting = false;
24 |
25 |
26 | public HidIO(HidIOConfig config)
27 | {
28 | this.config = config;
29 | data = new OutputData() { Buttons = new byte[10], Aime = new Aime() { Data = new byte[18] } };
30 | Reconnect();
31 | new Thread(PollThread).Start();
32 | }
33 | public override bool IsConnected => _openCount > 0;
34 | public override OutputData Data => data;
35 |
36 | public override void Reconnect()
37 | {
38 | if (reconnecting) return;
39 | reconnecting = true;
40 | if (IsConnected)
41 | _hid.Close();
42 |
43 | _openCount = _hid.Open(1, VID, PID);
44 | reconnecting = false;
45 | }
46 |
47 | public static int[] bitPosMap =
48 | {
49 | 23, 19, 22, 20, 21, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6
50 | };
51 |
52 |
53 | private unsafe void PollThread()
54 | {
55 | while (true)
56 | {
57 | if (!IsConnected)
58 | continue;
59 |
60 | var len = _hid.Receive(0, ref _inBuffer, 64, 1000);
61 | if (len < 0)
62 | {
63 | _openCount = 0;
64 | _hid.Close();
65 | continue;
66 | }
67 |
68 | OutputData temp = new OutputData();
69 | temp.Buttons = new ArraySegment(_inBuffer, 0, 10).ToArray();
70 | short lever;
71 | if (config.InvertLever)
72 | {
73 | lever = (short)(-BitConverter.ToInt16(_inBuffer, 10) - 1);
74 | }
75 | else
76 | {
77 | lever = BitConverter.ToInt16(_inBuffer, 10);
78 | }
79 | if (config.AutoCal)
80 | {
81 | if (lever < config.LeverLeft)
82 | {
83 | config.LeverLeft = lever;
84 | Console.WriteLine($"Set lever range: {config.LeverLeft}-{config.LeverRight}");
85 | }
86 | if (lever > config.LeverRight)
87 | {
88 | config.LeverRight = lever;
89 | Console.WriteLine($"Set lever range: {config.LeverLeft}-{config.LeverRight}");
90 | }
91 | }
92 | if (config.LeverRight != config.LeverLeft)
93 | {
94 | double normLever = (lever - config.LeverLeft) / (double)(config.LeverRight - config.LeverLeft);
95 | if (normLever < 0) normLever = 0;
96 | if (normLever > 1) normLever = 1;
97 | double leverd = -30000 + 60001 * normLever;
98 | temp.Lever = ((short)leverd);
99 | }
100 | else
101 | {
102 | temp.Lever = data.Lever;
103 | }
104 | temp.OptButtons = (OptButtons)_inBuffer[12];
105 | temp.Aime.Scan = _inBuffer[13];
106 | temp.Aime.Data = new byte[18];
107 | if (temp.Aime.Scan == 1)
108 | {
109 | byte[] mifareID = new ArraySegment(_inBuffer, 14, 10).ToArray();
110 | bool flag = true;
111 | for (int i = 0; i < 10; i++)
112 | {
113 | if (mifareID[i] != 255)
114 | {
115 | flag = false;
116 | break;
117 | }
118 | }
119 | if (flag)
120 | {
121 | mifareID = Utils.ReadOrCreateAimeTxt();
122 | }
123 | temp.Aime.ID = mifareID;
124 | }
125 | if (temp.Aime.Scan == 2)
126 | {
127 | temp.Aime.IDm = BitConverter.ToUInt64(_inBuffer, 14);
128 | temp.Aime.PMm = BitConverter.ToUInt64(_inBuffer, 22);
129 | temp.Aime.SystemCode = BitConverter.ToUInt16(_inBuffer, 30);
130 | }
131 | data = temp;
132 | }
133 | }
134 |
135 | public unsafe override void SetLed(uint data)
136 | {
137 | if (!IsConnected)
138 | return;
139 |
140 | SetLedInput led;
141 | led.Type = 0;
142 | led.LedBrightness = 40;
143 |
144 | for (var i = 0; i < 9; i++)
145 | {
146 | led.LedColors[i] = (byte)(((data >> bitPosMap[i]) & 1) * 255);
147 | led.LedColors[i + 15] = (byte)(((data >> bitPosMap[i + 9]) & 1) * 255);
148 | }
149 |
150 | var outBuffer = new byte[64];
151 | fixed (void* d = outBuffer)
152 | Kernel32.CopyMemory(d, &led, 64);
153 |
154 | _hid.Send(0, outBuffer, 64, 1000);
155 | }
156 |
157 | }
158 | public class HidIOConfig
159 | {
160 | public bool AutoCal { get; set; } = true;
161 | public short LeverLeft { get; set; } = short.MaxValue;
162 | public short LeverRight { get; set; } = short.MinValue;
163 | public bool InvertLever { get; set; } = true;
164 | }
165 | }
--------------------------------------------------------------------------------
/MU3Input/IO/IO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace MU3Input
6 | {
7 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 64)]
8 | public struct OutputData
9 | {
10 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.U1)]
11 | public byte[] Buttons;
12 |
13 | public short Lever;
14 |
15 | public OptButtons OptButtons;
16 |
17 | public Aime Aime;
18 | }
19 |
20 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 64)]
21 | public unsafe struct SetLedInput
22 | {
23 | public byte Type;
24 | public byte LedBrightness;
25 |
26 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
27 | public fixed byte LedColors[3 * 10];
28 | }
29 |
30 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 64)]
31 | public unsafe struct SetOptionInput
32 | {
33 | public byte Type;
34 |
35 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
36 | public fixed byte AimiId[10];
37 | }
38 | public abstract class IO
39 | {
40 | public abstract OutputData Data { get; }
41 |
42 | private byte[] leftButtonsCache = new byte[5];
43 | private byte[] rightButtonsCache = new byte[5];
44 | public byte LeftButton
45 | {
46 | get
47 | {
48 | byte result = 0;
49 | for (int i = 4; i >= 0; i--)
50 | {
51 | result <<= 1;
52 | // 按钮触点数量不为0时
53 | if (Data.Buttons[i] > 0)
54 | {
55 | // 当已被按下并增加触点数量时自动松开一帧
56 | if (leftButtonsCache[i] > 0 && Data.Buttons[i] > leftButtonsCache[i])
57 | {
58 | result += 0;
59 | }
60 | else
61 | {
62 | result += 1;
63 | }
64 | }
65 | }
66 | Array.Copy(Data.Buttons, 0, leftButtonsCache, 0, 5);
67 | return result;
68 | }
69 | }
70 |
71 | public byte RightButton
72 | {
73 | get
74 | {
75 | byte result = 0;
76 | for (int i = 4; i >= 0; i--)
77 | {
78 | result <<= 1;
79 | if (Data.Buttons[i + 5] > 0)
80 | {
81 | if (rightButtonsCache[i] > 0 && Data.Buttons[i + 5] > rightButtonsCache[i])
82 | {
83 | result += 0;
84 | }
85 | else
86 | {
87 | result += 1;
88 | }
89 | }
90 | }
91 | Array.Copy(Data.Buttons, 5, rightButtonsCache, 0, 5);
92 | return result;
93 | }
94 | }
95 |
96 | public short Lever
97 | {
98 | get
99 | {
100 | return Data.Lever;
101 | }
102 | }
103 | public Aime Aime => Data.Aime;
104 | public OptButtons OptButtonsStatus => Data.OptButtons;
105 |
106 | public abstract bool IsConnected { get; }
107 | public abstract void Reconnect();
108 | public abstract void SetLed(uint data);
109 | }
110 | [Flags]
111 | public enum OptButtons : byte
112 | {
113 | None = 0b000,
114 | Test = 0b001,
115 | Service = 0b010,
116 | Coin = 0b100
117 | }
118 |
119 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 19)]
120 | public struct Aime
121 | {
122 | [MarshalAs(UnmanagedType.U1)]
123 | public byte Scan;
124 |
125 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18, ArraySubType = UnmanagedType.U1)]
126 | public byte[] Data;
127 |
128 | public byte[] ID
129 | {
130 | get => new ArraySegment(Data, 0, 10).ToArray();
131 | set => value.CopyTo(Data, 0);
132 | }
133 |
134 | public ulong IDm
135 | {
136 | get => BitConverter.ToUInt64(Data, 0);
137 | set => BitConverter.GetBytes(value).CopyTo(Data, 0);
138 | }
139 | public ulong PMm
140 | {
141 | get => BitConverter.ToUInt64(Data, 8);
142 | set => BitConverter.GetBytes(value).CopyTo(Data, 8);
143 | }
144 | public ushort SystemCode
145 | {
146 | get => BitConverter.ToUInt16(Data, 16);
147 | set => BitConverter.GetBytes(value).CopyTo(Data, 16);
148 | }
149 | }
150 | enum MessageType : byte
151 | {
152 | // 控制器向IO发送的
153 | ButtonStatus = 1,
154 | MoveLever = 2,
155 | Scan = 3,
156 | Test = 4,
157 | Service = 5,
158 | RequestValues = 6,
159 | // IO向控制器发送的
160 | SetLed = 20,
161 | SetLever = 21,
162 | // 寻找在线设备
163 | Hello = 255
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/MU3Input/IO/KeyboardIO.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using Newtonsoft.Json.Linq;
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Diagnostics;
8 | using System.Drawing;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Windows.Forms;
13 |
14 | using static System.Windows.Forms.VisualStyles.VisualStyleElement;
15 |
16 | namespace MU3Input
17 | {
18 | internal class KeyboardIO : IO
19 | {
20 | private KeyboardIOConfig config;
21 | public override OutputData Data => GetData();
22 |
23 | public override bool IsConnected => true;
24 |
25 | public KeyboardIO(KeyboardIOConfig param)
26 | {
27 | config = param;
28 | }
29 |
30 | public override void Reconnect() { }
31 |
32 | public override void SetLed(uint data) { }
33 |
34 |
35 | StringBuilder sb = new StringBuilder();
36 | bool coinAvailable = true;
37 | private OutputData GetData()
38 | {
39 | IntPtr handle = User32.GetForegroundWindow();
40 | User32.GetWindowText(handle, sb, 16);
41 | string windowText = sb.ToString();
42 | if (windowText != "Otoge" && windowText != "Ongeki IO Debug")
43 | {
44 | return new OutputData() { Buttons = new byte[10], Aime = new Aime() { Data = new byte[18] } };
45 | }
46 |
47 | byte[] buttons = new byte[] {
48 | Pressed(config.L1),
49 | Pressed(config.L2),
50 | Pressed(config.L3),
51 | Pressed(config.LSide),
52 | Pressed(config.LMenu),
53 | Pressed(config.R1),
54 | Pressed(config.R2),
55 | Pressed(config.R3),
56 | Pressed(config.RSide),
57 | Pressed(config.RMenu),
58 | };
59 | short lever = 0;
60 | byte testPressed = Pressed(config.Test);
61 | byte servicePressed = Pressed(config.Service);
62 | byte coinPressed = Pressed(config.Coin);
63 | if (coinPressed > 0)
64 | {
65 | if (coinAvailable)
66 | {
67 | coinAvailable = false;
68 | }
69 | else
70 | {
71 | coinPressed = 0;
72 | }
73 | }
74 | else
75 | {
76 | coinAvailable = true;
77 | }
78 | OptButtons optButtons = (OptButtons)(testPressed << 0 | servicePressed << 1 | coinPressed << 2);
79 | Aime aime = new Aime()
80 | {
81 | Scan = Pressed(config.Scan),
82 | Data = new byte[18]
83 | };
84 | if (aime.Scan == 1)
85 | {
86 | byte[] bytes = Utils.ReadOrCreateAimeTxt();
87 | aime.ID = bytes;
88 | }
89 | return new OutputData
90 | {
91 | Buttons = buttons,
92 | Lever = lever,
93 | OptButtons = optButtons,
94 | Aime = aime
95 | };
96 | }
97 | private byte Pressed(Keys key)
98 | {
99 |
100 | return User32.GetAsyncKeyState(key) == 0 ? (byte)0 : (byte)1;
101 | }
102 | public class KeyboardIOConfig
103 | {
104 | public Keys L1 { get; set; } = (Keys)(-1);
105 | public Keys L2 { get; set; } = (Keys)(-1);
106 | public Keys L3 { get; set; } = (Keys)(-1);
107 | public Keys LSide { get; set; } = (Keys)(-1);
108 | public Keys LMenu { get; set; } = (Keys)(-1);
109 | public Keys R1 { get; set; } = (Keys)(-1);
110 | public Keys R2 { get; set; } = (Keys)(-1);
111 | public Keys R3 { get; set; } = (Keys)(-1);
112 | public Keys RSide { get; set; } = (Keys)(-1);
113 | public Keys RMenu { get; set; } = (Keys)(-1);
114 | public Keys Test { get; set; } = (Keys)(-1);
115 | public Keys Service { get; set; } = (Keys)(-1);
116 | public Keys Coin { get; set; } = (Keys)(-1);
117 | public Keys Scan { get; set; } = (Keys)(-1);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/MU3Input/IO/MixedIO.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | using static MU3Input.KeyboardIO;
9 |
10 | namespace MU3Input
11 | {
12 | public class MixedIO : IO
13 | {
14 | public override bool IsConnected => true;
15 | public override void Reconnect()
16 | {
17 | foreach (var item in Items)
18 | {
19 | item.Key.Reconnect();
20 | }
21 | }
22 | public Dictionary Items { get; }
23 | public override OutputData Data
24 | {
25 | get
26 | {
27 | var buttons = new byte[10];
28 | for (int i = 0; i < 10; i++)
29 | {
30 | var io = Items.FirstOrDefault(item => item.Value.HasFlag((ControllerPart)(1 << i))).Key;
31 | buttons[i] = io == null ? (byte)0 : io.Data.Buttons[i];
32 | }
33 | short lever = default;
34 | IO aimeIO = null;
35 |
36 | foreach (var item in Items)
37 | {
38 | if (item.Value.HasFlag(ControllerPart.Lever))
39 | lever = item.Key.Data.Lever;
40 | if (item.Value.HasFlag(ControllerPart.Aime))
41 | aimeIO = item.Key;
42 | if (!item.Key.IsConnected)
43 | item.Key.Reconnect();
44 | }
45 | return new OutputData
46 | {
47 | Buttons = buttons,
48 | Lever = lever,
49 | Aime = aimeIO?.Aime ?? default,
50 | OptButtons = Items.Select(item => item.Key.Data.OptButtons).Aggregate((item1, item2) => item1 | item2),
51 | };
52 | }
53 | }
54 |
55 | public MixedIO()
56 | {
57 | Items = new Dictionary();
58 | }
59 |
60 | public IO CreateIO(IOType type, JToken param)
61 | {
62 | switch (type)
63 | {
64 | case IOType.Hid:
65 | return new HidIO(param.ToObject());
66 | case IOType.Udp:
67 | return new UdpIO(param.Value());
68 | case IOType.Tcp:
69 | return new TcpIO(param.Value());
70 | case IOType.Usbmux:
71 | return new UsbmuxIO(param.Value());
72 | case IOType.Keyboard:
73 | return new KeyboardIO(param.ToObject());
74 | default: throw new ArgumentException($"{type}: Unknown IO type");
75 | }
76 | }
77 | public void Add(IO io, ControllerPart part)
78 | {
79 | if (Check(part, Items.Select(i => i.Value).ToArray()))
80 | {
81 | Items.Add(io, part);
82 | }
83 | }
84 | public void Remove(IO io)
85 | {
86 | Items.Remove(io);
87 | }
88 |
89 | public void Modify(IO io, ControllerPart part)
90 | {
91 | var parts = Items.Where(item => item.Key != io).Select(item => item.Value).ToArray();
92 | if (Check(part, parts))
93 | {
94 | Items[io] = part;
95 | }
96 | }
97 |
98 | public bool Check(ControllerPart part1, params ControllerPart[] parts)
99 | {
100 | if (parts.Length == 0) return true;
101 | ControllerPart part2 = parts.Aggregate((p1, p2) => p1 | p2);
102 | return (part1 & part2) == ControllerPart.None;
103 | }
104 |
105 | private uint currentLedData = 0;
106 | public override void SetLed(uint data)
107 | {
108 | currentLedData = data;
109 | foreach (IO io in Items.Keys) io.SetLed(currentLedData);
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/MU3Input/IO/TcpIO.cs:
--------------------------------------------------------------------------------
1 | using SimpleHID.Raw;
2 |
3 | using System;
4 | using System.Collections.ObjectModel;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using System.Net.Sockets;
8 | using System.Threading;
9 |
10 | namespace MU3Input
11 | {
12 | public class TcpIO : IO
13 | {
14 | private string ip = "127.0.0.1";
15 | private int port;
16 | private uint currentLedData = 0;
17 | private bool connecting = false;
18 | private TcpClient client;
19 | private NetworkStream networkStream;
20 | protected OutputData data;
21 |
22 | public TcpIO(int port)
23 | {
24 | this.port = port;
25 | data = new OutputData() { Buttons = new byte[10], Aime = new Aime() { Data = new byte[18] } };
26 | new Thread(PollThread).Start();
27 |
28 | }
29 | public override bool IsConnected => client?.Connected ?? false;
30 | public override OutputData Data => data;
31 | // 重连
32 | public override void Reconnect()
33 | {
34 | if (connecting) return;
35 | Disconnect();
36 | ConnectAsync(ip, port);
37 | //connectTask?.Wait();
38 | }
39 | public void ConnectAsync(string ip, int port)
40 | {
41 | if (connecting) return;
42 | connecting = true;
43 | try
44 | {
45 | var newClient = new TcpClient(ip, port);
46 | networkStream = newClient.GetStream();
47 | client = newClient;
48 | SetLed(currentLedData);
49 | }
50 | catch (Exception)
51 | {
52 | Disconnect();
53 | }
54 | connecting = false;
55 | }
56 | private void Disconnect()
57 | {
58 | if (IsConnected)
59 | {
60 | var tmpClient = client;
61 | var tmpStream = networkStream;
62 | client = null;
63 | networkStream = null;
64 | tmpClient?.Dispose();
65 | tmpStream?.Dispose();
66 | }
67 | }
68 | private byte[] _inBuffer = new byte[32];
69 | private unsafe void PollThread()
70 | {
71 | while (true)
72 | {
73 | if (!IsConnected)
74 | {
75 | Reconnect();
76 | continue;
77 | }
78 | int len = networkStream.Read(_inBuffer, 0, 1);
79 | if (len <= 0)
80 | {
81 | Reconnect();
82 | continue;
83 | }
84 | Receive((MessageType)_inBuffer[0]);
85 | }
86 | }
87 | private unsafe void Receive(MessageType type)
88 | {
89 | if (type == MessageType.ButtonStatus && networkStream.Read(_inBuffer, 0, 2) > 0)
90 | {
91 | int index = _inBuffer[0];
92 | data.Buttons[index] = _inBuffer[1];
93 | }
94 | else if (type == MessageType.MoveLever && networkStream.Read(_inBuffer, 0, 2) > 0)
95 | {
96 | var value = (short)(_inBuffer[1] << 8 | _inBuffer[0]);
97 | data.Lever = value;
98 | }
99 | else if (type == MessageType.Scan && networkStream.Read(_inBuffer, 0, 1) > 0)
100 | {
101 | data.Aime.Scan = _inBuffer[0];
102 | if (data.Aime.Scan == 0)
103 | {
104 |
105 | }
106 | else if (data.Aime.Scan == 1 && networkStream.Read(_inBuffer, 0, 10) > 0)
107 | {
108 | byte[] aimeId = new ArraySegment(_inBuffer, 0, 10).ToArray();
109 | if (aimeId.All(n => n == 255))
110 | {
111 | aimeId = Utils.ReadOrCreateAimeTxt();
112 | }
113 | data.Aime.ID = aimeId;
114 | }
115 | else if (data.Aime.Scan == 2 && networkStream.Read(_inBuffer, 0, 18) > 0)
116 | {
117 | data.Aime.IDm = BitConverter.ToUInt64(_inBuffer, 0);
118 | data.Aime.PMm = BitConverter.ToUInt64(_inBuffer, 8);
119 | data.Aime.SystemCode = BitConverter.ToUInt16(_inBuffer, 16);
120 | }
121 | }
122 | else if (type == MessageType.Test && networkStream.Read(_inBuffer, 0, 1) > 0)
123 | {
124 | if (_inBuffer[1] == 0) data.OptButtons &= ~OptButtons.Test;
125 | else data.OptButtons |= OptButtons.Test;
126 | Debug.WriteLine(Data.OptButtons);
127 | }
128 | else if (type == MessageType.Service && networkStream.Read(_inBuffer, 0, 1) > 0)
129 | {
130 | if (_inBuffer[1] == 0) data.OptButtons &= ~OptButtons.Service;
131 | else data.OptButtons |= OptButtons.Service;
132 | Debug.WriteLine(Data.OptButtons);
133 | }
134 | else if (type == MessageType.RequestValues)
135 | {
136 | SetLed(currentLedData);
137 | SetLever(Data.Lever);
138 | }
139 | // 收到心跳数据直接回传原数据表示在线
140 | else if (type == MessageType.Hello && networkStream.Read(_inBuffer, 0, 1) > 0)
141 | {
142 | networkStream.Write(new byte[] { (byte)MessageType.Hello, _inBuffer[0] }, 0, 2);
143 | }
144 | }
145 |
146 | private void SetLever(short lever)
147 | {
148 | try
149 | {
150 | if (!IsConnected)
151 | return;
152 | networkStream.Write(new byte[] { (byte)MessageType.SetLever }.Concat(BitConverter.GetBytes(lever)).ToArray(), 0, 3);
153 | }
154 | catch
155 | {
156 | return;
157 | }
158 | }
159 |
160 | public override unsafe void SetLed(uint data)
161 | {
162 | try
163 | {
164 | // 缓存led数据将其设置到新连接的设备
165 | currentLedData = data;
166 | if (!IsConnected)
167 | return;
168 | networkStream.Write(new byte[] { (byte)MessageType.SetLed }.Concat(BitConverter.GetBytes(data)).ToArray(), 0, 5);
169 | }
170 | catch
171 | {
172 | return;
173 | }
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/MU3Input/IO/UdpIO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Numerics;
7 | using System.Runtime.InteropServices;
8 | using System.Threading;
9 |
10 | namespace MU3Input
11 | {
12 | public class UdpIO : IO
13 | {
14 | uint currentLedData = 0;
15 | UdpClient client;
16 | IPEndPoint savedEP;
17 | IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
18 | System.Timers.Timer timer = new System.Timers.Timer(1500)
19 | {
20 | AutoReset = false
21 | };
22 | protected OutputData data;
23 |
24 | public UdpIO(int port)
25 | {
26 | data = new OutputData() { Buttons = new byte[10], Aime = new Aime() { Data = new byte[18] } };
27 | client = new UdpClient(port);
28 | timer.Elapsed += Timer_Elapsed;
29 | new Thread(PollThread).Start();
30 | }
31 |
32 | // 一段时间没收到心跳包自动断开以接受新的连接
33 | private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
34 | {
35 | isConnected = false;
36 | savedEP = null;
37 | }
38 |
39 | bool isConnected = false;
40 | public override bool IsConnected => isConnected;
41 | public override OutputData Data => data;
42 | public override void Reconnect() { }
43 |
44 | private void PollThread()
45 | {
46 | while (true)
47 | {
48 | byte[] buffer = client?.Receive(ref remoteEP);
49 | // 如果已连接设备但收到了其他设备的消息则忽略
50 | if (IsConnected && (!remoteEP.Address.Equals(savedEP?.Address))) return;
51 | ParseBuffer(buffer);
52 | }
53 | }
54 |
55 | private unsafe void ParseBuffer(byte[] buffer)
56 | {
57 | if ((buffer?.Length ?? 0) == 0) return;
58 | if (buffer[0] == (byte)MessageType.ButtonStatus && buffer.Length == 3)
59 | {
60 | int index = buffer[1];
61 | data.Buttons[index] = buffer[2];
62 | }
63 | else if (buffer[0] == (byte)MessageType.MoveLever && buffer.Length == 3)
64 | {
65 | var value = (short)(buffer[2] << 8 | buffer[1]);
66 | data.Lever = value;
67 | }
68 | else if (buffer[0] == (byte)MessageType.Scan && (buffer.Length == 2 || buffer.Length == 12 || buffer.Length == 20))
69 | {
70 | data.Aime.Scan = buffer[1];
71 | if (data.Aime.Scan == 0)
72 | {
73 |
74 | }
75 | else if (data.Aime.Scan == 1)
76 | {
77 | byte[] aimeId = new ArraySegment(buffer, 2, 10).ToArray();
78 | if (aimeId.All(n => n == 255))
79 | {
80 | aimeId = Utils.ReadOrCreateAimeTxt();
81 | }
82 | data.Aime.ID = aimeId;
83 | }
84 | else if (data.Aime.Scan == 2)
85 | {
86 | data.Aime.IDm = BitConverter.ToUInt64(buffer, 2);
87 | data.Aime.PMm = BitConverter.ToUInt64(buffer, 10);
88 | data.Aime.SystemCode = BitConverter.ToUInt16(buffer, 18);
89 | }
90 | }
91 | else if (buffer[0] == (byte)MessageType.Test && buffer.Length == 2)
92 | {
93 | if (buffer[1] == 0) data.OptButtons &= ~OptButtons.Test;
94 | else data.OptButtons |= OptButtons.Test;
95 | Debug.WriteLine(Data.OptButtons);
96 | }
97 | else if (buffer[0] == (byte)MessageType.Service && buffer.Length == 2)
98 | {
99 | if (buffer[1] == 0) data.OptButtons &= ~OptButtons.Service;
100 | else data.OptButtons |= OptButtons.Service;
101 | Debug.WriteLine(Data.OptButtons);
102 | }
103 | else if (buffer[0] == (byte)MessageType.RequestValues && buffer.Length == 1)
104 | {
105 | SetLed(currentLedData);
106 | SetLever(Data.Lever);
107 | }
108 | // 收到心跳数据直接回传原数据表示在线,并保存其地址阻止其他设备连接
109 | else if (buffer[0] == (byte)MessageType.Hello && buffer.Length == 2)
110 | {
111 | savedEP = new IPEndPoint(remoteEP.Address, remoteEP.Port);
112 | client.SendAsync(buffer, 2, savedEP);
113 | isConnected = true;
114 | timer.Stop();
115 | timer.Start();
116 | }
117 | }
118 | private void SetLever(short lever)
119 | {
120 | if (savedEP != null)
121 | {
122 | client?.SendAsync(new byte[] { (byte)MessageType.SetLever }.Concat(BitConverter.GetBytes(lever)).ToArray(), 3, savedEP);
123 | }
124 | }
125 |
126 | public override unsafe void SetLed(uint data)
127 | {
128 | currentLedData = data;
129 | if (savedEP != null)
130 | {
131 | client?.SendAsync(new byte[] { (byte)MessageType.SetLed }.Concat(BitConverter.GetBytes(data)).ToArray(), 5, savedEP);
132 | }
133 | }
134 |
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/MU3Input/IOTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Linq;
4 | using System.Reflection.Emit;
5 | using System.Windows.Forms;
6 |
7 | namespace MU3Input
8 | {
9 | public partial class IOTest : Form
10 | {
11 | private IO _io;
12 |
13 | private CheckBox[] _left;
14 | private CheckBox[] _right;
15 |
16 | public IOTest(IO io)
17 | {
18 | InitializeComponent();
19 |
20 | _left = new[] {
21 | lA,
22 | lB,
23 | lC,
24 | lS,
25 | lM,
26 | };
27 |
28 | _right = new[] {
29 | rA,
30 | rB,
31 | rC,
32 | rS,
33 | rM,
34 | };
35 |
36 | _io = io;
37 | }
38 |
39 | public static byte[] StringToByteArray(string hex)
40 | {
41 | var numberChars = hex.Length;
42 | var bytes = new byte[numberChars / 2];
43 | for (var i = 0; i < numberChars; i += 2)
44 | bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
45 | return bytes;
46 | }
47 |
48 | internal void UpdateData()
49 | {
50 | if (!Enabled && Handle == IntPtr.Zero) return;
51 |
52 | try
53 | {
54 | BeginInvoke(new Action(() =>
55 | {
56 |
57 | if (!_io.IsConnected) return;
58 |
59 | for (var i = 0; i < 5; i++)
60 | {
61 | _left[i].Checked = Convert.ToBoolean(_io.Data.Buttons[i]);
62 | _right[i].Checked = Convert.ToBoolean(_io.Data.Buttons[i + 5]);
63 | }
64 |
65 | trackBar1.Value = _io.Lever;
66 |
67 | if (_io.Aime.Scan == 0)
68 | {
69 | label1.Text = "Aime";
70 | textAimiId.Text = "None";
71 | }
72 | else if (_io.Aime.Scan == 1)
73 | {
74 | label1.Text = "AimeID";
75 | textAimiId.Text = BitConverter.ToString(_io.Aime.ID).Replace("-", "");
76 | }
77 | else if (_io.Aime.Scan == 2)
78 | {
79 | label1.Text = "IDm";
80 | textAimiId.Text = "0x" + BitConverter.ToUInt64(BitConverter.GetBytes(_io.Aime.IDm).Reverse().ToArray(), 0).ToString("X16");
81 | }
82 |
83 | lS.BackColor = Color.FromArgb(Mu3IO.LedData[0], Mu3IO.LedData[1], Mu3IO.LedData[2]);
84 | rS.BackColor = Color.FromArgb(Mu3IO.LedData[3], Mu3IO.LedData[4], Mu3IO.LedData[5]);
85 | }));
86 | }
87 | catch
88 | {
89 | // ignored
90 | }
91 | }
92 |
93 | public void SetColor(uint data)
94 | {
95 | try
96 | {
97 | BeginInvoke(new Action(() =>
98 | {
99 | _left[0].BackColor = Color.FromArgb(
100 | (int)((data >> 23) & 1) * 255,
101 | (int)((data >> 19) & 1) * 255,
102 | (int)((data >> 22) & 1) * 255
103 | );
104 | _left[1].BackColor = Color.FromArgb(
105 | (int)((data >> 20) & 1) * 255,
106 | (int)((data >> 21) & 1) * 255,
107 | (int)((data >> 18) & 1) * 255
108 | );
109 | _left[2].BackColor = Color.FromArgb(
110 | (int)((data >> 17) & 1) * 255,
111 | (int)((data >> 16) & 1) * 255,
112 | (int)((data >> 15) & 1) * 255
113 | );
114 | _right[0].BackColor = Color.FromArgb(
115 | (int)((data >> 14) & 1) * 255,
116 | (int)((data >> 13) & 1) * 255,
117 | (int)((data >> 12) & 1) * 255
118 | );
119 | _right[1].BackColor = Color.FromArgb(
120 | (int)((data >> 11) & 1) * 255,
121 | (int)((data >> 10) & 1) * 255,
122 | (int)((data >> 9) & 1) * 255
123 | );
124 | _right[2].BackColor = Color.FromArgb(
125 | (int)((data >> 8) & 1) * 255,
126 | (int)((data >> 7) & 1) * 255,
127 | (int)((data >> 6) & 1) * 255
128 | );
129 | }));
130 | }
131 | catch
132 | {
133 | // ignored
134 | }
135 | }
136 |
137 | private void btnSetOption_Click(object sender, EventArgs e)
138 | {
139 | byte[] aimiId;
140 |
141 | try
142 | {
143 | aimiId = StringToByteArray(textAimiId.Text);
144 | }
145 | catch
146 | {
147 | MessageBox.Show("Invaild id, Id need to be a hex dump of 10 byte data.", "Error");
148 | return;
149 | }
150 |
151 | if (aimiId.Length != 10)
152 | {
153 | MessageBox.Show("Invaild id, Id need to be a hex dump of 10 byte data.");
154 | return;
155 | }
156 |
157 | //_io.SetAimiId(aimiId);
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/MU3Input/IOTest.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/MU3Input/Kernel32.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using System.Text;
3 |
4 | namespace MU3Input
5 | {
6 | public class Kernel32
7 | {
8 | [DllImport("kernel32.dll")]
9 | public static extern long GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
10 | [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
11 | public static extern unsafe void CopyMemory(void* dest, void* src, int count);
12 | [DllImport("kernel32.dll")]
13 | public static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MU3Input/MU3IO.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.IO.MemoryMappedFiles;
3 | using System.Runtime.InteropServices;
4 | using System.Threading.Tasks;
5 |
6 | namespace MU3Input
7 | {
8 | public static class Mu3IO
9 | {
10 | internal static IO IO;
11 | internal static byte[] LedData;
12 | private static IOTest _test;
13 |
14 | private static MemoryMappedFile mmf;
15 | private static MemoryMappedViewAccessor accessor;
16 |
17 | static Mu3IO()
18 | {
19 | var io = new MixedIO();
20 | foreach (var ioConfig in Config.Instance.IO)
21 | {
22 | io.Add(io.CreateIO(ioConfig.Type, ioConfig.Param), ioConfig.Part);
23 | }
24 | IO = io;
25 | _test = new IOTest(io);
26 |
27 | //与mod共享内存以接收LED数据
28 | mmf = MemoryMappedFile.CreateOrOpen("mu3_led_data", 66 * 3);
29 | accessor = mmf.CreateViewAccessor(0, 66 * 3);
30 | LedData = new byte[6];
31 |
32 | Task.Run(() => _test.ShowDialog());
33 | }
34 |
35 | [DllExport(ExportName = "mu3_io_get_api_version")]
36 | public static ushort GetVersion()
37 | {
38 | return 0x0102;
39 | }
40 |
41 | [DllExport(CallingConvention.Cdecl, ExportName = "mu3_io_init")]
42 | public static uint Init()
43 | {
44 | if (Process.GetCurrentProcess().ProcessName != "amdaemon" &&
45 | Process.GetCurrentProcess().ProcessName != "Debug" &&
46 | Process.GetCurrentProcess().ProcessName != "TestSharp" &&
47 | Process.GetCurrentProcess().ProcessName != "Test")
48 | return 1;
49 | else return 0;
50 |
51 | }
52 |
53 | [DllExport(CallingConvention.Cdecl, ExportName = "mu3_io_poll")]
54 | public static uint Poll()
55 | {
56 | if (IO == null)
57 | return 0;
58 |
59 | if (!IO.IsConnected)
60 | {
61 | IO.Reconnect();
62 | }
63 |
64 | int leftBase = 0;
65 | accessor.ReadArray(leftBase, LedData, 0, 3);
66 |
67 | int rightBase = 59 * 3;
68 | accessor.ReadArray(rightBase, LedData, 3, 3);
69 |
70 | _test.UpdateData();
71 |
72 | return 0;
73 | }
74 |
75 | [DllExport(CallingConvention.Cdecl, ExportName = "mu3_io_get_opbtns")]
76 | public static void GetOpButtons(out byte opbtn)
77 | {
78 | if (IO == null || !IO.IsConnected)
79 | {
80 | opbtn = 0;
81 | return;
82 | }
83 |
84 | opbtn = (byte)IO.OptButtonsStatus;
85 | }
86 |
87 | [DllExport(CallingConvention.Cdecl, ExportName = "mu3_io_get_gamebtns")]
88 | public static void GetGameButtons(out byte left, out byte right)
89 | {
90 | if (IO == null || !IO.IsConnected)
91 | {
92 | left = 0;
93 | right = 0;
94 | return;
95 | }
96 |
97 | left = IO.LeftButton;
98 | right = IO.RightButton;
99 | }
100 |
101 | [DllExport(CallingConvention.Cdecl, ExportName = "mu3_io_get_lever")]
102 | public static void GetLever(out short pos)
103 | {
104 | pos = 0;
105 | if (IO == null || !IO.IsConnected)
106 | {
107 | pos = 0;
108 | return;
109 | }
110 |
111 | pos = IO.Lever;
112 | }
113 |
114 | [DllExport(CallingConvention.Cdecl, ExportName = "mu3_io_set_led")]
115 | public static void SetLed(uint data)
116 | {
117 | IO.SetLed(data);
118 | _test.SetColor(data);
119 | }
120 |
121 |
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/MU3Input/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("MU3Input")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("MU3Input")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("a90797a6-c546-4233-a183-453af52319d0")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/MU3Input/User32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Text;
4 | using System.Windows.Forms;
5 |
6 | namespace MU3Input
7 | {
8 | public class User32
9 | {
10 | [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetForegroundWindow")]
11 | public static extern IntPtr GetForegroundWindow();
12 |
13 |
14 | [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetWindowText")]
15 | public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int maxCount);
16 |
17 | [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetAsyncKeyState")]
18 | public static extern int GetAsyncKeyState(Keys vKey);
19 | }
20 | }
--------------------------------------------------------------------------------
/MU3Input/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Numerics;
5 | using System.Reflection;
6 |
7 | namespace MU3Input
8 | {
9 | internal class Utils
10 | {
11 | public static byte[] ReadOrCreateAimeTxt()
12 | {
13 | byte[] aimeId;
14 | var location = Assembly.GetCallingAssembly().Location;
15 | string directoryName = Path.GetDirectoryName(location);
16 | string deviceDirectory = Path.Combine(directoryName, "DEVICE");
17 | string aimeIdPath = Path.Combine(deviceDirectory, "aime.txt");
18 | try
19 | {
20 | var id = BigInteger.Parse(File.ReadAllText(aimeIdPath));
21 | var bytes = id.ToBcd();
22 | aimeId = new byte[10 - bytes.Length].Concat(bytes).ToArray();
23 | }
24 | catch (Exception)
25 | {
26 | Random random = new Random();
27 | byte[] temp = new byte[10];
28 | random.NextBytes(temp);
29 | var id = new BigInteger(temp);
30 | if (id < -1) id = -(id + 1);
31 | id = id % BigInteger.Parse("99999999999999999999");
32 | if (!Directory.Exists(deviceDirectory))
33 | {
34 | Directory.CreateDirectory(deviceDirectory);
35 | }
36 | var bytes = id.ToBcd();
37 | aimeId = new byte[10 - bytes.Length].Concat(bytes).ToArray();
38 | File.WriteAllText(aimeIdPath, id.ToString());
39 | }
40 | return aimeId;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### MU3Input `MU3Input.sln`
2 | #### IO library to use with segatools
3 | Usage:
4 | - Copy `MU3Input.dll` into game folder
5 | - Open segatools.ini and add following lines:
6 | ```ini
7 | [mu3io]
8 | path=MU3Input.dll
9 |
10 | [aimeio]
11 | path=MU3Input.dll
12 | ```
13 |
14 | You can use Jetbrains Rider or Visual Studio to compile.
15 |
16 | Note:
17 | - My lever is a non-linear potentiometer, so it has correction code in `Lever` property of `HidIO.cs`, You may want to change it or remove it.
18 |
19 | ### mu3controller `mu3controller\ `
20 | #### Arduino Leonardo firmware to use with above IO library.
21 | I'm using CLion to develop this, for CLion you will need to install platform io support plugin and run
22 | ```
23 | pio -f -c clion init --ide clion
24 | ```
25 | Note:
26 | - You can change pin settings in `src\components\ongeki_hardware.cpp`
--------------------------------------------------------------------------------
/SegaToolsPatch/0001-Add-led-code.patch:
--------------------------------------------------------------------------------
1 | From 786c9ca98942dd9f88ba10036d1579d81fabcd7a Mon Sep 17 00:00:00 2001
2 | From: GEEKiDoS
3 | Date: Fri, 1 Oct 2021 14:57:41 +0800
4 | Subject: [PATCH] Add led code
5 |
6 | ---
7 | board/io4.c | 2 +-
8 | board/io4.h | 1 +
9 | mu3hook/io4.c | 13 +++++++++++++
10 | mu3hook/mu3-dll.c | 3 +++
11 | mu3hook/mu3-dll.h | 1 +
12 | mu3hook/mu3hook.def | 1 +
13 | mu3io/mu3io.c | 4 ++++
14 | mu3io/mu3io.h | 2 ++
15 | 8 files changed, 26 insertions(+), 1 deletion(-)
16 |
17 | diff --git a/board/io4.c b/board/io4.c
18 | index efad62f..9cdb054 100644
19 | --- a/board/io4.c
20 | +++ b/board/io4.c
21 | @@ -223,7 +223,7 @@ static HRESULT io4_handle_write(struct irp *irp)
22 |
23 | case IO4_CMD_SET_GENERAL_OUTPUT:
24 | dprintf("USB I/O: GPIO Out\n");
25 | -
26 | + io4_ops->gpio_out(out.payload);
27 | return S_OK;
28 |
29 | case IO4_CMD_SET_PWM_OUTPUT:
30 | diff --git a/board/io4.h b/board/io4.h
31 | index 1a6cc05..87cd154 100644
32 | --- a/board/io4.h
33 | +++ b/board/io4.h
34 | @@ -24,6 +24,7 @@ struct io4_state {
35 |
36 | struct io4_ops {
37 | HRESULT (*poll)(void *ctx, struct io4_state *state);
38 | + HRESULT (*gpio_out)(uint8_t *payload);
39 | };
40 |
41 | HRESULT io4_hook_init(
42 | diff --git a/mu3hook/io4.c b/mu3hook/io4.c
43 | index 7edcb0c..d7df696 100644
44 | --- a/mu3hook/io4.c
45 | +++ b/mu3hook/io4.c
46 | @@ -11,9 +11,11 @@
47 | #include "util/dprintf.h"
48 |
49 | static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state);
50 | +static HRESULT mu3_io4_gpio_out(uint8_t *payload);
51 |
52 | static const struct io4_ops mu3_io4_ops = {
53 | .poll = mu3_io4_poll,
54 | + .gpio_out = mu3_io4_gpio_out,
55 | };
56 |
57 | HRESULT mu3_io4_hook_init(const struct io4_config *cfg)
58 | @@ -118,3 +120,14 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state)
59 |
60 | return S_OK;
61 | }
62 | +
63 | +static HRESULT mu3_io4_gpio_out(uint8_t *payload)
64 | +{
65 | + if (mu3_dll.set_led)
66 | + {
67 | + uint32_t data = payload[0] << 16 | payload[1] << 8 | payload[2];
68 | + mu3_dll.set_led(data);
69 | + }
70 | +
71 | + return S_OK;
72 | +}
73 | diff --git a/mu3hook/mu3-dll.c b/mu3hook/mu3-dll.c
74 | index 9e8e93e..6abf26c 100644
75 | --- a/mu3hook/mu3-dll.c
76 | +++ b/mu3hook/mu3-dll.c
77 | @@ -24,6 +24,9 @@ const struct dll_bind_sym mu3_dll_syms[] = {
78 | }, {
79 | .sym = "mu3_io_get_lever",
80 | .off = offsetof(struct mu3_dll, get_lever),
81 | + }, {
82 | + .sym = "mu3_io_set_led",
83 | + .off = offsetof(struct mu3_dll, set_led),
84 | }
85 | };
86 |
87 | diff --git a/mu3hook/mu3-dll.h b/mu3hook/mu3-dll.h
88 | index 41f280f..550772c 100644
89 | --- a/mu3hook/mu3-dll.h
90 | +++ b/mu3hook/mu3-dll.h
91 | @@ -11,6 +11,7 @@ struct mu3_dll {
92 | void (*get_opbtns)(uint8_t *opbtn);
93 | void (*get_gamebtns)(uint8_t *left, uint8_t *right);
94 | void (*get_lever)(int16_t *pos);
95 | + void (*set_led)(uint32_t info);
96 | };
97 |
98 | struct mu3_dll_config {
99 | diff --git a/mu3hook/mu3hook.def b/mu3hook/mu3hook.def
100 | index e7367fb..8b03862 100644
101 | --- a/mu3hook/mu3hook.def
102 | +++ b/mu3hook/mu3hook.def
103 | @@ -18,3 +18,4 @@ EXPORTS
104 | mu3_io_get_opbtns
105 | mu3_io_init
106 | mu3_io_poll
107 | + mu3_io_set_led
108 | diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c
109 | index 0bbd37f..bcbc668 100644
110 | --- a/mu3io/mu3io.c
111 | +++ b/mu3io/mu3io.c
112 | @@ -146,3 +146,7 @@ void mu3_io_get_lever(int16_t *pos)
113 | *pos = mu3_lever_xpos;
114 | }
115 | }
116 | +
117 | +void mu3_io_set_led(uint32_t led)
118 | +{
119 | +}
120 | diff --git a/mu3io/mu3io.h b/mu3io/mu3io.h
121 | index d46a475..e540a3d 100644
122 | --- a/mu3io/mu3io.h
123 | +++ b/mu3io/mu3io.h
124 | @@ -82,3 +82,5 @@ void mu3_io_get_gamebtns(uint8_t *left, uint8_t *right);
125 | Minimum API version: 0x0100 */
126 |
127 | void mu3_io_get_lever(int16_t *pos);
128 | +
129 | +void mu3_io_set_led(uint32_t led);
130 | --
131 | 2.30.1.windows.1
132 |
133 |
--------------------------------------------------------------------------------
/Test/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Test/Program.cs:
--------------------------------------------------------------------------------
1 | using MU3Input;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace Test
11 | {
12 | internal class Program
13 | {
14 | static unsafe void Main(string[] args)
15 | {
16 | ulong id = 0;
17 | ushort code = 0;
18 | IntPtr aimeid = Marshal.AllocHGlobal(10);
19 | Mu3IO.Init();
20 | AimiIO.Init();
21 | while (true)
22 | {
23 | Task.Delay(1).Wait();
24 | Mu3IO.Poll();
25 | Mu3IO.GetGameButtons(out byte left, out byte right);
26 | AimiIO.GetFelicaId(0, &id);
27 | AimiIO.GetFelicaPm(0, &id);
28 | AimiIO.GetFelicaSystemCode(0, &code);
29 | AimiIO.GetAimeId(0, (byte*)aimeid,10);
30 | }
31 | Console.ReadKey();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Test/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Test")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Test")]
13 | [assembly: AssemblyCopyright("Copyright © 2022")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("678bbc0e-4096-4064-bd0a-d2b311141111")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Test/Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {678BBC0E-4096-4064-BD0A-D2B311141111}
8 | Exe
9 | Test
10 | Test
11 | v4.7.2
12 | 512
13 | true
14 | true
15 | publish\
16 | true
17 | Disk
18 | false
19 | Foreground
20 | 7
21 | Days
22 | false
23 | false
24 | true
25 | 0
26 | 1.0.0.%2a
27 | false
28 | false
29 | true
30 |
31 |
32 | true
33 | bin\x64\Debug\
34 | DEBUG;TRACE
35 | full
36 | x64
37 | 7.3
38 | prompt
39 | true
40 | true
41 |
42 |
43 | bin\x64\Release\
44 | TRACE
45 | true
46 | pdbonly
47 | x64
48 | 7.3
49 | prompt
50 | true
51 | true
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {a90797a6-c546-4233-a183-453af52319d0}
73 | MU3Input
74 |
75 |
76 |
77 |
78 | False
79 | Microsoft .NET Framework 4.7.2 %28x86 和 x64%29
80 | true
81 |
82 |
83 | False
84 | .NET Framework 3.5 SP1
85 | false
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/mu3controller/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | CMakeLists.txt
3 | CMakeListsPrivate.txt
4 | cmake-build-*/
5 |
--------------------------------------------------------------------------------
/mu3controller/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/mu3controller/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/mu3controller/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/mu3controller/.idea/untitled1.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/mu3controller/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/mu3controller/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/Due.h:
--------------------------------------------------------------------------------
1 | // redefine some stuff so code works on Due
2 | // http://arduino.cc/forum/index.php?&topic=153761.0
3 |
4 | #ifndef Due_h
5 | #define Due_h
6 |
7 | #if defined(__SAM3X8E__)
8 | #define PROGMEM
9 | #define pgm_read_byte(x) (*((char *)x))
10 | // #define pgm_read_word(x) (*((short *)(x & 0xfffffffe)))
11 | #define pgm_read_word(x) ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
12 | #define pgm_read_byte_near(x) (*((char *)x))
13 | #define pgm_read_byte_far(x) (*((char *)x))
14 | // #define pgm_read_word_near(x) (*((short *)(x & 0xfffffffe))
15 | // #define pgm_read_word_far(x) (*((short *)(x & 0xfffffffe)))
16 | #define pgm_read_word_near(x) ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
17 | #define pgm_read_word_far(x) ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x))))
18 | #define PSTR(x) x
19 | #if defined F
20 | #undef F
21 | #endif
22 | #define F(X) (X)
23 | #endif
24 |
25 | #endif
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Software License Agreement (BSD License)
2 |
3 | Copyright (c) 2013-2014, Don Coleman
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holders nor the
17 | names of its contributors may be used to endorse or promote products
18 | derived from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY
21 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/MifareClassic.h:
--------------------------------------------------------------------------------
1 | #ifndef MifareClassic_h
2 | #define MifareClassic_h
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | class MifareClassic
10 | {
11 | public:
12 | MifareClassic(PN532& nfcShield);
13 | ~MifareClassic();
14 | NfcTag read(byte *uid, unsigned int uidLength);
15 | boolean write(NdefMessage& ndefMessage, byte *uid, unsigned int uidLength);
16 | boolean formatNDEF(byte * uid, unsigned int uidLength);
17 | boolean formatMifare(byte * uid, unsigned int uidLength);
18 | private:
19 | PN532* _nfcShield;
20 | int getBufferSize(int messageLength);
21 | int getNdefStartIndex(byte *data);
22 | bool decodeTlv(byte *data, int &messageLength, int &messageStartIndex);
23 | };
24 |
25 | #endif
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/MifareUltralight.h:
--------------------------------------------------------------------------------
1 | #ifndef MifareUltralight_h
2 | #define MifareUltralight_h
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class MifareUltralight
9 | {
10 | public:
11 | MifareUltralight(PN532& nfcShield);
12 | ~MifareUltralight();
13 | NfcTag read(byte *uid, unsigned int uidLength);
14 | boolean write(NdefMessage& ndefMessage, byte *uid, unsigned int uidLength);
15 | boolean clean();
16 | private:
17 | PN532* nfc;
18 | unsigned int tagCapacity;
19 | unsigned int messageLength;
20 | unsigned int bufferSize;
21 | unsigned int ndefStartIndex;
22 | boolean isUnformatted();
23 | void readCapabilityContainer();
24 | void findNdefMessage();
25 | void calculateBufferSize();
26 | };
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/Ndef.cpp:
--------------------------------------------------------------------------------
1 | #include "Ndef.h"
2 |
3 | // Borrowed from Adafruit_NFCShield_I2C
4 | void PrintHex(const byte * data, const long numBytes)
5 | {
6 | uint32_t szPos;
7 | for (szPos=0; szPos < numBytes; szPos++)
8 | {
9 | Serial.print("0x");
10 | // Append leading 0 for small values
11 | if (data[szPos] <= 0xF)
12 | Serial.print("0");
13 | Serial.print(data[szPos]&0xff, HEX);
14 | if ((numBytes > 1) && (szPos != numBytes - 1))
15 | {
16 | Serial.print(" ");
17 | }
18 | }
19 | Serial.println("");
20 | }
21 |
22 | // Borrowed from Adafruit_NFCShield_I2C
23 | void PrintHexChar(const byte * data, const long numBytes)
24 | {
25 | uint32_t szPos;
26 | for (szPos=0; szPos < numBytes; szPos++)
27 | {
28 | // Append leading 0 for small values
29 | if (data[szPos] <= 0xF)
30 | Serial.print("0");
31 | Serial.print(data[szPos], HEX);
32 | if ((numBytes > 1) && (szPos != numBytes - 1))
33 | {
34 | Serial.print(" ");
35 | }
36 | }
37 | Serial.print(" ");
38 | for (szPos=0; szPos < numBytes; szPos++)
39 | {
40 | if (data[szPos] <= 0x1F)
41 | Serial.print(".");
42 | else
43 | Serial.print((char)data[szPos]);
44 | }
45 | Serial.println("");
46 | }
47 |
48 | // Note if buffer % blockSize != 0, last block will not be written
49 | void DumpHex(const byte * data, const long numBytes, const unsigned int blockSize)
50 | {
51 | int i;
52 | for (i = 0; i < (numBytes / blockSize); i++)
53 | {
54 | PrintHexChar(data, blockSize);
55 | data += blockSize;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/Ndef.h:
--------------------------------------------------------------------------------
1 | #ifndef Ndef_h
2 | #define Ndef_h
3 |
4 | /* NOTE: To use the Ndef library in your code, don't include Ndef.h
5 | See README.md for details on which files to include in your sketch.
6 | */
7 |
8 | #include
9 |
10 | #define NULL (void *)0
11 |
12 | void PrintHex(const byte *data, const long numBytes);
13 | void PrintHexChar(const byte *data, const long numBytes);
14 | void DumpHex(const byte *data, const long numBytes, const int blockSize);
15 |
16 | #endif
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NdefMessage.h:
--------------------------------------------------------------------------------
1 | #ifndef NdefMessage_h
2 | #define NdefMessage_h
3 |
4 | #include
5 | #include
6 |
7 | #define MAX_NDEF_RECORDS 4
8 |
9 | class NdefMessage
10 | {
11 | public:
12 | NdefMessage(void);
13 | NdefMessage(const byte *data, const int numBytes);
14 | NdefMessage(const NdefMessage& rhs);
15 | ~NdefMessage();
16 | NdefMessage& operator=(const NdefMessage& rhs);
17 |
18 | int getEncodedSize(); // need so we can pass array to encode
19 | void encode(byte *data);
20 |
21 | boolean addRecord(NdefRecord& record);
22 | void addMimeMediaRecord(String mimeType, String payload);
23 | void addMimeMediaRecord(String mimeType, byte *payload, int payloadLength);
24 | void addTextRecord(String text);
25 | void addTextRecord(String text, String encoding);
26 | void addUriRecord(String uri);
27 | void addEmptyRecord();
28 |
29 | unsigned int getRecordCount();
30 | NdefRecord getRecord(int index);
31 | NdefRecord operator[](int index);
32 |
33 | void print();
34 | private:
35 | NdefRecord _records[MAX_NDEF_RECORDS];
36 | unsigned int _recordCount;
37 | };
38 |
39 | #endif
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NdefRecord.h:
--------------------------------------------------------------------------------
1 | #ifndef NdefRecord_h
2 | #define NdefRecord_h
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #define TNF_EMPTY 0x0
9 | #define TNF_WELL_KNOWN 0x01
10 | #define TNF_MIME_MEDIA 0x02
11 | #define TNF_ABSOLUTE_URI 0x03
12 | #define TNF_EXTERNAL_TYPE 0x04
13 | #define TNF_UNKNOWN 0x05
14 | #define TNF_UNCHANGED 0x06
15 | #define TNF_RESERVED 0x07
16 |
17 | class NdefRecord
18 | {
19 | public:
20 | NdefRecord();
21 | NdefRecord(const NdefRecord& rhs);
22 | ~NdefRecord();
23 | NdefRecord& operator=(const NdefRecord& rhs);
24 |
25 | int getEncodedSize();
26 | void encode(byte *data, bool firstRecord, bool lastRecord);
27 |
28 | unsigned int getTypeLength();
29 | int getPayloadLength();
30 | unsigned int getIdLength();
31 |
32 | byte getTnf();
33 | void getType(byte *type);
34 | void getPayload(byte *payload);
35 | void getId(byte *id);
36 |
37 | // convenience methods
38 | String getType();
39 | String getId();
40 |
41 | void setTnf(byte tnf);
42 | void setType(const byte *type, const unsigned int numBytes);
43 | void setPayload(const byte *payload, const int numBytes);
44 | void setId(const byte *id, const unsigned int numBytes);
45 |
46 | void print();
47 | private:
48 | byte getTnfByte(bool firstRecord, bool lastRecord);
49 | byte _tnf; // 3 bit
50 | unsigned int _typeLength;
51 | int _payloadLength;
52 | unsigned int _idLength;
53 | byte *_type;
54 | byte *_payload;
55 | byte *_id;
56 | };
57 |
58 | #endif
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NfcAdapter.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | NfcAdapter::NfcAdapter(PN532Interface &interface)
4 | {
5 | shield = new PN532(interface);
6 | }
7 |
8 | NfcAdapter::~NfcAdapter(void)
9 | {
10 | delete shield;
11 | }
12 |
13 | void NfcAdapter::begin(boolean verbose)
14 | {
15 | shield->begin();
16 |
17 | uint32_t versiondata = shield->getFirmwareVersion();
18 |
19 | if (! versiondata)
20 | {
21 | Serial.print(F("Didn't find PN53x board"));
22 | while (1); // halt
23 | }
24 |
25 | if (verbose)
26 | {
27 | Serial.print(F("Found chip PN5")); Serial.println((versiondata>>24) & 0xFF, HEX);
28 | Serial.print(F("Firmware ver. ")); Serial.print((versiondata>>16) & 0xFF, DEC);
29 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
30 | }
31 | // configure board to read RFID tags
32 | shield->SAMConfig();
33 | }
34 |
35 | boolean NfcAdapter::tagPresent(unsigned long timeout)
36 | {
37 | uint8_t success;
38 | uidLength = 0;
39 |
40 | if (timeout == 0)
41 | {
42 | success = shield->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, (uint8_t*)&uidLength);
43 | }
44 | else
45 | {
46 | success = shield->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, (uint8_t*)&uidLength, timeout);
47 | }
48 | return success;
49 | }
50 |
51 | boolean NfcAdapter::erase()
52 | {
53 | boolean success;
54 | NdefMessage message = NdefMessage();
55 | message.addEmptyRecord();
56 | return write(message);
57 | }
58 |
59 | boolean NfcAdapter::format()
60 | {
61 | boolean success;
62 | if (uidLength == 4)
63 | {
64 | MifareClassic mifareClassic = MifareClassic(*shield);
65 | success = mifareClassic.formatNDEF(uid, uidLength);
66 | }
67 | else
68 | {
69 | Serial.print(F("Unsupported Tag."));
70 | success = false;
71 | }
72 | return success;
73 | }
74 |
75 | boolean NfcAdapter::clean()
76 | {
77 | uint8_t type = guessTagType();
78 |
79 | if (type == TAG_TYPE_MIFARE_CLASSIC)
80 | {
81 | #ifdef NDEF_DEBUG
82 | Serial.println(F("Cleaning Mifare Classic"));
83 | #endif
84 | MifareClassic mifareClassic = MifareClassic(*shield);
85 | return mifareClassic.formatMifare(uid, uidLength);
86 | }
87 | else if (type == TAG_TYPE_2)
88 | {
89 | #ifdef NDEF_DEBUG
90 | Serial.println(F("Cleaning Mifare Ultralight"));
91 | #endif
92 | MifareUltralight ultralight = MifareUltralight(*shield);
93 | return ultralight.clean();
94 | }
95 | else
96 | {
97 | Serial.print(F("No driver for card type "));Serial.println(type);
98 | return false;
99 | }
100 |
101 | }
102 |
103 |
104 | NfcTag NfcAdapter::read()
105 | {
106 | uint8_t type = guessTagType();
107 |
108 | if (type == TAG_TYPE_MIFARE_CLASSIC)
109 | {
110 | #ifdef NDEF_DEBUG
111 | Serial.println(F("Reading Mifare Classic"));
112 | #endif
113 | MifareClassic mifareClassic = MifareClassic(*shield);
114 | return mifareClassic.read(uid, uidLength);
115 | }
116 | else if (type == TAG_TYPE_2)
117 | {
118 | #ifdef NDEF_DEBUG
119 | Serial.println(F("Reading Mifare Ultralight"));
120 | #endif
121 | MifareUltralight ultralight = MifareUltralight(*shield);
122 | return ultralight.read(uid, uidLength);
123 | }
124 | else if (type == TAG_TYPE_UNKNOWN)
125 | {
126 | Serial.print(F("Can not determine tag type"));
127 | return NfcTag(uid, uidLength);
128 | }
129 | else
130 | {
131 | Serial.print(F("No driver for card type "));Serial.println(type);
132 | // TODO should set type here
133 | return NfcTag(uid, uidLength);
134 | }
135 |
136 | }
137 |
138 | boolean NfcAdapter::write(NdefMessage& ndefMessage)
139 | {
140 | boolean success;
141 | uint8_t type = guessTagType();
142 |
143 | if (type == TAG_TYPE_MIFARE_CLASSIC)
144 | {
145 | #ifdef NDEF_DEBUG
146 | Serial.println(F("Writing Mifare Classic"));
147 | #endif
148 | MifareClassic mifareClassic = MifareClassic(*shield);
149 | success = mifareClassic.write(ndefMessage, uid, uidLength);
150 | }
151 | else if (type == TAG_TYPE_2)
152 | {
153 | #ifdef NDEF_DEBUG
154 | Serial.println(F("Writing Mifare Ultralight"));
155 | #endif
156 | MifareUltralight mifareUltralight = MifareUltralight(*shield);
157 | success = mifareUltralight.write(ndefMessage, uid, uidLength);
158 | }
159 | else if (type == TAG_TYPE_UNKNOWN)
160 | {
161 | Serial.print(F("Can not determine tag type"));
162 | success = false;
163 | }
164 | else
165 | {
166 | Serial.print(F("No driver for card type "));Serial.println(type);
167 | success = false;
168 | }
169 |
170 | return success;
171 | }
172 |
173 | // TODO this should return a Driver MifareClassic, MifareUltralight, Type 4, Unknown
174 | // Guess Tag Type by looking at the ATQA and SAK values
175 | // Need to follow spec for Card Identification. Maybe AN1303, AN1305 and ???
176 | unsigned int NfcAdapter::guessTagType()
177 | {
178 |
179 | // 4 byte id - Mifare Classic
180 | // - ATQA 0x4 && SAK 0x8
181 | // 7 byte id
182 | // - ATQA 0x44 && SAK 0x8 - Mifare Classic
183 | // - ATQA 0x44 && SAK 0x0 - Mifare Ultralight NFC Forum Type 2
184 | // - ATQA 0x344 && SAK 0x20 - NFC Forum Type 4
185 |
186 | if (uidLength == 4)
187 | {
188 | return TAG_TYPE_MIFARE_CLASSIC;
189 | }
190 | else
191 | {
192 | return TAG_TYPE_2;
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NfcAdapter.h:
--------------------------------------------------------------------------------
1 | #ifndef NfcAdapter_h
2 | #define NfcAdapter_h
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | // Drivers
10 | #include
11 | #include
12 |
13 | #define TAG_TYPE_MIFARE_CLASSIC (0)
14 | #define TAG_TYPE_1 (1)
15 | #define TAG_TYPE_2 (2)
16 | #define TAG_TYPE_3 (3)
17 | #define TAG_TYPE_4 (4)
18 | #define TAG_TYPE_UNKNOWN (99)
19 |
20 | #define IRQ (2)
21 | #define RESET (3) // Not connected by default on the NFC Shield
22 |
23 | class NfcAdapter {
24 | public:
25 | NfcAdapter(PN532Interface &interface);
26 |
27 | ~NfcAdapter(void);
28 | void begin(boolean verbose=true);
29 | boolean tagPresent(unsigned long timeout=0); // tagAvailable
30 | NfcTag read();
31 | boolean write(NdefMessage& ndefMessage);
32 | // erase tag by writing an empty NDEF record
33 | boolean erase();
34 | // format a tag as NDEF
35 | boolean format();
36 | // reset tag back to factory state
37 | boolean clean();
38 | private:
39 | PN532* shield;
40 | byte uid[7]; // Buffer to store the returned UID
41 | unsigned int uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
42 | unsigned int guessTagType();
43 | };
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NfcDriver.h:
--------------------------------------------------------------------------------
1 | // eventually the NFC drivers should extend this class
2 | class NfcDriver
3 | {
4 | public:
5 | virtual NfcTag read(uint8_t * uid, int uidLength) = 0;
6 | virtual boolean write(NdefMessage& message, uint8_t * uid, int uidLength) = 0;
7 | // erase()
8 | // format()
9 | }
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NfcTag.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | NfcTag::NfcTag()
4 | {
5 | _uid = 0;
6 | _uidLength = 0;
7 | _tagType = "Unknown";
8 | _ndefMessage = (NdefMessage*)NULL;
9 | }
10 |
11 | NfcTag::NfcTag(byte *uid, unsigned int uidLength)
12 | {
13 | _uid = uid;
14 | _uidLength = uidLength;
15 | _tagType = "Unknown";
16 | _ndefMessage = (NdefMessage*)NULL;
17 | }
18 |
19 | NfcTag::NfcTag(byte *uid, unsigned int uidLength, String tagType)
20 | {
21 | _uid = uid;
22 | _uidLength = uidLength;
23 | _tagType = tagType;
24 | _ndefMessage = (NdefMessage*)NULL;
25 | }
26 |
27 | NfcTag::NfcTag(byte *uid, unsigned int uidLength, String tagType, NdefMessage& ndefMessage)
28 | {
29 | _uid = uid;
30 | _uidLength = uidLength;
31 | _tagType = tagType;
32 | _ndefMessage = new NdefMessage(ndefMessage);
33 | }
34 |
35 | // I don't like this version, but it will use less memory
36 | NfcTag::NfcTag(byte *uid, unsigned int uidLength, String tagType, const byte *ndefData, const int ndefDataLength)
37 | {
38 | _uid = uid;
39 | _uidLength = uidLength;
40 | _tagType = tagType;
41 | _ndefMessage = new NdefMessage(ndefData, ndefDataLength);
42 | }
43 |
44 | NfcTag::~NfcTag()
45 | {
46 | delete _ndefMessage;
47 | }
48 |
49 | NfcTag& NfcTag::operator=(const NfcTag& rhs)
50 | {
51 | if (this != &rhs)
52 | {
53 | delete _ndefMessage;
54 | _uid = rhs._uid;
55 | _uidLength = rhs._uidLength;
56 | _tagType = rhs._tagType;
57 | // TODO do I need a copy here?
58 | _ndefMessage = rhs._ndefMessage;
59 | }
60 | return *this;
61 | }
62 |
63 | uint8_t NfcTag::getUidLength()
64 | {
65 | return _uidLength;
66 | }
67 |
68 | void NfcTag::getUid(byte *uid, unsigned int uidLength)
69 | {
70 | memcpy(uid, _uid, _uidLength < uidLength ? _uidLength : uidLength);
71 | }
72 |
73 | String NfcTag::getUidString()
74 | {
75 | String uidString = "";
76 | for (int i = 0; i < _uidLength; i++)
77 | {
78 | if (i > 0)
79 | {
80 | uidString += " ";
81 | }
82 |
83 | if (_uid[i] < 0xF)
84 | {
85 | uidString += "0";
86 | }
87 |
88 | uidString += String((unsigned int)_uid[i], (unsigned char)HEX);
89 | }
90 | uidString.toUpperCase();
91 | return uidString;
92 | }
93 |
94 | String NfcTag::getTagType()
95 | {
96 | return _tagType;
97 | }
98 |
99 | boolean NfcTag::hasNdefMessage()
100 | {
101 | return (_ndefMessage != NULL);
102 | }
103 |
104 | NdefMessage NfcTag::getNdefMessage()
105 | {
106 | return *_ndefMessage;
107 | }
108 |
109 | void NfcTag::print()
110 | {
111 | Serial.print(F("NFC Tag - "));Serial.println(_tagType);
112 | Serial.print(F("UID "));Serial.println(getUidString());
113 | if (_ndefMessage == NULL)
114 | {
115 | Serial.println(F("\nNo NDEF Message"));
116 | }
117 | else
118 | {
119 | _ndefMessage->print();
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/NfcTag.h:
--------------------------------------------------------------------------------
1 | #ifndef NfcTag_h
2 | #define NfcTag_h
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class NfcTag
9 | {
10 | public:
11 | NfcTag();
12 | NfcTag(byte *uid, unsigned int uidLength);
13 | NfcTag(byte *uid, unsigned int uidLength, String tagType);
14 | NfcTag(byte *uid, unsigned int uidLength, String tagType, NdefMessage& ndefMessage);
15 | NfcTag(byte *uid, unsigned int uidLength, String tagType, const byte *ndefData, const int ndefDataLength);
16 | ~NfcTag(void);
17 | NfcTag& operator=(const NfcTag& rhs);
18 | uint8_t getUidLength();
19 | void getUid(byte *uid, unsigned int uidLength);
20 | String getUidString();
21 | String getTagType();
22 | boolean hasNdefMessage();
23 | NdefMessage getNdefMessage();
24 | void print();
25 | private:
26 | byte *_uid;
27 | unsigned int _uidLength;
28 | String _tagType; // Mifare Classic, NFC Forum Type {1,2,3,4}, Unknown
29 | NdefMessage* _ndefMessage;
30 | // TODO capacity
31 | // TODO isFormatted
32 | };
33 |
34 | #endif
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/README.md:
--------------------------------------------------------------------------------
1 | # NDEF Library for Arduino
2 |
3 | Read and Write NDEF messages on NFC Tags with Arduino.
4 |
5 | NFC Data Exchange Format (NDEF) is a common data format that operates across all NFC devices, regardless of the underlying tag or device technology.
6 |
7 | This code works with the [Adafruit NFC Shield](https://www.adafruit.com/products/789), [Seeed Studio NFC Shield v2.0](http://www.seeedstudio.com/depot/nfc-shield-v20-p-1370.html) and the [Seeed Studio NFC Shield](http://www.seeedstudio.com/depot/nfc-shield-p-916.html?cPath=73). The library supports I2C for the Adafruit shield and SPI with the Seeed shields. The Adafruit Shield can also be modified to use SPI. It should also work with the [Adafruit NFC Breakout Board](https://www.adafruit.com/products/364).
8 |
9 | ### Supports
10 | - Reading from Mifare Classic Tags with 4 byte UIDs.
11 | - Writing to Mifare Classic Tags with 4 byte UIDs.
12 | - Reading from Mifare Ultralight tags.
13 | - Writing to Mifare Ultralight tags.
14 | - Peer to Peer with the Seeed Studio shield
15 |
16 | ### Requires
17 |
18 | [Yihui Xiong's PN532 Library](https://github.com/Seeed-Studio/PN532)
19 |
20 | ## Getting Started
21 |
22 | To use the Ndef library in your code, include the following in your sketch
23 |
24 | For the Adafruit Shield using I2C
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | PN532_I2C pn532_i2c(Wire);
32 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
33 |
34 | For the Seeed Shield using SPI
35 |
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | PN532_SPI pn532spi(SPI, 10);
42 | NfcAdapter nfc = NfcAdapter(pn532spi);
43 |
44 | ### NfcAdapter
45 |
46 | The user interacts with the NfcAdapter to read and write NFC tags using the NFC shield.
47 |
48 | Read a message from a tag
49 |
50 | if (nfc.tagPresent()) {
51 | NfcTag tag = nfc.read();
52 | tag.print();
53 | }
54 |
55 | Write a message to a tag
56 |
57 | if (nfc.tagPresent()) {
58 | NdefMessage message = NdefMessage();
59 | message.addTextRecord("Hello, Arduino!");
60 | success = nfc.write(message);
61 | }
62 |
63 | Erase a tag. Tags are erased by writing an empty NDEF message. Tags are not zeroed out the old data may still be read off a tag using an application like [NXP's TagInfo](https://play.google.com/store/apps/details?id=com.nxp.taginfolite&hl=en).
64 |
65 | if (nfc.tagPresent()) {
66 | success = nfc.erase();
67 | }
68 |
69 |
70 | Format a Mifare Classic tag as NDEF.
71 |
72 | if (nfc.tagPresent()) {
73 | success = nfc.format();
74 | }
75 |
76 |
77 | Clean a tag. Cleaning resets a tag back to a factory-like state. For Mifare Classic, tag is zeroed and reformatted as Mifare Classic (non-NDEF). For Mifare Ultralight, the tag is zeroed and left empty.
78 |
79 | if (nfc.tagPresent()) {
80 | success = nfc.clean();
81 | }
82 |
83 |
84 | ### NfcTag
85 |
86 | Reading a tag with the shield, returns a NfcTag object. The NfcTag object contains meta data about the tag UID, technology, size. When an NDEF tag is read, the NfcTag object contains a NdefMessage.
87 |
88 | ### NdefMessage
89 |
90 | A NdefMessage consist of one or more NdefRecords.
91 |
92 | The NdefMessage object has helper methods for adding records.
93 |
94 | ndefMessage.addTextRecord("hello, world");
95 | ndefMessage.addUriRecord("http://arduino.cc");
96 |
97 | The NdefMessage object is responsible for encoding NdefMessage into bytes so it can be written to a tag. The NdefMessage also decodes bytes read from a tag back into a NdefMessage object.
98 |
99 | ### NdefRecord
100 |
101 | A NdefRecord carries a payload and info about the payload within a NdefMessage.
102 |
103 | ### Peer to Peer
104 |
105 | Peer to Peer is provided by the LLCP and SNEP support in the [Seeed Studio library](https://github.com/Seeed-Studio/PN532). P2P requires SPI and has only been tested with the Seeed Studio shield. Peer to Peer was tested between Arduino and Android or BlackBerry 10. (Unfortunately Windows Phone 8 did not work.) See [P2P_Send](examples/P2P_Send/P2P_Send.ino) and [P2P_Receive](examples/P2P_Receive/P2P_Receive.ino) for more info.
106 |
107 | ### Specifications
108 |
109 | This code is based on the "NFC Data Exchange Format (NDEF) Technical Specification" and the "Record Type Definition Technical Specifications" that can be downloaded from the [NFC Forum](http://www.nfc-forum.org/specs/spec_license).
110 |
111 | ### Tests
112 |
113 | To run the tests, you'll need [ArduinoUnit](https://github.com/mmurdoch/arduinounit). To "install", I clone the repo to my home directory and symlink the source into ~/Documents/Arduino/libraries/ArduinoUnit.
114 |
115 | $ cd ~
116 | $ git clone git@github.com:mmurdoch/arduinounit.git
117 | $ cd ~/Documents/Arduino/libraries/
118 | $ ln -s ~/arduinounit/src ArduinoUnit
119 |
120 | Tests can be run on an Uno without a NFC shield, since the NDEF logic is what is being tested.
121 |
122 | ## Warning
123 |
124 | This software is in development. It works for the happy path. Error handling could use improvement. It runs out of memory, especially on the Uno board. Use small messages with the Uno. The Due board can write larger messages. Please submit patches.
125 |
126 | ## Book
127 | Need more info? Check out my book [Beginning NFC: Near Field Communication with Arduino, Android, and PhoneGap](http://shop.oreilly.com/product/0636920021193.do)
128 |
129 | 
130 |
131 | ## License
132 |
133 | [BSD License](https://github.com/don/Ndef/blob/master/LICENSE.txt) (c) 2013-2014, Don Coleman
134 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/CleanTag/CleanTag.ino:
--------------------------------------------------------------------------------
1 | // Clean resets a tag back to factory-like state
2 | // For Mifare Classic, tag is zero'd and reformatted as Mifare Classic
3 | // For Mifare Ultralight, tags is zero'd and left empty
4 |
5 | #if 0
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | PN532_SPI pn532spi(SPI, 10);
12 | NfcAdapter nfc = NfcAdapter(pn532spi);
13 | #else
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | PN532_I2C pn532_i2c(Wire);
21 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
22 | #endif
23 |
24 | void setup(void) {
25 | Serial.begin(9600);
26 | Serial.println("NFC Tag Cleaner");
27 | nfc.begin();
28 | }
29 |
30 | void loop(void) {
31 |
32 | Serial.println("\nPlace a tag on the NFC reader to clean.");
33 |
34 | if (nfc.tagPresent()) {
35 |
36 | bool success = nfc.clean();
37 | if (success) {
38 | Serial.println("\nSuccess, tag restored to factory state.");
39 | } else {
40 | Serial.println("\nError, unable to clean tag.");
41 | }
42 |
43 | }
44 | delay(5000);
45 | }
46 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/EraseTag/EraseTag.ino:
--------------------------------------------------------------------------------
1 | // Erases a NFC tag by writing an empty NDEF message
2 |
3 | #if 0
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | PN532_SPI pn532spi(SPI, 10);
10 | NfcAdapter nfc = NfcAdapter(pn532spi);
11 | #else
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | PN532_I2C pn532_i2c(Wire);
19 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
20 | #endif
21 |
22 | void setup(void) {
23 | Serial.begin(9600);
24 | Serial.println("NFC Tag Eraser");
25 | nfc.begin();
26 | }
27 |
28 | void loop(void) {
29 | Serial.println("\nPlace a tag on the NFC reader to erase.");
30 |
31 | if (nfc.tagPresent()) {
32 |
33 | bool success = nfc.erase();
34 | if (success) {
35 | Serial.println("\nSuccess, tag contains an empty record.");
36 | } else {
37 | Serial.println("\nUnable to erase tag.");
38 | }
39 |
40 | }
41 | delay(5000);
42 | }
43 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/FormatTag/FormatTag.ino:
--------------------------------------------------------------------------------
1 | // Formats a Mifare Classic tags as an NDEF tag
2 | // This will fail if the tag is already formatted NDEF
3 | // nfc.clean will turn a NDEF formatted Mifare Classic tag back to the Mifare Classic format
4 |
5 | #if 0
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | PN532_SPI pn532spi(SPI, 10);
12 | NfcAdapter nfc = NfcAdapter(pn532spi);
13 | #else
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | PN532_I2C pn532_i2c(Wire);
21 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
22 | #endif
23 |
24 | void setup(void) {
25 | Serial.begin(9600);
26 | Serial.println("NDEF Formatter");
27 | nfc.begin();
28 | }
29 |
30 | void loop(void) {
31 |
32 | Serial.println("\nPlace an unformatted Mifare Classic tag on the reader.");
33 | if (nfc.tagPresent()) {
34 |
35 | bool success = nfc.format();
36 | if (success) {
37 | Serial.println("\nSuccess, tag formatted as NDEF.");
38 | } else {
39 | Serial.println("\nFormat failed.");
40 | }
41 |
42 | }
43 | delay(5000);
44 | }
45 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/P2P_Receive/P2P_Receive.ino:
--------------------------------------------------------------------------------
1 | // Receive a NDEF message from a Peer
2 | // Requires SPI. Tested with Seeed Studio NFC Shield v2
3 |
4 | #include "SPI.h"
5 | #include "PN532_SPI.h"
6 | #include "snep.h"
7 | #include "NdefMessage.h"
8 |
9 | PN532_SPI pn532spi(SPI, 10);
10 | SNEP nfc(pn532spi);
11 | uint8_t ndefBuf[128];
12 |
13 | void setup() {
14 | Serial.begin(9600);
15 | Serial.println("NFC Peer to Peer Example - Receive Message");
16 | }
17 |
18 | void loop() {
19 | Serial.println("Waiting for message from Peer");
20 | int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf));
21 | if (msgSize > 0) {
22 | NdefMessage msg = NdefMessage(ndefBuf, msgSize);
23 | msg.print();
24 | Serial.println("\nSuccess");
25 | } else {
26 | Serial.println("Failed");
27 | }
28 | delay(3000);
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/P2P_Receive_LCD/P2P_Receive_LCD.ino:
--------------------------------------------------------------------------------
1 | // Receive a NDEF message from a Peer and
2 | // display the payload of the first record on a LCD
3 | //
4 | // SeeedStudio NFC shield http://www.seeedstudio.com/depot/NFC-Shield-V20-p-1370.html
5 | // LCD using the Adafruit backpack http://adafru.it/292
6 | // Adafruit Liquid Crystal library https://github.com/adafruit/LiquidCrystal
7 | // Use a Android of BlackBerry phone to send a message to the NFC shield
8 |
9 | #include "SPI.h"
10 | #include "PN532_SPI.h"
11 | #include "snep.h"
12 | #include "NdefMessage.h"
13 |
14 | #include "Wire.h"
15 | #include "LiquidCrystal.h"
16 |
17 | PN532_SPI pn532spi(SPI, 10);
18 | SNEP nfc(pn532spi);
19 | uint8_t ndefBuf[128];
20 |
21 | // Connect via i2c, default address #0 (A0-A2 not jumpered)
22 | LiquidCrystal lcd(0);
23 |
24 | void setup() {
25 | Serial.begin(9600);
26 | // set up the LCD's number of rows and columns:
27 | lcd.begin(16, 2);
28 | Serial.println("NFC Peer to Peer Example - Receive Message");
29 | }
30 |
31 | void loop() {
32 | Serial.println("Waiting for message from a peer");
33 | int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf));
34 | if (msgSize > 0) {
35 | NdefMessage msg = NdefMessage(ndefBuf, msgSize);
36 | msg.print();
37 |
38 | NdefRecord record = msg.getRecord(0);
39 |
40 | int payloadLength = record.getPayloadLength();
41 | byte payload[payloadLength];
42 | record.getPayload(payload);
43 |
44 | // The TNF and Type are used to determine how your application processes the payload
45 | // There's no generic processing for the payload, it's returned as a byte[]
46 | int startChar = 0;
47 | if (record.getTnf() == TNF_WELL_KNOWN && record.getType() == "T") { // text message
48 | // skip the language code
49 | startChar = payload[0] + 1;
50 | } else if (record.getTnf() == TNF_WELL_KNOWN && record.getType() == "U") { // URI
51 | // skip the url prefix (future versions should decode)
52 | startChar = 1;
53 | }
54 |
55 | // Force the data into a String (might fail for some content)
56 | // Real code should use smarter processing
57 | String payloadAsString = "";
58 | for (int c = startChar; c < payloadLength; c++) {
59 | payloadAsString += (char)payload[c];
60 | }
61 |
62 | // print on the LCD display
63 | lcd.setCursor(0, 0);
64 | lcd.print(payloadAsString);
65 |
66 | Serial.println("\nSuccess");
67 | } else {
68 | Serial.println("Failed");
69 | }
70 | delay(3000);
71 | }
72 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/P2P_Send/P2P_Send.ino:
--------------------------------------------------------------------------------
1 | // Sends a NDEF Message to a Peer
2 | // Requires SPI. Tested with Seeed Studio NFC Shield v2
3 |
4 | #include "SPI.h"
5 | #include "PN532_SPI.h"
6 | #include "snep.h"
7 | #include "NdefMessage.h"
8 |
9 | PN532_SPI pn532spi(SPI, 10);
10 | SNEP nfc(pn532spi);
11 | uint8_t ndefBuf[128];
12 |
13 | void setup() {
14 | Serial.begin(9600);
15 | Serial.println("NFC Peer to Peer Example - Send Message");
16 | }
17 |
18 | void loop() {
19 | Serial.println("Send a message to Peer");
20 |
21 | NdefMessage message = NdefMessage();
22 | message.addUriRecord("http://shop.oreilly.com/product/mobile/0636920021193.do");
23 | //message.addUriRecord("http://arduino.cc");
24 | //message.addUriRecord("https://github.com/don/NDEF");
25 |
26 |
27 | int messageSize = message.getEncodedSize();
28 | if (messageSize > sizeof(ndefBuf)) {
29 | Serial.println("ndefBuf is too small");
30 | while (1) {
31 | }
32 | }
33 |
34 | message.encode(ndefBuf);
35 | if (0 >= nfc.write(ndefBuf, messageSize)) {
36 | Serial.println("Failed");
37 | } else {
38 | Serial.println("Success");
39 | }
40 |
41 | delay(3000);
42 | }
43 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/ReadTag/ReadTag.ino:
--------------------------------------------------------------------------------
1 |
2 | #if 0
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | PN532_SPI pn532spi(SPI, 10);
9 | NfcAdapter nfc = NfcAdapter(pn532spi);
10 | #else
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | PN532_I2C pn532_i2c(Wire);
18 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
19 | #endif
20 |
21 | void setup(void) {
22 | Serial.begin(9600);
23 | Serial.println("NDEF Reader");
24 | nfc.begin();
25 | }
26 |
27 | void loop(void) {
28 | Serial.println("\nScan a NFC tag\n");
29 | if (nfc.tagPresent())
30 | {
31 | NfcTag tag = nfc.read();
32 | tag.print();
33 | }
34 | delay(5000);
35 | }
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/ReadTagExtended/ReadTagExtended.ino:
--------------------------------------------------------------------------------
1 | #if 0
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | PN532_SPI pn532spi(SPI, 10);
8 | NfcAdapter nfc = NfcAdapter(pn532spi);
9 | #else
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | PN532_I2C pn532_i2c(Wire);
17 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
18 | #endif
19 |
20 | void setup(void) {
21 | Serial.begin(9600);
22 | Serial.println("NDEF Reader");
23 | nfc.begin();
24 | }
25 |
26 | void loop(void) {
27 | Serial.println("\nScan a NFC tag\n");
28 |
29 | if (nfc.tagPresent())
30 | {
31 | NfcTag tag = nfc.read();
32 | Serial.println(tag.getTagType());
33 | Serial.print("UID: ");Serial.println(tag.getUidString());
34 |
35 | if (tag.hasNdefMessage()) // every tag won't have a message
36 | {
37 |
38 | NdefMessage message = tag.getNdefMessage();
39 | Serial.print("\nThis NFC Tag contains an NDEF Message with ");
40 | Serial.print(message.getRecordCount());
41 | Serial.print(" NDEF Record");
42 | if (message.getRecordCount() != 1) {
43 | Serial.print("s");
44 | }
45 | Serial.println(".");
46 |
47 | // cycle through the records, printing some info from each
48 | int recordCount = message.getRecordCount();
49 | for (int i = 0; i < recordCount; i++)
50 | {
51 | Serial.print("\nNDEF Record ");Serial.println(i+1);
52 | NdefRecord record = message.getRecord(i);
53 | // NdefRecord record = message[i]; // alternate syntax
54 |
55 | Serial.print(" TNF: ");Serial.println(record.getTnf());
56 | Serial.print(" Type: ");Serial.println(record.getType()); // will be "" for TNF_EMPTY
57 |
58 | // The TNF and Type should be used to determine how your application processes the payload
59 | // There's no generic processing for the payload, it's returned as a byte[]
60 | int payloadLength = record.getPayloadLength();
61 | byte payload[payloadLength];
62 | record.getPayload(payload);
63 |
64 | // Print the Hex and Printable Characters
65 | Serial.print(" Payload (HEX): ");
66 | PrintHexChar(payload, payloadLength);
67 |
68 | // Force the data into a String (might work depending on the content)
69 | // Real code should use smarter processing
70 | String payloadAsString = "";
71 | for (int c = 0; c < payloadLength; c++) {
72 | payloadAsString += (char)payload[c];
73 | }
74 | Serial.print(" Payload (as String): ");
75 | Serial.println(payloadAsString);
76 |
77 | // id is probably blank and will return ""
78 | String uid = record.getId();
79 | if (uid != "") {
80 | Serial.print(" ID: ");Serial.println(uid);
81 | }
82 | }
83 | }
84 | }
85 | delay(3000);
86 | }
87 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/WriteTag/WriteTag.ino:
--------------------------------------------------------------------------------
1 | #if 0
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | PN532_SPI pn532spi(SPI, 10);
8 | NfcAdapter nfc = NfcAdapter(pn532spi);
9 | #else
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | PN532_I2C pn532_i2c(Wire);
17 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
18 | #endif
19 |
20 | void setup() {
21 | Serial.begin(9600);
22 | Serial.println("NDEF Writer");
23 | nfc.begin();
24 | }
25 |
26 | void loop() {
27 | Serial.println("\nPlace a formatted Mifare Classic NFC tag on the reader.");
28 | if (nfc.tagPresent()) {
29 | NdefMessage message = NdefMessage();
30 | message.addUriRecord("http://arduino.cc");
31 |
32 | bool success = nfc.write(message);
33 | if (success) {
34 | Serial.println("Success. Try reading this tag with your phone.");
35 | } else {
36 | Serial.println("Write failed.");
37 | }
38 | }
39 | delay(5000);
40 | }
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/examples/WriteTagMultipleRecords/WriteTagMultipleRecords.ino:
--------------------------------------------------------------------------------
1 | #if 0
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | PN532_SPI pn532spi(SPI, 10);
8 | NfcAdapter nfc = NfcAdapter(pn532spi);
9 | #else
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | PN532_I2C pn532_i2c(Wire);
17 | NfcAdapter nfc = NfcAdapter(pn532_i2c);
18 | #endif
19 |
20 | void setup() {
21 | Serial.begin(9600);
22 | Serial.println("NDEF Writer");
23 | nfc.begin();
24 | }
25 |
26 | void loop() {
27 | Serial.println("\nPlace a formatted Mifare Classic NFC tag on the reader.");
28 | if (nfc.tagPresent()) {
29 | NdefMessage message = NdefMessage();
30 | message.addTextRecord("Hello, Arduino!");
31 | message.addUriRecord("http://arduino.cc");
32 | message.addTextRecord("Goodbye, Arduino!");
33 | boolean success = nfc.write(message);
34 | if (success) {
35 | Serial.println("Success. Try reading this tag with your phone.");
36 | } else {
37 | Serial.println("Write failed");
38 | }
39 | }
40 | delay(3000);
41 | }
42 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/keywords.txt:
--------------------------------------------------------------------------------
1 | #######################################
2 | # Syntax Coloring Map For Ndef
3 | #######################################
4 |
5 | #######################################
6 | # Datatypes (KEYWORD1)
7 | #######################################
8 |
9 | MifareClassic KEYWORD1
10 | MifareUltralight KEYWORD1
11 | NdefMessage KEYWORD1
12 | NdefRecord KEYWORD1
13 | NfcAdapter KEYWORD1
14 | NfcDriver KEYWORD1
15 | NfcTag KEYWORD1
16 |
17 | #######################################
18 | # Methods and Functions (KEYWORD2)
19 | #######################################
20 |
21 | addEmptyRecord KEYWORD2
22 | addMimeMediaRecord KEYWORD2
23 | addRecord KEYWORD2
24 | addTextRecord KEYWORD2
25 | addUriRecord KEYWORD2
26 | begin KEYWORD2
27 | encode KEYWORD2
28 | erase KEYWORD2
29 | format KEYWORD2
30 | getEncodedSize KEYWORD2
31 | getId KEYWORD2
32 | getIdLength KEYWORD2
33 | getNdefMessage KEYWORD2
34 | getPayload KEYWORD2
35 | getPayloadLength KEYWORD2
36 | getRecord KEYWORD2
37 | getRecordCount KEYWORD2
38 | getTagType KEYWORD2
39 | getTnf KEYWORD2
40 | getType KEYWORD2
41 | getTypeLength KEYWORD2
42 | getUid KEYWORD2
43 | getUidLength KEYWORD2
44 | getUidString KEYWORD2
45 | hasNdefMessage KEYWORD2
46 | print KEYWORD2
47 | read KEYWORD2
48 | setId KEYWORD2
49 | setPayload KEYWORD2
50 | setTnf KEYWORD2
51 | setType KEYWORD2
52 | share KEYWORD2
53 | tagPresent KEYWORD2
54 | unshare KEYWORD2
55 | write KEYWORD2
56 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/tests/NdefMemoryTest/NdefMemoryTest.ino:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | void leakCheck(void (*callback)())
8 | {
9 | int start = freeMemory();
10 | (*callback)();
11 | int end = freeMemory();
12 | Serial.println((end - start), DEC);
13 | }
14 |
15 | // Custom Assertion
16 | void assertNoLeak(void (*callback)())
17 | {
18 | int start = freeMemory();
19 | (*callback)();
20 | int end = freeMemory();
21 | assertEqual(0, (start - end));
22 | }
23 |
24 | void record()
25 | {
26 | NdefRecord* r = new NdefRecord();
27 | delete r;
28 | }
29 |
30 | void emptyRecord()
31 | {
32 | NdefRecord* r = new NdefRecord();
33 | r->print();
34 | delete r;
35 | }
36 |
37 | void textRecord()
38 | {
39 | NdefRecord* r = new NdefRecord();
40 | r->setTnf(0x1);
41 | uint8_t type[] = { 0x54 };
42 | r->setType(type, sizeof(type));
43 | uint8_t payload[] = { 0x1A, 0x1B, 0x1C };
44 | r->setPayload(payload, sizeof(payload));
45 | r->print();
46 | delete r;
47 | }
48 |
49 | void recordMallocZero()
50 | {
51 | NdefRecord r = NdefRecord();
52 | String type = r.getType();
53 | String id = r.getId();
54 | byte payload[r.getPayloadLength()];
55 | r.getPayload(payload);
56 | }
57 |
58 | // this is OK
59 | void emptyMessage()
60 | {
61 | NdefMessage* m = new NdefMessage();
62 | delete m;
63 | }
64 |
65 | // this is OK
66 | void printEmptyMessage()
67 | {
68 | NdefMessage* m = new NdefMessage();
69 | m->print();
70 | delete m;
71 | }
72 |
73 | // this is OK
74 | void printEmptyMessageNoNew()
75 | {
76 | NdefMessage m = NdefMessage();
77 | m.print();
78 | }
79 |
80 | void messageWithTextRecord()
81 | {
82 | NdefMessage m = NdefMessage();
83 | m.addTextRecord("foo");
84 | m.print();
85 | }
86 |
87 | void messageWithEmptyRecord()
88 | {
89 | NdefMessage m = NdefMessage();
90 | NdefRecord r = NdefRecord();
91 | m.addRecord(r);
92 | m.print();
93 | }
94 |
95 | void messageWithoutHelper()
96 | {
97 | NdefMessage m = NdefMessage();
98 | NdefRecord r = NdefRecord();
99 | r.setTnf(1);
100 | uint8_t type[] = { 0x54 };
101 | r.setType(type, sizeof(type));
102 | uint8_t payload[] = { 0x02, 0x65, 0x6E, 0x66, 0x6F, 0x6F };
103 | r.setPayload(payload, sizeof(payload));
104 | m.addRecord(r);
105 | m.print();
106 | }
107 |
108 | void messageWithId()
109 | {
110 | NdefMessage m = NdefMessage();
111 | NdefRecord r = NdefRecord();
112 | r.setTnf(1);
113 | uint8_t type[] = { 0x54 };
114 | r.setType(type, sizeof(type));
115 | uint8_t payload[] = { 0x02, 0x65, 0x6E, 0x66, 0x6F, 0x6F };
116 | r.setPayload(payload, sizeof(payload));
117 | uint8_t id[] = { 0x0, 0x0, 0x0 };
118 | r.setId(id, sizeof(id));
119 | m.addRecord(r);
120 | m.print();
121 | }
122 |
123 | void message80()
124 | {
125 | NdefMessage message = NdefMessage();
126 | message.addTextRecord("This record is 80 characters.X01234567890123456789012345678901234567890123456789");
127 | //message.print();
128 | }
129 |
130 | void message100()
131 | {
132 | NdefMessage message = NdefMessage();
133 | message.addTextRecord("This record is 100 characters.0123456789012345678901234567890123456789012345678901234567890123456789");
134 | //message.print();
135 | }
136 |
137 | void message120()
138 | {
139 | NdefMessage message = NdefMessage();
140 | message.addTextRecord("This record is 120 characters.012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
141 | //message.print();
142 | }
143 |
144 | void setup() {
145 | Serial.begin(9600);
146 | Serial.println("\n");
147 | Serial.println(F("========="));
148 | Serial.println(freeMemory());
149 | Serial.println(F("========="));
150 | }
151 |
152 | test(memoryKludgeEnd)
153 | {
154 | // TODO ensure the output matches start
155 | Serial.println(F("========="));
156 | Serial.print("End ");Serial.println(freeMemory());
157 | Serial.println(F("========="));
158 | }
159 |
160 | test(recordLeaks)
161 | {
162 | assertNoLeak(&record);
163 | assertNoLeak(&emptyRecord);
164 | assertNoLeak(&textRecord);
165 | }
166 |
167 | test(recordAccessorLeaks)
168 | {
169 | assertNoLeak(&recordMallocZero);
170 | }
171 |
172 | test(messageLeaks)
173 | {
174 | assertNoLeak(&emptyMessage);
175 | assertNoLeak(&printEmptyMessage);
176 | assertNoLeak(&printEmptyMessageNoNew);
177 | assertNoLeak(&messageWithTextRecord);
178 | assertNoLeak(&messageWithEmptyRecord);
179 | assertNoLeak(&messageWithoutHelper);
180 | assertNoLeak(&messageWithId);
181 | }
182 |
183 | test(messageOneBigRecord)
184 | {
185 | assertNoLeak(&message80);
186 | // The next 2 fail. Maybe out of memory? Look into helper methods
187 | //assertNoLeak(&message100);
188 | //assertNoLeak(&message120);
189 | }
190 |
191 | test(memoryKludgeStart)
192 | {
193 | Serial.println(F("---------"));
194 | Serial.print("Start ");Serial.println(freeMemory());
195 | Serial.println(F("---------"));
196 | }
197 |
198 | void loop() {
199 | Test::run();
200 | }
201 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/tests/NdefUnitTest/NdefUnitTest.ino:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | void assertBytesEqual(const uint8_t* expected, const uint8_t* actual, uint8_t size) {
7 | for (int i = 0; i < size; i++) {
8 | assertEqual(expected[i], actual[i]);
9 | }
10 | }
11 |
12 | void setup() {
13 | Serial.begin(9600);
14 | }
15 |
16 | test(accessors) {
17 | NdefRecord record = NdefRecord();
18 | record.setTnf(TNF_WELL_KNOWN);
19 | uint8_t recordType[] = { 0x54 }; // "T" Text Record
20 | assertEqual(0x54, recordType[0]);
21 | record.setType(recordType, sizeof(recordType));
22 | // 2 + "en" + "Unit Test"
23 | uint8_t payload[] = { 0x02, 0x65, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74 };
24 | record.setPayload(payload, sizeof(payload));
25 |
26 | assertEqual(TNF_WELL_KNOWN, record.getTnf());
27 | assertEqual(sizeof(recordType), record.getTypeLength());
28 | assertEqual(1, record.getTypeLength());
29 | assertEqual(sizeof(payload), record.getPayloadLength());
30 | assertEqual(12, record.getPayloadLength());
31 |
32 | uint8_t typeCheck[record.getTypeLength()];
33 | record.getType(typeCheck);
34 |
35 | assertEqual(0x54, typeCheck[0]);
36 | assertBytesEqual(recordType, typeCheck, sizeof(recordType));
37 |
38 | uint8_t payloadCheck[record.getPayloadLength()];
39 | record.getPayload(&payloadCheck[0]);
40 | assertBytesEqual(payload, payloadCheck, sizeof(payload));
41 | }
42 |
43 | test(newaccessors) {
44 | NdefRecord record = NdefRecord();
45 | record.setTnf(TNF_WELL_KNOWN);
46 | uint8_t recordType[] = { 0x54 }; // "T" Text Record
47 | assertEqual(0x54, recordType[0]);
48 | record.setType(recordType, sizeof(recordType));
49 | // 2 + "en" + "Unit Test"
50 | uint8_t payload[] = { 0x02, 0x65, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74 };
51 | record.setPayload(payload, sizeof(payload));
52 |
53 | assertEqual(TNF_WELL_KNOWN, record.getTnf());
54 | assertEqual(sizeof(recordType), record.getTypeLength());
55 | assertEqual(1, record.getTypeLength());
56 | assertEqual(sizeof(payload), record.getPayloadLength());
57 | assertEqual(12, record.getPayloadLength());
58 |
59 | ::String typeCheck = record.getType();
60 | assertTrue(typeCheck.equals("T"));
61 |
62 | byte payloadCheck[record.getPayloadLength()];
63 | record.getPayload(payloadCheck);
64 | assertBytesEqual(payload, payloadCheck, sizeof(payload));
65 | }
66 |
67 | test(assignment)
68 | {
69 | NdefRecord record = NdefRecord();
70 | record.setTnf(TNF_WELL_KNOWN);
71 | uint8_t recordType[] = { 0x54 }; // "T" Text Record
72 | assertEqual(0x54, recordType[0]);
73 | record.setType(recordType, sizeof(recordType));
74 | // 2 + "en" + "Unit Test"
75 | uint8_t payload[] = { 0x02, 0x65, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74 };
76 | record.setPayload(payload, sizeof(payload));
77 |
78 | NdefRecord record2 = NdefRecord();
79 | record2 = record;
80 |
81 | assertEqual(TNF_WELL_KNOWN, record.getTnf());
82 | assertEqual(sizeof(recordType), record2.getTypeLength());
83 | assertEqual(sizeof(payload), record2.getPayloadLength());
84 |
85 | ::String typeCheck = record.getType();
86 | assertTrue(typeCheck.equals("T"));
87 |
88 | byte payload2[record2.getPayloadLength()];
89 | record2.getPayload(payload2);
90 | assertBytesEqual(payload, payload2, sizeof(payload));
91 | }
92 |
93 | test(getEmptyPayload)
94 | {
95 | NdefRecord r = NdefRecord();
96 | assertEqual(TNF_EMPTY, r.getTnf());
97 | assertEqual(0, r.getPayloadLength());
98 |
99 | byte payload[r.getPayloadLength()];
100 | r.getPayload(payload);
101 |
102 | byte empty[0];
103 | assertBytesEqual(empty, payload, sizeof(payload));
104 | }
105 |
106 | void loop() {
107 | Test::run();
108 | }
109 |
--------------------------------------------------------------------------------
/mu3controller/lib/NDEF/tests/NfcTagTest/NfcTagTest.ino:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | void setup() {
7 | Serial.begin(9600);
8 | }
9 |
10 | // Test for pull requests #14 and #16
11 | test(getUid)
12 | {
13 | byte uid[4] = { 0x00, 0xFF, 0xAA, 0x17 };
14 | byte uidFromTag[sizeof(uid)];
15 |
16 | NfcTag tag = NfcTag(uid, sizeof(uid));
17 |
18 | assertEqual(sizeof(uid), tag.getUidLength());
19 |
20 | tag.getUid(uidFromTag, sizeof(uidFromTag));
21 |
22 | // make sure the 2 uids are the same
23 | for (int i = 0; i < sizeof(uid); i++) {
24 | assertEqual(uid[i], uidFromTag[i]);
25 | }
26 |
27 | // check contents, to ensure the original uid wasn't overwritten
28 | assertEqual(0x00, uid[0]);
29 | assertEqual(0xFF, uid[1]);
30 | assertEqual(0xAA, uid[2]);
31 | assertEqual(0x17, uid[3]);
32 | }
33 |
34 | void loop() {
35 | Test::run();
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/PN532Interface.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifndef __PN532_INTERFACE_H__
4 | #define __PN532_INTERFACE_H__
5 |
6 | #include
7 |
8 | #define PN532_PREAMBLE (0x00)
9 | #define PN532_STARTCODE1 (0x00)
10 | #define PN532_STARTCODE2 (0xFF)
11 | #define PN532_POSTAMBLE (0x00)
12 |
13 | #define PN532_HOSTTOPN532 (0xD4)
14 | #define PN532_PN532TOHOST (0xD5)
15 |
16 | #define PN532_ACK_WAIT_TIME (10) // ms, timeout of waiting for ACK
17 |
18 | #define PN532_INVALID_ACK (-1)
19 | #define PN532_TIMEOUT (-2)
20 | #define PN532_INVALID_FRAME (-3)
21 | #define PN532_NO_SPACE (-4)
22 |
23 | #define REVERSE_BITS_ORDER(b) b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; \
24 | b = (b & 0xCC) >> 2 | (b & 0x33) << 2; \
25 | b = (b & 0xAA) >> 1 | (b & 0x55) << 1
26 |
27 | class PN532Interface
28 | {
29 | public:
30 | virtual void begin() = 0;
31 | virtual void wakeup() = 0;
32 |
33 | /**
34 | * @brief write a command and check ack
35 | * @param header packet header
36 | * @param hlen length of header
37 | * @param body packet body
38 | * @param blen length of body
39 | * @return 0 success
40 | * not 0 failed
41 | */
42 | virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) = 0;
43 |
44 | /**
45 | * @brief read the response of a command, strip prefix and suffix
46 | * @param buf to contain the response data
47 | * @param len lenght to read
48 | * @param timeout max time to wait, 0 means no timeout
49 | * @return >=0 length of response without prefix and suffix
50 | * <0 failed to read response
51 | */
52 | virtual int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 1000) = 0;
53 | };
54 |
55 | #endif
56 |
57 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/PN532_debug.h:
--------------------------------------------------------------------------------
1 | #ifndef __DEBUG_H__
2 | #define __DEBUG_H__
3 |
4 | //#define DEBUG
5 |
6 | #include "Arduino.h"
7 |
8 | #ifdef DEBUG
9 | #define DMSG(args...) Serial.print(args)
10 | #define DMSG_STR(str) Serial.println(str)
11 | #define DMSG_HEX(num) Serial.print(' '); Serial.print((num>>4)&0x0F, HEX); Serial.print(num&0x0F, HEX)
12 | #define DMSG_INT(num) Serial.print(' '); Serial.print(num)
13 | #else
14 | #define DMSG(args...)
15 | #define DMSG_STR(str)
16 | #define DMSG_HEX(num)
17 | #define DMSG_INT(num)
18 | #endif
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/README.md:
--------------------------------------------------------------------------------
1 | ## NFC library for Arduino
2 |
3 | This is an Arduino library for PN532 to use NFC technology.
4 | It works with
5 |
6 | + [NFC Shield](http://goo.gl/Cac2OH)
7 | + [Xadow NFC](http://goo.gl/qBZMt0)
8 | + [PN532 NFC/RFID controller breakout board](http://goo.gl/tby9Sw)
9 |
10 | ### Features
11 | + Support I2C, SPI and HSU of PN532
12 | + Read/write Mifare Classic Card
13 | + Works with [Don's NDEF Library](http://goo.gl/jDjsXl)
14 | + Support Peer to Peer communication(exchange data with android 4.0+)
15 | + Support [mbed platform](http://goo.gl/kGPovZ)
16 |
17 | ### Getting Started
18 | 1. Download [zip file](http://goo.gl/F6beRM) and
19 | extract the 4 folders(PN532, PN532_SPI, PN532_I2C and PN532_HSU) into Arduino's libraries.
20 | 2. Downlaod [Don's NDEF library](http://goo.gl/ewxeAe) and extract it intro Arduino's libraries.
21 | 3. Follow the examples of the two libraries.
22 |
23 | ### To do
24 | + Card emulation
25 |
26 | ### Contribution
27 | It's based on [Adafruit_NFCShield_I2C](http://goo.gl/pk3FdB).
28 | [Seeed Studio](http://goo.gl/zh1iQh) adds SPI interface and peer to peer communication support.
29 | @Don writes the [NDEF library](http://goo.gl/jDjsXl) to make it more easy to use.
30 | @JiapengLi adds HSU interface.
31 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/emulatetag.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | @file emulatetag.h
4 | @author Armin Wieser
5 | @license BSD
6 |
7 | Implemented using NFC forum documents & library of libnfc
8 | */
9 | /**************************************************************************/
10 |
11 | #ifndef __EMULATETAG_H__
12 | #define __EMULATETAG_H__
13 |
14 | #include "PN532.h"
15 |
16 | #define NDEF_MAX_LENGTH 128 // altough ndef can handle up to 0xfffe in size, arduino cannot.
17 | typedef enum {COMMAND_COMPLETE, TAG_NOT_FOUND, FUNCTION_NOT_SUPPORTED, MEMORY_FAILURE, END_OF_FILE_BEFORE_REACHED_LE_BYTES} responseCommand;
18 |
19 | class EmulateTag{
20 |
21 | public:
22 | EmulateTag(PN532Interface &interface) : pn532(interface), uidPtr(0), tagWrittenByInitiator(false), tagWriteable(true), updateNdefCallback(0) { }
23 |
24 | bool init();
25 |
26 | bool emulate(const uint16_t tgInitAsTargetTimeout = 0);
27 |
28 | /*
29 | * @param uid pointer to byte array of length 3 (uid is 4 bytes - first byte is fixed) or zero for uid
30 | */
31 | void setUid(uint8_t* uid = 0);
32 |
33 | void setNdefFile(const uint8_t* ndef, const int16_t ndefLength);
34 |
35 | void getContent(uint8_t** buf, uint16_t* length){
36 | *buf = ndef_file + 2; // first 2 bytes = length
37 | *length = (ndef_file[0] << 8) + ndef_file[1];
38 | }
39 |
40 | bool writeOccured(){
41 | return tagWrittenByInitiator;
42 | }
43 |
44 | void setTagWriteable(bool setWriteable){
45 | tagWriteable = setWriteable;
46 | }
47 |
48 | uint8_t* getNdefFilePtr(){
49 | return ndef_file;
50 | }
51 |
52 | uint8_t getNdefMaxLength(){
53 | return NDEF_MAX_LENGTH;
54 | }
55 |
56 | void attach(void (*func)(uint8_t *buf, uint16_t length)) {
57 | updateNdefCallback = func;
58 | };
59 |
60 | private:
61 | PN532 pn532;
62 | uint8_t ndef_file[NDEF_MAX_LENGTH];
63 | uint8_t* uidPtr;
64 | bool tagWrittenByInitiator;
65 | bool tagWriteable;
66 | void (*updateNdefCallback)(uint8_t *ndef, uint16_t length);
67 |
68 | void setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset = 0);
69 | };
70 |
71 | #endif
72 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/FeliCa_card_detection/FeliCa_card_detection.pde:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | This example will attempt to connect to an FeliCa
4 | card or tag and retrieve some basic information about it
5 | that can be used to determine what type of card it is.
6 |
7 | Note that you need the baud rate to be 115200 because we need to print
8 | out the data and read from the card at the same time!
9 |
10 | To enable debug message, define DEBUG in PN532/PN532_debug.h
11 |
12 | */
13 | /**************************************************************************/
14 | #include
15 |
16 | #if 1
17 | #include
18 | #include
19 | #include
20 |
21 | PN532_SPI pn532spi(SPI, 10);
22 | PN532 nfc(pn532spi);
23 | #elif 0
24 | #include
25 | #include
26 |
27 | PN532_HSU pn532hsu(Serial1);
28 | PN532 nfc(pn532hsu);
29 | #else
30 | #include
31 | #include
32 | #include
33 |
34 | PN532_I2C pn532i2c(Wire);
35 | PN532 nfc(pn532i2c);
36 | #endif
37 |
38 | #include
39 |
40 | uint8_t _prevIDm[8];
41 | unsigned long _prevTime;
42 |
43 | void setup(void)
44 | {
45 | Serial.begin(115200);
46 | Serial.println("Hello!");
47 |
48 | nfc.begin();
49 |
50 | uint32_t versiondata = nfc.getFirmwareVersion();
51 | if (!versiondata)
52 | {
53 | Serial.print("Didn't find PN53x board");
54 | while (1) {delay(10);}; // halt
55 | }
56 |
57 | // Got ok data, print it out!
58 | Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
59 | Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
60 | Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
61 |
62 | // Set the max number of retry attempts to read from a card
63 | // This prevents us from waiting forever for a card, which is
64 | // the default behaviour of the PN532.
65 | nfc.setPassiveActivationRetries(0xFF);
66 | nfc.SAMConfig();
67 |
68 | memset(_prevIDm, 0, 8);
69 | }
70 |
71 | void loop(void)
72 | {
73 | uint8_t ret;
74 | uint16_t systemCode = 0xFFFF;
75 | uint8_t requestCode = 0x01; // System Code request
76 | uint8_t idm[8];
77 | uint8_t pmm[8];
78 | uint16_t systemCodeResponse;
79 |
80 | // Wait for an FeliCa type cards.
81 | // When one is found, some basic information such as IDm, PMm, and System Code are retrieved.
82 | Serial.print("Waiting for an FeliCa card... ");
83 | ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000);
84 |
85 | if (ret != 1)
86 | {
87 | Serial.println("Could not find a card");
88 | delay(500);
89 | return;
90 | }
91 |
92 | if ( memcmp(idm, _prevIDm, 8) == 0 ) {
93 | if ( (millis() - _prevTime) < 3000 ) {
94 | Serial.println("Same card");
95 | delay(500);
96 | return;
97 | }
98 | }
99 |
100 | Serial.println("Found a card!");
101 | Serial.print(" IDm: ");
102 | nfc.PrintHex(idm, 8);
103 | Serial.print(" PMm: ");
104 | nfc.PrintHex(pmm, 8);
105 | Serial.print(" System Code: ");
106 | Serial.print(systemCodeResponse, HEX);
107 | Serial.print("\n");
108 |
109 | memcpy(_prevIDm, idm, 8);
110 | _prevTime = millis();
111 |
112 | // Wait 1 second before continuing
113 | Serial.println("Card access completed!\n");
114 | delay(1000);
115 | }
116 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/FeliCa_card_read/FeliCa_card_read.pde:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | This example will attempt to connect to an FeliCa
4 | card or tag and retrieve some basic information about it
5 | that can be used to determine what type of card it is.
6 |
7 | Note that you need the baud rate to be 115200 because we need to print
8 | out the data and read from the card at the same time!
9 |
10 | To enable debug message, define DEBUG in PN532/PN532_debug.h
11 |
12 | */
13 | /**************************************************************************/
14 | #include
15 |
16 | #if 1
17 | #include
18 | #include
19 | #include
20 |
21 | PN532_SPI pn532spi(SPI, 10);
22 | PN532 nfc(pn532spi);
23 | #elif 0
24 | #include
25 | #include
26 |
27 | PN532_HSU pn532hsu(Serial1);
28 | PN532 nfc(pn532hsu);
29 | #else
30 | #include
31 | #include
32 | #include
33 |
34 | PN532_I2C pn532i2c(Wire);
35 | PN532 nfc(pn532i2c);
36 | #endif
37 |
38 | #include
39 |
40 | uint8_t _prevIDm[8];
41 | unsigned long _prevTime;
42 |
43 | void PrintHex8(const uint8_t d) {
44 | Serial.print(" ");
45 | Serial.print( (d >> 4) & 0x0F, HEX);
46 | Serial.print( d & 0x0F, HEX);
47 | }
48 |
49 | void setup(void)
50 | {
51 | Serial.begin(115200);
52 | Serial.println("Hello!");
53 |
54 | nfc.begin();
55 |
56 | uint32_t versiondata = nfc.getFirmwareVersion();
57 | if (!versiondata)
58 | {
59 | Serial.print("Didn't find PN53x board");
60 | while (1) {delay(10);}; // halt
61 | }
62 |
63 | // Got ok data, print it out!
64 | Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
65 | Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
66 | Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
67 |
68 | // Set the max number of retry attempts to read from a card
69 | // This prevents us from waiting forever for a card, which is
70 | // the default behaviour of the PN532.
71 | nfc.setPassiveActivationRetries(0xFF);
72 | nfc.SAMConfig();
73 |
74 | memset(_prevIDm, 0, 8);
75 | }
76 |
77 | void loop(void)
78 | {
79 | uint8_t ret;
80 | uint16_t systemCode = 0xFFFF;
81 | uint8_t requestCode = 0x01; // System Code request
82 | uint8_t idm[8];
83 | uint8_t pmm[8];
84 | uint16_t systemCodeResponse;
85 |
86 | // Wait for an FeliCa type cards.
87 | // When one is found, some basic information such as IDm, PMm, and System Code are retrieved.
88 | Serial.print("Waiting for an FeliCa card... ");
89 | ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000);
90 |
91 | if (ret != 1)
92 | {
93 | Serial.println("Could not find a card");
94 | delay(500);
95 | return;
96 | }
97 |
98 | if ( memcmp(idm, _prevIDm, 8) == 0 ) {
99 | if ( (millis() - _prevTime) < 3000 ) {
100 | Serial.println("Same card");
101 | delay(500);
102 | return;
103 | }
104 | }
105 |
106 | Serial.println("Found a card!");
107 | Serial.print(" IDm: ");
108 | nfc.PrintHex(idm, 8);
109 | Serial.print(" PMm: ");
110 | nfc.PrintHex(pmm, 8);
111 | Serial.print(" System Code: ");
112 | Serial.print(systemCodeResponse, HEX);
113 | Serial.print("\n");
114 |
115 | memcpy(_prevIDm, idm, 8);
116 | _prevTime = millis();
117 |
118 | uint8_t blockData[3][16];
119 | uint16_t serviceCodeList[1];
120 | uint16_t blockList[3];
121 |
122 | Serial.println("Write Without Encryption command ");
123 | serviceCodeList[0] = 0x0009;
124 | blockList[0] = 0x8000;
125 | unsigned long now = millis();
126 | blockData[0][3] = now & 0xFF;
127 | blockData[0][2] = (now >>= 8) & 0xFF;
128 | blockData[0][1] = (now >>= 8) & 0xFF;
129 | blockData[0][0] = (now >>= 8) & 0xFF;
130 | Serial.print(" Writing current millis (");
131 | PrintHex8(blockData[0][0]);
132 | PrintHex8(blockData[0][1]);
133 | PrintHex8(blockData[0][2]);
134 | PrintHex8(blockData[0][3]);
135 | Serial.print(" ) to Block 0 -> ");
136 | ret = nfc.felica_WriteWithoutEncryption(1, serviceCodeList, 1, blockList, blockData);
137 | if (ret != 1)
138 | {
139 | Serial.println("error");
140 | } else {
141 | Serial.println("OK!");
142 | }
143 | memset(blockData[0], 0, 16);
144 |
145 | Serial.print("Read Without Encryption command -> ");
146 | serviceCodeList[0] = 0x000B;
147 | blockList[0] = 0x8000;
148 | blockList[1] = 0x8001;
149 | blockList[2] = 0x8002;
150 | ret = nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 3, blockList, blockData);
151 | if (ret != 1)
152 | {
153 | Serial.println("error");
154 | } else {
155 | Serial.println("OK!");
156 | for(int i=0; i<3; i++ ) {
157 | Serial.print(" Block no. "); Serial.print(i, DEC); Serial.print(": ");
158 | nfc.PrintHex(blockData[i], 16);
159 | }
160 | }
161 |
162 | // Wait 1 second before continuing
163 | Serial.println("Card access completed!\n");
164 | delay(1000);
165 | }
166 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/android_hce/android_hce.ino:
--------------------------------------------------------------------------------
1 | #if 0
2 | #include
3 | #include
4 | #include "PN532.h"
5 |
6 | PN532_SPI pn532spi(SPI, 10);
7 | PN532 nfc(pn532spi);
8 | #elif 1
9 | #include
10 | #include
11 |
12 | PN532_HSU pn532hsu(Serial1);
13 | PN532 nfc(pn532hsu);
14 | #else
15 | #include
16 | #include
17 | #include
18 | #endif
19 |
20 | void setup()
21 | {
22 | Serial.begin(115200);
23 | Serial.println("-------Peer to Peer HCE--------");
24 |
25 | nfc.begin();
26 |
27 | uint32_t versiondata = nfc.getFirmwareVersion();
28 | if (! versiondata) {
29 | Serial.print("Didn't find PN53x board");
30 | while (1); // halt
31 | }
32 |
33 | // Got ok data, print it out!
34 | Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
35 | Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
36 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
37 |
38 | // Set the max number of retry attempts to read from a card
39 | // This prevents us from waiting forever for a card, which is
40 | // the default behaviour of the PN532.
41 | //nfc.setPassiveActivationRetries(0xFF);
42 |
43 | // configure board to read RFID tags
44 | nfc.SAMConfig();
45 | }
46 |
47 | void loop()
48 | {
49 | bool success;
50 |
51 | uint8_t responseLength = 32;
52 |
53 | Serial.println("Waiting for an ISO14443A card");
54 |
55 | // set shield to inListPassiveTarget
56 | success = nfc.inListPassiveTarget();
57 |
58 | if(success) {
59 |
60 | Serial.println("Found something!");
61 |
62 | uint8_t selectApdu[] = { 0x00, /* CLA */
63 | 0xA4, /* INS */
64 | 0x04, /* P1 */
65 | 0x00, /* P2 */
66 | 0x07, /* Length of AID */
67 | 0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* AID defined on Android App */
68 | 0x00 /* Le */ };
69 |
70 | uint8_t response[32];
71 |
72 | success = nfc.inDataExchange(selectApdu, sizeof(selectApdu), response, &responseLength);
73 |
74 | if(success) {
75 |
76 | Serial.print("responseLength: "); Serial.println(responseLength);
77 |
78 | nfc.PrintHexChar(response, responseLength);
79 |
80 | do {
81 | uint8_t apdu[] = "Hello from Arduino";
82 | uint8_t back[32];
83 | uint8_t length = 32;
84 |
85 | success = nfc.inDataExchange(apdu, sizeof(apdu), back, &length);
86 |
87 | if(success) {
88 |
89 | Serial.print("responseLength: "); Serial.println(length);
90 |
91 | nfc.PrintHexChar(back, length);
92 | }
93 | else {
94 |
95 | Serial.println("Broken connection?");
96 | }
97 | }
98 | while(success);
99 | }
100 | else {
101 |
102 | Serial.println("Failed sending SELECT AID");
103 | }
104 | }
105 | else {
106 |
107 | Serial.println("Didn't find anything!");
108 | }
109 |
110 | delay(1000);
111 | }
112 |
113 | void printResponse(uint8_t *response, uint8_t responseLength) {
114 |
115 | String respBuffer;
116 |
117 | for (int i = 0; i < responseLength; i++) {
118 |
119 | if (response[i] < 0x10)
120 | respBuffer = respBuffer + "0"; //Adds leading zeros if hex value is smaller than 0x10
121 |
122 | respBuffer = respBuffer + String(response[i], HEX) + " ";
123 | }
124 |
125 | Serial.print("response: "); Serial.println(respBuffer);
126 | }
127 |
128 | void setupNFC() {
129 |
130 | nfc.begin();
131 |
132 | uint32_t versiondata = nfc.getFirmwareVersion();
133 | if (! versiondata) {
134 | Serial.print("Didn't find PN53x board");
135 | while (1); // halt
136 | }
137 |
138 | // Got ok data, print it out!
139 | Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
140 | Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
141 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
142 |
143 | // configure board to read RFID tags
144 | nfc.SAMConfig();
145 | }
146 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/emulate_tag_ndef/emulate_tag_ndef.ino:
--------------------------------------------------------------------------------
1 | #include "emulatetag.h"
2 | #include "NdefMessage.h"
3 |
4 | #if 0
5 | #include
6 | #include
7 | #include "PN532.h"
8 |
9 | PN532_SPI pn532spi(SPI, 10);
10 | EmulateTag nfc(pn532spi);
11 | #elif 1
12 | #include
13 | #include
14 |
15 | PN532_HSU pn532hsu(Serial1);
16 | EmulateTag nfc(pn532hsu);
17 | #endif
18 |
19 |
20 |
21 |
22 |
23 | uint8_t ndefBuf[120];
24 | NdefMessage message;
25 | int messageSize;
26 |
27 | uint8_t uid[3] = { 0x12, 0x34, 0x56 };
28 |
29 | void setup()
30 | {
31 | Serial.begin(115200);
32 | Serial.println("------- Emulate Tag --------");
33 |
34 | message = NdefMessage();
35 | message.addUriRecord("http://www.elechouse.com");
36 | messageSize = message.getEncodedSize();
37 | if (messageSize > sizeof(ndefBuf)) {
38 | Serial.println("ndefBuf is too small");
39 | while (1) { }
40 | }
41 |
42 | Serial.print("Ndef encoded message size: ");
43 | Serial.println(messageSize);
44 |
45 | message.encode(ndefBuf);
46 |
47 | // comment out this command for no ndef message
48 | nfc.setNdefFile(ndefBuf, messageSize);
49 |
50 | // uid must be 3 bytes!
51 | nfc.setUid(uid);
52 |
53 | nfc.init();
54 | }
55 |
56 | void loop(){
57 | // uncomment for overriding ndef in case a write to this tag occured
58 | //nfc.setNdefFile(ndefBuf, messageSize);
59 |
60 | // start emulation (blocks)
61 | nfc.emulate();
62 |
63 | // or start emulation with timeout
64 | /*if(!nfc.emulate(1000)){ // timeout 1 second
65 | Serial.println("timed out");
66 | }*/
67 |
68 | // deny writing to the tag
69 | // nfc.setTagWriteable(false);
70 |
71 | if(nfc.writeOccured()){
72 | Serial.println("\nWrite occured !");
73 | uint8_t* tag_buf;
74 | uint16_t length;
75 |
76 | nfc.getContent(&tag_buf, &length);
77 | NdefMessage msg = NdefMessage(tag_buf, length);
78 | msg.print();
79 | }
80 |
81 | delay(1000);
82 | }
83 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/iso14443a_uid/iso14443a_uid.pde:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | This example will attempt to connect to an ISO14443A
4 | card or tag and retrieve some basic information about it
5 | that can be used to determine what type of card it is.
6 |
7 | Note that you need the baud rate to be 115200 because we need to print
8 | out the data and read from the card at the same time!
9 |
10 | To enable debug message, define DEBUG in PN532/PN532_debug.h
11 |
12 | */
13 | /**************************************************************************/
14 |
15 |
16 | /* When the number after #if set as 1, it will be switch to SPI Mode*/
17 | #if 0
18 | #include
19 | #include
20 | #include "PN532.h"
21 |
22 | PN532_SPI pn532spi(SPI, 10);
23 | PN532 nfc(pn532spi);
24 |
25 | /* When the number after #elif set as 1, it will be switch to HSU Mode*/
26 | #elif 0
27 | #include
28 | #include
29 |
30 | PN532_HSU pn532hsu(Serial1);
31 | PN532 nfc(pn532hsu);
32 |
33 | /* When the number after #if & #elif set as 0, it will be switch to I2C Mode*/
34 | #else
35 | #include
36 | #include
37 | #include
38 | #include
39 |
40 | PN532_I2C pn532i2c(Wire);
41 | PN532 nfc(pn532i2c);
42 | #endif
43 |
44 | void setup(void) {
45 | Serial.begin(115200);
46 | Serial.println("Hello!");
47 |
48 | nfc.begin();
49 |
50 | uint32_t versiondata = nfc.getFirmwareVersion();
51 | if (! versiondata) {
52 | Serial.print("Didn't find PN53x board");
53 | while (1); // halt
54 | }
55 |
56 | // Got ok data, print it out!
57 | Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
58 | Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
59 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
60 |
61 | // Set the max number of retry attempts to read from a card
62 | // This prevents us from waiting forever for a card, which is
63 | // the default behaviour of the PN532.
64 | nfc.setPassiveActivationRetries(0xFF);
65 |
66 | // configure board to read RFID tags
67 | nfc.SAMConfig();
68 |
69 | Serial.println("Waiting for an ISO14443A card");
70 | }
71 |
72 | void loop(void) {
73 | boolean success;
74 | uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
75 | uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
76 |
77 | // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
78 | // 'uid' will be populated with the UID, and uidLength will indicate
79 | // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
80 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
81 |
82 | if (success) {
83 | Serial.println("Found a card!");
84 | Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
85 | Serial.print("UID Value: ");
86 | for (uint8_t i=0; i < uidLength; i++)
87 | {
88 | Serial.print(" 0x");Serial.print(uid[i], HEX);
89 | }
90 | Serial.println("");
91 | // Wait 1 second before continuing
92 | delay(1000);
93 | }
94 | else
95 | {
96 | // PN532 probably timed out waiting for a card
97 | Serial.println("Timed out waiting for a card");
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/mifareclassic_memdump/mifareclassic_memdump.pde:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | This example attempts to dump the contents of a Mifare Classic 1K card
4 |
5 | Note that you need the baud rate to be 115200 because we need to print
6 | out the data and read from the card at the same time!
7 |
8 | To enable debug message, define DEBUG in PN532/PN532_debug.h
9 | */
10 | /**************************************************************************/
11 |
12 | #if 0
13 | #include
14 | #include
15 | #include "PN532.h"
16 |
17 | PN532_SPI pn532spi(SPI, 10);
18 | PN532 nfc(pn532spi);
19 | #elif 1
20 | #include
21 | #include
22 |
23 | PN532_HSU pn532hsu(Serial1);
24 | PN532 nfc(pn532hsu);
25 | #else
26 | #include
27 | #include
28 | #include
29 | #endif
30 |
31 | void setup(void) {
32 | // has to be fast to dump the entire memory contents!
33 | Serial.begin(115200);
34 | Serial.println("Looking for PN532...");
35 |
36 | nfc.begin();
37 |
38 | uint32_t versiondata = nfc.getFirmwareVersion();
39 | if (! versiondata) {
40 | Serial.print("Didn't find PN53x board");
41 | while (1); // halt
42 | }
43 | // Got ok data, print it out!
44 | Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
45 | Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
46 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
47 |
48 | // configure board to read RFID tags
49 | nfc.SAMConfig();
50 |
51 | Serial.println("Waiting for an ISO14443A Card ...");
52 | }
53 |
54 |
55 | void loop(void) {
56 | uint8_t success; // Flag to check if there was an error with the PN532
57 | uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
58 | uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
59 | uint8_t currentblock; // Counter to keep track of which block we're on
60 | bool authenticated = false; // Flag to indicate if the sector is authenticated
61 | uint8_t data[16]; // Array to store block data during reads
62 |
63 | // Keyb on NDEF and Mifare Classic should be the same
64 | uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
65 |
66 | // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
67 | // 'uid' will be populated with the UID, and uidLength will indicate
68 | // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
69 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
70 |
71 | if (success) {
72 | // Display some basic information about the card
73 | Serial.println("Found an ISO14443A card");
74 | Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
75 | Serial.print(" UID Value: ");
76 | for (uint8_t i = 0; i < uidLength; i++) {
77 | Serial.print(uid[i], HEX);
78 | Serial.print(' ');
79 | }
80 | Serial.println("");
81 |
82 | if (uidLength == 4)
83 | {
84 | // We probably have a Mifare Classic card ...
85 | Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
86 |
87 | // Now we try to go through all 16 sectors (each having 4 blocks)
88 | // authenticating each sector, and then dumping the blocks
89 | for (currentblock = 0; currentblock < 64; currentblock++)
90 | {
91 | // Check if this is a new block so that we can reauthenticate
92 | if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false;
93 |
94 | // If the sector hasn't been authenticated, do so first
95 | if (!authenticated)
96 | {
97 | // Starting of a new sector ... try to to authenticate
98 | Serial.print("------------------------Sector ");Serial.print(currentblock/4, DEC);Serial.println("-------------------------");
99 | if (currentblock == 0)
100 | {
101 | // This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!)
102 | // or 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 for NDEF formatted cards using key a,
103 | // but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
104 | success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
105 | }
106 | else
107 | {
108 | // This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!)
109 | // or 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 for NDEF formatted cards using key a,
110 | // but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
111 | success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
112 | }
113 | if (success)
114 | {
115 | authenticated = true;
116 | }
117 | else
118 | {
119 | Serial.println("Authentication error");
120 | }
121 | }
122 | // If we're still not authenticated just skip the block
123 | if (!authenticated)
124 | {
125 | Serial.print("Block ");Serial.print(currentblock, DEC);Serial.println(" unable to authenticate");
126 | }
127 | else
128 | {
129 | // Authenticated ... we should be able to read the block now
130 | // Dump the data into the 'data' array
131 | success = nfc.mifareclassic_ReadDataBlock(currentblock, data);
132 | if (success)
133 | {
134 | // Read successful
135 | Serial.print("Block ");Serial.print(currentblock, DEC);
136 | if (currentblock < 10)
137 | {
138 | Serial.print(" ");
139 | }
140 | else
141 | {
142 | Serial.print(" ");
143 | }
144 | // Dump the raw data
145 | nfc.PrintHexChar(data, 16);
146 | }
147 | else
148 | {
149 | // Oops ... something happened
150 | Serial.print("Block ");Serial.print(currentblock, DEC);
151 | Serial.println(" unable to read this block");
152 | }
153 | }
154 | }
155 | }
156 | else
157 | {
158 | Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
159 | }
160 | }
161 | // Wait a bit before trying again
162 | Serial.println("\n\nSend a character to run the mem dumper again!");
163 | Serial.flush();
164 | while (!Serial.available());
165 | while (Serial.available()) {
166 | Serial.read();
167 | }
168 | Serial.flush();
169 | }
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/mifareclassic_updatendef/mifareclassic_updatendef.pde:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | Updates a sector that is already formatted for NDEF (using
4 | mifareclassic_formatndef.pde for example), inserting a new url
5 |
6 | To enable debug message, define DEBUG in PN532/PN532_debug.h
7 | */
8 | /**************************************************************************/
9 |
10 | #if 0
11 | #include
12 | #include
13 | #include "PN532.h"
14 |
15 | PN532_SPI pn532spi(SPI, 10);
16 | PN532 nfc(pn532spi);
17 | #elif 1
18 | #include
19 | #include
20 |
21 | PN532_HSU pn532hsu(Serial1);
22 | PN532 nfc(pn532hsu);
23 | #else
24 | #include
25 | #include
26 | #include
27 | #endif
28 |
29 |
30 | /*
31 | We can encode many different kinds of pointers to the card,
32 | from a URL, to an Email address, to a phone number, and many more
33 | check the library header .h file to see the large # of supported
34 | prefixes!
35 | */
36 | // For a http://www. url:
37 | const char * url = "elechouse.com";
38 | uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT;
39 |
40 | // for an email address
41 | //const char * url = "mail@example.com";
42 | //uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO;
43 |
44 | // for a phone number
45 | //const char * url = "+1 212 555 1212";
46 | //uint8_t ndefprefix = NDEF_URIPREFIX_TEL;
47 |
48 |
49 | void setup(void) {
50 | Serial.begin(115200);
51 | Serial.println("Looking for PN532...");
52 |
53 | nfc.begin();
54 |
55 | uint32_t versiondata = nfc.getFirmwareVersion();
56 | if (! versiondata) {
57 | Serial.print("Didn't find PN53x board");
58 | while (1); // halt
59 | }
60 |
61 | // Got ok data, print it out!
62 | Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
63 | Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
64 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
65 |
66 | // configure board to read RFID tags
67 | nfc.SAMConfig();
68 | }
69 |
70 | void loop(void) {
71 | uint8_t success; // Flag to check if there was an error with the PN532
72 | uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
73 | uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
74 | bool authenticated = false; // Flag to indicate if the sector is authenticated
75 |
76 | // Use the default NDEF keys (these would have have set by mifareclassic_formatndef.pde!)
77 | uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };
78 | uint8_t keyb[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
79 |
80 | Serial.println("Place your NDEF formatted Mifare Classic card on the reader to update the");
81 | Serial.println("NDEF record and press any key to continue ...");
82 | // Wait for user input before proceeding
83 | while (!Serial.available());
84 | // a key was pressed1
85 | while (Serial.available()) Serial.read();
86 |
87 | // Wait for an ISO14443A type card (Mifare, etc.). When one is found
88 | // 'uid' will be populated with the UID, and uidLength will indicate
89 | // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
90 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
91 |
92 | if (success)
93 | {
94 | // Display some basic information about the card
95 | Serial.println("Found an ISO14443A card");
96 | Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
97 | Serial.print(" UID Value: ");
98 | nfc.PrintHex(uid, uidLength);
99 | Serial.println("");
100 |
101 | // Make sure this is a Mifare Classic card
102 | if (uidLength != 4)
103 | {
104 | Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
105 | return;
106 | }
107 |
108 | // We probably have a Mifare Classic card ...
109 | Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
110 |
111 | // Check if this is an NDEF card (using first block of sector 1 from mifareclassic_formatndef.pde)
112 | // Must authenticate on the first key using 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7
113 | success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keyb);
114 | if (!success)
115 | {
116 | Serial.println("Unable to authenticate block 4 ... is this card NDEF formatted?");
117 | return;
118 | }
119 |
120 | Serial.println("Authentication succeeded (seems to be an NDEF/NFC Forum tag) ...");
121 |
122 | // Authenticated seems to have worked
123 | // Try to write an NDEF record to sector 1
124 | // Use 0x01 for the URI Identifier Code to prepend "http://www."
125 | // to the url (and save some space). For information on URI ID Codes
126 | // see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef
127 | if (strlen(url) > 38)
128 | {
129 | // The length is also checked in the WriteNDEFURI function, but lets
130 | // warn users here just in case they change the value and it's bigger
131 | // than it should be
132 | Serial.println("URI is too long ... must be less than 38 characters!");
133 | return;
134 | }
135 |
136 | Serial.println("Updating sector 1 with URI as NDEF Message");
137 |
138 | // URI is within size limits ... write it to the card and report success/failure
139 | success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url);
140 | if (success)
141 | {
142 | Serial.println("NDEF URI Record written to sector 1");
143 | Serial.println("");
144 | }
145 | else
146 | {
147 | Serial.println("NDEF Record creation failed! :(");
148 | }
149 | }
150 |
151 | // Wait a bit before trying again
152 | Serial.println("\n\nDone!");
153 | delay(1000);
154 | Serial.flush();
155 | while(Serial.available()) Serial.read();
156 | }
157 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/p2p_raw/p2p_raw.ino:
--------------------------------------------------------------------------------
1 | // snep_test.ino
2 | // send a SNEP message to adnroid and get a message from android
3 |
4 | #include "SPI.h"
5 | #include "PN532_SPI.h"
6 | #include "llcp.h"
7 | #include "snep.h"
8 |
9 | PN532_SPI pn532spi(SPI, 10);
10 | SNEP nfc(pn532spi);
11 |
12 | void setup()
13 | {
14 | Serial.begin(115200);
15 | Serial.println("-------Peer to Peer--------");
16 | }
17 |
18 | uint8_t message[] = {
19 | 0xD2, 0xA, 0xB, 0x74,0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C,
20 | 0x61, 0x69, 0x6E, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77,
21 | 0x6F, 0x72, 0x6C, 0x64};
22 |
23 | uint8_t buf[128];
24 |
25 | void loop()
26 | {
27 |
28 | nfc.write(message, sizeof(message));
29 | delay(3000);
30 |
31 | int16_t len = nfc.read(buf, sizeof(buf));
32 | if (len > 0) {
33 | Serial.println("get a SNEP message:");
34 | for (uint8_t i = 0; i < len; i++) {
35 | Serial.print(buf[i], HEX);
36 | Serial.print(' ');
37 | }
38 | Serial.print('\n');
39 | for (uint8_t i = 0; i < len; i++) {
40 | char c = buf[i];
41 | if (c <= 0x1f || c > 0x7f) {
42 | Serial.print('.');
43 | } else {
44 | Serial.print(c);
45 | }
46 | }
47 | Serial.print('\n');
48 | }
49 | delay(3000);
50 | }
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/p2p_with_ndef_library/p2p_with_ndef_library.ino:
--------------------------------------------------------------------------------
1 | // send a NDEF message to adnroid or get a NDEF message
2 | //
3 | // note: [NDEF library](https://github.com/Don/NDEF) is needed.
4 |
5 | #include "SPI.h"
6 | #include "PN532_SPI.h"
7 | #include "snep.h"
8 | #include "NdefMessage.h"
9 |
10 | PN532_SPI pn532spi(SPI, 10);
11 | SNEP nfc(pn532spi);
12 | uint8_t ndefBuf[128];
13 |
14 | void setup()
15 | {
16 | Serial.begin(115200);
17 | Serial.println("-------Peer to Peer--------");
18 | }
19 |
20 | void loop()
21 | {
22 | #if 1
23 | Serial.println("Send a message to Android");
24 | NdefMessage message = NdefMessage();
25 | message.addUriRecord("http://www.seeedstudio.com");
26 | int messageSize = message.getEncodedSize();
27 | if (messageSize > sizeof(ndefBuf)) {
28 | Serial.println("ndefBuf is too small");
29 | while (1) {
30 | }
31 |
32 | }
33 |
34 | message.encode(ndefBuf);
35 | if (0 >= nfc.write(ndefBuf, messageSize)) {
36 | Serial.println("Failed");
37 | } else {
38 | Serial.println("Success");
39 | }
40 |
41 | delay(3000);
42 | #else
43 | // it seems there are some issues to use NdefMessage to decode the received data from Android
44 | Serial.println("Get a message from Android");
45 | int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf));
46 | if (msgSize > 0) {
47 | NdefMessage msg = NdefMessage(ndefBuf, msgSize);
48 | msg.print();
49 | Serial.println("\nSuccess");
50 | } else {
51 | Serial.println("failed");
52 | }
53 | delay(3000);
54 | #endif
55 | }
56 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/examples/readMifare/readMifare.pde:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | This example will wait for any ISO14443A card or tag, and
4 | depending on the size of the UID will attempt to read from it.
5 |
6 | If the card has a 4-byte UID it is probably a Mifare
7 | Classic card, and the following steps are taken:
8 |
9 | - Authenticate block 4 (the first block of Sector 1) using
10 | the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
11 | - If authentication succeeds, we can then read any of the
12 | 4 blocks in that sector (though only block 4 is read here)
13 |
14 | If the card has a 7-byte UID it is probably a Mifare
15 | Ultralight card, and the 4 byte pages can be read directly.
16 | Page 4 is read by default since this is the first 'general-
17 | purpose' page on the tags.
18 |
19 | To enable debug message, define DEBUG in PN532/PN532_debug.h
20 | */
21 | /**************************************************************************/
22 |
23 | #if 0
24 | #include
25 | #include
26 | #include "PN532.h"
27 |
28 | PN532_SPI pn532spi(SPI, 10);
29 | PN532 nfc(pn532spi);
30 | #elif 1
31 | #include
32 | #include
33 |
34 | PN532_HSU pn532hsu(Serial1);
35 | PN532 nfc(pn532hsu);
36 | #else
37 | #include
38 | #include
39 | #include
40 | PN532_I2C pn532i2c(Wire);
41 | PN532 nfc(pn532i2c);
42 | #endif
43 | void setup(void) {
44 | Serial.begin(115200);
45 | Serial.println("Hello!");
46 |
47 | nfc.begin();
48 |
49 | uint32_t versiondata = nfc.getFirmwareVersion();
50 | if (! versiondata) {
51 | Serial.print("Didn't find PN53x board");
52 | while (1); // halt
53 | }
54 | // Got ok data, print it out!
55 | Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
56 | Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
57 | Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
58 |
59 | // configure board to read RFID tags
60 | nfc.SAMConfig();
61 |
62 | Serial.println("Waiting for an ISO14443A Card ...");
63 | }
64 |
65 |
66 | void loop(void) {
67 | uint8_t success;
68 | uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
69 | uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
70 |
71 | // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
72 | // 'uid' will be populated with the UID, and uidLength will indicate
73 | // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
74 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
75 |
76 | if (success) {
77 | // Display some basic information about the card
78 | Serial.println("Found an ISO14443A card");
79 | Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
80 | Serial.print(" UID Value: ");
81 | nfc.PrintHex(uid, uidLength);
82 | Serial.println("");
83 |
84 | if (uidLength == 4)
85 | {
86 | // We probably have a Mifare Classic card ...
87 | Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
88 |
89 | // Now we need to try to authenticate it for read/write access
90 | // Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
91 | Serial.println("Trying to authenticate block 4 with default KEYA value");
92 | uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
93 |
94 | // Start with block 4 (the first block of sector 1) since sector 0
95 | // contains the manufacturer data and it's probably better just
96 | // to leave it alone unless you know what you're doing
97 | success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
98 |
99 | if (success)
100 | {
101 | Serial.println("Sector 1 (Blocks 4..7) has been authenticated");
102 | uint8_t data[16];
103 |
104 | // If you want to write something to block 4 to test with, uncomment
105 | // the following line and this text should be read back in a minute
106 | // data = { 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0};
107 | // success = nfc.mifareclassic_WriteDataBlock (4, data);
108 |
109 | // Try to read the contents of block 4
110 | success = nfc.mifareclassic_ReadDataBlock(4, data);
111 |
112 | if (success)
113 | {
114 | // Data seems to have been read ... spit it out
115 | Serial.println("Reading Block 4:");
116 | nfc.PrintHexChar(data, 16);
117 | Serial.println("");
118 |
119 | // Wait a bit before reading the card again
120 | delay(1000);
121 | }
122 | else
123 | {
124 | Serial.println("Ooops ... unable to read the requested block. Try another key?");
125 | }
126 | }
127 | else
128 | {
129 | Serial.println("Ooops ... authentication failed: Try another key?");
130 | }
131 | }
132 |
133 | if (uidLength == 7)
134 | {
135 | // We probably have a Mifare Ultralight card ...
136 | Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)");
137 |
138 | // Try to read the first general-purpose user page (#4)
139 | Serial.println("Reading page 4");
140 | uint8_t data[32];
141 | success = nfc.mifareultralight_ReadPage (4, data);
142 | if (success)
143 | {
144 | // Data seems to have been read ... spit it out
145 | nfc.PrintHexChar(data, 4);
146 | Serial.println("");
147 |
148 | // Wait a bit before reading the card again
149 | delay(1000);
150 | }
151 | else
152 | {
153 | Serial.println("Ooops ... unable to read the requested page!?");
154 | }
155 | }
156 | }
157 | }
158 |
159 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/license.txt:
--------------------------------------------------------------------------------
1 | Software License Agreement (BSD License)
2 |
3 | Copyright (c) 2012, Adafruit Industries
4 | Copyright (c) 2013, Seeed Technology Inc.
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above copyright
12 | notice, this list of conditions and the following disclaimer in the
13 | documentation and/or other materials provided with the distribution.
14 | 3. Neither the name of the copyright holders nor the
15 | names of its contributors may be used to endorse or promote products
16 | derived from this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/llcp.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __LLCP_H__
3 | #define __LLCP_H__
4 |
5 | #include "mac_link.h"
6 |
7 | #define LLCP_DEFAULT_TIMEOUT 20000
8 | #define LLCP_DEFAULT_DSAP 0x04
9 | #define LLCP_DEFAULT_SSAP 0x20
10 |
11 | class LLCP {
12 | public:
13 | LLCP(PN532Interface &interface) : link(interface) {
14 | headerBuf = link.getHeaderBuffer(&headerBufLen);
15 | ns = 0;
16 | nr = 0;
17 | };
18 |
19 | /**
20 | * @brief Actiave PN532 as a target
21 | * @param timeout max time to wait, 0 means no timeout
22 | * @return > 0 success
23 | * = 0 timeout
24 | * < 0 failed
25 | */
26 | int8_t activate(uint16_t timeout = 0);
27 |
28 | int8_t waitForConnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
29 |
30 | int8_t waitForDisconnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
31 |
32 | int8_t connect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
33 |
34 | int8_t disconnect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
35 |
36 | /**
37 | * @brief write a packet, the packet should be less than (255 - 2) bytes
38 | * @param header packet header
39 | * @param hlen length of header
40 | * @param body packet body
41 | * @param blen length of body
42 | * @return true success
43 | * false failed
44 | */
45 | bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
46 |
47 | /**
48 | * @brief read a packet, the packet will be less than (255 - 2) bytes
49 | * @param buf the buffer to contain the packet
50 | * @param len lenght of the buffer
51 | * @return >=0 length of the packet
52 | * <0 failed
53 | */
54 | int16_t read(uint8_t *buf, uint8_t len);
55 |
56 | uint8_t *getHeaderBuffer(uint8_t *len) {
57 | uint8_t *buf = link.getHeaderBuffer(len);
58 | len -= 3; // I PDU header has 3 bytes
59 | return buf;
60 | };
61 |
62 | private:
63 | MACLink link;
64 | uint8_t mode;
65 | uint8_t ssap;
66 | uint8_t dsap;
67 | uint8_t *headerBuf;
68 | uint8_t headerBufLen;
69 | uint8_t ns; // Number of I PDU Sent
70 | uint8_t nr; // Number of I PDU Received
71 |
72 | static uint8_t SYMM_PDU[2];
73 | };
74 |
75 | #endif // __LLCP_H__
76 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/mac_link.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "mac_link.h"
3 | #include "PN532_debug.h"
4 |
5 | int8_t MACLink::activateAsTarget(uint16_t timeout)
6 | {
7 | pn532.begin();
8 | pn532.SAMConfig();
9 | return pn532.tgInitAsTarget(timeout);
10 | }
11 |
12 | bool MACLink::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
13 | {
14 | return pn532.tgSetData(header, hlen, body, blen);
15 | }
16 |
17 | int16_t MACLink::read(uint8_t *buf, uint8_t len)
18 | {
19 | return pn532.tgGetData(buf, len);
20 | }
21 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/mac_link.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifndef __MAC_LINK_H__
4 | #define __MAC_LINK_H__
5 |
6 | #include "PN532.h"
7 |
8 | class MACLink {
9 | public:
10 | MACLink(PN532Interface &interface) : pn532(interface) {
11 |
12 | };
13 |
14 | /**
15 | * @brief Activate PN532 as a target
16 | * @param timeout max time to wait, 0 means no timeout
17 | * @return > 0 success
18 | * = 0 timeout
19 | * < 0 failed
20 | */
21 | int8_t activateAsTarget(uint16_t timeout = 0);
22 |
23 | /**
24 | * @brief write a PDU packet, the packet should be less than (255 - 2) bytes
25 | * @param header packet header
26 | * @param hlen length of header
27 | * @param body packet body
28 | * @param blen length of body
29 | * @return true success
30 | * false failed
31 | */
32 | bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
33 |
34 | /**
35 | * @brief read a PDU packet, the packet will be less than (255 - 2) bytes
36 | * @param buf the buffer to contain the PDU packet
37 | * @param len lenght of the buffer
38 | * @return >=0 length of the PDU packet
39 | * <0 failed
40 | */
41 | int16_t read(uint8_t *buf, uint8_t len);
42 |
43 | uint8_t *getHeaderBuffer(uint8_t *len) {
44 | return pn532.getBuffer(len);
45 | };
46 |
47 | private:
48 | PN532 pn532;
49 | };
50 |
51 | #endif // __MAC_LINK_H__
52 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/snep.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "snep.h"
3 | #include "PN532_debug.h"
4 |
5 | int8_t SNEP::write(const uint8_t *buf, uint8_t len, uint16_t timeout)
6 | {
7 | if (0 >= llcp.activate(timeout)) {
8 | DMSG("failed to activate PN532 as a target\n");
9 | return -1;
10 | }
11 |
12 | if (0 >= llcp.connect(timeout)) {
13 | DMSG("failed to set up a connection\n");
14 | return -2;
15 | }
16 |
17 | // response a success SNEP message
18 | headerBuf[0] = SNEP_DEFAULT_VERSION;
19 | headerBuf[1] = SNEP_REQUEST_PUT;
20 | headerBuf[2] = 0;
21 | headerBuf[3] = 0;
22 | headerBuf[4] = 0;
23 | headerBuf[5] = len;
24 | if (0 >= llcp.write(headerBuf, 6, buf, len)) {
25 | return -3;
26 | }
27 |
28 | uint8_t rbuf[16];
29 | if (6 > llcp.read(rbuf, sizeof(rbuf))) {
30 | return -4;
31 | }
32 |
33 | // check SNEP version
34 | if (SNEP_DEFAULT_VERSION != rbuf[0]) {
35 | DMSG("The received SNEP message's major version is different\n");
36 | // To-do: send Unsupported Version response
37 | return -4;
38 | }
39 |
40 | // expect a put request
41 | if (SNEP_RESPONSE_SUCCESS != rbuf[1]) {
42 | DMSG("Expect a success response\n");
43 | return -4;
44 | }
45 |
46 | llcp.disconnect(timeout);
47 |
48 | return 1;
49 | }
50 |
51 | int16_t SNEP::read(uint8_t *buf, uint8_t len, uint16_t timeout)
52 | {
53 | if (0 >= llcp.activate(timeout)) {
54 | DMSG("failed to activate PN532 as a target\n");
55 | return -1;
56 | }
57 |
58 | if (0 >= llcp.waitForConnection(timeout)) {
59 | DMSG("failed to set up a connection\n");
60 | return -2;
61 | }
62 |
63 | uint16_t status = llcp.read(buf, len);
64 | if (6 > status) {
65 | return -3;
66 | }
67 |
68 |
69 | // check SNEP version
70 | if (SNEP_DEFAULT_VERSION != buf[0]) {
71 | DMSG("The received SNEP message's major version is different\n");
72 | // To-do: send Unsupported Version response
73 | return -4;
74 | }
75 |
76 | // expect a put request
77 | if (SNEP_REQUEST_PUT != buf[1]) {
78 | DMSG("Expect a put request\n");
79 | return -4;
80 | }
81 |
82 | // check message's length
83 | uint32_t length = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8) + buf[5];
84 | // length should not be more than 244 (header + body < 255, header = 6 + 3 + 2)
85 | if (length > (status - 6)) {
86 | DMSG("The SNEP message is too large: ");
87 | DMSG_INT(length);
88 | DMSG_INT(status - 6);
89 | DMSG("\n");
90 | return -4;
91 | }
92 | for (uint8_t i = 0; i < length; i++) {
93 | buf[i] = buf[i + 6];
94 | }
95 |
96 | // response a success SNEP message
97 | headerBuf[0] = SNEP_DEFAULT_VERSION;
98 | headerBuf[1] = SNEP_RESPONSE_SUCCESS;
99 | headerBuf[2] = 0;
100 | headerBuf[3] = 0;
101 | headerBuf[4] = 0;
102 | headerBuf[5] = 0;
103 | llcp.write(headerBuf, 6);
104 |
105 | return length;
106 | }
107 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532/snep.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifndef __SNEP_H__
4 | #define __SNEP_H__
5 |
6 | #include "llcp.h"
7 |
8 | #define SNEP_DEFAULT_VERSION 0x10 // Major: 1, Minor: 0
9 |
10 | #define SNEP_REQUEST_PUT 0x02
11 | #define SNEP_REQUEST_GET 0x01
12 |
13 | #define SNEP_RESPONSE_SUCCESS 0x81
14 | #define SNEP_RESPONSE_REJECT 0xFF
15 |
16 | class SNEP {
17 | public:
18 | SNEP(PN532Interface &interface) : llcp(interface) {
19 | headerBuf = llcp.getHeaderBuffer(&headerBufLen);
20 | };
21 |
22 | /**
23 | * @brief write a SNEP packet, the packet should be less than (255 - 2 - 3) bytes
24 | * @param buf the buffer to contain the packet
25 | * @param len lenght of the buffer
26 | * @param timeout max time to wait, 0 means no timeout
27 | * @return >0 success
28 | * =0 timeout
29 | * <0 failed
30 | */
31 | int8_t write(const uint8_t *buf, uint8_t len, uint16_t timeout = 0);
32 |
33 | /**
34 | * @brief read a SNEP packet, the packet will be less than (255 - 2 - 3) bytes
35 | * @param buf the buffer to contain the packet
36 | * @param len lenght of the buffer
37 | * @param timeout max time to wait, 0 means no timeout
38 | * @return >=0 length of the packet
39 | * <0 failed
40 | */
41 | int16_t read(uint8_t *buf, uint8_t len, uint16_t timeout = 0);
42 |
43 | private:
44 | LLCP llcp;
45 | uint8_t *headerBuf;
46 | uint8_t headerBufLen;
47 | };
48 |
49 | #endif // __SNEP_H__
50 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532_HSU/PN532_HSU.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "PN532_HSU.h"
3 | #include "PN532_debug.h"
4 |
5 |
6 | PN532_HSU::PN532_HSU(HardwareSerial &serial)
7 | {
8 | _serial = &serial;
9 | command = 0;
10 | }
11 |
12 | void PN532_HSU::begin()
13 | {
14 | _serial->begin(115200);
15 | }
16 |
17 | void PN532_HSU::wakeup()
18 | {
19 | _serial->write(0x55);
20 | _serial->write(0x55);
21 | _serial->write(0);
22 | _serial->write(0);
23 | _serial->write(0);
24 |
25 | /** dump serial buffer */
26 | if(_serial->available()){
27 | DMSG("Dump serial buffer: ");
28 | }
29 | while(_serial->available()){
30 | uint8_t ret = _serial->read();
31 | DMSG_HEX(ret);
32 | }
33 |
34 | }
35 |
36 | int8_t PN532_HSU::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
37 | {
38 |
39 | /** dump serial buffer */
40 | if(_serial->available()){
41 | DMSG("Dump serial buffer: ");
42 | }
43 | while(_serial->available()){
44 | uint8_t ret = _serial->read();
45 | DMSG_HEX(ret);
46 | }
47 |
48 | command = header[0];
49 |
50 | _serial->write(PN532_PREAMBLE);
51 | _serial->write(PN532_STARTCODE1);
52 | _serial->write(PN532_STARTCODE2);
53 |
54 | uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA
55 | _serial->write(length);
56 | _serial->write(~length + 1); // checksum of length
57 |
58 | _serial->write(PN532_HOSTTOPN532);
59 | uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA
60 |
61 | DMSG("\nWrite: ");
62 |
63 | _serial->write(header, hlen);
64 | for (uint8_t i = 0; i < hlen; i++) {
65 | sum += header[i];
66 |
67 | DMSG_HEX(header[i]);
68 | }
69 |
70 | _serial->write(body, blen);
71 | for (uint8_t i = 0; i < blen; i++) {
72 | sum += body[i];
73 |
74 | DMSG_HEX(body[i]);
75 | }
76 |
77 | uint8_t checksum = ~sum + 1; // checksum of TFI + DATA
78 | _serial->write(checksum);
79 | _serial->write(PN532_POSTAMBLE);
80 |
81 | return readAckFrame();
82 | }
83 |
84 | int16_t PN532_HSU::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout)
85 | {
86 | uint8_t tmp[3];
87 |
88 | DMSG("\nRead: ");
89 |
90 | /** Frame Preamble and Start Code */
91 | if(receive(tmp, 3, timeout)<=0){
92 | return PN532_TIMEOUT;
93 | }
94 | if(0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]){
95 | DMSG("Preamble error");
96 | return PN532_INVALID_FRAME;
97 | }
98 |
99 | /** receive length and check */
100 | uint8_t length[2];
101 | if(receive(length, 2, timeout) <= 0){
102 | return PN532_TIMEOUT;
103 | }
104 | if( 0 != (uint8_t)(length[0] + length[1]) ){
105 | DMSG("Length error");
106 | return PN532_INVALID_FRAME;
107 | }
108 | length[0] -= 2;
109 | if( length[0] > len){
110 | return PN532_NO_SPACE;
111 | }
112 |
113 | /** receive command byte */
114 | uint8_t cmd = command + 1; // response command
115 | if(receive(tmp, 2, timeout) <= 0){
116 | return PN532_TIMEOUT;
117 | }
118 | if( PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]){
119 | DMSG("Command error");
120 | return PN532_INVALID_FRAME;
121 | }
122 |
123 | if(receive(buf, length[0], timeout) != length[0]){
124 | return PN532_TIMEOUT;
125 | }
126 | uint8_t sum = PN532_PN532TOHOST + cmd;
127 | for(uint8_t i=0; i return value buffer.
165 | len --> length expect to receive.
166 | timeout --> time of reveiving
167 | @retval number of received bytes, 0 means no data received.
168 | */
169 | int8_t PN532_HSU::receive(uint8_t *buf, int len, uint16_t timeout)
170 | {
171 | int read_bytes = 0;
172 | int ret;
173 | unsigned long start_millis;
174 |
175 | while (read_bytes < len) {
176 | start_millis = millis();
177 | do {
178 | ret = _serial->read();
179 | if (ret >= 0) {
180 | break;
181 | }
182 | } while((timeout == 0) || ((millis()- start_millis ) < timeout));
183 |
184 | if (ret < 0) {
185 | if(read_bytes){
186 | return read_bytes;
187 | }else{
188 | return PN532_TIMEOUT;
189 | }
190 | }
191 | buf[read_bytes] = (uint8_t)ret;
192 | DMSG_HEX(ret);
193 | read_bytes++;
194 | }
195 | return read_bytes;
196 | }
197 |
--------------------------------------------------------------------------------
/mu3controller/lib/PN532_HSU/PN532_HSU.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __PN532_HSU_H__
3 | #define __PN532_HSU_H__
4 |
5 | #include "PN532Interface.h"
6 | #include "Arduino.h"
7 |
8 | #define PN532_HSU_DEBUG
9 |
10 | #define PN532_HSU_READ_TIMEOUT (1000)
11 |
12 | class PN532_HSU : public PN532Interface {
13 | public:
14 | PN532_HSU(HardwareSerial &serial);
15 |
16 | void begin();
17 | void wakeup();
18 | virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
19 | int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout);
20 |
21 | private:
22 | HardwareSerial* _serial;
23 | uint8_t command;
24 |
25 | int8_t readAckFrame();
26 |
27 | int8_t receive(uint8_t *buf, int len, uint16_t timeout=PN532_HSU_READ_TIMEOUT);
28 | };
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/mu3controller/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/mu3controller/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:leonardo]
12 | platform = atmelavr
13 | board = leonardo
14 | framework = arduino
15 | lib_deps =
16 | fastled/FastLED@^3.4.0
17 | nicohood/HID-Project@^2.8.4
18 | dxinteractive/ResponsiveAnalogRead@^1.2.1
19 |
--------------------------------------------------------------------------------
/mu3controller/src/components/card_reader.hpp:
--------------------------------------------------------------------------------
1 | #ifndef __CARD_READER_H__
2 | #define __CARD_READER_H__
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #define SerialDevice SerialUSB
9 |
10 | #define NFC_STATE_NONE 0
11 | #define NFC_STATE_AIME 1
12 | #define NFC_STATE_FELICA 2
13 | #define NFC_STATE_BANA 4
14 | #define NFC_STATE_FAKE_AIME 8
15 | #define NFC_STATE_FAKE_FELICA 16
16 | #define NFC_STATE_OTHER 32
17 | #define NFC_STATE_ERROR 64
18 | #define NFC_STATE_NO_DEVICE 128
19 |
20 | #define NFC_POLL_INTERVAL 2000
21 |
22 | #define AIME_ALLOW 1
23 | #define FELICA_ALLOW 1
24 | #define BANA_ALLOW 1
25 | #define MIFARE_FAKE_AIME 1
26 | #define MIFARE_FAKE_FELICA 0
27 |
28 | typedef union
29 | {
30 | uint8_t luid[10];
31 | struct
32 | {
33 | uint8_t IDm[8];
34 | uint8_t PMm[8];
35 | union
36 | {
37 | uint16_t SystemCode;
38 | uint8_t System_Code[2];
39 | };
40 | };
41 | } Card;
42 |
43 | #define M2F_B 1
44 |
45 | extern bool nfc_enable;
46 | extern uint8_t card_type;
47 | extern Card card;
48 |
49 | extern void nfc_setup(void);
50 | extern void nfc_poll(void);
51 | extern void nfc_end(void);
52 | extern void PrintHex(const uint8_t *data, const uint32_t numBytes);
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/mu3controller/src/components/comio.hpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 |
3 | #ifdef LED_BOARD
4 | enum io_packet_type_t : uint8_t
5 | {
6 | PACKET_TYPE_REQUEST,
7 | PACKET_TYPE_RESPONSE,
8 | };
9 |
10 | enum io_ack_status_t : uint8_t
11 | {
12 | ACK_OK = 1,
13 | ACK_SUM_ERROR,
14 | ACK_PARITY_ERROR,
15 | ACK_FARMING_ERROR,
16 | ACK_OVER_RUN_ERROR,
17 | ACK_RECV_BUFFER_OVERFLOW,
18 | ACK_INVALID = 255,
19 | };
20 |
21 | enum io_report_status_t : uint8_t
22 | {
23 | REPORT_OK = 1,
24 | REPORT_BUSY,
25 | REPORT_UNKNOWN_COMMAND,
26 | REPORT_PARAM_ERROR,
27 | REPORT_INVALID = 255,
28 | };
29 |
30 | enum io_command_num_t : uint8_t
31 | {
32 | CMD_RESET = 16,
33 | CMD_SET_TIMEOUT,
34 |
35 | CMD_SET_DISABLE = 20,
36 |
37 | CMD_SET_LED_DIRECT = 130,
38 |
39 | CMD_BOARD_INFO = 240,
40 | CMD_BOARD_STATUS,
41 | CMD_FIRM_SUM,
42 | CMD_PROTOCOL_VERSION,
43 | };
44 |
45 | struct io_reqeust_t
46 | {
47 | io_command_num_t command;
48 | uint8_t data[1];
49 | // last byte: uint8_t checksum;
50 | };
51 |
52 | struct io_response_t
53 | {
54 | io_ack_status_t status;
55 | io_command_num_t command;
56 | io_report_status_t report;
57 | uint8_t data[1];
58 | // last byte: uint8_t checksum;
59 | };
60 |
61 | union io_packet_t
62 | {
63 | uint8_t buffer[1];
64 | struct {
65 | uint8_t sync;
66 | uint8_t dstNodeId;
67 | uint8_t srcNodeId;
68 | uint8_t length;
69 | union {
70 | io_reqeust_t request;
71 | io_response_t response;
72 | };
73 | };
74 | };
75 |
76 | inline io_packet_t* io_alloc(io_packet_type_t type, size_t size)
77 | {
78 | size += 5;
79 |
80 | if (type == PACKET_TYPE_RESPONSE)
81 | size += 2;
82 |
83 | return (io_packet_t*)malloc(size);
84 | }
85 |
86 | inline void io_fill_data(io_packet_t* packet, uint8_t dstNodeId, uint8_t srcNodeId)
87 | {
88 | packet->sync = 224;
89 | packet->dstNodeId = dstNodeId;
90 | packet->srcNodeId = srcNodeId;
91 | }
92 |
93 | inline size_t io_get_packet_size(io_packet_t* packet, io_packet_type_t type)
94 | {
95 | return packet->length + 5;
96 | }
97 |
98 | inline void io_apply_checksum(io_packet_t* packet)
99 | {
100 | packet->length += 3;
101 | auto totalLen = io_get_packet_size(packet, PACKET_TYPE_RESPONSE);
102 |
103 | uint8_t checksum = 0;
104 | checksum += packet->dstNodeId;
105 | checksum += packet->srcNodeId;
106 | checksum += packet->length;
107 | checksum += packet->response.status;
108 | checksum += packet->response.command;
109 | checksum += packet->response.report;
110 |
111 | for (auto i = 0; i < packet->length - 3; i++)
112 | checksum += packet->response.data[i];
113 |
114 | packet->request.data[totalLen - 6] = checksum;
115 | }
116 |
117 | inline size_t io_build_board_info(uint8_t* buffer, size_t bufferSize, const char* boardNo, const char* chipNo, uint8_t revision)
118 | {
119 | size_t boardNoLen = strlen(boardNo);
120 | size_t chipNoLen = strlen(chipNo);
121 | size_t totalLen = strlen(boardNo) + strlen(chipNo) + 3;
122 |
123 | if (bufferSize <= totalLen)
124 | return -1;
125 |
126 | memcpy(buffer, boardNo, boardNoLen);
127 | memcpy(buffer + (boardNoLen + 1), chipNo, chipNoLen);
128 |
129 | buffer[boardNoLen] = 10;
130 | buffer[boardNoLen + chipNoLen + 1] = 255;
131 | buffer[boardNoLen + chipNoLen + 2] = revision;
132 |
133 | return totalLen;
134 | }
135 |
136 | inline size_t io_build_firmsum(uint8_t* buffer, size_t bufferSize, uint16_t sum)
137 | {
138 | const size_t totalLen = 2;
139 |
140 | if (bufferSize <= totalLen)
141 | return -1;
142 |
143 | // big-endian
144 | uint8_t* buf = (uint8_t*)∑
145 | buffer[0] = buf[1];
146 | buffer[1] = buf[0];
147 |
148 | return totalLen;
149 | }
150 |
151 | inline size_t io_build_protocol_version(uint8_t* buffer, size_t bufferSize, uint8_t major, uint8_t minor)
152 | {
153 | const size_t totalLen = 3;
154 |
155 | if (bufferSize <= totalLen)
156 | return -1;
157 |
158 | buffer[0] = 1;
159 | buffer[1] = major;
160 | buffer[2] = minor;
161 |
162 | return totalLen;
163 | }
164 |
165 | inline size_t io_build_timeout(uint8_t* buffer, size_t bufferSize, uint16_t timeout)
166 | {
167 | const size_t totalLen = 2;
168 |
169 | if (bufferSize <= totalLen)
170 | return -1;
171 |
172 | // big-endian
173 | uint8_t* buf = (uint8_t*)&timeout;
174 | buffer[0] = buf[1];
175 | buffer[1] = buf[0];
176 |
177 | return totalLen;
178 | }
179 |
180 | inline size_t io_build_board_status(uint8_t* buffer, size_t bufferSize, uint8_t boardFlag, uint8_t uartFlag, uint8_t cmdFlag)
181 | {
182 | const size_t totalLen = 3;
183 |
184 | if (bufferSize <= totalLen)
185 | return -1;
186 |
187 | buffer[0] = boardFlag;
188 | buffer[1] = uartFlag;
189 | buffer[2] = cmdFlag;
190 |
191 | return totalLen;
192 | }
193 |
194 | inline size_t io_build_set_disable(uint8_t* buffer, size_t bufferSize, uint8_t disable)
195 | {
196 | const size_t totalLen = 1;
197 |
198 | if (bufferSize <= totalLen)
199 | return -1;
200 |
201 | buffer[0] = disable;
202 |
203 | return totalLen;
204 | }
205 | #endif
--------------------------------------------------------------------------------
/mu3controller/src/components/keyboard.cpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 | namespace component
3 | {
4 | namespace keyboard
5 | {
6 | const KeyboardKeycode KEY_MAP[12] = {
7 | // L: A B C SIDE MENU
8 | KeyboardKeycode::KEY_A,
9 | KeyboardKeycode::KEY_S,
10 | KeyboardKeycode::KEY_D,
11 | KeyboardKeycode::KEY_LEFT_SHIFT,
12 | KeyboardKeycode::KEY_ESC,
13 | // R: A B C SIDE MENU
14 | KeyboardKeycode::KEY_L,
15 | KeyboardKeycode::KEY_SEMICOLON,
16 | KeyboardKeycode::KEY_QUOTE,
17 | KeyboardKeycode::KEY_RIGHT_SHIFT,
18 | KeyboardKeycode::KEY_BACKSPACE,
19 | // FN1 FN2
20 | KeyboardKeycode::KEY_RESERVED,
21 | KeyboardKeycode::KEY_E,
22 | };
23 |
24 |
25 | void start()
26 | {
27 | Keyboard.begin();
28 | // 所有键盘按键松开/Releasekeyboard
29 | Keyboard.releaseAll();
30 | }
31 |
32 | void end()
33 | {
34 | Keyboard.releaseAll();
35 | Keyboard.end();
36 | }
37 |
38 | void update()
39 | {
40 | for (auto i = 0; i < 12; i++)
41 | {
42 | bool status = manager::key_status[i];
43 | if (status)
44 | {
45 | Keyboard.press(KEY_MAP[i]);
46 | }
47 | else
48 | {
49 | Keyboard.release(KEY_MAP[i]);
50 | }
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/mu3controller/src/components/keyboard.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace component
4 | {
5 | namespace keyboard
6 | {
7 | void start();
8 | void update();
9 | void end();
10 | }
11 | }
--------------------------------------------------------------------------------
/mu3controller/src/components/led_board.hpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 | #include "comio.hpp"
3 |
4 | #ifdef LED_BOARD
5 | namespace component
6 | {
7 | namespace led_board
8 | {
9 | void start();
10 | void init_color();
11 | void set_color(uint8_t lr, uint8_t lg, uint8_t lb, uint8_t rr, uint8_t rg, uint8_t rb);
12 | void update();
13 | void end();
14 | }
15 | }
16 | #endif
--------------------------------------------------------------------------------
/mu3controller/src/components/manager.cpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 | #include
3 | #include "led_board.hpp"
4 |
5 | namespace component
6 | {
7 | namespace manager
8 | {
9 |
10 | extern const uint8_t PIN_MAP[12] = {
11 | // L: A B C SIDE MENU
12 | 9,
13 | 8,
14 | 7,
15 | 16,
16 | 15,
17 | // R: A B C SIDE MENU
18 | 6,
19 | 5,
20 | 4,
21 | 14,
22 | 10,
23 | // FN1 FN2
24 | 3,
25 | 2,
26 | };
27 | bool key_status[12] = {0};
28 |
29 | bool running = false;
30 | bool keyboard_mode = false;
31 | bool switch_enabled = false;
32 | void start()
33 | {
34 | keyboard_mode = EEPROM.read(EEPROM_ADDR_KEYBOARD_MODE);
35 | // setup pin modes for button
36 | for (unsigned char i : manager::PIN_MAP)
37 | {
38 | pinMode(i, INPUT_PULLUP);
39 | }
40 |
41 | if (keyboard_mode)
42 | {
43 | keyboard::start();
44 | }
45 | else
46 | {
47 | raw_hid::start();
48 | ongeki_hardware::start();
49 | nfc_setup();
50 | #ifdef LED_BOARD
51 | led_board::start();
52 | #endif
53 | }
54 | running = true;
55 | }
56 |
57 | void update()
58 | {
59 | if (!running)
60 | return;
61 |
62 | // 按钮状态
63 | for (auto i = 0; i < 12; i++)
64 | {
65 | key_status[i] = digitalRead(PIN_MAP[i]) == LOW;
66 | }
67 |
68 | #ifdef HIGH_SIDE
69 | // 侧键
70 | key_status[3] = key_status[3] ^ 1;
71 | key_status[8] = key_status[8] ^ 1;
72 | #endif
73 |
74 | if (key_status[4] && key_status[9])
75 | {
76 | key_status[10] = true;
77 | }
78 |
79 | // 重置设置
80 | if (key_status[10] && key_status[11])
81 | {
82 | reset();
83 | return;
84 | }
85 |
86 | // 切换键盘与ongeki-io模式
87 | if (key_status[10] && key_status[7])
88 | {
89 | if (switch_enabled)
90 | {
91 | switch_mode();
92 | switch_enabled = false;
93 | }
94 | return;
95 | }
96 | else if (!switch_enabled)
97 | {
98 | switch_enabled = true;
99 | }
100 |
101 | if (keyboard_mode)
102 | {
103 | keyboard::update();
104 | }
105 | else
106 | {
107 | raw_hid::update();
108 | nfc_poll();
109 | #ifdef LED_BOARD
110 | led_board::update();
111 | #endif
112 | }
113 | }
114 |
115 | void end()
116 | {
117 | running = false;
118 | if (keyboard_mode)
119 | {
120 | keyboard::end();
121 | }
122 | else
123 | {
124 | raw_hid::end();
125 | nfc_end();
126 | ongeki_hardware::end();
127 | #ifdef LED_BOARD
128 | led_board::end();
129 | #endif
130 | }
131 | }
132 |
133 | void switch_mode()
134 | {
135 | if (!switch_enabled)
136 | return;
137 | end();
138 | EEPROM.put(EEPROM_ADDR_KEYBOARD_MODE, !keyboard_mode);
139 | start();
140 | }
141 |
142 | void reset()
143 | {
144 | end();
145 | EEPROM.put(EEPROM_ADDR_KEYBOARD_MODE, 0);
146 | EEPROM.put(EEPROM_ADDR_LEVER_LIMIT_1, 0);
147 | EEPROM.put(EEPROM_ADDR_LEVER_LIMIT_2, 1023);
148 | start();
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/mu3controller/src/components/manager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace component {
4 | namespace manager {
5 | extern const uint8_t PIN_MAP[12];
6 | extern bool key_status[];
7 | void start();
8 | void update();
9 | void end();
10 | void switch_mode();
11 | void reset();
12 | }
13 | }
14 |
15 | #include "raw_hid.hpp"
16 | #include "ongeki_hardware.hpp"
17 | #include "keyboard.hpp"
--------------------------------------------------------------------------------
/mu3controller/src/components/ongeki_hardware.cpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 | #include
3 | #include
4 | #include "components/card_reader.hpp"
5 | #include "components/led_board.hpp"
6 | #include
7 |
8 | namespace component
9 | {
10 | namespace ongeki_hardware
11 | {
12 | using namespace std;
13 | const int LEVER = PIN_A0;
14 | const int LED_PIN = PIN_A1;
15 |
16 | ResponsiveAnalogRead analog(LEVER, true, 0.1F);
17 |
18 | uint16_t lever_limit1 = 0;
19 | uint16_t lever_limit2 = 1023;
20 | uint16_t lever_limit_left;
21 | uint16_t lever_limit_right;
22 |
23 | CRGB lightColors[6];
24 |
25 | void start()
26 | {
27 | // setup led_t
28 | FastLED.addLeds(lightColors, 6);
29 | EEPROM.get(EEPROM_ADDR_LEVER_LIMIT_1, lever_limit1);
30 | EEPROM.get(EEPROM_ADDR_LEVER_LIMIT_2, lever_limit2);
31 | }
32 |
33 | void read_io(raw_hid::output_data_t *data)
34 | {
35 | for (int i = 0; i < 10; i++)
36 | {
37 | analog.update();
38 | }
39 | uint16_t lever = analog.getValue();
40 |
41 | // 设定摇杆范围
42 | if (manager::key_status[10] && manager::key_status[5])
43 | {
44 | lever_limit1 = lever;
45 | EEPROM.put(EEPROM_ADDR_LEVER_LIMIT_1, lever_limit1);
46 | }
47 | else if (manager::key_status[10] && manager::key_status[6])
48 | {
49 | lever_limit2 = lever;
50 | EEPROM.put(EEPROM_ADDR_LEVER_LIMIT_2, lever_limit2);
51 | }
52 |
53 | // lever_limit1大于lever_limit2 时,摇杆方向取反
54 | if (lever_limit1 < lever_limit2)
55 | {
56 | lever_limit_left = lever_limit1;
57 | lever_limit_right = lever_limit2;
58 | }
59 | else
60 | {
61 | lever = 1023 - lever;
62 | lever_limit_left = 1023 - lever_limit1;
63 | lever_limit_right = 1023 - lever_limit2;
64 | }
65 |
66 | // 禁止数值超出限制
67 | if (lever < lever_limit_left)
68 | {
69 | lever = lever_limit_left;
70 | }
71 | else if (lever > lever_limit_right)
72 | {
73 | lever = lever_limit_right;
74 | }
75 |
76 | // 摇杆数值映射到int16的范围
77 | data->lever = map(lever, lever_limit_left, lever_limit_right, -32768, 32767);
78 |
79 | // 设定opt按钮的状态
80 | uint8_t test_pressed = manager::key_status[10] && manager::key_status[0];
81 | uint8_t service_pressed = manager::key_status[10] && manager::key_status[1];
82 | uint8_t coin_pressed = manager::key_status[11];
83 | data->opt_buttons = (test_pressed << 0) | (service_pressed << 1) | (coin_pressed << 2);
84 |
85 | // 读取按钮状态
86 | for (auto i = 0; i < 10; i++)
87 | {
88 | data->buttons[i] = manager::key_status[i] && !manager::key_status[10];
89 | }
90 | }
91 |
92 | void set_led(raw_hid::led_t &data)
93 | {
94 | FastLED.setBrightness(data.ledBrightness);
95 |
96 | for (int i = 0; i < 3; i++)
97 | {
98 | memcpy(&lightColors[i], &data.ledColors[i], 3);
99 | memcpy(&lightColors[i + 3], &data.ledColors[i + 5], 3);
100 | }
101 |
102 | FastLED.show();
103 | }
104 |
105 | void end()
106 | {
107 | FastLED.clear();
108 | FastLED.show();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/mu3controller/src/components/ongeki_hardware.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace component {
4 | namespace ongeki_hardware {
5 | void start();
6 | void read_io(raw_hid::output_data_t *data);
7 | void set_led(raw_hid::led_t &data);
8 | void end();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/mu3controller/src/components/raw_hid.cpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 | #include "card_reader.hpp"
3 | #include
4 |
5 | namespace component {
6 | namespace raw_hid {
7 | uint8_t rawBuffer[255];
8 | uint8_t outBuffer[64];
9 | uint8_t inBuffer[64];
10 |
11 | output_data_t *pOutputData = reinterpret_cast(outBuffer);
12 | input_data_t *pInputData = reinterpret_cast(inBuffer);
13 |
14 | void start() {
15 | RawHID.begin(rawBuffer, sizeof(rawBuffer));
16 | }
17 |
18 | void update() {
19 | ongeki_hardware::read_io(pOutputData);
20 |
21 | pOutputData->card_type = card_type;
22 | pOutputData->card = card;
23 |
24 | RawHID.write(outBuffer, 64);
25 |
26 | if (RawHID.available()) {
27 | RawHID.readBytes(inBuffer, 64);
28 |
29 | switch (pInputData->type) {
30 | case 0: {
31 | ongeki_hardware::set_led(pInputData->led);
32 | break;
33 | }
34 | case 1: {
35 | EEPROM.put(0, pInputData->option.aimiId);
36 | break;
37 | }
38 | }
39 | }
40 | }
41 |
42 | void end() {
43 | RawHID.end();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/mu3controller/src/components/raw_hid.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "card_reader.hpp"
3 |
4 | namespace component {
5 | namespace raw_hid {
6 |
7 | #pragma pack(push, 1)
8 | struct aimi_id_t {
9 | uint8_t buffer[10];
10 | };
11 |
12 | struct output_data_t {
13 | union {
14 | char buffer[64];
15 | struct {
16 | uint8_t buttons[10];
17 | int16_t lever;
18 | uint8_t opt_buttons;
19 | uint8_t card_type;
20 | Card card;
21 | };
22 | };
23 | };
24 |
25 | typedef uint8_t color_t[3];
26 |
27 | struct led_t {
28 | uint8_t ledBrightness;
29 | color_t ledColors[10];
30 | };
31 |
32 | struct option_t {
33 | aimi_id_t aimiId;
34 | };
35 |
36 | struct input_data_t {
37 | uint8_t type;
38 | union {
39 | char buffer[61];
40 | led_t led;
41 | option_t option;
42 | };
43 | };
44 | #pragma pack(pop)
45 |
46 | void start();
47 | void update();
48 | void end();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/mu3controller/src/components/serial.cpp:
--------------------------------------------------------------------------------
1 | #define configUSE_CORE_AFFINITY 1
2 |
3 | #include "stdinclude.hpp"
4 |
5 | namespace component {
6 | namespace serial {
7 | void init() {
8 | Serial.begin(115200);
9 | }
10 |
11 | void write(uint8_t byte) {
12 | if(byte == 0xE0 || byte == 0xD0) {
13 | Serial.write((uint8_t)0xD0);
14 | Serial.write((uint8_t)(byte - 1));
15 | } else {
16 | Serial.write((uint8_t)byte);
17 | }
18 | }
19 |
20 | void write_head() {
21 | Serial.write((uint8_t)0xE0);
22 | }
23 |
24 | bool read(uint8_t &out) {
25 | auto byte = (uint8_t) Serial.read();
26 |
27 | if(byte == 0xD0) {
28 | out = (uint8_t)(Serial.read() + 1);
29 | return true;
30 | }
31 |
32 | out = byte;
33 | return false;
34 | }
35 |
36 | bool available() {
37 | auto avail = Serial.available();
38 | if(avail == 1) {
39 | uint8_t peek = Serial.peek();
40 |
41 | if(peek == 0xD0)
42 | return false;
43 |
44 | return true;
45 | } else if(avail > 0) {
46 | return true;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | void flush() {
53 | Serial.flush();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/mu3controller/src/components/serial.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdinclude.hpp"
3 | namespace component
4 | {
5 | namespace serial
6 | {
7 |
8 | bool read(uint8_t &out);
9 | void write(uint8_t byte);
10 | void write_head();
11 | bool available();
12 |
13 | void flush();
14 |
15 | void init();
16 | }
17 | }
--------------------------------------------------------------------------------
/mu3controller/src/eeprom_address.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | const int EEPROM_ADDR_KEYBOARD_MODE = 0;
4 | const int EEPROM_ADDR_LEVER_LIMIT_1 = 1;
5 | const int EEPROM_ADDR_LEVER_LIMIT_2 = 3;
--------------------------------------------------------------------------------
/mu3controller/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 |
3 | void setup()
4 | {
5 | component::manager::start();
6 | }
7 |
8 | void loop()
9 | {
10 | component::manager::update();
11 | }
12 |
--------------------------------------------------------------------------------
/mu3controller/src/stdinclude.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | #include "components/manager.hpp"
8 | #include "eeprom_address.h"
9 |
10 | #define HIGH_SIDE
11 | #define LED_BOARD
--------------------------------------------------------------------------------
/mu3controller/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PlatformIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PlatformIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------