def parse_request(request): interface = request.get('bus') if interface == None: interface = CAN_SEND_INTERFACE else: interface = interface[0] try: bus = CAN.Bus(interface) except OSError: raise BadRequest("bus '" + interface + "' does not exist") id = request.get('id') if id == None: raise BadRequest("id not specified") id = int(id[0]) data = request.get('data[]') # POST if data == None: data = request.get('data') # GET if data == None: data = [] # parse_url removes data field if empty array else: data = data[0].strip('[]').split(',') if len(data) == 1: if data[0] == '': data = [] data = list(map(int, data)) msg = CAN.Message(id, data) return (bus, msg)
def _send_sync(self): sync_object = self.od.get(ODI_SYNC) if sync_object is not None: sync_value = sync_object.get(ODSI_VALUE) if sync_value is not None: sync_id = sync_value & 0x3FF msg = CAN.Message(sync_id) self._send(msg)
def _heartbeat_consumer_timeout(self, id): if self.nmt_state != NMT_STATE_STOPPED: emcy_id = self.od.get(ODI_EMCY_ID) if emcy_id is not None: msg = CAN.Message( emcy_id, (EMCY_HEARTBEAT_BY_NODE + id).to_bytes(2, byteorder='big') + self.od.get(ODI_ERROR).get(ODSI_VALUE).to_bytes( 1, byteorder='big') + b'\x00\x00\x00\x00\x00') self._send(msg)
def heartbeat_consumer_timeout(id): global active_bus, canopen_od, nmt_state, node_id if nmt_state != CANopen.NMT_STATE_STOPPED: msg = CAN.Message( canopen_od.get(CANopen.ODI_EMCY_ID), (CANopen.EMCY_HEARTBEAT_BY_NODE + id).to_bytes( 2, byteorder='big') + canopen_od.get(CANopen.ODI_ERROR).get( CANopen.ODSI_VALUE).to_bytes(1, byteorder='big') + b'\x00\x00\x00\x00\x00') active_bus.send(msg)
def _send_pdo(self, i): i = i - 1 data = bytes() tpdo_mp = self.od.get(ODI_TPDO1_MAPPING_PARAMETER + i) if tpdo_mp is not None: for j in range(tpdo_mp.get(ODSI_VALUE, 0)): mapping_param = tpdo_mp.get(j + 1) if mapping_param is not None: mapping_object = self.od.get(mapping_param >> 16) if mapping_object is not None: mapping_value = mapping_object.get((mapping_param >> 8) & 0xFF) if mapping_value is not None: data = data + mapping_value.to_bytes( (mapping_param & 0xFF) // 8, byteorder='big') msg = CAN.Message(((FUNCTION_CODE_TPDO1 + (2 * i)) << FUNCTION_CODE_BITNUM) + self.id, data) self._send(msg)
def recv(self, msg: CAN.Message): id = msg.arbitration_id data = msg.data rtr = msg.is_remote_frame fc = (id >> FUNCTION_CODE_BITNUM) & 0xF if rtr: target_node = id & 0x7F if target_node == self.id or target_node == BROADCAST_NODE_ID: if self.nmt_state == NMT_STATE_OPERATIONAL: if fc == FUNCTION_CODE_TPDO1: tpdo1_cp = self.od.get( ODI_TPDO1_COMMUNICATION_PARAMETER) if tpdo1_cp is not None: tpdo1_cp_id = tpdo1_cp.get(ODSI_TPDO_COMM_PARAM_ID) if tpdo1_cp_id is not None and ( tpdo1_cp_id >> TPDO_COMM_PARAM_ID_VALID_BITNUM ) & 1 == 0 and ( tpdo1_cp_id >> TPDO_COMM_PARAM_ID_RTR_BITNUM) & 1 == 0: self._send_pdo(1) elif fc == FUNCTION_CODE_NMT_ERROR_CONTROL: self._send_heartbeat() elif fc == FUNCTION_CODE_NMT: command = id & 0x7F if command == NMT_NODE_CONTROL: target_node = data[1] if target_node == self.id or target_node == BROADCAST_NODE_ID: cs = data[0] if cs == NMT_NODE_CONTROL_START: self.nmt_state = NMT_STATE_OPERATIONAL elif cs == NMT_NODE_CONTROL_STOP: self.nmt_state = NMT_STATE_STOPPED elif cs == NMT_NODE_CONTROL_PREOPERATIONAL: self.nmt_state = NMT_STATE_PREOPERATIONAL elif cs == NMT_NODE_CONTROL_RESET_NODE: self.reset() elif cs == NMT_NODE_CONTROL_RESET_COMMUNICATION: self.reset_communication() elif fc == FUNCTION_CODE_SYNC and self.nmt_state == NMT_STATE_OPERATIONAL: for i in range(4): tpdo_cp = self.od.get(ODI_TPDO1_COMMUNICATION_PARAMETER + i) if tpdo_cp is not None: tpdo_cp_id = tpdo_cp.get(ODSI_TPDO_COMM_PARAM_ID) if tpdo_cp_id is not None and ( tpdo_cp_id >> TPDO_COMM_PARAM_ID_VALID_BITNUM) & 1 == 0: tpdo_cp_type = tpdo_cp.get(ODSI_TPDO_COMM_PARAM_TYPE) if tpdo_cp_type is not None and ( (tpdo_cp_type >= 0 and tpdo_cp_type <= 240) or tpdo_cp_type == 252): self._send_pdo(i + 1) elif fc == FUNCTION_CODE_SDO_RX and self.nmt_state != NMT_STATE_STOPPED: sdo_server_object = self.od.get(ODI_SDO_SERVER) if sdo_server_object is not None: sdo_server_id = sdo_server_object.get(ODSI_SERVER_DEFAULT_CSID) if sdo_server_id is not None and id == sdo_server_id: ccs = (data[0] >> SDO_CCS_BITNUM) & (2**SDO_CCS_LENGTH - 1) if len(data) >= 4: odi = (data[1] << 8) + data[2] odsi = data[3] if odi in self.od: obj = self.od.get(odi) if odsi in obj: if ccs == SDO_CCS_UPLOAD: scs = SDO_SCS_UPLOAD sdo_data = obj.get(odsi) elif ccs == SDO_CCS_DOWNLOAD: scs = SDO_SCS_DOWNLOAD n = (data[0] >> SDO_N_BITNUM) & ( 2**SDO_N_LENGTH - 1) self.od.update( { odi: int.from_bytes(data[4:], byteorder='big') } ) # Could be data[4:7-n], or different based on data type sdo_data = 0 else: scs = SDO_CS_ABORT sdo_data = SDO_ABORT_INVALID_CS else: scs = SDO_CS_ABORT sdo_data = SDO_ABORT_SUBINDEX_DNE else: scs = SDO_CS_ABORT sdo_data = SDO_ABORT_OBJECT_DNE else: odi = 0x0000 odsi = 0x00 scs = SDO_CS_ABORT sdo_data = SDO_ABORT_GENERAL # Don't see one specifically for sending not enough data bytes in the CAN msg (malformed SDO msg) sdo_data = sdo_data.to_bytes(4, byteorder='big') n = 4 - len(sdo_data) data = [(scs << SDO_SCS_BITNUM) + (n << SDO_N_BITNUM) + (1 << SDO_E_BITNUM) + (1 << SDO_S_BITNUM), (odi >> 8), (odi & 0xFF), (odsi)] + list(sdo_data) msg = CAN.Message(sdo_server_id, data) self._send(msg) elif fc == FUNCTION_CODE_NMT_ERROR_CONTROL: producer_id = id & 0x7F if producer_id in self._heartbeat_consumer_timers: self._heartbeat_consumer_timers.get( producer_id).cancel() heartbeat_consumer_time_object = self.od.get( ODI_HEARTBEAT_CONSUMER_TIME) if heartbeat_consumer_time_object is not None: heartbeat_consumer_time = heartbeat_consumer_time_object.get( ODSI_HEARTBEAT_CONSUMER_TIME, 0) / 1000 else: heartbeat_consumer_time = 0 if heartbeat_consumer_time != 0: heartbeat_consumer_timer = Timer( heartbeat_consumer_time, self._heartbeat_consumer_timeout, [producer_id]) heartbeat_consumer_timer.start() self._heartbeat_consumer_timers.update( {producer_id: heartbeat_consumer_timer})
def _send_heartbeat(self): msg = CAN.Message( (FUNCTION_CODE_NMT_ERROR_CONTROL << FUNCTION_CODE_BITNUM) + self.id, [self.nmt_state]) self._send(msg)
def _send_bootup(self): msg = CAN.Message(( FUNCTION_CODE_NMT_ERROR_CONTROL << FUNCTION_CODE_BITNUM) + self.id) self._send(msg)
def send_heartbeat(): global active_bus, node_id, nmt_state msg = CAN.Message((CANopen.FUNCTION_CODE_NMT_ERROR_CONTROL << CANopen.FUNCTION_CODE_BITNUM) + node_id, [nmt_state]) active_bus.send(msg)
def send_bootup(): global active_bus, node_id msg = CAN.Message((CANopen.FUNCTION_CODE_NMT_ERROR_CONTROL << CANopen.FUNCTION_CODE_BITNUM) + node_id) active_bus.sendall(msg)
def send_sync(): global active_bus, canopen_od sync_id = canopen_od.get(CANopen.ODI_SYNC).get(CANopen.ODSI_VALUE) & 0x3FF msg = CAN.Message(sync_id) active_bus.send(msg)
) & 1 == 1: data = bytes() for i in range( canopen_od.get( CANopen.ODI_TPDO1_MAPPING_PARAMETER ).get(CANopen.ODSI_VALUE)): mapping = canopen_od.get( CANopen.ODI_TPDO1_MAPPING_PARAMETER ).get(i + 1) data = data + canopen_od.get( mapping >> 16).get( (mapping >> 8) & 0xFF).to_bytes( (mapping & 0xFF) // 8, byteorder='big') msg = CAN.Message( (CANopen.FUNCTION_CODE_TPDO1 << CANopen.FUNCTION_CODE_BITNUM) + node_id, data) active_bus.send(msg) elif fc == CANopen.FUNCTION_CODE_NMT_ERROR_CONTROL: data = [nmt_state] msg = CAN.Message( (CANopen.FUNCTION_CODE_NMT_ERROR_CONTROL << CANopen.FUNCTION_CODE_BITNUM) + node_id, data) active_bus.send(msg) elif fc == CANopen.FUNCTION_CODE_NMT: command = id & 0x7F if command == CANopen.NMT_NODE_CONTROL: target_node = data[1] if target_node == node_id or target_node == CANopen.BROADCAST_NODE_ID: cs = data[0]