feat: release card reader SDK v0.1.0

This commit is contained in:
su 2026-09-08 17:55:28 +08:00
commit 7d2b65ff38
37 changed files with 6835 additions and 0 deletions

19
CHANGELOG.md Normal file
View File

@ -0,0 +1,19 @@
# Changelog
## [0.1.0]
### 中文
- 初始发布 AISU 830T Card Reader Unity Package。
- 支持读卡器打开、关闭和串口参数配置。
- 支持连接异常后的自动重连。
- 支持接收卡片信息和十进制 `CardNumber`。
- 提供 Unity 事件 API、Basic Sample 和 Console Demo。
### English
- Initial release of the AISU 830T Card Reader Unity package.
- Reader open/close and serial configuration.
- Automatic reconnect after connection failures.
- Card reading with decimal `CardNumber` values.
- Unity event API, Basic Sample, and Console Demo.

7
CHANGELOG.md.meta Normal file
View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5dcfefc0d619a834e87b1e62740cfa3d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Documentation~.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6837a6f6e2f24393a5f8b5ae32d59098
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

136
Documentation~/API.en.md Normal file
View File

@ -0,0 +1,136 @@
# API Reference
This document covers the Unity-facing public API of AISU 830T Card Reader SDK v0.1.0. The namespace is `Aisu.CardReader`.
## CardReaderManager
`CardReaderManager` is the scene-level reader component. Add it to a GameObject and keep one instance in the scene.
### Main properties
```csharp
public static CardReaderManager Instance { get; }
public SerialDeviceOptions SerialOptions { get; set; }
public bool IsConnected { get; }
```
- `Instance`: the current scene Manager.
- `SerialOptions`: serial configuration used by the Inspector and by code.
- `IsConnected`: whether the reader is currently connected.
### Main methods
```csharp
public void OpenReader();
public void CloseReader();
```
`OpenReader()` starts the reader connection. `CloseReader()` closes the current connection and stops automatic reconnect; `OpenReader()` can be called again later.
### Events
```csharp
public UnityEvent OnConnected { get; }
public UnityEvent OnDisconnected { get; }
public UnityEvent<SerialDeviceState> OnStateChanged { get; }
public UnityEvent<CardInfo> OnCardReceived { get; }
public UnityEvent<CardReaderErrorEventArgs> OnError { get; }
```
Use `AddListener` and `RemoveListener` for event subscription. UnityEvents raised through the Manager are dispatched on the Unity main thread.
## CardReaderApi
`CardReaderApi` is the static access point for the current `CardReaderManager` and is convenient for application scripts.
```csharp
public static bool IsConnected { get; }
public static void Open();
public static void Close();
public static UnityEvent OnConnected { get; }
public static UnityEvent OnDisconnected { get; }
public static UnityEvent<SerialDeviceState> OnStateChanged { get; }
public static UnityEvent<CardInfo> OnCardReceived { get; }
public static UnityEvent<CardReaderErrorEventArgs> OnError { get; }
```
`Open()` starts the connection and `Close()` closes it. Calling either method or accessing an event without an active `CardReaderManager` throws `InvalidOperationException`.
## SerialDeviceOptions
`SerialDeviceOptions` is the configuration type of `CardReaderManager.SerialOptions`. The currently exposed fields are:
| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `PortName` | `string` | none | Windows COM-port name. |
| `BaudRate` | `int` | `9600` | Baud rate. |
| `Parity` | `Parity` | `None` | Parity mode. |
| `DataBits` | `int` | `8` | Number of data bits. |
| `StopBits` | `StopBits` | `One` | Stop-bit setting. |
| `Handshake` | `Handshake` | `None` | Handshake mode. |
| `ReadTimeout` | `int` | `100` | Read timeout in milliseconds. |
| `WriteTimeout` | `int` | `1000` | Write timeout in milliseconds. |
| `RtsEnable` | `bool` | `true` | Whether RTS is enabled. |
| `DtrEnable` | `bool` | `true` | Whether DTR is enabled. |
| `AutoReconnect` | `bool` | `true` | Whether to keep retrying after a connection failure. |
| `ReconnectInterval` | `int` | `1000` | Automatic reconnect interval in milliseconds. |
| `MaxPendingSendCount` | `int` | `256` | Pending-data capacity. |
The actual COM port and UART settings depend on the connected reader.
## CardInfo
`CardInfo` is the card data supplied by `OnCardReceived`:
```csharp
public CardType CardType { get; }
public byte CardTypeCode { get; }
public string CardNumber { get; }
```
- `CardType`: the currently mapped type is `CardType.EM4100`.
- `CardTypeCode`: the raw type code reported by the device. Unknown values are preserved.
- `CardNumber`: a decimal card-number string.
### CardNumber rules
`CardNumber` is a `string` containing the decimal card number. Its default minimum width is 10 digits: values shorter than 10 digits are left-padded with `0`, and values longer than 10 digits are not truncated.
## CardType
```csharp
public enum CardType
{
Unknown = 0,
EM4100 = 0x02
}
```
## Error events
`OnError` provides `CardReaderErrorEventArgs`:
```csharp
public CardReaderException Exception { get; }
```
`Exception` is the actual exception object. Common causes include a missing COM port, a port already in use, and a failed connection. Identical connection errors are not repeatedly emitted, while automatic reconnect continues when `AutoReconnect` is enabled.
## Event usage
Register listeners with `AddListener` in `OnEnable` and remove them with `RemoveListener` in `OnDisable`:
```csharp
private void OnEnable()
{
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
}
private void OnDisable()
{
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
}
```
`CardReaderManager` releases serial resources when it is destroyed or when the application exits.

