//        TCBITBUS.C - TCtask - Bitbus Interconnect interface routines.
//        V1.2     TECON Ltd.

#include "tsk.h"
#include "bitbus.h"
#include "sio.h"

//**************************** Bitbus-TCX interface ***********************

tlink bitbus_tcx_timer;
flag bitbus_tcx_flag;

// local debug
static word port_base;

// bitbus_tcx_install
//          Creates and initializes objects for connecting via TCX44 device.
//          Returns 0 if OK, -1 on internal software error, -2 on hardware error.


word_s bitbus_tcx_install (word port)
{
        port_base= port;
        return (bitbus_tcx_flush());
}

#define FLUSH_DELAY 1000

// bitbus_tcx_flush
//          Set connection via TCX44 device to initial state.
//          Returns 0 if OK, -2 on hardware error.


word_s bitbus_tcx_flush (void)
{
        word_s c,cc;

        tsk_outp( RESET, 0);
        for (cc= FLUSH_DELAY; cc--; ) for (c= 250; c--; ) ;  // delay !!!
        if (tsk_inp( STATUS) != (byte)(RFNE | RCMD)) return (-2);
        return (0);
}

// bitbus_tcx_send
//          Send message to specifed node via TCX44 device.
//          Returns 0 if OK, -1 on error.


word_s bitbus_tcx_send (bitbus_msg *msg)
{
        word_s c, i= 2;

        while (1)
        {
                for (c= BITBUS_TCX_COUNTOUT; (--c) && (tsk_inp(STATUS) & TFNF); ) ;
                if (!c) return (-1);
                if ((byte)i < msg->length)
                {
// for( c=30000;c--;);
                        tsk_outp( DATA, *((byteptr)msg+(i++)));

                }
                else
                {
                        tsk_outp( COMMAND, 0);
                        return (0);
                }
        }
}

// bitbus_tcx_wait
//          Wait message from TCX44 device.
//          Returns 0 if OK, -1 on timeout, -2 on protocol error.


word_s bitbus_tcx_wait (bitbus_msg *msg, dword timeout)
{
        word_s c, i= 2;
        dword cc;

        cc = timeout;
        while(  cc--                                     // no timeout
                        && ( (tsk_inp(STATUS) & RFNE)           // receive fifo empty
                                || !(tsk_inp(STATUS) & RCMD))) ;     // receive commamnd
        if (!cc) return (-1);                             // timeout

        while (1)
        {
                for (c= BITBUS_TCX_COUNTOUT; (--c) && (tsk_inp(STATUS) & RFNE); ) ;
                if (!c)  return (-2);                      // error

                if (tsk_inp(STATUS) & RCMD)
                {
// for( c=30000;c--;);
                        *((byteptr)msg+(i++))= tsk_inp(DATA);
                }
                else
                {
                        tsk_inp(COMMAND);
                        return (0);
                }
        }
}


//**************************** Bitbus-COM interface ************************

#define COM(s,r)    v24_send( sio, s, 0L); \
                                        r= v24_receive( sio, BITBUS_COM_TIMEOUT)

local tlink bitbus_com_timer;
local flag  bitbus_com_flag;
local sioptr sio;

local word rcvbuf [2];
local byte xmtbuf [2];


// bitbus_com_install
//      Creates and initializes objects for connecting via Bitbus-COM
//      protocol
//      Returns 0 if OK, -1 on error.


word_s bitbus_com_install (word_s port)
{
        if (!create_flag( &bitbus_com_flag
#if (TSK_NAMED)
                                ,"BitCOM_F"
#endif
                                )) return (-1);          // error while flag creation
        sio = v24_install (port, 1, rcvbuf, sizeof (rcvbuf),
                                                                xmtbuf, sizeof (xmtbuf));
        if (sio == NULL) {delete_flag( &bitbus_com_flag); return (-1);}
        v24_change_baud (sio, BITBUS_COM_BAUD);
        v24_protocol (sio, 0, 0, 0);        // No XON/XOFF and RTS/CTS protocol
        return (0);
}

// bitbus_com_flush
//      Set connection via Bitbus-COM protocol to initial state.
//      Returns 0 if OK, -2 on protocol error.


word_s bitbus_com_flush (void)
{
        word_s ch, i;

        while (~v24_check(sio)) v24_receive (sio, 1L);
        for (i=0; i < 20; i++)
        {
                COM('D',ch);
                if (ch == -1) return (-2);
        }
        if (ch != 'D') return (-2);
        return (0);
}

// bitbus_com_send
//      Send message to specifed node via Bitbus-COM protocol.
//      Returns 0 if OK, -1 if no free buffers on bitbus device,
//      -2 on protocol error.


word_s bitbus_com_send (bitbus_msg *msg)
{
        word_s ch, i, err=0;

        COM('I',ch);
        if (ch == 'N') return (-1);
        if (ch != 'I') return (-2);
        for (i=0;i < msg->length-2;i++)
        {
                COM(*((byteptr)msg+i+2), ch);
                if (ch == -1) {err=-2; break;}
                if ((byte)ch != *((byteptr)msg+i+2)) err=-2;
        }
        if (err)
        {
                COM('D',ch);
                return (-2);
        }
        COM('E',ch);
        if (ch != 'E') return (-2);
        return (0);
}

// bitbus_com_wait
//      Wait message via Bitbus-COM protocol.
//      Returns 0 if OK, -1 on timeout, -2 on protocol error.


word_s bitbus_com_wait (bitbus_msg *msg, dword timeout)
{
        word_s ch, len, i, checksum= 0, err= -1;

        clear_flag( &bitbus_com_flag);
        create_timer( &bitbus_com_timer, timeout, &bitbus_com_flag, TKIND_FLAG, 0);
        do
        {
                COM('O',ch);
                if (ch == 'Q') continue;         // msg queue in bitbus device empty
                if (ch == 'O') err= 0;           // msg ready!
                else err= -2;                    // no or bad echo
                break;
        } while ( !check_flag( &bitbus_com_flag));
        if (!err)
        {
                COM('L',len);
                if ((len < 7) || (len > 20)) err= -2;
                else
                {
                        msg->length= (byte)len;
                        checksum= len;
                        for ( i= 3; i < len; i++)
                        {
                                COM('R',ch);
                                if (ch & 0xff00) {err= -2; break;}
                                *((byteptr)msg + i)= (byte)ch;
                                checksum-= ((checksum+= ch) > 255) ? 255 : 0;
                        }
                        COM((byte)checksum, ch);
                        if ((ch & 0xff00) || ((byte)ch != (byte)checksum)) err= -2;
                }
        }
        delete_timer( &bitbus_com_timer);
        return (err);
}