summaryrefslogtreecommitdiff
path: root/zephyr/include/emul/emul_bmi.h
blob: 9eac9c3f85c96bd9f4d7e53a2c70a5f921dfaf7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
/* Copyright 2021 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @file
 *
 * @brief Backend API for BMI emulator
 */

#ifndef __EMUL_BMI_H
#define __EMUL_BMI_H

#include <emul.h>
#include <drivers/i2c.h>
#include <drivers/i2c_emul.h>

/**
 * @brief BMI emulator backend API
 * @defgroup bmi_emul BMI emulator
 * @{
 *
 * BMI emulator supports responses to all write and read I2C messages.
 * Accelerometer and gyroscope registers are obtained from internal emulator
 * state, range register and offset. FIFO is fully simulated. Emulator can be
 * extended to support more models of BMI.
 * Application may alter emulator state:
 *
 * - define a Device Tree overlay file to set which inadvisable driver behaviour
 *   should be treated as errors and which model is emulated
 * - call @ref bmi_emul_set_reg and @ref bmi_emul_get_reg to set and get value
 *   of BMI registers
 * - call @ref bmi_emul_set_off and @ref bmi_emul_get_off to set and get
 *   internal offset value
 * - call @ref bmi_emul_set_value and @ref bmi_emul_get_value to set and get
 *   accelerometer or gyroscope value
 * - call bmi_emul_set_err_* to change emulator behaviour on inadvisable driver
 *   behaviour
 * - call @ref bmi_emul_simulate_cmd_exec_time to enable or disable simulation
 *   of command execution time
 * - call @ref bmi_emul_append_frame to add frame to FIFO
 * - call @reg bmi_emul_set_skipped_frames to generate skip frame on next access
 *   to FIFO
 * - call functions from emul_common_i2c.h to setup custom handlers for I2C
 *   messages
 */

/**
 * Axis argument used in @ref bmi_emul_set_value @ref bmi_emul_get_value
 * @ref bmi_emul_set_off and @ref bmi_emul_get_off
 */
enum bmi_emul_axis {
	BMI_EMUL_ACC_X,
	BMI_EMUL_ACC_Y,
	BMI_EMUL_ACC_Z,
	BMI_EMUL_GYR_X,
	BMI_EMUL_GYR_Y,
	BMI_EMUL_GYR_Z,
};

/** BMI emulator models */
#define BMI_EMUL_160		1
#define BMI_EMUL_260		2

/** Last register supported by emulator */
#define BMI_EMUL_MAX_REG	0x80
/** Maximum number of registers that can be backed in NVM */
#define BMI_EMUL_MAX_NVM_REGS	10

/** Headers used in FIFO frames */
#define BMI_EMUL_FIFO_HEAD_SKIP			0x40
#define BMI_EMUL_FIFO_HEAD_TIME			0x44
#define BMI_EMUL_FIFO_HEAD_CONFIG		0x48
#define BMI_EMUL_FIFO_HEAD_EMPTY		0x80
#define BMI_EMUL_FIFO_HEAD_DATA			0x80
#define BMI_EMUL_FIFO_HEAD_DATA_MAG		BIT(4)
#define BMI_EMUL_FIFO_HEAD_DATA_GYR		BIT(3)
#define BMI_EMUL_FIFO_HEAD_DATA_ACC		BIT(2)
#define BMI_EMUL_FIFO_HEAD_DATA_TAG_MASK	0x03

/**
 * Acceleration 1g in internal emulator units. It is helpful for using
 * functions @ref bmi_emul_set_value @ref bmi_emul_get_value
 * @ref bmi_emul_set_off and @ref bmi_emul_get_off
 */
#define BMI_EMUL_1G		BIT(14)
/**
 * Gyroscope 125°/s in internal emulator units. It is helpful for using
 * functions @ref bmi_emul_set_value @ref bmi_emul_get_value
 * @ref bmi_emul_set_off and @ref bmi_emul_get_off
 */
#define BMI_EMUL_125_DEG_S	BIT(15)

/** Type of frames that can be added to the emulator frames list */
#define BMI_EMUL_FRAME_CONFIG	BIT(0)
#define BMI_EMUL_FRAME_ACC	BIT(1)
#define BMI_EMUL_FRAME_MAG	BIT(2)
#define BMI_EMUL_FRAME_GYR	BIT(3)

/**
 * Code returned by model specific handle_read and handle_write functions, when
 * RO register is accessed on write or WO register is accessed on read
 */
#define BMI_EMUL_ACCESS_E	1

/** Structure used to describe single FIFO frame */
struct bmi_emul_frame {
	/** Type of frame */
	uint8_t type;
	/** Tag added to data frame */
	uint8_t tag;
	/** Value used in config frame */
	uint8_t config;
	/** Accelerometer sensor values in internal emulator units */
	int32_t acc_x;
	int32_t acc_y;
	int32_t acc_z;
	/** Gyroscope sensor values in internal emulator units */
	int32_t gyr_x;
	int32_t gyr_y;
	int32_t gyr_z;
	/** Magnetometer/other sensor values in internal emulator units */
	int32_t mag_x;
	int32_t mag_y;
	int32_t mag_z;
	int32_t rhall;