136
Documentation~/API.zh-CN.md Normal file
View File

@ -0,0 +1,136 @@
# API 参考
本文仅记录 AISU 830T Card Reader SDK v0.1.0 中面向 Unity 使用者的公开 API。命名空间为 `Aisu.CardReader`。
## CardReaderManager
`CardReaderManager` 是场景级读卡器管理组件。将它添加到场景中的 GameObject,并保持一个实例。
### 主要属性
```csharp
public static CardReaderManager Instance { get; }
public SerialDeviceOptions SerialOptions { get; set; }
public bool IsConnected { get; }
```
- `Instance`:当前场景中的 Manager。
- `SerialOptions`:Inspector 和代码使用的串口配置。
- `IsConnected`:当前是否已连接。
### 主要方法
```csharp
public void OpenReader();
public void CloseReader();
```
`OpenReader()` 启动读卡器连接。`CloseReader()` 关闭当前连接并停止自动重连;之后可以再次调用 `OpenReader()`。
### 事件
```csharp
public UnityEvent OnConnected { get; }
public UnityEvent OnDisconnected { get; }
public UnityEvent<SerialDeviceState> OnStateChanged { get; }
public UnityEvent<CardInfo> OnCardReceived { get; }
public UnityEvent<CardReaderErrorEventArgs> OnError { get; }
```
事件使用 `AddListener` 和 `RemoveListener`。通过 Manager 接收的 UnityEvent 在 Unity 主线程派发。
## CardReaderApi
`CardReaderApi` 是当前 `CardReaderManager` 的静态访问入口,适合在业务脚本中使用。
```csharp
public static bool IsConnected { get; }
public static void Open();
public static void Close();
public static UnityEvent OnConnected { get; }
public static UnityEvent OnDisconnected { get; }
public static UnityEvent<SerialDeviceState> OnStateChanged { get; }
public static UnityEvent<CardInfo> OnCardReceived { get; }
public static UnityEvent<CardReaderErrorEventArgs> OnError { get; }
```
`Open()` 与 `Close()` 的行为分别是启动连接和关闭连接。没有活动的 `CardReaderManager` 时,调用方法或访问事件会抛出 `InvalidOperationException`。
## SerialDeviceOptions
`SerialDeviceOptions` 是 `CardReaderManager.SerialOptions` 的配置类型。当前公开字段如下:
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `PortName` | `string` | 无 | Windows COM 端口名称。 |
| `BaudRate` | `int` | `9600` | 波特率。 |
| `Parity` | `Parity` | `None` | 校验方式。 |
| `DataBits` | `int` | `8` | 数据位。 |
| `StopBits` | `StopBits` | `One` | 停止位。 |
| `Handshake` | `Handshake` | `None` | 握手方式。 |
| `ReadTimeout` | `int` | `100` | 读超时,单位毫秒。 |
| `WriteTimeout` | `int` | `1000` | 写超时,单位毫秒。 |
| `RtsEnable` | `bool` | `true` | 是否启用 RTS。 |
| `DtrEnable` | `bool` | `true` | 是否启用 DTR。 |
| `AutoReconnect` | `bool` | `true` | 连接异常后是否继续自动重连。 |
| `ReconnectInterval` | `int` | `1000` | 自动重连间隔,单位毫秒。 |
| `MaxPendingSendCount` | `int` | `256` | 待发送数据容量。 |
实际设备的 COM 口和 UART 参数可能不同,请以设备配置为准。
## CardInfo
`CardInfo` 是 `OnCardReceived` 提供的卡片信息:
```csharp
public CardType CardType { get; }
public byte CardTypeCode { get; }
public string CardNumber { get; }
```
- `CardType`:当前已知类型为 `CardType.EM4100`。
- `CardTypeCode`:设备上报的原始类型码。未知类型不会丢失。
- `CardNumber`:十进制卡号字符串。
### CardNumber 规则
`CardNumber` 的类型为 `string`,表示十进制卡号字符串。默认最小长度为 10 位:不足 10 位时左侧补 `0`,超过 10 位时不截断。
## CardType
```csharp
public enum CardType
{
Unknown = 0,
EM4100 = 0x02
}
```
## 错误事件
`OnError` 提供 `CardReaderErrorEventArgs`:
```csharp
public CardReaderException Exception { get; }
```
`Exception` 是真实异常对象。常见原因包括 COM 端口不存在、端口被其他程序占用和连接失败。相同的连接错误不会持续重复派发,但在 `AutoReconnect` 开启时 SDK 仍会继续尝试连接。
## 事件使用约定
推荐在 `OnEnable` 中使用 `AddListener` 注册,在 `OnDisable` 中使用 `RemoveListener` 解除。生命周期示例:
```csharp
private void OnEnable()
{
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
}
private void OnDisable()
{
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
}
```
`CardReaderManager` 销毁或应用退出时会自动释放串口资源。

View File

