/**********************************************************************************************
    Copyright (C) 2007 Oliver Eichler oliver.eichler@gmx.de

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA

  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
  or one of its subsidiaries.

**********************************************************************************************/
#ifndef CSERIAL_H
#define CSERIAL_H

#include <string>
#ifdef WIN32
#include <windows.h>
#else
#include <termios.h>
#endif
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
//#include <stdint.h>
#include "ILink.h"
#include "Garmin.h"

namespace Garmin
{
    /// Garmin's serial protocol
    /**
        This should be kept common to all serial devices. However
        if your device does not fit into the protocol implementation
        at all, subclass it and make your fixes.
    */
    class CSerial : public ILink
    {
        public:
            CSerial(const std::string& port);
            virtual ~CSerial();

            /// see ILink::open()
            void open();
            /// see ILink::close()
            void close();
            /// see ILink::read()
            int read(Packet_t& data);
            /// see ILink::write()
            void write(const Packet_t& data);
            /// sync. up sequence
            /**
                This must be called prior to any other request.

                @param responseCount Number of response packets to expect

                @return Actual retrieved number of response packets to product_request
            */
            virtual int syncup(int responseCount = 0);

            int read(char *data);

            uint16_t getProductId(){return productId;}
            int16_t  getSoftwareVersion(){return softwareVersion;}
            const std::string& getProductString(){return productString;}
            uint16_t getDataType(int data_no, char tag, uint16_t protocol);

            // in: bitrate, example: 115200
            // returns: 0=success, <0 error
            int setBitrate( uint32_t bitrate);
            void readTimeout( uint32_t milliseconds);

        protected:

            int serial_char_read( uint8_t *byte, unsigned milliseconds);
            int serial_read(Packet_t& data, unsigned milliseconds = 1000);
            void serial_write(const Packet_t& data);

            int serial_check_ack( uint8_t cmd);
            void serial_send_ack( uint8_t cmd);
            void serial_send_nak( uint8_t cmd);

            virtual void debug(const char * mark, const Garmin::Packet_t& data);

#ifdef WIN32
            HANDLE hCom;
#else
            // file descripor for serial port
            int port_fd;
            struct termios gps_ttysave;
            fd_set fds_read;
            int interface;
#endif
            uint16_t productId;
            int16_t  softwareVersion;
            std::string productString;
            uint32_t protocolArraySize;
            Protocol_Data_t protocolArray[GUSB_PAYLOAD_SIZE];

            std::string port;
            uint32_t readtimeout_ms;
    };

}
#endif                           //CSERIAL_H