	/** Pointer to next frame or NULL */
	struct bmi_emul_frame *next;
};

/** Structure describing specific BMI model */
struct bmi_emul_type_data {
	/** Indicate if time frame should follow config frame */
	bool sensortime_follow_config_frame;

	/**
	 * @brief Compute register address that acctually will be accessed, when
	 *        selected register is @p reg and there was @p byte handled in
	 *        the current I2C message
	 *
	 * @param emul Pointer to BMI emulator
	 * @param reg Selected register
	 * @param byte Number of handled bytes in the current I2C message
	 * @param read If current I2C message is read
	 *
	 * @return Register address that will be accessed
	 */
	int (*access_reg)(struct i2c_emul *emul, int reg, int byte, bool read);

	/**
	 * @brief Model specific write function. It should modify state of
	 *        emulator if required.
	 *
	 * @param regs Pointer to array of emulator's registers
	 * @param emul Pointer to BMI emulator
	 * @param reg Selected register
	 * @param byte Number of handled bytes in this write command
	 * @param val Value that is being written
	 *
	 * @return 0 on success
	 * @return BMI_EMUL_ACCESS_E on RO register access
	 * @return other on error
	 */
	int (*handle_write)(uint8_t *regs, struct i2c_emul *emul, int reg,
			    int byte, uint8_t val);
	/**
	 * @brief Model specific read function. It should modify state of
	 *        emulator if required. @p buf should be set to response value.
	 *
	 * @param regs Pointer to array of emulator's registers
	 * @param emul Pointer to BMI emulator
	 * @param reg Selected register
	 * @param byte Byte which is accessed during block read
	 * @param buf Pointer where read byte should be stored
	 *
	 * @return 0 on success
	 * @return BMI_EMUL_ACCESS_E on WO register access
	 * @return other on error
	 */
	int (*handle_read)(uint8_t *regs, struct i2c_emul *emul, int reg,
			   int byte, char *buf);
	/**
	 * @brief Model specific reset function. It should modify state of
	 *        emulator to imitate after reset conditions.
	 *
	 * @param regs Pointer to array of emulator's registers
	 * @param emul Pointer to BMI emulator
	 */
	void (*reset)(uint8_t *regs, struct i2c_emul *emul);

	/** Array of reserved bits mask for each register */
	const uint8_t *rsvd_mask;

	/** Array of registers that are backed in NVM */
	const int *nvm_reg;
	/** Number of registers backed in NVM */
	int nvm_len;

	/** Gyroscope X axis register */
	int gyr_off_reg;
	/** Accelerometer X axis register */
	int acc_off_reg;
	/** Gyroscope 9 and 8 bits register */
	int gyr98_off_reg;
};

/**
 * @brief Get BMI160 model specific structure.
 *
 * @return Pointer to BMI160 specific structure
 */
const struct bmi_emul_type_data *get_bmi160_emul_type_data(void);
/**
 * @brief Get BMI260 model specific structure.
 *
 * @return Pointer to BMI260 specific structure
 */
const struct bmi_emul_type_data *get_bmi260_emul_type_data(void);

/**
 * @brief Get pointer to BMI emulator using device tree order number.
 *
 * @param ord Device tree order number obtained from DT_DEP_ORD macro
 *
 * @return Pointer to BMI emulator
 */
struct i2c_emul *bmi_emul_get(int ord);

/**
 * @brief Set value of given register of BMI
 *
 * @param emul Pointer to BMI emulator
 * @param reg Register address which value will be changed
 * @param val New value of the register
 */
void bmi_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val);

/**
 * @brief Get value of given register of BMI
 *
 * @param emul Pointer to BMI emulator
 * @param reg Register address
 *
 * @return Value of the register
 */
uint8_t bmi_emul_get_reg(struct i2c_emul *emul, int reg);

/**
 * @brief Get internal value of offset for given axis and sensor
 *
 * @param emul Pointer to BMI emulator
 * @param axis Axis to access
 *
 * @return Offset of given axis. LSB for accelerometer is 0.061mg and for
 *         gyroscope is 0.0037°/s.
 */
int16_t bmi_emul_get_off(struct i2c_emul *emul, enum bmi_emul_axis axis);

/**
 * @brief Set internal value of offset for given axis and sensor
 *
 * @param emul Pointer to BMI emulator
 * @param axis Axis to access
 * @param val New value of given axis. LSB for accelerometer is 0.061mg and for
 *            gyroscope is 0.0037°/s.
 */
void bmi_emul_set_off(struct i2c_emul *emul, enum bmi_emul_axis axis,
		      int16_t val);

/**
 * @brief Get internal value of sensor for given axis
 *
 * @param emul Pointer to BMI emulator
 * @param axis Axis to access
 *
 * @return Sensor value of given axis. LSB for accelerometer is 0.061mg and for
 *         gyroscope is 0.0037°/s.
 */
int32_t bmi_emul_get_value(struct i2c_emul *emul, enum bmi_emul_axis axis);

