px4io.cpp 78.5 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
76
77

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

87
#include <debug.h>
88

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

92
#include "uploader.h"
93
94
95

extern device::Device *PX4IO_i2c_interface() weak_function;
extern device::Device *PX4IO_serial_interface() weak_function;
96

97
98
#define PX4IO_SET_DEBUG			_IOC(0xff00, 0)
#define PX4IO_INAIR_RESTART_ENABLE	_IOC(0xff00, 1)
99
#define PX4IO_REBOOT_BOOTLOADER		_IOC(0xff00, 2)
Andrew Tridgell's avatar
Andrew Tridgell committed
100
#define PX4IO_CHECK_CRC			_IOC(0xff00, 3)
101

102
103
104
#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
105

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

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

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

135
136
	/**
	 * Detect if a PX4IO is connected.
Anton Babushkin's avatar
Anton Babushkin committed
137
	 *
138
139
140
141
	 * Only validate if there is a PX4IO to talk to.
	 */
	virtual int		detect();

142
143
	/**
	 * IO Control handler.
Anton Babushkin's avatar
Anton Babushkin committed
144
	 *
145
146
147
148
149
150
	 * 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)
	 */
151
	virtual int		ioctl(file *filp, int cmd, unsigned long arg);
152
153
154

	/**
	 * write handler.
Anton Babushkin's avatar
Anton Babushkin committed
155
	 *
156
157
158
159
160
161
162
	 * 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
	 */
163
	virtual ssize_t		write(file *filp, const char *buffer, size_t len);
164

165
166
167
	/**
	* Set the update rate for actuator outputs from FMU to IO.
	*
Lorenz Meier's avatar
Lorenz Meier committed
168
	* @param[in] rate		The rate in Hz actuator outpus are sent to IO.
169
	* 			Min 10 Hz, max 400 Hz
170
	*/
171
	int      		set_update_rate(int rate);
172

173
174
175
	/**
	* Set the battery current scaling and bias
	*
176
177
	* @param[in] amp_per_volt
	* @param[in] amp_bias
178
	*/
179
180
181
182
183
	void      		set_battery_current_scaling(float amp_per_volt, float amp_bias);

	/**
	 * Push failsafe values to IO.
	 *
Lorenz Meier's avatar
Lorenz Meier committed
184
185
	 * @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
186
187
	 */
	int			set_failsafe_values(const uint16_t *vals, unsigned len);
188

189
190
191
192
193
	/**
	 * Disable RC input handling
	 */
	int			disable_rc_handling();

194
	/**
195
196
197
198
	 * Print IO status.
	 *
	 * Print all relevant IO status information
	 */
199
200
	void			print_status();

201
	/**
202
	 * Fetch and print debug console output.
203
	 */
204
	int			print_debug();
205

206
#ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
207
208
209
210
211
	/**
	 * 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
212
	inline void		set_dsm_vcc_ctl(bool enable) {
213
214
215
		_dsm_vcc_ctl = enable;
	};

216
217
218
219
220
	/**
	 * 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
221
	inline bool		get_dsm_vcc_ctl() {
222
223
		return _dsm_vcc_ctl;
	};
224
225
226
#endif

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

228
private:
229
	device::Device		*_interface;
230

Lorenz Meier's avatar
Lorenz Meier committed
231
	// XXX
232
233
234
235
236
237
	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
238

239
240
	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
241
	unsigned		_rc_chan_count;		///< Internal copy of the last seen number of RC channels
242
	uint64_t		_rc_last_valid;		///< last valid timestamp
243

244
245
	volatile int		_task;			///< worker task id
	volatile bool		_task_should_exit;	///< worker terminate flag
246

247
	int			_mavlink_fd;		///< mavlink file descriptor.
248

249
250
	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
251
	perf_counter_t		_perf_chan_count;	///<local performance counter for channel number changes
252
253

	/* cached IO state */
254
255
	uint16_t		_status;		///< Various IO status flags
	uint16_t		_alarms;		///< Various IO alarms
256

257
	/* subscribed topics */
258
259
260
261
	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
262
	int			_t_actuator_armed;	///< system armed control topic
