/****************************************************************************************************/
/** @file
*
* Copyright (c) 2011, GhostCarProjekt, Germany, all rights reserved
*
* @par Module:
*      Application Communication
*
* @par Author:
*      and_ref
*
* @par Module Description:
*      see doxygen generated CHM file
*
* @par Filename:
*      ApplComm.c
*
* @par date of creation:
*      2011-10-02
*
******************************************************************************************************
*
* $Date: 2013-02-15 20:06:19 +0100 (Fr, 15 Feb 2013) $
* $Revision: 580 $
* $Author: and_ref $
* $HeadURL: svn://xxx/GCP/trunk/Software/Source/Application/ApplComm.c $
*
*****************************************************************************************************/


/****************************************************************************************************/
/*                                                                                                  */
/* Internal Definitions & Declarations                                                              */
/*                                                                                                  */
/****************************************************************************************************/

/****************************************************************************************************/
/* Module definition for conditional compiling                                                      */
/****************************************************************************************************/
#define MODULE_APPL_COMM

/****************************************************************************************************/
/* Include files System                                                                             */
/****************************************************************************************************/
#include "gtypes.h"
#include "gdefs.h"
#include "mc9s12c128.h"

/****************************************************************************************************/
/* Include files Modules                                                                            */
/****************************************************************************************************/
#include "BiosRs232.h"
#include "BswDp.h"
#include "BswHal.h"
#include "BiosIcp.h"
#include "ApplLap.h"
#include "ApplComm.h"                            /* headerfile of this c-module */
#include "SysScheduler.h"

/****************************************************************************************************/
/* Definition of module wide MACROs / #DEFINE-CONSTANTs - NOT for use in other modules              */
/****************************************************************************************************/
#define APPLCOMM_NUM_TXBUFFER     6
#define APPLCOMM_TXBUFFER_LENGTH  32

/****************************************************************************************************/
/* Declaration of module wide TYPEs - NOT for use in other modules                                  */
/****************************************************************************************************/
typedef struct
{
    u08 MaxUsedBuffersNum;      /* maximal so viele Puffer waren gleichzeitig befuellt; => Mass wie grosszuegig die Pufferanzahl ausgelegt ist */
    u08 MaxUsedBufferLen;       /* so lange war das laengste zu versendende Telegramm;  => Mass wie grosszuegig die Pufferlaenge ausgelegt ist */
    u32 NumNotAcceptedEnqTries; /* so viele Puffer konnten wegen mangelnder Pufferkapazitaet nicht angenommen werden */
    u32 NumAcceptedEnqTries;    /* so viele Puffer konnten angenommen werden */
    u32 NumSentBuffers;         /* Gesamtzahl aller versendeten Puffer */
    u32 NumDelayedBuffers;      /* Gesamtzahl aller zum Versand vorgesehenen Puffer, die nicht sofort in der Senderoutine versendet werden konnten */
    u32 NumDelays1ms;           /* Gesamtzahl der Sendepausen, um XBee sich wieder erholen zu lassen */
} tApplComm_Diagdata;

/****************************************************************************************************/
/* Definition of module wide VARIABLEs - NOT for use in other modules                               */
/****************************************************************************************************/
tApplComm_Diagdata            ApplComm_Diagdata; /* Modulinterne Diagnosedaten */
u16                           ApplComm_UpdaterateCntInit = 50; /* Updaterate; Versand der LiveMeasurementdaten in jedem n. Task */
u16                           ApplComm_UpdaterateLiveDiagdataInit = 1000; /* Updaterate fuer LiveDiagdaten in jedem n. Task */
u08                           ApplComm_TxBuffer[APPLCOMM_NUM_TXBUFFER][APPLCOMM_TXBUFFER_LENGTH];
u08                           ApplComm_QueuingIndex = 0;
u08                           ApplComm_SendingIndex = 0;

/****************************************************************************************************/
/* Definition of module wide (CONST-) CONSTANTs - NOT for use in other modules                      */
/****************************************************************************************************/

