px4io.cpp 83.8 KB
Newer Older
1
2
/****************************************************************************
 *
3
 *   Copyright (c) 2012-2014 PX4 Development Team. All rights reserved.
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
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
35
36
 * @file px4io.cpp
 * Driver for the PX4IO board.
37
 *
38
 * PX4IO is connected via I2C or DMA enabled high-speed UART.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 */

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include <time.h>
#include <queue.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
53
#include <stdlib.h>
54
55
#include <unistd.h>
#include <fcntl.h>
56
#include <math.h>
Andrew Tridgell's avatar
Andrew Tridgell committed
57
#include <crc32.h>
58
59
60
61
62
63

#include <arch/board/board.h>

#include <drivers/device/device.h>
#include <drivers/drv_rc_input.h>
#include <drivers/drv_pwm_output.h>
64
#include <drivers/drv_sbus.h>
65
#include <drivers/drv_gpio.h>
66
#include <drivers/drv_hrt.h>
67
#include <drivers/drv_mixer.h>
68

69
#include <systemlib/mixer/mixer.h>
70
#include <systemlib/perf_counter.h>
71
72
#include <systemlib/err.h>
#include <systemlib/systemlib.h>
73
#include <systemlib/scheduling_priorities.h>
74
#include <systemlib/param/param.h>
75
#include <systemlib/circuit_breaker.h>
76
77
78

#include <uORB/topics/actuator_controls.h>
#include <uORB/topics/actuator_outputs.h>
79
80
#include <uORB/topics/actuator_armed.h>
#include <uORB/topics/safety.h>
81
#include <uORB/topics/vehicle_control_mode.h>
82
#include <uORB/topics/vehicle_command.h>
83
#include <uORB/topics/rc_channels.h>
84
#include <uORB/topics/battery_status.h>
85
#include <uORB/topics/servorail_status.h>
86
#include <uORB/topics/parameter_update.h>
87

88
#include <debug.h>
89

90
#include <mavlink/mavlink_log.h>
91
#include <modules/px4iofirmware/protocol.h>
92

93
#include "uploader.h"
94

95
96
#include "modules/dataman/dataman.h"

97
98
extern device::Device *PX4IO_i2c_interface() weak_function;
extern device::Device *PX4IO_serial_interface() weak_function;
99

100
101
#define PX4IO_SET_DEBUG			_IOC(0xff00, 0)
#define PX4IO_INAIR_RESTART_ENABLE	_IOC(0xff00, 1)
102
#define PX4IO_REBOOT_BOOTLOADER		_IOC(0xff00, 2)
Andrew Tridgell's avatar
Andrew Tridgell committed
103
#define PX4IO_CHECK_CRC			_IOC(0xff00, 3)
104

105
106
107
#define UPDATE_INTERVAL_MIN		2			// 2 ms	-> 500 Hz
#define ORB_CHECK_INTERVAL		200000		// 200 ms -> 5 Hz
#define IO_POLL_INTERVAL		20000		// 20 ms -> 50 Hz
108

109
110
111
112
113
/**
 * The PX4IO class.
 *
 * Encapsulates PX4FMU to PX4IO communications modeled as file operations.
 */
