How do i use the RollBack Feature of ESP32 Efficiently? - freertos

As i Understand the rollback feature is supposed to get implemented and the app is supposed to get into Diagnosis mode as soon as i enable APP_ROLLBACK_ENABLE Feature, yet my app is not going into diagnosis state. The state is mentioned in code :
As it can be seen here that my state is supposedly not ESP_VERIFY
esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
print_sha256(sha_256, "SHA-256 for current firmware: ");
const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
ESP_LOGI(TAG, "Get State Partition was Successfull");
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
// run diagnostic function ...
bool diagnostic_is_ok = true;
if (diagnostic_is_ok) {
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ...");
esp_ota_mark_app_valid_cancel_rollback();
} else {
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ...");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
EXPECTED: App Diagnosis should occur
ACTUAL: App Diagnosis code is not getting state :ESP_OTA_IMG_PENDING_VERIFY

When you download your firmware first time, OTADATA will be erased. In bootloader, it set to the right ota_seq and ESP_OTA_IMG_VALID state. It means that in an application your code will be not checked by the diagnostic code, because you have only one bootable app and rollback is not possible.
After OTA your app has ESP_OTA_IMG_PENDING_VERIFY state and only while first booting this part of code should be executed. This state will be changed esp_ota_mark_app_valid_cancel_rollback() function to ESP_OTA_IMG_VALID.

Related

Why does the Zynq Ultrascale+ FPD watchdog status remain at zero when it appears to be configured correctly?

I've written the following code for the Zynq Ultrascale+ Z106 board and stepped through it examining the registers. They seem to be set correctly. I start the watchdog and then later (not shown) I restart it before entering a loop. But STATUS.WDZ never reaches 1. This is for the APUs and I've verified that it's using the correct base address for the FPD SWDT. I've read through the technical reference manual several times. What am I missing?
This code is part of a C++ class where start() and stop() map to the corresponding Xilinx API functions.
I'm using the most recent version of Vitis.
UPDATE: I changed XPAR_XWDTPS_1_DEVICE_ID to XPAR_XWDTPS_0_DEVICE_ID and WDZ is set after some time has elapsed. My understanding is that this is for the RPUs and LPD however and so, while I appear to be able to configure it from an APU core, the interrupt signal will go to the GIC instance associated with an RPU core and will be of no help.
int status;
auto configuration = XWdtPs_LookupConfig(XPAR_XWDTPS_1_DEVICE_ID);
status = XWdtPs_CfgInitialize(&_wdt, configuration, configuration->BaseAddress);
if (status != XST_SUCCESS)
{
printf("Watchdog: Configuration initialization failed.");
return;
}
status = XWdtPs_SelfTest(&_wdt);
if (status != XST_SUCCESS)
{
printf("Watchdog: Self testing failed.");
return;
}
// Stop / disable the timer before configuring.
stop();
// Set the fields of the control register. The counter reset value is the count value that is
// used when the watchdog is restarted. The counter is 24 bits and this value sets the upper 12
// bits: 0x00NN'NFFF.
XWdtPs_SetControlValue(&_wdt, XWDTPS_COUNTER_RESET, 0);
// Set the initial divider ratio at the smallest value.
XWdtPs_SetControlValue(&_wdt, XWDTPS_CLK_PRESCALE, XWDTPS_CCR_PSCALE_0008);
// Disable the reset output.
output_enabled(RESET_OUTPUT, false);
// Enable the IRQ output.
output_enabled(IRQ_OUTPUT, true);
start();

Network change state not getting detected in Release mode background - Xamarin.iOS

In my application, I have used Xamarin.Essentials to detect network changes in background & fire notifications based on network availability. The code works perfectly on the device & simulator during Debug. However, the Xamarin.Essentials fail to detect connectivity changes in Release mode, especially in the background. The events get triggered when the application reenters into the application (when application becomes ro foreground)
Following is the code I have used
CrossConnectivity.Current.ConnectivityChanged += Current_ConnectivityChanged;
private void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
if (_networkService.IsConnected())
{
ShowBannerNotificaiton("Internet", "Available", "data1");
}
else
{
ShowBannerNotificaiton("Internet", "Not Available", "data2");
}
}
Appreciate the solution given

CloudKit App to handle different iCloud accounts

