nfcscript 0.0.7__tar.gz → 0.0.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nfcscript
3
- Version: 0.0.7
3
+ Version: 0.0.9
4
4
  Summary: A plugin-based core engine for DSL-style NFC testing automation.
5
5
  Author: crthu
6
6
  Requires-Python: >=3.14
@@ -191,7 +191,7 @@ with session() as reader:
191
191
 
192
192
  | 函数 | 说明 |
193
193
  |------|------|
194
- | `ASSERT_EQUAL(expected, actual, msg)` | 相等断言 |
194
+ | `ASSERT_EQUAL(actual, expected, msg)` | 相等断言 |
195
195
  | `ASSERT_LEN(data, expected_len, msg)` | 长度断言 |
196
196
  | `ASSERT_IS_NOT_NONE(value, msg)` | 非空断言 |
197
197
  | `ASSERT_IS_NONE(value, msg)` | 空值断言 |
@@ -253,6 +253,16 @@ NFC_TRACE_DRIVER=true
253
253
  NFC_TRACE_PROTOCOL=true
254
254
  ```
255
255
 
256
+ ## AI 编写脚本
257
+
258
+ 本目录下 `SKILL.md` 提供了 DSL 的完整 API 参考和 few-shot 示例,可直接用于 AI Agent 生成 NFC 脚本。
259
+
260
+ **使用方式**:在 AI 对话中引用该文件,例如:
261
+ ```
262
+ @nfcscript/SKILL.md
263
+ ```
264
+ Agent 会基于 SKILL.md 中的 API 签名、few-shot 示例和约定生成正确的脚本代码。
265
+
256
266
  ## 开发
257
267
 
258
268
  ```bash
@@ -181,7 +181,7 @@ with session() as reader:
181
181
 
182
182
  | 函数 | 说明 |
183
183
  |------|------|
184
- | `ASSERT_EQUAL(expected, actual, msg)` | 相等断言 |
184
+ | `ASSERT_EQUAL(actual, expected, msg)` | 相等断言 |
185
185
  | `ASSERT_LEN(data, expected_len, msg)` | 长度断言 |
186
186
  | `ASSERT_IS_NOT_NONE(value, msg)` | 非空断言 |
187
187
  | `ASSERT_IS_NONE(value, msg)` | 空值断言 |
@@ -243,6 +243,16 @@ NFC_TRACE_DRIVER=true
243
243
  NFC_TRACE_PROTOCOL=true
244
244
  ```
245
245
 
246
+ ## AI 编写脚本
247
+
248
+ 本目录下 `SKILL.md` 提供了 DSL 的完整 API 参考和 few-shot 示例,可直接用于 AI Agent 生成 NFC 脚本。
249
+
250
+ **使用方式**:在 AI 对话中引用该文件,例如:
251
+ ```
252
+ @nfcscript/SKILL.md
253
+ ```
254
+ Agent 会基于 SKILL.md 中的 API 签名、few-shot 示例和约定生成正确的脚本代码。
255
+
246
256
  ## 开发
247
257
 
248
258
  ```bash
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nfcscript"
3
- version = "0.0.7"
3
+ version = "0.0.9"
4
4
  description = "A plugin-based core engine for DSL-style NFC testing automation."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -34,7 +34,7 @@ dev = [
34
34
  ]
35
35
 
36
36
  [tool.bumpversion]
37
- current_version = "0.0.7"
37
+ current_version = "0.0.9"
38
38
  commit = true
39
39
  tag = true
40
40
  allow_dirty = true
@@ -1,20 +1,12 @@
1
1
  import os
2
2
  from contextlib import contextmanager
3
- from typing import NamedTuple
3
+ from nfctester.drivers.card_reader import CardInfo, TransceiveResult
4
4
  from nfctester.registry import CardReaderRegistry
5
5
  from .assertions import ASSERT_EQUAL, ASSERT_IS_NOT_NONE, ASSERT_LEN
6
6
  from .checksum import GET_BCC
7
7
  from .hex_util import FORMAT_HEX
8
8
 
9
9
 
10
- class TransceiveResult(NamedTuple):
11
- """transceive_bits 返回结果"""
12
- data: list[int]
13
- """接收到的数据字节列表"""
14
- bits: int
15
- """最后一个字节的有效位数 (0 = 完整字节)"""
16
-
17
-
18
10
  class _NFCState:
19
11
  """单例状态管理,封装读卡器生命周期"""
20
12
 