114
class PX4IO : public device::CDev
115
116
{
public:
117
118
	/**
	 * Constructor.
Anton Babushkin's avatar
Anton Babushkin committed
119
	 *
120
121
	 * Initialize all class variables.
	 */
122
	PX4IO(device::Device *interface);
Lorenz Meier's avatar
Lorenz Meier committed
123

124
125
	/**
	 * Destructor.
Anton Babushkin's avatar
Anton Babushkin committed
126
	 *
127
128
	 * Wait for worker thread to terminate.
	 */
129
	virtual ~PX4IO();
130

131
132
	/**
	 * Initialize the PX4IO class.
Anton Babushkin's avatar
Anton Babushkin committed
133
	 *
134
	 * Retrieve relevant initial system parameters. Initialize PX4IO registers.
135
	 */
136
137
	virtual int		init();

138
139
140
141
142
143
144
	/**
	 * Initialize the PX4IO class.
	 *
	 * Retrieve relevant initial system parameters. Initialize PX4IO registers.
	 *
	 * @param disable_rc_handling set to true to forbid override / RC handling on IO
	 */
145
	int			init(bool disable_rc_handling);
146

147
148
	/**
	 * Detect if a PX4IO is connected.
Anton Babushkin's avatar
Anton Babushkin committed
149
	 *
150
151
152
153
	 * Only validate if there is a PX4IO to talk to.
	 */
	virtual int		detect();

154
155
	/**
	 * IO Control handler.
Anton Babushkin's avatar
Anton Babushkin committed
156
	 *
157
158
159
160
161
162
	 * Handle all IOCTL calls to the PX4IO file descriptor.
	 *
	 * @param[in] filp file handle (not used). This function is always called directly through object reference
	 * @param[in] cmd the IOCTL command
	 * @param[in] the IOCTL command parameter (optional)
	 */
163
	virtual int		ioctl(file *filp, int cmd, unsigned long arg);
164
165
166

	/**
	 * write handler.
Anton Babushkin's avatar
Anton Babushkin committed
167
	 *
168
169
170
171
172
173
174
	 * Handle writes to the PX4IO file descriptor.
	 *
	 * @param[in] filp file handle (not used). This function is always called directly through object reference
	 * @param[in] buffer pointer to the data buffer to be written
	 * @param[in] len size in bytes to be written
	 * @return number of bytes written
	 */
175
	virtual ssize_t		write(file *filp, const char *buffer, size_t len);
176

177
178
179
	/**
	* Set the update rate for actuator outputs from FMU to IO.
	*
Lorenz Meier's avatar
Lorenz Meier committed
180
	* @param[in] rate		The rate in Hz actuator outpus are sent to IO.
181
	* 			Min 10 Hz, max 400 Hz
182
	*/
183
	int      		set_update_rate(int rate);
184

185
186
187
	/**
	* Set the battery current scaling and bias
	*
188
189
	* @param[in] amp_per_volt
	* @param[in] amp_bias
190
	*/
191
192
193
194
195
	void      		set_battery_current_scaling(float amp_per_volt, float amp_bias);

	/**
	 * Push failsafe values to IO.
	 *
Lorenz Meier's avatar
Lorenz Meier committed
196
197
	 * @param[in] vals	Failsafe control inputs: in us PPM (900 for zero, 1500 for centered, 2100 for full)
	 * @param[in] len	Number of channels, could up to 8
198
199
	 */
	int			set_failsafe_values(const uint16_t *vals, unsigned len);
200

201
202
203
204
205
	/**
	 * Disable RC input handling
	 */
	int			disable_rc_handling();

206
	/**
207
208
209
	 * Print IO status.
	 *
	 * Print all relevant IO status information
210
211
	 *
	 * @param extended_status Shows more verbose information (in particular RC config)
212
	 */
213
	void			print_status(bool extended_status);
214

215
	/**
216
	 * Fetch and print debug console output.
217
	 */
218
	int			print_debug();
219

220
#ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
221
222
223
224
225
	/**
	 * Set the DSM VCC is controlled by relay one flag
	 *
	 * @param[in] enable true=DSM satellite VCC is controlled by relay1, false=DSM satellite VCC not controlled
	 */
Anton Babushkin's avatar
Anton Babushkin committed
226
	inline void		set_dsm_vcc_ctl(bool enable) {
227
228
229
		_dsm_vcc_ctl = enable;
	};

230
231
232
233
234
	/**
	 * Get the DSM VCC is controlled by relay one flag
	 *
	 * @return true=DSM satellite VCC is controlled by relay1, false=DSM satellite VCC not controlled
	 */
Anton Babushkin's avatar
Anton Babushkin committed
235
	inline bool		get_dsm_vcc_ctl() {
236
237
		return _dsm_vcc_ctl;
	};
238
239
240
#endif

	inline uint16_t		system_status() const {return _status;}
241

242
private:
243
	device::Device		*_interface;
244

Lorenz Meier's avatar
Lorenz Meier committed
245
	// XXX
246
247
248
249
250
251
	unsigned		_hardware;		///< Hardware revision
	unsigned		_max_actuators;		///< Maximum # of actuators supported by PX4IO
	unsigned		_max_controls;		///< Maximum # of controls supported by PX4IO
	unsigned		_max_rc_input;		///< Maximum receiver channels supported by PX4IO
	unsigned		_max_relays;		///< Maximum relays supported by PX4IO
	unsigned		_max_transfer;		///< Maximum number of I2C transfers supported by PX4IO
252

253
254
	unsigned 		_update_interval;	///< Subscription interval limiting send rate
	bool			_rc_handling_disabled;	///< If set, IO does not evaluate, but only forward the RC values
Lorenz Meier's avatar
Lorenz Meier committed
255
	unsigned		_rc_chan_count;		///< Internal copy of the last seen number of RC channels
256
	uint64_t		_rc_last_valid;		///< last valid timestamp
257

258
259
	volatile int		_task;			///< worker task id
	volatile bool		_task_should_exit;	///< worker terminate flag
260

261
	int			_mavlink_fd;		///< mavlink file descriptor.
262

263
264
	perf_counter_t		_perf_update;		///<local performance counter for status updates
	perf_counter_t		_perf_write;		///<local performance counter for PWM control writes
Lorenz Meier's avatar
Lorenz Meier committed
265
	perf_counter_t		_perf_chan_count;	///<local performance counter for channel number changes
266
267

	/* cached IO state */
268
269
	uint16_t		_status;		///< Various IO status flags
	uint16_t		_alarms;		///< Various IO alarms
270

271
	/* subscribed topics */
272
273
274
275
	int			_t_actuator_controls_0;	///< actuator controls group 0 topic
	int			_t_actuator_controls_1;	///< actuator controls group 1 topic
	int			_t_actuator_controls_2;	///< actuator controls group 2 topic
	int			_t_actuator_controls_3;	///< actuator controls group 3 topic
276
	int			_t_actuator_armed;	///< system armed control topic
Lorenz Meier's avatar
Lorenz Meier committed
277
278
	int 			_t_vehicle_control_mode;///< vehicle control mode topic
	int			_t_param;		///< parameter update topic
279
	int			_t_vehicle_command;	///< vehicle command topic
280

281
	/* advertised topics */
Lorenz Meier's avatar
Lorenz Meier committed
282
283
284
	orb_advert_t 		_to_input_rc;		///< rc inputs from io
	orb_advert_t		_to_outputs;		///< mixed servo outputs topic
	orb_advert_t		_to_battery;		///< battery status / voltage
285
	orb_advert_t		_to_servorail;		///< servorail status
Lorenz Meier's avatar
Lorenz Meier committed
286
	orb_advert_t		_to_safety;		///< status of safety
287

288
289
	actuator_outputs_s	_outputs;		///< mixed outputs
	servorail_status_s	_servorail_status;	///< servorail status
290

291
	bool			_primary_pwm_device;	///< true if we are the default PWM output
292
	bool			_lockdown_override;	///< allow to override the safety lockdown
293

294
295
296
297
	float			_battery_amp_per_volt;	///< current sensor amps/volt
	float			_battery_amp_bias;	///< current sensor bias
	float			_battery_mamphour_total;///< amp hours consumed so far
	uint64_t		_battery_last_timestamp;///< last amp hour calculation timestamp
298
	bool			_cb_flighttermination;	///< true if the flight termination circuit breaker is enabled
Jean Cyr's avatar
Jean Cyr committed
299

300
#ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
301
	bool			_dsm_vcc_ctl;		///< true if relay 1 controls DSM satellite RX power
302
#endif
Jean Cyr's avatar
Jean Cyr committed
303

304
305
306
	/**
	 * Trampoline to the worker task
	 */
307
	static void		task_main_trampoline(int argc, char *argv[]);
308
309
310
311

	/**
	 * worker task
	 */
312
	void			task_main();
313

314
	/**
315
	 * Send controls for one group to IO
316
	 */
317
318
319
320
321
322
	int			io_set_control_state(unsigned group);

	/**
	 * Send all controls to IO
	 */
	int			io_set_control_groups();
323

324
	/**
325
	 * Update IO's arming-related state
326
	 */
327
	int			io_set_arming_state();
328

329
330
331
332
333
	/**
	 * Push RC channel configuration to IO.
	 */
	int			io_set_rc_config();

px4dev's avatar
px4dev committed
334
335
	/**
	 * Fetch status and alarms from IO
336
337
	 *
	 * Also publishes battery voltage/current.
px4dev's avatar
px4dev committed
338
339
340
	 */
	int			io_get_status();

341
342
343
344
345
	/**
	 * Disable RC input handling
	 */
	int			io_disable_rc_handling();

px4dev's avatar
px4dev committed
346
	/**
347
	 * Fetch RC inputs from IO.
348
349
	 *
	 * @param input_rc	Input structure to populate.
350
351
352
353
354
355
356
357
358
359
360
361
362
	 * @return		OK if data was returned.
	 */
	int			io_get_raw_rc_input(rc_input_values &input_rc);

	/**
	 * Fetch and publish raw RC input data.
	 */
	int			io_publish_raw_rc();

	/**
	 * Fetch and publish the PWM servo outputs.
	 */
	int			io_publish_pwm_outputs();
px4dev's avatar
px4dev committed
363

364
	/**
365
	 * write register(s)
366
367
368
369
370
	 *
	 * @param page		Register page to write to.
	 * @param offset	Register offset to start writing at.
	 * @param values	Pointer to array of values to write.
	 * @param num_values	The number of values to write.
371
	 * @return		OK if all values were successfully written.
372
	 */
373
	int			io_reg_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values);
