OpenBLT: firmwarė per CAN

Posted: 2016-12-24 in Darbeliai
Žymos:, ,

Išmanūs šviesos valdikliai | Elektronika | Darau, blėVisai nekalėdinės temos mano tinklarašty. Tiesa, jau turiu pusę japoniško kario recepto, bet turbūt irgi ne į temą. Pastebėjau tik, kad prieš Kalėdas padaugėjo baksnojimų į Velingtono kepsnio receptą. Ruošiuosi ir pats jį kepti.

Nugriebdamas laiko vis bandžiau prisėsti prie vieno mintyse kirbėjusio neramumo: o kaip reikės savo šviesų sistemoje atnaujinti firmwares? Dabar krapštydamasis net SWD nenaudoju, pažaidžiu džemperiukais ir permetu firmwares per USART. Kartais tai nervija, ypač, kai prasideda kokios nors neaiškios klaidelės gaudymas ir firmwarę reikia kas pusę minutės perkompiliuot ir permest. Bet konfigūruotis SWD tingėjau dar labiau 😀

Tačiau visgi nėra jokios prasmės manyti, kad kai mano šviesų sistema iš tikro dirbs, ten neprireiks ko nors paremontuoti. Naivu būtų taip tikėtis. Elementariai aš galiu sugalvoti ją praplėsti, įdėti dar kokių nors navarotų. Tai juk normalu. Bet kad norint atnaujinti firmwarę reikėtų eiti iki elektros spintos ir prie kiekvieno įrenginuko junginėt USB-UART konverterį… na jau ne. Tai būtų labai nepatogu, labai vargintų ir apskritai tai būtų labai kvailas sprendimas.

Škia kadangi mano sistema suksis komunikuodama per CAN magistralę, tai sprendimas jau peršasi pats: reikia sugalvoti, kaip atnaujinti firmwarę per CAN. Ohoho, kokia užduotėlė neeilinė. Reikės CAN bootloaderio.

Pradžiai pasiskaitinėjau STM gromatas apie visokius bootloaderius. Pačiuose procesoriukuose yra gimtasis bootloaderis, kuriuo aš dabar ir naudojuosi. Kur ir kaip jis ten įsiūtas — nežinau. Ar jį iš viso galima pakeisti/perrašyti — irgi nežinau. Bet tai ir neturėtų rūpėti. Šis bootloaderis yra kaip ir „sisteminis“, procesoriuko dalis, jį kažkuo keisti ir nereikia.

Kas apskritai yra bootloaderis? Tai yra tokia firmwarės dalis, kuri pasileidžia pirmiausia, pakabo, palaukia, ar bus kas nors atnaujinama ir jei ne — paleidžia pagrindinę firmwarės dalį. Pati firmwarė savęs perrašyti negali — jei ji užsikrovė iš tam tikros adresų erdvės flashe, tai ten pat įrašinėti negalima. Gali kokią savo aktyviai naudojamą konstantą sugadint ar dar kažką. Todėl reikia programinę įrangą dalinti į dvi dalis. Pirmoji bus bootloaderis, kuris gali užimti kelis kilobaitus atminties. Antroji — pagrindinė programa, įrašoma tolėliau už bootloaderio.

Mano mintis buvo maždaug tokia, kaip viskas galėtų vykti:

  • Per CAN magistralę konkrečiam divaisui nusiunčiu persikrovimo komandą
  • Divaisas persikrauna į bootloaderį
  • Bootloaderis porą sekundžių laukia, ar gaus firmwarės įrašymo komandą
  • Jei gauna, tai laukia toliau firmwarės duomenukų ir juos įrašinėja
  • Jei negauna, tai pakabėjęs paleidžia pagrindinę firmwarę

Radau vieną bandymą tokį bootloaderį padaryti, bet ten viskas buvo gan bjauru ir nelabai veikė. Tada pakrapščiau galvą ir pabandžiau kažką pasidėlioti pats — užkniso.

Ir visai netyčia radau OpenBLT. Baisiai geras ir profesionalus projektas. Palaiko krūvą visokių protokolų firmwarėms atnaujinti, tarp jų — ir CAN. Nu tai būčiau durnas, jei nesinaudočiau.