Lorenz Meier's avatar
Lorenz Meier committed
263
264
	int 			_t_vehicle_control_mode;///< vehicle control mode topic
	int			_t_param;		///< parameter update topic
265
	int			_t_vehicle_command;	///< vehicle command topic
266

267
	/* advertised topics */
Lorenz Meier's avatar
Lorenz Meier committed
268
269
270
	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
271
	orb_advert_t		_to_servorail;		///< servorail status
Lorenz Meier's avatar
Lorenz Meier committed
272
	orb_advert_t		_to_safety;		///< status of safety
273

274
275
	actuator_outputs_s	_outputs;		///< mixed outputs
	servorail_status_s	_servorail_status;	///< servorail status
276

277
	bool			_primary_pwm_device;	///< true if we are the default PWM output
278
	bool			_lockdown_override;	///< allow to override the safety lockdown
279

280
281
282
283
	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
Jean Cyr's avatar
Jean Cyr committed
284

285
#ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
286
	bool			_dsm_vcc_ctl;		///< true if relay 1 controls DSM satellite RX power
287
#endif
Jean Cyr's avatar
Jean Cyr committed
288

289
290
291
	/**
	 * Trampoline to the worker task
	 */
292
	static void		task_main_trampoline(int argc, char *argv[]);
293
294
295
296

	/**
	 * worker task
	 */
297
	void			task_main();
298

299
	/**
300
	 * Send controls for one group to IO
301
	 */
302
303
304
305
306
307
	int			io_set_control_state(unsigned group);

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

309
	/**
310
	 * Update IO's arming-related state
311
	 */
312
	int			io_set_arming_state();
313

314
315
316
317
318
	/**
	 * Push RC channel configuration to IO.
	 */
	int			io_set_rc_config();

px4dev's avatar
px4dev committed
319
320
	/**
	 * Fetch status and alarms from IO
321
322
	 *
	 * Also publishes battery voltage/current.
px4dev's avatar
px4dev committed
323
324
325
	 */
	int			io_get_status();

326
327
328
329
330
	/**
	 * Disable RC input handling
	 */
	int			io_disable_rc_handling();

px4dev's avatar
px4dev committed
331
	/**
332
	 * Fetch RC inputs from IO.
333
334
	 *
	 * @param input_rc	Input structure to populate.
335
336
337
338
339
340
341
342
343
344
345
346
347
	 * @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
348

349
	/**
350
	 * write register(s)
351
352
353
354
355
	 *
	 * @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.
356
	 * @return		OK if all values were successfully written.
357
	 */
358
	int			io_reg_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values);
359

360
361
362
363
364
365
	/**
	 * write a register
	 *
	 * @param page		Register page to write to.
	 * @param offset	Register offset to write to.
	 * @param value		Value to write.
366
	 * @return		OK if the value was written successfully.
367
368
369
	 */
	int			io_reg_set(uint8_t page, uint8_t offset, const uint16_t value);

370
	/**
371
	 * read register(s)
372
373
374
375
376
	 *
	 * @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.
377
	 * @return		OK if all values were successfully read.
378
	 */
379
	int			io_reg_get(uint8_t page, uint8_t offset, uint16_t *values, unsigned num_values);
380

381
382
383
384
385
386
387
388
389
390
	/**
	 * 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;

391
	/**
392
393
394
395
396
397
	 * 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.
398
	 */
399
	int			io_reg_modify(uint8_t page, uint8_t offset, uint16_t clearbits, uint16_t setbits);
400

401
402
403
	/**
	 * Send mixer definition text to IO
	 */
Anton Babushkin's avatar
Anton Babushkin committed
404
	int			mixer_send(const char *buf, unsigned buflen, unsigned retries = 3);
405

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
	/**
	 * 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);

424
425
426
	/**
	 * Handle issuing dsm bind ioctl to px4io.
	 *
Jean Cyr's avatar
Jean Cyr committed
427
	 * @param dsmMode	0:dsm2, 1:dsmx
428
	 */
Jean Cyr's avatar
Jean Cyr committed
429
	void			dsm_bind_ioctl(int dsmMode);
430

