#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2018 - 2022 Vasily Evseenko # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # import struct from . import call_and_check_rc, ExecError from .mavlink import MAV_MODE_FLAG_SAFETY_ARMED, MAVLINK_MSG_ID_HEARTBEAT from twisted.python import log from twisted.internet import reactor, defer, utils from twisted.internet.protocol import Protocol, DatagramProtocol def parse_mavlink_l2_v1(msg): plen, seq, sys_id, comp_id, msg_id = struct.unpack(' 4096: buffer = buffer[skip:] skip = 0 data = yield mlist mlist = [] if not data: continue buffer.extend(data) while len(buffer) - skip >= 8: version = buffer[skip] # mavlink 1 if version == 0xfe: mlen = 8 + buffer[skip + 1] # mavlink 2 elif version == 0xfd: mlen, flags = struct.unpack('BB', buffer[skip + 1 : skip + 3]) if flags & ~0x01: log.msg('Unsupported mavlink flags: 0x%x' % (flags,)) mlen += (25 if flags & 0x01 else 12) else: skip += 1 bad += 1 continue if bad: log.msg('skip %d bad bytes before sync' % (bad,)) bad = 0 if len(buffer) - skip < mlen: break if parse_l2: mlist.append(parse_map[version](buffer[skip: skip + mlen])) else: mlist.append(bytes(buffer[skip: skip + mlen])) skip += mlen class MavlinkARMProtocol(object): def __init__(self, call_on_arm, call_on_disarm): self.call_on_arm = call_on_arm self.call_on_disarm = call_on_disarm self.armed = None self.locked = False self.mavlink_fsm = mavlink_parser_gen(parse_l2=True) self.mavlink_fsm.send(None) def dataReceived(self, data): for l2_headers, m in self.mavlink_fsm.send(data): self.messageReceived(l2_headers, m) def messageReceived(self, l2_headers, message): seq, sys_id, comp_id, msg_id = l2_headers if (sys_id, comp_id, msg_id) != (1, 1, MAVLINK_MSG_ID_HEARTBEAT): return armed = bool(message[6] & MAV_MODE_FLAG_SAFETY_ARMED) if not self.locked: self.locked = True def _unlock(x): self.locked = False return x return defer.maybeDeferred(self.change_state, armed).addBoth(_unlock) def change_state(self, armed): if armed == self.armed: return self.armed = armed cmd = None if armed: log.msg('State change: ARMED') cmd = self.call_on_arm else: log.msg('State change: DISARMED') cmd = self.call_on_disarm def on_err(f): log.msg('Command exec failed: %s' % (f.value,), isError=1) if f.value.stdout: log.msg(f.value.stdout, isError=1) if f.value.stderr: log.msg(f.value.stderr, isError=1) if cmd is not None: return call_and_check_rc(cmd).addErrback(on_err)