OpenBLT tinka krūvai visokių procesoriukų su įvairiais įgyvendinimais. STM32 yra palaikoma visa krūva įskaitant ir Cortex-M3, ko reikia man. Pridėta ir krūvelė pavyzdžių, taip pat firmwarės įkėlimo programėlės kompui. Viena jų, SerialBoot, susikompiliuoja ir Linux’ui.

Pradžia tokia ir buvo. Iš pavyzduko susirankiojau OpenBLT projektą, užsikūriau, pavyko viską sukompiliuot. Binarnikas gavosi biškį virš keturių kilobaitų, tai mano pagrindinė firmwarė gali gultis nuo 8 kB ribos. Iš 64 kB flashe lieka 56 kB, ko man yra per akis. Ypač, kad vis dar terliojuosi su debugine versija, o kai viską pramesiu, tai liks kur kas mažiau.

Užbėgdamas į priekį galiu pasakyt, kad per CAN iš pradžių atnaujinti firmwarės nepavyko. Na, firmwarei atnaujinti siunčiau duomenukus su Python skriptuku ir šį bei tą ne visai teisingai padariau, per daug tikėdamasis, kad OpenBLT viską suvaldys. Nereikia taip tikėtis 🙂

Tada pasidariau OpenBLT versiją su atnaujinimu per USART ir susikompiliavau SerialBoot. Tas, rupūžė, kažkodėl palaiko tik Motorola S19 firmwarių formatą, tai dar teko susinestaliuoti srecord. Tada Intel HEX failą galima paversti į S19 šitaip:

srec_cat OpenBLT_TEST_APP.hex -intel -o OpenBLT_TEST_APP.s19

Per USARTą viskas suveikė. Taigi man net firmwarę iš karto pavyko teisingai pasiruošti. Dar prikišau OpenBLT visokių debugų ir pasižiūrėjau konkrečią komandų seką, kaip viskas į bootloaderį keliauja.

Firmwarės paruošimas

Taigi sakykim, kad bootloaderis užima iki 8 kB, o pagrindinė firmwarė įrašoma į flash atmintį procesoriuką būtent nuo šios ribos. Kaip jau ne kartą minėjau, aš viską dėlioju Eclipse, dabar konkrečiai Mars versijoje, tai ldscripts katalogėlyje reikia susirasti failą mem.ld. Jame yra eilutė FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K. 0x08000000 yra flash atminties pradžios adresas. Prie šito reikia pridėti 8 kB ir eilutę pakeisti. Štai visas mano mem.ld failiukas:

/* Memory Spaces Definitions */

MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 56K
FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
}

/* higher address of the user mode stack */
_estack = 0x20000000 + 20*1024;

Toliau. OpenBLT būtinai vektorių lentukės pabaigoje nori įrašyti checksumą. Taip anas žino, kad yra gera firmwarė įrašyta ir ją galima užkrauti. Kitu atveju OpenBLT sukasi be perstojo ir laukia, kol jam naują firmwarę duos įrašyt.

OpenBLT puslapyje tas yra aprašyta maždaug, bet ne visai aiškiai. Kur tie vektoriai sukišti, priklauso nuo programavimo aplinkos, nuo naudojamo kompiliatoriaus ir dar nuo visokių kitokių velniavų. Eclipse Mars man tas dalykas mėtėsi system/src/CMSIS/vectors_stm32f10x.c failiuke prie STM32F10X_MD defino:

#elif defined(STM32F10X_MD)

USB_HP_CAN1_TX_IRQHandler, //
USB_LP_CAN1_RX0_IRQHandler, //
CAN1_RX1_IRQHandler, //
CAN1_SCE_IRQHandler, //
EXTI9_5_IRQHandler, //
TIM1_BRK_IRQHandler, //
TIM1_UP_IRQHandler, //
TIM1_TRG_COM_IRQHandler, //
TIM1_CC_IRQHandler, //
TIM2_IRQHandler, //
TIM3_IRQHandler, //
TIM4_IRQHandler, //
I2C1_EV_IRQHandler, //
I2C1_ER_IRQHandler, //
I2C2_EV_IRQHandler, //
I2C2_ER_IRQHandler, //
SPI1_IRQHandler, //
SPI2_IRQHandler, //
USART1_IRQHandler, //
USART2_IRQHandler, //
USART3_IRQHandler, //
EXTI15_10_IRQHandler, //
RTCAlarm_IRQHandler, //
USBWakeUp_IRQHandler, //
0, //
0, //
0, //
0, //
0, //
0, //
0, //
// @0x108. This is for boot in RAM mode for STM32F10x Low Density devices.
(pHandler)0xF108F85F,
(void*)0x55AA11EE // OpenBLT checksum place

