//---------------------------------------------------------------------------
/*
Remote Train Control Program for Windows

© Copyright 2019 by Mark DiVecchio

    This file is part of Remote Train Control.

    Remote Train Control 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 3 of the License, or
    (at your option) any later version.

    Remote Train Control 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 Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

*/
// Home Page : http://www.silogic.com/trains/RTC_Running.html
//---------------------------------------------------------------------------
#ifndef Comm_ThreadH
#define Comm_ThreadH

typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

#ifdef __cplusplus
extern "C" {
#endif

/*
Copyright (c) 2016, Moritz Bitsch

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
 * This code only supports Speck 2-16 bit words of data and a 4-16 bit word key
 *
 * https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/documents/papers/session1-shors-paper.pdf
 */
#define SPECK_TYPE uint16_t 	// unsigned short
#define SPECK_ROUNDS 22
#define SPECK_KEY_LEN 4 		// 4-16 bit words or 64 bits

#define ROR(x, r) ((x >> r) | (x << ((sizeof(SPECK_TYPE) * 8) - r)))
#define ROL(x, r) ((x << r) | (x >> ((sizeof(SPECK_TYPE) * 8) - r)))

#define R(x, y, k) (x = ROR(x, 7), x += y, x ^= k, y = ROL(y, 2), y ^= x)
#define RR(x, y, k) (y ^= x, y = ROR(y, 2), x ^= k, x -= y, x = ROL(x, 7))

void speck_expand(SPECK_TYPE const K[ SPECK_KEY_LEN], SPECK_TYPE S[SPECK_ROUNDS]);
void speck_encrypt(SPECK_TYPE const pt[2], SPECK_TYPE ct[ 2], SPECK_TYPE const K[SPECK_ROUNDS]);
void speck_decrypt(SPECK_TYPE const ct[2], SPECK_TYPE pt[ 2], SPECK_TYPE const K[SPECK_ROUNDS]);

void speck_encrypt_combined(SPECK_TYPE const pt[2], SPECK_TYPE ct[2], SPECK_TYPE const K[SPECK_KEY_LEN]);
void speck_decrypt_combined(SPECK_TYPE const ct[2], SPECK_TYPE pt[2], SPECK_TYPE const K[SPECK_KEY_LEN]);

#ifdef __cplusplus
}
#endif
//---------------------------------------------------------------------------
#include <Classes.hpp>
//---------------------------------------------------------------------------
#define DWDELAY 60000		// default timeout of 60 seconds on some WaitForSingleEvent calls

// Types of commands in the FIFO and Dispatch Lists
//
#define CMD_Type_SendString 0
#define CMD_Type_WaitForResponse 1
#define CMD_Type_SendHex 2
#define CMD_Type_DelayedCommand 3
//---------------------------------------------------------------------------
//
// Convert a RAM address (0 - 0x3FF) and byte number (0-3) into a "q" command address
//
#define RAMTOQ(address, byteno) ( ((byteno) << 14) | (((address) & 0x0001) << 13 | ((address) & 0xFFE) >> 1) ^ 0x1F80)
//
// Convert a 'q' command address into a RAM address (0-0x3FF) and byte number (0-3)
//
#define QTORAM(qc)  ((((qc & 0x2000) >> 13) | ((qc & 0x01FF) << 1)) ^ 0x0300)
#define QTOBYTE(qc) ((qc & 0xC000) >> 14)
//---------------------------------------------------------------------------
/*
Message for communicating between the Comm Thread and the Main VCL UI Thread
*/
struct UI_Struct {
	String Line;
    TColor PrintColor;
    TAbNumEdit * Countr;
    TAbNumSpin * Spinner;
    TColor ColorDefault;
    TEdit * EditBox;
    TRichEdit * Buffer;
    TAbLED * LED;
    TComboBox * ComboBox;
    union {
	    TStringGrid * StringGrid;
        TPanel * Panel;
        TListBox * ListBox;
        TAbRockerSwitch * RockerSwitch;
        };
    union {
        TLabel  * Label;
        TButton  * But;
        };
    union {
	    int iValue;
        int iSignalNo;
        int iEngineNo;
        };
    int * pValue;
	union {
    	int iTIU;
        int iNumberPlate;
        };
    float fValue;
    bool bValue;
    union {
    	int iChan;
        int iMode;
        };
	union {
	    int iState;
        int iAspect;
        int iDistant;
        int iRSNo;
        };
    union {
	    int iAIU;
        int iCol;
        // int iTraffic;
        };
    union {
	    int PCNo;
        int iRow;
        };
    int iDir;
    int iType;
    String Status;   // Message 28
    String Caption;  // Message 28
    };