431
432
433
434
435
	/**
	 * Handle a battery update from IO.
	 *
	 * Publish IO battery information if necessary.
	 *
436
437
	 * @param vbatt		vbatt register
	 * @param ibatt		ibatt register
438
439
	 */
	void			io_handle_battery(uint16_t vbatt, uint16_t ibatt);
440

441
442
443
444
445
446
447
448
	/**
	 * Handle a servorail update from IO.
	 *
	 * Publish servo rail information if necessary.
	 *
	 * @param vservo	vservo register
	 * @param vrssi 	vrssi register
	 */
449
	void			io_handle_vservo(uint16_t vservo, uint16_t vrssi);
450
451

};
452

px4dev's avatar
px4dev committed
453
namespace
454
455
{

456
PX4IO	*g_dev = nullptr;
457
458
459

}

460
PX4IO::PX4IO(device::Device *interface) :
461
	CDev("px4io", PX4IO_DEVICE_PATH),
462
	_interface(interface),
463
	_hardware(0),
464
	_max_actuators(0),
465
	_max_controls(0),
466
467
468
469
	_max_rc_input(0),
	_max_relays(0),
	_max_transfer(16),	/* sensible default */
	_update_interval(0),
470
	_rc_handling_disabled(false),
Lorenz Meier's avatar
Lorenz Meier committed
471
	_rc_chan_count(0),
472
	_rc_last_valid(0),
473
474
	_task(-1),
	_task_should_exit(false),
475
	_mavlink_fd(-1),
Lorenz Meier's avatar
Lorenz Meier committed
476
477
478
	_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
479
480
	_status(0),
	_alarms(0),
481
482
483
484
	_t_actuator_controls_0(-1),
	_t_actuator_controls_1(-1),
	_t_actuator_controls_2(-1),
	_t_actuator_controls_3(-1),
485
	_t_actuator_armed(-1),
486
	_t_vehicle_control_mode(-1),
px4dev's avatar
px4dev committed
487
	_t_param(-1),
488
	_t_vehicle_command(-1),
489
490
491
	_to_input_rc(0),
	_to_outputs(0),
	_to_battery(0),
492
	_to_servorail(0),
493
	_to_safety(0),
494
	_primary_pwm_device(false),
495
	_lockdown_override(false),
Anton Babushkin's avatar
Anton Babushkin committed
496
	_battery_amp_per_volt(90.0f / 5.0f), // this matches the 3DR current sensor
497
498
	_battery_amp_bias(0),
	_battery_mamphour_total(0),
499
500
	_battery_last_timestamp(0)
#ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
Anton Babushkin's avatar
Anton Babushkin committed
501
	, _dsm_vcc_ctl(false)
502
503
#endif

504
{
505
	/* we need this potentially before it could be set in task_main */
506
507
	g_dev = this;

508
	_debug_enabled = false;
509
	_servorail_status.rssi_v = 0;
510
511
512
513
}

PX4IO::~PX4IO()
{
514
515
	/* tell the task we want it to go away */
	_task_should_exit = true;
516

517
518
519
520
	/* spin waiting for the task to stop */
	for (unsigned i = 0; (i < 10) && (_task != -1); i++) {
		/* give it another 100ms */
		usleep(100000);
521
	}
522

523
524
525
	/* well, kill it anyway, though this will probably crash */
	if (_task != -1)
		task_delete(_task);
526

527
528
529
	if (_interface != nullptr)
		delete _interface;

530
531
532
	g_dev = nullptr;
}

533
534
535
536
537
int
PX4IO::detect()
{
	int ret;

538
	if (_task == -1) {
539

540
541
		/* do regular cdev init */
		ret = CDev::init();
Anton Babushkin's avatar
Anton Babushkin committed
542

543
544
		if (ret != OK)
			return ret;
545

546
547
		/* get some parameters */
		unsigned protocol = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_PROTOCOL_VERSION);
Anton Babushkin's avatar
Anton Babushkin committed
548

549
550
551
		if (protocol != PX4IO_PROTOCOL_VERSION) {
			if (protocol == _io_reg_get_error) {
				log("IO not installed");
Anton Babushkin's avatar
Anton Babushkin committed
552

553
554
555
556
			} else {
				log("IO version error");
				mavlink_log_emergency(_mavlink_fd, "IO VERSION MISMATCH, PLEASE UPGRADE SOFTWARE!");
			}
Anton Babushkin's avatar
Anton Babushkin committed
557

558
			return -1;
559
		}
560
	}