374

375
376
377
378
379
380
	/**
	 * write a register
	 *
	 * @param page		Register page to write to.
	 * @param offset	Register offset to write to.
	 * @param value		Value to write.
381
	 * @return		OK if the value was written successfully.
382
383
384
	 */
	int			io_reg_set(uint8_t page, uint8_t offset, const uint16_t value);

385
	/**
386
	 * read register(s)
387
388
389
390
391
	 *
	 * @param page		Register page to read from.
	 * @param offset	Register offset to start reading from.
	 * @param values	Pointer to array where values should be stored.
	 * @param num_values	The number of values to read.
392
	 * @return		OK if all values were successfully read.
393
	 */
394
	int			io_reg_get(uint8_t page, uint8_t offset, uint16_t *values, unsigned num_values);
395

396
397
398
399
400
401
402
403
404
405
	/**
	 * read a register
	 *
	 * @param page		Register page to read from.
	 * @param offset	Register offset to start reading from.
	 * @return		Register value that was read, or _io_reg_get_error on error.
	 */
	uint32_t		io_reg_get(uint8_t page, uint8_t offset);
	static const uint32_t	_io_reg_get_error = 0x80000000;

406
	/**
407
408
409
410
411
412
	 * modify a register
	 *
	 * @param page		Register page to modify.
	 * @param offset	Register offset to modify.
	 * @param clearbits	Bits to clear in the register.
	 * @param setbits	Bits to set in the register.
413
	 */
