@wodzik/cubecore 0.1.12 → 0.1.13

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.
@@ -9,9 +9,21 @@
9
9
  */
10
10
  export declare class ClockSync {
11
11
  private readonly window;
12
+ private readonly jump;
12
13
  private samples;
13
- /** @param window how many recent samples the offset is estimated from (the cube clock drifts slowly). */
14
- constructor(window?: number);
14
+ /**
15
+ * @param window how many recent samples the offset is estimated from (the cube clock drifts slowly).
16
+ * @param jump a cube clock that lost time (GAN gen2's 16-bit move intervals roll over after
17
+ * ~65 s idle): this many samples in a row that agree with each other (within `agree` ms)
18
+ * and are all over `jumpMs` later than the offset — the cube clock jumped, start again
19
+ * from them. A burst of late notifications (a backgrounded tab) doesn't agree: its
20
+ * samples spread over the moves' real intervals.
21
+ */
22
+ constructor(window?: number, jump?: {
23
+ samples: number;
24
+ jumpMs: number;
25
+ agree: number;
26
+ });
15
27
  /** Offset (local − cube) estimated so far, or null before the first sample. */
16
28
  get offset(): number | null;
17
29
  /** Feed one event: its cube time and, if it has one, the local time it arrived. */
@@ -9,10 +9,19 @@
9
9
  */
10
10
  export class ClockSync {
11
11
  window;
12
+ jump;
12
13
  samples = [];
13
- /** @param window how many recent samples the offset is estimated from (the cube clock drifts slowly). */
14
- constructor(window = 64) {
14
+ /**
15
+ * @param window how many recent samples the offset is estimated from (the cube clock drifts slowly).
16
+ * @param jump a cube clock that lost time (GAN gen2's 16-bit move intervals roll over after
17
+ * ~65 s idle): this many samples in a row that agree with each other (within `agree` ms)
18
+ * and are all over `jumpMs` later than the offset — the cube clock jumped, start again
19
+ * from them. A burst of late notifications (a backgrounded tab) doesn't agree: its
20
+ * samples spread over the moves' real intervals.
21
+ */
22
+ constructor(window = 64, jump = { samples: 5, jumpMs: 1000, agree: 200 }) {
15
23
  this.window = window;
24
+ this.jump = jump;
16
25
  }
17
26
  /** Offset (local − cube) estimated so far, or null before the first sample. */
18
27
  get offset() {
@@ -25,6 +34,14 @@ export class ClockSync {
25
34
  this.samples.push(localTime - cubeTime);
26
35
  if (this.samples.length > this.window)
27
36
  this.samples.shift();
37
+ const { samples: n, jumpMs, agree } = this.jump;
38
+ if (this.samples.length <= n)
39
+ return;
40
+ const recent = this.samples.slice(-n);
41
+ const best = Math.min(...this.samples.slice(0, -n));
42
+ const lo = Math.min(...recent);
43
+ if (lo - best > jumpMs && Math.max(...recent) - lo <= agree)
44
+ this.samples = recent;
28
45
  }
29
46
  /** The cube time on the page's clock (null until an offset is known). */
30
47
  toLocal(cubeTime) {
@@ -202,6 +202,7 @@ declare class GanCubeClassicConnection implements GanCubeConnection, GanCubeRawC
202
202
  declare class GanGen2ProtocolDriver implements GanProtocolDriver {
203
203
  private lastSerial;
204
204
  private lastMoveTimestamp;
205
+ private hadMove;
205
206
  private cubeTimestamp;
206
207
  createCommandMessage(command: GanCubeCommand): Uint8Array | undefined;
207
208
  handleStateEvent(conn: GanCubeRawConnection, eventMessage: Uint8Array): Promise<GanCubeEvent[]>;
@@ -124,6 +124,7 @@ class GanProtocolMessageView {
124
124
  class GanGen2ProtocolDriver {
125
125
  lastSerial = -1;
126
126
  lastMoveTimestamp = 0;
127
+ hadMove = false;
127
128
  cubeTimestamp = 0;
128
129
  createCommandMessage(command) {
129
130
  var msg = new Uint8Array(20).fill(0);
@@ -190,6 +191,14 @@ class GanGen2ProtocolDriver {
190
191
  if (elapsed == 0) { // In case of 16-bit cube timestamp register overflow
191
192
  elapsed = timestamp - this.lastMoveTimestamp;
192
193
  }
194
+ // After more than the 16-bit register holds (~65 s idle), the interval
195
+ // before the first of these moves rolls over: the local one is right.
196
+ // (cubecore: GAN i3 times ran a minute or more off after the cube lay idle)
197
+ if (i == diff - 1 && this.hadMove) {
198
+ const local = timestamp - this.lastMoveTimestamp;
199
+ if (local > 0xFFFF && elapsed < local)
200
+ elapsed = local;
201
+ }
193
202
  this.cubeTimestamp += elapsed;
194
203
  cubeEvents.push({
195
204
  type: "MOVE",
@@ -203,6 +212,7 @@ class GanGen2ProtocolDriver {
203
212
  });
204
213
  }
205
214
  this.lastMoveTimestamp = timestamp;
215
+ this.hadMove = true;
206
216
  }
207
217
  }
208
218
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.12",
6
+ "version": "0.1.13",
7
7
  "description": "A 3×3×3 cube library for the web, built around smart (Bluetooth) cubes: state, notation, methods, solvers and scrambles, a three.js renderer with skins, pictures, web components, React bindings.",
8
8
  "license": "MPL-2.0",
9
9
  "author": "Tomasz Wodzikowski <wodziszczakow@gmail.com>",