Files
seat-firmware/tools/tests/test_no_version_query.py

83 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""Host regression tests against the real v40 CAN dispatch function; no hardware motion."""
from pathlib import Path
import subprocess, tempfile
root=Path(__file__).resolve().parents[2]
source=(root/'firmware/application/seat_demo_compat.inc').read_text()
start=source.index('void SeatDemoCompat_Service(void)')
end=source.index('\nvoid SeatDemoCompat_ReleaseAxisForNative',start)
service=source[start:end]
preamble=r'''
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include "ota_can.h"
#include "seat_legacy_version_query.h"
#define SEAT_DEMO_CAN_COMMAND_ID 0x300
#define SEAT_DEMO_OPCODE_STOP_ALL 9
#define MOTOR_DIRECTION_STOPPED 0
#define SEAT_DEMO_ACK_STOP_ALL_ACCEPTED 1
#define SEAT_DEMO_REJECT_NONE 0
typedef struct { unsigned opcode,motor,direction,sequence; } seat_demo_command_t;
static bool seatDemoInitialized=true,seatDemoCalibrationWorker,seatDemoStopAllFromIsr;
static unsigned seatDemoServiceDepth,seatDemoStopAllSequenceFromIsr;
static bool seatDemoLastSequenceValid,seatDemoLastCommandValid;
static unsigned seatDemoSequenceReference=123;
static seat_demo_command_t seatDemoLastCommand;
static ota_can_frame_t frames[512];
static unsigned frameCount,frameNext,commandCount,thermalFrames,txCount,ackCount;
static unsigned dynamicCalls,taskCalls,dispatchCalls,thermalCalls,feedbackCalls;
static unsigned commands[512];
static uint32_t Cy_SysLib_EnterCriticalSection(void){return 0;}
static void Cy_SysLib_ExitCriticalSection(uint32_t s){(void)s;}
void OtaCan_Service(void){}
bool OtaCan_PopFrame(ota_can_frame_t *frame){if(frameNext==frameCount)return false;*frame=frames[frameNext++];return true;}
bool OtaCan_QueueFrame(uint32_t id,const uint8_t data[8]){(void)id;(void)data;txCount++;return true;}
static void SeatDemoCompat_StopNativeOwnersForAll(void){}
static void SeatDemoCompat_StopAllInternal(uint16_t s){(void)s;}
static void SeatDemoCompat_SetResponse(unsigned a,unsigned b,seat_demo_command_t *c){(void)a;(void)b;(void)c;ackCount++;}
static void SeatDemoCompat_HandleCommand(const ota_can_frame_t *f){commands[commandCount++]=f->data[0];seatDemoSequenceReference=f->data[2]|((unsigned)f->data[3]<<8);}
static void SeatDemoThermal_HandleFrame(const ota_can_frame_t *f){(void)f;thermalFrames++;}
static void SeatDemoDynamic_Service(void){dynamicCalls++;}
static void SeatDemoCompat_ServiceTasks(void){taskCalls++;}
static void SeatDemoCompat_ServiceDispatcher(void){dispatchCalls++;}
static void SeatDemoThermal_Service(void){thermalCalls++;}
static void SeatDemoCompat_ServiceFeedback(void){feedbackCalls++;}
'''
tests=r'''
int main(void){
ota_can_frame_t q={.identifier=0x300,.dlc=8,.data={0x10,0x10,0,0,0,0,0,0}};
assert(!SeatDemo_IsLegacyVersionQuery(NULL));
for(unsigned i=0;i<65536;i++){q.data[2]=i;q.data[3]=i>>8;assert(SeatDemo_IsLegacyVersionQuery(&q));}
for(unsigned opcode=0;opcode<256;opcode++){q.data[0]=opcode;assert(SeatDemo_IsLegacyVersionQuery(&q)==(opcode==0x10));}
q.data[0]=0x10;
for(unsigned i=4;i<8;i++){q.data[i]=1;assert(!SeatDemo_IsLegacyVersionQuery(&q));q.data[i]=0;}
q.identifier=0x6a0;assert(!SeatDemo_IsLegacyVersionQuery(&q));q.identifier=0x300;
q.dlc=7;assert(!SeatDemo_IsLegacyVersionQuery(&q));q.dlc=8;
q.data[1]=0;assert(!SeatDemo_IsLegacyVersionQuery(&q));q.data[1]=0x10;
for(unsigned i=0;i<200;i++)frames[frameCount++]=q;
SeatDemoCompat_Service();
assert(commandCount==0&&txCount==0&&ackCount==0&&seatDemoSequenceReference==123);
assert(dynamicCalls==1&&taskCalls==1&&dispatchCalls==1&&thermalCalls==1&&feedbackCalls==1);
assert(seatDemoServiceDepth==0);
frameNext=frameCount=0;
unsigned ops[]={1,3,9,0x0c,0x0e,0x0f};
for(unsigned i=0;i<sizeof(ops)/sizeof(*ops);i++){
frames[frameCount++]=q;
ota_can_frame_t command=q;command.data[0]=ops[i];command.data[2]=i+1;command.data[3]=0;
frames[frameCount++]=command;
}
ota_can_frame_t thermal=q;thermal.identifier=0x29e;frames[frameCount++]=thermal;
SeatDemoCompat_Service();
assert(commandCount==6&&thermalFrames==1&&seatDemoSequenceReference==6&&txCount==0);
for(unsigned i=0;i<6;i++)assert(commands[i]==ops[i]);
assert(dynamicCalls==2&&taskCalls==2&&dispatchCalls==2&&thermalCalls==2&&feedbackCalls==2);
puts("PASS: 65536 legacy query sequences ignored; no query TX/ACK/sequence changes; mixed motion/STOP/dynamic/thermal frames retain routing and feedback service");
}
'''
with tempfile.TemporaryDirectory(prefix='n7-v40-query-') as tmp:
c=Path(tmp)/'test.c';exe=Path(tmp)/'test'
c.write_text(preamble+service+tests)
subprocess.run(['gcc','-std=c11','-Wall','-Wextra','-Werror','-I'+str(root/'firmware/bootloader/src'),'-I'+str(root/'firmware/application'),str(c),'-o',str(exe)],check=True)
subprocess.run([str(exe)],check=True)