COM Module Sources


com.c

/**
 *
 * @copyright © 2010 - 2019, Fraunhofer-Gesellschaft zur Foerderung der
 *  angewandten Forschung e.V. All rights reserved.
 *
 * BSD 3-Clause License
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1.  Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * We kindly request you to use one or more of the following phrases to refer
 * to foxBMS in your hardware, software, documentation or advertising
 * materials:
 *
 * ″This product uses parts of foxBMS®″
 *
 * ″This product includes parts of foxBMS®″
 *
 * ″This product is derived from foxBMS®″
 *
 */

/**
 * @file    com.c
 * @author  foxBMS Team
 * @date    28.08.2015 (date of creation)
 * @ingroup DRIVERS
 * @prefix  COM
 *
 * @brief   Driver for the COM module.
 *
 * Generic communication module which handles pre-defined user input and output.
 * In its current state it only uses UART/RS232 for communication
 *
 */



/*================== Includes =============================================*/
#include "com.h"

#if BUILD_MODULE_ENABLE_COM == 1
#if BUILD_MODULE_ENABLE_CONTACTOR == 1
#include "contactor.h"
#endif
#include "mcu.h"
#include "nvram_cfg.h"
#include "os.h"
#include <string.h>
#include "rtc.h"
#include "uart.h"
#include "stdio.h"

/*================== Macros and Definitions ===============================*/
#define TESTMODE_TIMEOUT 30000

/**
 * @brief Maximum number of tasks that can be handled by com-module.
 */
#define COM_RUNTIMESTATS_MAXTASK    32u

static char com_receivedbyte[UART_COM_RECEIVEBUFFER_LENGTH];

/*================== Constant and Variable Definitions ====================*/
uint8_t printHelp = 0;

static uint8_t com_testmode_enabled = 0;
static uint32_t com_tickcount = 0;

static RTC_Time_s com_Time;
static RTC_Date_s com_Date;

#if BUILD_MODULE_ENABLE_RUNTIMESTATS == 1
/**
 * @brief Array for the task list of runtime stats.
 */
static TaskStatus_t pxTaskStatusArray[COM_RUNTIMESTATS_MAXTASK * sizeof(TaskStatus_t)];
#endif

/*================== Function Prototypes ==================================*/

static void COM_getRunTime();
/*================== Function Implementations =============================*/
/* Secondary MCU has no SOX module so setting the SOC leads to an error */
__attribute__((weak)) void SOC_SetValue(float v1, float v2, float v3) {
    printf("ERROR: No SOC on secondary MCU");
}

void COM_printTimeAndDate(void) {
    /* Get time and date */
    RTC_getTime(&com_Time);
    RTC_getDate(&com_Date);

    printf("Date and Time: 20%02d.%02d.%02d - %02d:%02d:%02d\r\n",
      com_Date.Year, com_Date.Month, com_Date.Date, com_Time.Hours,
      com_Time.Minutes, com_Time.Seconds);
}


void COM_StartupInfo(void) {
    /* Get RCC Core Reset Register */
    uint32_t tmp = main_state.CSR;
    printf("........................................\r\n");
    printf("System starting...\r\n");
    printf("RCC Core Reset Register: 0x%x\r\n", (unsigned int)tmp);

    /* Print time and date */
    COM_printTimeAndDate();
    COM_getRunTime();
}

