ilabs-flir 2.0.7 → 2.0.8
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.
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// ObjC shim to expose `FLIRManager` from the npm package and forward to `FlirManager` at runtime
|
|
2
|
+
#import <Foundation/Foundation.h>
|
|
3
|
+
#import <UIKit/UIKit.h>
|
|
4
|
+
|
|
5
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
6
|
+
|
|
7
|
+
@interface FLIRManager : NSObject
|
|
8
|
+
|
|
9
|
+
+ (instancetype)shared;
|
|
10
|
+
|
|
11
|
+
- (BOOL)isAvailable;
|
|
12
|
+
- (double)getTemperatureAtPoint:(int)x y:(int)y;
|
|
13
|
+
- (double)getTemperatureAtNormalized:(double)nx y:(double)ny;
|
|
14
|
+
- (int)getBatteryLevel;
|
|
15
|
+
- (BOOL)isBatteryCharging;
|
|
16
|
+
- (void)setPreferSdkRotation:(BOOL)prefer;
|
|
17
|
+
- (BOOL)isPreferSdkRotation;
|
|
18
|
+
- (nullable UIImage *)latestFrameImage;
|
|
19
|
+
- (void)startDiscovery;
|
|
20
|
+
- (void)stopDiscovery;
|
|
21
|
+
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// ObjC shim implementation forwarding to Swift `FlirManager` via runtime selectors
|
|
2
|
+
#import "FLIRManager.h"
|
|
3
|
+
#import <objc/message.h>
|
|
4
|
+
|
|
5
|
+
@implementation FLIRManager
|
|
6
|
+
|
|
7
|
+
+ (instancetype)shared {
|
|
8
|
+
Class cls = NSClassFromString(@"FlirManager");
|
|
9
|
+
if (!cls) return nil;
|
|
10
|
+
SEL sel = sel_registerName("shared");
|
|
11
|
+
if (![cls respondsToSelector:sel]) return nil;
|
|
12
|
+
id (*msgSend0)(id, SEL) = (id (*)(id, SEL))objc_msgSend;
|
|
13
|
+
return msgSend0((id)cls, sel);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (BOOL)isAvailable {
|
|
17
|
+
Class cls = NSClassFromString(@"FlirManager");
|
|
18
|
+
SEL sel = sel_registerName("isSDKAvailable");
|
|
19
|
+
if (!cls || ![cls respondsToSelector:sel]) return NO;
|
|
20
|
+
BOOL (*msgSend0)(id, SEL) = (BOOL (*)(id, SEL))objc_msgSend;
|
|
21
|
+
return msgSend0((id)cls, sel);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
- (double)getTemperatureAtPoint:(int)x y:(int)y {
|
|
25
|
+
id inst = [[self class] shared];
|
|
26
|
+
SEL sel = sel_registerName("getTemperatureAt: y:");
|
|
27
|
+
// Swift method name mangling may differ; fall back to method used by FlirModule
|
|
28
|
+
SEL selAlt = sel_registerName("getTemperatureAtPoint:y:");
|
|
29
|
+
SEL use = NULL;
|
|
30
|
+
if (inst && [inst respondsToSelector:sel]) use = sel;
|
|
31
|
+
if (inst && [inst respondsToSelector:selAlt]) use = selAlt;
|
|
32
|
+
if (!inst || !use) return NAN;
|
|
33
|
+
double (*msgSend2)(id, SEL, int, int) = (double (*)(id, SEL, int, int))objc_msgSend;
|
|
34
|
+
return msgSend2(inst, use, x, y);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (double)getTemperatureAtNormalized:(double)nx y:(double)ny {
|
|
38
|
+
id inst = [[self class] shared];
|
|
39
|
+
SEL sel = sel_registerName("getTemperatureAtNormalized:y:");
|
|
40
|
+
if (!inst || ![inst respondsToSelector:sel]) return NAN;
|
|
41
|
+
double (*msgSend2)(id, SEL, double, double) = (double (*)(id, SEL, double, double))objc_msgSend;
|
|
42
|
+
return msgSend2(inst, sel, nx, ny);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
- (int)getBatteryLevel {
|
|
46
|
+
id inst = [[self class] shared];
|
|
47
|
+
SEL sel = sel_registerName("getBatteryLevel");
|
|
48
|
+
if (!inst || ![inst respondsToSelector:sel]) return -1;
|
|
49
|
+
int (*msgSend0)(id, SEL) = (int (*)(id, SEL))objc_msgSend;
|
|
50
|
+
return msgSend0(inst, sel);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
- (BOOL)isBatteryCharging {
|
|
54
|
+
id inst = [[self class] shared];
|
|
55
|
+
SEL sel = sel_registerName("isBatteryCharging");
|
|
56
|
+
if (!inst || ![inst respondsToSelector:sel]) return NO;
|
|
57
|
+
BOOL (*msgSend0)(id, SEL) = (BOOL (*)(id, SEL))objc_msgSend;
|
|
58
|
+
return msgSend0(inst, sel);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)setPreferSdkRotation:(BOOL)prefer {
|
|
62
|
+
id inst = [[self class] shared];
|
|
63
|
+
SEL sel = sel_registerName("setPreferSdkRotation:");
|
|
64
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
65
|
+
void (*msgSend1)(id, SEL, BOOL) = (void (*)(id, SEL, BOOL))objc_msgSend;
|
|
66
|
+
msgSend1(inst, sel, prefer);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
- (BOOL)isPreferSdkRotation {
|
|
70
|
+
id inst = [[self class] shared];
|
|
71
|
+
SEL sel = sel_registerName("isPreferSdkRotation");
|
|
72
|
+
if (!inst || ![inst respondsToSelector:sel]) return NO;
|
|
73
|
+
BOOL (*msgSend0)(id, SEL) = (BOOL (*)(id, SEL))objc_msgSend;
|
|
74
|
+
return msgSend0(inst, sel);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
- (nullable NSString *)latestFrameBase64 {
|
|
78
|
+
id inst = [[self class] shared];
|
|
79
|
+
SEL sel = sel_registerName("latestFrameBase64");
|
|
80
|
+
if (!inst || ![inst respondsToSelector:sel]) return nil;
|
|
81
|
+
id (*msgSend0)(id, SEL) = (id (*)(id, SEL))objc_msgSend;
|
|
82
|
+
return (NSString *)msgSend0(inst, sel);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (void)retainClient:(NSString *)clientId {
|
|
86
|
+
id inst = [[self class] shared];
|
|
87
|
+
SEL sel = sel_registerName("retainClient:");
|
|
88
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
89
|
+
void (*msgSend1)(id, SEL, id) = (void (*)(id, SEL, id))objc_msgSend;
|
|
90
|
+
msgSend1(inst, sel, clientId);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
- (void)releaseClient:(NSString *)clientId {
|
|
94
|
+
id inst = [[self class] shared];
|
|
95
|
+
SEL sel = sel_registerName("releaseClient:");
|
|
96
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
97
|
+
void (*msgSend1)(id, SEL, id) = (void (*)(id, SEL, id))objc_msgSend;
|
|
98
|
+
msgSend1(inst, sel, clientId);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
- (void)setPalette:(NSString *)paletteName {
|
|
102
|
+
id inst = [[self class] shared];
|
|
103
|
+
SEL sel = sel_registerName("setPalette:");
|
|
104
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
105
|
+
void (*msgSend1)(id, SEL, id) = (void (*)(id, SEL, id))objc_msgSend;
|
|
106
|
+
msgSend1(inst, sel, paletteName);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
- (void)setPaletteFromAcol:(double)acol {
|
|
110
|
+
id inst = [[self class] shared];
|
|
111
|
+
SEL sel = sel_registerName("setPaletteFromAcol:");
|
|
112
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
113
|
+
void (*msgSend1)(id, SEL, double) = (void (*)(id, SEL, double))objc_msgSend;
|
|
114
|
+
msgSend1(inst, sel, acol);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
- (nullable NSString *)getPaletteNameFromAcol:(double)acol {
|
|
118
|
+
Class cls = NSClassFromString(@"FlirManager");
|
|
119
|
+
SEL sel = sel_registerName("getPaletteNameFromAcol:");
|
|
120
|
+
if (!cls || ![cls respondsToSelector:sel]) return nil;
|
|
121
|
+
id (*msgSend1)(id, SEL, double) = (id (*)(id, SEL, double))objc_msgSend;
|
|
122
|
+
return (NSString *)msgSend1((id)cls, sel, acol);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
- (nullable UIImage *)latestFrameImage {
|
|
126
|
+
id inst = [[self class] shared];
|
|
127
|
+
SEL sel = sel_registerName("latestImage");
|
|
128
|
+
SEL selAlt = sel_registerName("latestFrameImage");
|
|
129
|
+
SEL use = NULL;
|
|
130
|
+
if (inst && [inst respondsToSelector:selAlt]) use = selAlt;
|
|
131
|
+
else if (inst && [inst respondsToSelector:sel]) use = sel;
|
|
132
|
+
if (!inst || !use) return nil;
|
|
133
|
+
id (*msgSend0)(id, SEL) = (id (*)(id, SEL))objc_msgSend;
|
|
134
|
+
return (UIImage *)msgSend0(inst, use);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
- (void)startDiscovery {
|
|
138
|
+
id inst = [[self class] shared];
|
|
139
|
+
SEL sel = sel_registerName("startDiscovery");
|
|
140
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
141
|
+
void (*msgSend0)(id, SEL) = (void (*)(id, SEL))objc_msgSend;
|
|
142
|
+
msgSend0(inst, sel);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
- (void)stopDiscovery {
|
|
146
|
+
id inst = [[self class] shared];
|
|
147
|
+
SEL sel = sel_registerName("stopDiscovery");
|
|
148
|
+
if (!inst || ![inst respondsToSelector:sel]) return;
|
|
149
|
+
void (*msgSend0)(id, SEL) = (void (*)(id, SEL))objc_msgSend;
|
|
150
|
+
msgSend0(inst, sel);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
@objc public class FLIRManager: NSObject {
|
|
5
|
+
@objc public static let shared = FLIRManager()
|
|
6
|
+
|
|
7
|
+
@objc public func isAvailable() -> Bool {
|
|
8
|
+
return FlirManager.isSDKAvailable
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@objc public func getTemperatureAtPoint(x: Int, y: Int) -> Double {
|
|
12
|
+
// FlirManager currently doesn't expose a direct getTemperatureAtPoint API.
|
|
13
|
+
// Return NaN for now (consumers should handle NaN) until full parity is implemented.
|
|
14
|
+
return Double.nan
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@objc public func getTemperatureAtNormalized(_ nx: Double, y: Double) -> Double {
|
|
18
|
+
return Double.nan
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@objc public func getBatteryLevel() -> Int {
|
|
22
|
+
return -1
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@objc public func isBatteryCharging() -> Bool {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@objc public func setPreferSdkRotation(_ prefer: Bool) {
|
|
30
|
+
// FlirManager doesn't currently support rotation preference; no-op
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@objc public func isPreferSdkRotation() -> Bool {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@objc public func latestFrameImage() -> UIImage? {
|
|
38
|
+
return FlirManager.shared.latestImage
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@objc public func startDiscovery() {
|
|
42
|
+
FlirManager.shared.startDiscovery()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@objc public func stopDiscovery() {
|
|
46
|
+
FlirManager.shared.stopDiscovery()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -70,6 +70,9 @@ import ThermalSDK
|
|
|
70
70
|
|
|
71
71
|
// Discovered devices
|
|
72
72
|
private var discoveredDevices: [FlirDeviceInfo] = []
|
|
73
|
+
// Client lifecycle for discovery/connection ownership
|
|
74
|
+
private var activeClients: Set<String> = []
|
|
75
|
+
private var shutdownWorkItem: DispatchWorkItem? = nil
|
|
73
76
|
|
|
74
77
|
#if FLIR_ENABLED
|
|
75
78
|
private var discovery: FLIRDiscovery?
|
|
@@ -100,6 +103,164 @@ import ThermalSDK
|
|
|
100
103
|
@objc public func getDiscoveredDevices() -> [FlirDeviceInfo] {
|
|
101
104
|
return discoveredDevices
|
|
102
105
|
}
|
|
106
|
+
|
|
107
|
+
// MARK: - Temperature & Battery Access
|
|
108
|
+
|
|
109
|
+
/// Returns a temperature data dictionary for the given pixel, or nil if unavailable.
|
|
110
|
+
@objc public func getTemperatureData(x: Int = -1, y: Int = -1) -> [String: Any]? {
|
|
111
|
+
#if FLIR_ENABLED
|
|
112
|
+
guard let streamer = streamer else { return nil }
|
|
113
|
+
var result: [String: Any]? = nil
|
|
114
|
+
streamer.withThermalImage { thermalImage in
|
|
115
|
+
// Attempt to extract per-pixel measurements if available
|
|
116
|
+
if let measurements = thermalImage.measurements as? [NSNumber],
|
|
117
|
+
measurements.count > 0,
|
|
118
|
+
let img = streamer.getImage() {
|
|
119
|
+
let width = Int(img.size.width)
|
|
120
|
+
let height = Int(img.size.height)
|
|
121
|
+
if width > 0 && height > 0 && x >= 0 && y >= 0 && x < width && y < height {
|
|
122
|
+
let idx = y * width + x
|
|
123
|
+
if idx < measurements.count {
|
|
124
|
+
let temp = measurements[idx].doubleValue
|
|
125
|
+
result = ["temperature": temp]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Fallback: use lastTemperature if set
|
|
130
|
+
if result == nil && !lastTemperature.isNaN {
|
|
131
|
+
result = ["temperature": lastTemperature]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result
|
|
135
|
+
#else
|
|
136
|
+
return nil
|
|
137
|
+
#endif
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@objc public func getTemperatureAtPoint(_ x: Int, y: Int) -> Double {
|
|
141
|
+
if let data = getTemperatureData(x: x, y: y), let t = data["temperature"] as? Double {
|
|
142
|
+
return t
|
|
143
|
+
}
|
|
144
|
+
return Double.nan
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@objc public func getTemperatureAtNormalized(_ nx: Double, y: Double) -> Double {
|
|
148
|
+
guard let img = latestImage else { return Double.nan }
|
|
149
|
+
let px = Int(nx * Double(img.size.width))
|
|
150
|
+
let py = Int(y * Double(img.size.height))
|
|
151
|
+
return getTemperatureAtPoint(px, y: py)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@objc public func getBatteryLevel() -> Int {
|
|
155
|
+
#if FLIR_ENABLED
|
|
156
|
+
if let cam = camera {
|
|
157
|
+
if let val = cam.value(forKey: "batteryLevel") as? Int { return val }
|
|
158
|
+
if let batt = cam.value(forKey: "battery") as? NSObject,
|
|
159
|
+
let lv = batt.value(forKey: "level") as? Int { return lv }
|
|
160
|
+
}
|
|
161
|
+
#endif
|
|
162
|
+
return -1
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@objc public func isBatteryCharging() -> Bool {
|
|
166
|
+
#if FLIR_ENABLED
|
|
167
|
+
if let cam = camera {
|
|
168
|
+
if let ch = cam.value(forKey: "isCharging") as? Bool { return ch }
|
|
169
|
+
if let batt = cam.value(forKey: "battery") as? NSObject,
|
|
170
|
+
let ch = batt.value(forKey: "charging") as? Bool { return ch }
|
|
171
|
+
}
|
|
172
|
+
#endif
|
|
173
|
+
return false
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@objc public func latestFrameImage() -> UIImage? {
|
|
177
|
+
return latestImage
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@objc public func latestFrameBase64() -> String? {
|
|
181
|
+
guard let img = latestImage else { return nil }
|
|
182
|
+
if let data = img.jpegData(compressionQuality: 0.7) {
|
|
183
|
+
return data.base64EncodedString()
|
|
184
|
+
}
|
|
185
|
+
if let data = img.pngData() {
|
|
186
|
+
return data.base64EncodedString()
|
|
187
|
+
}
|
|
188
|
+
return nil
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Client lifecycle helpers: callers (UI/filters) can retain/release to ensure
|
|
192
|
+
// discovery runs while any client is active.
|
|
193
|
+
@objc public func retainClient(_ clientId: String) {
|
|
194
|
+
DispatchQueue.main.async {
|
|
195
|
+
self.activeClients.insert(clientId)
|
|
196
|
+
self.shutdownWorkItem?.cancel()
|
|
197
|
+
self.shutdownWorkItem = nil
|
|
198
|
+
if self.activeClients.count == 1 {
|
|
199
|
+
self.startDiscovery()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@objc public func releaseClient(_ clientId: String) {
|
|
205
|
+
DispatchQueue.main.async {
|
|
206
|
+
self.activeClients.remove(clientId)
|
|
207
|
+
self.shutdownWorkItem?.cancel()
|
|
208
|
+
let work = DispatchWorkItem { [weak self] in
|
|
209
|
+
guard let self = self else { return }
|
|
210
|
+
if self.activeClients.isEmpty {
|
|
211
|
+
self.stopDiscovery()
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
self.shutdownWorkItem = work
|
|
215
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: work)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// MARK: - Palette Control
|
|
220
|
+
|
|
221
|
+
/// Set palette by name (case-insensitive). If the SDK isn't available or the
|
|
222
|
+
/// palette cannot be found, this is a no-op.
|
|
223
|
+
@objc public func setPalette(_ paletteName: String) {
|
|
224
|
+
#if FLIR_ENABLED
|
|
225
|
+
guard let streamer = streamer, let thermalImage = streamer.getImage() else {
|
|
226
|
+
NSLog("[FlirManager] Cannot set palette - no active streamer")
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if let paletteManager = FLIRPaletteManager.defaultPalettes() {
|
|
231
|
+
for palette in paletteManager {
|
|
232
|
+
if let p = palette as? FLIRPalette, p.name.lowercased() == paletteName.lowercased() {
|
|
233
|
+
thermalImage.palette = p
|
|
234
|
+
NSLog("[FlirManager] ✅ Palette set to: \(paletteName)")
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
NSLog("[FlirManager] Palette not found: \(paletteName)")
|
|
239
|
+
} else {
|
|
240
|
+
NSLog("[FlirManager] SDK not available - cannot set palette")
|
|
241
|
+
}
|
|
242
|
+
#else
|
|
243
|
+
NSLog("[FlirManager] SDK not available - cannot set palette")
|
|
244
|
+
#endif
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/// Map a normalized acol value (0..1) to a palette name.
|
|
248
|
+
@objc public static func getPaletteNameFromAcol(_ acol: Float) -> String {
|
|
249
|
+
if acol < 0.125 { return "WhiteHot" }
|
|
250
|
+
else if acol < 0.25 { return "BlackHot" }
|
|
251
|
+
else if acol < 0.375 { return "Iron" }
|
|
252
|
+
else if acol < 0.5 { return "Rainbow" }
|
|
253
|
+
else if acol < 0.625 { return "Lava" }
|
|
254
|
+
else if acol < 0.75 { return "Arctic" }
|
|
255
|
+
else if acol < 0.875 { return "Coldest" }
|
|
256
|
+
else { return "Hottest" }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@objc public func setPaletteFromAcol(_ acol: Float) {
|
|
260
|
+
let paletteName = FlirManager.getPaletteNameFromAcol(acol)
|
|
261
|
+
NSLog("[FlirManager] Setting palette from acol=\(acol) -> \(paletteName)")
|
|
262
|
+
setPalette(paletteName)
|
|
263
|
+
}
|
|
103
264
|
|
|
104
265
|
// MARK: - SDK Availability
|
|
105
266
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#import "FlirState.h"
|
|
12
12
|
#import <React/RCTLog.h>
|
|
13
13
|
#import <React/RCTBridge.h>
|
|
14
|
+
#import <objc/message.h>
|
|
14
15
|
|
|
15
16
|
#if __has_include(<ThermalSDK/ThermalSDK.h>)
|
|
16
17
|
#define FLIR_SDK_AVAILABLE 1
|
|
@@ -19,8 +20,62 @@
|
|
|
19
20
|
#define FLIR_SDK_AVAILABLE 0
|
|
20
21
|
#endif
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
-
|
|
23
|
+
// Use runtime lookup to avoid a hard link-time dependency on `FLIRManager`.
|
|
24
|
+
// This prevents duplicate-definition and missing-symbol build failures when
|
|
25
|
+
// the Swift `FLIRManager` may or may not be available at build/link time.
|
|
26
|
+
static id flir_manager_shared(void) {
|
|
27
|
+
Class cls = NSClassFromString(@"FLIRManager");
|
|
28
|
+
if (!cls) return nil;
|
|
29
|
+
SEL sel = sel_registerName("shared");
|
|
30
|
+
if (![cls respondsToSelector:sel]) return nil;
|
|
31
|
+
id (*msgSend0)(id, SEL) = (id (*)(id, SEL))objc_msgSend;
|
|
32
|
+
return msgSend0((id)cls, sel);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static double flir_getTemperatureAtPoint(int x, int y) {
|
|
36
|
+
id inst = flir_manager_shared();
|
|
37
|
+
if (!inst) return NAN;
|
|
38
|
+
SEL sel = sel_registerName("getTemperatureAtPoint:y:");
|
|
39
|
+
if (![inst respondsToSelector:sel]) return NAN;
|
|
40
|
+
double (*msgSend2)(id, SEL, int, int) = (double (*)(id, SEL, int, int))objc_msgSend;
|
|
41
|
+
return msgSend2(inst, sel, x, y);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static int flir_getBatteryLevel(void) {
|
|
45
|
+
id inst = flir_manager_shared();
|
|
46
|
+
if (!inst) return -1;
|
|
47
|
+
SEL sel = sel_registerName("getBatteryLevel");
|
|
48
|
+
if (![inst respondsToSelector:sel]) return -1;
|
|
49
|
+
int (*msgSend0)(id, SEL) = (int (*)(id, SEL))objc_msgSend;
|
|
50
|
+
return msgSend0(inst, sel);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static BOOL flir_isBatteryCharging(void) {
|
|
54
|
+
id inst = flir_manager_shared();
|
|
55
|
+
if (!inst) return NO;
|
|
56
|
+
SEL sel = sel_registerName("isBatteryCharging");
|
|
57
|
+
if (![inst respondsToSelector:sel]) return NO;
|
|
58
|
+
BOOL (*msgSend0)(id, SEL) = (BOOL (*)(id, SEL))objc_msgSend;
|
|
59
|
+
return msgSend0(inst, sel);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static void flir_setPreferSdkRotation(BOOL prefer) {
|
|
63
|
+
id inst = flir_manager_shared();
|
|
64
|
+
if (!inst) return;
|
|
65
|
+
SEL sel = sel_registerName("setPreferSdkRotation:");
|
|
66
|
+
if (![inst respondsToSelector:sel]) return;
|
|
67
|
+
void (*msgSend1)(id, SEL, BOOL) = (void (*)(id, SEL, BOOL))objc_msgSend;
|
|
68
|
+
msgSend1(inst, sel, prefer);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static BOOL flir_isPreferSdkRotation(void) {
|
|
72
|
+
id inst = flir_manager_shared();
|
|
73
|
+
if (!inst) return NO;
|
|
74
|
+
SEL sel = sel_registerName("isPreferSdkRotation");
|
|
75
|
+
if (![inst respondsToSelector:sel]) return NO;
|
|
76
|
+
BOOL (*msgSend0)(id, SEL) = (BOOL (*)(id, SEL))objc_msgSend;
|
|
77
|
+
return msgSend0(inst, sel);
|
|
78
|
+
}
|
|
24
79
|
|
|
25
80
|
@interface FlirModule()
|
|
26
81
|
#if FLIR_SDK_AVAILABLE
|
|
@@ -344,8 +399,8 @@ RCT_EXPORT_METHOD(getTemperatureAt:(nonnull NSNumber *)x
|
|
|
344
399
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
345
400
|
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
346
401
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
347
|
-
// Call into native FLIRManager to query temperature at point
|
|
348
|
-
double temp = [
|
|
402
|
+
// Call into native FLIRManager to query temperature at point (runtime lookup)
|
|
403
|
+
double temp = flir_getTemperatureAtPoint([x intValue], [y intValue]);
|
|
349
404
|
if (isnan(temp)) {
|
|
350
405
|
resolve([NSNull null]);
|
|
351
406
|
} else {
|
|
@@ -513,7 +568,7 @@ RCT_EXPORT_METHOD(getBatteryLevel:(RCTPromiseResolveBlock)resolve
|
|
|
513
568
|
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
514
569
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
515
570
|
#if FLIR_SDK_AVAILABLE
|
|
516
|
-
int level =
|
|
571
|
+
int level = flir_getBatteryLevel();
|
|
517
572
|
resolve(@(level));
|
|
518
573
|
#else
|
|
519
574
|
resolve(@(-1));
|
|
@@ -525,7 +580,7 @@ RCT_EXPORT_METHOD(isBatteryCharging:(RCTPromiseResolveBlock)resolve
|
|
|
525
580
|
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
526
581
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
527
582
|
#if FLIR_SDK_AVAILABLE
|
|
528
|
-
BOOL ch =
|
|
583
|
+
BOOL ch = flir_isBatteryCharging();
|
|
529
584
|
resolve(@(ch));
|
|
530
585
|
#else
|
|
531
586
|
resolve(@(NO));
|
|
@@ -537,8 +592,8 @@ RCT_EXPORT_METHOD(setPreferSdkRotation:(BOOL)prefer
|
|
|
537
592
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
538
593
|
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
539
594
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
540
|
-
|
|
541
|
-
|
|
595
|
+
@try {
|
|
596
|
+
flir_setPreferSdkRotation(prefer);
|
|
542
597
|
resolve(@(YES));
|
|
543
598
|
} @catch (NSException *ex) {
|
|
544
599
|
reject(@"ERR_FLIR_SET_ROTATION_PREF", ex.reason, nil);
|
|
@@ -549,7 +604,7 @@ RCT_EXPORT_METHOD(setPreferSdkRotation:(BOOL)prefer
|
|
|
549
604
|
RCT_EXPORT_METHOD(isPreferSdkRotation:(RCTPromiseResolveBlock)resolve
|
|
550
605
|
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
551
606
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
552
|
-
BOOL v =
|
|
607
|
+
BOOL v = flir_isPreferSdkRotation();
|
|
553
608
|
resolve(@(v));
|
|
554
609
|
});
|
|
555
610
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ilabs-flir",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
4
4
|
"description": "FLIR Thermal SDK for React Native - iOS & Android (bundled at compile time via postinstall)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"android/Flir/build.gradle.kts",
|
|
16
16
|
"ios/Flir/src/",
|
|
17
17
|
"ios/Flir/SDKLoader/",
|
|
18
|
-
|
|
19
18
|
"app.plugin.js",
|
|
20
19
|
"Flir.podspec",
|
|
21
20
|
"sdk-manifest.json",
|