//////////////////////////////////////////////////////////////////////////////// // The WaitForTinyBooterUpload method was designed to allow porting kit partners // to define how/when tinybooter mode is entered as well as configure default // timeout values. // // timeout_ms - this parameter determines the time in milliseconds TinyBooter is // supposed to wait for commands from the host. A -1 value will // indicate to wait forever. // return value - the boolean return value indicates whether TinyBooter should enter // upload mode. If false is returned the booter will attempt to // launch the first application in FLASH that it finds. If the return // value is true, TinyBooter will wait for the given timeout value // (parameter timeout_ms) for valid commands before launching the first // application //////////////////////////////////////////////////////////////////////////////// bool WaitForTinyBooterUpload( INT32 &timeout_ms ) { bool enterBooterMode = false; GPIO_BUTTON_CONFIG * ButtonConfig = &g_GPIO_BUTTON_Config; // wait forever when using RAM build #if defined(TARGETLOCATION_RAM) enterBooterMode = true; timeout_ms = -1; #endif // user override (UP+DOWN buttons held) if ((ButtonConfig->Mapping[BUTTON_ENTR_IDX].m_HW != GPIO_PIN_NONE)) { Events_WaitForEvents(0,100); // wait for buttons to init if(!CPU_GPIO_GetPinState( ButtonConfig->Mapping[BUTTON_ENTR_IDX].m_HW)) { UINT32 down, up; // user override, so lets stay for 2sec timeout_ms = 2000; enterBooterMode = true; while(Buttons_GetNextStateChange(down, up) && (0 != (down & BUTTON_ENTR))); } } return enterBooterMode; }
//////////////////////////////////////////////////////////////////////////////// // The TinyBooter_OnStateChange method is an event handler for state changes in // the TinyBooter. It is designed to help porting kit users control the tinybooter // execution and allow them to add diagnostics. //////////////////////////////////////////////////////////////////////////////// void TinyBooter_OnStateChange( TinyBooterState state, void* data, void ** retData ) { switch(state) { //////////////////////////////////////////////////////////////////////////////////// // State_EnterBooterMode - TinyBooter has entered upload mode //////////////////////////////////////////////////////////////////////////////////// case State_EnterBooterMode: CPU_GPIO_EnableOutputPin(LED1, TRUE); CPU_GPIO_EnableOutputPin(LED2, TRUE); CPU_GPIO_EnableOutputPin(LED3, TRUE); #if defined(TARGETLOCATION_RAM) CPU_GPIO_EnableOutputPin(LED4, TRUE); #else CPU_GPIO_EnableOutputPin(LED4, FALSE); #endif hal_fprintf( STREAM_LCD, "Waiting\r" ); break; //////////////////////////////////////////////////////////////////////////////////// // State_ButtonPress - A button was pressed while Tinybooter // The data parameter is a pointer to the timeout value for the booter mode. //////////////////////////////////////////////////////////////////////////////////// case State_ButtonPress: if(NULL != data) { UINT32 down, up; INT32* timeout_ms = (INT32*)data; // wait forever if a button was pressed *timeout_ms = -1; // process buttons while(Buttons_GetNextStateChange(down, up)) { // leave a way to exit boot mode incase it was accidentally entered if(0 != (down & BUTTON_ENTR)) { // force an enumerate and launch *timeout_ms = 0; } } } break; //////////////////////////////////////////////////////////////////////////////////// // State_ValidCommunication - TinyBooter has received valid communication from the host // The data parameter is a pointer to the timeout value for the booter mode. //////////////////////////////////////////////////////////////////////////////////// case State_ValidCommunication: if(NULL != data) { INT32* timeout_ms = (INT32*)data; // if we received any com/usb data then let's change the timeout to at least 20 seconds if(*timeout_ms != -1 && *timeout_ms < 20000) { *timeout_ms = 20000; } } break; //////////////////////////////////////////////////////////////////////////////////// // State_Timeout - The default timeout for TinyBooter has expired and TinyBooter will // perform an EnumerateAndLaunch //////////////////////////////////////////////////////////////////////////////////// case State_Timeout: break; //////////////////////////////////////////////////////////////////////////////////// // State_MemoryXXX - Identifies memory accesses. //////////////////////////////////////////////////////////////////////////////////// case State_MemoryWrite: hal_fprintf( STREAM_LCD, "Wr: 0x%08x\r", (UINT32)data ); break; case State_MemoryErase: hal_fprintf( STREAM_LCD, "Er: 0x%08x\r", (UINT32)data ); break; //////////////////////////////////////////////////////////////////////////////////// // State_CryptoXXX - Start and result of Crypto signature check //////////////////////////////////////////////////////////////////////////////////// case State_CryptoStart: hal_fprintf( STREAM_LCD, "Chk signature \r" ); hal_printf( "Chk signature \r" ); break; // The data parameter is a boolean that represents signature PASS/FAILURE case State_CryptoResult: if((bool)data) { hal_fprintf( STREAM_LCD, "Signature PASS\r\n\r\n" ); hal_printf( "Signature PASS\r\n\r\n" ); } else { hal_fprintf( STREAM_LCD, "Signature FAIL\r\n\r\n" ); hal_printf( "Signature FAIL\r\n\r\n" ); } DebuggerPort_Flush(HalSystemConfig.DebugTextPort); break; //////////////////////////////////////////////////////////////////////////////////// // State_Launch - The host has requested to launch an application at a given address, // or a timeout has occured and TinyBooter is about to launch the // first application it finds in FLASH. // // The data parameter is a UINT32 value representing the launch address //////////////////////////////////////////////////////////////////////////////////// case State_Launch: if(NULL != data) { CPU_GPIO_EnableOutputPin(LED1, FALSE); hal_fprintf( STREAM_LCD, "Starting application at 0x%08x\r\n", (UINT32)data ); // copy the native code from the Load area to execute area. // set the *retAddres to real execute address after loading the data // *retData = exeAddress *retData =(void*) ((UINT32)data | 1); // set Thumb bit! } break; } }
void ApplicationEntryPoint() { UINT32 ComEvent; g_State.Initialize(); ComEvent = 0; if(COM_IsSerial(g_State.UsartPort) && (g_State.UsartPort != COM_NULL)) { ComEvent = SYSTEM_EVENT_FLAG_COM_IN; } #if !defined(TARGETLOCATION_RAM) g_State.WaitForActivity = (g_State.ProgramCount != 0); // is there a main app? #else g_State.WaitForActivity = FALSE; // forever #endif { UINT32 ButtonsPressed; UINT32 ButtonsReleased; char c; // clear any events present from startup while(Events_Get( SYSTEM_EVENT_FLAG_ALL )); // clear any junk from com port buffers while(DebuggerPort_Read( g_State.UsartPort, &c, sizeof(c) )); // clear any junk from button buffer while(Buttons_GetNextStateChange( ButtonsPressed, ButtonsReleased )); } { BOOL ProcessingSREC = FALSE; BOOL ProcessingXREC = FALSE; INT32 ProcessingZENFLASH = 0; INT32 Mode = 0; INT32 MenuChoice = 1; // main application location when USB not enabled BOOL MenuUpdate = TRUE; UINT32 USBEvent = 0; COM_HANDLE ReadPort = COM_NULL; int MenuOffset = 1; // no USB enabled INT64 WaitTimeout = 0; #if defined(PLATFORM_ARM_MOTE2) CPU_GPIO_SetPinState( LED1_GREEN, LED_ON ); #endif if(g_State.WaitForActivity) { WaitTimeout = HAL_Time_CurrentTime() + (INT64)g_State.WaitInterval * (10 * 1000); hal_printf( "Waiting %d.%03d second(s) for hex upload\r\n", g_State.WaitInterval / 1000, g_State.WaitInterval % 1000 ); } else { hal_printf( "Waiting forever for hex upload\r\n" ); } // checking the existence of Usb Driver, all the default values are set to no USB if( USB_DEVICE_STATE_NO_CONTROLLER != USB_GetStatus( ConvertCOM_UsbController(g_State.UsbPort) ) ) { g_State.UsingUsb = TRUE; MenuChoice = 2; MenuOffset = 2; } while(true) { if(MenuUpdate) { MenuUpdate = FALSE; LCD_Clear(); hal_fprintf( STREAM_LCD, "\f"); switch(Mode) { case 0: hal_fprintf( STREAM_LCD, " Zen Boot\r\n\r\n" ); hal_fprintf( STREAM_LCD, "%c PortBooter\r\n", MenuChoice == 0 ? '*' : ' ' ); if(g_State.UsingUsb) { hal_fprintf( STREAM_LCD, "%c FlashUSB\r\n", MenuChoice == 1 ? '*' : ' ' ); } for(int i = 0; i < g_State.ProgramCount; i++) { hal_fprintf( STREAM_LCD, "%c Prg:%08x\r\n", (i+MenuOffset) == MenuChoice ? '*' : ' ', g_State.Programs[i] ); } break; case 1: hal_printf( "PortBooter v%d.%d.%d.%d\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_REVISION); hal_fprintf( STREAM_LCD, "Waiting forever for hex upload\r\n" ); break; case 2: hal_fprintf( STREAM_LCD, "FlashUSB\r\n" ); hal_fprintf( STREAM_LCD, "Waiting forever for hex upload\r\n" ); break; } } UINT32 Events = Events_WaitForEvents( ComEvent | SYSTEM_EVENT_FLAG_BUTTON | SYSTEM_EVENT_FLAG_USB_IN, 2000 ); if(Events & SYSTEM_EVENT_FLAG_BUTTON) { UINT32 ButtonsPressed; UINT32 ButtonsReleased; Events_Clear( SYSTEM_EVENT_FLAG_BUTTON ); while(Buttons_GetNextStateChange( ButtonsPressed, ButtonsReleased )); { if(g_State.SerialPortActive == FALSE) { //printf("%02x %02x\r\n", ButtonsPressed, ButtonsReleased); // up if(ButtonsPressed & BUTTON_UP) { switch(Mode) { case 0: MenuChoice = __max( MenuChoice-1, 0 ); break; } g_State.WaitForActivity = FALSE; MenuUpdate = TRUE; } // down if(ButtonsPressed & BUTTON_DOWN) { switch(Mode) { case 0: MenuChoice = __min( MenuChoice+1, g_State.ProgramCount + MenuOffset-1 ); break; } g_State.WaitForActivity = FALSE; MenuUpdate = TRUE; } // enter button if(ButtonsPressed & BUTTON_ENTR) { switch(Mode) { case 0: if(MenuChoice == 0) { Mode = 1; //UsingUsb = FALSE; } else if(g_State.UsingUsb && MenuChoice == 1) { Mode = 2; USB_Configure( ConvertCOM_UsbController(g_State.UsbPort), &UsbDefaultConfiguration ); USB_Initialize( ConvertCOM_UsbController(g_State.UsbPort) ); USB_OpenStream( ConvertCOM_UsbStream(g_State.UsbPort), USB_DEBUG_EP_WRITE, USB_DEBUG_EP_READ ); //UsingUsb = TRUE; } else { StartApplication( (void (*)())g_State.Programs[MenuChoice-MenuOffset] ); } break; case 1: Mode = 0; break; case 2: // USB_Uninitialize(); Mode = 0; break; } g_State.WaitForActivity = FALSE; MenuUpdate = TRUE; } if(ButtonsReleased) { MenuUpdate = TRUE; } } } } if((Events & ComEvent) || (Events & SYSTEM_EVENT_FLAG_USB_IN)) { char c; if(Events & ComEvent) { Events_Clear( ComEvent ); ReadPort = g_State.UsartPort; g_State.pStreamOutput = ReadPort; } else { USBEvent = USB_GetEvent( ConvertCOM_UsbController(g_State.UsbPort), USB_EVENT_ALL ); if( !(USBEvent & g_State.UsbEventCode) ) continue; g_State.pStreamOutput = g_State.UsbPort; ReadPort = g_State.UsbPort; } while(DebuggerPort_Read( ReadPort, &c, sizeof(c) )) { if(ProcessingSREC) { ProcessingSREC = g_SREC.Process( c ); } else if(ProcessingXREC) { ProcessingXREC = g_XREC.Process( c ); } else if(ProcessingZENFLASH) { const char Signature[] = "ZENFLASH\r"; //printf( "Got %d at %d\r\n", c, ProcessingZENFLASH ); if(Signature[ProcessingZENFLASH++] == c) { if(Signature[ProcessingZENFLASH] == 0) { SignalActivity(); ProcessingZENFLASH = 0; } } else { ProcessingZENFLASH = 0; } } else if('S' == c) { ProcessingSREC = TRUE; } else if('X' == c) { ProcessingXREC = TRUE; } else if('Z' == c) { ProcessingZENFLASH = 1; } } } if(g_State.WaitForActivity && WaitTimeout < HAL_Time_CurrentTime()) { #if defined(PLATFORM_ARM_MOTE2) CPU_GPIO_SetPinState(LED1_GREEN, LED_OFF); // Turn off Green LED for iMOTE2 #endif // we didn't see anything on serial port for wait interval (2 seconds nominally), // continue with code - just run the normal application StartApplication( (void (*)())g_State.Programs[0] ); } } } }
//////////////////////////////////////////////////////////////////////////////// // The TinyBooter_OnStateChange method is an event handler for state changes in // the TinyBooter. It is designed to help porting kit users control the tinybooter // execution and allow them to add diagnostics. //////////////////////////////////////////////////////////////////////////////// void TinyBooter_OnStateChange(TinyBooterState state, void* data, void ** retData) { switch (state) { //////////////////////////////////////////////////////////////////////////////////// // State_EnterBooterMode - TinyBooter has entered upload mode //////////////////////////////////////////////////////////////////////////////////// case State_EnterBooterMode: hal_fprintf(STREAM_LCD, "Waiting\r"); break; //////////////////////////////////////////////////////////////////////////////////// // State_ButtonPress - A button was pressed while Tinybooter // The data parameter is a pointer to the timeout value for the booter mode. //////////////////////////////////////////////////////////////////////////////////// case State_ButtonPress: if (NULL != data) { UINT32 down, up; INT32* timeout_ms = (INT32*)data; // wait forever if a button was pressed *timeout_ms = -1; // process buttons while (Buttons_GetNextStateChange(down, up)) { // leave a way to exit boot mode incase it was accidentally entered if (0 != (down & BUTTON_ENTR)) { // force an enumerate and launch *timeout_ms = 0; } } } break; //////////////////////////////////////////////////////////////////////////////////// // State_ValidCommunication - TinyBooter has received valid communication from the host // The data parameter is a pointer to the timeout value for the booter mode. //////////////////////////////////////////////////////////////////////////////////// case State_ValidCommunication: if (NULL != data) { INT32* timeout_ms = (INT32*)data; // if we received any com/usb data then let's change the timeout to at least 20 seconds if (*timeout_ms != -1 && *timeout_ms < 20000) { *timeout_ms = 20000; } } break; //////////////////////////////////////////////////////////////////////////////////// // State_Timeout - The default timeout for TinyBooter has expired and TinyBooter will // perform an EnumerateAndLaunch //////////////////////////////////////////////////////////////////////////////////// case State_Timeout: break; //////////////////////////////////////////////////////////////////////////////////// // State_MemoryXXX - Identifies memory accesses. //////////////////////////////////////////////////////////////////////////////////// case State_MemoryWrite: hal_fprintf(STREAM_LCD, "Wr: 0x%08x\r", (UINT32)data); break; case State_MemoryErase: hal_fprintf(STREAM_LCD, "Er: 0x%08x\r", (UINT32)data); break; //////////////////////////////////////////////////////////////////////////////////// // State_CryptoXXX - Start and result of Crypto signature check //////////////////////////////////////////////////////////////////////////////////// case State_CryptoStart: hal_fprintf(STREAM_LCD, "Chk signature \r"); hal_printf("Chk signature \r"); break; // The data parameter is a boolean that represents signature PASS/FAILURE case State_CryptoResult: if ((bool)data) { hal_fprintf(STREAM_LCD, "Signature PASS\r\n\r\n"); hal_printf("Signature PASS\r\n\r\n"); } else { hal_fprintf(STREAM_LCD, "Signature FAIL\r\n\r\n"); hal_printf("Signature FAIL\r\n\r\n"); } DebuggerPort_Flush(HalSystemConfig.DebugTextPort); break; //////////////////////////////////////////////////////////////////////////////////// // State_Launch - The host has requested to launch an application at a given address, // or a timeout has occured and TinyBooter is about to launch the // first application it finds in FLASH. // // The data parameter is a UINT32 value representing the launch address //////////////////////////////////////////////////////////////////////////////////// case State_Launch: UINT32 address = (UINT32)data; if (NULL != data) { hal_fprintf(STREAM_LCD, "Starting application at 0x%08x\r\n", address); debug_printf("Starting application at 0x%08x\r\n", address); if (address == CODE_BASEADDRESS || address == EXCODE_BASEADDRESS) { BlockStorageDevice *device; ByteAddress ByteAddress; UINT32 physicalAddress = CODE_BASEADDRESS; if (BlockStorageList::FindDeviceForPhysicalAddress(&device, physicalAddress, ByteAddress)) { BlockStorageStream stream; if (stream.Initialize(BlockUsage::CODE, device)) { if (stream.CurrentAddress() != CODE_BASEADDRESS) { hal_fprintf(STREAM_LCD, "Warn: at wrong offset: 0x%08x\r\n", (UINT32)stream.CurrentAddress()); debug_printf("Warn: at wrong offset: 0x%08x\r\n", (UINT32)stream.CurrentAddress()); stream.Seek(CODE_BASEADDRESS - stream.CurrentAddress(), BlockStorageStream::SeekCurrent); } BYTE *dst; dst = (BYTE *)EXCODE_BASEADDRESS; stream.Read(&dst, CODE_SIZE); if (retData != NULL) { *retData = (void*)EXCODE_BASEADDRESS; } CPU_DrainWriteBuffers(); } } } else if (retData != NULL) { *retData = (void*)data; } } break; } }