414
	int			io_reg_modify(uint8_t page, uint8_t offset, uint16_t clearbits, uint16_t setbits);
415

416
417
418
	/**
	 * Send mixer definition text to IO
	 */
Anton Babushkin's avatar
Anton Babushkin committed
419
	int			mixer_send(const char *buf, unsigned buflen, unsigned retries = 3);
420

421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
	/**
	 * Handle a status update from IO.
	 *
	 * Publish IO status information if necessary.
	 *
	 * @param status	The status register
	 */
	int			io_handle_status(uint16_t status);

	/**
	 * Handle an alarm update from IO.
	 *
	 * Publish IO alarm information if necessary.
	 *
	 * @param alarm		The status register
	 */
	int			io_handle_alarms(uint16_t alarms);

439
440
441
	/**
	 * Handle issuing dsm bind ioctl to px4io.
	 *
Jean Cyr's avatar
Jean Cyr committed
442
	 * @param dsmMode	0:dsm2, 1:dsmx
443
	 */
Jean Cyr's avatar
Jean Cyr committed
444
	void			dsm_bind_ioctl(int dsmMode);
445

446
447
448
449
450
	/**
	 * Handle a battery update from IO.
	 *
	 * Publish IO battery information if necessary.
	 *
451
452
	 * @param vbatt		vbatt register
	 * @param ibatt		ibatt register
453
454
	 */
	void			io_handle_battery(uint16_t vbatt, uint16_t ibatt);
455

456
457
458
459
460
461
462
463
	/**
	 * Handle a servorail update from IO.
	 *
	 * Publish servo rail information if necessary.
	 *
	 * @param vservo	vservo register
	 * @param vrssi 	vrssi register
	 */
464
	void			io_handle_vservo(uint16_t vservo, uint16_t vrssi);
465

Lorenz Meier's avatar
Lorenz Meier committed
466
467
468
	/* do not allow to copy this class due to ptr data members */
	PX4IO(const PX4IO&);
	PX4IO operator=(const PX4IO&);
469
};
470

px4dev's avatar
px4dev committed
471
namespace
472
473
{

474
PX4IO	*g_dev = nullptr;
475
476
477

}

478
PX4IO::PX4IO(device::Device *interface) :
479
	CDev("px4io", PX4IO_DEVICE_PATH),
480
	_interface(interface),
481
	_hardware(0),
482
	_max_actuators(0),
483
	_max_controls(0),
484
485
486
487
	_max_rc_input(0),
	_max_relays(0),
	_max_transfer(16),	/* sensible default */
	_update_interval(0),
488
	_rc_handling_disabled(false),
Lorenz Meier's avatar
Lorenz Meier committed
489
	_rc_chan_count(0),
490
	_rc_last_valid(0),
491
492
	_task(-1),
	_task_should_exit(false),
493
	_mavlink_fd(-1),
Lorenz Meier's avatar
Lorenz Meier committed
494
495
496
	_perf_update(perf_alloc(PC_ELAPSED, "io update")),
	_perf_write(perf_alloc(PC_ELAPSED, "io write")),
	_perf_chan_count(perf_alloc(PC_COUNT, "io rc #")),
px4dev's avatar
px4dev committed
497
498
	_status(0),
	_alarms(0),