Dar labai pasisekė, kad pridėtas komentaras “@0x108”, kuris reiškia vektorių lentukės pabaigą. Nes bootloaderiui, žinote, reikia žinoti, kur ta pabaiga. Na, šitas komentaras man padėjo. Tokią nurodžiau, tokia ir suveikė.

O kas būtų, jeigu jūsų programavimo aplinka, ar tiesiog meikfailų ir kitų skriptų kratinys nebūtų toks dokumentuotas? Kaip reikėtų sužinoti vektorių lentukės dydį? Šiaip nesudėtinga, vienintelis reikalavimas — priversti kompiliatorių sugeneruoti Intel HEX failą. Tada jame atvirkštine seka (nes nu tokia baitų tvarka) reikėtų to OpenBLT stebuklingo skaičiuko paieškoti. Na, ieškoti reiktų EE11AA55 🙂 Tada pagal tai, kurioje eilutėje radote ir kurioje jos vietoje galėtumėte išsikapstyti ir adresą. Atėmus keturis (nes tiek baitų užima) gautumėte vektorių lentukės pabaigą. Išbandžiau, patikrinau, sutampa.

Pagal OpenBLT rekomendacijas naudojant STM32 bibliotekas reikėtų iškirsti vektorių lentukės pradžios perrašymą. Nes šiaip ji įrašoma flash pradžioje, o mes tą pradžią dėl bootloaderio nustumiam. Aš tą padariau tik dėl visa ko, nes pastebėjau, kad kažkur tolėliau kode yra „tikrosios“ flasho pradžios nuskaitymas. Na, bet dzin, užkomentavau viską system_stm32f10x.c faile:

//#ifdef VECT_TAB_SRAM
// SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
//#else
// SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
//#endif

Taigi su šiais trim pakeitimais per USART bootloaderį įkelta mano firmwarė veikia ir nesispyrioja. Asemblerinių steko inicializacijų pagal rekomendacijas nedariau, nes panašu, kad jos reikalingos bootloaderiui, o ne pagrindinei firmwarei. Pavyzdinėje programulkėje to irgi nėra. Na, sakau, ne visai aiškiai ten aprašyta.

Kišimas per bootloaderį

Firmwarės kišimas per bootloaderį yra gan paprastas, siunčiama krūvelė komandų ir žiūrimi atsakymai. Norint galima uždėti ten visokias apsaugas, bet man to nereikės. Pirmiausia siunčiama prisijungimo komanda ir bootloaderis pasiruošia priiminėti tolimesnius nurodymus. Tada nustatomas adresas ir nurodoma, kiek bitukų ištrinti. Tada nurodomas vėl adresas ir siunčiami bitukai įrašymui. Viskas paprastai ir aiškiai išdėliota diagramoje.

Visgi man iš pirmo karto nepavyko. Aš pasirašiau Python skriptuką, kuris nuskaito HEX failą ir nusiunčia viską per CAN magistralę. Vienas niuansas, kurį tuoj pat pagavau: reikia stengtis siųsti po lyginį baitų skaičių, nes gi STM32 flashas įrašinėjamas 16 bitų gabalais. O aš ten naudodamas maksimalų CAN žinutės duomenų kiekį galėjau siųsti po 7 baitus. Bala nematė, neverta, siųsiu po 6.

Bet ir tai nepadėjo. Kas liko tada? Pabandyti tą patį bootloaderį perkompiliuot į USART variantą ir su SerialBoot sukišti tą pačią firmwarę. Tada suveikė. Na, uch, reiškia, pačią firmwarę paruošiau gerai. O kas toliau?

Toliau bootloaderį prikišau debuginių mesedžiukų, kurie per USART2 viską spjaudė į ekraną maždaug taip:

Blahaha ir pradedam USART bootloadery
CONNECT
CONNECT
PGM_START
SET_MTA: 134225920, 08002000, 00  20 00 08
PGM_CLEAR: 18631, 000048C7, C7  48 00 00
SET_MTA: 134225920, 08002000, 00  20 00 08
PGM: 00 50 00 20 25 22 00 08 2D 22 00 08 31 22 00 08 49 22 00 08 4D 22 00 08 65 22 00 08 00 00 00 00
SET_MTA: 134225952, 08002020, 20  20 00 08
PGM: 00 00 00 00 00 00 00 00 00 00 00 00 79 4A 00 08 81 22 00 08 00 00 00 00 09 4B 00 08 4D 4B 00 08
SET_MTA: 134225984, 08002040, 40  20 00 08
PGM: 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08
SET_MTA: 134226016, 08002060, 60  20 00 08
PGM: 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08
SET_MTA: 134226048, 08002080, 80  20 00 08
PGM: 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 DD 46 00 08 99 22 00 08 99 22 00 08 99 22 00 08
SET_MTA: 134226080, 080020A0, A0  20 00 08
PGM: 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08
SET_MTA: 134226112, 080020C0, C0  20 00 08
PGM: 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08 99 22 00 08
SET_MTA: 134226144, 080020E0, E0  20 00 08
PGM: 99 22 00 08 99 22 00 08 99 22 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
SET_MTA: 134226176, 08002100, 00  21 00 08
PGM: 00 00 00 00 00 00 00 00 5F F8 08 F1 EE 11 AA 55 00 B5 83 B0 01 F0 88 FA 30 4B 31 4A 13 60 31 4A
SET_MTA: 134226208, 08002120, 20  21 00 08
PGM: 13 60 31 4B 31 4A 03 E0 11 68 19 60 04 33 04 32 2F 49 8B 42 F8 D3 2A 4B 1A 68 2E 4B 9A 42 04 D1
...

Taip pasižiūrėjau, kokia seka ir kokiais baitais bootloaderis realiai priima duomenus. Nes ką aš žinau, galėjau ir baitų endianesą supainioti. Lyg ir žinau, koks jis, nu bet maža ką.

Matote ten tokį SET_MTA? Prieš kiekvieną duomenukų purptelėjimą nusiunčiamas adresas, kur juos rašyti. Teoriškai to SET_MTA prieš kiekvieną įrašymą nereikėtų, nes bootloaderio kodas automatiškai pasiskaičiuoja, kiek baitų įrašė ir koks tas kitas MTA. Bet visgi galima jį ir nustatinėti. Tai nusprendžiau nustatinėti, nu maža ką.

Pasitobulinau savo Pythono skriptuką, perkompiliavau bootloaderį priimti duomenukus per CAN ir nusiunčiau. Beje, pasidariau tokią mažą programulkę, kuri į tą patį USART2 tiesiog parašo, kad užsikrovė.

Endianai pasirodė besą geri. Programulkė užsikrovė. Jėga!

Sukišu savo lempinį firmwarą. O tas nesikrauna. Nejėga. Kas per šūds?

Teko išsianalizuoti HEX failus. Atradau, per vargus ir kančias, kad jie nėra nuoseklūs. T.y. yra bent vienas įrašas, kuris baigiasi, o kito įrašo adresas gerokai tolėliau, nei kad iš paskos. Skylė HEXe, žodžiu. Greičiausiai dėl to, kad sudėtinga ir didelė programa, kažkurios sekcijos gal paalignintos, kaip ir turi būti, pagal sektorius. Nu tai ir gaunasi „skylė“. O aš nuskaitinėdamas tuos HEX failus paimdavau pradinį adreso poslinkį ir toliau nuo jo varydavau. Skylė persidengdavo ir firmwarė susigadindavo. Kai šitą pataisiau, viskas užveikė!

Vienas tik „trūkumas“: mano plokštėse yra trys signaliniai diodukai, padariau, kad bootloaderio laukimo metu raudonas mirksėtų. Bet šviesų ir mygtukų plokštėse, deja, skiriasi tų diodų pinukai. Tai teko pasidaryti su defainais skirtingas bootloaderio versijas.

Na va, dabar reikia dar sukodyti savo firmwarėse, kad jas būtų galima per CAN nusiuntus signaliuką perkrauti ir firmwarės skraidys per CAN kaip didelės. Smagumėlis.

Dar vienas gerumas iš šito reikalo. Aš visokius nustatymus saugau flash atminties pabaigoje. OpenBLT ištrina tik tuos sektorius, kurie nurodomi. Taigi perrašau firmwarę, o įrenginio nustatymai išlieka!