@ -0,0 +1,88 @@
# Getting Started
This guide describes the actual usage flow for AISU 830T Card Reader SDK v0.1.0.
## 1. Install the package
In Unity Package Manager, choose **Add package from git URL...** and enter:
```text
https://git.aisu.xin/aisu-sdk/card-reader-830t-package.git
```
The Package ID is `xin.aisu.card-reader-830t`. The minimum Unity version is 2021.3, and the current supported platform is Windows.
## 2. Import the Basic Sample
Open the package details, find the **Samples** section, and click **Import** for **Basic**. Open the imported `Scenes/CardReaderSample.unity` scene.
## 3. Add CardReaderManager
Create a GameObject in the scene and add the `CardReaderManager` component. Keep one Manager instance in the scene.
## 4. Configure the serial port
Configure `SerialOptions` in the Manager Inspector:
- `PortName`: the actual Windows COM port, for example `COM3`.
- `BaudRate`, `Parity`, `DataBits`, and `StopBits`: use the reader's settings.
- Keep the other defaults, or configure `ReadTimeout`, `WriteTimeout`, `AutoReconnect`, `ReconnectInterval`, and `MaxPendingSendCount` as needed.
## 5. Open and listen for events
Register listeners with `AddListener`, then call `CardReaderApi.Open()`:
```csharp
using Aisu.CardReader;
using UnityEngine;
public sealed class CardReaderUsage : MonoBehaviour
{
private void OnEnable()
{
CardReaderApi.OnConnected.AddListener(OnConnected);
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
CardReaderApi.OnError.AddListener(OnError);
}
private void Start()
{
CardReaderApi.Open();
}
private static void OnConnected()
{
Debug.Log("Reader connected.");
}
private static void OnCardReceived(CardInfo card)
{
Debug.Log($"{card.CardType}: {card.CardNumber}");
}
private static void OnError(CardReaderErrorEventArgs error)
{
Debug.LogError(error.Exception.Message);
}
private void OnDisable()
{
CardReaderApi.OnConnected.RemoveListener(OnConnected);
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
CardReaderApi.OnError.RemoveListener(OnError);
CardReaderApi.Close();
}
}
```
Once connected, present a card to the reader and handle `OnCardReceived`. `CardInfo.CardNumber` is a decimal string with a default minimum width of 10 digits; shorter values are left-padded with `0`, and longer values are not truncated.
## 6. Close
Call `CardReaderApi.Close()` to close the current connection and stop automatic reconnect. You can call `Open()` again later.
You can also call `OpenReader()` and `CloseReader()` on the current Manager.
## Lifetime
`CardReaderManager` releases serial resources when it is destroyed or when the application exits. Register events in `OnEnable` and remove them with `RemoveListener` in `OnDisable`. Without an active Manager, `CardReaderApi.Open()`, `Close()`, and event access throw `InvalidOperationException`.

View File

@ -0,0 +1,88 @@
# 快速开始
本文介绍 AISU 830T Card Reader SDK v0.1.0 的实际使用流程。
## 1. 安装 Package
在 Unity Package Manager 选择 **Add package from git URL...**,输入:
```text
https://git.aisu.xin/aisu-sdk/card-reader-830t-package.git
```
Package ID 为 `xin.aisu.card-reader-830t`,最低 Unity 版本为 2021.3,当前支持 Windows。
## 2. 导入 Basic Sample
打开包详情中的 **Samples** 区域,点击 **Import** 导入 **Basic**。使用导入后的 `Scenes/CardReaderSample.unity`。
## 3. 添加 CardReaderManager
在场景中创建一个 GameObject,添加 `CardReaderManager` 组件。场景中保持一个 Manager 实例。
## 4. 配置串口
在 Manager Inspector 中设置 `SerialOptions`:
- `PortName`:实际 Windows COM 端口,例如 `COM3`。
- `BaudRate`、`Parity`、`DataBits`、`StopBits`:按读卡器参数设置。
- 其他字段保留默认值,或按项目需要配置 `ReadTimeout`、`WriteTimeout`、`AutoReconnect`、`ReconnectInterval` 和 `MaxPendingSendCount`。
## 5. Open 与事件监听
使用 `AddListener` 注册事件,并调用 `CardReaderApi.Open()`:
```csharp
using Aisu.CardReader;
using UnityEngine;
public sealed class CardReaderUsage : MonoBehaviour
{
private void OnEnable()
{
CardReaderApi.OnConnected.AddListener(OnConnected);
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
CardReaderApi.OnError.AddListener(OnError);
}
private void Start()
{
CardReaderApi.Open();
}
private static void OnConnected()
{
Debug.Log("Reader connected.");
}
private static void OnCardReceived(CardInfo card)
{
Debug.Log($"{card.CardType}: {card.CardNumber}");
}
private static void OnError(CardReaderErrorEventArgs error)
{
Debug.LogError(error.Exception.Message);
}
private void OnDisable()
{
CardReaderApi.OnConnected.RemoveListener(OnConnected);
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
CardReaderApi.OnError.RemoveListener(OnError);
CardReaderApi.Close();
}
}
```
设备连接后,将卡片靠近读卡器即可收到 `OnCardReceived`。事件中的 `CardInfo.CardNumber` 是十进制字符串:默认最小 10 位,不足时左侧补 `0`,超过 10 位不截断。
## 6. Close
调用 `CardReaderApi.Close()` 关闭当前连接并停止自动重连。之后可以再次调用 `Open()`。
也可以直接调用当前 Manager 的 `OpenReader()` 和 `CloseReader()`。
## 生命周期
`CardReaderManager` 被销毁或应用退出时会自动释放串口资源。事件建议在 `OnEnable` 注册、在 `OnDisable` 使用 `RemoveListener` 解除。没有活动 Manager 时调用 `CardReaderApi.Open()`、`Close()` 或访问事件会抛出 `InvalidOperationException`。

17
Documentation~/index.md Normal file
View File

@ -0,0 +1,17 @@
# AISU 830T Card Reader SDK Documentation
## 中文
- [快速开始](GettingStarted.zh-CN.md)
- [API 参考](API.zh-CN.md)
- [Basic Sample](../Samples~/Basic/README.md)
## English
- [Getting Started](GettingStarted.en.md)
- [API Reference](API.en.md)
- [Basic Sample](../Samples~/Basic/README.en.md)
SDK version: `0.1.0`
Package ID: `xin.aisu.card-reader-830t`