class TCommThread : public TThread
{
private:
	__fastcall TCommThread(bool CreateSuspended);
    int * MyResultValue;
    bool __fastcall TIUSendWaitforResponseRetry(unsigned char ConsistNo, byte * Command,
		int ExpectedCount, int WaitTime, unsigned char Remote, unsigned char TIU, int * ptrRespCode,
    	int * SWResponseCount, byte * SWResponseBuffer);
    bool __fastcall Send_String(unsigned char Consist, byte * Command_String,
		unsigned char TIU, unsigned char Remote, int Expected, int WaitTime, bool Record_Flag, byte * ptrLashUpEngineList,
    	int * ptrRespCode, int * SSResponseCount, byte * SSResponseBuffer);
    bool __fastcall SendHexStr(byte * Cmd_In, int Len, int ExpectedByteCount, int Timeout, char cTIULocal);

    unsigned int __fastcall CRCGen(Cmd * Command, int StartChar, int EndChar, bool Quiet);
    unsigned int __fastcall CRCEvaluation(Cmd * Cmd_String, int StartChar, int EndChar, bool Quiet);

    int NumRetries;
    bool Speed_Mode, TXOnlyComm, Echo;
	TForm * MyCaller;
	HWND ParentHandle;

    bool My_Radio_COM_Mode, My_WTIU_WiFi_Mode, My_RFID_COM_Mode, My_RFID_WiFi_Mode, My_AIU_WiFi_Mode;
    int MyListBoxCount;

    void __fastcall SetName(DWORD dwThreadID, LPCSTR szThreadName);

    bool __fastcall SendReadRAMCommand(struct FIFOItem * PItem);
	void SetName();

    String TIUIP;		// IP of WiFi Radio for TIU/WTIU Communications
    String TIUPort;	    // Port for WTIU Communications
	//bool MultiCast;		// set true for Radio MultiCast TX

    // AIU Send socket
    void __fastcall AIUSendChangeState(TObject *Sender,
          TSocketState OldState, TSocketState NewState);
    void __fastcall AIUSendSendData(TObject *Sender,
      int BytesSent);
	void __fastcall AIUSendDataSent(TObject *Sender, WORD ErrCode);
	void __fastcall AIUSendSessionClosed(TObject *Sender, WORD ErrCode);
   	void __fastcall AIUSendSessionConnected(TObject *Sender, WORD ErrCode);
    String AIUIP;		// IP of AIU WiFi
    String AIUPort;	    // Port for AIU
	bool AIUMultiCast;	// set true for AIU MultiCast TX

    #if __BORLANDC__ >= 0x720
	// Defined for CB10.1 C++ programs that use the VCL.
  	Overbyteicswinsock::TInAddr FServerAddr;
	Overbyteicswinsock::TSockAddrIn Detector;
    #else
    TInAddr FServerAddr;
	TSockAddrIn Detector;
	#endif

	bool RadioWiFiTXConnected, AIUWiFiTXConnected;
   	// RawRXData must be AnsiString because the c_str() taken needs to be a char type.
    AnsiString RawRXData;   // data returned in global RawRXData by WTIUTXRXDataAvailable() after call to SendStr()
    bool RawRXDataReady;     // WTIUTXRXDataAvailable() sets ResponseReady to true when all data has been received

