capacitor-motioncal 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -1,126 +1,372 @@
1
1
  # Capacitor MotionCal Plugin
2
2
 
3
- A Capacitor plugin for motion/magnetometer calibration using native C libraries.
3
+ A Capacitor plugin for real-time magnetometer calibration using the Freescale/NXP MotionCal algorithm (ported from [PaulStoffregen/MotionCal](https://github.com/PaulStoffregen/MotionCal)). The plugin accepts raw IMU sensor readings and computes hard-iron offset, soft-iron matrix, and geomagnetic field magnitude — the three values needed to correct a magnetometer heading.
4
+
5
+ ## How it works
6
+
7
+ ```
8
+ Ionic app (sensor events)
9
+
10
+ ▼ rawData({ data: [9 int16 counts] }) — every sensor sample
11
+ MotionCal plugin ──► C calibration engine
12
+
13
+ ▼ isSendCalAvailable() — poll until quality is good
14
+
15
+ ▼ sendCalibration() — finalise
16
+
17
+ ▼ getHardIronOffset() / getSoftIronMatrix() — apply to compass readings
18
+ ```
19
+
20
+ The calibration engine accumulates magnetic field samples in a sphere-fitting buffer. Once the sphere is well-covered (quality metrics below threshold), `isSendCalAvailable()` returns `1` and you can call `sendCalibration()` to lock in the result.
21
+
22
+ ---
4
23
 
5
24
  ## Installation
6
25
 
7
- Install directly from GitHub:
26
+ ### From npm (after publish)
27
+
28
+ ```bash
29
+ npm install capacitor-motioncal
30
+ npx cap sync
31
+ ```
32
+
33
+ ### From GitHub
8
34
 
9
35
  ```bash
10
36
  npm install github:denizak/motioncal-capacitor
11
37
  npx cap sync
12
38
  ```
13
39
 
14
- Or clone and install locally:
40
+ ### Local path install (for testing before publish — see [Testing](#testing-locally-before-publishing))
15
41
 
16
42
  ```bash
17
- git clone https://github.com/denizak/motioncal-capacitor.git capacitor-motioncal
18
- npm install ./capacitor-motioncal
43
+ npm install ../path/to/Capacitor-MotionCal
19
44
  npx cap sync
20
45
  ```
21
46
 
22
- ## API
47
+ ---
23
48
 
24
- ### updateBValue(options)
49
+ ## Ionic / Angular Integration
25
50
 
26
- Update the B (magnetic field magnitude) value.
51
+ ### 1. Install and sync
52
+
53
+ ```bash
54
+ npm install capacitor-motioncal
55
+ npx cap sync
56
+ ```
57
+
58
+ ### 2. Create a calibration service
59
+
60
+ Create `src/app/services/motioncal.service.ts`:
27
61
 
28
62
  ```typescript
63
+ import { Injectable } from '@angular/core';
29
64
  import { MotionCalibration } from 'capacitor-motioncal';
30
65
 
31
- await MotionCalibration.updateBValue({ value: 45.0 });
66
+ export interface CalibrationResult {
67
+ hardIronOffset: number[]; // [x, y, z] in µT
68
+ softIronMatrix: number[][]; // 3×3 correction matrix
69
+ fieldMagnitude: number; // geomagnetic field strength in µT
70
+ drawPoints: number[][]; // collected sphere points for visualisation
71
+ }
72
+
73
+ @Injectable({ providedIn: 'root' })
74
+ export class MotionCalService {
75
+
76
+ /** Feed one IMU sample into the calibration engine.
77
+ *
78
+ * All values must be converted to int16 raw counts using:
79
+ * Accelerometer: multiply g × 8192 (G_PER_COUNT = 1/8192)
80
+ * Gyroscope: multiply deg/s × 16 (DEG_PER_SEC_PER_COUNT = 1/16)
81
+ * Magnetometer: multiply µT × 10 (UT_PER_COUNT = 0.1)
82
+ */
83
+ async feedSample(
84
+ ax: number, ay: number, az: number, // accelerometer in g
85
+ gx: number, gy: number, gz: number, // gyroscope in deg/s
86
+ mx: number, my: number, mz: number, // magnetometer in µT
87
+ ): Promise<void> {
88
+ await MotionCalibration.rawData({
89
+ data: [
90
+ Math.round(ax * 8192), Math.round(ay * 8192), Math.round(az * 8192),
91
+ Math.round(gx * 16), Math.round(gy * 16), Math.round(gz * 16),
92
+ Math.round(mx * 10), Math.round(my * 10), Math.round(mz * 10),
93
+ ],
94
+ });
95
+ }
96
+
97
+ /** Returns true when the algorithm has enough data for a good calibration. */
98
+ async isReady(): Promise<boolean> {
99
+ const { available } = await MotionCalibration.isSendCalAvailable();
100
+ return available === 1;
101
+ }
102
+
103
+ /** Returns quality error values — lower is better.
104
+ * isSendCalAvailable() already gates on these, but you can surface them in UI. */
105
+ async getQuality() {
106
+ const [gap, variance, wobble, fit] = await Promise.all([
107
+ MotionCalibration.getQualitySurfaceGapError(),
108
+ MotionCalibration.getQualityMagnitudeVarianceError(),
109
+ MotionCalibration.getQualityWobbleError(),
110
+ MotionCalibration.getQualitySphericalFitError(),
111
+ ]);
112
+ return {
113
+ surfaceGap: gap.error,
114
+ magnitudeVariance: variance.error,
115
+ wobble: wobble.error,
116
+ sphericalFit: fit.error,
117
+ };
118
+ }
119
+
120
+ /** Finalise calibration and return all results. Call only after isReady() === true. */
121
+ async finalise(): Promise<CalibrationResult> {
122
+ await MotionCalibration.sendCalibration();
123
+
124
+ const [offset, matrix, magnitude, points] = await Promise.all([
125
+ MotionCalibration.getHardIronOffset(),
126
+ MotionCalibration.getSoftIronMatrix(),
127
+ MotionCalibration.getGeomagneticFieldMagnitude(),
128
+ MotionCalibration.getDrawPoints(),
129
+ ]);
130
+
131
+ return {
132
+ hardIronOffset: offset.offset,
133
+ softIronMatrix: matrix.matrix,
134
+ fieldMagnitude: magnitude.magnitude,
135
+ drawPoints: points.points,
136
+ };
137
+ }
138
+
139
+ /** Reset the engine to start a new calibration session. */
140
+ async reset(): Promise<void> {
141
+ await MotionCalibration.resetRawData();
142
+ await MotionCalibration.clearDrawPoints();
143
+ }
144
+ }
32
145
  ```
33
146
 
34
- ### getBValue()
147
+ ### 3. Use the service in a component
35
148
 
36
- Get the current B value.
149
+ ```typescript
150
+ import { Component, OnDestroy } from '@angular/core';
151
+ import { MotionCalService, CalibrationResult } from '../services/motioncal.service';
152
+
153
+ // Use @capacitor/motion or the Web DeviceMotion API to obtain sensor events.
154
+ // The plugin also integrates with @awesome-cordova-plugins/device-motion if needed.
155
+
156
+ @Component({
157
+ selector: 'app-calibration',
158
+ template: `
159
+ <ion-content>
160
+ <ion-button (click)="start()" [disabled]="running">Start Calibration</ion-button>
161
+ <ion-button (click)="stop()" [disabled]="!running">Stop</ion-button>
162
+
163
+ <div *ngIf="running">
164
+ <p>Quality — gap: {{ quality?.surfaceGap | number:'1.3-3' }}
165
+ wobble: {{ quality?.wobble | number:'1.3-3' }}</p>
166
+ <p *ngIf="ready">✓ Ready — tap Stop to finalise</p>
167
+ </div>
168
+
169
+ <div *ngIf="result">
170
+ <h3>Calibration Complete</h3>
171
+ <p>Hard iron offset: {{ result.hardIronOffset | json }}</p>
172
+ <p>Field magnitude: {{ result.fieldMagnitude | number:'1.2-2' }} µT</p>
173
+ </div>
174
+ </ion-content>
175
+ `,
176
+ })
177
+ export class CalibrationPage implements OnDestroy {
178
+ running = false;
179
+ ready = false;
180
+ quality: Awaited<ReturnType<MotionCalService['getQuality']>> | null = null;
181
+ result: CalibrationResult | null = null;
182
+
183
+ private intervalId: ReturnType<typeof setInterval> | null = null;
184
+
185
+ constructor(private cal: MotionCalService) {}
186
+
187
+ async start() {
188
+ await this.cal.reset();
189
+ this.running = true;
190
+ this.result = null;
191
+
192
+ // Subscribe to your sensor source here.
193
+ // Example using window.addEventListener for DeviceMotion + DeviceOrientation:
194
+ window.addEventListener('devicemotion', this.onMotion);
195
+ window.addEventListener('deviceorientation', this.onOrientation);
196
+
197
+ // Poll quality every 500 ms for UI feedback.
198
+ this.intervalId = setInterval(async () => {
199
+ this.quality = await this.cal.getQuality();
200
+ this.ready = await this.cal.isReady();
201
+ }, 500);
202
+ }
203
+
204
+ async stop() {
205
+ this.running = false;
206
+ window.removeEventListener('devicemotion', this.onMotion);
207
+ window.removeEventListener('deviceorientation', this.onOrientation);
208
+ if (this.intervalId) clearInterval(this.intervalId);
209
+
210
+ if (this.ready) {
211
+ this.result = await this.cal.finalise();
212
+ }
213
+ }
214
+
215
+ // Replace with actual sensor values from your sensor plugin/service.
216
+ private onMotion = async (e: DeviceMotionEvent) => {
217
+ const a = e.accelerationIncludingGravity;
218
+ const r = e.rotationRate;
219
+ if (!a || !r) return;
220
+ // Magnetometer must come from a separate sensor source (e.g. @capacitor/motion
221
+ // does not expose magnetometer — use a dedicated plugin or native bridge).
222
+ // Here mx/my/mz are placeholders; replace with real values.
223
+ await this.cal.feedSample(
224
+ a.x ?? 0, a.y ?? 0, a.z ?? 0,
225
+ r.alpha ?? 0, r.beta ?? 0, r.gamma ?? 0,
226
+ 0, 0, 0, // ← replace with real magnetometer µT values
227
+ );
228
+ };
229
+
230
+ private onOrientation = (_e: DeviceOrientationEvent) => { /* optional */ };
231
+
232
+ ngOnDestroy() { this.stop(); }
233
+ }
234
+ ```
235
+
236
+ ### 4. Apply calibration to compass readings
37
237
 
38
238
  ```typescript
39
- const result = await MotionCalibration.getBValue();
40
- console.log('B value:', result.value);
239
+ // After calibration is done, correct raw magnetometer readings before computing heading:
240
+ function applyCalibration(
241
+ rawMag: [number, number, number],
242
+ hardIron: number[],
243
+ softIron: number[][],
244
+ ): [number, number, number] {
245
+ // Step 1: subtract hard-iron offset
246
+ const hx = rawMag[0] - hardIron[0];
247
+ const hy = rawMag[1] - hardIron[1];
248
+ const hz = rawMag[2] - hardIron[2];
249
+
250
+ // Step 2: multiply by soft-iron matrix
251
+ return [
252
+ softIron[0][0]*hx + softIron[0][1]*hy + softIron[0][2]*hz,
253
+ softIron[1][0]*hx + softIron[1][1]*hy + softIron[1][2]*hz,
254
+ softIron[2][0]*hx + softIron[2][1]*hy + softIron[2][2]*hz,
255
+ ];
256
+ }
257
+
258
+ function headingDegrees(mx: number, my: number): number {
259
+ return (Math.atan2(my, mx) * 180 / Math.PI + 360) % 360;
260
+ }
41
261
  ```
42
262
 
43
- ### readDataFromFile(options)
263
+ ---
44
264
 
45
- Read calibration data from a file.
265
+ ## Testing Locally Before Publishing
46
266
 
47
- ```typescript
48
- const result = await MotionCalibration.readDataFromFile({ filename: 'magdata.bin' });
49
- console.log('Read result:', result.result);
267
+ ### Step 1 — Build the plugin
268
+
269
+ ```bash
270
+ cd /path/to/Capacitor-MotionCal
271
+ npm run build
50
272
  ```
51
273
 
52
- ### sendCalibration()
274
+ Verify `dist/` was generated with no TypeScript errors.
53
275
 
54
- Send/process the calibration data.
276
+ ### Step 2 — Install into the Ionic app via local path
55
277
 
56
- ```typescript
57
- const result = await MotionCalibration.sendCalibration();
58
- console.log('Calibration result:', result.result);
278
+ In your Ionic app directory:
279
+
280
+ ```bash
281
+ npm install /path/to/Capacitor-MotionCal
282
+ npx cap sync
59
283
  ```
60
284
 
61
- ### Quality Metrics
285
+ This installs the exact local build. You can iterate on the plugin and re-run `npm run build` + `npx cap sync` to pick up changes without publishing.
62
286
 
63
- ```typescript
64
- const gapError = await MotionCalibration.getQualitySurfaceGapError();
65
- const varianceError = await MotionCalibration.getQualityMagnitudeVarianceError();
66
- const wobbleError = await MotionCalibration.getQualityWobbleError();
67
- const fitError = await MotionCalibration.getQualitySphericalFitError();
287
+ ### Step 3 — Verify the iOS build compiles
288
+
289
+ Back in the plugin directory:
290
+
291
+ ```bash
292
+ npm run verify:ios
68
293
  ```
69
294
 
70
- ### Calibration Results
295
+ This runs `pod install` + `xcodebuild` for the iOS target. Fix any Swift/C compile errors before proceeding.
71
296
 
72
- ```typescript
73
- // Get hard iron offset [x, y, z]
74
- const offset = await MotionCalibration.getHardIronOffset();
75
- console.log('Hard iron offset:', offset.offset);
297
+ ### Step 4 — Verify the Android build compiles
298
+
299
+ ```bash
300
+ npm run verify:android
301
+ ```
302
+
303
+ Runs `./gradlew clean build test`. Requires the Android SDK in your `$PATH` / `$ANDROID_HOME`.
304
+
305
+ ### Step 5 — Smoke test on a real device
76
306
 
77
- // Get soft iron matrix (3x3)
78
- const matrix = await MotionCalibration.getSoftIronMatrix();
79
- console.log('Soft iron matrix:', matrix.matrix);
307
+ 1. Open the Ionic app in Xcode (`npx cap open ios`) or Android Studio (`npx cap open android`).
308
+ 2. Run on a physical device (simulators have no magnetometer).
309
+ 3. With the app open, wave/rotate the device in a figure-8 pattern to ensure `rawData` calls are being accepted and `isSendCalAvailable` eventually returns `1`.
310
+ 4. Call `sendCalibration()` and log the results — `hardIronOffset` should be non-zero and `fieldMagnitude` should be in the range 20–80 µT (typical for Earth's field).
80
311
 
81
- // Get geomagnetic field magnitude
82
- const magnitude = await MotionCalibration.getGeomagneticFieldMagnitude();
83
- console.log('Field magnitude:', magnitude.magnitude);
312
+ ### Step 6 Pack and inspect what will be published
313
+
314
+ ```bash
315
+ npm pack --dry-run
84
316
  ```
85
317
 
86
- ### Visualization
318
+ This lists all files that will be included in the npm package. Verify:
319
+ - `dist/` is present
320
+ - `android/src/main/` is present
321
+ - `ios/Sources/` is present
322
+ - `common/` (C source files) is present
323
+ - No test files, node_modules, or local config bleed in
87
324
 
88
- ```typescript
89
- // Get points for 3D visualization
90
- const points = await MotionCalibration.getDrawPoints();
91
- console.log('Draw points:', points.points);
325
+ To create the actual tarball for manual inspection:
92
326
 
93
- // Clear points
94
- await MotionCalibration.clearDrawPoints();
327
+ ```bash
328
+ npm pack
329
+ # creates capacitor-motioncal-x.x.x.tgz
330
+ tar -tzf capacitor-motioncal-*.tgz | sort
95
331
  ```
96
332
 
97
- ### Reset
333
+ ### Step 7 — Publish
98
334
 
99
- ```typescript
100
- await MotionCalibration.resetRawData();
335
+ ```bash
336
+ npm login # one-time
337
+ npm publish
101
338
  ```
102
339
 
340
+ For a scoped package use `npm publish --access public`.
341
+
342
+ ---
343
+
103
344
  ## Full API Reference
104
345
 
105
- | Method | Parameters | Returns |
106
- |--------|------------|---------|
107
- | `updateBValue` | `{ value: number }` | `Promise<void>` |
108
- | `getBValue` | - | `Promise<{ value: number }>` |
109
- | `isSendCalAvailable` | - | `Promise<{ available: number }>` |
110
- | `readDataFromFile` | `{ filename: string }` | `Promise<{ result: number }>` |
111
- | `setResultFilename` | `{ filename: string }` | `Promise<void>` |
112
- | `sendCalibration` | - | `Promise<{ result: number }>` |
113
- | `getQualitySurfaceGapError` | - | `Promise<{ error: number }>` |
114
- | `getQualityMagnitudeVarianceError` | - | `Promise<{ error: number }>` |
115
- | `getQualityWobbleError` | - | `Promise<{ error: number }>` |
116
- | `getQualitySphericalFitError` | - | `Promise<{ error: number }>` |
117
- | `displayCallback` | - | `Promise<void>` |
118
- | `getCalibrationData` | - | `Promise<{ data: string }>` |
119
- | `getDrawPoints` | - | `Promise<{ points: number[][] }>` |
120
- | `resetRawData` | - | `Promise<void>` |
121
- | `getHardIronOffset` | - | `Promise<{ offset: number[] }>` |
122
- | `getSoftIronMatrix` | - | `Promise<{ matrix: number[][] }>` |
123
- | `getGeomagneticFieldMagnitude` | - | `Promise<{ magnitude: number }>` |
124
- | `clearDrawPoints` | - | `Promise<void>` |
346
+ | Method | Parameters | Returns | Notes |
347
+ |--------|------------|---------|-------|
348
+ | `rawData` | `{ data: number[] }` | `Promise<void>` | 9 int16 counts; call every sensor sample |
349
+ | `isSendCalAvailable` | | `Promise<{ available: number }>` | `1` = ready to finalise |
350
+ | `sendCalibration` | | `Promise<{ result: number }>` | Finalises calibration; call after `isSendCalAvailable` |
351
+ | `getHardIronOffset` | | `Promise<{ offset: number[] }>` | [x, y, z] bias in µT |
352
+ | `getSoftIronMatrix` | — | `Promise<{ matrix: number[][] }>` | 3×3 scaling/rotation matrix |
353
+ | `getGeomagneticFieldMagnitude` | | `Promise<{ magnitude: number }>` | Earth field strength in µT |
354
+ | `getCalibrationData` | | `Promise<{ data: string }>` | Raw 68-byte calibration packet as base64 |
355
+ | `getQualitySurfaceGapError` | | `Promise<{ error: number }>` | Lower is better |
356
+ | `getQualityMagnitudeVarianceError` | | `Promise<{ error: number }>` | Lower is better |
357
+ | `getQualityWobbleError` | | `Promise<{ error: number }>` | Lower is better |
358
+ | `getQualitySphericalFitError` | | `Promise<{ error: number }>` | Lower is better |
359
+ | `displayCallback` | | `Promise<void>` | Triggers internal visualisation update |
360
+ | `getDrawPoints` | | `Promise<{ points: number[][] }>` | Sphere surface points for 3D display |
361
+ | `clearDrawPoints` | | `Promise<void>` | Clears the visualisation buffer |
362
+ | `resetRawData` | | `Promise<void>` | Resets entire calibration state |
363
+
364
+ ### int16 conversion factors
365
+
366
+ | Sensor | Unit | Multiply by | Constant |
367
+ |--------|------|-------------|----------|
368
+ | Accelerometer | g | 8192 | `G_PER_COUNT = 1/8192` |
369
+ | Gyroscope | deg/s | 16 | `DEG_PER_SEC_PER_COUNT = 1/16` |
370
+ | Magnetometer | µT | 10 | `UT_PER_COUNT = 0.1` |
125
371
 
126
372
 
@@ -0,0 +1,29 @@
1
+ cmake_minimum_required(VERSION 3.22.1)
2
+ project("motioncalibration" C)
3
+
4
+ # Suppress warnings from upstream C code (Freescale/NXP algorithm, not authored here).
5
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -w")
6
+
7
+ add_library(
8
+ motioncalibration
9
+ SHARED
10
+
11
+ # JNI bridge (Java ↔ C)
12
+ src/main/jni/jni_bridge.c
13
+
14
+ # Algorithm sources (shared with iOS via common/)
15
+ ../common/rawdata.c
16
+ ../common/serialdata.c
17
+ ../common/visualize.c
18
+ ../common/magcal.c
19
+ ../common/mahony.c
20
+ ../common/matrix.c
21
+ ../common/quality.c
22
+ )
23
+
24
+ # Make imuread.h and other common/ headers visible to all C files.
25
+ target_include_directories(motioncalibration PRIVATE ../common)
26
+
27
+ # Android system libraries
28
+ find_library(log-lib log)
29
+ target_link_libraries(motioncalibration ${log-lib} m)
@@ -44,10 +44,10 @@ android {
44
44
  sourceCompatibility JavaVersion.VERSION_17
45
45
  targetCompatibility JavaVersion.VERSION_17
46
46
  }
47
-
48
- sourceSets {
49
- main {
50
- jniLibs.srcDirs = ['src/main/jniLibs']
47
+
48
+ externalNativeBuild {
49
+ cmake {
50
+ path "CMakeLists.txt"
51
51
  }
52
52
  }
53
53
  }
@@ -13,7 +13,7 @@ import org.json.JSONArray;
13
13
  import org.json.JSONException;
14
14
 
15
15
  @CapacitorPlugin(name = "MotionCalibration")
16
- public class MotionCalibrationPlugin extends Plugin {
16
+ public class MotionCalibration extends Plugin {
17
17
 
18
18
  // Load the native library
19
19
  static {
@@ -21,11 +21,8 @@ public class MotionCalibrationPlugin extends Plugin {
21
21
  }
22
22
 
23
23
  // Native method declarations
24
- private native void updateBValueNative(float bValue);
25
- private native float getBValueNative();
26
24
  private native short isSendCalAvailableNative();
27
- private native int readDataFromFileNative(String filename);
28
- private native void setResultFilenameNative(String filename);
25
+ private native void rawDataNative(short[] data);
29
26
  private native int sendCalibrationNative();
30
27
  private native float getQualitySurfaceGapErrorNative();
31
28
  private native float getQualityMagnitudeVarianceErrorNative();
@@ -40,25 +37,6 @@ public class MotionCalibrationPlugin extends Plugin {
40
37
  private native float getGeomagneticFieldMagnitudeNative();
41
38
  private native void clearDrawPointsNative();
42
39
 
43
- @PluginMethod
44
- public void updateBValue(PluginCall call) {
45
- Float value = call.getFloat("value");
46
- if (value == null) {
47
- call.reject("Value is required");
48
- return;
49
- }
50
- updateBValueNative(value);
51
- call.resolve();
52
- }
53
-
54
- @PluginMethod
55
- public void getBValue(PluginCall call) {
56
- float result = getBValueNative();
57
- JSObject ret = new JSObject();
58
- ret.put("value", result);
59
- call.resolve(ret);
60
- }
61
-
62
40
  @PluginMethod
63
41
  public void isSendCalAvailable(PluginCall call) {
64
42
  short isAvailable = isSendCalAvailableNative();
@@ -68,29 +46,22 @@ public class MotionCalibrationPlugin extends Plugin {
68
46
  }
69
47
 
70
48
  @PluginMethod
71
- public void readDataFromFile(PluginCall call) {
72
- String filename = call.getString("filename");
73
- if (filename == null) {
74
- call.reject("Filename is required");
49
+ public void rawData(PluginCall call) {
50
+ JSArray dataArray = call.getArray("data");
51
+ if (dataArray == null || dataArray.length() != 9) {
52
+ call.reject("Expected array of 9 numbers");
75
53
  return;
76
54
  }
77
- String fullPath = getContext().getFilesDir().getAbsolutePath() + "/" + filename;
78
- int result = readDataFromFileNative(fullPath);
79
- JSObject ret = new JSObject();
80
- ret.put("result", result);
81
- call.resolve(ret);
82
- }
83
-
84
- @PluginMethod
85
- public void setResultFilename(PluginCall call) {
86
- String filename = call.getString("filename");
87
- if (filename == null) {
88
- call.reject("Filename is required");
89
- return;
55
+ try {
56
+ short[] data = new short[9];
57
+ for (int i = 0; i < 9; i++) {
58
+ data[i] = (short) dataArray.getInt(i);
59
+ }
60
+ rawDataNative(data);
61
+ call.resolve();
62
+ } catch (Exception e) {
63
+ call.reject("Failed to process raw data: " + e.getMessage());
90
64
  }
91
- String fullPath = getContext().getFilesDir().getAbsolutePath() + "/" + filename;
92
- setResultFilenameNative(fullPath);
93
- call.resolve();
94
65
  }
95
66
 
96
67
  @PluginMethod
@@ -245,4 +216,4 @@ public class MotionCalibrationPlugin extends Plugin {
245
216
  clearDrawPointsNative();
246
217
  call.resolve();
247
218
  }
248
- }
219
+ }