stringService = $stringService ?? new StringService(); } public function getAdditionalDeviceAttributes(): array { return [ 'avr-family' => $this->getAvrFamily()->value ?? '', ]; } public function getSignature(): ?Signature { $byteZero = $this->getPropertyValue('signatures', 'signature0'); $byteOne = $this->getPropertyValue('signatures', 'signature1'); $byteTwo = $this->getPropertyValue('signatures', 'signature2'); if (!empty($byteZero) && !empty($byteOne) && !empty($byteTwo)) { $signature = new Signature(); $signature->byteZero = $this->stringService->tryStringToInt($byteZero); $signature->byteOne = $this->stringService->tryStringToInt($byteOne); $signature->byteTwo = $this->stringService->tryStringToInt($byteTwo); return $signature; } return null; } public function getAvrFamily(): ?AvrFamily { return AvrFamily::tryFrom($this->deviceAttributesByName['avr-family']); } public function getSupportedPhysicalInterfaces(): array { $physicalInterfacesByName = [ 'isp' => AvrPhysicalInterface::ISP, 'debugwire' => AvrPhysicalInterface::DEBUG_WIRE, 'updi' => AvrPhysicalInterface::UPDI, 'pdi' => AvrPhysicalInterface::PDI, 'jtag' => AvrPhysicalInterface::JTAG, ]; return array_filter(array_map( fn (PhysicalInterface $interface): ?AvrPhysicalInterface => $physicalInterfacesByName[strtolower($interface->name ?? '')] ?? null, $this->physicalInterfaces )); } public function getSupportedDebugPhysicalInterfaces(): array { $physicalInterfacesByName = [ 'debugwire' => AvrPhysicalInterface::DEBUG_WIRE, 'updi' => AvrPhysicalInterface::UPDI, 'pdi' => AvrPhysicalInterface::PDI, 'jtag' => AvrPhysicalInterface::JTAG, ]; return array_filter(array_map( fn (PhysicalInterface $interface): ?AvrPhysicalInterface => $physicalInterfacesByName[strtolower($interface->name ?? '')] ?? null, $this->physicalInterfaces )); } public function getDebugWireParameters(): DebugWireParameters { $output = new DebugWireParameters(); $programMemorySegment = $this->getProgramMemorySegment(); if ($programMemorySegment instanceof MemorySegment) { $output->flashStartAddress = $programMemorySegment->startAddress; $output->flashSize = $programMemorySegment->size; $output->flashPageSize = $programMemorySegment->pageSize; } $ramMemorySegment = $this->getRamSegment(); if ($ramMemorySegment instanceof MemorySegment) { $output->ramStartAddress = $ramMemorySegment->startAddress; } $output->bootSectionOptions = $this->getBootSectionOptions(); $eepromMemorySegment = $this->getEepromSegment(); if ($eepromMemorySegment instanceof MemorySegment) { $output->eepromSize = $eepromMemorySegment->size; $output->eepromPageSize = $eepromMemorySegment->pageSize; } $output->ocdRevision = $this->stringService->tryStringToInt( $this->getPropertyValue('ocd', 'ocd_revision') ); $output->ocdDataRegisterAddress = $this->stringService->tryStringToInt( $this->getPropertyValue('ocd', 'ocd_datareg') ); $eepromPeripheral = $this->getTargetPeripheral('eeprom'); if ($eepromPeripheral instanceof TargetPeripheral) { $eepromAddressRegister = $eepromPeripheral->getRegister('eeprom', 'eear'); if ($eepromAddressRegister instanceof TargetRegister) { $output->eearAddressLow = $eepromAddressRegister->address; $output->eearAddressHigh = $eepromAddressRegister->size > 1 ? $eepromAddressRegister->address !== null ? $eepromAddressRegister->address >> 8 : null : $eepromAddressRegister->address ; } else { $eearAddressLow = $eepromPeripheral->getRegister('eeprom', 'eearl'); $eearAddressHigh = $eepromPeripheral->getRegister('eeprom', 'eearh'); if ($eearAddressLow instanceof TargetRegister) { $output->eearAddressLow = $eearAddressLow->address; $output->eearAddressHigh = $eearAddressLow->size > 1 ? $eearAddressLow->address !== null ? $eearAddressLow->address >> 8 : null : $eearAddressLow->address; } if ($eearAddressHigh instanceof TargetRegister) { $output->eearAddressHigh = $eearAddressHigh->address; } } $eepromDataRegister = $eepromPeripheral->getRegister('eeprom', 'eedr'); if ($eepromDataRegister instanceof TargetRegister) { $output->eedrAddress = $eepromDataRegister->address; } $eepromControlRegister = $eepromPeripheral->getRegister('eeprom', 'eecr'); if ($eepromControlRegister instanceof TargetRegister) { $output->eecrAddress = $eepromControlRegister->address; } } $cpuPeripheral = $this->getTargetPeripheral('cpu'); if ($cpuPeripheral instanceof TargetPeripheral) { $spmcsRegister = $cpuPeripheral->getRegister('cpu', 'spmcsr') ?? $cpuPeripheral->getRegister('cpu', 'spmcr'); if ($spmcsRegister instanceof TargetRegister) { $output->spmcrAddress = $spmcsRegister->address; } $osccalRegister = $cpuPeripheral->getRegister('cpu', 'osccal') ?? $cpuPeripheral->getRegister('cpu', 'osccal0') ?? $cpuPeripheral->getRegister('cpu', 'osccal1') ?? $cpuPeripheral->getRegister('cpu', 'fosccal') ?? $cpuPeripheral->getRegister('cpu', 'sosccala'); if ($osccalRegister instanceof TargetRegister) { $output->osccalAddress = $osccalRegister->address; } } if ($output->spmcrAddress === null) { $bootLoaderPeripheral = $this->getTargetPeripheral('boot_load'); if ($bootLoaderPeripheral instanceof TargetPeripheral) { $spmcsRegister = $bootLoaderPeripheral->getRegister('boot_load', 'spmcr') ?? $bootLoaderPeripheral->getRegister('boot_load', 'spmcsr'); if ($spmcsRegister instanceof TargetRegister) { $output->spmcrAddress = $spmcsRegister->address; } } } return $output; } public function getIspParameters(): IspParameters { $output = new IspParameters(); $output->programModeTimeout = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_timeout') ); $output->programModeStabilizationDelay = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_stabdelay') ); $output->programModeCommandExecutionDelay = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_cmdexedelay') ); $output->programModeSyncLoops = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_synchloops') ); $output->programModeByteDelay = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_bytedelay') ); $output->programModePollValue = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_pollvalue') ); $output->programModePollIndex = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispenterprogmode_pollindex') ); $output->programModePreDelay = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispleaveprogmode_predelay') ); $output->programModePostDelay = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispleaveprogmode_postdelay') ); $output->readSignaturePollIndex = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispreadsign_pollindex') ); $output->readFusePollIndex = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispreadfuse_pollindex') ); $output->readLockPollIndex = $this->stringService->tryStringToInt( $this->getPropertyValue('isp_interface', 'ispreadlock_pollindex') ); return $output; } public function getJtagParameters(): JtagParameters { $output = new JtagParameters(); $programMemorySegment = $this->getProgramMemorySegment(); if ($programMemorySegment instanceof MemorySegment) { $output->flashStartAddress = $programMemorySegment->startAddress; $output->flashSize = $programMemorySegment->size; $output->flashPageSize = $programMemorySegment->pageSize; } $ramMemorySegment = $this->getRamSegment(); if ($ramMemorySegment instanceof MemorySegment) { $output->ramStartAddress = $ramMemorySegment->startAddress; } $output->bootSectionOptions = $this->getBootSectionOptions(); $eepromMemorySegment = $this->getEepromSegment(); if ($eepromMemorySegment instanceof MemorySegment) { $output->eepromSize = $eepromMemorySegment->size; $output->eepromPageSize = $eepromMemorySegment->pageSize; } $output->ocdRevision = $this->stringService->tryStringToInt($this->getPropertyValue('ocd', 'ocd_revision')); $output->ocdDataRegisterAddress = $this->stringService->tryStringToInt($this->getPropertyValue('ocd', 'ocd_datareg')); $eepromPeripheral = $this->getTargetPeripheral('eeprom'); if ($eepromPeripheral instanceof TargetPeripheral) { $eepromAddressRegister = $eepromPeripheral->getRegister('eeprom', 'eear'); if ($eepromAddressRegister instanceof TargetRegister) { $output->eearAddressLow = $eepromAddressRegister->address; $output->eearAddressHigh = $eepromAddressRegister->size > 1 ? $eepromAddressRegister->address !== null ? $eepromAddressRegister->address >> 2 : null : $eepromAddressRegister->address ; } else { $eearAddressLow = $eepromPeripheral->getRegister('eeprom', 'eearl'); $eearAddressHigh = $eepromPeripheral->getRegister('eeprom', 'eearh'); if ($eearAddressLow instanceof TargetRegister) { $output->eearAddressLow = $eearAddressLow->address; } if ($eearAddressHigh instanceof TargetRegister) { $output->eearAddressHigh = $eearAddressHigh->address; } } $eepromDataRegister = $eepromPeripheral->getRegister('eeprom', 'eedr'); if ($eepromDataRegister instanceof TargetRegister) { $output->eedrAddress = $eepromDataRegister->address; } $eepromControlRegister = $eepromPeripheral->getRegister('eeprom', 'eecr'); if ($eepromControlRegister instanceof TargetRegister) { $output->eecrAddress = $eepromControlRegister->address; } } $cpuPeripheral = $this->getTargetPeripheral('cpu'); if ($cpuPeripheral instanceof TargetPeripheral) { $spmcsRegister = $cpuPeripheral->getRegister('cpu', 'spmcsr') ?? $cpuPeripheral->getRegister('cpu', 'spmcr'); if ($spmcsRegister instanceof TargetRegister) { $output->spmcrAddress = $spmcsRegister->address; } $osccalRegister = $cpuPeripheral->getRegister('cpu', 'osccal') ?? $cpuPeripheral->getRegister('cpu', 'osccal0') ?? $cpuPeripheral->getRegister('cpu', 'osccal1') ?? $cpuPeripheral->getRegister('cpu', 'fosccal') ?? $cpuPeripheral->getRegister('cpu', 'sosccala'); if ($osccalRegister instanceof TargetRegister) { $output->osccalAddress = $osccalRegister->address; } } if ($output->spmcrAddress === null) { $bootLoaderPeripheral = $this->getTargetPeripheral('boot_load'); if ($bootLoaderPeripheral instanceof TargetPeripheral) { $spmcsRegister = $bootLoaderPeripheral->getRegister('boot_load', 'spmcr') ?? $bootLoaderPeripheral->getRegister('boot_load', 'spmcsr'); if ($spmcsRegister instanceof TargetRegister) { $output->spmcrAddress = $spmcsRegister->address; } } } return $output; } public function getPdiParameters(): PdiParameters { $output = new PdiParameters(); $output->appSectionOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'app_section_offset') ); $output->bootSectionOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'boot_section_offset') ); $output->ramOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'datamem_offset') ); $output->eepromOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'eeprom_offset') ); $output->userSignaturesOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'user_signatures_offset') ); $output->productionSignaturesOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'prod_signatures_offset') ); $output->fuseRegistersOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'fuse_registers_offset') ); $output->lockRegistersOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'lock_registers_offset') ); $programMemorySegment = $this->getProgramMemorySegment(); if ($programMemorySegment instanceof MemorySegment) { $output->flashPageSize = $programMemorySegment->pageSize; $appSection = $programMemorySegment->getSection('app_section'); if ($appSection instanceof MemorySegmentSection) { $output->appSectionSize = $appSection->size; } $bootSection = $programMemorySegment->getSection('boot_section'); if ($bootSection instanceof MemorySegmentSection) { $output->bootSectionSize = $bootSection->size; } } $eepromMemorySegment = $this->getEepromSegment(); if ($eepromMemorySegment instanceof MemorySegment) { $output->eepromSize = $eepromMemorySegment->size; $output->eepromPageSize = $eepromMemorySegment->pageSize; } $nvmModuleRegisterGroup = $this->getTargetRegisterGroup('nvm', 'nvm'); if ($nvmModuleRegisterGroup instanceof TargetRegisterGroup) { $output->nvmModuleBaseAddress = $nvmModuleRegisterGroup->baseAddress; } $output->signatureOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('pdi_interface', 'signature_offset') ); return $output; } public function getUpdiParameters(): UpdiParameters { $output = new UpdiParameters(); $output->programMemoryOffset = $this->stringService->tryStringToInt( $this->getPropertyValue('updi_interface', 'progmem_offset') ); $programMemorySegment = $this->getProgramMemorySegment(); if ($programMemorySegment instanceof MemorySegment) { $output->flashSize = $programMemorySegment->size; $output->flashPageSize = $programMemorySegment->pageSize; } $eepromMemorySegment = $this->getEepromSegment(); if ($eepromMemorySegment instanceof MemorySegment) { $output->eepromStartAddress = $eepromMemorySegment->startAddress; $output->eepromSize = $eepromMemorySegment->size; $output->eepromPageSize = $eepromMemorySegment->pageSize; } $output->nvmModuleBaseAddress = $this->getTargetRegisterGroup( 'nvmctrl', 'nvmctrl' )->baseAddress ?? null; $output->ocdBaseAddress = $this->stringService->tryStringToInt( $this->getPropertyValue('updi_interface', 'ocd_base_addr') ); $signatureMemorySegment = $this->getMemorySegment( 'signatures', 'signatures' ) ?? $this->getMemorySegment( 'data', 'signatures' ); if ($signatureMemorySegment instanceof MemorySegment) { $output->signatureSegmentStartAddress = $signatureMemorySegment->startAddress; } $fuseMemorySegment = $this->getMemorySegment( 'fuses', 'fuses' ) ?? $this->getMemorySegment( 'data', 'fuses' ); if ($fuseMemorySegment instanceof MemorySegment) { $output->fuseSegmentSize = $fuseMemorySegment->size; $output->fuseSegmentStartAddress = $fuseMemorySegment->startAddress; } $lockbitsMemorySegment = $this->getMemorySegment( 'lockbits', 'lockbits' ) ?? $this->getMemorySegment( 'data', 'lockbits' ); if ($lockbitsMemorySegment instanceof MemorySegment) { $output->lockbitsSegmentStartAddress = $lockbitsMemorySegment->startAddress; } return $output; } public function getFuseTargetPeripheral(): ?TargetPeripheral { return $this->getTargetPeripheral('fuse'); } public function getFuseTargetRegisterGroup(): ?TargetRegisterGroup { return $this->getFuseTargetPeripheral()?->getRegisterGroup("fuse"); } public function getFuseBitsDescriptor(string $fuseBitFieldKey): ?FuseBitsDescriptor { $fuseRegisterGroup = $this->getFuseTargetRegisterGroup(); if ($fuseRegisterGroup instanceof TargetRegisterGroup) { foreach ($fuseRegisterGroup->registers as $fuseRegister) { foreach ($fuseRegister->bitFields as $bitField) { if ($bitField->key === $fuseBitFieldKey) { return new FuseBitsDescriptor($fuseRegister->name); } } } } return null; } private function getProgramMemorySegment(): ?MemorySegment { return $this->getMemorySegment('prog', 'internal_program_memory'); } private function getRamSegment(): ?MemorySegment { return $this->getMemorySegment('data', 'internal_ram'); } private function getEepromSegment(): ?MemorySegment { return $this->getMemorySegment('eeprom', 'internal_eeprom') ?? $this->getMemorySegment('data', 'internal_eeprom'); } private function getBootSectionOptions(): array { $output = []; $bootSectionPropertyGroups = $this->getPropertyGroup('boot_section_options')->subPropertyGroups ?? []; foreach ($bootSectionPropertyGroups as $propertyGroup) { $output[] = new BootSection( $this->stringService->tryStringToInt($propertyGroup->getPropertyValue('start_address')), $this->stringService->tryStringToInt($propertyGroup->getPropertyValue('size')), $this->stringService->tryStringToInt($propertyGroup->getPropertyValue('page_size')) ); } return $output; } }