499
500
501
502
	_t_actuator_controls_0(-1),
	_t_actuator_controls_1(-1),
	_t_actuator_controls_2(-1),
	_t_actuator_controls_3(-1),
503
	_t_actuator_armed(-1),
504
	_t_vehicle_control_mode(-1),
px4dev's avatar
px4dev committed
505
	_t_param(-1),
506
	_t_vehicle_command(-1),
507
508
509
	_to_input_rc(0),
	_to_outputs(0),
	_to_battery(0),
510
	_to_servorail(0),
511
	_to_safety(0),
Lorenz Meier's avatar
Lorenz Meier committed
512
513
	_outputs{},
	_servorail_status{},
514
	_primary_pwm_device(false),
515
	_lockdown_override(false),
Anton Babushkin's avatar
Anton Babushkin committed
516
	_battery_amp_per_volt(90.0f / 5.0f), // this matches the 3DR current sensor
517
518
	_battery_amp_bias(0),
	_battery_mamphour_total(0),
519
520
	_battery_last_timestamp(0),
	_cb_flighttermination(true)
521
#ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
Anton Babushkin's avatar
Anton Babushkin committed
522
	, _dsm_vcc_ctl(false)
523
524
#endif

525
{
526
	/* we need this potentially before it could be set in task_main */
527
528
	g_dev = this;

529
	_debug_enabled = false;
530
	_servorail_status.rssi_v = 0;
531
532
533
534
}

PX4IO::~PX4IO()
{
535
536
	/* tell the task we want it to go away */
	_task_should_exit = true;
537

538
539
540
541
	/* spin waiting for the task to stop */
	for (unsigned i = 0; (i < 10) && (_task != -1); i++) {
		/* give it another 100ms */
		usleep(100000);
542
	}
543

544
545
546
	/* well, kill it anyway, though this will probably crash */
	if (_task != -1)
		task_delete(_task);
547

548
549
550
	if (_interface != nullptr)
		delete _interface;

551
552
553
554
555
	/* deallocate perfs */
	perf_free(_perf_update);
	perf_free(_perf_write);
	perf_free(_perf_chan_count);

556
557
558
	g_dev = nullptr;
}

559
560
561
562
563
int
PX4IO::detect()
{
	int ret;

564
	if (_task == -1) {
565

566
567
		/* do regular cdev init */
		ret = CDev::init();
Anton Babushkin's avatar
Anton Babushkin committed
568

569
570
		if (ret != OK)
			return ret;
571

572
573
		/* get some parameters */
		unsigned protocol = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_PROTOCOL_VERSION);
Anton Babushkin's avatar
Anton Babushkin committed
574

575
576
577
		if (protocol != PX4IO_PROTOCOL_VERSION) {
			if (protocol == _io_reg_get_error) {
				log("IO not installed");
Anton Babushkin's avatar
Anton Babushkin committed
578

579
580
581
582
			} else {
				log("IO version error");
				mavlink_log_emergency(_mavlink_fd, "IO VERSION MISMATCH, PLEASE UPGRADE SOFTWARE!");
			}
Anton Babushkin's avatar
Anton Babushkin committed
583

584
			return -1;
585
		}
586
	}
587

Lorenz Meier's avatar
Lorenz Meier committed
588
	log("IO found");
589
590
591
592

	return 0;
}

593
594
595
int
PX4IO::init(bool rc_handling_disabled) {
	_rc_handling_disabled = rc_handling_disabled;
596
	return init();
597
598
}

599
600
601
602
int
PX4IO::init()
{
	int ret;
603
604
	param_t sys_restart_param;
	int sys_restart_val = DM_INIT_REASON_VOLATILE;
605
606
607

	ASSERT(_task == -1);

608
	sys_restart_param = param_find("SYS_RESTART_TYPE");
609
610
611
612
	if (sys_restart_param != PARAM_INVALID) {
		/* Indicate restart type is unknown */
		param_set(sys_restart_param, &sys_restart_val);
	}
613

614
	/* do regular cdev init */
615
	ret = CDev::init();
Anton Babushkin's avatar
Anton Babushkin committed
616

617
618
619
	if (ret != OK)
		return ret;

620
	/* get some parameters */
621
	unsigned protocol = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_PROTOCOL_VERSION);
Anton Babushkin's avatar
Anton Babushkin committed
622

623
624
625
626
627
628
	if (protocol == _io_reg_get_error) {
		log("failed to communicate with IO");
		mavlink_log_emergency(_mavlink_fd, "[IO] failed to communicate with IO, abort.");
		return -1;
	}