157
README.en.md Normal file
View File

@ -0,0 +1,157 @@
# AISU 830T Card Reader SDK
AISU 830T Card Reader SDK is a Unity UPM package for connecting an 830T card reader and receiving card data reported by the device.
## Supported environment
- Unity 2021.3 or later
- AISU 830T Card Reader
- Package ID: `xin.aisu.card-reader-830t`
Android, Wiegand, active card search/read/write commands, and ACK/NAK APIs are not supported in this release.
## Installation
In Unity Package Manager, choose **Add package from git URL...** and enter:
```text
https://git.aisu.xin/aisu-sdk/card-reader-830t-package.git
```
You can also add the package from a local folder. After installation, import **Basic** or **Console Demo** from the package's **Samples** section.
## Quick start
Place one `CardReaderManager` in the scene, configure `SerialOptions` in the Inspector, and use `CardReaderApi`:
```csharp
using Aisu.CardReader;
using UnityEngine;
public sealed class CardReaderExample : MonoBehaviour
{
private void OnEnable()
{
CardReaderApi.OnConnected.AddListener(OnConnected);
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
CardReaderApi.OnError.AddListener(OnError);
}
private void Start()
{
CardReaderApi.Open();
}
private static void OnConnected()
{
Debug.Log("Card reader connected.");
}
private static void OnCardReceived(CardInfo card)
{
Debug.Log($"{card.CardType} ({card.CardTypeCode:X2}): {card.CardNumber}");
}
private static void OnError(CardReaderErrorEventArgs error)
{
Debug.LogError(error.Exception.Message);
}
private void OnDisable()
{
CardReaderApi.OnConnected.RemoveListener(OnConnected);
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
CardReaderApi.OnError.RemoveListener(OnError);
CardReaderApi.Close();
}
}
```
## CardReaderManager
`CardReaderManager` is the scene-level entry point. Keep one Manager instance in the scene. It exposes `SerialOptions`, `IsConnected`, `OpenReader()`, `CloseReader()`, and connection, disconnection, state, card, and error events.
## Inspector serial settings
`SerialOptions` uses `SerialDeviceOptions`. The currently exposed fields are:
- `PortName`: Windows COM port, for example `COM3`.
- `BaudRate`: baud rate, default `9600`.
- `Parity`: parity mode, default `None`.
- `DataBits`: data bits, default `8`.
- `StopBits`: stop bits, default `One`.
- `Handshake`: handshake mode, default `None`.
- `ReadTimeout`: read timeout in milliseconds, default `100`.
- `WriteTimeout`: write timeout in milliseconds, default `1000`.
- `RtsEnable` / `DtrEnable`: RTS/DTR flags, enabled by default.
- `AutoReconnect`: whether to retry after a connection failure, enabled by default.
- `ReconnectInterval`: retry interval in milliseconds, default `1000`.
- `MaxPendingSendCount`: send queue capacity, default `256`.
Configure the UART fields for the actual device. The Samples do not contain a fixed local COM port.
## CardReaderApi and events
`CardReaderApi` is the static access point for the current Manager. It provides:
- `Open()`: starts the reader connection.
- `Close()`: closes the current connection and stops automatic reconnect; `Open()` can be called again later.
- `IsConnected`: current connection state.
- `OnConnected`, `OnDisconnected`, `OnStateChanged`, `OnCardReceived`, and `OnError`.
Use `AddListener` to subscribe and `RemoveListener` to unsubscribe. Pair them in `OnEnable` and `OnDisable`. Accessing events or calling `Open`/`Close` without an active `CardReaderManager` throws `InvalidOperationException`.
## CardInfo and CardNumber
`CardInfo` contains:
- `CardType`: the currently mapped type is `CardType.EM4100`.
- `CardTypeCode`: the raw type code reported by the device.
- `CardNumber`: a decimal card-number string of type `string`.
`CardNumber` has a default minimum width of 10 digits. Values shorter than 10 digits are left-padded with `0`; longer values are not truncated.
## Automatic reconnect and errors
When `AutoReconnect` is enabled, the SDK continues retrying after a connection failure according to `ReconnectInterval`. `OnError` provides the actual `Exception`; common causes include a missing COM port, a port already in use, or a failed connection. Identical connection errors are not repeatedly emitted, while automatic reconnect continues.
## Samples
- **Basic**: full UI controls, COM-port selection, connection state, card information, and error log display.
- **Console Demo**: minimal API calls and console logging.
## Frequently asked questions
### No COM port is listed
Confirm that the reader is connected and its driver is installed. Check the actual COM name in Windows Device Manager. The Basic Sample's **Refresh** button rescans available ports.
### The COM port is already in use
Close other serial tools or applications using the port, then select it again and call `Open()`.
### The reader cannot connect
Check `PortName`, baud rate, parity, data bits, and stop bits against the device settings. Also confirm that no other program owns the port.
### How does automatic reconnect work?
With `AutoReconnect` enabled, the SDK retries at `ReconnectInterval`. Calling `Close()` stops the current connection and automatic reconnect.
### Are serial resources released when Unity exits?
`CardReaderManager` releases the serial resources when it is destroyed or when the application exits.
### How do I import the Basic Sample?
After installing the package, open its details in Package Manager, find **Samples**, and click **Import** for **Basic**. A version directory in the imported path is standard Unity behavior.
## Version
This documentation describes SDK `v0.1.0`.
More information:
- [Getting Started](Documentation~/GettingStarted.en.md)
- [API reference](Documentation~/API.en.md)
- [Basic Sample guide](Samples~/Basic/README.en.md)

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# AISU 830T Card Reader SDK
Unity package for integrating AISU 830T card readers.
Language:
- [中文](README.zh-CN.md)
- [English](README.en.md)

