mohan-bee/mini-mp3-player
Portable, battery-powered MP3 player hardware with USB charging, microSD storage, an MCU, VS10xx audio decoder, headphone output, status controls, and regulated power rails.
- Version
- 1.2.0
- License
- unset
- Stars
- 0
firmware/tests/run.py
#!/usr/bin/env python3
"""Host integration tests. Images are synthetic filesystem fixtures, not audio."""
import pathlib, struct, subprocess, tempfile
root = pathlib.Path(__file__).resolve().parents[1]
def run(*args):
subprocess.run(args, cwd=root, check=True)
with tempfile.TemporaryDirectory() as tmp:
run('cc', '-std=c11', '-Wall', '-Wextra', '-Werror', '-Iinclude',
'src/buttons.c', 'src/decoder.c', 'tests/test_controls.c', '-o', tmp+'/controls')
run(tmp+'/controls')
run('cc', '-std=c11', '-Wall', '-Wextra', '-Werror', '-Iinclude', '-Ivendor/fatfs',
'src/diskio.c', 'tests/test_sd.c', '-o', tmp+'/sd')
run(tmp+'/sd')
run('cc', '-std=c11', '-Wall', '-Wextra', '-Ivendor/fatfs',
'vendor/fatfs/ff.c', 'tests/test_fatfs.c', '-o', tmp+'/fatfs')
for fat32 in (False, True):
sectors, reserved, fat_sectors = (70000,32,550) if fat32 else (8192,1,32)
root_sectors = 0 if fat32 else 32
data_start = reserved+fat_sectors+root_sectors
image = bytearray(sectors*512)
def u16(at,v): struct.pack_into('<H',image,at,v)
def u32(at,v): struct.pack_into('<I',image,at,v)
image[:3]=b'\xeb\x58\x90'; image[3:11]=b'MP3TEST '
u16(11,512); image[13]=1; u16(14,reserved); image[16]=1
u16(17,0 if fat32 else 512); image[21]=0xf8
if fat32:
u32(32,sectors); u32(36,fat_sectors); u32(44,2)
u16(48,1); image[66]=0x29; image[82:90]=b'FAT32 '
else:
u16(19,sectors); u16(22,fat_sectors); image[38]=0x29
image[54:62]=b'FAT16 '
image[510:512]=b'\x55\xaa'
eof=0x0fffffff if fat32 else 0xffff
def fat(cluster,value):
(u32 if fat32 else u16)(reserved*512+cluster*(4 if fat32 else 2),value)
fat(0,eof-7); fat(1,eof)
if fat32: fat(2,eof)
# Deliberately fragmented so cluster-chain traversal is exercised.
chain=list(range(4,44,2))
payload=bytes((i*17+3)&255 for i in range(10003))
for i,cluster in enumerate(chain):
fat(cluster,chain[i+1] if i+1<len(chain) else eof)
offset=(data_start+cluster-2)*512
chunk=payload[i*512:(i+1)*512]
image[offset:offset+len(chunk)]=chunk
directory=(data_start if fat32 else reserved+fat_sectors)*512
image[directory:directory+11]=b'0001 MP3'; image[directory+11]=0x20
u16(directory+26,chain[0]); u32(directory+28,len(payload))
path=pathlib.Path(tmp)/('fat32.img' if fat32 else 'fat16.img')
path.write_bytes(image); run(tmp+'/fatfs',str(path))