Skip to content

Commit fadf6f7

Browse files
authored
Api js/rfid (#1987)
* Add technical overview for SRIX/ST25TB tags This document provides a comprehensive technical overview of SRIX and ST25TB contactless RFID memory chips, detailing their features, operating conditions, memory organization, command set, and application patterns. * SRIX Development Notes * Ignore custom documentation directory Add custom documentation directory to .gitignore * Update status for T-Embed CC1101 to 'Not Tested' * Create RFID API README with usage and details Added a comprehensive README for the RFID JavaScript API, detailing features, usage, and implementation. * Revise RFID API README for new features and usage Updated RFID API documentation to reflect new features, including headless operation and enhanced JavaScript bindings. * Enhance RFID API README with author and module status Updated the README to include author information and credits, and modified the status of supported modules. * Example scripts for RFID API * Add RFID JavaScript interface functions * Add RFID JavaScript header file * Register RFID functions in the interpreter * Add RFID module include to interpreter.h * Add headless mode functionality to TagOMatic * Add headless mode constructor and JS support methods * Delete docs_custom directory * Update rfid_js.h Add new commands for JS interpreter * Update rfid_js.cpp New commands for RFID API JS * Bugfix dialog_js.cpp Bugfix for SD priority over LittleFS * Update tag_o_matic.h for JS API * Update tag_o_matic.cpp for RFID JS API Added dome headless function for JS API. Implemented in tag-o-matic to maintain standard logic * Bugfix PN532.cpp Bugfix to close loop while writing tag * Bugfix RFID2.cpp Bugfix for writing loop (same as PN532) * Update .gitignore * Update rfid_js.h * Update rfid_js.cpp added AddMifareKey function * Update pn532_srix.cpp * Update pn532_srix.h * Update srix_tool.cpp add SRIX headless, review code for PN532 i2C polling mode * Update srix_tool.h * Update rfid_js.h * Update rfid_js.cpp
1 parent 5177ccf commit fadf6f7

File tree

13 files changed

+1674
-32
lines changed

13 files changed

+1674
-32
lines changed

lib/PN532_SRIX/pn532_srix.cpp

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
* @author Lilz
1616
* @license GNU Lesser General Public License v3.0 (see license.txt)
17-
* Refactored by Senape3000 to reuse Adafruit_PN532 constants only
17+
* Refactored by Senape3000 to reuse Adafruit_PN532 constants only (v1.2)
1818
* This is a library for the communication with an I2C PN532 NFC/RFID breakout board.
1919
* adapted from Adafruit's library.
2020
* This library supports only I2C to communicate.
@@ -68,7 +68,7 @@ bool Arduino_PN532_SRIX::SAMConfig() {
6868

6969
void Arduino_PN532_SRIX::readData(uint8_t *buffer, uint8_t n) {
7070
delay(2);
71-
Wire.requestFrom((uint8_t)PN532_I2C_ADDRESS, (uint8_t)(n + 1));
71+
Wire.requestFrom((uint8_t)PN532_I2C_ADDRESS, (uint8_t)(n + 2));
7272

7373
// Discard RDY byte
7474
Wire.read();
@@ -83,12 +83,70 @@ void Arduino_PN532_SRIX::readData(uint8_t *buffer, uint8_t n) {
8383
bool Arduino_PN532_SRIX::readACK() {
8484
uint8_t ackBuffer[6];
8585
readData(ackBuffer, 6);
86-
return (memcmp(ackBuffer, pn532ack, 6) == 0);
86+
87+
#ifdef SRIX_LIB_DEBUG
88+
Serial.print("[PN532] ACK Read: ");
89+
for(int i=0; i<6; i++) {
90+
if(ackBuffer[i] < 0x10) Serial.print("0");
91+
Serial.print(ackBuffer[i], HEX);
92+
Serial.print(" ");
93+
}
94+
Serial.println();
95+
#endif
96+
97+
bool result = (memcmp(ackBuffer, pn532ack, 6) == 0);
98+
99+
#ifdef SRIX_LIB_DEBUG
100+
if(!result) Serial.println("[PN532] ❌ ACK Failed");
101+
#endif
102+
103+
return result;
87104
}
88105

89106
bool Arduino_PN532_SRIX::isReady() {
90-
if (_irq == 255) return true; // Polling mode
91-
return (digitalRead(_irq) == LOW);
107+
// --- POLLING MODE (No IRQ pin) ---
108+
if (_irq == 255) {
109+
// Request 1 byte from PN532 (Status Byte)
110+
delayMicroseconds(500);
111+
Wire.requestFrom((uint8_t)PN532_I2C_ADDRESS, (uint8_t)1);
112+
113+
// If no response or bus locked, assume not ready
114+
if (!Wire.available()) {
115+
#ifdef SRIX_LIB_DEBUG
116+
Serial.println("[PN532] isReady: No response from I2C (bus busy or chip offline)");
117+
#endif
118+
return false;
119+
}
120+
121+
// Read status byte
122+
uint8_t status = Wire.read();
123+
124+
#ifdef SRIX_LIB_DEBUG
125+
Serial.print("[PN532] Status byte: 0x");
126+
if(status < 0x10) Serial.print("0");
127+
Serial.print(status, HEX);
128+
Serial.print(" -> ");
129+
Serial.println((status & 0x01) ? "READY" : "BUSY");
130+
#endif
131+
132+
// Check Bit 0 (LSB):
133+
// 1 = Ready
134+
// 0 = Busy
135+
return (status & 0x01);
136+
}
137+
138+
// --- IRQ MODE (Hardware pin) ---
139+
// IRQ pin goes LOW when chip is ready
140+
bool ready = (digitalRead(_irq) == LOW);
141+
142+
#ifdef SRIX_LIB_DEBUG
143+
Serial.print("[PN532] IRQ pin ");
144+
Serial.print(_irq);
145+
Serial.print(": ");
146+
Serial.println(ready ? "LOW (Ready)" : "HIGH (Busy)");
147+
#endif
148+
149+
return ready;
92150
}
93151

94152
bool Arduino_PN532_SRIX::waitReady(uint16_t timeout) {
@@ -101,7 +159,7 @@ bool Arduino_PN532_SRIX::waitReady(uint16_t timeout) {
101159
}
102160
delay(10);
103161
}
104-
162+
SRIX_LIB_LOG("Ready from waitReady");
105163
return true;
106164
}
107165

@@ -113,7 +171,7 @@ void Arduino_PN532_SRIX::writeCommand(uint8_t *command, uint8_t commandLength) {
113171

114172
Wire.beginTransmission(PN532_I2C_ADDRESS);
115173

116-
checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
174+
checksum = PN532_PREAMBLE + PN532_STARTCODE1 + PN532_STARTCODE2;
117175
Wire.write(PN532_PREAMBLE);
118176
Wire.write(PN532_STARTCODE1);
119177
Wire.write(PN532_STARTCODE2);
@@ -135,12 +193,27 @@ void Arduino_PN532_SRIX::writeCommand(uint8_t *command, uint8_t commandLength) {
135193
Wire.endTransmission();
136194
}
137195

138-
bool Arduino_PN532_SRIX::sendCommandCheckAck(uint8_t *command, uint8_t commandLength, uint16_t timeout) {
139-
writeCommand(command, commandLength);
196+
bool Arduino_PN532_SRIX::sendCommandCheckAck(uint8_t *command, uint8_t commandLenght, uint16_t timeout) {
197+
// default timeout of one second
198+
// write the command
199+
writeCommand(command, commandLenght);
200+
201+
// Wait for chip to say its ready!
202+
if (!waitReady(timeout)) { return false; }
140203

141-
if (!waitReady(timeout)) return false;
204+
#ifdef SRIX_LIB_DEBUG
205+
Serial.println(F("\nI2C IRQ received"));
206+
#endif
142207

143-
return readACK();
208+
// Check acknowledgement
209+
if (!readACK()) {
210+
#ifdef SRIX_LIB_DEBUG
211+
Serial.println(F("\nNo ACK frame received!"));
212+
#endif
213+
return false;
214+
}
215+
216+
return true; // ACK is valid
144217
}
145218

146219
// ========== PN532 GENERIC FUNCTIONS ==========
@@ -242,7 +315,11 @@ bool Arduino_PN532_SRIX::SRIX_write_block(uint8_t address, uint8_t *block) {
242315
_packetbuffer[5] = block[2];
243316
_packetbuffer[6] = block[3];
244317

245-
return sendCommandCheckAck(_packetbuffer, 7);
318+
if (!sendCommandCheckAck(_packetbuffer, 7)) {
319+
SRIX_LIB_LOG("[SRIX_LIB] Write FAIL");
320+
return false; }
321+
SRIX_LIB_LOG("[SRIX_LIB] Write OK");
322+
return true;
246323
}
247324

248325
bool Arduino_PN532_SRIX::SRIX_get_uid(uint8_t *buffer) {

lib/PN532_SRIX/pn532_srix.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
* @author Lilz
1616
* @license GNU Lesser General Public License v3.0 (see license.txt)
17-
* Refactored by Senape3000 to reuse Adafruit_PN532 constants only
17+
* Refactored by Senape3000 to reuse Adafruit_PN532 constants only (v1.2)
1818
* This is a library for the communication with an I2C PN532 NFC/RFID breakout board.
1919
* adapted from Adafruit's library.
2020
* This library supports only I2C to communicate.
@@ -27,6 +27,18 @@
2727
#include <Arduino.h>
2828
#include <Wire.h>
2929

30+
// Uncomment to enable verbose debug output on Serial
31+
// #define SRIX_LIB_DEBUG
32+
33+
// Helper macro for debug
34+
#ifdef SRIX_LIB_DEBUG
35+
#define SRIX_LIB_LOG(...) Serial.printf(__VA_ARGS__); Serial.println()
36+
#define SRIX_LIB_PRINT(...) Serial.print(__VA_ARGS__)
37+
#else
38+
#define SRIX_LIB_LOG(...)
39+
#define SRIX_LIB_PRINT(...)
40+
#endif
41+
3042
// SRIX4K-specific commands
3143
#define SRIX4K_INITIATE (0x06)
3244
#define SRIX4K_SELECT (0x0E)

src/modules/bjs_interpreter/dialog_js.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ JSValue native_dialogPickFile(JSContext *ctx, JSValue *this_val, int argc, JSVal
106106
}
107107
FS *fs = NULL;
108108
if (SD.exists(filepath)) fs = &SD;
109-
if (LittleFS.exists(filepath)) fs = &LittleFS;
109+
else if (LittleFS.exists(filepath)) fs = &LittleFS; // ← added 'else'
110110
if (fs) { r = loopSD(*fs, true, extension, filepath); }
111111
return JS_NewString(ctx, r.c_str());
112112
}
@@ -184,9 +184,9 @@ JSValue native_dialogViewFile(JSContext *ctx, JSValue *this_val, int argc, JSVal
184184
if (!filepath.startsWith("/")) filepath = "/" + filepath;
185185
FS *fs = NULL;
186186
if (SD.exists(filepath)) fs = &SD;
187-
if (LittleFS.exists(filepath)) fs = &LittleFS;
188-
if (fs) viewFile(*fs, filepath);
189-
return JS_UNDEFINED;
187+
else if (LittleFS.exists(filepath)) fs = &LittleFS; // ← add "else if" for SD Priority
188+
if (fs) { viewFile(*fs, filepath); }
189+
return 0;
190190
}
191191

192192
JSValue native_dialogViewText(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {

src/modules/bjs_interpreter/interpreter.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,52 @@ void interpreterHandler(void *pvParameters) {
2828
tft.setTextSize(FM);
2929
tft.setTextColor(TFT_WHITE);
3030

31+
/// TODO: Add DUK_USE_NATIVE_STACK_CHECK check with
32+
/// uxTaskGetStackHighWaterMark
33+
duk_context *ctx =
34+
duk_create_heap(alloc_function, realloc_function, free_function, NULL, js_fatal_error_handler);
35+
36+
// Init containers
37+
clearDisplayModuleData();
38+
39+
registerConsole(ctx);
40+
41+
// Typescript emits: Object.defineProperty(exports, "__esModule", { value:
42+
// true }); In every file, this is polyfill so typescript project can run on
43+
// Bruce
44+
duk_push_object(ctx);
45+
duk_put_global_string(ctx, "exports");
46+
47+
bduk_register_c_lightfunc(ctx, "require", native_require, 1);
48+
bduk_register_c_lightfunc(ctx, "assert", native_assert, 2);
49+
// Deprecated
50+
bduk_register_c_lightfunc(ctx, "load", native_load, 1);
51+
registerGlobals(ctx);
52+
registerMath(ctx);
53+
registerRFID(ctx);
54+
// registerAudio(ctx);
55+
// registerBadUSB(ctx);
56+
// TODO: BLE UART API js wrapper https://github.com/pr3y/Bruce/pull/1133
57+
// registerDevice(ctx);
58+
// registerDialog(ctx);
59+
// registerDisplay(ctx);
60+
// registerGPIO(ctx);
61+
// registerI2C(ctx);
62+
// registerIR(ctx);
63+
// registerKeyboard(ctx);
64+
// registerNotification(ctx);
65+
// registerSerial(ctx);
66+
// registerStorage(ctx);
67+
// registerSubGHz(ctx);
68+
// registerWiFi(ctx);
69+
70+
Serial.printf(
71+
"global populated:\nPSRAM: [Free: %d, max alloc: %d],\nRAM: [Free: %d, "
72+
"max alloc: %d]\n",
73+
ESP.getFreePsram(),
74+
ESP.getMaxAllocPsram(),
75+
ESP.getFreeHeap(),
76+
ESP.getMaxAllocHeap()
3177
bool psramAvailable = psramFound();
3278

3379
size_t mem_size = psramAvailable ? 65536 : 32768;
@@ -148,6 +194,106 @@ bool run_bjs_script_headless(FS fs, String filename) {
148194
scriptName = strdup(filename.c_str() + slash + 1);
149195
scriptDirpath = strndup(filename.c_str(), slash);
150196

197+
/* 2FIX: not working
198+
// terminate the script
199+
duk_ret_t native_exit(duk_context *ctx) {
200+
duk_error(ctx, DUK_ERR_ERROR, "Script exited");
201+
interpreter_start=false;
202+
return 0;
203+
}
204+
*/
205+
206+
duk_ret_t native_require(duk_context *ctx) {
207+
duk_idx_t obj_idx = duk_push_object(ctx);
208+
209+
if (!duk_is_string(ctx, 0)) { return 1; }
210+
String filepath = duk_to_string(ctx, 0);
211+
212+
if (filepath == "audio") {
213+
putPropAudioFunctions(ctx, obj_idx, 0);
214+
} else if (filepath == "badusb") {
215+
putPropBadUSBFunctions(ctx, obj_idx, 0);
216+
} else if (filepath == "blebeacon") {
217+
218+
} else if (filepath == "dialog" || filepath == "gui") {
219+
putPropDialogFunctions(ctx, obj_idx, 0);
220+
} else if (filepath == "display") {
221+
putPropDisplayFunctions(ctx, obj_idx, 0);
222+
223+
} else if (filepath == "device" || filepath == "flipper") {
224+
putPropDeviceFunctions(ctx, obj_idx, 0);
225+
} else if (filepath == "gpio") {
226+
putPropGPIOFunctions(ctx, obj_idx, 0);
227+
} else if (filepath == "i2c") {
228+
putPropI2CFunctions(ctx, obj_idx, 0);
229+
} else if (filepath == "http") {
230+
// TODO: Make the WebServer API compatible with the Node.js API
231+
// The more compatible we are, the more Node.js scripts can run on Bruce
232+
// MEMO: We need to implement an event loop so the WebServer can run:
233+
// https://github.com/svaarala/duktape/tree/master/examples/eventloop
234+
235+
} else if (filepath == "ir") {
236+
putPropIRFunctions(ctx, obj_idx, 0);
237+
} else if (filepath == "rfid") {
238+
putPropRFIDFunctions(ctx, obj_idx, 0);
239+
} else if (filepath == "keyboard" || filepath == "input") {
240+
putPropKeyboardFunctions(ctx, obj_idx, 0);
241+
} else if (filepath == "math") {
242+
putPropMathFunctions(ctx, obj_idx, 0);
243+
} else if (filepath == "notification") {
244+
putPropNotificationFunctions(ctx, obj_idx, 0);
245+
} else if (filepath == "serial") {
246+
putPropSerialFunctions(ctx, obj_idx, 0);
247+
} else if (filepath == "storage") {
248+
putPropStorageFunctions(ctx, obj_idx, 0);
249+
} else if (filepath == "subghz") {
250+
putPropSubGHzFunctions(ctx, obj_idx, 0);
251+
} else if (filepath == "wifi") {
252+
putPropWiFiFunctions(ctx, obj_idx, 0);
253+
} else {
254+
FS *fs = NULL;
255+
if (SD.exists(filepath)) fs = &SD;
256+
else if (LittleFS.exists(filepath)) fs = &LittleFS;
257+
if (fs == NULL) { return 1; }
258+
259+
const char *requiredScript = readBigFile(*fs, filepath);
260+
if (requiredScript == NULL) { return 1; }
261+
262+
duk_push_string(ctx, "(function(){exports={};module={exports:exports};\n");
263+
duk_push_string(ctx, requiredScript);
264+
duk_push_string(ctx, "\n})");
265+
duk_concat(ctx, 3);
266+
267+
duk_int_t pcall_rc = duk_pcompile(ctx, DUK_COMPILE_EVAL);
268+
if (pcall_rc != DUK_EXEC_SUCCESS) { return 1; }
269+
270+
pcall_rc = duk_pcall(ctx, 1);
271+
if (pcall_rc == DUK_EXEC_SUCCESS) {
272+
duk_get_prop_string(ctx, -1, "exports");
273+
duk_compact(ctx, -1);
274+
}
275+
}
276+
277+
return 1;
278+
}
279+
280+
duk_ret_t native_assert(duk_context *ctx) {
281+
if (duk_get_boolean_default(ctx, 0, false)) {
282+
duk_push_boolean(ctx, true);
283+
return 1;
284+
}
285+
return duk_error(ctx, DUK_ERR_ERROR, "Assertion failed: %s", duk_get_string_default(ctx, 1, "assert"));
286+
}
287+
288+
// Deprecated
289+
duk_ret_t native_load(duk_context *ctx) {
290+
free((char *)script);
291+
free((char *)scriptDirpath);
292+
free((char *)scriptName);
293+
script = strdup(duk_to_string(ctx, 0));
294+
scriptDirpath = NULL;
295+
scriptName = NULL;
296+
return 0;
151297
returnToMenu = true;
152298
interpreter_state = 1;
153299
startInterpreterTask();

src/modules/bjs_interpreter/interpreter.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@
66

77
#include <string.h>
88

9+
#include "audio_js.h"
10+
#include "badusb_js.h"
11+
#include "device_js.h"
12+
#include "dialog_js.h"
13+
#include "display_js.h"
14+
#include "globals_js.h"
15+
#include "gpio_js.h"
16+
#include "helpers_js.h"
17+
#include "i2c_js.h"
18+
#include "ir_js.h"
19+
#include "keyboard_js.h"
20+
#include "math_js.h"
21+
#include "notification_js.h"
22+
#include "rfid_js.h"
23+
#include "serial_js.h"
24+
#include "storage_js.h"
25+
#include "subghz_js.h"
26+
#include "wifi_js.h"
927
extern TaskHandle_t interpreterTaskHandler;
1028

1129
// Credits to https://github.com/justinknight93/Doolittle

0 commit comments

Comments
 (0)