@garmin/fitsdk 21.168.0 → 21.169.0

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/src/encoder.js CHANGED
@@ -1,323 +1,323 @@
1
- /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
3
- // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
- // may not use this file except in compliance with the Flexible and Interoperable Data
5
- // Transfer (FIT) Protocol License.
6
- /////////////////////////////////////////////////////////////////////////////////////////////
7
- // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.168.0Release
9
- // Tag = production/release/21.168.0-0-gb831b31
10
- /////////////////////////////////////////////////////////////////////////////////////////////
11
-
12
-
13
- import CrcCalculator from "./crc-calculator.js";
14
- import FIT from "./fit.js";
15
- import MesgDefinition from "./mesg-definition.js";
16
- import OutputStream from "./output-stream.js";
17
- import Profile from "./profile.js";
18
- import Utils from "./utils.js";
19
-
20
- const HEADER_WITH_CRC_SIZE = 14;
21
- const HEADER_WITHOUT_CRC_SIZE = 12;
22
-
23
- /**
24
- * A class for encoding FIT files.
25
- * @class
26
- */
27
- class Encoder {
28
- /**
29
- Creates a FIT File Encoder
30
- * @param {Object} [options] - Encoder options (optional)
31
- * @param {Object.<number,{object, object }} [options.fieldDescriptions=null] - (optional, default null) fieldDescriptions
32
- * @constructor
33
- */
34
- constructor({ fieldDescriptions = null, } = {}) {
35
- this.#fieldDescriptions = {};
36
-
37
- for (const [key, {developerDataIdMesg, fieldDescriptionMesg}] of Object.entries(fieldDescriptions ?? {})) {
38
- this.addDeveloperField(key, developerDataIdMesg, fieldDescriptionMesg);
39
- }
40
-
41
- this.#writeEmptyFileHeader();
42
- }
43
-
44
- /**
45
- * Closes the encoder and returns the file data
46
- * @returns {Uint8Array} A Uint8Array containing the file data
47
- */
48
- close() {
49
- this.#updateFileHeader();
50
- this.#writeFileCrc();
51
-
52
- return this.#outputStream.uint8Array;
53
- }
54
-
55
- /**
56
- * Encodes a mesg into the file.
57
- * @param {Object} mesg - The message data
58
- * @param {Number} mesg.mesgNum - The mesg number for this message
59
- * @return {this}
60
- */
61
- writeMesg(mesg) {
62
- return this.onMesg(mesg.mesgNum, mesg);
63
- }
64
-
65
- /**
66
- * Encodes a mesg into the file.
67
- * This method can be used as a Decoder~mesgListener callback.
68
- * @param {Number} mesgNum - The message number for this message
69
- * @param {Object} mesg - The message data
70
- * @return {this}
71
- */
72
- onMesg(mesgNum, mesg) {
73
- try {
74
- const mesgDefinition = this.#createMesgDefinition(mesgNum, mesg);
75
- this.#writeMesgDefinitionIfNotActive(mesgDefinition);
76
-
77
- // Write Message Header
78
- this.#outputStream.writeUInt8(mesgDefinition.localMesgNum);
79
-
80
- // Write Field Values
81
- mesgDefinition.fieldDefinitions.forEach((fieldDefinition) => {
82
- const values = this.#transformValues(mesg[fieldDefinition.name], fieldDefinition);
83
- const baseTypeDef = FIT.BaseTypeDefinitions[fieldDefinition.baseType];
84
-
85
- this.#outputStream.write(values, baseTypeDef.type);
86
- });
87
-
88
- // Write Developer Field Values
89
- mesgDefinition.developerFieldDefinitions.forEach((developerFieldDefinition) => {
90
- const values = this.#transformValues(
91
- mesg.developerFields[developerFieldDefinition.key],
92
- developerFieldDefinition);
93
-
94
- const baseTypeDef = FIT.BaseTypeDefinitions[developerFieldDefinition.baseType];
95
-
96
- this.#outputStream.write(values, baseTypeDef.type);
97
- });
98
- }
99
- catch (error) {
100
- throw new Error(
101
- "Could not write Message", {
102
- cause: {
103
- mesg,
104
- cause: {
105
- message: error.message,
106
- cause: error.cause,
107
- },
108
- },
109
- }
110
- );
111
- }
112
-
113
- return this;
114
- };
115
-
116
- /**
117
- * Adds a Developer Data Field Description and associated Developer Data Id Message to the Endoder
118
- * This provides the Encoder with the context required to write Developer Fields to the output-stream.
119
- * *** This method does not write the messages to the output-stream ***
120
- * This method can be used as a Decoder~fieldDescriptionListener callback.
121
- * @param {Number} key - The message number for this message
122
- * @param {Object} developerDataIdMesg - The Developer Data Id mesg
123
- * @param {Object} fieldDescriptionMesg - The Field Description mesg
124
- * @return {this}
125
- */
126
- addDeveloperField(key, developerDataIdMesg, fieldDescriptionMesg) {
127
- if(developerDataIdMesg.developerDataIndex == null || fieldDescriptionMesg.developerDataIndex == null) {
128
- throw new Error("addDeveloperField() - one or more developerDataIndex values are null.", {
129
- cause: {
130
- key,
131
- developerDataIdMesg,
132
- fieldDescriptionMesg
133
- }
134
- });
135
- }
136
-
137
- if(developerDataIdMesg.developerDataIndex !== fieldDescriptionMesg.developerDataIndex) {
138
- throw new Error("addDeveloperField() - developerDataIndex values do not match.", {
139
- cause: {
140
- key,
141
- developerDataIdMesg,
142
- fieldDescriptionMesg
143
- }
144
- });
145
- }
146
-
147
- this.#fieldDescriptions[key] = {
148
- developerDataIdMesg,
149
- fieldDescriptionMesg
150
- }
151
-
152
- return this;
153
- }
154
-
155
- #writeEmptyFileHeader() {
156
- Array(HEADER_WITH_CRC_SIZE).fill(0).forEach((zero) => {
157
- this.#outputStream.writeUInt8(zero);
158
- });
159
- }
160
-
161
- #updateFileHeader() {
162
- const arrayBuffer = new ArrayBuffer(HEADER_WITH_CRC_SIZE);
163
- const dataView = new DataView(arrayBuffer);
164
-
165
- // Header Size
166
- dataView.setUint8(0, HEADER_WITH_CRC_SIZE);
167
-
168
- // Protocol Version
169
- dataView.setUint8(1, 2);
170
-
171
- // Profile Version
172
- dataView.setUint16(2, Profile.version.major * 1000 + Profile.version.minor, true);
173
-
174
- // Data Size
175
- dataView.setUint32(4, this.#outputStream.length - HEADER_WITH_CRC_SIZE, true);
176
-
177
- // Data Type ".FIT"
178
- dataView.setUint8(8, 0x2E);
179
- dataView.setUint8(9, 0x46);
180
- dataView.setUint8(10, 0x49);
181
- dataView.setUint8(11, 0x54);
182
-
183
- // Header CRC
184
- const crc = CrcCalculator.calculateCRC(new Uint8Array(arrayBuffer), 0, HEADER_WITHOUT_CRC_SIZE);
185
- dataView.setUint16(12, crc, true);
186
-
187
- this.#outputStream.set(new Uint8Array(arrayBuffer));
188
- }
189
-
190
- #writeFileCrc() {
191
- const crc = CrcCalculator.calculateCRC(this.#outputStream.uint8Array, 0, this.#outputStream.length);
192
- this.#outputStream.writeUInt16(crc);
193
- }
194
-
195
- #transformValues(value, fieldDefinition) {
196
- const values = Array.isArray(value) ? value : [value,];
197
-
198
- return values.map((value) => {
199
- return this.#transformValue(value, fieldDefinition);
200
- });
201
- }
202
-
203
- #transformValue(value, fieldDefinition) {
204
- try {
205
- if (FIT.isNotNumberStringDateOrBoolean(value)) {
206
- return FIT.BaseTypeDefinitions[fieldDefinition.baseType].invalid;
207
- }
208
-
209
- // Is this a numeric field?
210
- if (FIT.NumericFieldTypes.includes(fieldDefinition.type)) {
211
- if (!FIT.isNumeric(value)) {
212
- throw new Error();
213
- }
214
-
215
- const scale = fieldDefinition.components.length > 1 ? 1 : fieldDefinition.scale;
216
- const offset = fieldDefinition.components.length > 1 ? 0 : fieldDefinition.offset;
217
-
218
- return (value + offset) * scale;
219
- }
220
-
221
- // Is this a date_time field?
222
- if (fieldDefinition.type === "dateTime") {
223
- if (FIT.isDate(value)) {
224
- return Utils.convertDateToDateTime(value);
225
- }
226
-
227
- if (!FIT.isNumeric(value)) {
228
- throw new Error();
229
- }
230
-
231
- return value;
232
- }
233
-
234
- // Is this a string field
235
- if (fieldDefinition.type === "string") {
236
- if (!FIT.isString(value)) {
237
- throw new Error();
238
- }
239
-
240
- return value;
241
- }
242
-
243
- // Must be a FIT type field
244
- if (FIT.isNumeric(value)) {
245
- return value;
246
- }
247
-
248
- const profileType = Profile.types[fieldDefinition.type];
249
-
250
- const [typeValue,] = Object.entries(profileType).find(([, typeValue,]) => {
251
- return typeValue === value;
252
- });
253
-
254
- return typeValue;
255
- }
256
- catch {
257
- throw new Error(
258
- `Could not convert "${value}" to "${fieldDefinition.type}"`,
259
- { cause: { value, fieldDefinition, }, });
260
- }
261
- }
262
-
263
- /**
264
- * Creates a MesgDefinition from the mesgNum and mesg.
265
- * @param {Number} mesgNum - The mesg number for this message
266
- * @param {Object} [mesg] - The message data
267
- * @return {MesgDefinition}
268
- */
269
- #createMesgDefinition = (mesgNum, mesg) => {
270
- const mesgDefinition = new MesgDefinition(mesgNum, mesg, { fieldDescriptions: this.#fieldDescriptions, });
271
- mesgDefinition.localMesgNum = this.#lookupLocalMesgNum(mesgDefinition);
272
-
273
- return mesgDefinition;
274
- };
275
-
276
- /**
277
- * Searches the #localMesgDefinitions for a matching mesgDefinition
278
- * @param {Object} mesgDefinition - the mesg definition to match
279
- * @return The localMesgNum to be used with mesgDefinition
280
- */
281
- #lookupLocalMesgNum = (mesgDefinition) => {
282
- const localMesgNum = this.#localMesgDefinitions.findIndex((localMesgDefinition) => {
283
- return localMesgDefinition?.equals(mesgDefinition) ?? false;
284
- });
285
-
286
- return (localMesgNum !== -1 ? localMesgNum : this.#nextLocalMesgNum++) & FIT.LOCAL_MESG_NUM_MASK;
287
- };
288
-
289
- /**
290
- * Writes the mesgDefinition to the output stream, if it is not one of the currently active 16
291
- * @param {Object} mesgDefinition - the mesg definition to match
292
- * @return The localMesgNum to be used with mesgDefinition
293
- */
294
- #writeMesgDefinitionIfNotActive = (mesgDefinition) => {
295
- const localMesgNum = mesgDefinition.localMesgNum;
296
-
297
- if (this.#localMesgDefinitions[localMesgNum] == null
298
- || !this.#localMesgDefinitions[localMesgNum].equals(mesgDefinition)) {
299
- this.#writeMesgDefinition(mesgDefinition);
300
- }
301
-
302
- return localMesgNum;
303
- };
304
-
305
- /**
306
- * Writes the mesgDefinition to the output stream
307
- * @param {Object} mesgDefinition - the mesg definition to write
308
- * @return {this}
309
- */
310
- #writeMesgDefinition(mesgDefinition) {
311
- mesgDefinition.write(this.#outputStream);
312
- this.#localMesgDefinitions[mesgDefinition.localMesgNum] = mesgDefinition;
313
-
314
- return this;
315
- }
316
-
317
- #localMesgDefinitions = Array(16).fill(null);
318
- #nextLocalMesgNum = 0;
319
- #outputStream = new OutputStream();
320
- #fieldDescriptions = null;
321
- }
322
-
323
- export default Encoder;
1
+ /////////////////////////////////////////////////////////////////////////////////////////////
2
+ // Copyright 2025 Garmin International, Inc.
3
+ // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
+ // may not use this file except in compliance with the Flexible and Interoperable Data
5
+ // Transfer (FIT) Protocol License.
6
+ /////////////////////////////////////////////////////////////////////////////////////////////
7
+ // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
+ // Profile Version = 21.169.0Release
9
+ // Tag = production/release/21.169.0-0-g7105132
10
+ /////////////////////////////////////////////////////////////////////////////////////////////
11
+
12
+
13
+ import CrcCalculator from "./crc-calculator.js";
14
+ import FIT from "./fit.js";
15
+ import MesgDefinition from "./mesg-definition.js";
16
+ import OutputStream from "./output-stream.js";
17
+ import Profile from "./profile.js";
18
+ import Utils from "./utils.js";
19
+
20
+ const HEADER_WITH_CRC_SIZE = 14;
21
+ const HEADER_WITHOUT_CRC_SIZE = 12;
22
+
23
+ /**
24
+ * A class for encoding FIT files.
25
+ * @class
26
+ */
27
+ class Encoder {
28
+ /**
29
+ Creates a FIT File Encoder
30
+ * @param {Object} [options] - Encoder options (optional)
31
+ * @param {Object.<number,{object, object }} [options.fieldDescriptions=null] - (optional, default null) fieldDescriptions
32
+ * @constructor
33
+ */
34
+ constructor({ fieldDescriptions = null, } = {}) {
35
+ this.#fieldDescriptions = {};
36
+
37
+ for (const [key, {developerDataIdMesg, fieldDescriptionMesg}] of Object.entries(fieldDescriptions ?? {})) {
38
+ this.addDeveloperField(key, developerDataIdMesg, fieldDescriptionMesg);
39
+ }
40
+
41
+ this.#writeEmptyFileHeader();
42
+ }
43
+
44
+ /**
45
+ * Closes the encoder and returns the file data
46
+ * @returns {Uint8Array} A Uint8Array containing the file data
47
+ */
48
+ close() {
49
+ this.#updateFileHeader();
50
+ this.#writeFileCrc();
51
+
52
+ return this.#outputStream.uint8Array;
53
+ }
54
+
55
+ /**
56
+ * Encodes a mesg into the file.
57
+ * @param {Object} mesg - The message data
58
+ * @param {Number} mesg.mesgNum - The mesg number for this message
59
+ * @return {this}
60
+ */
61
+ writeMesg(mesg) {
62
+ return this.onMesg(mesg.mesgNum, mesg);
63
+ }
64
+
65
+ /**
66
+ * Encodes a mesg into the file.
67
+ * This method can be used as a Decoder~mesgListener callback.
68
+ * @param {Number} mesgNum - The message number for this message
69
+ * @param {Object} mesg - The message data
70
+ * @return {this}
71
+ */
72
+ onMesg(mesgNum, mesg) {
73
+ try {
74
+ const mesgDefinition = this.#createMesgDefinition(mesgNum, mesg);
75
+ this.#writeMesgDefinitionIfNotActive(mesgDefinition);
76
+
77
+ // Write Message Header
78
+ this.#outputStream.writeUInt8(mesgDefinition.localMesgNum);
79
+
80
+ // Write Field Values
81
+ mesgDefinition.fieldDefinitions.forEach((fieldDefinition) => {
82
+ const values = this.#transformValues(mesg[fieldDefinition.name], fieldDefinition);
83
+ const baseTypeDef = FIT.BaseTypeDefinitions[fieldDefinition.baseType];
84
+
85
+ this.#outputStream.write(values, baseTypeDef.type);
86
+ });
87
+
88
+ // Write Developer Field Values
89
+ mesgDefinition.developerFieldDefinitions.forEach((developerFieldDefinition) => {
90
+ const values = this.#transformValues(
91
+ mesg.developerFields[developerFieldDefinition.key],
92
+ developerFieldDefinition);
93
+
94
+ const baseTypeDef = FIT.BaseTypeDefinitions[developerFieldDefinition.baseType];
95
+
96
+ this.#outputStream.write(values, baseTypeDef.type);
97
+ });
98
+ }
99
+ catch (error) {
100
+ throw new Error(
101
+ "Could not write Message", {
102
+ cause: {
103
+ mesg,
104
+ cause: {
105
+ message: error.message,
106
+ cause: error.cause,
107
+ },
108
+ },
109
+ }
110
+ );
111
+ }
112
+
113
+ return this;
114
+ };
115
+
116
+ /**
117
+ * Adds a Developer Data Field Description and associated Developer Data Id Message to the Endoder
118
+ * This provides the Encoder with the context required to write Developer Fields to the output-stream.
119
+ * *** This method does not write the messages to the output-stream ***
120
+ * This method can be used as a Decoder~fieldDescriptionListener callback.
121
+ * @param {Number} key - The message number for this message
122
+ * @param {Object} developerDataIdMesg - The Developer Data Id mesg
123
+ * @param {Object} fieldDescriptionMesg - The Field Description mesg
124
+ * @return {this}
125
+ */
126
+ addDeveloperField(key, developerDataIdMesg, fieldDescriptionMesg) {
127
+ if(developerDataIdMesg.developerDataIndex == null || fieldDescriptionMesg.developerDataIndex == null) {
128
+ throw new Error("addDeveloperField() - one or more developerDataIndex values are null.", {
129
+ cause: {
130
+ key,
131
+ developerDataIdMesg,
132
+ fieldDescriptionMesg
133
+ }
134
+ });
135
+ }
136
+
137
+ if(developerDataIdMesg.developerDataIndex !== fieldDescriptionMesg.developerDataIndex) {
138
+ throw new Error("addDeveloperField() - developerDataIndex values do not match.", {
139
+ cause: {
140
+ key,
141
+ developerDataIdMesg,
142
+ fieldDescriptionMesg
143
+ }
144
+ });
145
+ }
146
+
147
+ this.#fieldDescriptions[key] = {
148
+ developerDataIdMesg,
149
+ fieldDescriptionMesg
150
+ }
151
+
152
+ return this;
153
+ }
154
+
155
+ #writeEmptyFileHeader() {
156
+ Array(HEADER_WITH_CRC_SIZE).fill(0).forEach((zero) => {
157
+ this.#outputStream.writeUInt8(zero);
158
+ });
159
+ }
160
+
161
+ #updateFileHeader() {
162
+ const arrayBuffer = new ArrayBuffer(HEADER_WITH_CRC_SIZE);
163
+ const dataView = new DataView(arrayBuffer);
164
+
165
+ // Header Size
166
+ dataView.setUint8(0, HEADER_WITH_CRC_SIZE);
167
+
168
+ // Protocol Version
169
+ dataView.setUint8(1, 2);
170
+
171
+ // Profile Version
172
+ dataView.setUint16(2, Profile.version.major * 1000 + Profile.version.minor, true);
173
+
174
+ // Data Size
175
+ dataView.setUint32(4, this.#outputStream.length - HEADER_WITH_CRC_SIZE, true);
176
+
177
+ // Data Type ".FIT"
178
+ dataView.setUint8(8, 0x2E);
179
+ dataView.setUint8(9, 0x46);
180
+ dataView.setUint8(10, 0x49);
181
+ dataView.setUint8(11, 0x54);
182
+
183
+ // Header CRC
184
+ const crc = CrcCalculator.calculateCRC(new Uint8Array(arrayBuffer), 0, HEADER_WITHOUT_CRC_SIZE);
185
+ dataView.setUint16(12, crc, true);
186
+
187
+ this.#outputStream.set(new Uint8Array(arrayBuffer));
188
+ }
189
+
190
+ #writeFileCrc() {
191
+ const crc = CrcCalculator.calculateCRC(this.#outputStream.uint8Array, 0, this.#outputStream.length);
192
+ this.#outputStream.writeUInt16(crc);
193
+ }
194
+
195
+ #transformValues(value, fieldDefinition) {
196
+ const values = Array.isArray(value) ? value : [value,];
197
+
198
+ return values.map((value) => {
199
+ return this.#transformValue(value, fieldDefinition);
200
+ });
201
+ }
202
+
203
+ #transformValue(value, fieldDefinition) {
204
+ try {
205
+ if (FIT.isNotNumberStringDateOrBoolean(value)) {
206
+ return FIT.BaseTypeDefinitions[fieldDefinition.baseType].invalid;
207
+ }
208
+
209
+ // Is this a numeric field?
210
+ if (FIT.NumericFieldTypes.includes(fieldDefinition.type)) {
211
+ if (!FIT.isNumeric(value)) {
212
+ throw new Error();
213
+ }
214
+
215
+ const scale = fieldDefinition.components.length > 1 ? 1 : fieldDefinition.scale;
216
+ const offset = fieldDefinition.components.length > 1 ? 0 : fieldDefinition.offset;
217
+
218
+ return (value + offset) * scale;
219
+ }
220
+
221
+ // Is this a date_time field?
222
+ if (fieldDefinition.type === "dateTime") {
223
+ if (FIT.isDate(value)) {
224
+ return Utils.convertDateToDateTime(value);
225
+ }
226
+
227
+ if (!FIT.isNumeric(value)) {
228
+ throw new Error();
229
+ }
230
+
231
+ return value;
232
+ }
233
+
234
+ // Is this a string field
235
+ if (fieldDefinition.type === "string") {
236
+ if (!FIT.isString(value)) {
237
+ throw new Error();
238
+ }
239
+
240
+ return value;
241
+ }
242
+
243
+ // Must be a FIT type field
244
+ if (FIT.isNumeric(value)) {
245
+ return value;
246
+ }
247
+
248
+ const profileType = Profile.types[fieldDefinition.type];
249
+
250
+ const [typeValue,] = Object.entries(profileType).find(([, typeValue,]) => {
251
+ return typeValue === value;
252
+ });
253
+
254
+ return typeValue;
255
+ }
256
+ catch {
257
+ throw new Error(
258
+ `Could not convert "${value}" to "${fieldDefinition.type}"`,
259
+ { cause: { value, fieldDefinition, }, });
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Creates a MesgDefinition from the mesgNum and mesg.
265
+ * @param {Number} mesgNum - The mesg number for this message
266
+ * @param {Object} [mesg] - The message data
267
+ * @return {MesgDefinition}
268
+ */
269
+ #createMesgDefinition = (mesgNum, mesg) => {
270
+ const mesgDefinition = new MesgDefinition(mesgNum, mesg, { fieldDescriptions: this.#fieldDescriptions, });
271
+ mesgDefinition.localMesgNum = this.#lookupLocalMesgNum(mesgDefinition);
272
+
273
+ return mesgDefinition;
274
+ };
275
+
276
+ /**
277
+ * Searches the #localMesgDefinitions for a matching mesgDefinition
278
+ * @param {Object} mesgDefinition - the mesg definition to match
279
+ * @return The localMesgNum to be used with mesgDefinition
280
+ */
281
+ #lookupLocalMesgNum = (mesgDefinition) => {
282
+ const localMesgNum = this.#localMesgDefinitions.findIndex((localMesgDefinition) => {
283
+ return localMesgDefinition?.equals(mesgDefinition) ?? false;
284
+ });
285
+
286
+ return (localMesgNum !== -1 ? localMesgNum : this.#nextLocalMesgNum++) & FIT.LOCAL_MESG_NUM_MASK;
287
+ };
288
+
289
+ /**
290
+ * Writes the mesgDefinition to the output stream, if it is not one of the currently active 16
291
+ * @param {Object} mesgDefinition - the mesg definition to match
292
+ * @return The localMesgNum to be used with mesgDefinition
293
+ */
294
+ #writeMesgDefinitionIfNotActive = (mesgDefinition) => {
295
+ const localMesgNum = mesgDefinition.localMesgNum;
296
+
297
+ if (this.#localMesgDefinitions[localMesgNum] == null
298
+ || !this.#localMesgDefinitions[localMesgNum].equals(mesgDefinition)) {
299
+ this.#writeMesgDefinition(mesgDefinition);
300
+ }
301
+
302
+ return localMesgNum;
303
+ };
304
+
305
+ /**
306
+ * Writes the mesgDefinition to the output stream
307
+ * @param {Object} mesgDefinition - the mesg definition to write
308
+ * @return {this}
309
+ */
310
+ #writeMesgDefinition(mesgDefinition) {
311
+ mesgDefinition.write(this.#outputStream);
312
+ this.#localMesgDefinitions[mesgDefinition.localMesgNum] = mesgDefinition;
313
+
314
+ return this;
315
+ }
316
+
317
+ #localMesgDefinitions = Array(16).fill(null);
318
+ #nextLocalMesgNum = 0;
319
+ #outputStream = new OutputStream();
320
+ #fieldDescriptions = null;
321
+ }
322
+
323
+ export default Encoder;