629
630
631
632
633
	if (protocol != PX4IO_PROTOCOL_VERSION) {
		log("protocol/firmware mismatch");
		mavlink_log_emergency(_mavlink_fd, "[IO] protocol/firmware mismatch, abort.");
		return -1;
	}
Anton Babushkin's avatar
Anton Babushkin committed
634

635
	_hardware      = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_HARDWARE_VERSION);
636
	_max_actuators = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_ACTUATOR_COUNT);
637
	_max_controls  = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_CONTROL_COUNT);
638
	_max_relays    = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_RELAY_COUNT);
639
	_max_transfer  = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_MAX_TRANSFER) - 2;
640
	_max_rc_input  = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_RC_INPUT_COUNT);
Anton Babushkin's avatar
Anton Babushkin committed
641

642
	if ((_max_actuators < 1) || (_max_actuators > 255) ||
643
	    (_max_relays > 32)   ||
644
	    (_max_transfer < 16) || (_max_transfer > 255)  ||
645
	    (_max_rc_input < 1)  || (_max_rc_input > 255)) {
646

647
648
		log("config read error");
		mavlink_log_emergency(_mavlink_fd, "[IO] config read fail, abort.");
649
		return -1;
650
	}
Anton Babushkin's avatar
Anton Babushkin committed
651

652
653
654
	if (_max_rc_input > RC_INPUT_MAX_CHANNELS)
		_max_rc_input = RC_INPUT_MAX_CHANNELS;

655
656
657
658
659
660
	/*
	 * Check for IO flight state - if FMU was flagged to be in
	 * armed state, FMU is recovering from an in-air reset.
	 * Read back status and request the commander to arm
	 * in this case.
	 */
px4dev's avatar
px4dev committed
661

662
663
	uint16_t reg;

664
665
	/* get IO's last seen FMU state */
	ret = io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, &reg, sizeof(reg));
Anton Babushkin's avatar
Anton Babushkin committed
666

667
	if (ret != OK)
668
		return ret;
669

670
671
672
673
674
	/*
	 * in-air restart is only tried if the IO board reports it is
	 * already armed, and has been configured for in-air restart
	 */
	if ((reg & PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK) &&
675
	    (reg & PX4IO_P_SETUP_ARMING_FMU_ARMED)) {
676

677
678
679
		/* get a status update from IO */
		io_get_status();

Anton Babushkin's avatar
Anton Babushkin committed
680
681
		mavlink_log_emergency(_mavlink_fd, "[IO] RECOVERING FROM FMU IN-AIR RESTART");
		log("INAIR RESTART RECOVERY (needs commander app running)");
682

683
684
685
686
687
		/* WARNING: COMMANDER app/vehicle status must be initialized.
		 * If this fails (or the app is not started), worst-case IO
		 * remains untouched (so manual override is still available).
		 */

688
		int safety_sub = orb_subscribe(ORB_ID(actuator_armed));
689
		/* fill with initial values, clear updated flag */
690
		struct actuator_armed_s safety;
691
692
		uint64_t try_start_time = hrt_absolute_time();
		bool updated = false;
Anton Babushkin's avatar
Anton Babushkin committed
693

694
		/* keep checking for an update, ensure we got a arming information,
695
696
		   not something that was published a long time ago. */
		do {
697
			orb_check(safety_sub, &updated);
698
699
700

			if (updated) {
				/* got data, copy and exit loop */
701
				orb_copy(ORB_ID(actuator_armed), safety_sub, &safety);
702
703
704
705
706
707
				break;
			}

			/* wait 10 ms */
			usleep(10000);

708
			/* abort after 5s */
Anton Babushkin's avatar
Anton Babushkin committed
709
			if ((hrt_absolute_time() - try_start_time) / 1000 > 3000) {
710
711
712
713
714
715
716
717
				log("failed to recover from in-air restart (1), aborting IO driver init.");
				return 1;
			}

		} while (true);

		/* send command to arm system via command API */
		vehicle_command_s cmd;
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
		/* send this to itself */
		param_t sys_id_param = param_find("MAV_SYS_ID");
		param_t comp_id_param = param_find("MAV_COMP_ID");

		int32_t sys_id;
		int32_t comp_id;

		if (param_get(sys_id_param, &sys_id)) {
			errx(1, "PRM SYSID");
		}

		if (param_get(comp_id_param, &comp_id)) {
			errx(1, "PRM CMPID");
		}

		cmd.target_system = sys_id;
		cmd.target_component = comp_id;
		cmd.source_system = sys_id;
		cmd.source_component = comp_id;
737
738
739
740
741
742
743
744
745
		/* request arming */
		cmd.param1 = 1.0f;
		cmd.param2 = 0;
		cmd.param3 = 0;
		cmd.param4 = 0;
		cmd.param5 = 0;
		cmd.param6 = 0;
		cmd.param7 = 0;
		cmd.command = VEHICLE_CMD_COMPONENT_ARM_DISARM;
746

747
748
749
750
		/* ask to confirm command */
		cmd.confirmation =  1;

		/* send command once */
751
		orb_advert_t pub = orb_advertise(ORB_ID(vehicle_command), &cmd);
752
753
754

		/* spin here until IO's state has propagated into the system */
		do {
755
			orb_check(safety_sub, &updated);
756
757

			if (updated) {
758
				orb_copy(ORB_ID(actuator_armed), safety_sub, &safety);
759
760
			}

761
762
			/* wait 50 ms */
			usleep(50000);
763

764
			/* abort after 5s */
Anton Babushkin's avatar
Anton Babushkin committed
765
			if ((hrt_absolute_time() - try_start_time) / 1000 > 2000) {
766
767
768
769
				log("failed to recover from in-air restart (2), aborting IO driver init.");
				return 1;
			}

770
			/* re-send if necessary */
771
			if (!safety.armed) {
772
773
774
775
				orb_publish(ORB_ID(vehicle_command), pub, &cmd);
				log("re-sending arm cmd");
			}

Anton Babushkin's avatar
Anton Babushkin committed
776
			/* keep waiting for state change for 2 s */
777
		} while (!safety.armed);
778

779
780
781
782
783
		/* Indicate restart type is in-flight */
		sys_restart_val = DM_INIT_REASON_IN_FLIGHT;
		param_set(sys_restart_param, &sys_restart_val);


Anton Babushkin's avatar
Anton Babushkin committed
784
		/* regular boot, no in-air restart, init IO */
785
786
787
788

	} else {

		/* dis-arm IO before touching anything */
Anton Babushkin's avatar
Anton Babushkin committed
789
790
791
792
793
		io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING,
			      PX4IO_P_SETUP_ARMING_FMU_ARMED |
			      PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK |
			      PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK |
			      PX4IO_P_SETUP_ARMING_ALWAYS_PWM_ENABLE, 0);
