/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#include <eCxx/eCxx_Internal.h>
#include <eCxx/Platform/Common/Application.h>


namespace eCxx {


//
// An application base class that contains all common member types/constants/variables/functions/etc.
//
const char PROGMEM Application_Base::PGMStrNoError[] = "No Error";
const char PROGMEM Application_Base::PGMStrUnknown[] = "Unknown";


uint32_t Application_Base::random32() noexcept
{
    // Based on:
    //     https://gist.github.com/tommyettinger/46a874533244883189143505d203312c
    //     Written in 2017 by Tommy Ettinger (tommy[DOT]ettinger[AT]gmail.com)

    static uint32_t state = 0x5871CE5UL;

    uint32_t result  = ( state += 0x6D2B79F5UL );
             result  = ( result ^ (result >> 15) ) * (result | 1UL);
             result ^= result + ( result ^ (result >> 7) ) * (result | 61UL);

    return result ^ (result >> 14);
}


//
// Scheduled-user-callback support
//
Application_Base::VoidFuncPtrArg Application_Base::_schedUserCB   [Application_Base::MaxScheduledUserCallback] = { nullptr };
void*                            Application_Base::_schedUserCBArg[Application_Base::MaxScheduledUserCallback] = { nullptr };


bool Application_Base::scheduleAtomicUserCallback(VoidFuncPtrArg userFunc, void* arg)
{
    // Ensure atomic operation when registering a user callback
    AtomicGuard g;

    // Find an empty slot for the user callback and its argument
    for(uint8_t i = 0; i < MaxScheduledUserCallback; ++i) {
        // Check if the current slot is empty
        if(_schedUserCB[i]) continue;
        // The current slot is empty, use it
        _schedUserCB   [i] = userFunc;
        _schedUserCBArg[i] = arg;
        return true;
    }

    // No empty slot was found
    return false;
}


} // namespace eCxx


//
// Include the platform-specific's implementation of the Application class
//
#define INCLUDE_ECXX_PLATFORM_SPECIFIC_APPLICATION_CPP

// AVR
#if defined(__AVR_ARCH_X__)
    #include "AVRX/Application.cpp"
#elif defined(__AVR_ARCH__)
    #include "AVR/Application.cpp"
#endif

// NodeMCU - ESP8266
#ifdef __XTENSA__
    #include "NodeMCU/Application.cpp"
#endif

#undef INCLUDE_ECXX_PLATFORM_SPECIFIC_APPLICATION_CPP


//
// Include a generic implementation of C++ portability helper functions for platforms
// that do not have their own implementation
//
#ifndef __XTENSA__
    #define INCLUDE_ECXX_CTL_CXX_PORTABILITY_CPP
    #include "../CTL/C++Portability.cpp"
#endif