#if BUILD_MODULE_ENABLE_RUNTIMESTATS == 1
void COM_printRuntimeStats(void) {
    /* Code based on FreeRTOS templates */
    volatile UBaseType_t uxArraySize, x;
    uint32_t ulTotalRunTime, ulStatsAsPercentage;
    uint8_t uLongestName = 0;

    /* Take a snapshot of the number of tasks in case it changes while this
    function is executing. */
    uxArraySize = uxTaskGetNumberOfTasks();

    /* warn if more tasks than can be handled exist*/
    if (uxArraySize > COM_RUNTIMESTATS_MAXTASK) {
        printf("WARNING: More tasks than the maximum capability exist, no tasks will be shown.\r\n");
        uxArraySize = COM_RUNTIMESTATS_MAXTASK;
    }

    if (pxTaskStatusArray != NULL) {
        /* Generate raw status information about each task. */
        uxArraySize = uxTaskGetSystemState(pxTaskStatusArray,
                                  uxArraySize,
                                  &ulTotalRunTime);

        /* For percentage calculations. */
        ulTotalRunTime /= 100UL;

        /* Get length of longest task name */

        for (x = 0; x < uxArraySize; x++) {
            if (strlen(pxTaskStatusArray[x].pcTaskName) > uLongestName) {
                uLongestName = strlen(pxTaskStatusArray[x].pcTaskName);
            }
        }

        /* Avoid divide by zero errors. */
        if (ulTotalRunTime > 0) {
            printf("Task Name%-*s   Time  Load  Watermark\r\n", uLongestName-9, " ");
            /* For each populated position in the pxTaskStatusArray array,
              format the raw data as human readable ASCII data. */
            for (x = 0; x < uxArraySize; x++) {
                /* What percentage of the total run time has the task used?
                  This will always be rounded down to the nearest integer.
                    ulTotalRunTimeDiv100 has already been divided by 100. */
                ulStatsAsPercentage =
                    pxTaskStatusArray[x].ulRunTimeCounter / ulTotalRunTime;

                if (ulStatsAsPercentage > 0UL) {
                    printf("%-*s  %5lu  %3lu%%      %5hu\r\n", uLongestName,
                                  pxTaskStatusArray[x].pcTaskName,
                                  pxTaskStatusArray[x].ulRunTimeCounter / 100000,
                                  ulStatsAsPercentage, pxTaskStatusArray[x].usStackHighWaterMark);
                } else {
                    /* If the percentage is zero here then the task has
                      consumed less than 1% of the total run time. */
                    printf("%-*s  %5lu   <1%%      %5hu\r\n", uLongestName,
                                  pxTaskStatusArray[x].pcTaskName,
                                  pxTaskStatusArray[x].ulRunTimeCounter/100000,
                                  pxTaskStatusArray[x].usStackHighWaterMark);
                }
            }
        }
    }
    printf("The load percentage shown is calculated over the whole system uptime!\r\n");
}
#endif

void COM_printHelpCommand(void) {
    if (printHelp == 0)
        return;
    printf("\r\nFollowing commands are available: :\r\n\r\n");

    printf("====================  ========================================================================================================\r\n");
    printf("Command               Description\r\n");
    printf("====================  ========================================================================================================\r\n");
    printf("help                  get available command list\r\n");
    printf("gettime               get system time\r\n");
    printf("getruntime            get runtime since last reset\r\n");
    printf("getoperatingtime      get total operating time\r\n");
    printf("printdiaginfo         get diagnosis entries of DIAG module (entries can only be printed once)\r\n");
    printf("printcontactorinfo    get contactor information (number of switches/hard switches) (entries can only be printed once)\r\n");
    printf("printstats            get the FreeRTOS runtime statistics\r\n");
    printf("teston                enable testmode, testmode will be disabled after a predefined timeout of 30s when no new command is sent\r\n");
    printf("====================  ========================================================================================================\r\n");

    printf("\r\nFollowing commands are only available during enabled testmode:\r\n\r\n");

    printf("Command                     Description\r\n");
    printf("==========================  ==========================================================================================\r\n");
    printf("testoff                     disable testmode\r\n");
    printf("settime YY MM DD HH MM SS   set mcu time and date (YY-year, MM-month, DD-date, HH-hours, MM-minutes, SS-seconds)\r\n");
    printf("reset                       enforces complete software reset using HAL_NVIC_SystemReset()\r\n");
    printf("watchdogtest                performs watchdog test, watchdog timeout results in system reset (predefined 1s)\r\n");
    printf("setsoc xxx.xxx              set SOC value (000.000%% - 100.000%%)\r\n");
    printf("ceX                         enables contactor number X (only possible if BMS is in no error state)\r\n");
    printf("cdX                         disables contactor number X (only possible if BMS is in no error state)\r\n");
    printf("==========================  ==========================================================================================\r\n");
    printHelp = 0;
}