794

795
796
		if (_rc_handling_disabled) {
			ret = io_disable_rc_handling();
Anton Babushkin's avatar
Anton Babushkin committed
797

798
799
800
801
802
			if (ret != OK) {
				log("failed disabling RC handling");
				return ret;
			}

803
804
805
		} else {
			/* publish RC config to IO */
			ret = io_set_rc_config();
Anton Babushkin's avatar
Anton Babushkin committed
806

807
808
809
810
811
			if (ret != OK) {
				log("failed to update RC input config");
				mavlink_log_info(_mavlink_fd, "[IO] RC config upload fail");
				return ret;
			}
812
813
		}

814
815
816
817
		/* Indicate restart type is power on */
		sys_restart_val = DM_INIT_REASON_POWER_ON;
		param_set(sys_restart_param, &sys_restart_val);

818
819
	}

820
821
	/* try to claim the generic PWM output device node as well - it's OK if we fail at this */
	ret = register_driver(PWM_OUTPUT_DEVICE_PATH, &fops, 0666, (void *)this);
px4dev's avatar
px4dev committed
822

823
824
825
826
827
	if (ret == OK) {
		log("default PWM output device");
		_primary_pwm_device = true;
	}

828
	/* start the IO interface task */
829
830
831
832
833
834
	_task = task_spawn_cmd("px4io",
					SCHED_DEFAULT,
					SCHED_PRIORITY_ACTUATOR_OUTPUTS,
					2000,
					(main_t)&PX4IO::task_main_trampoline,
					nullptr);
835

836
837
838
839
840
	if (_task < 0) {
		debug("task start failed: %d", errno);
		return -errno;
	}

841
842
	mavlink_log_info(_mavlink_fd, "[IO] init ok");

843
844
845
846
847
848
849
850
851
852
853
854
	return OK;
}

void
PX4IO::task_main_trampoline(int argc, char *argv[])
{
	g_dev->task_main();
}