@@ -33,13 +25,13 @@ class _NFCState:
33
25
 
34
26
  def connect(self, port: str = "COM20", reader_type: str = "pn532"):
35
27
  self._reader = CardReaderRegistry.create(reader_type, transport="serial", port=port)
36
- self._reader.connect()
28
+ self._reader.open()
37
29
  self._connected = True
38
30
  print(f"Connected to {reader_type.upper()} on port {port}")
39
31
 
40
32
  def disconnect(self):
41
33
  if self._connected and self._reader:
42
- self._reader.disconnect()
34
+ self._reader.close()
43
35
  self._connected = False
44
36
  self._reader = None
45
37
  print("Disconnected")
@@ -84,30 +76,29 @@ def get_reader():
84
76
  return _state.reader
85
77
 
86
78
 
87
- def active(ll: bool = False, ignore_error: bool = False, reqa_cmd: int = 0x26) -> dict | None:
79
+ def active(ll: bool = False, ignore_error: bool = False, reqa_cmd: int = 0x26) -> CardInfo | None:
88
80
  """
89
81
  寻卡操作,检测并激活目标卡片。
90
82
 
91
83
  Args:
92
84
  ll: 如果为 True,则执行底层抗冲突流程以兼容非标卡;
93
- 如果为 False,则使用 PN532 原生 find()。
85
+ 如果为 False,则使用读卡器原生 active()。
94
86
  ignore_error: 如果为 True,当 BCC 或 SAK 校验失败时,记录警告而不停止执行。
95
87
  reqa_cmd: 底层寻卡时使用的 REQA 命令字节,默认 0x26。
96
88
  仅在 ll=True 时生效。
97
89
 
98
90
  Returns:
99
- dict: 包含卡片信息的字典,失败时返回 None。
100
- Key 说明:
91
+ CardInfo: 包含卡片信息的数据类,失败时返回 None。
92
+ 属性说明:
101
93
  - 'uid' (bytes): 卡片的 UID。
102
94
  - 'atq' (bytes): 卡片的 ATQ (Answer To Request)。
103
95
  - 'sak' (int): 卡片的 SAK (Select Acknowledge)。
104
- - 'raw' (bytes): PN532 返回的原始响应数据。
105
96
  """
106
97
  _state.ensure_connected()
107
98
  reader = _state.reader
108
99
 
109
100
  if not ll:
110
- return reader.find()
101
+ return reader.active()
111
102
 
112
103
  # 手动底层寻卡流程
113
104
  # 1. REQA
@@ -138,7 +129,7 @@ def active(ll: bool = False, ignore_error: bool = False, reqa_cmd: int = 0x26) -
138
129
 
139
130
  print(f"cl{cl}.uid: {FORMAT_HEX(data)}")
140
131
  has_next = (data[0] == 0x88)
141
- uid_to_select = data[0:5]
132
+ uid_to_select = list(data[0:5])
142
133
  sak_res = select(cl_level=cl, uid=uid_to_select)
143
134
 
144
135
  # SAK 校验
@@ -156,13 +147,7 @@ def active(ll: bool = False, ignore_error: bool = False, reqa_cmd: int = 0x26) -
156
147
  sak = sak_res[0] if sak_res else 0
157
148
  break
158
149
 
159
- # 返回兼容的字典格式
160
- return {
161
- 'uid': bytes(full_uid),
162
- 'atq': bytes(atq),
163
- 'sak': sak,
164
- 'raw': bytes(full_uid), # 兼容原有的 raw 字段
165
- }
150
+ return CardInfo(uid=bytes(full_uid), atq=bytes(atq), sak=sak)
166
151
 
167
152
 
168
153
  def transceive(data: list[int], tx_crc: bool = True, rx_crc: bool = True) -> list[int]:
@@ -179,9 +164,8 @@ def transceive(data: list[int], tx_crc: bool = True, rx_crc: bool = True) -> lis
179
164
  """
180
165
  _state.ensure_connected()
181
166
  reader = _state.reader
182
- reader.set_crc(tx_crc, rx_crc)
183
- res = reader.transceive(bytes(data))
184
- return list(res) if res is not None else []
167
+ res = reader.transceive(bytes(data), tx_crc=tx_crc, rx_crc=rx_crc)
168
+ return list(res.data) if res and res.data else []
185
169
 
186
170
 
187
171
  def transceive_bits(data: list[int], last_tx_bits: int = 0, tx_crc: bool = True, rx_crc: bool = True) -> TransceiveResult | None:
@@ -196,15 +180,11 @@ def transceive_bits(data: list[int], last_tx_bits: int = 0, tx_crc: bool = True,
196
180
  rx_crc: 接收时是否自动校验 CRC。
197
181
 
198
182
  Returns:
199
- TransceiveResult | None: 包含 data 和 bits 属性,失败返回 None。
183
+ TransceiveResult | None: 包含 data 和 rx_bits 属性,失败返回 None。
200
184
  """