static void COM_settime(void) {
            /* Command length = 24, +1 for \0, +1 cause index always one step ahead */
        if (strlen(com_receivedbyte) == 26) {
            /* Set time and date only if command length is like expected */
           uint8_t value, tmp10, tmp1, retVal = 0;

           /* Calculate year */
            tmp10 = com_receivedbyte[8] - '0';
            tmp1 = com_receivedbyte[9] - '0';
            value = (tmp10 * 10) + tmp1;

            if (IS_RTC_YEAR(value))  /* Check if value is valid */
                com_Date.Year = value;
            else
                retVal = 0xFF;

            /* Calculate month */
            tmp10 = com_receivedbyte[11] - '0';
            tmp1 = com_receivedbyte[12] - '0';
            value = (tmp10 * 10) + tmp1;

            if (IS_RTC_MONTH(value))  /* Check if value is valid */
                com_Date.Month = value;
            else
                retVal = 0xFF;

            /* Calculate day */
            tmp10 = com_receivedbyte[14] - '0';
            tmp1 = com_receivedbyte[15] - '0';
            value = (tmp10 * 10) + tmp1;

            if (IS_RTC_DATE(value))  /* Check if value is valid */
                com_Date.Date = value;
            else
                retVal = 0xFF;

            /* Calculate hours */
            tmp10 = com_receivedbyte[17] - '0';
            tmp1 = com_receivedbyte[18] - '0';
            value = (tmp10 * 10) + tmp1;

            if (IS_RTC_HOUR24(value))  /* Check if value is valid */
                com_Time.Hours = value;
            else
                retVal = 0xFF;

            /* Calculate minutes */
            tmp10 = com_receivedbyte[20] - '0';
            tmp1 = com_receivedbyte[21] - '0';
            value = (tmp10 * 10) + tmp1;

            if (IS_RTC_MINUTES(value))  /* Check if value is valid */
                com_Time.Minutes = value;
            else
                retVal = 0xFF;

           /* Calculate seconds */
            tmp10 = com_receivedbyte[23] - '0';
            tmp1 = com_receivedbyte[24] - '0';
            value = (tmp10 * 10) + tmp1;

            if (IS_RTC_SECONDS(value))  /* Check if value is valid */
                com_Time.Seconds = value;
            else
                retVal = 0xFF;

            if (retVal == 0) {
                /* Set time and date */
                RTC_setTime(&com_Time);
                RTC_setDate(&com_Date);

                printf("Time and date set!\r\n");
            } else {
                /* Print error message */
                printf("Invalid parameter!\r\n%.25s\r\n", com_receivedbyte);
            }

        } else {
            /* Print error message */
            printf("Invalid parameter length!\r\n");
            printf("%.*s\r\n", strlen(com_receivedbyte), com_receivedbyte);
        }
}

static void COM_getRunTime() {
    printf("Runtime: %02dh %02dm %02ds\r\n", os_timer.Timer_h,
       os_timer.Timer_min, os_timer.Timer_sec);
}

uint8_t COM_testMode_Decoder(void) {
    uint8_t commandValid = 0;

    if (strncmp(com_receivedbyte, "testoff", 7) == 0) {/* DISABLE TESTMODE */
        com_testmode_enabled = 0;
        printf("Testmode disabled on request!\r\n");
        commandValid = 1;
    } else if (strncmp(com_receivedbyte, "settime", 7) == 0) {  /* SETTIME */
        COM_settime();
        commandValid = 1;
    } else if (strncmp(com_receivedbyte, "reset", 5) == 0) { /* RESET */
        printf("Software reset!\r\n");
        commandValid = 1;
        HAL_NVIC_SystemReset();
    } else if (strncmp(com_receivedbyte, "watchdogtest", 12) == 0) {
        printf("WDG");
        commandValid = 1;
        OS_taskDelay(1);

        /* disable global interrupt, no saving of interrupt status because of follwing reset */
        (void)MCU_DisableINT();

      while (1) {
          /* stop system and wait for watchdog reset*/
      }

      return commandValid;
    } else if (strncmp(com_receivedbyte, "setsoc", 6) == 0) { /* Set soc */
        /* Set SOC */
        /* Command length = 14, +1 for \0 and +1 cause index always one step ahead "setsoc xxx.xxx"*/
        if (strlen(com_receivedbyte) == 15) {
            /* Set time and date only if command length is like expected */
            uint8_t tmp100 = 0, tmp10 = 0, tmp1 = 0;
            float value = 0;

            /* Calculate year */
            tmp100 = com_receivedbyte[7] - '0';
            tmp10 = com_receivedbyte[8] - '0';
            tmp1 = com_receivedbyte[9] - '0';
            value = (tmp100 * 100) + (tmp10 * 10) + tmp1;

            tmp1 = com_receivedbyte[11] - '0';
            tmp10 = com_receivedbyte[12] - '0';
            tmp100 = com_receivedbyte[13] - '0';
            value = value + (tmp1 * 0.1f) + (tmp10 * 0.01f) + (tmp100 * 0.001f);

            if (0 <= value && value <= 100)
                SOC_SetValue(value, value, value);
        }
        commandValid = 1;
#if BUILD_MODULE_ENABLE_CONTACTOR == 1
    /* SWITCH CONTACTORS */
    } else if (strncmp(com_receivedbyte, "contactor enable", 16) == 0) {
        /* Convert ascii number to int */
        int16_t contNumber;
        contNumber = com_receivedbyte[17] - '0';

        /* Switch contactor */
        if ((0 <= contNumber) && (contNumber <= BS_NR_OF_CONTACTORS)) {
            /* Close contactor */
            if (com_receivedbyte[1] == 'e') {
                printf("Contactor %d", contNumber);

                CONT_SetContactorState(contNumber, CONT_SWITCH_ON);

                printf(" enabled\r\n");
            }
        } else {
             /* Invalid contactor number */
            uint8_t a = BS_NR_OF_CONTACTORS;
            printf("Invalid contactor number! Only %d contactors are connected! \r\n", a);
        }
        commandValid = 1;
    } else if (strncmp(com_receivedbyte, "contactor disable", 17) == 0) {
        /* Convert ascii number to int */
        int16_t contNumber;
        contNumber = com_receivedbyte[18] - '0';

        /* Switch contactor */
        if ((0 <= contNumber) && (contNumber <= BS_NR_OF_CONTACTORS)) {
            /* Open contactor */
                printf("Contactor %d", contNumber);

                CONT_SetContactorState(contNumber, CONT_SWITCH_OFF);

                printf(" disabled\r\n");
        } else {
             /* Invalid contactor number */
            uint8_t a = BS_NR_OF_CONTACTORS;
            printf("Invalid contactor number! Only %d contactors are connected! \r\n", a);
        }
        commandValid = 1;
#endif
    }
    return commandValid;
}

