@irsdk-node/native 5.1.0 → 5.2.1
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.
- package/binding.gyp +5 -13
- package/dist/cjs/index.cjs +24 -9
- package/dist/esm/index.js +23 -9
- package/dist/types/INativeSDK.d.ts +11 -0
- package/dist/types/MockSdk.d.ts +4 -1
- package/dist/types/index.d.ts +1 -0
- package/install.js +4 -0
- package/lib/irsdk_node.cpp +533 -0
- package/lib/irsdk_node.h +93 -36
- package/lib/logger.cpp +68 -0
- package/lib/logger.h +57 -0
- package/lib/root.cpp +11 -0
- package/package.json +6 -6
- package/prebuilds/@irsdk-node+native.node +0 -0
- package/lib/irsdk_node.cc +0 -457
- package/lib/irsdk_node_mocked.cc +0 -226
- package/prebuilds/darwin-arm64/@irsdk-node+native.node +0 -0
- package/prebuilds/linux-x64/@irsdk-node+native.node +0 -0
- package/prebuilds/win32-x64/@irsdk-node+native.node +0 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
#include "./irsdk_defines.h"
|
|
2
|
+
#include "./irsdk_node.h"
|
|
3
|
+
#include "./logger.h"
|
|
4
|
+
#include <cstdio>
|
|
5
|
+
#include <napi.h>
|
|
6
|
+
#include <napi-inl.h>
|
|
7
|
+
#include <string.h>
|
|
8
|
+
|
|
9
|
+
static const char *K_IRSDK_CLASS_EXPORT_NAME = "iRacingSdkNode";
|
|
10
|
+
|
|
11
|
+
// ---------------------------
|
|
12
|
+
// Constructors
|
|
13
|
+
// ---------------------------
|
|
14
|
+
Napi::Object iRacingSdkNode::Init(Napi::Env aEnv, Napi::Object aExports)
|
|
15
|
+
{
|
|
16
|
+
Napi::Function func = DefineClass(aEnv, K_IRSDK_CLASS_EXPORT_NAME, {
|
|
17
|
+
// Properties
|
|
18
|
+
InstanceAccessor<&iRacingSdkNode::_napi_prop_getCurrSessionDataVer>("currDataVersion"),
|
|
19
|
+
InstanceAccessor<&iRacingSdkNode::_napi_prop_getEnableLogging, &iRacingSdkNode::_napi_prop_setEnableLogging>("enableLogging"),
|
|
20
|
+
InstanceAccessor<&iRacingSdkNode::_napi_prop_getLogLevel, &iRacingSdkNode::_napi_prop_setLogLevel>("logLevel"),
|
|
21
|
+
InstanceAccessor<&iRacingSdkNode::_napi_prop_getIsMocked>("isMocked"),
|
|
22
|
+
|
|
23
|
+
// Methods
|
|
24
|
+
// Control
|
|
25
|
+
InstanceMethod("startSDK", &iRacingSdkNode::_napi_startSdk),
|
|
26
|
+
InstanceMethod("stopSDK", &iRacingSdkNode::_napi_stopSdk),
|
|
27
|
+
InstanceMethod("waitForData", &iRacingSdkNode::_napi_waitForData),
|
|
28
|
+
InstanceMethod("broadcast", &iRacingSdkNode::_napi_broadcastMessage),
|
|
29
|
+
// Getters
|
|
30
|
+
InstanceMethod("isRunning", &iRacingSdkNode::_napi_isRunning),
|
|
31
|
+
InstanceMethod("getSessionVersionNum", &iRacingSdkNode::_napi_getSessionVersionNum),
|
|
32
|
+
InstanceMethod("getSessionConnectionID", &iRacingSdkNode::_napi_getSessionConnectionID),
|
|
33
|
+
InstanceMethod("getSessionData", &iRacingSdkNode::_napi_getSessionData),
|
|
34
|
+
InstanceMethod("getTelemetryData", &iRacingSdkNode::_napi_getTelemetryData),
|
|
35
|
+
InstanceMethod("getTelemetryVariable", &iRacingSdkNode::GetTelemetryVar),
|
|
36
|
+
// Helpers
|
|
37
|
+
InstanceMethod("__getTelemetryTypes", &iRacingSdkNode::_napi_getTelemetryTypes)
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
Napi::FunctionReference *constructor = new Napi::FunctionReference();
|
|
41
|
+
*constructor = Napi::Persistent(func);
|
|
42
|
+
aEnv.SetInstanceData(constructor);
|
|
43
|
+
|
|
44
|
+
aExports.Set(K_IRSDK_CLASS_EXPORT_NAME, func);
|
|
45
|
+
return aExports;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
iRacingSdkNode::iRacingSdkNode(const Napi::CallbackInfo &aInfo)
|
|
49
|
+
: Napi::ObjectWrap<iRacingSdkNode>(aInfo),
|
|
50
|
+
_data(NULL),
|
|
51
|
+
_bufLineLen(0),
|
|
52
|
+
_sessionStatusID(0),
|
|
53
|
+
_lastSessionCt(-1),
|
|
54
|
+
_sessionData(NULL),
|
|
55
|
+
_logger(irsdk_node::LogLevel_None)
|
|
56
|
+
{
|
|
57
|
+
printf("Initializing iRacingSdkNode\n");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Internal implementation ----------------------------------------------------
|
|
61
|
+
|
|
62
|
+
// Public API
|
|
63
|
+
// -----------
|
|
64
|
+
|
|
65
|
+
bool iRacingSdkNode::startup()
|
|
66
|
+
{
|
|
67
|
+
_logger.debug("StartSdk: Attempting to connect to SDK");
|
|
68
|
+
|
|
69
|
+
if (!irsdk_isConnected())
|
|
70
|
+
{
|
|
71
|
+
_logger.debug("iRacing SDK not connected, connecting\n");
|
|
72
|
+
bool result = irsdk_startup();
|
|
73
|
+
_logger.info("Attempted SDK startup (result: %i)\n", result);
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void iRacingSdkNode::shutdown()
|
|
82
|
+
{
|
|
83
|
+
_logger.info("Running irsdk-node shutdown");
|
|
84
|
+
irsdk_shutdown();
|
|
85
|
+
_resetData();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
bool iRacingSdkNode::isConnected() const
|
|
89
|
+
{
|
|
90
|
+
return _data != NULL && irsdk_isConnected();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
int iRacingSdkNode::getSessionInfoStrCount()
|
|
94
|
+
{
|
|
95
|
+
return irsdk_getSessionInfoStrUpdate();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
bool iRacingSdkNode::wasSessionStrUpdated()
|
|
99
|
+
{
|
|
100
|
+
return _lastSessionCt != getSessionInfoStrCount();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
bool iRacingSdkNode::waitForData(int aTimeoutMs)
|
|
104
|
+
{
|
|
105
|
+
// Wait for new data or for a session to start
|
|
106
|
+
if (irsdk_waitForDataReady(aTimeoutMs, _data) && irsdk_getHeader())
|
|
107
|
+
{
|
|
108
|
+
_logger.debug("Got data from iRacing SDK\n");
|
|
109
|
+
const irsdk_header *header = irsdk_getHeader();
|
|
110
|
+
|
|
111
|
+
// New connection or data changed length
|
|
112
|
+
if (!_data || _bufLineLen != header->bufLen)
|
|
113
|
+
{
|
|
114
|
+
_logger.debug("Connection started / data changed length\n");
|
|
115
|
+
|
|
116
|
+
// Reset memory to hold incoming data
|
|
117
|
+
if (_data) delete[] _data;
|
|
118
|
+
_bufLineLen = header->bufLen;
|
|
119
|
+
_data = new char[_bufLineLen];
|
|
120
|
+
|
|
121
|
+
// Increment connection and reset info string and buffer length
|
|
122
|
+
_sessionStatusID++;
|
|
123
|
+
_lastSessionCt = -1;
|
|
124
|
+
|
|
125
|
+
// Try to fill in the new data
|
|
126
|
+
if (irsdk_getNewData(_data))
|
|
127
|
+
{
|
|
128
|
+
_logger.debug("New data retrieved successfully\n");
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
} else if (_data)
|
|
132
|
+
{
|
|
133
|
+
_logger.debug("Data already available, ready for processing\n");
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
} else if (!isConnected())
|
|
137
|
+
{
|
|
138
|
+
_logger.debug("Session ended. Cleaning up.\n");
|
|
139
|
+
_resetData();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_logger.debug("No data available.\n");
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const char *iRacingSdkNode::getSessionStr()
|
|
148
|
+
{
|
|
149
|
+
if (!isConnected())
|
|
150
|
+
return NULL;
|
|
151
|
+
|
|
152
|
+
// If there is no session data cached or the session string is out of date,
|
|
153
|
+
// fetch the latest and update the cached session count.
|
|
154
|
+
if (!_sessionData || wasSessionStrUpdated())
|
|
155
|
+
{
|
|
156
|
+
_logger.debug("Invalid session data, fetching latest\n");
|
|
157
|
+
|
|
158
|
+
int latestUpdate = getSessionInfoStrCount();
|
|
159
|
+
_logger.info("Session data has been updated (prev: %d, new: %d)\n", _lastSessionCt, latestUpdate);
|
|
160
|
+
|
|
161
|
+
_lastSessionCt = latestUpdate;
|
|
162
|
+
_sessionData = irsdk_getSessionInfoStr();
|
|
163
|
+
} else
|
|
164
|
+
{
|
|
165
|
+
_logger.debug("Session data is valid, re-using cached\n");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return _sessionData;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Private API
|
|
172
|
+
// -------------
|
|
173
|
+
|
|
174
|
+
void iRacingSdkNode::_resetData()
|
|
175
|
+
{
|
|
176
|
+
_logger.debug("Resetting cached data...\n");
|
|
177
|
+
|
|
178
|
+
if (_data) delete[] _data;
|
|
179
|
+
_data = NULL;
|
|
180
|
+
_sessionData = NULL;
|
|
181
|
+
_lastSessionCt = -1;
|
|
182
|
+
|
|
183
|
+
_logger.debug("Finished resetting cached data\n");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Node API -------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
// Property implementations
|
|
189
|
+
// -------------------------
|
|
190
|
+
|
|
191
|
+
Napi::Value iRacingSdkNode::_napi_prop_getCurrSessionDataVer(const Napi::CallbackInfo &aInfo)
|
|
192
|
+
{
|
|
193
|
+
return Napi::Number::New(aInfo.Env(), this->_lastSessionCt);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
Napi::Value iRacingSdkNode::_napi_prop_getEnableLogging(const Napi::CallbackInfo &aInfo)
|
|
197
|
+
{
|
|
198
|
+
bool enabled = this->_logger.logLevel > irsdk_node::LogLevel_None;
|
|
199
|
+
return Napi::Boolean::New(aInfo.Env(), enabled);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void iRacingSdkNode::_napi_prop_setEnableLogging(const Napi::CallbackInfo &aInfo, const Napi::Value &aValue)
|
|
203
|
+
{
|
|
204
|
+
Napi::Boolean enable;
|
|
205
|
+
if (!aValue.IsBoolean())
|
|
206
|
+
{
|
|
207
|
+
enable = Napi::Boolean::New(aInfo.Env(), false);
|
|
208
|
+
} else
|
|
209
|
+
{
|
|
210
|
+
enable = aValue.As<Napi::Boolean>();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
this->_logger.logLevel = enable ? irsdk_node::LogLevel_Error : irsdk_node::LogLevel_None;
|
|
214
|
+
this->_logger.warn("DEPRECATION WARNING: .enableLogging is deprecated, please use .logLevel instead\n");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Napi::Value iRacingSdkNode::_napi_prop_getLogLevel(const Napi::CallbackInfo &aInfo)
|
|
218
|
+
{
|
|
219
|
+
return Napi::Number::New(aInfo.Env(), this->_logger.logLevel);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
void iRacingSdkNode::_napi_prop_setLogLevel(const Napi::CallbackInfo &aInfo, const Napi::Value &aValue)
|
|
223
|
+
{
|
|
224
|
+
if (!aValue.IsNumber())
|
|
225
|
+
{
|
|
226
|
+
this->_logger.warn(".logLevel must be given a number (or the LogLevel enum)\n");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
irsdk_node::LogLevel level = static_cast<irsdk_node::LogLevel>(aValue.As<Napi::Number>().Int32Value());
|
|
231
|
+
if (level < irsdk_node::LogLevel_None || level > irsdk_node::LogLevel_Debug)
|
|
232
|
+
{
|
|
233
|
+
this->_logger.warn("logLevel given an invalid value\n");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
this->_logger.logLevel = level;
|
|
238
|
+
this->_logger.info("Log level changed to %s\n", irsdk_node::Logger::GetLabelForLevel(level));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
Napi::Value iRacingSdkNode::_napi_prop_getIsMocked(const Napi::CallbackInfo &aInfo)
|
|
242
|
+
{
|
|
243
|
+
return Napi::Boolean::New(aInfo.Env(), false);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
// Instance implementations
|
|
248
|
+
// ---------------------------
|
|
249
|
+
|
|
250
|
+
// SDK Control
|
|
251
|
+
Napi::Value iRacingSdkNode::_napi_startSdk(const Napi::CallbackInfo &aInfo)
|
|
252
|
+
{
|
|
253
|
+
return Napi::Boolean::New(aInfo.Env(), startup());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
Napi::Value iRacingSdkNode::_napi_stopSdk(const Napi::CallbackInfo &aInfo)
|
|
257
|
+
{
|
|
258
|
+
shutdown();
|
|
259
|
+
return Napi::Boolean::New(aInfo.Env(), true);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
Napi::Value iRacingSdkNode::_napi_waitForData(const Napi::CallbackInfo &aInfo)
|
|
263
|
+
{
|
|
264
|
+
int timeout = aInfo.Length() <= 0 || !aInfo[0].IsNumber()
|
|
265
|
+
? K_DEFAULT_TIMEOUT_MS
|
|
266
|
+
: aInfo[0].As<Napi::Number>().Int32Value();
|
|
267
|
+
|
|
268
|
+
if (timeout < 16) timeout = 16;
|
|
269
|
+
|
|
270
|
+
return Napi::Boolean::New(aInfo.Env(), waitForData(timeout));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
Napi::Value iRacingSdkNode::_napi_broadcastMessage(const Napi::CallbackInfo &aInfo)
|
|
274
|
+
{
|
|
275
|
+
auto env = aInfo.Env();
|
|
276
|
+
|
|
277
|
+
// Determine message type
|
|
278
|
+
if (aInfo.Length() <= 2 || !aInfo[0].IsNumber())
|
|
279
|
+
{
|
|
280
|
+
return Napi::Boolean::New(env, false);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (aInfo.Length() == 4 && !aInfo[2].IsNumber())
|
|
284
|
+
{
|
|
285
|
+
return Napi::Boolean::New(env, false);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
Napi::Number msgEnumIndex = aInfo[0].As<Napi::Number>();
|
|
289
|
+
irsdk_BroadcastMsg msgType = static_cast<irsdk_BroadcastMsg>(msgEnumIndex.Int32Value());
|
|
290
|
+
|
|
291
|
+
// Args
|
|
292
|
+
Napi::Number arg1 = aInfo[1].As<Napi::Number>();
|
|
293
|
+
Napi::Number arg2 = aInfo[2].As<Napi::Number>();
|
|
294
|
+
Napi::Number arg3 = aInfo[3].As<Napi::Number>();
|
|
295
|
+
|
|
296
|
+
irsdk_ChatCommandMode chatCommand = irsdk_ChatCommand_Cancel;
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
// Handle each message independently.
|
|
300
|
+
//
|
|
301
|
+
// This could be consolidated, but then it becomes way too difficult to easily
|
|
302
|
+
// grep what each messages expected API is, as some are not necessarily what
|
|
303
|
+
switch (msgType)
|
|
304
|
+
{
|
|
305
|
+
// BroadcastCamSwitchPos: car position, group, camera
|
|
306
|
+
// BroadcastCamSwitchNum: driver #, group, camera
|
|
307
|
+
case irsdk_BroadcastCamSwitchPos:
|
|
308
|
+
case irsdk_BroadcastCamSwitchNum:
|
|
309
|
+
// First arg can be irsdk_csMode enum.
|
|
310
|
+
// Any value above -1 equates to focusing on a specific driver.
|
|
311
|
+
irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.Int32Value(), arg3.Int32Value());
|
|
312
|
+
break;
|
|
313
|
+
|
|
314
|
+
// irsdk_CameraState, unused, unused
|
|
315
|
+
case irsdk_BroadcastCamSetState:
|
|
316
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_CameraState>(arg1.Int32Value()), 0);
|
|
317
|
+
break;
|
|
318
|
+
|
|
319
|
+
// speed, slowMotion, unused
|
|
320
|
+
case irsdk_BroadcastReplaySetPlaySpeed:
|
|
321
|
+
// Speed (arg1) should be multiples of 2 (0, 1, 2, 4, 8, 16), can be negative
|
|
322
|
+
// Slow mo (arg2) should be 1 | 0
|
|
323
|
+
irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.ToBoolean().Value());
|
|
324
|
+
break;
|
|
325
|
+
|
|
326
|
+
// irsdk_RpyPosMode, Frame Number (high, low)
|
|
327
|
+
case irsdk_BroadcastReplaySetPlayPosition:
|
|
328
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_RpyPosMode>(arg1.Int32Value()), arg2.Int32Value());
|
|
329
|
+
break;
|
|
330
|
+
|
|
331
|
+
// irsdk_RpySrchMode, unused, unused
|
|
332
|
+
case irsdk_BroadcastReplaySearch:
|
|
333
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_RpySrchMode>(arg1.Int32Value()), 0, 0);
|
|
334
|
+
break;
|
|
335
|
+
|
|
336
|
+
// irsdk_RpyStateMode, unused, unused
|
|
337
|
+
case irsdk_BroadcastReplaySetState:
|
|
338
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_RpyStateMode>(arg1.Int32Value()), 0);
|
|
339
|
+
break;
|
|
340
|
+
|
|
341
|
+
// irsdk_ReloadTexturesMode, carIdx, unused
|
|
342
|
+
case irsdk_BroadcastReloadTextures:
|
|
343
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_ReloadTexturesMode>(arg1.Int32Value()), arg2.Int32Value(), 0);
|
|
344
|
+
break;
|
|
345
|
+
|
|
346
|
+
// irsdk_ChatCommandMode, subCommand, unused
|
|
347
|
+
case irsdk_BroadcastChatComand:
|
|
348
|
+
chatCommand = static_cast<irsdk_ChatCommandMode>(arg1.Int32Value());
|
|
349
|
+
if (chatCommand != irsdk_ChatCommand_Macro)
|
|
350
|
+
{
|
|
351
|
+
irsdk_broadcastMsg(msgType, chatCommand, 0);
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// If the chat command is to use a macro, parse the macro id (1 - 15) (2nd arg)
|
|
356
|
+
irsdk_broadcastMsg(msgType, chatCommand, arg2.Int32Value(), 0);
|
|
357
|
+
break;
|
|
358
|
+
|
|
359
|
+
// irsdk_PitCommandMode, parameter
|
|
360
|
+
case irsdk_BroadcastPitCommand:
|
|
361
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_PitCommandMode>(arg1.Int32Value()), arg2.Int32Value());
|
|
362
|
+
break;
|
|
363
|
+
|
|
364
|
+
// irsdk_TelemCommandMode, unused, unused
|
|
365
|
+
case irsdk_BroadcastTelemCommand:
|
|
366
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_TelemCommandMode>(arg1.Int32Value()), 0, 0);
|
|
367
|
+
break;
|
|
368
|
+
|
|
369
|
+
// irsdk_FFBCommandMode, value (float, high, low)
|
|
370
|
+
case irsdk_BroadcastFFBCommand:
|
|
371
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_FFBCommandMode>(arg1.Int32Value()), arg2.FloatValue());
|
|
372
|
+
break;
|
|
373
|
+
|
|
374
|
+
// This does a search and not a direct jump, so it may take a while
|
|
375
|
+
// sessionNum, sessionTimeMS (high, low)
|
|
376
|
+
case irsdk_BroadcastReplaySearchSessionTime:
|
|
377
|
+
irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.Int32Value());
|
|
378
|
+
break;
|
|
379
|
+
|
|
380
|
+
// irsdk_VideoCaptureMode, unused, unused
|
|
381
|
+
case irsdk_BroadcastVideoCapture:
|
|
382
|
+
irsdk_broadcastMsg(msgType, static_cast<irsdk_VideoCaptureMode>(arg1.Int32Value()), 0);
|
|
383
|
+
break;
|
|
384
|
+
|
|
385
|
+
// Unused + out-of-bounds
|
|
386
|
+
default:
|
|
387
|
+
this->_logger.error("Attempted to broadcast an unsupported message.\n");
|
|
388
|
+
return Napi::Boolean::New(env, false);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return Napi::Boolean::New(env, true);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// SDK State Getters
|
|
395
|
+
Napi::Value iRacingSdkNode::_napi_isRunning(const Napi::CallbackInfo &aInfo)
|
|
396
|
+
{
|
|
397
|
+
return Napi::Boolean::New(aInfo.Env(), isConnected());
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
Napi::Value iRacingSdkNode::_napi_getSessionVersionNum(const Napi::CallbackInfo &aInfo)
|
|
401
|
+
{
|
|
402
|
+
return Napi::Number::New(aInfo.Env(), getSessionInfoStrCount());
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
Napi::Value iRacingSdkNode::_napi_getSessionConnectionID(const Napi::CallbackInfo &aInfo)
|
|
406
|
+
{
|
|
407
|
+
return Napi::Number::New(aInfo.Env(), this->_sessionStatusID);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
Napi::Value iRacingSdkNode::_napi_getSessionData(const Napi::CallbackInfo &aInfo)
|
|
411
|
+
{
|
|
412
|
+
auto session = getSessionStr();
|
|
413
|
+
|
|
414
|
+
if (session == NULL)
|
|
415
|
+
return Napi::String::New(aInfo.Env(), "");
|
|
416
|
+
|
|
417
|
+
return Napi::String::New(aInfo.Env(), session);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
Napi::Value iRacingSdkNode::GetTelemetryVar(const Napi::CallbackInfo &aInfo)
|
|
421
|
+
{
|
|
422
|
+
Napi::Env env = aInfo.Env();
|
|
423
|
+
|
|
424
|
+
int varIndex;
|
|
425
|
+
if (aInfo.Length() <= 0)
|
|
426
|
+
{
|
|
427
|
+
varIndex = 0;
|
|
428
|
+
} else if (!aInfo[0].IsNumber())
|
|
429
|
+
{
|
|
430
|
+
if (aInfo[0].IsString())
|
|
431
|
+
{
|
|
432
|
+
const char *name = aInfo[0].As<Napi::String>().Utf8Value().c_str();
|
|
433
|
+
return this->GetTelemetryVar(env, name);
|
|
434
|
+
}
|
|
435
|
+
varIndex = 0;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return this->GetTelemetryVarByIndex(env, varIndex);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
Napi::Value iRacingSdkNode::_napi_getTelemetryData(const Napi::CallbackInfo &aInfo)
|
|
442
|
+
{
|
|
443
|
+
const irsdk_header *header = irsdk_getHeader();
|
|
444
|
+
auto env = aInfo.Env();
|
|
445
|
+
auto telemVars = Napi::Object::New(env);
|
|
446
|
+
|
|
447
|
+
int count = header->numVars;
|
|
448
|
+
for (int i = 0; i < count; i++)
|
|
449
|
+
{
|
|
450
|
+
auto telemVariable = this->GetTelemetryVarByIndex(env, i);
|
|
451
|
+
if (telemVariable.IsObject() && telemVariable.Has("name"))
|
|
452
|
+
{
|
|
453
|
+
telemVars.Set(telemVariable.Get("name"), telemVariable);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return telemVars;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Helpers
|
|
461
|
+
Napi::Value iRacingSdkNode::_napi_getTelemetryTypes(const Napi::CallbackInfo &aInfo)
|
|
462
|
+
{
|
|
463
|
+
auto env = aInfo.Env();
|
|
464
|
+
auto result = Napi::Object::New(env);
|
|
465
|
+
|
|
466
|
+
const int count = irsdk_getHeader()->numVars;
|
|
467
|
+
const irsdk_varHeader *varHeader;
|
|
468
|
+
for (int i = 0; i < count; i++)
|
|
469
|
+
{
|
|
470
|
+
varHeader = irsdk_getVarHeaderEntry(i);
|
|
471
|
+
result.Set(varHeader->name, Napi::Number::New(env, varHeader->type));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// ---------------------------
|
|
478
|
+
// Helper functions
|
|
479
|
+
// ---------------------------
|
|
480
|
+
bool iRacingSdkNode::GetTelemetryBool(int aEntry, int aIndex)
|
|
481
|
+
{
|
|
482
|
+
const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
|
|
483
|
+
return *(reinterpret_cast<bool const *>(_data + headerVar->offset) + aIndex);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
int iRacingSdkNode::GetTelemetryInt(int aEntry, int aIndex)
|
|
487
|
+
{
|
|
488
|
+
// Each int is 4 bytes
|
|
489
|
+
const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
|
|
490
|
+
return *(reinterpret_cast<int const *>(_data + headerVar->offset) + aIndex * 4);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
float iRacingSdkNode::GetTelemetryFloat(int aEntry, int aIndex)
|
|
494
|
+
{
|
|
495
|
+
// Each float is 4 bytes
|
|
496
|
+
const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
|
|
497
|
+
return *(reinterpret_cast<float const *>(_data + headerVar->offset) + aIndex * 4);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
double iRacingSdkNode::GetTelemetryDouble(int aEntry, int aIndex)
|
|
501
|
+
{
|
|
502
|
+
// Each double is 8 bytes
|
|
503
|
+
const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
|
|
504
|
+
return *(reinterpret_cast<double const *>(_data + headerVar->offset) + aIndex * 8);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
Napi::Object iRacingSdkNode::GetTelemetryVarByIndex(const Napi::Env aEnv, int aIndex)
|
|
508
|
+
{
|
|
509
|
+
auto headerVar = irsdk_getVarHeaderEntry(aIndex);
|
|
510
|
+
auto telemVar = Napi::Object::New(aEnv);
|
|
511
|
+
|
|
512
|
+
// Create entry object
|
|
513
|
+
telemVar.Set("countAsTime", headerVar->countAsTime);
|
|
514
|
+
telemVar.Set("length", headerVar->count);
|
|
515
|
+
telemVar.Set("name", headerVar->name);
|
|
516
|
+
telemVar.Set("description", headerVar->desc);
|
|
517
|
+
telemVar.Set("unit", headerVar->unit);
|
|
518
|
+
telemVar.Set("varType", headerVar->type);
|
|
519
|
+
|
|
520
|
+
int dataSize = headerVar->count * irsdk_VarTypeBytes[headerVar->type];
|
|
521
|
+
auto entryVal = Napi::ArrayBuffer::New(aEnv, dataSize);
|
|
522
|
+
memcpy(entryVal.Data(), this->_data + headerVar->offset, dataSize);
|
|
523
|
+
|
|
524
|
+
telemVar.Set("value", entryVal);
|
|
525
|
+
return telemVar;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
Napi::Object iRacingSdkNode::GetTelemetryVar(const Napi::Env aEnv, const char *aVarName)
|
|
529
|
+
{
|
|
530
|
+
int varIndex = irsdk_varNameToIndex(aVarName);
|
|
531
|
+
return this->GetTelemetryVarByIndex(aEnv, varIndex);
|
|
532
|
+
}
|
|
533
|
+
|
package/lib/irsdk_node.h
CHANGED
|
@@ -1,49 +1,106 @@
|
|
|
1
1
|
#ifndef IRSDK_NODE_H
|
|
2
2
|
#define IRSDK_NODE_H
|
|
3
3
|
|
|
4
|
+
#include "./logger.h"
|
|
4
5
|
#include <napi.h>
|
|
5
6
|
|
|
7
|
+
static const int K_DEFAULT_TIMEOUT_MS = 16;
|
|
8
|
+
|
|
6
9
|
class iRacingSdkNode : public Napi::ObjectWrap<iRacingSdkNode>
|
|
7
10
|
{
|
|
8
11
|
public:
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
static Napi::Object Init(Napi::Env aEnv, Napi::Object aExports);
|
|
13
|
+
iRacingSdkNode(const Napi::CallbackInfo &aInfo);
|
|
14
|
+
|
|
15
|
+
// Main API ---------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/// @brief Returns true if the SDK is currently active and connected to a
|
|
18
|
+
/// session, ie, the data buffer is not null and the SDK returns connected.
|
|
19
|
+
/// This means that the user is actively in an iRacing session.
|
|
20
|
+
///
|
|
21
|
+
/// @return If there is an active connection to the SDK.
|
|
22
|
+
bool isConnected() const;
|
|
23
|
+
|
|
24
|
+
/// @brief Triggers closing the SDK memory file, also resetting any cached
|
|
25
|
+
/// internal instance data.
|
|
26
|
+
void shutdown();
|
|
27
|
+
|
|
28
|
+
/// @brief Initializes the SDK, attempting to open the memory file containing
|
|
29
|
+
/// the SDK data. This occurs implicitly during the main data processing loop.
|
|
30
|
+
///
|
|
31
|
+
/// @return True if the SDK memory file was opened successfully.
|
|
32
|
+
bool startup();
|
|
33
|
+
|
|
34
|
+
/// @brief Main SDK data fetching loop tick. Will sleep for the given timeout
|
|
35
|
+
/// if no data is available, then attempt to pull data again.
|
|
36
|
+
///
|
|
37
|
+
/// @param aTimeoutMs The amount of time to wait, in MS.
|
|
38
|
+
/// @return True if data is ready and available, false if not.
|
|
39
|
+
bool waitForData(int aTimeoutMs = K_DEFAULT_TIMEOUT_MS);
|
|
40
|
+
|
|
41
|
+
/// @brief If connected, will return the entire session session string.
|
|
42
|
+
/// @return The YAML session string, in full.
|
|
43
|
+
const char *getSessionStr();
|
|
44
|
+
|
|
45
|
+
// Helper utils -----------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
/// @brief Gets the current session info version number directly from the SDK.
|
|
48
|
+
/// This value increments every time the session info string changes.
|
|
49
|
+
///
|
|
50
|
+
/// (see irsdk_getSessionInfoStrUpdate() in irsdk_defines.h)
|
|
51
|
+
///
|
|
52
|
+
/// @return The current session info version.
|
|
53
|
+
inline int getSessionInfoStrCount();
|
|
54
|
+
|
|
55
|
+
/// @brief Checks the current SDK session info string version vs. this
|
|
56
|
+
/// class instances session info string version.
|
|
57
|
+
///
|
|
58
|
+
/// @return True if the session info string versions do not match.
|
|
59
|
+
inline bool wasSessionStrUpdated();
|
|
11
60
|
|
|
12
61
|
private:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
62
|
+
// Properties
|
|
63
|
+
Napi::Value _napi_prop_getCurrSessionDataVer(const Napi::CallbackInfo &aInfo);
|
|
64
|
+
/** @deprecated in favor of iRacingSdkNode::_napi_prop_getLogLevel */
|
|
65
|
+
Napi::Value _napi_prop_getEnableLogging(const Napi::CallbackInfo &aInfo);
|
|
66
|
+
/** @deprecated in favor of iRacingSdkNode::_napi_prop_setLogLevel */
|
|
67
|
+
void _napi_prop_setEnableLogging(const Napi::CallbackInfo &aInfo, const Napi::Value &aValue);
|
|
68
|
+
Napi::Value _napi_prop_getLogLevel(const Napi::CallbackInfo &aInfo);
|
|
69
|
+
void _napi_prop_setLogLevel(const Napi::CallbackInfo &aInfo, const Napi::Value &aValue);
|
|
70
|
+
Napi::Value _napi_prop_getIsMocked(const Napi::CallbackInfo &aInfo);
|
|
71
|
+
|
|
72
|
+
// Methods
|
|
73
|
+
// Control
|
|
74
|
+
Napi::Value _napi_startSdk(const Napi::CallbackInfo &aInfo);
|
|
75
|
+
Napi::Value _napi_stopSdk(const Napi::CallbackInfo &aInfo);
|
|
76
|
+
Napi::Value _napi_waitForData(const Napi::CallbackInfo &aInfo);
|
|
77
|
+
Napi::Value _napi_broadcastMessage(const Napi::CallbackInfo &aInfo);
|
|
78
|
+
// Getters
|
|
79
|
+
Napi::Value _napi_isRunning(const Napi::CallbackInfo &aInfo);
|
|
80
|
+
Napi::Value _napi_getSessionVersionNum(const Napi::CallbackInfo &aInfo);
|
|
81
|
+
Napi::Value _napi_getSessionConnectionID(const Napi::CallbackInfo &aInfo);
|
|
82
|
+
Napi::Value _napi_getSessionData(const Napi::CallbackInfo &aInfo);
|
|
83
|
+
Napi::Value _napi_getTelemetryData(const Napi::CallbackInfo &aInfo);
|
|
84
|
+
// Helpers
|
|
85
|
+
Napi::Value _napi_getTelemetryTypes(const Napi::CallbackInfo &aInfo);
|
|
86
|
+
Napi::Value GetTelemetryVar(const Napi::CallbackInfo &aInfo);
|
|
87
|
+
|
|
88
|
+
bool GetTelemetryBool(int entry, int index);
|
|
89
|
+
int GetTelemetryInt(int entry, int index);
|
|
90
|
+
float GetTelemetryFloat(int entry, int index);
|
|
91
|
+
double GetTelemetryDouble(int entry, int index);
|
|
92
|
+
Napi::Object GetTelemetryVarByIndex(const Napi::Env env, int index);
|
|
93
|
+
Napi::Object GetTelemetryVar(const Napi::Env env, const char *varName);
|
|
94
|
+
|
|
95
|
+
/// @brief Resets the current session data / session data status count.
|
|
96
|
+
void _resetData();
|
|
97
|
+
|
|
98
|
+
char *_data;
|
|
99
|
+
int _bufLineLen;
|
|
100
|
+
int _sessionStatusID;
|
|
101
|
+
int _lastSessionCt;
|
|
102
|
+
const char *_sessionData;
|
|
103
|
+
irsdk_node::Logger _logger;
|
|
47
104
|
};
|
|
48
105
|
|
|
49
106
|
#endif
|