7
README.md.meta Normal file
View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: df6324a2d5fda2947a4601402d564451
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

157
README.zh-CN.md Normal file
View File

@ -0,0 +1,157 @@
# AISU 830T Card Reader SDK
AISU 830T Card Reader SDK 是一个面向 Unity 的 UPM Package,用于在 Windows 上连接 830T 读卡器,接收设备主动上报的卡片信息。
## 支持环境
- Unity 2021.3 或更高版本
- AISU 830T Card Reader
- Package ID:`xin.aisu.card-reader-830t`
当前不支持 Wiegand、主动寻卡/读卡/写卡命令或 ACK/NAK API。
## 安装
在 Unity Package Manager 中选择 **Add package from git URL...**,输入:
```text
https://git.aisu.xin/aisu-sdk/card-reader-830t-package.git
```
也可以将本地 Package 目录添加到 Unity 项目。安装后,在包详情的 **Samples** 区域导入 **Basic** 或 **Console Demo**。
## 快速开始
在场景中放置一个 `CardReaderManager`,在 Inspector 中配置 `SerialOptions`,然后使用 `CardReaderApi`:
```csharp
using Aisu.CardReader;
using UnityEngine;
public sealed class CardReaderExample : MonoBehaviour
{
private void OnEnable()
{
CardReaderApi.OnConnected.AddListener(OnConnected);
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
CardReaderApi.OnError.AddListener(OnError);
}
private void Start()
{
CardReaderApi.Open();
}
private static void OnConnected()
{
Debug.Log("Card reader connected.");
}
private static void OnCardReceived(CardInfo card)
{
Debug.Log($"{card.CardType} ({card.CardTypeCode:X2}): {card.CardNumber}");
}
private static void OnError(CardReaderErrorEventArgs error)
{
Debug.LogError(error.Exception.Message);
}
private void OnDisable()
{
CardReaderApi.OnConnected.RemoveListener(OnConnected);
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
CardReaderApi.OnError.RemoveListener(OnError);
CardReaderApi.Close();
}
}
```
## CardReaderManager
`CardReaderManager` 是场景级入口。场景中应保持一个 Manager 实例。它提供 `SerialOptions`、`IsConnected`、`OpenReader()`、`CloseReader()` 以及连接、断开、状态、卡片和错误事件。
## Inspector 串口参数
`SerialOptions` 类型为 `SerialDeviceOptions`,当前公开字段如下:
- `PortName`:Windows COM 端口,例如 `COM3`。
- `BaudRate`:波特率,默认 `9600`。
- `Parity`:校验方式,默认 `None`。
- `DataBits`:数据位,默认 `8`。
- `StopBits`:停止位,默认 `One`。
- `Handshake`:握手方式,默认 `None`。
- `ReadTimeout`:读超时毫秒数,默认 `100`。
- `WriteTimeout`:写超时毫秒数,默认 `1000`。
- `RtsEnable` / `DtrEnable`:RTS/DTR,默认开启。
- `AutoReconnect`:连接异常后是否自动重连,默认开启。
- `ReconnectInterval`:重连间隔毫秒数,默认 `1000`。
- `MaxPendingSendCount`:发送队列容量,默认 `256`。
请根据实际设备参数配置 UART 字段。Sample 不包含固定的本地 COM 端口。
## CardReaderApi 与事件
`CardReaderApi` 是当前 Manager 的静态访问入口,提供:
- `Open()`:启动 Reader 连接。
- `Close()`:关闭当前连接并停止自动重连;之后可以再次 `Open()`。
- `IsConnected`:当前连接状态。
- `OnConnected`、`OnDisconnected`、`OnStateChanged`、`OnCardReceived`、`OnError`。
事件使用 `AddListener` 注册、`RemoveListener` 解除,建议在 `OnEnable` 和 `OnDisable` 中成对处理。没有活动的 `CardReaderManager` 时访问事件或调用 `Open`/`Close` 会抛出 `InvalidOperationException`。
## CardInfo 与 CardNumber
`CardInfo` 包含:
- `CardType`:当前已知类型为 `CardType.EM4100`。
- `CardTypeCode`:设备上报的原始类型码。
- `CardNumber`:类型为 `string` 的十进制卡号字符串。
`CardNumber` 默认最小长度为 10 位;不足 10 位时在左侧补 `0`,超过 10 位时不截断。
## 自动重连与错误处理
当 `AutoReconnect` 开启时,连接异常后 SDK 会按 `ReconnectInterval` 继续尝试连接。`OnError` 提供真实的 `Exception`,常见原因包括 COM 端口不存在、端口被占用或连接失败。相同的连接错误不会持续刷出重复事件,但 SDK 仍会继续自动重连。
## Samples
- **Basic**:完整 UI 操作、COM 端口选择、连接状态、卡片信息和错误日志显示。
- **Console Demo**:最小 API 调用和日志输出示例。
## 常见问题
### 找不到 COM 端口
确认设备已连接、驱动已安装,并在 Windows 设备管理器中查看实际 COM 名称。Basic Sample 的 **Refresh** 会重新扫描端口。
### COM 端口被占用
关闭其他串口工具或正在使用该端口的程序,然后重新选择端口并调用 `Open()`。
### 无法连接 Reader
检查 `PortName`、波特率、Parity、DataBits 和 StopBits 是否与设备设置一致,并确认设备没有被其他程序占用。
### 自动重连如何工作
开启 `AutoReconnect` 后,SDK 会按 `ReconnectInterval` 重试。调用 `Close()` 会停止当前连接和自动重连。
### Unity 退出后是否释放串口
`CardReaderManager` 在销毁或应用退出时会自动释放串口资源。
### 如何导入 Basic Sample
安装 Package 后,在 Package Manager 的包详情中找到 **Samples**,点击 **Import** 导入 **Basic**。导入路径带有版本目录是 Unity 的标准行为。
## 版本
当前文档对应 SDK `v0.1.0`。
更多内容:
- [快速开始](Documentation~/GettingStarted.zh-CN.md)
- [API 文档](Documentation~/API.zh-CN.md)
- [Basic Sample 文档](Samples~/Basic/README.md)

