Line data Source code
1 : /*
2 : * Copyright (C) 2015-2016 Intel Corporation. All rights reserved.
3 : *
4 : * This file is free software: you can redistribute it and/or modify it
5 : * under the terms of the GNU General Public License as published by the
6 : * Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This file is distributed in the hope that it will be useful, but
10 : * WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 : * See the GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License along
15 : * with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 : #pragma once
18 :
19 : #include <inttypes.h>
20 :
21 : #include "AP_HAL_Namespace.h"
22 : #include "utility/functor.h"
23 : #include "AP_HAL_Boards.h"
24 :
25 : #if CONFIG_HAL_BOARD != HAL_BOARD_QURT
26 : // we need utility for std::move, but not on QURT due to a include error in hexagon SDK
27 : #include <utility>
28 : #endif
29 :
30 : /*
31 : * This is an interface abstracting I2C and SPI devices
32 : */
33 : class AP_HAL::Device {
34 : public:
35 : enum BusType {
36 : BUS_TYPE_UNKNOWN = 0,
37 : BUS_TYPE_I2C = 1,
38 : BUS_TYPE_SPI = 2,
39 : BUS_TYPE_UAVCAN = 3,
40 : BUS_TYPE_SITL = 4,
41 : BUS_TYPE_MSP = 5,
42 : BUS_TYPE_SERIAL = 6,
43 : BUS_TYPE_WSPI = 7,
44 : };
45 :
46 : enum Speed {
47 : SPEED_HIGH,
48 : SPEED_LOW,
49 : };
50 :
51 : // Used for comms with devices that support wide SPI
52 : // like quad spi
53 : struct CommandHeader {
54 : uint32_t cmd; //Command phase data.
55 : uint32_t cfg; //Transfer configuration field.
56 : uint32_t addr; //Address phase data.
57 : uint32_t alt; // Alternate phase data.
58 : uint32_t dummy; // Number of dummy cycles to be inserted.
59 : };
60 :
61 : FUNCTOR_TYPEDEF(PeriodicCb, void);
62 : typedef void* PeriodicHandle;
63 :
64 : // Register Read Write Callback
65 : // returns: void parameters: register address, register data, register datasize, direction R:false, W:true
66 : FUNCTOR_TYPEDEF(RegisterRWCb, void, uint8_t, uint8_t*, uint32_t, bool);
67 : typedef void* RegisterRWHandle;
68 :
69 : FUNCTOR_TYPEDEF(BankSelectCb, bool, uint8_t);
70 :
71 46288 : Device(enum BusType type)
72 46288 : {
73 46288 : _bus_id.devid_s.bus_type = type;
74 46288 : }
75 :
76 : // return bus type
77 0 : enum BusType bus_type(void) const {
78 0 : return _bus_id.devid_s.bus_type;
79 : }
80 :
81 : // return bus number
82 1 : uint8_t bus_num(void) const {
83 1 : return _bus_id.devid_s.bus;
84 : }
85 :
86 : // return 24 bit bus identifier
87 14 : uint32_t get_bus_id(void) const {
88 14 : return _bus_id.devid;
89 : }
90 :
91 : // return address on bus
92 1 : uint8_t get_bus_address(void) const {
93 1 : return _bus_id.devid_s.address;
94 : }
95 :
96 : // set device type within a device class (eg. AP_COMPASS_TYPE_LSM303D)
97 : void set_device_type(uint8_t devtype);
98 :
99 39874 : virtual ~Device() {
100 39874 : delete[] _checked.regs;
101 39874 : }
102 :
103 : /*
104 : * Change device address. Note that this is the 7 bit address, it
105 : * does not include the bit for read/write. Only works on I2C
106 : */
107 0 : virtual void set_address(uint8_t address) {};
108 :
109 : /*
110 : * Set the speed of future transfers. Depending on the bus the speed may
111 : * be shared for all devices on the same bus.
112 : *
113 : * Return: true if speed was successfully set or platform doesn't implement
114 : * it; false otherwise.
115 : */
116 : virtual bool set_speed(Speed speed) = 0;
117 :
118 : /*
119 : * This does a single bus transaction which sends send_len bytes,
120 : * then receives recv_len bytes back from the slave. Operation is
121 : * half-duplex independent of bus type.
122 : *
123 : * Return: true on a successful transfer, false on failure.
124 : */
125 : virtual bool transfer(const uint8_t *send, uint32_t send_len,
126 : uint8_t *recv, uint32_t recv_len) = 0;
127 :
128 : /*
129 : * Core transfer function. This does a single bus transaction which
130 : * sends len bytes and receives len bytes back from the slave.
131 : * On full-duplex buses (e.g. SPI), the transfer is full-duplex,
132 : * unlike `transfer`.
133 : * DMA-optimized on some implementations
134 : *
135 : * Return: true on a successful transfer, false on failure.
136 : */
137 0 : virtual bool transfer_fullduplex(uint8_t *send_recv, uint32_t len) {
138 0 : return transfer(send_recv, len, send_recv, len);
139 : }
140 :
141 : /*
142 : * Sets the required flags before transaction starts
143 : * this is to be used by Wide SPI communication interfaces like
144 : * Dual/Quad/Octo SPI
145 : */
146 0 : virtual void set_cmd_header(const CommandHeader& cmd_hdr) {}
147 :
148 : /*
149 : * Sets up peripheral for execution in place mode
150 : * Only relevant for Wide SPI setup.
151 : */
152 0 : virtual bool enter_xip_mode(void** map_ptr) { return false; }
153 0 : virtual bool exit_xip_mode() { return false; }
154 :
155 : /**
156 : * Wrapper function over #transfer() to read recv_len registers, starting
157 : * by first_reg, into the array pointed by recv. The read flag passed to
158 : * #set_read_flag(uint8_t) is ORed with first_reg before performing the
159 : * transfer.
160 : *
161 : * Return: true on a successful transfer, false on failure.
162 : */
163 : bool read_registers(uint8_t first_reg, uint8_t *recv, uint32_t recv_len);
164 :
165 : /**
166 : * Wrapper function over #transfer() to write a byte to the register reg.
167 : * The transfer is done by sending reg and val in that order.
168 : *
169 : * Return: true on a successful transfer, false on failure.
170 : */
171 : bool write_register(uint8_t reg, uint8_t val, bool checked=false);
172 :
173 : /*
174 : * Sets a callback to be called when a register is read or written.
175 : */
176 0 : virtual void set_register_rw_callback(RegisterRWCb register_rw_callback) {
177 0 : _register_rw_callback = register_rw_callback;
178 0 : }
179 :
180 : /**
181 : * Wrapper function over #transfer() to call bank selection callback
182 : * and then invoke the transfer call
183 : *
184 : * Return: true on a successful transfer, false on failure.
185 : */
186 : bool transfer_bank(uint8_t bank, const uint8_t *send, uint32_t send_len,
187 : uint8_t *recv, uint32_t recv_len);
188 :
189 : /**
190 : * Wrapper function over #transfer_bank() to read recv_len registers, starting
191 : * by first_reg, into the array pointed by recv. The read flag passed to
192 : * #set_read_flag(uint8_t) is ORed with first_reg before performing the
193 : * transfer.
194 : *
195 : * Return: true on a successful transfer, false on failure.
196 : */
197 : bool read_bank_registers(uint8_t bank, uint8_t first_reg, uint8_t *recv, uint32_t recv_len);
198 :
199 : /**
200 : * Wrapper function over #transfer_bank() to write a byte to the register reg.
201 : * The transfer is done by sending reg and val in that order.
202 : *
203 : * Return: true on a successful transfer, false on failure.
204 : */
205 : bool write_bank_register(uint8_t bank, uint8_t reg, uint8_t val, bool checked=false);
206 :
207 : /**
208 : * set a value for a checked register in a bank
209 : */
210 : void set_checked_register(uint8_t bank, uint8_t reg, uint8_t val);
211 :
212 : /**
213 : * set a value for a checked register
214 : */
215 : void set_checked_register(uint8_t reg, uint8_t val);
216 :
217 : /**
218 : * setup for register value checking. Frequency is how often to check registers. If set to 10 then
219 : * every 10th call to check_next_register will check a register
220 : */
221 : bool setup_checked_registers(uint8_t num_regs, uint8_t frequency=10);
222 :
223 : /**
224 : * check next register value for correctness. Return false if value is incorrect
225 : * or register checking has not been setup
226 : */
227 : bool check_next_register(void);
228 :
229 : // checked registers
230 : struct checkreg {
231 : uint8_t bank;
232 : uint8_t regnum;
233 : uint8_t value;
234 : };
235 :
236 : /**
237 : * check next register value for correctness, with return of
238 : * failure value. Return false if value is incorrect or register
239 : * checking has not been setup
240 : */
241 : bool check_next_register(struct checkreg &fail);
242 :
243 : /**
244 : * Wrapper function over #transfer() to read a sequence of bytes from
245 : * device. No value is written, differently from the #read_registers()
246 : * method and hence doesn't include the read flag set by #set_read_flag()
247 : */
248 76858 : bool read(uint8_t *recv, uint32_t recv_len)
249 : {
250 76858 : return transfer(nullptr, 0, recv, recv_len);
251 : }
252 :
253 : /*
254 : * Get the semaphore for the bus this device is in. This is intended for
255 : * drivers to use during initialization phase only.
256 : */
257 : virtual AP_HAL::Semaphore *get_semaphore() = 0;
258 :
259 : /*
260 : * Register a periodic callback for this bus. All callbacks on the
261 : * same bus are made from the same thread with lock already taken. In
262 : * other words, the callback is not executed on the main thread (or the
263 : * thread which registered the callback), but in a separate per-bus
264 : * thread.
265 : *
266 : * After registering the periodic callback, the other functions should not
267 : * be used anymore from other contexts. If it really needs to be done, the
268 : * lock must be taken.
269 : *
270 : * Return: A handle for this periodic callback. To cancel the callback
271 : * call #unregister_callback() or return false on the callback.
272 : */
273 : virtual PeriodicHandle register_periodic_callback(uint32_t period_usec, PeriodicCb) = 0;
274 :
275 : /*
276 : * Adjust the time for the periodic callback registered with
277 : * #register_periodic_callback. Note that the time will be re-calculated
278 : * from the moment this call is made and expire after @period_usec.
279 : *
280 : * Return: true if periodic callback was successfully adjusted, false otherwise.
281 : */
282 : virtual bool adjust_periodic_callback(PeriodicHandle h, uint32_t period_usec) = 0;
283 :
284 : /*
285 : * Cancel a periodic callback on this bus.
286 : *
287 : * Return: true if callback was successfully unregistered, false
288 : * otherwise.
289 : */
290 0 : virtual bool unregister_callback(PeriodicHandle h) { return false; }
291 :
292 : /*
293 : * Sets a bank_select callback to be used for bank selection during register check
294 : */
295 0 : virtual void setup_bankselect_callback(BankSelectCb bank_select) {
296 0 : _bank_select = bank_select;
297 0 : }
298 :
299 : /*
300 : * Sets a bank_select callback to be used for bank selection during register check
301 : */
302 0 : virtual void deregister_bankselect_callback() {
303 0 : _bank_select = nullptr;
304 0 : }
305 :
306 :
307 : /*
308 : allows to set callback that will be called after DMA transfer complete.
309 : if this callback is set then any read/write operation will return directly after transfer setup and
310 : bus semaphore must not be released until register_completion_callback(0) called from callback itself
311 : */
312 0 : virtual void register_completion_callback(AP_HAL::MemberProc proc) {}
313 0 : virtual void register_completion_callback(AP_HAL::Proc proc) {}
314 :
315 : /*
316 : * support for direct control of SPI chip select. Needed for
317 : * devices with unusual SPI transfer patterns that include
318 : * specific delays
319 : */
320 147198 : virtual bool set_chip_select(bool set) { return false; }
321 :
322 : /**
323 : * Some devices connected on the I2C or SPI bus require a bit to be set on
324 : * the register address in order to perform a read operation. This sets a
325 : * flag to be used by #read_registers(). The flag's default value is zero.
326 : */
327 : void set_read_flag(uint8_t flag);
328 :
329 : /**
330 : * make a bus id given bus type, bus number, bus address and
331 : * device type This is for use by devices that do not use one of
332 : * the standard HAL Device types, such as UAVCAN devices
333 : */
334 : static uint32_t make_bus_id(enum BusType bus_type, uint8_t bus, uint8_t address, uint8_t devtype);
335 :
336 : /**
337 : * return a new bus ID for the same bus connection but a new device type.
338 : * This is used for auxiliary bus connections
339 : */
340 : static uint32_t change_bus_id(uint32_t old_id, uint8_t devtype);
341 :
342 : /**
343 : * return bus ID with a new devtype
344 : */
345 : uint32_t get_bus_id_devtype(uint8_t devtype) const;
346 :
347 : /**
348 : * get bus type
349 : */
350 : static enum BusType devid_get_bus_type(uint32_t dev_id);
351 :
352 : static uint8_t devid_get_bus(uint32_t dev_id);
353 :
354 : static uint8_t devid_get_address(uint32_t dev_id);
355 :
356 : static uint8_t devid_get_devtype(uint32_t dev_id);
357 :
358 :
359 : /* set number of retries on transfers */
360 0 : virtual void set_retries(uint8_t retries) {};
361 :
362 : protected:
363 : uint8_t _read_flag = 0;
364 :
365 : /*
366 : broken out device elements. The bitfields are used to keep
367 : the overall value small enough to fit in a float accurately,
368 : which makes it possible to transport over the MAVLink
369 : parameter protocol without loss of information.
370 : */
371 : struct DeviceStructure {
372 : enum BusType bus_type : 3;
373 : uint8_t bus: 5; // which instance of the bus type
374 : uint8_t address; // address on the bus (eg. I2C address)
375 : uint8_t devtype; // device class specific device type
376 : };
377 :
378 : union DeviceId {
379 : struct DeviceStructure devid_s;
380 : uint32_t devid;
381 : };
382 :
383 : union DeviceId _bus_id;
384 :
385 : // set device address (eg. i2c bus address or spi CS)
386 46288 : void set_device_address(uint8_t address) {
387 46288 : _bus_id.devid_s.address = address;
388 46288 : }
389 :
390 : // set device bus number
391 46288 : void set_device_bus(uint8_t bus) {
392 46288 : _bus_id.devid_s.bus = bus;
393 46288 : }
394 :
395 : private:
396 : BankSelectCb _bank_select;
397 : RegisterRWCb _register_rw_callback;
398 : struct {
399 : uint8_t n_allocated;
400 : uint8_t n_set;
401 : uint8_t next;
402 : uint8_t frequency;
403 : uint8_t counter;
404 : struct checkreg last_reg_fail;
405 : struct checkreg *regs;
406 : } _checked;
407 : };
|