561

Lorenz Meier's avatar
Lorenz Meier committed
562
	log("IO found");
563
564
565
566

	return 0;
}

567
568
569
570
571
572
573
574
int
PX4IO::init()
{
	int ret;

	ASSERT(_task == -1);

	/* do regular cdev init */
575
	ret = CDev::init();
Anton Babushkin's avatar
Anton Babushkin committed
576

577
578
579
	if (ret != OK)
		return ret;

580
	/* get some parameters */
581
	unsigned protocol = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_PROTOCOL_VERSION);
Anton Babushkin's avatar
Anton Babushkin committed
582

583
584
585
586
587
588
	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;
	}

589
590
591
592
593
	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
594

595
	_hardware      = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_HARDWARE_VERSION);
596
	_max_actuators = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_ACTUATOR_COUNT);
597
	_max_controls  = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_CONTROL_COUNT);
598
	_max_relays    = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_RELAY_COUNT);
599
	_max_transfer  = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_MAX_TRANSFER) - 2;
600
	_max_rc_input  = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_RC_INPUT_COUNT);
Anton Babushkin's avatar
Anton Babushkin committed
601

602
	if ((_max_actuators < 1) || (_max_actuators > 255) ||
603
	    (_max_relays > 32)   ||
604
	    (_max_transfer < 16) || (_max_transfer > 255)  ||
605
	    (_max_rc_input < 1)  || (_max_rc_input > 255)) {
606

607
608
		log("config read error");
		mavlink_log_emergency(_mavlink_fd, "[IO] config read fail, abort.");
609
		return -1;
610
	}
Anton Babushkin's avatar
Anton Babushkin committed
611

612
613
614
	if (_max_rc_input > RC_INPUT_MAX_CHANNELS)
		_max_rc_input = RC_INPUT_MAX_CHANNELS;

615
616
617
618
619
620
	/*
	 * 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
621

622
623
	uint16_t reg;

624
625
	/* 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
626

627
	if (ret != OK)
628
		return ret;
629

630
631
632
633
634
	/*
	 * 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) &&
635
	    (reg & PX4IO_P_SETUP_ARMING_FMU_ARMED)) {
636

637
638
639
		/* get a status update from IO */
		io_get_status();

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

643
644
645
646
647
		/* 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).
		 */

648
		int safety_sub = orb_subscribe(ORB_ID(actuator_armed));
649
		/* fill with initial values, clear updated flag */
650
		struct actuator_armed_s safety;
651
652
		uint64_t try_start_time = hrt_absolute_time();
		bool updated = false;
Anton Babushkin's avatar
Anton Babushkin committed
653

654
		/* keep checking for an update, ensure we got a arming information,
655
656
		   not something that was published a long time ago. */
		do {
657
			orb_check(safety_sub, &updated);
658
659
660

			if (updated) {
				/* got data, copy and exit loop */
661
				orb_copy(ORB_ID(actuator_armed), safety_sub, &safety);
662
663
664
665
666
667
				break;
			}

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

668
			/* abort after 5s */
Anton Babushkin's avatar
Anton Babushkin committed
669
			if ((hrt_absolute_time() - try_start_time) / 1000 > 3000) {
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
				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;
		/* 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;
687
688
689
690
		// cmd.target_system = status.system_id;
		// cmd.target_component = status.component_id;
		// cmd.source_system = status.system_id;
		// cmd.source_component = status.component_id;
691
692
693
694
		/* ask to confirm command */
		cmd.confirmation =  1;

		/* send command once */
695
		orb_advert_t pub = orb_advertise(ORB_ID(vehicle_command), &cmd);
696
697
698

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

			if (updated) {
702
				orb_copy(ORB_ID(actuator_armed), safety_sub, &safety);
703
704
			}

705
706
			/* wait 50 ms */
			usleep(50000);
707

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

714
			/* re-send if necessary */
715
			if (!safety.armed) {
716
717
718
719
				orb_publish(ORB_ID(vehicle_command), pub, &cmd);
				log("re-sending arm cmd");
			}

Anton Babushkin's avatar
Anton Babushkin committed
720
			/* keep waiting for state change for 2 s */
721
		} while (!safety.armed);
722

Anton Babushkin's avatar
Anton Babushkin committed
723
		/* regular boot, no in-air restart, init IO */
724
725
726
727

	} else {

		/* dis-arm IO before touching anything */
Anton Babushkin's avatar
Anton Babushkin committed
728
729
730
731
732
		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);