I have an app that keeps user data in a private database using CloudKit and iCloud. I have written code to handle when the user logs out of iCloud and back in as a different user via Settings -> iCloud on their device. I am currently in Beta Testing mode and when I try this as an internal tester, the app crashes when I change accounts. When I test this in development mode using either the Xcode simulator or a real device, my code works great. My question is: should CloudKit apps be able to handle when the iCloud account changes on the device? If so, is this case able to be tested with internal testing via TestFlight. My code to handle account changes is below...
func isCloudAccountAvailableASync() {
container.accountStatusWithCompletionHandler { (accountStatus, error) in
switch accountStatus {
case .Available:
print("INFO: iCloud Available!")
// begin sync process by finding the current iCloud user
self.fetchUserID()
return
case .NoAccount:
print("INFO: No iCloud account")
case .Restricted:
print("WARNING: iCloud restricted")
case .CouldNotDetermine:
print("WARNING: Unable to determine iCloud status")
}
// if you get here, no sync happened so make sure to exec the callback
self.syncEnded(false)
}
}
func fetchUserID(numTries: Int = 0) {
container.fetchUserRecordIDWithCompletionHandler( { recordID, error in
if let error = error {
// error handling code
// reach here then fetchUser was a failure
self.syncEnded(false)
}
else {
// fetchUserID success
if self.lastiCloudUser == nil {
print("INFO: our first iCloud user! \(recordID)")
self.saveUserID()
}
else if !recordID!.isEqual(self.lastiCloudUser) {
// User has changed!!!!!!!!!!!!!
self.saveUserID()
// delete all local data
// reset the saved server token
self.saveServerToken(nil)
// try again with reset fields
}
// else user never changed, then just create a zone
// continue the sync process
self.initZone()
}
})
}
---EDIT/UPDATE:---
Here is a screenshot of my crash log
---EDIT/UPDATE 2:---
I was able to generate another crash with a different crash log. This crash log still doesn't point to my code, but at least describes a function...
I kept making it crash and somehow got a crash log that included a line of code I could link to a line in my Xcode project. My issue was with NSOrderedSet and iOS 9. That issue can be found here. I do not know why I only got hex in my crash log before, if anyone knows how to deal with hex crash logs I would love to hear it.
Here are the answers to my original question for anyone out there:
Should CloudKit apps be able to handle when the iCloud account changes on the device?
Answer: Yes
If so, is this case able to be tested with internal testing via TestFlight?
Answer: Yes
It's hard to say were your app crashes exactly.
You have to be aware that after an account change you should reset the state of your app (clearing local user data and navigating away from the screen that has user specific data)
On startup of your app you should call a function like this:
func reactToiCloudloginChanges() {
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSUbiquityIdentityDidChange, object: nil, queue: nil) { _ in
// The user’s iCloud login changed: should refresh all local user data here.
Async.main {
self.viewController?.removeFromParentViewController()
// Or some other code to go back to your start screen.
}
return
}
}

Why does Social.localUser.Authenticate lead to crash when there is no internet connection in Unity app?