void COM_Decoder(void) {
    uint32_t commandValid = 0;
    /* Command Received - Replace Carrier Return with null character */
    fgets(com_receivedbyte, UART_COM_RECEIVEBUFFER_LENGTH , stdin);

    /* Command received and testmode enabled */
    if (com_testmode_enabled) {
        commandValid = COM_testMode_Decoder();
    }

    if (commandValid > 0) {
#if BUILD_MODULE_ENABLE_RUNTIMESTATS == 1
    } else if (strncmp(com_receivedbyte, "printstats", 10) == 0) {
      COM_printRuntimeStats();
    commandValid = 1;
#endif
    } else if (strncmp(com_receivedbyte, "teston", 6) == 0) { /* ENABLE TESTMODE */
        /* Set timeout */
        com_tickcount = OS_getOSSysTick();

        if (!com_testmode_enabled) {
            /* Enable testmode */
            com_testmode_enabled = 1;

            printf("Testmode enabled!\r\n");
        } else {
            /* Testmode already enabled */
           printf("Testmode already enabled!\r\n");
        }

        /* Reset timeout to TESTMODE_TIMEOUT */
        com_tickcount = OS_getOSSysTick();

        commandValid = 1;
    } else if (strncmp(com_receivedbyte, "help", 4) == 0) { /* PRINT help command */
        /* Print contactor info */
        printHelp = 1;
        commandValid = 1;
#if BUILD_MODULE_ENABLE_CONTACTOR == 1
    } else if (strncmp(com_receivedbyte, "printcontactorinfo", 18) == 0) { /* PRINT CONTACTOR INFO */
        /* Print contactor info */
        DIAG_PrintContactorInfo();
        commandValid = 1;
#endif
    } else if (strncmp(com_receivedbyte, "printdiaginfo", 13) == 0) { /* PRINT DIAG INFO */
        /* Print diag info */
        DIAG_PrintErrors();
        commandValid = 1;
    } else if (strncmp(com_receivedbyte, "gettime", 7) == 0) {  /* GETTIME */
        /* Print time and date */
       COM_printTimeAndDate();
       commandValid = 1;
    } else if (strncmp(com_receivedbyte, "getruntime", 10) == 0) { /* Get runtime */
        /* Print runtime */
        COM_getRunTime();
        commandValid = 1;
#if BUILD_MODULE_ENABLE_NVRAM == 1
    } else if (strncmp(com_receivedbyte, "getoperatingtime", 16) == 0) { /* Get operating time */
        printf("Operating time: %03dd %02dh %02dm %02ds\r\n",
           bkpsram_op_hours.Timer_d, bkpsram_op_hours.Timer_h,
            bkpsram_op_hours.Timer_min, bkpsram_op_hours.Timer_sec);
        commandValid = 1;
#endif
    }
    if (!commandValid) {
        /* Invalid command */
        printf("Invalid command!\r\n%s\r\n", com_receivedbyte);
    }

    /* Timed out --> disable testmode */
    if (com_tickcount + TESTMODE_TIMEOUT < OS_getOSSysTick() && com_testmode_enabled) {
        com_testmode_enabled = 0;
        printf("Testmode disabled on timeout!\r\n");
    }
}
#endif /* BUILD_MODULE_ENABLE_COM */