    void __fastcall WTIUTXRXDataSent(TObject *Sender, WORD ErrCode);
	void __fastcall WTIUTXRXSendData(TObject *Sender, int BytesSent);
	void __fastcall WTIUTXRXSessionConnected(TObject *Sender, WORD ErrCode);
	void __fastcall WTIUTXRXSessionClosed(TObject *Sender, WORD ErrCode);
    void __fastcall WTIUTXRXDataAvailable(TObject *Sender, WORD ErrCode);
    void __fastcall WTIUTXRXSessionAvailable(TObject *Sender, WORD ErrCode);
    bool __fastcall Handshake(TWSocket * Socket);
    bool __fastcall GetWIUInfo(TWSocket * Socket, int * iTIU, int * iAIUCount);
    String __fastcall SendWTIUString(int TIU, String Command, int ConsistNo, int WaitTime);
    bool __fastcall WTIUSendWaitforResponse(TWSocket * socket, String Command, int WaitTime);
    bool __fastcall WTIUWaitforConnection(TWSocket * socket);
    void __fastcall ProcessWIUCommand(AnsiString);

    void __fastcall TCommThread::SleepButHandleMessages(DWORD sleepMs);
    void __fastcall TCommThread::SleepButHandleMessagesandRawRXDataReady(DWORD sleepMs);

protected:
	void __fastcall Execute();
    void __fastcall CleanUp();
    void __fastcall Initialize();
    void __fastcall RunOnTerminate(TObject * Sender);

public:
    __fastcall TCommThread(bool CreateSuspended, TForm * Caller, HWND Parent, String PortName, int BaudRate, int ParitySel, char BitsSel, int StopSel,
    				bool Radio_COM_Mode, bool WTIU_WiFi_Mode, bool RFID_COM_Mode, bool RFID_WiFi_Mode, bool AIU_WiFi_Mode, bool Signals_WiFi_Mode, int * ResultValue);
    __fastcall ~TCommThread();

    bool __fastcall Send_String_FIFO(unsigned char Consist, byte * Command_String,
		unsigned char TIU, unsigned char Remote, int Expected, int WaitTime, bool Record_Flag, byte * ptrLashUpEngineList = (byte *) NULL,
		int * ptrRespCode = (int *) NULL, int * SSResponseCount = (int *) NULL, byte * SSResponseBuffer = (byte *) NULL);

	bool __fastcall TIUSendWaitforResponse_FIFO(unsigned char Consist, byte * Command,
		int ExpectedCount, int WaitTime, unsigned char Remote, unsigned char TIU, int * ptrRespCode = (int *) NULL,
	    int * SWResponseCount = (int *) NULL, byte * SWResponseBuffer = (byte *) NULL);

    bool __fastcall SendHexStrStr_FIFO(int Port, String Cmd_In, int Len);
    bool __fastcall SendHexStr_FIFO(int Port, byte * Cmd_In, int Len);

    void __fastcall charstringtobinary(char * Command, char * Packet, int Len);

    // Thread to VCL communications
    void __fastcall PrintItem(String PrintLine, TColor PrintColor = clBlack);
    void __fastcall Bump(TAbNumEdit * Countr);
    void __fastcall Dec(TAbNumEdit * Countr);
    void __fastcall GetCounterValue(TAbNumEdit * Countr, int * CntrVal);
    void __fastcall SetColor(TAbNumSpin * Spinner, TColor SpinnerColorDefault);
    void __fastcall SetTextValue(TEdit * EditBox, String TextValue);
    void __fastcall GetTextValue(TEdit * EditBox, String &TextValue);
    void __fastcall SetRecordingTextValue(String TextValue);
    void __fastcall ShowinTIUBuffer(String TextValue, TColor Color = clLime);
    void __fastcall PopupItem(String PrintLine, int Duration = 2000, String PrintLine2 = "");
    void __fastcall ShowinBuffer(TRichEdit * Buf, String PrintLine, TColor PrintColor = clBlack, bool Scroll = true);
    void __fastcall GetSpinnerValue(TAbNumSpin * Spinner, int * SpinnerVal);
    void __fastcall SetSpinnerValue(TAbNumSpin * Spinner, int Value = 0);
	void __fastcall SetNumEditValue(TAbNumEdit * Countr, int Value = 0);
    void __fastcall SetPCLED(TAbLED * LED, int iState, String Line);
    void __fastcall SetNumEditColor(TAbNumEdit * Countr, TColor Color);
    void __fastcall GetComboBoxText(TComboBox * ComboBox, AnsiString &TextValue, int Index);
    void __fastcall ClearCounter(TAbNumEdit * Countr);
    void __fastcall SetCounter(TAbNumEdit * Countr, float value);
    void __fastcall OpenAIUWindow(int TIU, int AIU);
    void __fastcall GetAIUSwitchState(int iChannel, int iAIU, int iTIU, bool &bState, int MyPCNo);
    void __fastcall GetAIUAccState(int iChannel, int iAIU, int iTIU, bool &bState, int MyPCNo);
	void __fastcall GetAIUSwitchName(int iChannel, int iAIU, int iTIU, AnsiString &TextValue, int MyPCNo);
	void __fastcall GetAIUAccName(int iChannel, int iAIU, int iTIU, AnsiString &TextValue, int MyPCNo);
    void __fastcall MakeItSo(int iAIU, int iTIU, int MyPCNo);
	void __fastcall SetVirtualAIUAccState(bool bState, int iChannel, int iAIU, int iTIU, int MyPCNo);
    void __fastcall RTSSwitch(bool Checked);
    void __fastcall DTRSwitch(bool Checked);
	void __fastcall AddCntr(TAbNumEdit * Countr, int Val);

