Client for Qt's VirtualCAN TCP server. Protocol: Text-based format per Qt VirtualCAN spec: can : # # \n CAN-ID is sent as DECIMAL (not hex!): 0x100 → "can0:256##data" (256 decimal = 0x100 hex) Flags (optional): R - Remote Request
| 222 | |
| 223 | |
| 224 | class QtVirtualCANClient: |
| 225 | """ |
| 226 | Client for Qt's VirtualCAN TCP server. |
| 227 | |
| 228 | Protocol: Text-based format per Qt VirtualCAN spec: |
| 229 | can<channel>:<CAN-ID>#<flags>#<hex-data>\n |
| 230 | |
| 231 | CAN-ID is sent as DECIMAL (not hex!): |
| 232 | 0x100 → "can0:256##data" (256 decimal = 0x100 hex) |
| 233 | |
| 234 | Flags (optional): |
| 235 | R - Remote Request |
| 236 | X - Extended Frame Format |
| 237 | F - Flexible Data Rate (CAN FD) |
| 238 | B - Bitrate Switch |
| 239 | E - Error State Indicator |
| 240 | L - Local Echo |
| 241 | |
| 242 | Example: "can0:256##0102030405060708\n" (CAN ID 0x100, no flags) |
| 243 | """ |
| 244 | |
| 245 | def __init__( |
| 246 | self, host: str = "localhost", port: int = 35468, channel: str = "can0" |
| 247 | ): |
| 248 | """Initialize VirtualCAN client.""" |
| 249 | self.host = host |
| 250 | self.port = port |
| 251 | self.channel = channel |
| 252 | self.sock: Optional[socket.socket] = None |
| 253 | |
| 254 | def connect(self) -> bool: |
| 255 | """Connect to Qt VirtualCAN TCP server.""" |
| 256 | try: |
| 257 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 258 | self.sock.connect((self.host, self.port)) |
| 259 | print(f"Connected to Qt VirtualCAN: {self.host}:{self.port}/{self.channel}") |
| 260 | return True |
| 261 | except Exception as e: |
| 262 | print(f"Failed to connect to Qt VirtualCAN") |
| 263 | print(f"Error: {e}") |
| 264 | print("\nTroubleshooting:") |
| 265 | print(" - Start Serial Studio first") |
| 266 | print(" - Select VirtualCAN driver") |
| 267 | print(f" - Connect to interface: {self.channel}") |
| 268 | print(" - Then run this simulator") |
| 269 | return False |
| 270 | |
| 271 | def disconnect(self): |
| 272 | """Disconnect from server.""" |
| 273 | if self.sock: |
| 274 | self.sock.close() |
| 275 | self.sock = None |
| 276 | |
| 277 | def send_frame(self, can_id: int, data: bytes): |
| 278 | """ |
| 279 | Send CAN frame to VirtualCAN server. |
| 280 | |
| 281 | Uses Qt VirtualCAN text protocol: |
no outgoing calls
no test coverage detected