Pabaigai mano įkelties programulkė, galite nagrinėtis ir naudotis, jei netyčia prireiktų. Kuo, tiesą sakant, truputėliuką abejoju 😀

# -*- coding: utf-8 -*-
'''
Created on 2016-12-20

@author: Darau, blė
'''
CAN_TX_ID = 0x0667
CAN_RX_ID = 0x07E1

XCP_CONNECT = 0xFF
XCP_GET_STATUS = 0xFD
XCP_SET_MTA = 0xF6
XCP_PROGRAM_START = 0xD2
XCP_PROGRAM_CLEAR = 0xD1
XCP_PROGRAM = 0xD0
XCP_PROGRAM_MAX = 0xC9
XCP_PROGRAM_RESET = 0xCF

XCP_DATA_MAX = 6

HEX_DATA = 0x00
HEX_OFFSET = 0x04
HEX_EOF = 0x01

import can
import sys

can_interface = 'can0'
bus = can.interface.Bus(can_interface, bustype='socketcan_native')

def read_hex_records(fname):
    blob = [];
    for l in open(fname):
        if l[0:1] != ':':
            print('Wrong HEX format')
            return False
        
        byte_count = int(l[1:3], 16)
        addr = int(l[3:7], 16)
        rec_type = int(l[7:9], 16)
        
        if rec_type == HEX_DATA:
            hex_data = []
            for i in range(0, byte_count):
                hex_data.append(int(l[9+(i*2):11+(i*2)], 16))
            hex_rec = {
                   'type': HEX_DATA,
                   'addr': addr,
                   'data': hex_data
               }
            blob.append(hex_rec)
        elif byte_count == 0x02 and rec_type == HEX_OFFSET:
            hex_rec = {
                   'type': HEX_OFFSET,
                   'addr': (int(l[9:13], 16) << 16)
               }
            blob.append(hex_rec)
        elif rec_type == HEX_EOF:
            break
    
    return blob


def get_hex_start_end(blob):
    start = 1
    if blob[0]['type'] == HEX_OFFSET and blob[1]['type'] == HEX_DATA:
        base_address = blob[0]['addr']
        start_address = blob[0]['addr'] + blob[1]['addr']
        start = 2
    elif blob[0]['type'] == HEX_DATA:
        start_address = blob[0]['addr']
        base_address =  blob[0]['addr']
    else:
        start_address = 0
        base_address = 0
    
    last_base_address = base_address
    last_address = start_address
    for i in range(start, len(blob)):
        if blob[i]['type'] == HEX_DATA:
            last_address = last_base_address + blob[i]['addr']
        elif blob[i]['type'] == HEX_OFFSET and blob[i+1]['type'] == HEX_DATA:
            last_base_address = blob[i]['addr']
    
    if blob[-1]['type'] == HEX_DATA:
        last_address += len(blob[-1]['data'])
    
    return (start_address, last_address)


def connect():
    msg = can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=[XCP_CONNECT])
    try_cnt = 100
    while try_cnt > 0:
        bus.send(msg)
        resp = bus.recv(0.1)
        if resp is not None and resp.arbitration_id == CAN_RX_ID:
            print(resp)
            break
        else:
            resp = None
        try_cnt-=1

    if resp is not None:
        return True
    else:
        return False

def program_start():
    bus.send(can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=[XCP_PROGRAM_START]))
    resp = bus.recv(1.0)

    if resp is not None and resp.arbitration_id == CAN_RX_ID:
        print('Start program...')
        return True
    else:
        return False

def erase_flash(start_address, erase_len):
    data=[XCP_SET_MTA, 0, 0, 0,
          start_address & 0xFF,
          (start_address >> 8 ) & 0xFF,
          (start_address >> 16) & 0xFF,
          (start_address >> 24) & 0xFF]
    bus.send(can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=data))

    resp = bus.recv(1.0)
    if resp is None:
        print('Could not set MTA')
        return False

    data=[XCP_PROGRAM_CLEAR, 0, 0, 0,
          erase_len & 0xFF,
          (erase_len >> 8 ) & 0xFF,
          (erase_len >> 16) & 0xFF,
          (erase_len >> 24) & 0xFF]
    bus.send(can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=data))

    print('Waiting for erase response...')
    resp = bus.recv(30.0)
    if resp is not None:
        return True
    else:
        print('Erase failed')
        return False