733

734
735
		if (_rc_handling_disabled) {
			ret = io_disable_rc_handling();
Anton Babushkin's avatar
Anton Babushkin committed
736

737
738
739
		} else {
			/* publish RC config to IO */
			ret = io_set_rc_config();
Anton Babushkin's avatar
Anton Babushkin committed
740

741
742
743
744
745
			if (ret != OK) {
				log("failed to update RC input config");
				mavlink_log_info(_mavlink_fd, "[IO] RC config upload fail");
				return ret;
			}
746
747
		}

748
749
	}

750
751
	/* 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
752

753
754
755
756
757
	if (ret == OK) {
		log("default PWM output device");
		_primary_pwm_device = true;
	}

758
	/* start the IO interface task */
759
	_task = task_create("px4io", SCHED_PRIORITY_ACTUATOR_OUTPUTS, 2048, (main_t)&PX4IO::task_main_trampoline, nullptr);
760

761
762
763
764
765
	if (_task < 0) {
		debug("task start failed: %d", errno);
		return -errno;
	}

766
767
	mavlink_log_info(_mavlink_fd, "[IO] init ok");

768
769
770
771
772
773
774
775
776
777
778
779
	return OK;
}

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

void
PX4IO::task_main()
{
780
781
	hrt_abstime poll_last = 0;
	hrt_abstime orb_check_last = 0;
782

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

785
786
787
788
	/*
	 * Subscribe to the appropriate PWM output topic based on whether we are the
	 * primary PWM output or not.
	 */
789
790
791
792
793
794
795
796
	_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 */
797
	_t_actuator_armed = orb_subscribe(ORB_ID(actuator_armed));
798
	_t_vehicle_control_mode = orb_subscribe(ORB_ID(vehicle_control_mode));
799
	_t_param = orb_subscribe(ORB_ID(parameter_update));
800
801
	_t_vehicle_command = orb_subscribe(ORB_ID(vehicle_command));

802
	if ((_t_actuator_controls_0 < 0) ||
Anton Babushkin's avatar
Anton Babushkin committed
803
804
805
806
	    (_t_actuator_armed < 0) ||
	    (_t_vehicle_control_mode < 0) ||
	    (_t_param < 0) ||
	    (_t_vehicle_command < 0)) {
807
808
809
810
		log("subscription(s) failed");
		goto out;
	}

811
	/* poll descriptor */
812
	pollfd fds[1];
813
	fds[0].fd = _t_actuator_controls_0;
814
815
	fds[0].events = POLLIN;

816
817
	/* lock against the ioctl handler */
	lock();
818

819
	/* loop talking to IO */
820
821
	while (!_task_should_exit) {

822
823
		/* adjust update interval */
		if (_update_interval != 0) {
824
825
			if (_update_interval < UPDATE_INTERVAL_MIN)
				_update_interval = UPDATE_INTERVAL_MIN;
Anton Babushkin's avatar
Anton Babushkin committed
826

827
828
			if (_update_interval > 100)
				_update_interval = 100;
Anton Babushkin's avatar
Anton Babushkin committed
829

830
831
832
833
834
			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.
			 */
835
836
837
			_update_interval = 0;
		}

838
		/* sleep waiting for topic updates, but no more than 20ms */
839
		unlock();
840
		int ret = ::poll(fds, 1, 20);
841
		lock();
842
843
844
845
846
847
848

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

849
850
851
		perf_begin(_perf_update);
		hrt_abstime now = hrt_absolute_time();

852
		/* if we have new control data from the ORB, handle it */
853
		if (fds[0].revents & POLLIN) {
854
855
856

			/* 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
857
			(void)io_set_control_groups();
858
859
		}

860
861
862
		if (now >= poll_last + IO_POLL_INTERVAL) {
			/* run at 50Hz */
			poll_last = now;
863

864
			/* pull status and alarms from IO */
865
866
			io_get_status();

867
			/* get raw R/C input from IO */
868
869
			io_publish_raw_rc();

870
			/* fetch PWM outputs from IO */
871
			io_publish_pwm_outputs();
872
873
874
875
876
877
		}

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

878
879
880
881
			/* try to claim the MAVLink log FD */
			if (_mavlink_fd < 0)
				_mavlink_fd = ::open(MAVLINK_LOG_DEVICE, 0);

882
883
884
885
886
			/* 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
887

888
889
890
			if (!updated) {
				orb_check(_t_vehicle_control_mode, &updated);
			}
Anton Babushkin's avatar
Anton Babushkin committed
891

892
893
894
895
896
897
			if (updated) {
				io_set_arming_state();
			}

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

899
900
901
			if (updated) {
				struct vehicle_command_s cmd;
				orb_copy(ORB_ID(vehicle_command), _t_vehicle_command, &cmd);
Anton Babushkin's avatar
Anton Babushkin committed
902

903
				// Check for a DSM pairing command
904
				if (((int)cmd.command == VEHICLE_CMD_START_RX_PAIR) && ((int)cmd.param1 == 0)) {
905
906
907
					dsm_bind_ioctl((int)cmd.param2);
				}
			}
908
909
910
911
912
913

			/*
			 * If parameters have changed, re-send RC mappings to IO
			 *
			 * XXX this may be a bit spammy
			 */
914
			orb_check(_t_param, &updated);
Anton Babushkin's avatar
Anton Babushkin committed
915

916
			if (updated) {
917
				parameter_update_s pupdate;
918
919
				orb_copy(ORB_ID(parameter_update), _t_param, &pupdate);

Jean Cyr's avatar
Jean Cyr committed
920
921
				int32_t dsm_bind_val;
				param_t dsm_bind_param;
Jean Cyr's avatar
Jean Cyr committed
922

923
				/* see if bind parameter has been set, and reset it to -1 */
Jean Cyr's avatar
Jean Cyr committed
924
				param_get(dsm_bind_param = param_find("RC_DSM_BIND"), &dsm_bind_val);
Anton Babushkin's avatar
Anton Babushkin committed
925

926
				if (dsm_bind_val > -1) {
Jean Cyr's avatar
Jean Cyr committed
927
928
					dsm_bind_ioctl(dsm_bind_val);
					dsm_bind_val = -1;
Jean Cyr's avatar
Jean Cyr committed
929
					param_set(dsm_bind_param, &dsm_bind_val);
Jean Cyr's avatar
Jean Cyr committed
930
				}
931
932
933

				/* re-upload RC input config as it may have changed */
				io_set_rc_config();
934
935
936
937
938

				/* re-set the battery scaling */
				int32_t voltage_scaling_val;
				param_t voltage_scaling_param;

Lorenz Meier's avatar
Lorenz Meier committed
939
				/* set battery voltage scaling */
940
941
				param_get(voltage_scaling_param = param_find("BAT_V_SCALE_IO"), &voltage_scaling_val);

Lorenz Meier's avatar
Lorenz Meier committed
942
				/* send scaling voltage to IO */
943
944
945
946
				uint16_t scaling = voltage_scaling_val;
				int pret = io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_VBATT_SCALE, &scaling, 1);

				if (pret != OK) {
947
					log("vscale upload failed");
948
				}
949
950

				/* send RC throttle failsafe value to IO */
951
952
				int32_t failsafe_param_val;
				param_t failsafe_param = param_find("RC_FAILS_THR");
953

Lorenz Meier's avatar
Lorenz Meier committed
954
				if (failsafe_param > 0) {
955
956
957
958
959