void
PX4IO::task_main()
{
855
856
	hrt_abstime poll_last = 0;
	hrt_abstime orb_check_last = 0;
857

858
	_mavlink_fd = ::open(MAVLINK_LOG_DEVICE, 0);
Jean Cyr's avatar
Jean Cyr committed
859

860
861
862
863
	/*
	 * Subscribe to the appropriate PWM output topic based on whether we are the
	 * primary PWM output or not.
	 */
864
865
866
867
868
869
870
871
	_t_actuator_controls_0 = orb_subscribe(ORB_ID(actuator_controls_0));
	orb_set_interval(_t_actuator_controls_0, 20);		/* default to 50Hz */
	_t_actuator_controls_1 = orb_subscribe(ORB_ID(actuator_controls_1));
	orb_set_interval(_t_actuator_controls_1, 33);		/* default to 30Hz */
	_t_actuator_controls_2 = orb_subscribe(ORB_ID(actuator_controls_2));
	orb_set_interval(_t_actuator_controls_2, 33);		/* default to 30Hz */
	_t_actuator_controls_3 = orb_subscribe(ORB_ID(actuator_controls_3));
	orb_set_interval(_t_actuator_controls_3, 33);		/* default to 30Hz */
872
	_t_actuator_armed = orb_subscribe(ORB_ID(actuator_armed));
873
	_t_vehicle_control_mode = orb_subscribe(ORB_ID(vehicle_control_mode));
874
	_t_param = orb_subscribe(ORB_ID(parameter_update));
875
876
	_t_vehicle_command = orb_subscribe(ORB_ID(vehicle_command));

877
	if ((_t_actuator_controls_0 < 0) ||
Anton Babushkin's avatar
Anton Babushkin committed
878
879
880
881
	    (_t_actuator_armed < 0) ||
	    (_t_vehicle_control_mode < 0) ||
	    (_t_param < 0) ||
	    (_t_vehicle_command < 0)) {
882
883
884
885
		log("subscription(s) failed");
		goto out;
	}

886
	/* poll descriptor */
887
	pollfd fds[1];
888
	fds[0].fd = _t_actuator_controls_0;
889
890
	fds[0].events = POLLIN;

891
892
	/* lock against the ioctl handler */
	lock();
893

894
	/* loop talking to IO */
895
896
	while (!_task_should_exit) {

897
898
		/* adjust update interval */
		if (_update_interval != 0) {
899
900
			if (_update_interval < UPDATE_INTERVAL_MIN)
				_update_interval = UPDATE_INTERVAL_MIN;
Anton Babushkin's avatar
Anton Babushkin committed
901

902
903
			if (_update_interval > 100)
				_update_interval = 100;
Anton Babushkin's avatar
Anton Babushkin committed
904

905
906
907
908
909
			orb_set_interval(_t_actuator_controls_0, _update_interval);
			/*
			 * NOT changing the rate of groups 1-3 here, because only attitude
			 * really needs to run fast.
			 */
910
911
912
			_update_interval = 0;
		}

913
		/* sleep waiting for topic updates, but no more than 20ms */
914
		unlock();
915
		int ret = ::poll(fds, 1, 20);
916
		lock();
917
918
919
920
921
922
923

		/* this would be bad... */
		if (ret < 0) {
			log("poll error %d", errno);
			continue;
		}

924
925
926
		perf_begin(_perf_update);
		hrt_abstime now = hrt_absolute_time();

927
		/* if we have new control data from the ORB, handle it */
928
		if (fds[0].revents & POLLIN) {
929
930
931

			/* we're not nice to the lower-priority control groups and only check them
			   when the primary group updated (which is now). */
Lorenz Meier's avatar
Lorenz Meier committed
932
			(void)io_set_control_groups();
933
934
		}

935
936
937
		if (now >= poll_last + IO_POLL_INTERVAL) {
			/* run at 50Hz */
			poll_last = now;
938

939
			/* pull status and alarms from IO */
940
941
			io_get_status();

942
			/* get raw R/C input from IO */
943
944
			io_publish_raw_rc();

945
			/* fetch PWM outputs from IO */
946
			io_publish_pwm_outputs();
947
948
949
950
951
952
		}

		if (now >= orb_check_last + ORB_CHECK_INTERVAL) {
			/* run at 5Hz */
			orb_check_last = now;

953
954
955
956
			/* try to claim the MAVLink log FD */
			if (_mavlink_fd < 0)
				_mavlink_fd = ::open(MAVLINK_LOG_DEVICE, 0);

957
958
959
960
961
			/* check updates on uORB topics and handle it */
			bool updated = false;

			/* arming state */
			orb_check(_t_actuator_armed, &updated);
Anton Babushkin's avatar
Anton Babushkin committed
962

963
964
965
			if (!updated) {
				orb_check(_t_vehicle_control_mode, &updated);
			}
Anton Babushkin's avatar
Anton Babushkin committed
966

967
968
969
970
971
972
			if (updated) {
				io_set_arming_state();
			}

			/* vehicle command */
			orb_check(_t_vehicle_command, &updated);
Anton Babushkin's avatar
Anton Babushkin committed
973

974
975
976
			if (updated) {
				struct vehicle_command_s cmd;
				orb_copy(ORB_ID(vehicle_command), _t_vehicle_command, &cmd);