root/branches/libfreebob-downloader/src/bebob/bebob_dl_mgr.cpp

Revision 276, 19.6 kB (checked in by wagi, 16 years ago)

2006-06-27 Daniel Wagner <wagi@monom.org>

  • configure.ac: Version bump to 1.1.0
  • remove bebob_light code
  • downloader various improvements
  • ConfigRom::isAvcDevice() removed. Device probe code added.
    Each device driver class can check if it supports a device.
Line 
1 /* bebob_dl_mgr.cpp
2  * Copyright (C) 2006 by Daniel Wagner
3  *
4  * This file is part of FreeBoB.
5  *
6  * FreeBoB is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * FreeBoB is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with FreeBoB; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18  * MA 02111-1307 USA.
19  */
20
21 #include "bebob_dl_mgr.h"
22 #include "bebob_dl_codes.h"
23 #include "bebob_dl_bcd.h"
24
25 #include "configrom.h"
26 #include "libfreebobavc/ieee1394service.h"
27 #include "libfreebobavc/serialize.h"
28
29 #include <netinet/in.h>
30
31 #include <cstdio>
32
33 namespace BeBoB {
34     enum {
35         AddrRegInfo    = 0xffffc8020000ULL,
36         AddrRegReq     = 0xffffc8021000ULL,
37         AddrRegReqBuf  = 0xffffc8021040ULL,
38         AddrRegResp    = 0xffffc8029000ULL,
39         AddrRegRespBuf = 0xffffc8029040ULL,
40     };
41
42     enum {
43         RegInfoManufactorIdOffset =      0x00,
44         RegInfoProtocolVersionOffset =   0x08,
45         RegInfoBootloaderVersionOffset = 0x0c,
46         RegInfoGUID =                    0x10,
47         RegInfoHardwareModelId =         0x18,
48         RegInfoHardwareRevision =        0x1c,
49         RegInfoSoftwareDate =            0x20,
50         RegInfoSoftwareTime =            0x28,
51         RegInfoSoftwareId =              0x30,
52         RegInfoSoftwareVersion =         0x34,
53         RegInfoBaseAddress =             0x38,
54         RegInfoMaxImageLen =             0x3c,
55         RegInfoBootloaderDate =          0x40,
56         RegInfoBootloaderTime =          0x48,
57         RegInfoDebuggerDate =            0x50,
58         RegInfoDebuggerTime =            0x58,
59         RegInfoDebuggerId =              0x60,
60         RegInfoDebuggerVersion =         0x64
61     };
62
63     enum {
64         MaxRetries = 10,
65     };
66
67     IMPL_DEBUG_MODULE( BootloaderManager, BootloaderManager, DEBUG_LEVEL_NORMAL );
68 }
69
70 BeBoB::BootloaderManager::BootloaderManager(Ieee1394Service& ieee1349service,
71                                             fb_nodeid_t nodeId )
72     : m_ieee1394service( &ieee1349service )
73     , m_protocolVersion( eBPV_Unknown )
74     , m_isAppRunning( false )
75 {
76     memset( &m_cachedInfoRegs, 0, sizeof( m_cachedInfoRegs ) );
77
78     m_configRom = new ConfigRom( *m_ieee1394service, nodeId );
79     // XXX throw exception if initialize fails!
80     m_configRom->initialize();
81     cacheInfoRegisters();
82
83     switch(  m_cachedInfoRegs.m_protocolVersion ) {
84     case 1:
85         m_protocolVersion = eBPV_V1;
86         break;
87     case 3:
88         m_protocolVersion = eBPV_V3;
89         break;
90     default:
91         // exception?
92         break;
93     }
94
95     pthread_mutex_init( &m_mutex, 0 );
96     pthread_cond_init( &m_cond, 0 );
97
98     m_functor = new MemberFunctor0< BeBoB::BootloaderManager*,
99                 void (BeBoB::BootloaderManager::*)() >
100                 ( this, &BeBoB::BootloaderManager::busresetHandler, false );
101     m_ieee1394service->addBusResetHandler( m_functor );
102 }
103
104 BeBoB::BootloaderManager::~BootloaderManager()
105 {
106     m_ieee1394service->remBusResetHandler( m_functor );
107     delete( m_functor );
108
109     delete m_configRom;
110
111     pthread_cond_destroy( &m_cond );
112     pthread_mutex_destroy( &m_mutex );
113 }
114
115 bool
116 BeBoB::BootloaderManager::cacheInfoRegisters()
117 {
118     if ( !m_configRom->updatedNodeId() ) {
119         return false;
120     }
121
122     if ( !m_ieee1394service->read(
123              0xffc0 | m_configRom->getNodeId(),
124              AddrRegInfo,
125              sizeof( m_cachedInfoRegs )/4,
126              reinterpret_cast<fb_quadlet_t*>( &m_cachedInfoRegs ) ) )
127     {
128         return false;
129     }
130
131     if ( m_cachedInfoRegs.m_bootloaderVersion != 0x0 ) {
132         m_isAppRunning = false;
133     } else {
134         m_isAppRunning = true;
135     }
136
137     m_cachedInfoRegs.m_guid = ( m_cachedInfoRegs.m_guid >> 32 )
138                               | ( m_cachedInfoRegs.m_guid << 32 );
139
140     return true;
141 }
142
143 bool
144 BeBoB::BootloaderManager::cacheInfoRegisters( int retries )
145 {
146     for ( int i = 0; i < retries; ++i ) {
147         if ( cacheInfoRegisters() ) {
148             return true;
149         }
150         sleep( 1 );
151     }
152
153     return false;
154 }
155
156 void
157 BeBoB::BootloaderManager::printInfoRegisters()
158 {
159     using namespace std;
160
161     if ( !cacheInfoRegisters() ) {
162         debugError( "Could not read info registers\n" );
163         return;
164     }
165
166     printf( "Info Registers\n" );
167     printf( "\tManufactors Id:\t\t%s\n",
168             makeString( m_cachedInfoRegs.m_manId ).c_str() );
169     printf( "\tProtocol Version:\t0x%08x\n",
170             m_cachedInfoRegs.m_protocolVersion );
171     printf( "\tBootloader Version:\t0x%08x\n",
172             m_cachedInfoRegs.m_bootloaderVersion );
173     printf( "\tGUID:\t\t\t0x%08x%08x\n",
174             ( unsigned int )( m_cachedInfoRegs.m_guid >> 32 ),
175             ( unsigned int )( m_cachedInfoRegs.m_guid & 0xffffffff ) );
176     printf( "\tHardware Model ID:\t0x%08x\n",
177             m_cachedInfoRegs.m_hardwareModelId );
178     printf( "\tHardware Revision:\t0x%08x\n",
179             m_cachedInfoRegs.m_hardwareRevision );
180     if (  m_cachedInfoRegs.m_softwareDate
181           && m_cachedInfoRegs.m_softwareTime )
182     {
183         printf( "\tSoftware Date:\t\t%s, %s\n",
184                 makeDate( m_cachedInfoRegs.m_softwareDate ).c_str(),
185                 makeTime( m_cachedInfoRegs.m_softwareTime ).c_str() );
186     }
187     printf( "\tSoftware Id:\t\t0x%08x\n", m_cachedInfoRegs.m_softwareId );
188     printf( "\tSoftware Version:\t0x%08x\n",
189             m_cachedInfoRegs.m_softwareVersion );
190     printf( "\tBase Address:\t\t0x%08x\n", m_cachedInfoRegs.m_baseAddress );
191     printf( "\tMax. Image Len:\t\t0x%08x\n", m_cachedInfoRegs.m_maxImageLen );
192     if ( m_cachedInfoRegs.m_bootloaderDate
193          && m_cachedInfoRegs.m_bootloaderTime )
194     {
195         printf( "\tBootloader Date:\t%s, %s\n",
196                 makeDate( m_cachedInfoRegs.m_bootloaderDate ).c_str(),
197                 makeTime( m_cachedInfoRegs.m_bootloaderTime ).c_str() );
198     }
199     if ( m_cachedInfoRegs.m_debuggerDate
200          && m_cachedInfoRegs.m_debuggerTime )
201     {
202         printf( "\tDebugger Date:\t\t%s, %s\n",
203                 makeDate( m_cachedInfoRegs.m_debuggerDate ).c_str(),
204                 makeTime( m_cachedInfoRegs.m_debuggerTime ).c_str() );
205     }
206     printf( "\tDebugger Id:\t\t0x%08x\n", m_cachedInfoRegs.m_debuggerId );
207     printf( "\tDebugger Version:\t0x%08x\n",
208             m_cachedInfoRegs.m_debuggerVersion );
209 }
210
211 bool
212 BeBoB::BootloaderManager::downloadFirmware( std::string filename )
213 {
214     using namespace std;
215
216     printf( "parse BCD file\n" );
217     std::auto_ptr<BCD> bcd = std::auto_ptr<BCD>( new BCD( filename ) );
218     if ( !bcd.get() ) {
219         debugError( "downloadFirmware: Could not open or parse BCD '%s'\n",
220                     filename.c_str() );
221         return false;
222     }
223     if ( !bcd->parse() ) {
224         debugError( "downloadFirmware: BCD parsing failed\n" );
225         return false;
226     }
227
228     printf( "prepare for download (start bootloader)\n" );
229     if ( !startBootloaderCmd() ) {
230         debugError( "downloadFirmware: Could not start bootloader\n" );
231         return false;
232     }
233
234     printf( "start downloading protocol for application image\n" );
235     if ( !downloadObject( *bcd, eOT_Application ) ) {
236         debugError( "downloadFirmware: Firmware download failed\n" );
237         return false;
238     }
239
240     printf( "start downloading protocol for CnE\n" );
241     if ( !downloadObject( *bcd, eOT_CnE ) ) {
242         debugError( "downloadFirmware: CnE download failed\n" );
243         return false;
244     }
245
246     printf( "setting CnE to factory default settings\n" );
247     if ( !initializeConfigToFactorySettingCmd() ) {
248         debugError( "downloadFirmware: Could not reinitalize CnE\n" );
249         return false;
250     }
251
252     printf( "start application\n" );
253     if ( !startApplicationCmd() ) {
254         debugError( "downloadFirmware: Could not restart application\n" );
255         return false;
256     }
257
258     return true;
259 }
260
261 bool
262 BeBoB::BootloaderManager::downloadCnE( std::string filename )
263 {
264     using namespace std;
265
266     printf( "parse BCD file\n" );
267     std::auto_ptr<BCD> bcd = std::auto_ptr<BCD>( new BCD( filename ) );
268     if ( !bcd.get() ) {
269         debugError( "downloadCnE: Could not open or parse BCD '%s'\n",
270                     filename.c_str() );
271         return false;
272     }
273     if ( !bcd->parse() ) {
274         debugError( "downloadCnE: BCD parsing failed\n" );
275         return false;
276     }
277
278     printf( "prepare for download (start bootloader)\n" );
279     if ( !startBootloaderCmd() ) {
280         debugError( "downloadCnE: Could not start bootloader\n" );
281         return false;
282     }
283
284     printf( "start downloading protocol for CnE\n" );
285     if ( !downloadObject( *bcd, eOT_CnE ) ) {
286         debugError( "downloadCnE: CnE download failed\n" );
287         return false;
288     }
289
290     printf( "setting CnE to factory default settings\n" );
291     if ( !initializeConfigToFactorySettingCmd() ) {
292         debugError( "downloadFirmware: Could not reinitalize CnE\n" );
293         return false;
294     }
295
296     printf( "start application\n" );
297     if ( !startApplicationCmd() ) {
298         debugError( "downloadCnE: Could not restart application\n" );
299         return false;
300     }
301
302     return true;
303 }
304
305
306 bool
307 BeBoB::BootloaderManager::downloadObject( BCD& bcd, EObjectType eObject )
308 {
309     using namespace std;
310
311     CommandCodesDownloadStart::EObject eCCDSObject;
312     fb_quadlet_t baseAddress;
313     fb_quadlet_t imageLength;
314     fb_quadlet_t crc;
315     fb_quadlet_t offset;
316
317     switch ( eObject ) {
318     case eOT_Application:
319         eCCDSObject = CommandCodesDownloadStart::eO_Application;
320         baseAddress = bcd.getImageBaseAddress();
321         imageLength = bcd.getImageLength();
322         crc = bcd.getImageCRC();
323         offset = bcd.getImageOffset();
324         break;
325     case eOT_CnE:
326         eCCDSObject = CommandCodesDownloadStart::eO_Config;
327         baseAddress = 0;
328         imageLength = bcd.getCnELength();
329         crc = bcd.getCnECRC();
330         offset = bcd.getCnEOffset();
331         break;
332     default:
333         return false;
334     }
335
336     CommandCodesDownloadStart ccDStart ( m_protocolVersion, eCCDSObject );
337     ccDStart.setDate( bcd.getSoftwareDate() );
338     ccDStart.setTime( bcd.getSoftwareTime() );
339     ccDStart.setId( bcd.getSoftwareId() );
340     ccDStart.setVersion( bcd.getSoftwareVersion() );
341     ccDStart.setBaseAddress( baseAddress );
342     ccDStart.setLength( imageLength );
343     ccDStart.setCRC( crc );
344
345     if ( !writeRequest( ccDStart ) ) {
346         debugError( "downloadObject: start command write request failed\n" );
347         return false;
348     }
349
350     // bootloader erases the flash, have to wait until is ready
351     // to answer our next request
352     printf( "wait unitl flash ereasing has terminated\n" );
353     sleep( 20 );
354
355     if ( !readResponse( ccDStart ) ) {
356         debugError( "downloadObject: (start) command read request failed\n" );
357         return false;
358     }
359
360     if ( ccDStart.getMaxBlockSize() < 0 ) {
361         debugError( "downloadObject: (start) command reported error %d\n",
362                     ccDStart.getMaxBlockSize() );
363         return false;
364     }
365
366     unsigned int maxBlockSize = m_configRom->getAsyMaxPayload();
367     unsigned int i = 0;
368     fb_quadlet_t address = 0;
369     bool result = true;
370     int totalBytes = imageLength;
371     int downloadedBytes = 0;
372     while ( imageLength > 0 ) {
373         unsigned int blockSize = imageLength > maxBlockSize ?
374                         maxBlockSize  : imageLength;
375
376         fb_byte_t block[blockSize];
377         if ( !bcd.read( offset, block, blockSize ) ) {
378             result = false;
379             break;
380         }
381
382         if ( !get1394Serivce()->write(
383                  0xffc0 | getConfigRom()->getNodeId(),
384                  AddrRegReqBuf,
385                  ( blockSize + 3 ) / 4,
386                  reinterpret_cast<fb_quadlet_t*>( block ) ) )
387         {
388             debugError( "downloadObject: Could not write to node %d\n",
389                         getConfigRom()->getNodeId() );
390             return false;
391         }
392
393         CommandCodesDownloadBlock ccBlock( m_protocolVersion );
394         ccBlock.setSeqNumber( i );
395         ccBlock.setAddress( baseAddress + address );
396         ccBlock.setNumberBytes( blockSize );
397
398         if ( !writeRequest( ccBlock ) ) {
399             debugError( "downloadObject: (block) write request failed" );
400             result = false;
401             break;
402         }
403         usleep( 100 );
404
405         if ( !readResponse( ccBlock ) ) {
406             debugError( "downloadObject: (block) read request failed\n" );
407             result = false;
408             break;
409         }
410
411         if ( i != ccBlock.getRespSeqNumber() ) {
412             debugError( "downloadObject: (block) wrong sequence number "
413                         "reported. %d expected, %d reported\n",
414                         i, ccBlock.getRespSeqNumber() );
415             result = false;
416             break;
417         }
418         if ( ccBlock.getRespErrorCode() != 0 ) {
419             debugError( "downloadObject: (block) failed download with "
420                         "error code 0x%08x\n", ccBlock.getRespErrorCode() );
421             result = false;
422             break;
423         }
424
425         downloadedBytes += blockSize;
426         if ( ( i % 100 ) == 0 ) {
427            printf( "%10d/%d bytes downloaded\n",
428                    downloadedBytes, totalBytes );
429         }
430
431         imageLength -= blockSize;
432         address += blockSize;
433         offset += blockSize;
434         i++;
435     }
436     printf( "%10d/%d bytes downloaded\n",
437             downloadedBytes, totalBytes );
438
439     if ( !result ) {
440         debugError( "downloadObject: seqNumber = %d, "
441                     "address = 0%08x, offset = 0x%08x, "
442                     "restImageLength = 0x%08x\n",
443                     i, address, offset, imageLength );
444     }
445
446     CommandCodesDownloadEnd ccEnd( m_protocolVersion );
447     if ( !writeRequest( ccEnd ) ) {
448         debugError( "downloadObject: (end) command write failed\n" );
449     }
450
451     printf( "wait for transaction completion\n" );
452     sleep( 10 );
453
454     if ( !readResponse( ccEnd ) ) {
455         debugError( "downloadObject: (end) command read failed\n" );
456     }
457
458     if ( result ) {
459         if ( ccEnd.getRespIsValid() ) {
460             if ( ccEnd.getRespCrc32() == crc ) {
461                 debugOutput( DebugModule::eDL_Normal,
462                              "downloadObject: CRC match\n" );
463             } else {
464                 debugError( "downloadObject: CRC mismatch. 0x%08x expected, "
465                             "0x%08x reported",
466                             crc, ccEnd.getRespCrc32() );
467                 result = false;
468             }
469         } else {
470             debugError( "downloadObject: (end) object is not valid\n" );
471             result = false;
472         }
473     }
474     printf( "download protocol successfuly completed\n" );
475     return result;
476 }
477
478 bool
479 BeBoB::BootloaderManager::programGUID( fb_octlet_t guid )
480 {
481     if ( !startBootloaderCmd() ) {
482         debugError( "programGUID: Could not start bootloader\n" );
483         return false;
484     }
485
486     if ( !programGUIDCmd( guid ) ) {
487         debugError( "programGUID: Could not program guid\n" );
488         return false;
489     }
490
491     if ( !startApplicationCmd() ) {
492         debugError( "Could not restart application\n");
493         return false;
494     }
495
496     return true;
497 }
498
499 void
500 BeBoB::BootloaderManager::busresetHandler()
501 {
502     pthread_cond_signal( &m_cond );
503 }
504
505 void
506 BeBoB::BootloaderManager::waitForBusReset()
507 {
508     pthread_cond_wait( &m_cond, &m_mutex );
509 }
510
511 bool
512 BeBoB::BootloaderManager::writeRequest( CommandCodes& cmd )
513 {
514     unsigned char buf[ ( ( cmd.getMaxSize()+3 )/4 ) * 4 ];
515     memset( buf, 0, sizeof( buf ) );
516
517     BufferSerialize se( buf,  sizeof( buf ) );
518     if ( !cmd.serialize( se ) ) {
519         debugError( "writeRequest: Could not serialize command code %d\n",
520                     cmd.getCommandCode() );
521         return false;
522     }
523
524     if ( !get1394Serivce()->write(
525              0xffc0 | getConfigRom()->getNodeId(),
526              AddrRegReq,
527              sizeof( buf )/4,
528              reinterpret_cast<fb_quadlet_t*>( buf ) ) )
529     {
530         debugError( "writeRequest: Could not ARM write to node %d\n",
531                     getConfigRom()->getNodeId() );
532         return false;
533     }
534
535     return true;
536 }
537
538 bool
539 BeBoB::BootloaderManager::readResponse( CommandCodes& writeRequestCmd )
540 {
541     const size_t buf_length = 0x40;
542     unsigned char raw[buf_length];
543     if ( !get1394Serivce()->read(
544              0xffc0 | getConfigRom()->getNodeId(),
545              AddrRegResp,
546              writeRequestCmd.getRespSizeInQuadlets(),
547              reinterpret_cast<fb_quadlet_t*>( raw ) ) )
548     {
549         return false;
550     }
551
552     BufferDeserialize de( raw, buf_length );
553     if ( !writeRequestCmd.deserialize( de ) ) {
554         debugError( "readResponse: deserialize failed\n" );
555         return false;
556     }
557
558     bool result =
559         writeRequestCmd.getProtocolVersion()
560         == writeRequestCmd.getRespProtocolVersion();
561     result &=
562         writeRequestCmd.getCommandId()
563         == writeRequestCmd.getRespCommandId();
564     result &=
565         writeRequestCmd.getCommandCode()
566         == writeRequestCmd.getRespCommandCode();
567     #ifdef DEBUG
568        if ( !result ) {
569            debugError( "readResponse: protocol version: %d expected, "
570                        " %d reported\n",
571                        writeRequestCmd.getProtocolVersion(),
572                        writeRequestCmd.getRespProtocolVersion() );
573            debugError( "readResponse: command id: %d expected, "
574                        " %d reported\n",
575                        writeRequestCmd.getCommandId(),
576                        writeRequestCmd.getRespCommandId() );
577            debugError( "readResponse: command code: %d expected, "
578                        " %d reported\n",
579                        writeRequestCmd.getCommandCode(),
580                        writeRequestCmd.getRespCommandCode() );
581        }
582     #endif
583     return result;
584 }
585
586 bool
587 BeBoB::BootloaderManager::startBootloaderCmd()
588 {
589     CommandCodesReset cmd( m_protocolVersion,
590                            CommandCodesReset::eSM_Bootloader ) ;
591     if ( !writeRequest( cmd ) ) {
592         debugError( "startBootloaderCmd: writeRequest failed\n" );
593         return false;
594     }
595
596     waitForBusReset();
597     if ( !cacheInfoRegisters( MaxRetries ) ) {
598         debugError( "startBootloaderCmd: Could not read info registers\n" );
599         return false;
600     }
601
602     // wait for bootloader finish startup sequence
603     // there is no way to find out when it has finished
604     sleep( 10 );
605
606     return true;
607 }
608
609 bool
610 BeBoB::BootloaderManager::startApplicationCmd()
611 {
612     CommandCodesGo cmd( m_protocolVersion,
613                            CommandCodesGo::eSM_Application ) ;
614     if ( !writeRequest( cmd ) ) {
615         debugError( "startApplicationCmd: writeRequest failed\n" );
616         return false;
617     }
618
619     return true;
620 }
621
622 bool
623 BeBoB::BootloaderManager::programGUIDCmd( fb_octlet_t guid )
624 {
625     CommandCodesProgramGUID cmd( m_protocolVersion, guid );
626     if ( !writeRequest( cmd ) ) {
627         debugError( "programGUIDCmd: writeRequest failed\n" );
628         return false;
629     }
630
631     sleep( 1 );
632
633     return true;
634 }
635
636 bool
637 BeBoB::BootloaderManager::initializePersParamCmd()
638 {
639     CommandCodesInitializePersParam cmd( m_protocolVersion );
640     if ( !writeRequest( cmd ) ) {
641         debugError( "initializePersParamCmd: writeRequest failed\n" );
642         return false;
643     }
644
645     sleep( 1 );
646
647     return true;
648 }
649
650 bool
651 BeBoB::BootloaderManager::initializeConfigToFactorySettingCmd()
652 {
653     CommandCodesInitializeConfigToFactorySetting cmd( m_protocolVersion );
654     if ( !writeRequest( cmd ) ) {
655         debugError( "initializeConfigToFactorySettingCmd: writeRequest failed\n" );
656         return false;
657     }
658
659     sleep( 5 );
660
661     return true;
662 }
Note: See TracBrowser for help on using the browser.