8
Runtime.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 04b022d97a25bee4f9c23b88297ff5a4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/Plugins.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 30b0694242524259a249d31bf2e082c5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,32 @@
fileFormatVersion: 2
guid: 23419227fdc74ce8aa78b6eb70b2b722
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
- first:
Standalone: Windows
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

8
Samples~.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a1b1ba0e7a4541c9a518d103a0b2c355
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
# AISU 830T Basic Sample
The Basic Sample provides a complete Unity UI for Windows reader integration: COM-port selection, connection state, card information, and error logs.
## Import
1. Install `xin.aisu.card-reader-830t` through Unity Package Manager.
2. Open the package details and import **Basic** from **Samples**.
3. Open the imported `Scenes/CardReaderSample.unity` scene.
## Select a COM port and connect
1. Run the project on Windows in the Unity Editor or a Windows Standalone build.
2. Click **Refresh** to scan the available COM ports.
3. Select the COM port connected to the AISU 830T reader.
4. Confirm the UART settings in the scene's `CardReaderManager.SerialOptions`.
5. Click **Open**.
## Present a card
After the reader connects, present a card. The UI displays `CardType`, `CardTypeCode`, and the decimal `CardNumber` when the reader reports card data.
## Disconnect
Click **Close** to close the connection and stop automatic reconnect. The Manager also releases serial resources when the scene or application is destroyed.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8f4e2c1a7b6d4e90a3c5f1d2e6b8a407
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

28
Samples~/Basic/README.md Normal file
View File