/****************************************************************************************************/
/* Declaration of module wide FUNCTIONs - NOT for use in other modules                              */
/****************************************************************************************************/
static void ApplComm_ProcessRxTask(void);
static void ApplComm_ProcessTxTask(void);
static void ApplComm_EnqueueLiveMeasuredata(void);
static void ApplComm_EnqueueLiveGapdata(void);
static void ApplComm_EnqueueLiveDiagdata(void);
static void ApplComm_EnqueueReadChannelResponse(u08 Channel, u16 Data16);
static void ApplComm_TransmitQueue(void);

/****************************************************************************************************/
/*                                                                                                  */
/* End of Internal Definitions & Declarations                                                       */
/*                                                                                                  */
/****************************************************************************************************/


/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_Init                                                                                    */
/*                                                                                                  */
/****************************************************************************************************/
#define APPLCOM_MAX_LOG_CHANNELS    6
tBswDp_Channelindex ApplComm_LogChannelList[APPLCOM_MAX_LOG_CHANNELS];
void ApplComm_Init(void)
{
    u08 i;

    for (i=0; i<APPLCOM_MAX_LOG_CHANNELS; i++)
    {
        ApplComm_LogChannelList[i] = 0xFF; /* Defaultinit: Alle Logkanaele abschalten */
    }

    /* Testbetrieb: Alle Debugdaten raussenden */
    ApplComm_LogChannelList[0] = BSWDP_CHANNEL_WheelRpm;
    ApplComm_LogChannelList[1] = BSWDP_CHANNEL_TargetRpm;
    ApplComm_LogChannelList[2] = BSWDP_CHANNEL_GyroZRaw;
    ApplComm_LogChannelList[3] = BSWDP_CHANNEL_GyroZRawNorm;
    ApplComm_LogChannelList[4] = BSWDP_CHANNEL_PwmDrive;
    ApplComm_LogChannelList[5] = BSWDP_CHANNEL_PwmBrake;

    /* Sendedatentypen einstellen */
    ApplComm_DataToTransmit.Bitfeld.Byte = 0;
    ApplComm_DataToTransmit.Bitfeld.Bits.LiveSectordataAllowed = TRUE;
    ApplComm_DataToTransmit.Bitfeld.Bits.LiveSyncdataAllowed   = TRUE;
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_Task                                                                                    */
/*                                                                                                  */
/****************************************************************************************************/
void ApplComm_Task(void)
{
    ApplComm_ProcessRxTask();
    ApplComm_ProcessTxTask();
    ApplComm_TransmitQueue(); /* Zusammengestellte Puffer versenden */
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_ProcessRxTask                                                                           */
/*                                                                                                  */
/****************************************************************************************************/
volatile u32 Fastlog_TxFails = 0;
static void ApplComm_ProcessRxTask(void)
{
    u08        FrameIdRx = 0;
    u16        temp16;
    u08        RxRefSectorindex = 0;

    /* Verarbeitung der eingetroffenen Frames */
    if (BiosRs232_ApplRxBuffer.BufferFull)
    {
        FrameIdRx = BiosRs232_ApplRxBuffer.Buffer[1];

        switch (BiosRs232_ApplRxBuffer.Buffer[2]) /* Kommando */
        {
            case 0x00: /* ConfigureActiveChannels empfangen? */
                ApplComm_LogChannelList[0] = BiosRs232_ApplRxBuffer.Buffer[3];
                ApplComm_LogChannelList[1] = BiosRs232_ApplRxBuffer.Buffer[4];
                ApplComm_LogChannelList[2] = BiosRs232_ApplRxBuffer.Buffer[5];
                ApplComm_LogChannelList[3] = BiosRs232_ApplRxBuffer.Buffer[6];
                ApplComm_LogChannelList[4] = BiosRs232_ApplRxBuffer.Buffer[7];
                ApplComm_LogChannelList[5] = BiosRs232_ApplRxBuffer.Buffer[8];
                break;
            case 0x01: /* ConfigureActivityMode empfangen? */
                BswDp_RequestedActivityMode = BiosRs232_ApplRxBuffer.Buffer[3];
                break;
            case 0x02: /* ConfigureUpdaterate empfangen? */
                ApplComm_UpdaterateCntInit = (((u16)BiosRs232_ApplRxBuffer.Buffer[3]<<8)|BiosRs232_ApplRxBuffer.Buffer[4]);
                ApplComm_DataToTransmit.Bitfeld.Bits.LiveMeasuredataAllowed = TRUE;
                break;
            case 0x10: /* StartAction empfangen? */
                if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x00)           /* Mute */
                {
                    ApplComm_DataToTransmit.Bitfeld.Byte = 0x00;        /* alle Sendedaten abschalten */
                    DpRam.DebugMode = NORMAL;                           /* Etwaigen FastlogMode sofort verlassen */
                }
                else if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x01)      /* LiveMeasureDataStart */
                {
                    ApplComm_DataToTransmit.Bitfeld.Bits.LiveMeasuredataAllowed = TRUE;
                }
                else if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x02)      /* SectordataStart */
                {
                    ApplComm_DataToTransmit.Bitfeld.Bits.LiveSectordataAllowed = TRUE;
                }
                else if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x03)      /* SyncEventdataStart */
                {
                    ApplComm_DataToTransmit.Bitfeld.Bits.LiveSyncdataAllowed = TRUE;
                }
                else if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x04)      /* EnterFastlogMode */
                {
                    DpRam.DebugMode = FASTLOG;
                    /* Alle internen Variablen auf 0 setzen und mit LEARNING beginnen/losfahren */
                    BswHal_Init();
                    ApplLap_Init();
                    BswDp_RequestedActivityMode = LEARNING; /* mit LEARNING losfahren */
               }
                else if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x05)      /* LiveGapdataStart */
                {
                    ApplComm_DataToTransmit.Bitfeld.Bits.LiveGapdataAllowed = TRUE;
                }
                else if (BiosRs232_ApplRxBuffer.Buffer[3] == 0x06)      /* LiveDiagdataStart */
                {
                    ApplComm_DataToTransmit.Bitfeld.Bits.LiveDiagdataAllowed = TRUE;
                }
                break;
            case 0x40: /* WriteChannel empfangen? */
                temp16 = (((u16)BiosRs232_ApplRxBuffer.Buffer[4]<<8)|BiosRs232_ApplRxBuffer.Buffer[5]);
                BswDp_SetChannelData16(BiosRs232_ApplRxBuffer.Buffer[3], temp16);
                break;
            case 0x47: /* "ReadChannel" empfangen? */
                /* Inhalt des angefragten Kanals ermitteln */
                temp16 = BswDp_GetChannelData16(BiosRs232_ApplRxBuffer.Buffer[3]);
                /* Inhalt an PC zuruecksenden */
                ApplComm_EnqueueReadChannelResponse(BiosRs232_ApplRxBuffer.Buffer[3], temp16);
                break;
        }
        BiosRs232_ApplRxBuffer.BufferFull = 0; /* Verarbeitung abgeschlossen => Puffer wieder freigeben */
    }
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_ProcessTxTask                                                                           */
/*                                                                                                  */
/****************************************************************************************************/
static void ApplComm_ProcessTxTask(void)
{
    static u16 ApplComm_UpdaterateCnt_LiveMeasuredata = 0;
    static u16 ApplComm_UpdaterateCnt_LiveDiagdata    = 0;
    u08        i = 0;
    u08        Pos = 0;
    u08        temp = 0;
    u08        FastlogBuffer[8];

    if (DpRam.DebugMode == FASTLOG) /* Messdaten schnell versenden */
    {
        /* zuerst alle (anderen) zyklischen Sender abschalten */
        ApplComm_DataToTransmit.Bitfeld.Byte = 0;

        /* Zusammenstellen der zu versendenden Daten */
        FastlogBuffer[0] = (u08)(DpRam.GyroZRawComp >> 8);
        FastlogBuffer[1] = (u08)(DpRam.GyroZRawComp >> 0);
        FastlogBuffer[2] = ApplLap_Events.Bitfeld.Byte;
        FastlogBuffer[3] = DpRam.DeltaTicks1ms;
        FastlogBuffer[4] = (u08)(DpRam.WheelRpm >> 8);
        FastlogBuffer[5] = (u08)(DpRam.WheelRpm >> 0);
        FastlogBuffer[6] = (u08)(DpRam.TargetRpm >> 8);
        FastlogBuffer[7] = (u08)(DpRam.TargetRpm >> 0);

        /* Daten versenden */
        temp = BiosRs232_EnqueueTxData(&FastlogBuffer[0], 8, FALSE); /* FALSE: Framing fuer diese Uebertragung deaktivieren */
        if (temp != 0) /* Versand der Daten NICHT akzeptiert? (busy oder "too long") */
        {
            Fastlog_TxFails++; /* Statistik */
        }
    }

    /* Verarbeitung anstehender Befehle/Aktionen */
    if (ApplComm_DataToTransmit.Bitfeld.Bits.LiveMeasuredataAllowed)
    {
        if (ApplComm_UpdaterateCnt_LiveMeasuredata == 0)
        {
            ApplComm_UpdaterateCnt_LiveMeasuredata = ApplComm_UpdaterateCntInit; /* Timer neu aufziehen */
            ApplComm_EnqueueLiveMeasuredata();
        }
        ApplComm_UpdaterateCnt_LiveMeasuredata--;
    }

    if (ApplComm_DataToTransmit.Bitfeld.Bits.LiveGapdataAllowed)
    {
        if (BiosIcp_GapSector.ReadyToSend)
        {
            BiosIcp_GapSector.ReadyToSend = FALSE; /* Trigger zuruecknehmen */
            ApplComm_EnqueueLiveGapdata();
        }
    }

    if (ApplComm_DataToTransmit.Bitfeld.Bits.LiveDiagdataAllowed)
    {
        if (ApplComm_UpdaterateCnt_LiveDiagdata == 0)
        {
            ApplComm_UpdaterateCnt_LiveDiagdata = ApplComm_UpdaterateLiveDiagdataInit; /* Timer neu aufziehen */
            ApplComm_EnqueueLiveDiagdata();
        }
        ApplComm_UpdaterateCnt_LiveDiagdata--;
    }
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueLiveMeasuredata                                                                  */
/*  Stellt ein LiveMeasuredata-Telegramm zusammen und reiht es in den Sendepuffer ein.              */
/*                                                                                                  */
/****************************************************************************************************/
static void ApplComm_EnqueueLiveMeasuredata(void)
{
    u08        Buffer[23];
    u08        i;

    /* Logdaten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x80;                       /* Kommandokennung      */
    Buffer[ 1] = (u08)(SysScheduler_Systemtime>>24);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(SysScheduler_Systemtime>>16);     /* Zeitstempel          */
    Buffer[ 3] = (u08)(SysScheduler_Systemtime>> 8);     /* Zeitstempel          */
    Buffer[ 4] = (u08)(SysScheduler_Systemtime>> 0);     /* Zeitstempel LSB      */

    /* Bestellte Messdaten einfuellen */
    for (i=0; i<6; i++) /* 6 Messkanaele zu je 16Bit werden pro Frame uebertragen */
    {
        if (ApplComm_LogChannelList[i] != 0xFF) /* Kanal aktiv? */
        {
            Buffer[5+(i*3)] = (u08)ApplComm_LogChannelList[i];                                                         /* Kanalkennung */
            Buffer[6+(i*3)] = (u08)((BswDp_GetChannelData16((tBswDp_Channelindex)ApplComm_LogChannelList[i])) >> 8);   /* obere  8Bit  */
            Buffer[7+(i*3)] = (u08)((BswDp_GetChannelData16((tBswDp_Channelindex)ApplComm_LogChannelList[i])) >> 0);   /* untere 8Bit  */
        }
        else /* => kein Kanal ausgewaehlt => Nullen senden */
        {
            Buffer[5+(i*3)] = (u08)ApplComm_LogChannelList[i];                                                         /* Kanalkennung */
            Buffer[6+(i*3)] = 0;                                                                                       /* obere  8Bit  */
            Buffer[7+(i*3)] = 0;                                                                                       /* untere 8Bit  */
        }
    }
    (void)ApplComm_EnqueueMessage(&Buffer[0], 23); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueLiveBlackSectordata                                                              */
/*  Stellt ein LiveSectordata-Telegramm zusammen und reiht es in den Sendepuffer ein.               */
/*                                                                                                  */
/****************************************************************************************************/
void ApplComm_EnqueueLiveBlackSectordata(tBlackSector Sectordata)
{
    u08        Buffer[15];

    /* Sektordaten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x82;                                   /* Kommandokennung      */
    Buffer[ 1] = (u08)(SysScheduler_Systemtime>>24);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(SysScheduler_Systemtime>>16);     /* Zeitstempel          */
    Buffer[ 3] = (u08)(SysScheduler_Systemtime>> 8);     /* Zeitstempel          */
    Buffer[ 4] = (u08)(SysScheduler_Systemtime>> 0);     /* Zeitstempel LSB      */
    Buffer[ 5] = (u08)(Sectordata.Length>>8);
    Buffer[ 6] = (u08)(Sectordata.Length);
    Buffer[ 7] = (u08)(Sectordata.Angle>>8);
    Buffer[ 8] = (u08)(Sectordata.Angle);
    Buffer[ 9] = (u08)(Sectordata.WegpunktAbs>>24);
    Buffer[10] = (u08)(Sectordata.WegpunktAbs>>16);
    Buffer[11] = (u08)(Sectordata.WegpunktAbs>>8);
    Buffer[12] = (u08)(Sectordata.WegpunktAbs>>0);
    Buffer[13] = (u08)(Sectordata.Lage>>8);
    Buffer[14] = (u08)(Sectordata.Lage);
    if (ApplComm_DataToTransmit.Bitfeld.Bits.LiveSectordataAllowed) /* Datenversand eingeschaltet? */
    {
        (void)ApplComm_EnqueueMessage(&Buffer[0], 15); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
    }
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueLiveWhiteSectordata                                                              */
/*  Stellt ein LiveSectordata-Telegramm zusammen und reiht es in den Sendepuffer ein.               */
/*                                                                                                  */
/****************************************************************************************************/
void ApplComm_EnqueueLiveWhiteSectordata(tWhiteSector Sectordata)
{
    u08        Buffer[15];

    /* Sektordaten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x83;                                   /* Kommandokennung      */
    Buffer[ 1] = (u08)(SysScheduler_Systemtime>>24);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(SysScheduler_Systemtime>>16);     /* Zeitstempel          */
    Buffer[ 3] = (u08)(SysScheduler_Systemtime>> 8);     /* Zeitstempel          */
    Buffer[ 4] = (u08)(SysScheduler_Systemtime>> 0);     /* Zeitstempel LSB      */
    Buffer[ 5] = (u08)(Sectordata.Length>>8);
    Buffer[ 6] = (u08)(Sectordata.Length);
    Buffer[ 7] = (u08)(Sectordata.Angle>>8);
    Buffer[ 8] = (u08)(Sectordata.Angle);
    Buffer[ 9] = (u08)(Sectordata.WegpunktAbs>>24);
    Buffer[10] = (u08)(Sectordata.WegpunktAbs>>16);
    Buffer[11] = (u08)(Sectordata.WegpunktAbs>>8);
    Buffer[12] = (u08)(Sectordata.WegpunktAbs>>0);
    Buffer[13] = (u08)(Sectordata.Bandmitte>>8);
    Buffer[14] = (u08)(Sectordata.Bandmitte);
    if (ApplComm_DataToTransmit.Bitfeld.Bits.LiveSectordataAllowed) /* Datenversand eingeschaltet? */
    {
        (void)ApplComm_EnqueueMessage(&Buffer[0], 15); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
    }
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueLiveSyncdata                                                                     */
/*  Stellt ein LiveSectordata-Telegramm zusammen und reiht es in den Sendepuffer ein.               */
/*                                                                                                  */
/****************************************************************************************************/
void ApplComm_EnqueueLiveSyncdata(tPosDetDataset Syncdata)
{
    u08        Buffer[11];

    /* Sektordaten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x84;                                   /* Kommandokennung      */
    Buffer[ 1] = (u08)(SysScheduler_Systemtime>>24);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(SysScheduler_Systemtime>>16);     /* Zeitstempel          */
    Buffer[ 3] = (u08)(SysScheduler_Systemtime>> 8);     /* Zeitstempel          */
    Buffer[ 4] = (u08)(SysScheduler_Systemtime>> 0);     /* Zeitstempel LSB      */
    Buffer[ 5] = (u08)(Syncdata.RefWheelticksAbs>>24);
    Buffer[ 6] = (u08)(Syncdata.RefWheelticksAbs>>16);
    Buffer[ 7] = (u08)(Syncdata.RefWheelticksAbs>>8);
    Buffer[ 8] = (u08)(Syncdata.RefWheelticksAbs>>0);
    Buffer[ 9] = (u08)(Syncdata.SyncDataWheelticksAbs>>8);
    Buffer[10] = (u08)(Syncdata.SyncDataWheelticksAbs>>0);
    if (ApplComm_DataToTransmit.Bitfeld.Bits.LiveSyncdataAllowed) /* Datenversand eingeschaltet? */
    {
        (void)ApplComm_EnqueueMessage(&Buffer[0], 11); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
    }
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueLiveGapdata                                                                      */
/*  Stellt ein LiveGapdata-Telegramm zusammen und reiht es in den Sendepuffer ein.                  */
/*  Die zu versendenden Daten liegen als globale Daten vor                                          */
/*                                                                                                  */
/****************************************************************************************************/
static void ApplComm_EnqueueLiveGapdata(void)
{
    u08        Buffer[17];

    /* Sektordaten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x87;                                   /* Kommandokennung      */
    Buffer[ 1] = (u08)(SysScheduler_Systemtime>>24);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(SysScheduler_Systemtime>>16);     /* Zeitstempel          */
    Buffer[ 3] = (u08)(SysScheduler_Systemtime>> 8);     /* Zeitstempel          */
    Buffer[ 4] = (u08)(SysScheduler_Systemtime>> 0);     /* Zeitstempel LSB      */
    Buffer[ 5] = (u08)(BiosIcp_GapSector.GapNr>>8);
    Buffer[ 6] = (u08)(BiosIcp_GapSector.GapNr);
    Buffer[ 7] = (u08)(BiosIcp_GapSector.GapLength>>8);
    Buffer[ 8] = (u08)(BiosIcp_GapSector.GapLength);
    Buffer[ 9] = (u08)(BiosIcp_GapSector.GapStartWheelticks>>8);
    Buffer[10] = (u08)(BiosIcp_GapSector.GapStartWheelticks);
    Buffer[11] = (u08)(BiosIcp_GapSector.SectorLength>>8);
    Buffer[12] = (u08)(BiosIcp_GapSector.SectorLength);
    Buffer[13] = 0;
    Buffer[14] = 0;
    Buffer[15] = 0;
    Buffer[16] = 0;
    (void)ApplComm_EnqueueMessage(&Buffer[0], 17); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueLiveDiagdata                                                                     */
/*  Stellt ein LiveDiagdata-Telegramm zusammen und reiht es in den Sendepuffer ein.                 */
/*  Die zu versendenden Daten liegen als globale Daten vor                                          */
/*                                                                                                  */
/****************************************************************************************************/
static void ApplComm_EnqueueLiveDiagdata(void)
{
    u08        Buffer[17];

    /* Sektordaten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x86;                                   /* Kommandokennung      */
    Buffer[ 1] = (u08)(SysScheduler_Systemtime>>24);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(SysScheduler_Systemtime>>16);     /* Zeitstempel          */
    Buffer[ 3] = (u08)(SysScheduler_Systemtime>> 8);     /* Zeitstempel          */
    Buffer[ 4] = (u08)(SysScheduler_Systemtime>> 0);     /* Zeitstempel LSB      */
    Buffer[ 5] = (u08)(SysScheduler_ProcessorLoad1ms>>8);
    Buffer[ 6] = (u08)(SysScheduler_ProcessorLoad1ms);
    Buffer[ 7] = (u08)(SysScheduler_ProcessorLoadIdle>>8);
    Buffer[ 8] = (u08)(SysScheduler_ProcessorLoadIdle);
    Buffer[ 9] = (u08)(0x00);
    Buffer[10] = (u08)(0x00);
    Buffer[11] = (u08)(0x00);
    Buffer[12] = (u08)(0x00);
    Buffer[13] = 0;
    Buffer[14] = 0;
    Buffer[15] = 0;
    Buffer[16] = 0;
    (void)ApplComm_EnqueueMessage(&Buffer[0], 17); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueReadChannelResponse                                                              */
/*  Stellt ein Antworttelegramm auf eine zuvor eingegangene ReadChannel-Anfrage zusammen            */
/*  und reiht diese in den Sendepuffer ein.                                                         */
/*                                                                                                  */
/* Parameter:     Channel: Kanalnummer des angefragten Kanals                                       */
/*                Data16:  Datum des angefragten Kanals                                             */
/* Rueckgabewert: -                                                                                 */
/*                                                                                                  */
/****************************************************************************************************/
static void ApplComm_EnqueueReadChannelResponse(u08 Channel, u16 Data16)
{
    u08 Buffer[4];

    /* Daten fuer den Versand zusammenstellen */
    Buffer[ 0] = 0x48;               /* Kommandokennung      */
    Buffer[ 1] = (u08)(Channel);     /* Zeitstempel MSB      */
    Buffer[ 2] = (u08)(Data16>>8);   /* Zeitstempel          */
    Buffer[ 3] = (u08)(Data16&0xFF); /* Zeitstempel          */
    (void)ApplComm_EnqueueMessage(&Buffer[0], 4);
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_TransmitBuffers                                                                         */
/*  Vorbereitete Datenpuffer versenden, sofern die Schnittstelle dafuer frei ist                    */
/*                                                                                                  */
/****************************************************************************************************/
static void ApplComm_TransmitQueue(void)
{
    u08        temp;
    static u16 BusyCnt1ms = 0;        /* zaehlt wie lange die Schnittstelle am Stueck belegt ist */
    static u16 DelayCnt1ms = 0;
    static u16 BusyCnt1ms_MAX = 30;   /* nach 30ms Dauerbusy sollte eine Pause beginnen */
    static u16 DelayCnt1ms_INIT = 30; /* Pause sollte mind. 30ms lang sein */

    /* Pruefen, ob Daten zu versenden sind */
    if (ApplComm_SendingIndex != ApplComm_QueuingIndex) /* Liegen Daten zum Versand vor? */
    {
        if (BusyCnt1ms < BusyCnt1ms_MAX)
        {
            BusyCnt1ms++;

            DelayCnt1ms = DelayCnt1ms_INIT;
            ApplComm_SendingIndex = (u08)((ApplComm_SendingIndex+1) % APPLCOMM_NUM_TXBUFFER); /* auf naechsten zu versendenden Puffer weiterschalten */
            /* todo/Hinweis: Sendelaenge ist momentan auf Maximum eingestellt... koennte noch verbessert werden; damit wuerden dann die Sendedaten auf die tatsaechlich benoetigte Menge begrenzt. */
            temp = BiosRs232_EnqueueTxData(&ApplComm_TxBuffer[ApplComm_SendingIndex][0], APPLCOMM_TXBUFFER_LENGTH, TRUE); /* nicht pruefen, ob Versand geklappt hat. Wenn nicht, dann sind die Daten sowieso zu alt, werden also nicht mehr gebraucht */
            if (temp != 0) /* Versand der Daten NICHT akzeptiert? (busy oder "too long") */
            {
                ApplComm_SendingIndex = (u08)((ApplComm_SendingIndex+APPLCOMM_NUM_TXBUFFER-1) % APPLCOMM_NUM_TXBUFFER); /* auf alten Puffer wieder zurueckschalten, damit naechster Durchlauf mit dem richtigen Puffer arbeitet */
                ApplComm_Diagdata.NumDelayedBuffers++; /* Statistik; Versand verzoegert */
            }
            else /* => Daten konnten verschickt werden */
            {
                ApplComm_Diagdata.NumSentBuffers++; /* Statistik */
            }
        }
        else /* => XBee muss eine Pause gegoennt werden */
        {
            if (DelayCnt1ms)
            {
                DelayCnt1ms--;
            }
            else /* => Verzoegerungszeit ist abgelaufen */
            {
                BusyCnt1ms = 0;
                ApplComm_Diagdata.NumDelays1ms++; /* Statistik */
            }
        }
    }
    else /* => Es sind momentan keine Daten zu verschicken */
    {
        BusyCnt1ms = 0; /* ...also endet die Busyzeit hier */
    }
}

/****************************************************************************************************/
/*                                                                                                  */
/* ApplComm_EnqueueMessage                                                                          */
/*  Daten zum Versand vorbereiten, aus den uebergebenen Daten in lokalen Puffer umkopieren          */
/*                                                                                                  */
/* Rueckgabewert: 0: ok, Daten wurden angenommen                                                    */
/*                1: BufferFull                                                                     */
/*                2: BufferTooShort                                                                 */
/*                                                                                                  */
/****************************************************************************************************/
u08 ApplComm_EnqueueMessage(u08 *Data, u08 Len)
{
    u08 retVal = 1;
    u08 CurrentUsage;
    u08 i;

    /* Laengeninfo plausibilisieren */
    if (Len > APPLCOMM_TXBUFFER_LENGTH)
    {
        retVal = 2;
        ApplComm_Diagdata.MaxUsedBufferLen = Len;
    }
    else
    {
        /* Pruefen, ob der SendingIndex nicht genau eins vor dem QueuingIndex steht. Das wuerde naemlich bedeuten, dass der Puffer voll ist und im naechsten Puffer keine neuen Daten mehr annehmen kann */
        if ( ((ApplComm_QueuingIndex+1)%APPLCOMM_NUM_TXBUFFER) != ApplComm_SendingIndex) /* Wuerde das Befuellen des Puffers auf den gerade im Versand befindlichen Puffer schreiben? */
        {
            retVal = 0; /* Daten wurden angenommen */
            ApplComm_Diagdata.NumAcceptedEnqTries++;
            ApplComm_QueuingIndex = (u08)((ApplComm_QueuingIndex+1) % APPLCOMM_NUM_TXBUFFER); /* auf naechsten Puffer weiterschalten, dieser wird dann JETZT gefuellt */
            for (i=0; i<Len; i++)
            {
                ApplComm_TxBuffer[ApplComm_QueuingIndex][i] = *(Data+i);
            }
        }
        else
        {
            ApplComm_Diagdata.NumNotAcceptedEnqTries++; /* Statistik */
        }

        /* Statistik */
        if (ApplComm_Diagdata.MaxUsedBufferLen < Len)
        {
            ApplComm_Diagdata.MaxUsedBufferLen = Len;
        }
        CurrentUsage = (u08)((ApplComm_QueuingIndex + APPLCOMM_NUM_TXBUFFER) - ApplComm_SendingIndex) % APPLCOMM_NUM_TXBUFFER;
        if (CurrentUsage > ApplComm_Diagdata.MaxUsedBuffersNum)
        {
            ApplComm_Diagdata.MaxUsedBuffersNum = CurrentUsage;
        }
    }

    return (retVal);
}