com.h

/**
 *
 * @copyright &copy; 2010 - 2019, Fraunhofer-Gesellschaft zur Foerderung der
 *  angewandten Forschung e.V. All rights reserved.
 *
 * BSD 3-Clause License
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1.  Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * We kindly request you to use one or more of the following phrases to refer
 * to foxBMS in your hardware, software, documentation or advertising
 * materials:
 *
 * &Prime;This product uses parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product includes parts of foxBMS&reg;&Prime;
 *
 * &Prime;This product is derived from foxBMS&reg;&Prime;
 *
 */

/**
 * @file    com.h
 * @author  foxBMS Team
 * @date    28.08.2015 (date of creation)
 * @ingroup DRIVERS
 * @prefix  COM
 *
 * @brief   Header for the driver for the COM module
 *
 * Available COM commands:
 *
 * help                       -- prints list of available commands
 * teston                     -- Enables testmode
 * printcontactorinfo         -- prints the contactor info (number of switches and the contactor hard switch entries
 * printdiaginfo              -- prints the diagnosis info
 * printstats                 -- get the FreeRTOS runtime statistics
 * gettime                    -- prints mcu time and date
 * getruntime                 -- get runtime since last reset
 * getoperatingtime           -- get total operating time
 *
 * Following commands only available in testmode!
 *
 * testoff                    -- disables testmode
 * settime YY MM DD HH MM SS  -- sets mcu time and date (YY-year, MM-month, DD-date, HH-hours, MM-minutes, SS-seconds)
 * reset                      -- resets mcu
 * watchdogtest               -- watchdog timeout results in system reset
 * setsoc xxx.xxx             -- set SOC value (000.000% - 100.000%)
 * ceX                        -- enables contactor number X
 * cdX                        -- disables contactor number X
 *
 *
 */

#ifndef COM_H_
#define COM_H_

/*================== Includes =============================================*/
#include "general.h"

/*================== Macros and Definitions ===============================*/
#if (BUILD_MODULE_DEBUGPRINTF)
#if (!BUILD_MODULE_ENABLE_UART)
#error ERROR: wrong combination of module enable keys in general.h !
#error BUILD_MODULE_DEBUGPRINTF could only be used when UART module BUILD_MODULE_ENABLE_UART is activated
#endif
#else
    #define fprintf(...)
    #define printf(...)
#endif


/*================== Constant and Variable Definitions ====================*/



/*================== Function Prototypes ==================================*/

/**
 * @brief COM_Decoder parses and interprets user defined input data.
 *
 * This function needs to be called within a cyclic engtask e.g. ENG_TSK_Cyclic_10ms
 * It processes input data received by the UART module asynchronly.
 *
 */
extern void COM_Decoder(void);

/**
 * @brief COM_StartupInfo prints some startup related informations (time & date).
 *
 * This function needs proper initialized RTC and UART module to work.
 * Called during startup process in main function.
 */
extern void COM_StartupInfo(void);

/**
 * Prints date and time info on serial interface
 */
extern void COM_printTimeAndDate(void);

/**
 * Prints list of available commands
 */
extern void COM_printHelpCommand(void);


/**
 * @brief UART_vWrite provides an interface to send data.
 *
 * This function copies data from input buffer to transmit ringbuffer
 * and processes this data in case it's not already busy transmitting data.
 * The copying will stop as soon as an ASCII NULL character is detected.
 * To avoid data corruption caused by simultaneous accesses some kind of
 * critical section is used.
 *
 * @return (type: uint8_t)
 */
extern void COM_uartWrite(const uint8_t *source);

/**
 * @brief UART_vWrite provides an interface to send data.
 *
 * This function copies data from input buffer to transmit ringbuffer
 * and processes this data in case it's not already busy transmitting data.
 * To avoid data corruption caused by simultaneous accesses some kind of
 * critical section is used. The difference between UART_vWrite(const uint8_t *source) and
 * this function is, that this one does not stop at an ASCII_NULL character. Therefore writing of non ASCII characters
 * is possible without having to worry that the data might represent an ASCII NULL character.
 *
 * @return (type: uint8_t)
 */
extern void UART_uartWrite_intbuf(const uint8_t *source, uint16_t length);

void SYSCALL_Init(void);

/*================== Function Implementations =============================*/

#endif /* COM_H_ */