With an internet connection
Everything works flawlessly. There is no memory problem leading to crash.
With no internet connection
The app proceeds to the menu screen, where it eventually crashes because it is out of memory.
I have concluded that the problem lies in the following line of code
Social.localUser.Authenticate
When I comment out the above line, the memory problem goes away when there is no internet connection.
Here is my relevant code
void Start ()
{
Social.localUser.Authenticate(ProcessAuthentication);
}
public void ProcessAuthentication(bool success)
{
if(success)
Debug.Log ("Authenticated");
else
Debug.Log ("Failed to authenticate");
}
Leading up to the crash
2016-02-27 15:46:37.131 BrickBall[449:60670] Received memory warning.
WARNING -> applicationDidReceiveMemoryWarning()
2016-02-27 15:46:37.302 BrickBall[449:60670] Received memory warning.
WARNING -> applicationDidReceiveMemoryWarning()
2016-02-27 15:46:37.349 BrickBall[449:60670] Received memory warning.
WARNING -> applicationDidReceiveMemoryWarning()
2016-02-27 15:46:37.437 BrickBall[449:60670] Received memory warning.
WARNING -> applicationDidReceiveMemoryWarning()
Message from debugger: Terminated due to memory issue
Why would that line of code be causing the out of memory crash when there is no internet connect?
My guess is that you'll eventually need to talk to Unity. Game center will use cached credentials when there's no network connectivity to report that it successfully connected to the server and authenticated, even though it didn't. I have a bug open--and an ongoing discussion--with Apple on this. This behavior allows some game types to continue even when there's no network, then sync up later when connection is restored. However, I ran into problems where I assumed I could do things because GC said it was authenticated, but I really couldn't because it really wasn't. :/
This means apps have to handle three cases:
successful authentication with GC
failed authentication with GC
failed authentication, but reported as successful based on cached data
It's possible that Unity doesn't handle the third situation. To confirm or refute this, try the following:
Confirm that Unity does cleanly handle authentication failures
establish connectivity
log out of game center
Break connectivity (airplane mode, etc)
Retry your app
I would expect that success would be false at this point and run cleanly.
If that works as expected, I'd talk to Unity about how they handle Game Center reporting a (cached) success in a disconnected situation.
Edit2:
I had to go back and look at my code to see exactly how I hardened against it. The scenario was: while completely disconnected and/or in airplane mode, Game Center was presenting the "welcome back" message and localPlayer.authenticated was set to YES... BUT, the error code was set and complaining that it couldn't connect.
I opened bug 22232706, "[GKLocalPlayer localPlayer].authenticated always returns true after any authentication handler is set," and which still has an ongoing discussion. Apple confirmed the behavior, but says its intended.
Below is how I hardened my authentication handler to deal with this situation. It won't help you since Unity is handling this for you, but I thought other readers may find this helpful. (The TL;DR version is: always always always check the error code first, before you check .authenticated or before you check if viewController is set)
[localPlayer setAuthenticateHandler:^(UIViewController *loginViewController, NSError *error)
{
//Note: this handler fires once when you call setAuthenticated, and again when the user completes the login screen (if necessary)
//did we get an error? Could be the result of either the initial call, or the result of the login attempt
//Very important: ALWAYS check `error` before checking for a viewController or .authenticated.
if (error)
{
//Here's a fun fact... even if you're in airplane mode and can't communicate to the server,
//when this call back fires with an error code, localPlayer.authenticated is sometimes set to YES despite the total failure. ><
//combos seen so far:
//error.code == -1009 -> authenticated = YES
//error.code == 2 -> authenticated = NO
//error.code ==3 -> authenticated = YES
if ([GKLocalPlayer localPlayer].authenticated == YES)
{
NSLog(#"error.code = %ld but localPlayer.authenticated = %d", (long)error.code, [GKLocalPlayer localPlayer].authenticated);
}
//Do stuff here to disable network play, disable buttons, warn users, etc.
return;
}
//if we received a loginViewContoller, then the user needs to log in.
if (loginViewController)
{
//the user isn't logged in, so show the login screen.
[rootVC2 presentViewController:loginViewController animated:NO completion:^
{
//was the login successful?
if ([GKLocalPlayer localPlayer].authenticated)
{
//enable network play, or refresh matches or whatever you need to do...
}
}];
}
//if there was not loginViewController and no error, then the user is alreay logged in
else
{
//the user is already logged in
//refresh matches, leaderboards, whatever you need to do...
}
}];

Which event tells you that the device is successfully started

I am making an application that auto starts when the phone restarts. I want to run some events when the phone complets its restart. The UiApp is running even before the device finishes his reset cause I configured the app as an auto start app.
What event should I listen too and that starts when the phone completes the reboot, not in between?
Thanks
It is possible to know if the system is in startup by using :
ApplicationManager.isStartup()
You will need to poll this using a timer till it returns false. However it must be borne in mind that this means that the OS has booted and the system is able to run the application. It does not mean that the entire environment for your application to run is set up completely. For example (as noted by Michael) microSD card might not have been mounted, network connectivity might not been established, or some other service on which your application might depend is not yet available. It's up to you to verify they are available before you begin working of your application.
The approach you need to take is:
Poll if isStartup returns false (System is not in startup phase)
Implement FileSystemListener to check if microSD card is mounted.
Note that mount name for a microSD card is "SDCard".
class FileSystemListenerImpl implements FileSystemListener
{
final static String SDCARD_NAME ="SDCard/";
public FileSystemListenerImpl( )
{
}
public void rootChanged( int state, String rootName )
{
if( state == FileSystemListener.ROOT_ADDED)
{
if( SDCARD_NAME.equals(rootName))
{
_isMicroSDReady=true;
scheduleApplicationStart();
removeFileSystemListener(this);
}
}
else if( state == FileSystemListener.ROOT_REMOVED)
{
}
}
}

Resources