def write_fw(blob):
    blob_len = len(blob)

    addr_offset = 0
    
    for i in range(0, len(blob)):
        if blob[i]['type'] == HEX_DATA:
            ptr = 0
            mta = addr_offset + blob[i]['addr']
            record_len = len(blob[i]['data'])
            while ptr < record_len:
                data=[XCP_SET_MTA, 0, 0, 0, 
                  mta & 0xFF,
                  (mta >> 8 ) & 0xFF,
                  (mta >> 16) & 0xFF,
                  (mta >> 24) & 0xFF]
                bus.send(can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=data))
                
                resp = bus.recv(1.0)
                if resp is None or resp.arbitration_id != CAN_RX_ID:
                    print('Could not set MTA')
                    return False
                
                if resp.data[0] != 0xFF:
                    print('MTA Ack error: %02X' % resp.data[0])
                    return False
                
                if record_len - ptr >= XCP_DATA_MAX:
                    ptr_end = ptr+XCP_DATA_MAX
                    data_len = XCP_DATA_MAX
                else:
                    ptr_end = record_len
                    data_len = record_len - ptr
                
                msg = can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data = [XCP_PROGRAM, data_len] + blob[i]['data'][ptr:ptr_end])
                
                bus.send(msg)
                resp = bus.recv(10.0)
                
                if resp is None or resp.arbitration_id != CAN_RX_ID:
                    print('Flash write failed')
                    return False
                
                if resp.data[0] != 0xFF:
                    print('Write Ack error: %02X' % resp.data[0])
                    return False
                
                ptr+=XCP_DATA_MAX
                mta+=XCP_DATA_MAX
        elif blob[i]['type'] == HEX_OFFSET:
            addr_offset = blob[i]['addr']
        
        sys.stdout.write('\rSent % 2d%%' % int(float(i)/blob_len*100.0))
        
    print()
    
    # Final message with zero length, programming end
    bus.send(can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=[XCP_PROGRAM, 0]))
    resp = bus.recv(10.0)
    
    if resp is None or resp.arbitration_id != CAN_RX_ID:
            print('Flash finalization failed')
            return False
    
    return True

def reset():
    print('Sending reset')
    bus.send(can.Message(arbitration_id=CAN_TX_ID, extended_id=False, data=[XCP_PROGRAM_RESET]))

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print('Please provide HEX file name')

    b = read_hex_records(sys.argv[1])
    if not b:
        print('Could not read HEX file')
        exit(0)

    s, e = get_hex_start_end(b)

    print('Start address: %08X, length: %d' % (s, e-s))

    print('Connecting to bootloader...')
    if not connect():
        print('Could not connect')
        exit(0)

    print('Starting programming...')
    if not program_start():
        print('Could not start programming')
        reset()
        exit(0)

    print('Erasing %d bytes from flash at %08X' % (e-s, s))
    if not erase_flash(s, e-s):
        print('Could not erase')
        reset()
        exit(0)

    print('Flashing firmware...')
    if not write_fw(b):
        print('Could not flash')
        reset()
        exit(0)

    reset()

    print('Flashing end')

Tiek šiam kartui, gražių švenčių, blė.

Advertisements
Komentarai
  1. klejus parašė:

    Ploju! Puiki neformalaus švietimo pamoka.
    Ps. Su šventėm!

  2. scaniagti parašė:

    Iš esmės tai sukursi lanksčią namų apšvietimo sistemą. Nebrangią ir technologišką. Tereikia galvotesnio verslininko, tiražuot pas kiniečius ir įrenginėt vokiečiams 😉

Parašykite komentarą

Įveskite savo duomenis žemiau arba prisijunkite per socialinį tinklą:

WordPress.com Logo

Jūs komentuojate naudodamiesi savo WordPress.com paskyra. Atsijungti / Keisti )

Twitter picture

Jūs komentuojate naudodamiesi savo Twitter paskyra. Atsijungti / Keisti )

Facebook photo

Jūs komentuojate naudodamiesi savo Facebook paskyra. Atsijungti / Keisti )

Google+ photo

Jūs komentuojate naudodamiesi savo Google+ paskyra. Atsijungti / Keisti )

Connecting to %s