/**
 * @brief Set internal value of sensor for given axis
 *
 * @param emul Pointer to BMI emulator
 * @param axis Axis to access
 * @param val New value of given axis. LSB for accelerometer is 0.061mg and for
 *            gyroscope is 0.0037°/s.
 */
void bmi_emul_set_value(struct i2c_emul *emul, enum bmi_emul_axis axis,
			int32_t val);

/**
 * @brief Set if error should be generated when read only register is being
 *        written
 *
 * @param emul Pointer to BMI emulator
 * @param set Check for this error
 */
void bmi_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set);

/**
 * @brief Set if error should be generated when reserved bits of register are
 *        not set to 0 on write I2C message
 *
 * @param emul Pointer to BMI emulator
 * @param set Check for this error
 */
void bmi_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set);

/**
 * @brief Set if error should be generated when write only register is read
 *
 * @param emul Pointer to BMI emulator
 * @param set Check for this error
 */
void bmi_emul_set_err_on_wo_read(struct i2c_emul *emul, bool set);

/**
 * @brief Set if effect of simulated command should take place after simulated
 *        time pass from issuing command.
 *
 * @param emul Pointer to BMI emulator
 * @param set Simulate command execution time
 */
void bmi_emul_simulate_cmd_exec_time(struct i2c_emul *emul, bool set);

/**
 * @brief Set number of skipped frames. It will generate skip frame on next
 *        access to FIFO. After that number of skipped frames is reset to 0.
 *
 * @param emul Pointer to BMI emulator
 * @param skip Number of skipped frames
 */
void bmi_emul_set_skipped_frames(struct i2c_emul *emul, uint8_t skip);

/**
 * @brief Clear all FIFO frames, set current frame to empty and reset fifo_skip
 *        counter
 *
 * @param emul Pointer to BMI emulator
 * @param tag_time Indicate if sensor time should be included in empty frame
 * @param header Indicate if header should be included in frame
 */
void bmi_emul_flush_fifo(struct i2c_emul *emul, bool tag_time, bool header);

/**
 * @brief Restore registers backed by NVM, reset sensor time and flush FIFO
 *
 * @param emul Pointer to BMI emulator
 */
void bmi_emul_reset_common(struct i2c_emul *emul, bool tag_time, bool header);

/**
 * @brief Set command end time to @p time ms from now
 *
 * @param emul Pointer to BMI emulator
 * @param time After this amount of ms command should end
 */
void bmi_emul_set_cmd_end_time(struct i2c_emul *emul, int time);

/**
 * @brief Check if command should end
 *
 * @param emul Pointer to BMI emulator
 */
bool bmi_emul_is_cmd_end(struct i2c_emul *emul);

/**
 * @brief Append FIFO @p frame to the emulator list of frames. It can be read
 *        using I2C interface.
 *
 * @param emul Pointer to BMI emulator
 * @param frame Pointer to new FIFO frame. Pointed data has to be valid while
 *              emulator may use this frame (until flush of FIFO or reading
 *              it out through I2C)
 */
void bmi_emul_append_frame(struct i2c_emul *emul, struct bmi_emul_frame *frame);

/**
 * @brief Get length of all frames that are on the emulator list of frames.
 *
 * @param emul Pointer to BMI emulator
 * @param tag_time Indicate if sensor time should be included in empty frame
 * @param header Indicate if header should be included in frame
 */
uint16_t bmi_emul_fifo_len(struct i2c_emul *emul, bool tag_time, bool header);

/**
 * @brief Get next byte that should be returned on FIFO data access.
 *
 * @param emul Pointer to BMI emulator
 * @param byte Which byte of block read command is currently handled
 * @param tag_time Indicate if sensor time should be included in empty frame
 * @param header Indicate if header should be included in frame
 * @param acc_shift How many bits should be right shifted from accelerometer
 *                  data
 * @param gyr_shift How many bits should be right shifted from gyroscope data
 *
 * @return FIFO data byte
 */
uint8_t bmi_emul_get_fifo_data(struct i2c_emul *emul, int byte,
			       bool tag_time, bool header, int acc_shift,
			       int gyr_shift);

/**
 * @brief Saves current internal state of sensors to emulator's registers.
 *
 * @param emul Pointer to BMI emulator
 * @param acc_shift How many bits should be right shifted from accelerometer
 *                  data
 * @param gyr_shift How many bits should be right shifted from gyroscope data
 * @param acc_reg Register which holds LSB of accelerometer sensor
 * @param gyr_reg Register which holds LSB of gyroscope sensor
 * @param sensortime_reg Register which holds LSB of sensor time
 * @param acc_off_en Indicate if accelerometer offset should be included to
 *                   sensor data value
 * @param gyr_off_en Indicate if gyroscope offset should be included to
 *                   sensor data value
 */
void bmi_emul_state_to_reg(struct i2c_emul *emul, int acc_shift,
			   int gyr_shift, int acc_reg, int gyr_reg,
			   int sensortime_reg, bool acc_off_en,
			   bool gyr_off_en);

/**
 * @}
 */

#endif /* __EMUL_BMI_H */