static void fatalError(int type)
{
    int count;

    switch (type) {
    case FATAL_ERROR_HARDWARE:
        count = 1;
        break;
    case FATAL_ERROR_SCHEDULER:
        count = 2;
        break;
    default:
        count = 3;
        break;
    }

    while(1) {
        for (int c = 0; c < count; c++) {
            LED_enable(1);
            LED_enable(2);
            for (int i=0; i<FLASH_DELAY; i++) {}
            LED_disable(1);
            LED_disable(2);
            for (int i=0; i < FLASH_DELAY; i++) {}
        }
        for (int i=0; i < FLASH_PAUSE_DELAY; i++) {}
    }
}
int Lua_SetLED(lua_State *L)
{
    if (lua_gettop(L) >= 2) {
        unsigned int LED = lua_tointeger(L,1);
        unsigned int state = lua_tointeger(L,2);
        if (state) {
            LED_enable(LED);
        } else {
            LED_disable(LED);
        }
    }
    return 0;
}
static void error_led(bool on)
{
        on ? LED_enable(3) : LED_disable(3);
}
void loggerTaskEx(void *params)
{
        LoggerConfig *loggerConfig = getWorkingLoggerConfig();
        size_t bufferIndex = 0;
        size_t currentTicks = 0;
        int buffer_size = 0;
        int loggingSampleRate = SAMPLE_DISABLED;
        int sampleRateTimebase = SAMPLE_DISABLED;
        int telemetrySampleRate = SAMPLE_DISABLED;

        g_loggingShouldRun = 0;
        vSemaphoreCreateBinary(onTick);
        logging_set_status(LOGGING_STATUS_IDLE);
        logging_set_logging_start(0);
        g_configChanged = 1;

        while (1) {
                xSemaphoreTake(onTick, portMAX_DELAY);
                ++currentTicks;

                if (g_configChanged) {
                        buffer_size = init_sample_ring_buffer(loggerConfig);
                        if (!buffer_size) {
                                pr_error("Failed to allocate any buffers!\r\n");
                                LED_enable(3);

                                /*
                                 * Do this to ensure the log message gets out
                                 * and we give system time to recover.
                                 */
                                delayMs(10);
                                continue;
                        }

                        LED_disable(3);

                        updateSampleRates(loggerConfig, &loggingSampleRate,
                                          &telemetrySampleRate,
                                          &sampleRateTimebase);
                        resetLapCount();
                        lapstats_reset_distance();
                        currentTicks = 0;
                        g_configChanged = 0;
                }

                /* Only reset the watchdog when we are configured and ready to rock */
                watchdog_reset();

                if (currentTicks % BACKGROUND_SAMPLE_RATE == 0)
                        doBackgroundSampling();

                const bool is_logging = logging_is_active();
                if (g_loggingShouldRun && !is_logging) {
                        logging_started();
                        const LoggerMessage logStartMsg = getLogStartMessage();
                        queue_logfile_record(&logStartMsg);
                        queueTelemetryRecord(&logStartMsg);
                }

                if (!g_loggingShouldRun && is_logging) {
                        logging_stopped();
                        const LoggerMessage logStopMsg = getLogStopMessage();
                        queue_logfile_record(&logStopMsg);
                        queueTelemetryRecord(&logStopMsg);
                        logging_set_status(LOGGING_STATUS_IDLE);
                }

                /* Prepare a Sample */
                struct sample *sample = &g_sample_buffer[bufferIndex];

                /* Check if we need to actually populate the buffer. */
                const int sampledRate = populate_sample_buffer(sample,
                                                               currentTicks);
                if (sampledRate == SAMPLE_DISABLED)
                        continue;

                /* If here, create the LoggerMessage to send with the sample */
                const LoggerMessage msg = create_logger_message(
                        LoggerMessageType_Sample, sample);

                /*
                 * We only log to file if the user has manually pushed the
                 * logging button.
                 */
                if (is_logging && sampledRate >= loggingSampleRate) {
                        /* XXX Move this to file writer? */
                        const portBASE_TYPE res = queue_logfile_record(&msg);
                        const logging_status_t ls = pdTRUE == res ?
                                LOGGING_STATUS_WRITING :
                                LOGGING_STATUS_ERROR_WRITING;
                        logging_set_status(ls);
                }

                /* send the sample on to the telemetry task(s) */
                if (sampledRate >= telemetrySampleRate ||
                    currentTicks % telemetrySampleRate == 0)
                        queueTelemetryRecord(&msg);

                ++bufferIndex;
                bufferIndex %= buffer_size;
        }
}