@ -0,0 +1,28 @@
# AISU 830T Basic Sample
该 Sample 用于 Windows + Unity Editor/Standalone 的实机联调,使用包内已提供的 `Scenes/CardReaderSample.unity` 和 `Scripts/CardReaderSampleUI.cs`。
## 导入
1. 在 Package Manager 安装 `xin.aisu.card-reader-830t`。
2. 在包详情的 **Samples** 区域导入 **Basic**。
3. 打开导入后的 `Scenes/CardReaderSample.unity`。
## 选择 COM 与连接
1. 运行 Windows Unity Editor 或 Windows Standalone。
2. 点击 **Refresh**,Sample 使用 `SerialPort.GetPortNames()` 扫描当前 COM 端口。
3. 选择 830T 对应的 COM 口,并按实际设备参数确认 UART 配置。
4. 点击 **Open**。端口不存在、被占用或参数不完整时,错误会显示在 Sample 日志中。
## 刷卡
连接成功后,将卡片靠近已连接的 830T 读卡器。设备主动上报完整帧时,界面显示 `CardType`、原始 `CardTypeCode` 和 `CardNumber`。Sample 不发送寻卡或读卡命令。
## 断开
点击 **Close** 停止接收并关闭串口。切换场景或销毁组件时,Manager 也会执行清理和资源释放。
## Console Demo
包内另有 **Console Demo** Sample,使用 `CardReaderApi` 的 `Open`、`Close`、`OnConnected`、`OnCardReceived`、`OnDisconnected` 和 `OnError`。导入后请在场景中的 `CardReaderManager.SerialOptions.PortName` 选择实际 COM 口。

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a71e3c5f8b2d4a609c1e7f3b5d8a2c40
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9191a9de2297dad41840d247eeadb6d7
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.IO.Ports;
using UnityEngine;
using UnityEngine.UI;
namespace Aisu.CardReader.Samples
{
/// <summary>用于 Windows 实机联调的最小 Unity UI 示例。</summary>
public sealed class CardReaderSampleUI : MonoBehaviour
{
[SerializeField] private Dropdown portDropdown;
[SerializeField] private Button refreshButton;
[SerializeField] private Button openButton;
[SerializeField] private Button closeButton;
[SerializeField] private Text stateText;
[SerializeField] private Text portText;
[SerializeField] private Text cardTypeText;
[SerializeField] private Text cardNumberText;
[SerializeField] private Text lastEventTimeText;
[SerializeField] private Text errorText;
[SerializeField] private Text logText;
private readonly List<string> portNames = new List<string>();
private readonly List<string> logLines = new List<string>();
private CardReaderManager manager;
private bool operationInProgress;
private bool destroying;
private bool apiSubscribed;
private void Awake()
{
manager = CardReaderManager.Instance;
SetText(stateText, "状态:未连接");
SetText(portText, "端口:-");
SetText(cardTypeText, "CardType:-");
SetText(cardNumberText, "CardNumber:-");
SetText(lastEventTimeText, "最后事件:-");
SetText(errorText, "错误:-");
SetText(logText, "日志:-");
}
private void OnEnable()
{
refreshButton?.onClick.AddListener(RefreshPorts);
openButton?.onClick.AddListener(OpenSelectedPort);
closeButton?.onClick.AddListener(CloseReader);
SubscribeApiEvents();
}
private void Start()
{
// Manager 与 Sample 的 Awake 顺序不应影响事件订阅和首次端口扫描。
SubscribeApiEvents();
RefreshPorts();
}
private void SubscribeApiEvents()
{
if (apiSubscribed) return;
if (manager == null) manager = CardReaderManager.Instance;
if (manager == null) return;
CardReaderApi.OnConnected.AddListener(OnConnected);
CardReaderApi.OnDisconnected.AddListener(OnDisconnected);
CardReaderApi.OnStateChanged.AddListener(OnStateChanged);
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
CardReaderApi.OnError.AddListener(OnReaderError);
apiSubscribed = true;
}
private void OnDisable()
{
refreshButton?.onClick.RemoveListener(RefreshPorts);
openButton?.onClick.RemoveListener(OpenSelectedPort);
closeButton?.onClick.RemoveListener(CloseReader);
if (!apiSubscribed || manager == null) return;
CardReaderApi.OnConnected.RemoveListener(OnConnected);
CardReaderApi.OnDisconnected.RemoveListener(OnDisconnected);
CardReaderApi.OnStateChanged.RemoveListener(OnStateChanged);
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
CardReaderApi.OnError.RemoveListener(OnReaderError);
apiSubscribed = false;
}
public void RefreshPorts()
{
if (destroying || operationInProgress) return;
var previousPort = GetSelectedPort();
portNames.Clear();
portNames.AddRange(SerialPort.GetPortNames());
portNames.Sort(StringComparer.OrdinalIgnoreCase);
if (portDropdown != null)
{
var options = portNames.Count == 0
? new List<string> { "No Ports" }
: new List<string>(portNames);
portDropdown.ClearOptions();
portDropdown.AddOptions(options);
var selectedIndex = previousPort == null ? 0 : portNames.IndexOf(previousPort);
portDropdown.value = selectedIndex < 0 ? 0 : selectedIndex;
portDropdown.RefreshShownValue();
}
SetText(portText, portNames.Count == 0 ? "端口:未发现串口" : "端口:" + GetSelectedPort());
if (portNames.Count == 0) SetStateText("未发现串口");
AppendLog(portNames.Count == 0 ? "未发现可用串口。" : "发现串口:" + string.Join(", ", portNames));
UpdateButtons();
}
public void OpenSelectedPort()
{
if (destroying || operationInProgress || manager == null || portDropdown == null || portNames.Count == 0)
return;
operationInProgress = true;
UpdateButtons();
try
{
var selectedPort = GetSelectedPort();
if (string.IsNullOrEmpty(selectedPort)) return;
var current = manager.SerialOptions;
manager.SerialOptions = new SerialDeviceOptions
{
PortName = selectedPort, BaudRate = current.BaudRate,
Parity = current.Parity, DataBits = current.DataBits, StopBits = current.StopBits,
Handshake = current.Handshake, RtsEnable = current.RtsEnable, DtrEnable = current.DtrEnable,
ReadTimeout = current.ReadTimeout, WriteTimeout = current.WriteTimeout,
AutoReconnect = current.AutoReconnect, ReconnectInterval = current.ReconnectInterval,
MaxPendingSendCount = current.MaxPendingSendCount
};
CardReaderApi.Open();
SetText(portText, "端口:" + selectedPort);
AppendLog("已打开读卡器:" + selectedPort);
}
catch (Exception exception) { ShowError("连接失败", exception); }
finally { operationInProgress = false; UpdateButtons(); }
}
public void CloseReader()
{
if (destroying || operationInProgress || manager == null) return;
operationInProgress = true;
try
{
CardReaderApi.Close();
AppendLog("已关闭读卡器。");
}
catch (Exception exception) { ShowError("断开失败", exception); }
finally { operationInProgress = false; UpdateButtons(); }
}
private void OnConnected()
{
SetStateText("Connected");
AppendLog("读卡器已连接。");
UpdateButtons();
}
private void OnDisconnected()
{
SetStateText("Disconnected");
AppendLog("读卡器已断开。");
UpdateButtons();
}
private void OnStateChanged(SerialDeviceState state)
{
SetStateText(state.ToString());
AppendLog("状态:" + state);
UpdateButtons();
}
private void OnCardReceived(CardInfo card)
{
SetText(cardTypeText, $"CardType:{card.CardType} (0x{card.CardTypeCode:X2})");
SetText(cardNumberText, $"CardNumber:{card.CardNumber}");
SetText(lastEventTimeText, $"最后事件:{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
AppendLog("收到卡片:" + card.CardNumber);
}
private void OnReaderError(CardReaderErrorEventArgs args) { ShowError("Transport/Core 错误", args.Exception); }
private void OnDestroy()
{
destroying = true;
}
private void UpdateButtons()
{
var connected = manager != null && manager.IsConnected;
if (refreshButton != null) refreshButton.interactable = !operationInProgress && !connected;
if (openButton != null) openButton.interactable = !operationInProgress && !connected && portNames.Count > 0;
if (closeButton != null) closeButton.interactable = !operationInProgress && connected;
}
private void ShowError(string message, Exception exception)
{
var text = exception == null ? message : message + ":" + FormatException(exception);
SetText(errorText, "错误:" + text);
AppendLog(text);
Debug.LogError("[AISU 830T Sample] " + text, this);
}
private string GetSelectedPort()
{
if (portDropdown == null || portDropdown.value < 0 || portDropdown.value >= portNames.Count)
return null;
return portNames[portDropdown.value];
}
private void SetStateText(string state) { SetText(stateText, "状态:" + state); }
private void AppendLog(string message)
{
if (logText == null) return;
logLines.Add(DateTime.Now.ToString("HH:mm:ss.fff") + " " + message);
if (logLines.Count > 40) logLines.RemoveAt(0);
SetText(logText, "日志:\n" + string.Join("\n", logLines));
}
private static string FormatException(Exception exception)
{
var current = exception;
var result = exception.GetType().Name + ": " + exception.Message;
while (current.InnerException != null)
{
current = current.InnerException;
result += " | " + current.GetType().Name + ": " + current.Message;
}
return result;
}
private static void SetText(Text target, string value) { if (target != null) target.text = value; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5d9c4f0bca3e4dbd8b2f7c4d9e1a6f20
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,12 @@
# AISU 830T Console Demo
Console Demo is a minimal logging sample that demonstrates `CardReaderApi` connection, disconnection, event subscription, and card-data output.
## Usage
1. Install `xin.aisu.card-reader-830t`.
2. Import **Console Demo** from the package's **Samples** section in Package Manager.
3. Open the imported `Scenes/SampleScene.unity` scene.
4. Set the actual COM port and UART settings in `CardReaderManager.SerialOptions`.
5. Run the scene. The sample uses `CardReaderApi.Open()` and writes connection, card, error, and disconnection messages to the Unity Console.
6. When the scene stops, the sample calls `CardReaderApi.Close()` and removes its listeners.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6d1f8a3c5b7e4290a2c4f6d8b1e3a750
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,12 @@
# AISU 830T Console Demo
Console Demo 是最小 API 调用和日志输出示例,用于演示 `CardReaderApi` 的连接、断开、事件监听和卡片信息输出。
## 使用
1. 安装 `xin.aisu.card-reader-830t`。
2. 在 Package Manager 的 **Samples** 区域导入 **Console Demo**。
3. 打开导入后的 `Scenes/SampleScene.unity`。
4. 在场景中的 `CardReaderManager.SerialOptions` 设置实际 COM 端口和 UART 参数。
5. 运行场景。示例使用 `CardReaderApi.Open()`,并将连接、卡片、错误和断开信息输出到 Unity Console。
6. 停止场景时示例调用 `CardReaderApi.Close()` 并解除监听。

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2a7c9e4f1b6d4380a5e2c7f9b3d81460
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3a2787d9312860343befc5d46c9545de
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,359 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 705507994}
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &705507993
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 705507995}
- component: {fileID: 705507994}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &705507994
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 705507993}
m_Enabled: 1
serializedVersion: 10
m_Type: 1
m_Shape: 0
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 1
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &705507995
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 705507993}
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1 &963194225
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 963194228}
- component: {fileID: 963194227}
- component: {fileID: 963194226}
- component: {fileID: 963194230}
- component: {fileID: 963194229}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &963194226
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_Enabled: 1
--- !u!20 &963194227
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &963194228
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &963194229
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8d870f68f8917954ba64b45d81cffc2c, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &963194230
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 23419227fdc74ce8aa78b6eb70b2b722, type: 3}
m_Name:
m_EditorClassIdentifier:
serialOptions:
PortName:
BaudRate: 9600
Parity: 0
DataBits: 8
StopBits: 1
Handshake: 0
ReadTimeout: 100
WriteTimeout: 1000
RtsEnable: 1
DtrEnable: 1
AutoReconnect: 1
ReconnectInterval: 1000
MaxPendingSendCount: 256
openOnStart: 0
onConnected:
m_PersistentCalls:
m_Calls: []
onDisconnected:
m_PersistentCalls:
m_Calls: []
onStateChanged:
m_PersistentCalls:
m_Calls: []
onCardReceived:
m_PersistentCalls:
m_Calls: []
onError:
m_PersistentCalls:
m_Calls: []

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9fc0d4010bbf28b4594072e72b8655ab
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fe930ff4a01082c46a7763a7047dc4f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,43 @@
using Aisu.CardReader;
using UnityEngine;
public sealed class CardReaderConsoleTest : MonoBehaviour
{
private void Start()
{
CardReaderApi.OnConnected.AddListener(OnConnected);
CardReaderApi.OnCardReceived.AddListener(OnCardReceived);
CardReaderApi.OnError.AddListener(OnError);
CardReaderApi.OnDisconnected.AddListener(OnDisconnected);
CardReaderApi.Open();
}
private static void OnConnected()
{
Debug.Log("On Connected.");
}
private static void OnCardReceived(CardInfo card)
{
Debug.Log($"{card.CardType} ({card.CardTypeCode:X2}): {card.CardNumber}");
}
private static void OnError(CardReaderErrorEventArgs error)
{
Debug.LogError(error.Exception.Message);
}
private static void OnDisconnected()
{
Debug.Log("On Disconnected.");
}
private void OnDestroy()
{
CardReaderApi.OnConnected.RemoveListener(OnConnected);
CardReaderApi.OnCardReceived.RemoveListener(OnCardReceived);
CardReaderApi.OnError.RemoveListener(OnError);
CardReaderApi.OnDisconnected.RemoveListener(OnDisconnected);
CardReaderApi.Close();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d870f68f8917954ba64b45d81cffc2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

25
package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "xin.aisu.card-reader-830t",
"displayName": "AISU 830T Card Reader SDK",
"version": "0.1.0",
"unity": "2021.3",
"description": "AISU 830T card reader SDK for Unity on Windows.",
"samples": [
{
"displayName": "Basic",
"description": "Basic Card Reader usage sample.",
"path": "Samples~/Basic"
},
{
"displayName": "Console Demo",
"description": "Minimal console-style sample demonstrating the Card Reader SDK API.",
"path": "Samples~/Console Demo"
}
],
"dependencies": {
"com.unity.ugui": "1.0.0"
},
"author": {
"name": "AISU"
}
}

7
package.json.meta Normal file
View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bae067ad5ccd4f44e893d57f7f231c2a
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: