mirror of
https://github.com/infiniteCable2/panda.git
synced 2026-06-08 07:45:00 +08:00
Merge branch 'upstream/panda/master' into sync-20260401
This commit is contained in:
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@@ -114,7 +114,7 @@ pipeline {
|
|||||||
["build", "scons"],
|
["build", "scons"],
|
||||||
["flash", "cd scripts/ && ./reflash_internal_panda.py"],
|
["flash", "cd scripts/ && ./reflash_internal_panda.py"],
|
||||||
["flash jungle", "cd board/jungle && ./flash.py --all"],
|
["flash jungle", "cd board/jungle && ./flash.py --all"],
|
||||||
["test", "cd tests/hitl && pytest --durations=0 2*.py [5-9]*.py"],
|
["test", "cd tests/hitl && pytest -o 'addopts=' --durations=0 2*.py [5-9]*.py"],
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ pipeline {
|
|||||||
["build", "scons"],
|
["build", "scons"],
|
||||||
["flash", "cd scripts/ && ./reflash_internal_panda.py"],
|
["flash", "cd scripts/ && ./reflash_internal_panda.py"],
|
||||||
["flash jungle", "cd board/jungle && ./flash.py --all"],
|
["flash jungle", "cd board/jungle && ./flash.py --all"],
|
||||||
["test", "cd tests/hitl && pytest --durations=0 2*.py [5-9]*.py"],
|
["test", "cd tests/hitl && pytest -o 'addopts=' --durations=0 2*.py [5-9]*.py"],
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import hashlib
|
||||||
import opendbc
|
import opendbc
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
@@ -150,6 +151,14 @@ with open("board/obj/cert.h", "w") as f:
|
|||||||
for cert in certs:
|
for cert in certs:
|
||||||
f.write("\n".join(cert) + "\n")
|
f.write("\n".join(cert) + "\n")
|
||||||
|
|
||||||
|
# Packet version defines: SHA hash of the struct header files
|
||||||
|
def version_hash(path):
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
return int.from_bytes(hashlib.sha256(f.read()).digest()[:4], 'little')
|
||||||
|
hh, ch, jh = version_hash("board/health.h"), version_hash(os.path.join(opendbc.INCLUDE_PATH, "opendbc/safety/can.h")), version_hash("board/jungle/jungle_health.h")
|
||||||
|
common_flags += [f"-DHEALTH_PACKET_VERSION=0x{hh:08X}U", f"-DCAN_PACKET_VERSION_HASH=0x{ch:08X}U",
|
||||||
|
f"-DJUNGLE_HEALTH_PACKET_VERSION=0x{jh:08X}U"]
|
||||||
|
|
||||||
# panda fw
|
# panda fw
|
||||||
build_project("panda_h7", base_project_h7, "./board/main.c", [])
|
build_project("panda_h7", base_project_h7, "./board/main.c", [])
|
||||||
|
|
||||||
|
|||||||
@@ -89,13 +89,13 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// **** 0xdd: get healthpacket and CANPacket versions
|
// **** 0xdd: get healthpacket and CANPacket version hashes
|
||||||
case 0xdd:
|
case 0xdd: {
|
||||||
resp[0] = HEALTH_PACKET_VERSION;
|
uint32_t versions[2] = {HEALTH_PACKET_VERSION, CAN_PACKET_VERSION_HASH};
|
||||||
resp[1] = CAN_PACKET_VERSION;
|
(void)memcpy(resp, (uint8_t *)versions, sizeof(versions));
|
||||||
resp[2] = CAN_HEALTH_PACKET_VERSION;
|
resp_len = sizeof(versions);
|
||||||
resp_len = 3U;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Ignore unhandled requests
|
// Ignore unhandled requests
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// When changing these structs, python/__init__.py needs to be kept up to date!
|
|
||||||
|
|
||||||
#define HEALTH_PACKET_VERSION 18
|
|
||||||
struct __attribute__((packed)) health_t {
|
struct __attribute__((packed)) health_t {
|
||||||
uint32_t uptime_pkt;
|
uint32_t uptime_pkt;
|
||||||
uint32_t voltage_pkt;
|
uint32_t voltage_pkt;
|
||||||
@@ -32,7 +29,6 @@ struct __attribute__((packed)) health_t {
|
|||||||
uint16_t sound_output_level_pkt;
|
uint16_t sound_output_level_pkt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CAN_HEALTH_PACKET_VERSION 5
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint8_t bus_off;
|
uint8_t bus_off;
|
||||||
uint32_t bus_off_cnt;
|
uint32_t bus_off_cnt;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import struct
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from panda import Panda, PandaDFU
|
from panda import Panda, PandaDFU
|
||||||
from panda.python.constants import McuType
|
from panda.python.constants import McuType, compute_version_hash
|
||||||
|
|
||||||
BASEDIR = os.path.dirname(os.path.realpath(__file__))
|
BASEDIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
FW_PATH = os.path.join(BASEDIR, "../obj/")
|
FW_PATH = os.path.join(BASEDIR, "../obj/")
|
||||||
@@ -39,7 +39,7 @@ class PandaJungle(Panda):
|
|||||||
H7_DEVICES = [HW_TYPE_V2, ]
|
H7_DEVICES = [HW_TYPE_V2, ]
|
||||||
SUPPORTED_DEVICES = H7_DEVICES
|
SUPPORTED_DEVICES = H7_DEVICES
|
||||||
|
|
||||||
HEALTH_PACKET_VERSION = 1
|
HEALTH_PACKET_VERSION = compute_version_hash(os.path.join(BASEDIR, "jungle_health.h"))
|
||||||
HEALTH_STRUCT = struct.Struct("<IffffffHHHHHHHHHHHH")
|
HEALTH_STRUCT = struct.Struct("<IffffffHHHHHHHHHHHH")
|
||||||
|
|
||||||
HARNESS_ORIENTATION_NONE = 0
|
HARNESS_ORIENTATION_NONE = 0
|
||||||
@@ -108,13 +108,11 @@ class PandaJungle(Panda):
|
|||||||
|
|
||||||
# ******************* control *******************
|
# ******************* control *******************
|
||||||
|
|
||||||
# Returns tuple with health packet version and CAN packet/USB packet version
|
|
||||||
def get_packets_versions(self):
|
def get_packets_versions(self):
|
||||||
dat = self._handle.controlRead(PandaJungle.REQUEST_IN, 0xdd, 0, 0, 3)
|
dat = self._handle.controlRead(PandaJungle.REQUEST_IN, 0xdd, 0, 0, 8)
|
||||||
if dat and len(dat) == 3:
|
if dat and len(dat) == 8:
|
||||||
a = struct.unpack("BBB", dat)
|
return struct.unpack("<II", dat)
|
||||||
return (a[0], a[1], a[2])
|
return (0, 0)
|
||||||
return (-1, -1, -1)
|
|
||||||
|
|
||||||
# ******************* jungle stuff *******************
|
# ******************* jungle stuff *******************
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// When changing these structs, python/__init__.py needs to be kept up to date!
|
|
||||||
|
|
||||||
#define JUNGLE_HEALTH_PACKET_VERSION 1
|
|
||||||
struct __attribute__((packed)) jungle_health_t {
|
struct __attribute__((packed)) jungle_health_t {
|
||||||
uint32_t uptime_pkt;
|
uint32_t uptime_pkt;
|
||||||
float ch1_power;
|
float ch1_power;
|
||||||
|
|||||||
@@ -180,13 +180,13 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
|||||||
current_board->set_can_mode(CAN_MODE_NORMAL);
|
current_board->set_can_mode(CAN_MODE_NORMAL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// **** 0xdd: get healthpacket and CANPacket versions
|
// **** 0xdd: get healthpacket and CANPacket version hashes
|
||||||
case 0xdd:
|
case 0xdd: {
|
||||||
resp[0] = JUNGLE_HEALTH_PACKET_VERSION;
|
uint32_t versions[2] = {JUNGLE_HEALTH_PACKET_VERSION, CAN_PACKET_VERSION_HASH};
|
||||||
resp[1] = CAN_PACKET_VERSION;
|
(void)memcpy(resp, (uint8_t *)versions, sizeof(versions));
|
||||||
resp[2] = CAN_HEALTH_PACKET_VERSION;
|
resp_len = sizeof(versions);
|
||||||
resp_len = 3;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// **** 0xde: set can bitrate
|
// **** 0xde: set can bitrate
|
||||||
case 0xde:
|
case 0xde:
|
||||||
if ((req->param1 < PANDA_CAN_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) {
|
if ((req->param1 < PANDA_CAN_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) {
|
||||||
|
|||||||
@@ -226,13 +226,13 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
|||||||
case 0xdc:
|
case 0xdc:
|
||||||
set_safety_mode(req->param1, (uint16_t)req->param2);
|
set_safety_mode(req->param1, (uint16_t)req->param2);
|
||||||
break;
|
break;
|
||||||
// **** 0xdd: get healthpacket and CANPacket versions
|
// **** 0xdd: get health and CAN packet versions
|
||||||
case 0xdd:
|
case 0xdd: {
|
||||||
resp[0] = HEALTH_PACKET_VERSION;
|
uint32_t versions[2] = {HEALTH_PACKET_VERSION, CAN_PACKET_VERSION_HASH};
|
||||||
resp[1] = CAN_PACKET_VERSION;
|
(void)memcpy(resp, (uint8_t *)versions, sizeof(versions));
|
||||||
resp[2] = CAN_HEALTH_PACKET_VERSION;
|
resp_len = sizeof(versions);
|
||||||
resp_len = 3;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// **** 0xde: set can bitrate
|
// **** 0xde: set can bitrate
|
||||||
case 0xde:
|
case 0xde:
|
||||||
if ((req->param1 < PANDA_CAN_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) {
|
if ((req->param1 < PANDA_CAN_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) {
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ dev = [
|
|||||||
"pytest-timeout",
|
"pytest-timeout",
|
||||||
"ruff",
|
"ruff",
|
||||||
"setuptools",
|
"setuptools",
|
||||||
"gcc-arm-none-eabi @ git+https://github.com/commaai/dependencies.git@releases#subdirectory=gcc-arm-none-eabi",
|
"gcc-arm-none-eabi @ git+https://github.com/commaai/dependencies.git@release-gcc-arm-none-eabi#subdirectory=gcc-arm-none-eabi",
|
||||||
"cppcheck @ git+https://github.com/commaai/dependencies.git@releases#subdirectory=cppcheck",
|
"cppcheck @ git+https://github.com/commaai/dependencies.git@release-cppcheck#subdirectory=cppcheck",
|
||||||
]
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
@@ -49,6 +49,10 @@ packages = [
|
|||||||
"panda.board.jungle",
|
"panda.board.jungle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.setuptools.package-data]
|
||||||
|
"panda.board" = ["health.h"]
|
||||||
|
"panda.board.jungle" = ["jungle_health.h"]
|
||||||
|
|
||||||
[tool.setuptools.package-dir]
|
[tool.setuptools.package-dir]
|
||||||
panda = "."
|
panda = "."
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import ctypes
|
|||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
from itertools import accumulate
|
from itertools import accumulate
|
||||||
|
|
||||||
|
import opendbc
|
||||||
from opendbc.car.structs import CarParams
|
from opendbc.car.structs import CarParams
|
||||||
|
|
||||||
from .base import BaseHandle
|
from .base import BaseHandle
|
||||||
from .constants import FW_PATH, McuType
|
from .constants import BASEDIR, FW_PATH, McuType, compute_version_hash
|
||||||
from .dfu import PandaDFU
|
from .dfu import PandaDFU
|
||||||
from .spi import PandaSpiHandle, PandaSpiException, PandaProtocolMismatch
|
from .spi import PandaSpiHandle, PandaSpiException, PandaProtocolMismatch
|
||||||
from .usb import PandaUsbHandle
|
from .usb import PandaUsbHandle
|
||||||
@@ -104,7 +105,6 @@ def ensure_version(desc, lib_field, panda_field, fn):
|
|||||||
return fn(self, *args, **kwargs)
|
return fn(self, *args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
ensure_can_packet_version = partial(ensure_version, "CAN", "CAN_PACKET_VERSION", "can_version")
|
ensure_can_packet_version = partial(ensure_version, "CAN", "CAN_PACKET_VERSION", "can_version")
|
||||||
ensure_can_health_packet_version = partial(ensure_version, "CAN health", "CAN_HEALTH_PACKET_VERSION", "can_health_version")
|
|
||||||
ensure_health_packet_version = partial(ensure_version, "health", "HEALTH_PACKET_VERSION", "health_version")
|
ensure_health_packet_version = partial(ensure_version, "health", "HEALTH_PACKET_VERSION", "health_version")
|
||||||
|
|
||||||
|
|
||||||
@@ -126,9 +126,8 @@ class Panda:
|
|||||||
HW_TYPE_CUATRO = b'\x0a'
|
HW_TYPE_CUATRO = b'\x0a'
|
||||||
HW_TYPE_BODY = b'\xb1'
|
HW_TYPE_BODY = b'\xb1'
|
||||||
|
|
||||||
CAN_PACKET_VERSION = 4
|
CAN_PACKET_VERSION = compute_version_hash(os.path.join(opendbc.INCLUDE_PATH, "opendbc/safety/can.h"))
|
||||||
HEALTH_PACKET_VERSION = 18
|
HEALTH_PACKET_VERSION = compute_version_hash(os.path.join(BASEDIR, "board/health.h"))
|
||||||
CAN_HEALTH_PACKET_VERSION = 5
|
|
||||||
HEALTH_STRUCT = struct.Struct("<IIIIIIIIBBBBBHBBBHfBBHHHBH")
|
HEALTH_STRUCT = struct.Struct("<IIIIIIIIBBBBBHBBBHfBBHHHBH")
|
||||||
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIIHHBBBIIII")
|
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIIHHBBBIIII")
|
||||||
|
|
||||||
@@ -210,7 +209,7 @@ class Panda:
|
|||||||
self._serial = serial
|
self._serial = serial
|
||||||
self._connect_serial = serial
|
self._connect_serial = serial
|
||||||
self._handle_open = True
|
self._handle_open = True
|
||||||
self.health_version, self.can_version, self.can_health_version = self.get_packets_versions()
|
self.health_version, self.can_version = self.get_packets_versions()
|
||||||
logger.debug("connected")
|
logger.debug("connected")
|
||||||
|
|
||||||
# disable openpilot's heartbeat checks
|
# disable openpilot's heartbeat checks
|
||||||
@@ -536,7 +535,7 @@ class Panda:
|
|||||||
"sound_output_level": a[25],
|
"sound_output_level": a[25],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ensure_can_health_packet_version
|
@ensure_health_packet_version
|
||||||
def can_health(self, can_number):
|
def can_health(self, can_number):
|
||||||
LEC_ERROR_CODE = {
|
LEC_ERROR_CODE = {
|
||||||
0: "No error",
|
0: "No error",
|
||||||
@@ -598,14 +597,11 @@ class Panda:
|
|||||||
def get_type(self):
|
def get_type(self):
|
||||||
return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
|
return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
|
||||||
|
|
||||||
# Returns tuple with health packet version and CAN packet/USB packet version
|
|
||||||
def get_packets_versions(self):
|
def get_packets_versions(self):
|
||||||
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xdd, 0, 0, 3)
|
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xdd, 0, 0, 8)
|
||||||
if dat and len(dat) == 3:
|
if dat and len(dat) == 8:
|
||||||
a = struct.unpack("BBB", dat)
|
return struct.unpack("<II", dat)
|
||||||
return (a[0], a[1], a[2])
|
return (0, 0)
|
||||||
else:
|
|
||||||
return (0, 0, 0)
|
|
||||||
|
|
||||||
def is_internal(self):
|
def is_internal(self):
|
||||||
return self.get_type() in Panda.INTERNAL_DEVICES
|
return self.get_type() in Panda.INTERNAL_DEVICES
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import os
|
import os
|
||||||
import enum
|
import enum
|
||||||
|
import hashlib
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
|
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
|
||||||
FW_PATH = os.path.join(BASEDIR, "board/obj/")
|
FW_PATH = os.path.join(BASEDIR, "board/obj/")
|
||||||
|
|
||||||
|
def compute_version_hash(filepath):
|
||||||
|
with open(filepath, "rb") as f:
|
||||||
|
return int.from_bytes(hashlib.sha256(f.read()).digest()[:4], 'little')
|
||||||
|
|
||||||
USBPACKET_MAX_SIZE = 0x40
|
USBPACKET_MAX_SIZE = 0x40
|
||||||
|
|
||||||
class McuConfig(NamedTuple):
|
class McuConfig(NamedTuple):
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ def pytest_configure(config):
|
|||||||
config.addinivalue_line(
|
config.addinivalue_line(
|
||||||
"markers", "panda_expect_can_error: mark test to ignore CAN health errors"
|
"markers", "panda_expect_can_error: mark test to ignore CAN health errors"
|
||||||
)
|
)
|
||||||
|
config.addinivalue_line(
|
||||||
|
"markers", "timeout: set test timeout in seconds"
|
||||||
|
)
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
@pytest.hookimpl(tryfirst=True)
|
||||||
def pytest_collection_modifyitems(items):
|
def pytest_collection_modifyitems(items):
|
||||||
|
|||||||
Reference in New Issue
Block a user