/*
 * \brief Nut/OS Initialization.
 *
 * Initializes the memory management and the thread system and starts 
 * an idle thread, which in turn initializes the timer management. 
 * Finally the application's main() function is called.
 *
 * Depending on the compiler, different methods are used to execute this
 * function before main() is called.
 *
 * For ICCAVR the default crtatmega.o startup file is replaced by
 * crtnut.o, which calls NutInit instead of main(). This is done
 * by adding the following compiler options in the project:
 * \code -ucrtnut.o nutinit.o \endcode
 * 
 * For AVRGCC this function is located in section .init8, which is
 * called immediately before jumping to main(). NutInit is defined
 * as:
 * \code
 * void NutInit(void) __attribute__ ((naked)) __attribute__ ((section (".init8")));
 * \endcode
 */
void NutInit(void)
{
    /*
     * We can't use local variables in naked functions.
     */
#ifdef NUTDEBUG
    outp(7, UBRR);
    outp(BV(RXEN) | BV(TXEN), UCR);
#endif

#ifndef __GNUC__
// FIXME: move this line to an appropriate initialization section of ICCAVR (os)
    outp(BV(SRE) | BV(SRW), MCUCR);
#endif

    /* First check, whether external RAM is available
     */
    *(NUTRAMEND - 1) = 0x55;
    *NUTRAMEND = 0xAA;
    if (*(NUTRAMEND - 1) == 0x55 && *NUTRAMEND == 0xAA) {
        /* If we have external RAM, initialize stack pointer to
         *  end of external RAM to avoid overwriting .data and .bss section
         */
        SP = (u_short) NUTRAMEND;

        /* Then add the remaining RAM to heap
         */
        if ((u_short) NUTRAMEND - (u_short) (&__heap_start) > 384)
            NutHeapAdd(&__heap_start, (u_short) NUTRAMEND - 256 - (u_short) (&__heap_start));
    } else {
        /* No external RAM, so disable external memory interface to use the port pins
           for normal operation
         */
        MCUCR = 0x00;

        /* Add the remaining internal RAM to heap
         */
        if ((u_short) RAMEND - (u_short) (&__heap_start) > 384)
            NutHeapAdd(&__heap_start, (u_short) RAMEND - 256 - (u_short) (&__heap_start));
    };
    /*
     * Read eeprom configuration.
     */
    if (NutLoadConfig()) {
        strcpy(confos.hostname, "ethernut");
        NutSaveConfig();
    }

    /* Create idle thread
     */
    NutThreadCreate("idle", NutIdle, 0, 384);
}
/*!
 * \brief Apply new configuration.
 *
 * \param dist Pointer to the discovery datagram. It is assumed, that
 *             the validity of the datagram contents had been checked
 *             by the caller.
 */
int NutDiscoveryAppConf(DISCOVERY_TELE * dist)
{
    memcpy(confos.hostname, dist->dist_hostname, sizeof(confos.hostname));
    NutSaveConfig();

    memcpy(confnet.cdn_mac, dist->dist_mac, sizeof(confnet.cdn_mac));
    confnet.cdn_ip_addr = dist->dist_ip_addr;
    confnet.cdn_ip_mask = dist->dist_ip_mask;
    confnet.cdn_gateway = dist->dist_gateway;
    confnet.cdn_cip_addr = dist->dist_cip_addr;

    return NutNetSaveConfig();
}