    void __fastcall GetStringGridText(TStringGrid * StringGrid, AnsiString &TextValue, int &PSLevel, int Index);
	void __fastcall SetLabelText(TLabel * Label, String TextValue);
	void __fastcall PopupMessage(String Message, String Caption, String Status, int dly);
    void __fastcall GetListBoxText(TListBox * ListBox, String &TextValue, int Index);

	// Layout Flags
	void __fastcall GetFlag(int FlagNo, int &iState);
	void __fastcall SetFlag(int FlagNo, int &iState);
	void __fastcall GetFlagName(int FlagNo, String &FlagName);
	void __fastcall SetFlagName(int FlagNo, String FlagName, int &iState);
    void __fastcall ShowLayout(void);

    // Fixed Signals
	void __fastcall GetAspect(int SignalNo, int &Aspect, int &iMode, int &iType);
	void __fastcall SetAspect(int SignalNo, int &Aspect);
	void __fastcall GetSignalName(int SignalNo, String &SignalName, int &NumberPlate, int &iType);
	void __fastcall CreateSignal(int SignalNo, int iDir, int iType, int Col, int Row, String SignalName, int &Aspect, int iMode = 3, int NumberPlate = 0);
	void __fastcall DeleteSignal(int SignalNo);
    void __fastcall DeleteAllSignals(void);
    void __fastcall ShowSignals(void);

    // Cab Signals
	void __fastcall SetCabAspect(int Head, int Aspect, int MyPCNo);
    void __fastcall GetCabAspect(int Head, int &iAspect, int &iMode, int &iType, int MyPCNo);
	void __fastcall SetCabLabels(int Head, String sName, int iNumberPlate, int iType, int MyPCNo);
    void __fastcall CreateCabSignals(int iHead, int iDistant, int MyPCNo);

    // LED
	void __fastcall SetLED(TAbLED * LED, TColor ColorOn = clLime, bool Checked = true, bool Flashing = false, String Line = NULL);

    // Utility
	void __fastcall GetTIU(int EngineNo, int &TIUNo);
	void __fastcall SetRockerSwitch(TAbRockerSwitch * RockerSwitch, bool bValue);
    void __fastcall SetButtonCaption(TButton * But, String Caption);

    // Route/Scene
    void __fastcall ProcessRS(int RSNo, int iFunc);

    bool Finished;	// true when finished

    TThreadList * FIFO;	    //  FIFO Communication List - Thread Safe
    WORD ConnectError;      // WTIUTXRX session connection error code. set by WTIUTXRXSessionConnected()
    bool TIUCommands[256];	// List of TIU based Commands, indexed by first character of command
    byte LastEngine[TIUMAX];// last engine number sent to the WTIU with 'y' command, 127 == unknown
};
//---------------------------------------------------------------------------
#endif

