Добавить загрузку F28335 по ProtoCAN и сервисные команды клиента
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
#ifndef TEST_DSP_H
|
||||
#define TEST_DSP_H
|
||||
#include <stdint.h>
|
||||
#define EALLOW
|
||||
#define EDIS
|
||||
struct test_reg { uint32_t all; struct { unsigned DLC, RTR; } bit; };
|
||||
struct MBOX { struct test_reg MSGID, MSGCTRL, MDL, MDH; };
|
||||
static struct { struct MBOX MBOX3, MBOX4, MBOX6; } ECanaMboxes;
|
||||
static struct { struct test_reg CANME,CANMD,CANRMP,CANRML,CANMIM,CANTA,CANAA,CANTRS,CANTRR; } ECanaRegs;
|
||||
static struct { struct test_reg LAM3,LAM6; } ECanaLAMRegs;
|
||||
static struct { unsigned long InterruptCount; } CpuTimer1;
|
||||
static struct { unsigned WDCR; } SysCtrlRegs;
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#ifndef EEPROM_M95M02
|
||||
#define EEPROM_M95M02 1
|
||||
#endif
|
||||
#define BALSAM167_EEPROM_FIRMWARE_BYTES 261884UL
|
||||
void Seeprom_write(unsigned long word, unsigned int *data, unsigned long bytes);
|
||||
void Seeprom_read(unsigned long word, unsigned int *data, unsigned long bytes);
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Host regression suite. CC may point to clang/gcc; this does not replace a TI build."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
cc = os.environ.get('CC') or shutil.which('clang') or shutil.which('gcc')
|
||||
if not cc:
|
||||
raise SystemExit('Set CC to a C99 host compiler')
|
||||
store = 'ports/tms320f28335/f28335_boot_store.c'
|
||||
cases = [
|
||||
('core', [], ['src/pcan_boot.c', 'tests/test_pcan_boot.c']),
|
||||
('store_native', [], [store, 'tests/test_f28335_boot_store.c']),
|
||||
('store_wide', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'tests/test_f28335_boot_store.c']),
|
||||
('loader', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']),
|
||||
('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'],
|
||||
[store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']),
|
||||
]
|
||||
with tempfile.TemporaryDirectory(prefix='f28335-ab-') as tmp:
|
||||
for name, defines, sources in cases:
|
||||
exe = Path(tmp) / (name + '.exe')
|
||||
subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Iinclude',
|
||||
'-Itests/f28335_stubs', *defines, *sources, '-o', str(exe)], cwd=root, check=True)
|
||||
sample = os.environ.get('F28335_SAMPLE_IMAGE') if name == 'store_wide' else None
|
||||
subprocess.run([str(exe), *([sample] if sample else [])], check=True, timeout=30)
|
||||
@@ -0,0 +1,118 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include "../ports/tms320f28335/f28335_boot_store.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
static unsigned char eeprom[0x40000],backup[0x40000];
|
||||
static long budget=-1;
|
||||
static int read_fail;
|
||||
static unsigned written_words;
|
||||
static bool read_mem(void *u,uint32_t addr,pcan_boot_byte_t *p,unsigned int n)
|
||||
{ unsigned i; (void)u; assert(addr+n<=sizeof(eeprom)); if(read_fail) return false;
|
||||
for(i=0;i<n;++i) p[i]=eeprom[addr+i]; return true; }
|
||||
static bool write_mem(void *u,uint32_t addr,const pcan_boot_byte_t *p,unsigned int n)
|
||||
{ unsigned i; (void)u; assert(addr+n<=0x3FE00);
|
||||
for(i=0;i<n;++i) { if(budget==0) return false; if(budget>0) --budget; eeprom[addr+i]=(unsigned char)p[i]; }
|
||||
return true; }
|
||||
static f28335_boot_io_t io={read_mem,write_mem,0};
|
||||
static pcan_boot_byte_t image[40];
|
||||
static pcan_boot_manifest_t manifest;
|
||||
static void make_image(void)
|
||||
{
|
||||
memset(image,0,sizeof(image)); image[0]=0xAA; image[1]=8;
|
||||
image[20]=0; image[21]=0x80; /* entry=8000, high-word first */
|
||||
image[22]=5; image[26]=0; image[27]=0x80;
|
||||
image[28]=0x34; image[29]=0x12;
|
||||
memset(&manifest,0,sizeof(manifest)); manifest.product_type=0x2833;
|
||||
manifest.hardware_revision_min=manifest.hardware_revision_max=1;
|
||||
manifest.image_size=40; manifest.image_crc32=f28335_boot_crc(0,image,40);
|
||||
manifest.firmware_version=0x01010002;
|
||||
}
|
||||
static void image_to(f28335_boot_store_t *s,unsigned slot)
|
||||
{ unsigned i; assert(f28335_boot_prepare(s,slot));
|
||||
for(i=0;i<40;i+=8) assert(f28335_boot_write(s,slot,i,image+i,8)); }
|
||||
static bool ram(void *u,uint32_t address,uint16_t word)
|
||||
{ (void)u; assert(address==0x8000+written_words); if(!written_words) assert(word==0x1234);
|
||||
++written_words; return true; }
|
||||
static void reopen(f28335_boot_store_t *s) { assert(f28335_boot_open(s,&io)); }
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
f28335_boot_store_t s; unsigned slot; uint32_t entry; long cut;
|
||||
memset(eeprom,0xA5,sizeof(eeprom)); make_image(); reopen(&s);
|
||||
assert(s.active==255 && !s.valid); assert(f28335_boot_select(&s,&slot) && slot==255);
|
||||
image_to(&s,0); assert(f28335_boot_verify(&s,0,&manifest,&entry) && entry==0x8000);
|
||||
assert(f28335_boot_commit(&s,0,&manifest));
|
||||
assert(!f28335_boot_confirm(&s,0)); /* Cannot confirm an image not yet started. */
|
||||
reopen(&s); assert(f28335_boot_select(&s,&slot) && slot==0 && s.attempted);
|
||||
assert(f28335_boot_load(&s,slot,ram,0,&entry) && written_words==5);
|
||||
assert(!f28335_boot_confirm(&s,1)); assert(f28335_boot_confirm(&s,0));
|
||||
assert(f28335_boot_confirm(&s,0)); /* idempotent */
|
||||
assert(!f28335_boot_prepare(&s,0));
|
||||
assert(!f28335_boot_write(&s,0,0,image,8));
|
||||
assert(!f28335_boot_write(&s,1,F28335_AB_SLOT_BYTES,image,8));
|
||||
image_to(&s,1); memcpy(backup,eeprom,sizeof(eeprom));
|
||||
/* Every torn write position in journal publication keeps confirmed A. */
|
||||
for(cut=0;cut<=68;++cut) {
|
||||
memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut;
|
||||
(void)f28335_boot_commit(&s,1,&manifest); budget=-1; reopen(&s);
|
||||
assert(s.active==0); assert(f28335_boot_verify(&s,0,&s.image[0],0));
|
||||
assert(s.pending==255 || s.pending==1);
|
||||
}
|
||||
memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); assert(f28335_boot_commit(&s,1,&manifest));
|
||||
memcpy(backup,eeprom,sizeof(eeprom));
|
||||
/* Torn trial bookkeeping must never select an unrecorded trial. */
|
||||
for(cut=0;cut<=68;++cut) {
|
||||
memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut;
|
||||
if(f28335_boot_select(&s,&slot)) { assert(slot==1); assert(s.attempted); }
|
||||
budget=-1; reopen(&s); assert(s.active==0);
|
||||
}
|
||||
memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s);
|
||||
assert(f28335_boot_select(&s,&slot) && slot==1);
|
||||
reopen(&s); assert(f28335_boot_select(&s,&slot) && slot==0 && s.pending==255);
|
||||
image_to(&s,1); assert(f28335_boot_commit(&s,1,&manifest));
|
||||
assert(f28335_boot_select(&s,&slot) && slot==1);
|
||||
memcpy(backup,eeprom,sizeof(eeprom));
|
||||
for(cut=0;cut<=68;++cut) {
|
||||
memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut;
|
||||
(void)f28335_boot_confirm(&s,1); budget=-1; reopen(&s);
|
||||
assert(s.active==0 || s.active==1);
|
||||
assert(f28335_boot_select(&s,&slot) && (slot==0 || slot==1));
|
||||
}
|
||||
memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); assert(f28335_boot_confirm(&s,1));
|
||||
/* CRC correct but malicious SCI8 destination and entry are rejected. */
|
||||
image_to(&s,0); image[26]=0; image[27]=0xE0;
|
||||
manifest.image_crc32=f28335_boot_crc(0,image,40);
|
||||
image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0));
|
||||
image[27]=0x80; image[21]=0x90; manifest.image_crc32=f28335_boot_crc(0,image,40);
|
||||
image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0));
|
||||
make_image(); image[22]=1; image[30]=1; image[35]=0x80;
|
||||
manifest.image_crc32=f28335_boot_crc(0,image,40);
|
||||
image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); /* overlapping sections */
|
||||
make_image(); image_to(&s,0); manifest.image_size=38;
|
||||
manifest.image_crc32=f28335_boot_crc(0,image,38);
|
||||
assert(!f28335_boot_verify(&s,0,&manifest,0)); /* missing terminator */
|
||||
make_image(); image[22]=4; manifest.image_crc32=f28335_boot_crc(0,image,40);
|
||||
image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); /* trailing octets */
|
||||
make_image(); image_to(&s,0); eeprom[F28335_AB_SLOT_A+29]^=1;
|
||||
assert(!f28335_boot_verify(&s,0,&manifest,0));
|
||||
/* Failed EEPROM reads fail closed, including subsequent writes. */
|
||||
read_fail=1; assert(!f28335_boot_open(&s,&io));
|
||||
assert(!f28335_boot_prepare(&s,0)); assert(!f28335_boot_write(&s,0,0,image,8)); read_fail=0;
|
||||
for(entry=0x3FE00;entry<0x40000;++entry) assert(eeprom[entry]==0xA5);
|
||||
if(argc>1) {
|
||||
FILE *file=fopen(argv[1],"rb"); uint32_t offset,crc=0;
|
||||
pcan_boot_byte_t bytes[32]; unsigned n;
|
||||
assert(file); make_image();
|
||||
manifest.image_size=(uint32_t)fread(eeprom+F28335_AB_SLOT_A,1,F28335_AB_SLOT_BYTES,file);
|
||||
assert(!ferror(file) && fgetc(file)==EOF); fclose(file); reopen(&s);
|
||||
for(offset=0;offset<manifest.image_size;offset+=n) {
|
||||
n=manifest.image_size-offset<32?(unsigned)(manifest.image_size-offset):32;
|
||||
assert(read_mem(0,F28335_AB_SLOT_A+offset,bytes,n)); crc=f28335_boot_crc(crc,bytes,n);
|
||||
}
|
||||
manifest.image_crc32=crc;
|
||||
assert(f28335_boot_verify(&s,0,&manifest,&entry));
|
||||
puts("Production SCI8 binary: CRC, destinations and entry accepted");
|
||||
}
|
||||
puts("F28335 A/B: journal power cuts, trial, rollback, confirm, bounds, SCI8: OK");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Production CAN adapter, fake hardware, wide C28x wire octets. */
|
||||
#define EEPROM_M95M02 1
|
||||
#ifndef F28335_BOOT_LOADER
|
||||
#define F28335_BOOT_LOADER 1
|
||||
#endif
|
||||
#define F28335_CAN_BOOT_FIRMWARE_VERSION 0x12345678UL
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
void ServiceDog(void);
|
||||
#include "../ports/tms320f28335/f28335_can_boot.c"
|
||||
static unsigned char memory[0x40000];
|
||||
static unsigned int running=255,resets,reset_arg,dog_feeds;
|
||||
static int fail_write;
|
||||
void ServiceDog(void) { ++dog_feeds; }
|
||||
bool F28335Boot_Read(void *u,uint32_t a,pcan_boot_byte_t *p,unsigned int n)
|
||||
{ unsigned i; (void)u; assert(a+n<=sizeof(memory)); for(i=0;i<n;++i)p[i]=memory[a+i]; return true; }
|
||||
bool F28335Boot_Write(void *u,uint32_t a,const pcan_boot_byte_t *p,unsigned int n)
|
||||
{ unsigned i; (void)u; assert(a+n<=0x3FE00); if(fail_write)return false;
|
||||
for(i=0;i<n;++i)memory[a+i]=(unsigned char)p[i]; return true; }
|
||||
uint32_t F28335Boot_Now(void) { return CpuTimer1.InterruptCount; }
|
||||
unsigned int F28335Boot_RunningSlot(void) { return running; }
|
||||
void F28335Boot_Reset(unsigned int session) { ++resets;reset_arg=session;reset_requested=0; }
|
||||
static void command(unsigned cmd,const pcan_boot_byte_t *d,unsigned n)
|
||||
{ tx_busy=0; assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,7,9,0x100|cmd),d,n)); }
|
||||
static void put32(pcan_boot_byte_t *p,uint32_t v)
|
||||
{ unsigned i;for(i=0;i<4;++i)p[i]=(v>>(i*8))&255; }
|
||||
int main(void)
|
||||
{
|
||||
pcan_boot_byte_t image[40]={0xAA,8},meta[8],compat[8]={0x33,0x28,1,1,2,0,1,1};
|
||||
unsigned i,slot; pcan_boot_manifest_t m;
|
||||
memset(memory,0xA5,sizeof(memory)); image[21]=0x80; image[22]=5; image[27]=0x80;
|
||||
F28335CanBoot_Init(); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2);
|
||||
if(!F28335_BOOT_LOADER) {
|
||||
/* SPI-ROM application without Flash-loader handoff cannot erase anything. */
|
||||
command(2,0,0); assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE && !reset_requested);
|
||||
memset(&m,0,sizeof(m));m.image_size=40;m.image_crc32=f28335_boot_crc(0,image,40);
|
||||
m.product_type=0x2833;m.hardware_revision_min=m.hardware_revision_max=1;
|
||||
assert(f28335_boot_prepare(&store,0));
|
||||
for(i=0;i<40;i+=8)assert(f28335_boot_write(&store,0,i,image+i,8));
|
||||
assert(f28335_boot_commit(&store,0,&m)); assert(f28335_boot_select(&store,&slot));
|
||||
running=0; F28335CanBoot_Init();
|
||||
assert(!F28335CanBoot_WatchdogAllowed());
|
||||
command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE);
|
||||
F28335CanBoot_Ready();
|
||||
for(i=0;i<100;++i) F28335CanBoot_Service();
|
||||
assert(!confirmed && store.pending==0);
|
||||
CpuTimer1.InterruptCount=5000; F28335CanBoot_Service();
|
||||
assert(confirmed && store.active==0 && dog_feeds);
|
||||
command(2,0,0); assert(reset_requested && reset_session==1 && boot.state==PCAN_BOOT_STATE_IDLE);
|
||||
F28335CanBoot_Service();assert(resets==1 && reset_arg==1);
|
||||
command(1,0,0);assert(ECanaMboxes.MBOX4.MDH.all==0x12345678UL);
|
||||
} else {
|
||||
command(2,0,0); put32(meta,40);put32(meta+4,f28335_boot_crc(0,image,40));
|
||||
command(3,meta,8);command(4,compat,8);assert(boot.target_slot==0);
|
||||
command(5,0,0);
|
||||
for(i=0;i<5;++i) { tx_busy=0; assert(pcan_boot_process(&boot,
|
||||
pcan_boot_make_id(1,0,3,7,10,i),image+i*8,8)); }
|
||||
command(6,0,0);assert(boot.state==PCAN_BOOT_STATE_VERIFIED);
|
||||
command(7,0,0);assert(store.pending==0 && boot.state==PCAN_BOOT_STATE_COMMITTED);
|
||||
command(7,0,0);assert(boot.last_status==0);
|
||||
command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE);
|
||||
command(9,0,0);assert(reset_requested);tx_busy=0;
|
||||
F28335CanBoot_Service();assert(resets==1 && reset_arg==0);
|
||||
command(10,0,0);command(2,0,0);command(3,meta,8);command(4,compat,8);
|
||||
command(5,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_FLASH_ERROR); /* Pending is protected. */
|
||||
}
|
||||
command(12,0,0); assert((ECanaMboxes.MBOX4.MSGID.all&65535)==12);
|
||||
command(13,0,0); assert(ECanaMboxes.MBOX4.MDH.all==130560);
|
||||
meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x33383246UL); /* F283 */
|
||||
meta[0]=3;command(15,meta,1);assert(ECanaMboxes.MBOX4.MDL.all==0x3FEFCUL);
|
||||
assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,6,9,0x102),0,0));
|
||||
tx_busy=0;
|
||||
assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),0,0));
|
||||
assert(boot.discovery_pending); pcan_boot_poll(&boot,boot.discovery_at);
|
||||
assert(!boot.discovery_pending && (ECanaMboxes.MBOX4.MSGID.all&65535)==1);
|
||||
assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x102),0,0));
|
||||
head=tail=0; ECanaRegs.CANRMP.all=8;
|
||||
ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,3,7,9,12);
|
||||
ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0;
|
||||
F28335CanBoot_RxISR(); assert(head==1 && tail==0);
|
||||
tx_busy=0; F28335CanBoot_Service(); assert(tail==1);
|
||||
ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=1; F28335CanBoot_RxISR(); assert(head==1);
|
||||
ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=0;
|
||||
overflow=1;tx_busy=0;F28335CanBoot_Service();assert(boot.state==PCAN_BOOT_STATE_IDLE);
|
||||
/* An ACK arriving after cancellation must never execute a queued reset. */
|
||||
tx_busy=1;tx_canceling=0;reset_requested=1;sent_at=0;
|
||||
CpuTimer1.InterruptCount=300;ECanaRegs.CANTA.all=0;ECanaRegs.CANAA.all=0;
|
||||
F28335CanBoot_Service();assert(!reset_requested && tx_canceling);
|
||||
ECanaRegs.CANTA.all=16; F28335CanBoot_Service();assert(!tx_busy && resets==1);
|
||||
for(i=0x3FE00;i<0x40000;++i)assert(memory[i]==0xA5);
|
||||
puts(F28335_BOOT_LOADER?"F28335 loader CAN services: OK":"F28335 application handoff/confirmation: OK");
|
||||
return 0;
|
||||
}
|
||||
@@ -264,7 +264,7 @@ static void test_rejects_wrong_session_and_compatibility(void)
|
||||
data[3] = 3U;
|
||||
put_u32(&data[4], 1U);
|
||||
assert(command(&boot, 7U, PCAN_BOOT_CMD_BEGIN_COMPAT, data, 8U));
|
||||
assert(fake.last_data[0] == PCAN_BOOT_STATUS_WRONG_HARDWARE);
|
||||
assert(fake.last_data[0] == PCAN_BOOT_STATUS_WRONG_DEVICE);
|
||||
assert(boot.state == PCAN_BOOT_STATE_FAILED);
|
||||
}
|
||||
|
||||
@@ -306,8 +306,41 @@ static void test_single_slot_update(void)
|
||||
assert(memcmp(fake.flash[0], image, sizeof(image)) == 0);
|
||||
}
|
||||
|
||||
static void test_services_timeout_and_retries(void)
|
||||
{
|
||||
pcan_boot_t boot; fake_t fake;
|
||||
uint8_t image[8]={0},compat[8]={0}; unsigned count;
|
||||
setup(&boot,&fake); boot.config.session_timeout_ms=30000;
|
||||
pcan_boot_poll(&boot,0xFFFFFF00UL);
|
||||
assert(command(&boot,7,PCAN_BOOT_CMD_ENTER_BOOT,NULL,0));
|
||||
assert(command(&boot,8,PCAN_BOOT_CMD_ENTER_BOOT,NULL,0));
|
||||
assert(boot.session_id==7 && fake.last_data[0]==PCAN_BOOT_STATUS_BUSY);
|
||||
assert(command(&boot,7,PCAN_BOOT_CMD_ERASE,image,1));
|
||||
assert(fake.last_data[0]==PCAN_BOOT_STATUS_INVALID_SIZE);
|
||||
pcan_boot_poll(&boot,29743); assert(boot.state!=PCAN_BOOT_STATE_IDLE);
|
||||
pcan_boot_poll(&boot,29744); assert(boot.state==PCAN_BOOT_STATE_IDLE);
|
||||
assert(command(&boot,0,PCAN_BOOT_CMD_PING,NULL,0));
|
||||
assert(pcan_boot_id_msg_body(fake.last_id)==12);
|
||||
count=fake.sends;
|
||||
assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),NULL,0));
|
||||
assert(fake.sends==count); pcan_boot_poll(&boot,boot.discovery_at);
|
||||
assert(fake.sends==count+1 && pcan_boot_id_msg_body(fake.last_id)==1);
|
||||
assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x702),NULL,0));
|
||||
begin_update(&boot,image,8);
|
||||
put_u16(compat,boot.manifest.product_type);
|
||||
compat[2]=boot.manifest.hardware_revision_min; compat[3]=boot.manifest.hardware_revision_max;
|
||||
put_u32(compat+4,boot.manifest.firmware_version);
|
||||
assert(command(&boot,7,4,compat,8)); assert(fake.last_data[0]==0);
|
||||
assert(command(&boot,7,5,NULL,0)); count=fake.erases;
|
||||
assert(command(&boot,7,5,NULL,0)); assert(fake.erases==count && fake.last_data[0]==0);
|
||||
assert(pcan_boot_process(&boot,request_id(PCAN_BOOT_MSG_DATA_B,0),image,8));
|
||||
assert(command(&boot,7,6,NULL,0)); assert(command(&boot,7,6,NULL,0)); assert(fake.last_data[0]==0);
|
||||
assert(command(&boot,7,7,NULL,0)); assert(command(&boot,7,7,NULL,0)); assert(fake.last_data[0]==0);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_services_timeout_and_retries();
|
||||
test_id_layout();
|
||||
test_crc32_reference();
|
||||
test_complete_update();
|
||||
|
||||
Reference in New Issue
Block a user