201
185
  _state.ensure_connected()
202
186
  reader = _state.reader
203
- reader.set_crc(tx_crc, rx_crc)
204
- res = reader.transceive(bytes(data), last_tx_bits=last_tx_bits)
205
- if res is None:
206
- return None
207
- return TransceiveResult(data=list(res), bits=reader.last_rx_bits)
187
+ return reader.transceive_bits(bytes(data), last_tx_bits=last_tx_bits, tx_crc=tx_crc, rx_crc=rx_crc)
208
188
 
209
189
 
210
190
  def reqa(cmd: int = 0x26) -> TransceiveResult | None:
@@ -239,7 +219,7 @@ def anticoll(cl_level: int, nvb: int = 0x20, uid_prefix: list[int] = []) -> Tran
239
219
  :param cl_level: 1 (0x93), 2 (0x95), or 3 (0x97)
240
220
  :param nvb: Number of Valid Bits,定义了包含 SEL 和 NVB 在内的有效位数
241
221
  :param uid_prefix: 已知的部分 UID (0-4 字节)
242
- :return: TransceiveResult 包含 data 和 bits 属性
222
+ :return: TransceiveResult 包含 data 和 rx_bits 属性
243
223
  """
244
224
  cmd = [_get_sel_cmd(cl_level), nvb] + uid_prefix
245
225
  # 抗冲突响应无 CRC
@@ -260,13 +240,13 @@ def select(cl_level: int, uid: list[int]) -> list[int] | None:
260
240
  def field_on():
261
241
  """开启 PN532 的 RF 场。"""
262
242
  _state.ensure_connected()
263
- _state.reader.set_rf_field(True)
243
+ _state.reader.rf_field = True
264
244
 
265
245
 
266
246
  def field_off():
267
247
  """关闭 PN532 的 RF 场。"""
268
248
  _state.ensure_connected()
269
- _state.reader.set_rf_field(False)
249
+ _state.reader.rf_field = False
270
250
 
271
251
 
272
252
  def close():
@@ -283,7 +263,7 @@ def session(port: str = None, reader_type: str = None):
283
263
 
284
264
  用法:
285
265
  with session("COM20") as reader:
286
- card_info = reader.find()
266
+ card_info = reader.active()
287
267
  """
288
268
  if port is None:
289
269
  port = os.environ.get("NFC_PORT")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nfcscript
3
- Version: 0.0.7
3
+ Version: 0.0.9
4
4
  Summary: A plugin-based core engine for DSL-style NFC testing automation.
5
5
  Author: crthu
6
6
  Requires-Python: >=3.14
@@ -191,7 +191,7 @@ with session() as reader:
191
191
 
192
192
  | 函数 | 说明 |
193
193
  |------|------|
194
- | `ASSERT_EQUAL(expected, actual, msg)` | 相等断言 |
194
+ | `ASSERT_EQUAL(actual, expected, msg)` | 相等断言 |
195
195
  | `ASSERT_LEN(data, expected_len, msg)` | 长度断言 |
196
196
  | `ASSERT_IS_NOT_NONE(value, msg)` | 非空断言 |
197
197
  | `ASSERT_IS_NONE(value, msg)` | 空值断言 |
@@ -253,6 +253,16 @@ NFC_TRACE_DRIVER=true
253
253
  NFC_TRACE_PROTOCOL=true
254
254
  ```
255
255
 
256
+ ## AI 编写脚本
257
+
258
+ 本目录下 `SKILL.md` 提供了 DSL 的完整 API 参考和 few-shot 示例,可直接用于 AI Agent 生成 NFC 脚本。
259
+
260
+ **使用方式**:在 AI 对话中引用该文件,例如:
261
+ ```
262
+ @nfcscript/SKILL.md
263
+ ```
264
+ Agent 会基于 SKILL.md 中的 API 签名、few-shot 示例和约定生成正确的脚本代码。
265
+
256
266
  ## 开发
257
267
 
258
268
  ```bash
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes