3

1]1i have a gps device that should send GPRMC Data but it require login packect Review the dataSheet Device DataSheet

enter image description here

i can recieve the login 787811010XXX739050313XXX20200001000E0EAD0D0A

     IMEI Sart With XXX

the packet is different from the example Image

i have 2 Questions 1-according to the data recieveid and the example what should i send 2- how to calcaulate the Error Check Thank You

Edit

public static void StartListening()
{
    // Data buffer for incoming data.
    byte[] bytes = new Byte[1024];

    // Establish the local endpoint for the socket.
    // The DNS name of the computer
    // running the listener is "host.contoso.com".
    IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
    IPAddress ipAddress = ipHostInfo.AddressList[0];
    IPAddress local = IPAddress.Parse("My IP");
    IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 8841);

    // Create a TCP/IP socket.
    Socket listener = new Socket(AddressFamily.InterNetwork,
        SocketType.Stream, ProtocolType.Tcp);

    // Bind the socket to the local endpoint and listen for incoming connections.
    try
    {
        listener.Bind(localEndPoint);
        listener.Listen(100);

        while (true)
        {
            // Set the event to nonsignaled state.
            allDone.Reset();

            // Start an asynchronous socket to listen for connections.
            // Console.WriteLine("Waiting for a connection...");
            listener.BeginAccept(
                new AsyncCallback(AcceptCallback),
                listener);

            // Wait until a connection is made before continuing.
            allDone.WaitOne();
        }

    }
    catch (Exception e)
    {
        // Console.WriteLine(e.ToString());
    }

    // Console.WriteLine("\nPress ENTER to continue...");
    // Console.Read();

}
private static void Send(Socket handler, String data)
{
    // Convert the string data to byte data using ASCII encoding.
    byte[] byteData = Encoding.ASCII.GetBytes(data);

    // Begin sending the data to the remote device.
    handler.BeginSend(byteData, 0, byteData.Length, 0,
        new AsyncCallback(SendCallback), handler);
}
private static void Send(Socket handler, byte[]  data)
{
    // Convert the string data to byte data using ASCII encoding.
   // byte[] byteData = Encoding.ASCII.GetBytes(data);

    // Begin sending the data to the remote device.
    handler.BeginSend(data, 0, data.Length, 0,
        new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
    try
    {
        // Retrieve the socket from the state object.
        Socket handler = (Socket)ar.AsyncState;

        // Complete sending the data to the remote device.
        int bytesSent = handler.EndSend(ar);
        // Console.WriteLine("Sent {0} bytes to client.", bytesSent);

        handler.Shutdown(SocketShutdown.Both);
        handler.Close();

    }
    catch (Exception e)
    {
        // Console.WriteLine(e.ToString());
    }
}
public static void AcceptCallback(IAsyncResult ar)
{
    // Signal the main thread to continue.
    allDone.Set();

    // Get the socket that handles the client request.
    Socket listener = (Socket)ar.AsyncState;
    Socket handler = listener.EndAccept(ar);

    // Create the state object.
    StateObject state = new StateObject();
    state.workSocket = handler;
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(ReadCallback), state);
}
static byte[] Unpack(string data)
{
    //return null indicates an error
    List<byte> bytes = new List<byte>();

    // check start and end bytes

    if ((data.Substring(0, 4) != "7878") && (data.Substring(data.Length - 4) != "0D0A"))
    {
        return null;
    }

    for (int index = 4; index < data.Length - 4; index += 2)
    {
        bytes.Add(byte.Parse(data.Substring(index, 2), System.Globalization.NumberStyles.HexNumber));
    }
    //crc test
    byte[] packet = bytes.Take(bytes.Count - 2).ToArray();
    byte[] crc = bytes.Skip(bytes.Count - 2).ToArray();

    uint CalculatedCRC = crc_bytes(packet);


    return packet;
}
public static UInt16 crc_bytes(byte[] data)
{
    ushort crc = 0xFFFF;

    for (int i = 0; i < data.Length; i++)
    {
        crc ^= (ushort)(data[i] << 8);
        for (int j = 0; j < 8; j++)
        {
            if ((crc & 0x8000) > 0)
                crc = (ushort)((crc << 1) ^ 0x1021);
            else
                crc <<= 1;
        }
    }

    return crc;
}
public static void ReadCallback(IAsyncResult ar)
{
    String content = String.Empty;

    // Retrieve the state object and the handler socket
    // from the asynchronous state object.
    StateObject state = (StateObject)ar.AsyncState;
    Socket handler = state.workSocket;

    // Read data from the client socket. 
    int bytesRead = handler.EndReceive(ar);

    if (bytesRead > 0)
    {

        if (state.buffer[3] == 1)
        {

            string input = BitConverter.ToString(state.buffer, 0, bytesRead).Replace("-", "");

            byte[] bytes = Unpack(input);

            byte[] serialNumber = bytes.Skip(bytes.Length - 2).ToArray();

            byte[] response = { 0x78, 0x78, 0x05, 0x01, 0x00, 0x00, 0x00, 0x0 };

            serialNumber.CopyTo(response, 4);

            UInt16 sendCRC = crc_bytes(response.Take(response.Length - 2).ToArray());

            response[response.Length - 2] = (byte)((sendCRC >> 8) & 0xFF);
            response[response.Length - 1] = (byte)((sendCRC) & 0xFF);

            Send(handler, response);
           // handler.Send(response);
        }
        else
        {
            // There  might be more data, so store the data received so far.
            state.sb.Append(Encoding.ASCII.GetString(
                state.buffer, 0, bytesRead));

            // Check for end-of-file tag. If it is not there, read 
            // more data.
            content = state.sb.ToString();


            SaveData(content);
            // Not all data received. Get more.
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
            // }
        }
    }
}

Vendor DataSheet

4.6. Error Check A check code may be used by the terminal or the server to distinguish whether the received information is error or not. To prevent errors occur during data transmission, error check is added to against data misoperation, so as to increase the security and efficiency of the system. The check code is generated by the CRC-ITU checking method. The check codes of data in the structure of the protocol, from the Packet Length to the Information Serial Number (including “Packet Length” and “Information Serial Number”) , are values of CRC-ITU. CRC error occur when the received information is calculated, the receiver will ignore and discard the data packet. 4

DataBase Table

CREATE TABLE [dbo].[T_Tracking](
[id] [int] IDENTITY(1,1) NOT NULL,
[IMEI] [nvarchar](50) NULL,
[TrackTime] [datetime] NULL,
[CurrTime] [datetime] NULL CONSTRAINT [DF_T_Tracking_CurrTime]  DEFAULT (getutcdate()),
[Longitude] [nvarchar](50) NULL,
[Lattitude] [nvarchar](50) NULL,
[speed] [float] NULL    

You Code

 switch (protocolNumber)
                            {
                                case PROTOCOL_NUMBER.LOGIN_MESSAGE:
                                    serialNumber.CopyTo(loginResponse, 4);

                                    sendCRC = crc_bytes(loginResponse.Skip(2).Take(loginResponse.Length - 6).ToArray());

                                    loginResponse[loginResponse.Length - 4] = (byte)((sendCRC >> 8) & 0xFF);
                                    loginResponse[loginResponse.Length - 3] = (byte)((sendCRC) & 0xFF);

                                    string terminalID = Encoding.ASCII.GetString(receiveMessage.Skip(4).Take(messageLength - 5).ToArray());
                                    Console.WriteLine("Received good login message from Serial Number : '{0}', Terminal ID = '{1}'", "0x" + serialNumber[0].ToString("X2") + serialNumber[1].ToString("X2"), terminalID);

                                    Console.WriteLine("Send Message : '{0}'", BytesToString(loginResponse));
                                    Send(state.workSocket, loginResponse);

                                    break;
                                case PROTOCOL_NUMBER.LOCATION_DATA:
                                    year = receiveMessage[4];
                                    month = receiveMessage[5];
                                    day = receiveMessage[6];
                                    hour = receiveMessage[7];
                                    minute = receiveMessage[8];
                                    second = receiveMessage[9];

                                    date = new DateTime(2000 + year, month, day, hour, minute, second);
                                    Console.WriteLine("Received good location message from Serial Number '{0}', Time = '{1}'", "0x" + serialNumber[0].ToString("X2") + serialNumber[1].ToString("X2"), date.ToLongDateString()); string lng = message.Substring(22, 8);
                                Int64 lngVal = Convert.ToInt64(lng, 16);

                                double step3 = (double)lngVal / 30000;
                                double step4 = (double)((step3 / 60));
                                //int lngdeg =Convert.ToInt32( step4.ToString().Split('.')[0]);

                                //  double step5 = (double)(step4 * 60) - step3;


                                string lat = message.Substring(30, 8);
                                Int64 altVal = Convert.ToInt64(lat, 16);
                                double Lstep3 = (double)altVal / 30000;
                                double Lstep4 = (double)((Lstep3) / 60);
                                //  double Lstep5 = (double)(Lstep4 * 60) - Lstep3;
                                //Console.WriteLine("Date : '{0}',Long : '{1}', Receive Message : '{2}'", dateStr, step4, Lstep4);
                                string speedstr = message.Substring(38, 2);
                                int SpeedVal = Convert.ToInt32(speedstr, 16);
                                SaveData(IMEI , dateStr, step4.ToString(), Lstep4.ToString(), SpeedVal);//Get IMEI From Login Message that is the Problem
                                    break;

enter image description here

Status Message enter image description here

Maher Khalil
  • 529
  • 1
  • 15
  • 28
  • Any Response Please – Maher Khalil Jun 10 '17 at 12:40
  • Posting was updated with jdweng code and now works. Question answered. – jdweng Jun 11 '17 at 08:08
  • No i mean to ask is this code (In the Edit) is correct because it is not working it calculate CRC but the device still send login Packet i wonder if my impemitaion is correct or should i use it some othe way – Maher Khalil Jun 11 '17 at 08:38
  • @jdweng i have BL10 GPS Tracker device can please help me to integrate it ..i am using java in backend.. – Amol Raje Apr 17 '18 at 14:58
  • we are using this for the bicycle sharing project – Amol Raje Apr 17 '18 at 15:00
  • I am creating `thread` for each new device request I think that I need to keep `thread` alive to keep a connection with GPS device and send response packet for every. – Amol Raje Apr 17 '18 at 15:04
  • but I am facing a problem with sending online command of unlocking to GPS device when the user wants to unlock the bicycle because how can I send a task to already running thread. – Amol Raje Apr 17 '18 at 15:11
  • please help me. thank you. – Amol Raje Apr 17 '18 at 15:13
  • I don't know why you need separate threads. The Async method handles the threads. Each connection (socket) is added to the dictionary. So once you look up the IP address of the device you return the StateObject (which has the socket) and you just send to the socket for the device returned from the dictionary. – jdweng Apr 17 '18 at 15:36
  • Its been a while since I've looked at the code. You need to unlock by the IMEI of the device. I give each connection a number which is the key in the dictionary connectionDict. The StateObject contains the IMEI number. So to get the socket to send the unlock you need to enumerate through the connectionDict to find the IMEI and Socket and then send the unlock message to the socket. I've been expecting a question on unlocking for over a year. Didn't initially add to the code. – jdweng Apr 17 '18 at 15:49
  • How do you disable a bicycle if somebody tries to steal it. On a car it shuts down the oil pump. On a bicycle to you give it a flat tire? – jdweng Apr 17 '18 at 15:55
  • The code uses two Network layers 1) Application : The while loop in ProcessMessages() 2) Transport Layer : TCP Async Send/Receive. The application layer has two ports 1) TCP 2) FIFO to database. To unlock you need to add a Port to the Application While loop to read commands. I would use a FIFO similar to database interface. The Application layer every loop will check if data is available in the FIFO. If data is available send to TCP the unlock message. – jdweng Apr 17 '18 at 17:22
  • @jdweng thanks for your reply.. I didn't understand why I don't need `thread` i have to responses to GPS devices for every request to keep the connection alive. – Amol Raje Apr 18 '18 at 05:10
  • the IMEI number I get only first time from GPS device in login packet then only location, heartbeat, and other packets after some interval in that no IMEI number. – Amol Raje Apr 18 '18 at 05:13
  • here is the coomunication protocol pdf https://drive.google.com/file/d/1AsBk3iPyLGk4QyuDevYx86lJlfUVYE1t/view?usp=sharing – Amol Raje Apr 18 '18 at 05:13
  • can please help me with some little bit with java code and the flow so can understand? – Amol Raje Apr 18 '18 at 05:14
  • also, there is no separate IP address for GPS devices they all are sending a packet to single IP address and port of the server. – Amol Raje Apr 18 '18 at 05:37
  • Don't modify the code for threading. It works perfectly as is. The issues you are having are due to the threading issue. Using one thread the IMEI is received in first message and then kept in the StateObject. Creating multiple threads will loose the IMEI wshich is needed. Each connection has a source and destination IP address. The destination IP is the same for all connections. The source IP is different for each device. When you respond back to a device you are using the same connection that the initial connection was received in the Accept method. – jdweng Apr 18 '18 at 09:48
  • currently, I am using thread it works but I want to ask how can I find connection means which thread is connected to which IMEI so i can send the unlock request to devices when needed, but i can't find a way please help me with some code. how can I crate StateObject and store the IMEI and how to send a task to already running thread on the particular connection. – Amol Raje Apr 18 '18 at 10:48
  • I need to do this project in java can someone help me with some example to read login packet –  Apr 23 '18 at 05:48

2 Answers2

7

Here is section 2 :

      public void ProcessMessages()
        {
            UInt16 sendCRC = 0;
            DateTime date;
            int year = 0;
            int month = 0;
            int day = 0;
            int hour = 0;
            int minute = 0;
            int second = 0;

            KeyValuePair<List<byte>, StateObject> byteState;
            KeyValuePair<UNPACK_STATUS, byte[]> status;
            byte[] receiveMessage = null;
            StateObject state = null;
            byte[] serialNumber = null;
            byte[] serverFlagBit = null;
            byte[] stringArray = null;
            string stringMessage = "";
            byte lengthOfCommand = 0;
            PROTOCOL_NUMBER protocolNumber = PROTOCOL_NUMBER.NONE;

            try
            {
                Boolean firstMessage = true;
                acceptDone.Set();
                //loop forever
                while (true)
                {
                    allDone.WaitOne();

                    //read fifo until empty
                    while (true)
                    {
                        //read one connection until buffer doesn't contain any more packets
                        byteState = ReadWrite(PROCESS_STATE.PROCESS, null, null, -1);

                        if (byteState.Value.fifoCount == -1) break;

                        state = byteState.Value;
                        while (true)
                        {
                            status = Unpack(byteState);
                            if (status.Key == UNPACK_STATUS.NOT_ENOUGH_BYTES)
                                break;

                            if (status.Key == UNPACK_STATUS.ERROR)
                            {
                                Console.WriteLine("Error : Bad Receive Message, Data");
                                break;
                            }

                            //message is 2 start bytes + 1 byte (message length) + 1 byte message length + 2 end bytes
                            receiveMessage = status.Value;

                            int messageLength = receiveMessage[2];
                            Console.WriteLine("Status : '{0}', Receive Message : '{1}'", status.Key == UNPACK_STATUS.GOOD_MESSAGE ? "Good" : "Bad", BytesToString(receiveMessage.Take(messageLength + 5).ToArray()));

                            if (status.Key != UNPACK_STATUS.GOOD_MESSAGE)
                            {
                                break;
                            }
                            else
                            {
                                if (firstMessage)
                                {
                                    if (receiveMessage[3] != 0x01)
                                    {
                                        Console.WriteLine("Error : Expected Login Message : '{0}'", BytesToString(receiveMessage));
                                        break;
                                    }
                                    firstMessage = false;
                                }

                                //skip start bytes, message length.  then go back 4 bytes (CRC and serial number)
                                serialNumber = receiveMessage.Skip(2 + 1 + messageLength - 4).Take(2).ToArray();

                                protocolNumber = (PROTOCOL_NUMBER)receiveMessage[3];
                                Console.WriteLine("Protocol Number : '{0}'",protocolNumber.ToString());
                                switch (protocolNumber)
                                {
                                    case PROTOCOL_NUMBER.LOGIN_MESSAGE:
                                        serialNumber.CopyTo(loginResponse, 4);

                                        sendCRC = crc_bytes(loginResponse.Skip(2).Take(loginResponse.Length - 6).ToArray());

                                        loginResponse[loginResponse.Length - 4] = (byte)((sendCRC >> 8) & 0xFF);
                                        loginResponse[loginResponse.Length - 3] = (byte)((sendCRC) & 0xFF);

                                        //
                                        string IMEI = Encoding.ASCII.GetString(receiveMessage.Skip(4).Take(messageLength - 5).ToArray());
                                        byteState.Value.IMEI = IMEI;

                                        Console.WriteLine("Received good login message from Serial Number : '{0}', Terminal ID = '{1}'", "0x" + serialNumber[0].ToString("X2") + serialNumber[1].ToString("X2"), IMEI);

                                        Console.WriteLine("Send Message : '{0}'", BytesToString(loginResponse));
                                        Send(state.workSocket, loginResponse);

                                        WriteDBMessageLogin loginMessage = new WriteDBMessageLogin() { message = DATABASE_MESSAGE_TYPE.LOGIN, IMEI = IMEI, date = DateTime.Now };

                                        WriteDBAsync.ReadWriteFifo(WriteDBAsync.Mode.WRITE, loginMessage);

                                        Console.WriteLine("Wrote to database");
                                        break;
                                    case PROTOCOL_NUMBER.LOCATION_DATA:
                                        year = receiveMessage[4];
                                        month = receiveMessage[5];
                                        day = receiveMessage[6];
                                        hour = receiveMessage[7];
                                        minute = receiveMessage[8];
                                        second = receiveMessage[9];

                                        date = new DateTime(2000 + year, month, day, hour, minute, second);

                                        WriteDBMessageLocation locationMessage = new WriteDBMessageLocation();
                                        locationMessage.message = DATABASE_MESSAGE_TYPE.LOCATION;

                                        locationMessage.trackTime = date;
                                        locationMessage.currTime = DateTime.Now;

                                        locationMessage.lattitude = new byte[4];
                                        Array.Copy(receiveMessage, 11, locationMessage.lattitude, 0, 4);

                                        locationMessage.longitude = new byte[4];
                                        Array.Copy(receiveMessage, 15, locationMessage.longitude, 0, 4);
                                        locationMessage.speed = receiveMessage[19];

                                        locationMessage.courseStatus = new byte[2];
                                        Array.Copy(receiveMessage, 20, locationMessage.courseStatus, 0, 2);

                                        locationMessage.IMEI = byteState.Value.IMEI;
                                        WriteDBAsync.ReadWriteFifo(WriteDBAsync.Mode.WRITE, locationMessage);


                                        Console.WriteLine("Received good location message from Serial Number '{0}', Time = '{1}'", "0x" + serialNumber[0].ToString("X2") + serialNumber[1].ToString("X2"), date.ToLongDateString());
                                        break;

                                    case PROTOCOL_NUMBER.ALARM_DATA:

                                        //first response
                                        int alarmPacketLen = alarmResponse.Length - 5;
                                        alarmResponse[2] = (byte)(alarmPacketLen & 0xFF);

                                        serialNumber.CopyTo(alarmResponse, alarmPacketLen - 1);

                                        sendCRC = crc_bytes(alarmResponse.Skip(2).Take(alarmPacketLen - 1).ToArray());

                                        alarmResponse[alarmPacketLen + 1] = (byte)((sendCRC >> 8) & 0xFF);
                                        alarmResponse[alarmPacketLen + 2] = (byte)((sendCRC) & 0xFF);

                                        Console.WriteLine("Send Alarm Response Message : '{0}'", BytesToString(alarmResponse));
                                        Send(state.workSocket, alarmResponse);


                                        //second response
                                        year = receiveMessage[4];
                                        month = receiveMessage[5];
                                        day = receiveMessage[6];
                                        hour = receiveMessage[7];
                                        minute = receiveMessage[8];
                                        second = receiveMessage[9];

                                        date = new DateTime(2000 + year, month, day, hour, minute, second);
                                        Console.WriteLine("Received good alarm message from Serial Number '{0}', Time = '{1}'", "0x" + serialNumber[0].ToString("X2") + serialNumber[1].ToString("X2"), date.ToLongDateString());
                                        int alarmDataAddressPacketLen = alarmDataAddressResponse.Length - 5;
                                        alarmDataAddressResponse[2] = (byte)(alarmDataAddressPacketLen & 0xFF);

                                        serialNumber.CopyTo(alarmDataAddressResponse, alarmDataAddressPacketLen - 1);

                                        sendCRC = crc_bytes(alarmDataAddressResponse.Skip(2).Take(alarmDataAddressPacketLen - 1).ToArray());

                                        alarmDataAddressResponse[alarmDataAddressPacketLen + 1] = (byte)((sendCRC >> 8) & 0xFF);
                                        alarmDataAddressResponse[alarmDataAddressPacketLen + 2] = (byte)((sendCRC) & 0xFF);

                                        Console.WriteLine("Send Alarm Data Address Message : '{0}'", BytesToString(alarmDataAddressResponse));
                                        Send(state.workSocket, alarmDataAddressResponse);

                                        break;

                                    case PROTOCOL_NUMBER.STATUS_INFO:
                                        serialNumber.CopyTo(heartbeatResponse, 4);

                                        byte info = receiveMessage[4];
                                        byte voltage = receiveMessage[5];
                                        byte GSMsignalStrength = receiveMessage[6];
                                        UInt16 alarmLanguage = (UInt16)((receiveMessage[7] << 8) | receiveMessage[8]);

                                        ALARM alarm = (ALARM)((info >> 3) & 0x07);

                                        sendCRC = crc_bytes(heartbeatResponse.Skip(2).Take(heartbeatResponse.Length - 6).ToArray());

                                        heartbeatResponse[heartbeatResponse.Length - 4] = (byte)((sendCRC >> 8) & 0xFF);
                                        heartbeatResponse[heartbeatResponse.Length - 3] = (byte)((sendCRC) & 0xFF);

                                        Console.WriteLine("Received good status message from Serial Number : '{0}', INFO : '0x{1}{2}{3}{4}'",
                                            "0x" + serialNumber[0].ToString("X2") + serialNumber[1].ToString("X2"),
                                            info.ToString("X2"), voltage.ToString("X2"), GSMsignalStrength.ToString("X2"),
                                            alarmLanguage.ToString("X4"));

                                        Console.WriteLine("Send Message : '{0}'", BytesToString(heartbeatResponse));
                                        Send(state.workSocket, heartbeatResponse);

                                        switch (alarm)
                                        {
                                            //reset cut off alarm
                                            case ALARM.POWER_CUT_ALARM:
                                                int connectOilAndElectricityPacketLen = connectOilAndEletricity.Length - 5;
                                                serialNumber.CopyTo(connectOilAndEletricity, connectOilAndElectricityPacketLen - 1);
                                                sendCRC = crc_bytes(connectOilAndEletricity.Skip(2).Take(connectOilAndEletricity.Length - 6).ToArray());
                                                connectOilAndEletricity[connectOilAndEletricity.Length - 4] = (byte)((sendCRC >> 8) & 0xFF);
                                                connectOilAndEletricity[connectOilAndEletricity.Length - 3] = (byte)((sendCRC) & 0xFF);

                                                serverFlagBit = new byte[4];
                                                Array.Copy(connectOilAndEletricity, 5, serverFlagBit, 0, 4);

                                                lengthOfCommand = connectOilAndEletricity[4];
                                                stringArray = new byte[lengthOfCommand - 4]; //do not include server flag bit
                                                Array.Copy(connectOilAndEletricity, 9, stringArray, 0, lengthOfCommand - 4);
                                                stringMessage = Encoding.ASCII.GetString(stringArray);

                                                Console.WriteLine("Reset Oil and Electricity, Server Flag Bit : '{0}{1}{2}{3}', Message : '{4}'",
                                                  serverFlagBit[0].ToString("X2"),
                                                  serverFlagBit[1].ToString("X2"),
                                                  serverFlagBit[2].ToString("X2"),
                                                  serverFlagBit[3].ToString("X2"),
                                                  stringMessage);
                                                Send(state.workSocket, connectOilAndEletricity);
                                                break;
                                         }

                                        break;

                                    case PROTOCOL_NUMBER.STRING_INFO :
                                        lengthOfCommand = receiveMessage[4];
                                        serverFlagBit = new byte[4];
                                        Array.Copy(receiveMessage, 5, serverFlagBit, 0, 4);
                                        stringArray = new byte[lengthOfCommand - 4]; //do not include server flag bit
                                        Array.Copy(receiveMessage, 9, stringArray, 0, lengthOfCommand - 4);
                                        stringMessage = Encoding.ASCII.GetString(stringArray);

                                        Console.WriteLine("String Message, Server Flag Bit : '{0}{1}{2}{3}', Message : '{4}'", 
                                            serverFlagBit[0].ToString("X2"),
                                            serverFlagBit[1].ToString("X2"),
                                            serverFlagBit[2].ToString("X2"),
                                            serverFlagBit[3].ToString("X2"),
                                            stringMessage);

                                        break;

                                } //end switch
                            }// End if
                        } //end while
                    }//end while fifo > 0
                    allDone.Reset();
                }//end while true
            }
            catch (Exception e)
            {

                Console.WriteLine(e.Message);
            }

        }

        static string BytesToString(byte[] bytes)
        {

            return string.Join("", bytes.Select(x => x.ToString("X2")));
        }
        static KeyValuePair<UNPACK_STATUS, byte[]> Unpack(KeyValuePair<List<byte>, StateObject> bitState)
        {
            List<byte> working_buffer = bitState.Key;
            //return null indicates an error
            if (working_buffer.Count() < 3) return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.NOT_ENOUGH_BYTES, null);

            int len = working_buffer[2];

            if (working_buffer.Count < len + 5) return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.NOT_ENOUGH_BYTES, null);
            // check start and end bytes
            // remove message fro workig buffer and dictionary 
            KeyValuePair<List<byte>, StateObject> byteState = ReadWrite(PROCESS_STATE.UNPACK, null, null, bitState.Value.connectionNumber);
            if (byteState.Key.Count == 0) return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.ERROR, null);

            List<byte> packet = byteState.Key;

            //crc test
            byte[] crc = packet.Skip(len + 1).Take(2).ToArray();
            ushort crcShort = (ushort)((crc[0] << 8) | crc[1]);
            //skip start bytes, crc, and end bytes
            ushort CalculatedCRC = crc_bytes(packet.Skip(2).Take(len - 1).ToArray());

            if (CalculatedCRC != crcShort)
            {
                return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.BAD_CRC, packet.ToArray());
            }

            return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.GOOD_MESSAGE, packet.ToArray());
        }
        static public UInt16 crc_bytes(byte[] data)
        {
            ushort crc = 0xFFFF;

            for (int i = 0; i < data.Length; i++)
            {
                crc ^= (ushort)(Reflect(data[i], 8) << 8);
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x8000) > 0)
                        crc = (ushort)((crc << 1) ^ 0x1021);
                    else
                        crc <<= 1;
                }
            }
            crc = Reflect(crc, 16);
            crc = (ushort)~crc;
            return crc;
        }
        static public ushort Reflect(ushort data, int size)
        {
            ushort output = 0;
            for (int i = 0; i < size; i++)
            {
                int lsb = data & 0x01;
                output = (ushort)((output << 1) | lsb);
                data >>= 1;
            }
            return output;
        }

        static KeyValuePair<List<byte>, StateObject> ReadWrite(PROCESS_STATE ps, Socket handler, IAsyncResult ar, long unpackConnectionNumber)
        {
            KeyValuePair<List<byte>, StateObject> byteState = new KeyValuePair<List<byte>, StateObject>(); ;
            StateObject stateObject = null;
            int bytesRead = -1;
            int workingBufferLen = 0;
            List<byte> working_buffer = null;
            byte[] buffer = null;

            Object thisLock1 = new Object();

            lock (thisLock1)
            {
                switch (ps)
                {
                    case PROCESS_STATE.ACCEPT:

                        acceptDone.WaitOne();
                        acceptDone.Reset();
                        stateObject = new StateObject();
                        stateObject.buffer = new byte[BUFFER_SIZE];
                        connectionDict.Add(connectionNumber, new KeyValuePair<List<byte>, StateObject>(new List<byte>(), stateObject));
                        stateObject.connectionNumber = connectionNumber++;

                        stateObject.workSocket = handler;

                        byteState = new KeyValuePair<List<byte>, StateObject>(null, stateObject);
                        acceptDone.Set();
                        break;

                    case PROCESS_STATE.READ:
                        //catch when client disconnects

                        //wait if accept is being called
                        //acceptDone.WaitOne();
                        try
                        {
                            stateObject = ar.AsyncState as StateObject;
                            // Read data from the client socket. 
                            bytesRead = stateObject.workSocket.EndReceive(ar);

                            if (bytesRead > 0)
                            {
                                byteState = connectionDict[stateObject.connectionNumber];

                                buffer = new byte[bytesRead];
                                Array.Copy(byteState.Value.buffer, buffer, bytesRead);

                                byteState.Key.AddRange(buffer);
                            }
                            //only put one instance of connection number into fifo
                            if (!fifo.Contains(byteState.Value.connectionNumber)) {

                                fifo.Add(byteState.Value.connectionNumber);
                            }
                        }
                        catch (Exception ex)
                        {
                            //will get here if client disconnects
                            fifo.RemoveAll(x => x == byteState.Value.connectionNumber);
                            connectionDict.Remove(byteState.Value.connectionNumber);
                            byteState = new KeyValuePair<List<byte>, StateObject>(new List<byte>(), null);
                        }
                        break;

                    case PROCESS_STATE.PROCESS:
                        if (fifo.Count > 0)
                        {
                            //get message from working buffer
                            //unpack will later delete message
                            //remove connection number from fifo
                            // the list in the key in known as the working buffer
                            byteState = new KeyValuePair<List<byte>, StateObject>(connectionDict[fifo[0]].Key, connectionDict[fifo[0]].Value);
                            fifo.RemoveAt(0);
                            //put a valid value in fifoCount so -1 below can be detected.
                            byteState.Value.fifoCount = fifo.Count;
                        }
                        else
                        {
                            //getting here is normal when there is no more work to be performed
                            //set fifocount to zero so rest of code know fifo was empty so code waits for next receive message
                            byteState = new KeyValuePair<List<byte>, StateObject>(null, new StateObject() { fifoCount = -1 });
                        }
                        break;

                    case PROCESS_STATE.UNPACK:
                        try
                        {
                            working_buffer = connectionDict[unpackConnectionNumber].Key;
                            workingBufferLen = working_buffer[2];
                            if ((working_buffer[0] != 0x78) && (working_buffer[1] != 0x78) && (working_buffer[workingBufferLen + 3] != 0x0D) && (working_buffer[workingBufferLen + 4] != 0x0A))
                            {



                                working_buffer.Clear();
                                return new KeyValuePair<List<byte>, StateObject>(new List<byte>(), null);
                            }
                            List<byte> packet = working_buffer.GetRange(0, workingBufferLen + 5);
                            working_buffer.RemoveRange(0, workingBufferLen + 5);
                            byteState = new KeyValuePair<List<byte>, StateObject>(packet, null);
                        }
                        catch(Exception ex)
                        {

                            int testPoint = 0;
                        }

                        break;
                }// end switch
            }

            return byteState;
        }

        static void Send(Socket handler, String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.
            handler.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback(SendCallback), handler);
        }
        static void Send(Socket socket, byte[] data)
        {
            // Convert the string data to byte data using ASCII encoding.
            // byte[] byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.
            socket.BeginSend(data, 0, data.Length, 0,
                new AsyncCallback(SendCallback), socket);
        }
        static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket handler = ar.AsyncState as Socket;

                // Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                // Console.WriteLine("Sent {0} bytes to client.", bytesSent);

            }
            catch (Exception e)
            {
                // Console.WriteLine(e.ToString());
                int myerror = -1;
            }
        }

        public static void AcceptCallback(IAsyncResult ar)
        {
            try
            {

                // Get the socket that handles the client request.
                // Retrieve the state object and the handler socket
                // from the asynchronous state object.

                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);

                // Create the state object.
                StateObject state = ReadWrite(PROCESS_STATE.ACCEPT, handler, ar, - 1).Value;

                handler.BeginReceive(state.buffer, 0, BUFFER_SIZE, 0,
                    new AsyncCallback(ReadCallback), state);

            }
            catch (Exception ex)
            {
                int myerror = -1;
            }
        }

        public static void ReadCallback(IAsyncResult ar)
        {
            try
            {
                StateObject state = ar.AsyncState as StateObject;
                Socket handler = state.workSocket;

                // Read data from the client socket. 
                KeyValuePair<List<byte>, StateObject> byteState = ReadWrite(PROCESS_STATE.READ, handler, ar, -1);

                if (byteState.Value != null)
                {
                    allDone.Set();
                    handler.BeginReceive(state.buffer, 0, BUFFER_SIZE, 0,
                        new AsyncCallback(ReadCallback), state);
                }
                else
                {
                    int testPoint = 0;
                }
            }
            catch (Exception ex)
            {
                int myerror = -1;
            }

            // Signal the main thread to continue.  
            allDone.Set();
        }
    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • GPS besides giving a Location gives accurate time info. It looks like both of your devices sent out a Status message at the same time, then didn't send any more location messages. So it looked like my code wasn't working. Eventually the 20 minute timeout occurred, the devices disconnected/reconnected, and every thing started working. It was the devices that stopped sending. – jdweng Jun 23 '17 at 13:48
  • you mean that if 2 devices send status at the same time both will stop sendind for 20 min that would be a serious problem i have 2 devices they are my test devices i will start with 500 device after a week thats means the situation of 2 devices sending status at the same time will have high probability you can imagine – Maher Khalil Jun 23 '17 at 14:50
  • No. I was describing the case we had when no response to the heartbeat was sent. It appears (not sure) that when you have 500 devices you will get all 500 heartbeats at same time. Manufacturer should of made the heartbeat occur at different times for each device. – jdweng Jun 23 '17 at 16:05
  • i hope you mean that i will not going to face the situation of status message whan i have large number of devices – Maher Khalil Jun 23 '17 at 16:43
  • How often the Status Message is sent is a parameter in the devices. These messages are probably sent periodically every 10 minutes from each device. I just mean the they will all come at the same time. I don't think it will cause an issue. – jdweng Jun 23 '17 at 17:09
  • Hi Sorry but i tried to fix it but did not succed when a status message come it hang i have attached image in the main post when that happens it does not go away it hangs the program the real problem is that it became constant i closed the program and re-open it the same sequence happens login the send the status then send and just stop – Maher Khalil Jun 28 '17 at 09:40
  • It is not hanging on the status message. Either the devices are not sending, or the code is hitting one of the exceptions. The best thing to do is to add break points in the code on the Catch blocks. When I wrote the code I didn't want to put write messages in code where it was going into a service. So we need to find out which exception it is getting. I suspect it is the intermittent error that I was seeing occasionally. – jdweng Jun 28 '17 at 11:05
  • You are getting a Power Cut Alarm. I think the device turned off. See page 23 of user manual. 5.3.1.4 = 0x04, bit 3 to 5 = 010 (binary). Charge is off and ACC is low. – jdweng Jun 28 '17 at 11:25
  • it can't be since it sends login and accepts the login response and some times it send few packages before the status appear – Maher Khalil Jun 28 '17 at 11:33
  • The must a wire that needs connecting on the device. See https://www.manualslib.com/manual/754200/Smart-Tracker-Gt06.html?page=7#manual – jdweng Jun 28 '17 at 11:41
  • i did not understand but if it is wiring problem it will not send location or even it will not send login it will not accept response – Maher Khalil Jun 28 '17 at 11:47
  • Not necessarily. If a wire is not connected it may be intermittent. What is the INFO when it is working. If it stops working only when you get the Power Cut Alarm then we know it must be the alarm. – jdweng Jun 28 '17 at 12:04
  • the senario open the program i get this message (status) wait about 10 minutes with no change close re-open the same happenes some times after 3-4 closes it start sending few location packets before it send the status then it hangs also if it is wire problem i can test another device ?? – Maher Khalil Jun 28 '17 at 12:08
  • Are software is a server.The server has to start before the device.So when you restart the server the device doesn't know there is a disconnect.So it eventually times out and then reconnects.That explains the the 10 minutes.Then it successfully logs in and sends location data. You have to look at the Serial Number Field which indicates the count of messages from the device.The failure you posted was at serial number 0x001B (27 decimal).So it looks like it is probably always failing at the first status message. I checked the message, the send message is good including CRC. Try another device. – jdweng Jun 28 '17 at 13:01
  • the server is 24 - 7 and it has other services running it might be the device but why some times it send ?? thanks – Maher Khalil Jun 28 '17 at 13:24
  • I only know what the flow chart says and the on-line manual. Every time you restart you server software the device has to reconnect. The only way it reconnects is after a time-out. Look at the flow chart. It could take 25 minutes before the device tries to reconnect after a heart beat is sent. And the heartbeat may only be sent every 5 minutes (not sure) so the time could be up to 30 minutes. The Comm wire isn't connected and the flow chart doesn't indicate what happens when errors occur. See on-line manual page 8 para 5.2. – jdweng Jun 28 '17 at 13:53
  • I updated code. I think we need to reset the cutoff alarm. So I added three things. 1) Process the string info command which is the response when the server sends the command to reset cutoff alarm. 2)Then when we get an info packet with cutoff alarm we send the command to turn back on. 3) Alarm Data Address message I was only sending one command back to device. So I modified code to send two commands. One is just a response and the 2nd is data. – jdweng Jun 29 '17 at 08:31
  • where is the definition of alarmDataAddressResponse ?? where is the definition of ALARM ALARM alarm = (ALARM)((info >> 3) & 0x07); where is the difinition of the ENUm Alarm case ALARM.POWER_CUT_ALARM: – Maher Khalil Jun 30 '17 at 16:25
  • Alarm data is message 0x16 (page 8) which is the 4th byte. If you go to bottom of page 37 it says "Process of Alarm Packet" (note 2nd message is 0x17 but should be 0x80). Then there is one transmission and two receptions where transmission is from device to server. So the message from device is shown in 5.3.1 (page 16). First response is shown in 5.3.2 (page 19-20). The second message from Server to Terminal is 6.1 (page 26). And response is 6.2 (string info page 27). Took me a lot of reading to figure all this out. Not very clear. Could of made a mistake. Could be a typo in manual. – jdweng Jun 30 '17 at 16:48
  • i ment in the code there is no decleration for these variables alarmDataAddressResponse[2] = (byte)(alarmDataAddressPacketLen & 0xFF); – Maher Khalil Jun 30 '17 at 16:51
  • Dear jdweng, I have implemented the ET300 GPS tracking communication protocol by refering the code which you have suggested in the Answer of this post. ET300 and CONCOX are almost same in protocol implementation. During the tesing of application, i got the login packet, location and status info data but i didn't get the alarm data. When the alarm data received by Server from terminal? Will it be receive when something is happen in device? For example. if ignition will be changed from Off to On at that time alarm data received by Server. Please confirm? – Prem Nov 30 '18 at 04:24
  • 1
    When I generated code I only did simulations. The OP did actual testing of the device. It was a while ago when I generated the code. I believe the OP did some test and I went back and I made changes to the Alarm code to work. It looks like the code is automatically resetting the alarms (see case ALARM.POWER_CUT_ALARM:). I think is real world you do not want to send the reset automatically. – jdweng Nov 30 '18 at 11:21
  • @jdweng Can you help me with parser library in nodejs..? – Suraj Bhatt May 25 '23 at 22:07
  • @SurajBhatt : I don't know Java. – jdweng May 26 '23 at 08:48
  • @jdweng i am not looking in Java.. it's in javascript. Btw if anyone looking in nodejs i got one parser library and here is link. https://github.com/vondraussen/gt06 – Suraj Bhatt May 28 '23 at 17:31
  • In my code I received connections from many devices so I have an async TCP listener and as I receive each request I take the data and put into a FIFO. Then in another thread I read the FIFO, parse the data, and send a response. You have to make sure you process each request before the device sends a second request. You also have to keep track which socket each request arrived so you can send the response back on same connection. For testing, I created a device simulator to send messages. – jdweng May 28 '23 at 20:42
3

Here is the modified code Section 1 :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Data;
using System.Data.SqlClient;
using System.ComponentModel;
using System.Timers;

namespace ConcoxServer
{
    public class StateObject
    {
        public long connectionNumber = -1;
        public Socket workSocket { get; set; }
        public byte[] buffer { get; set; }
        public int fifoCount { get; set;}
        public string IMEI { get; set; }
    }

    public enum PROTOCOL_NUMBER
    {
        LOGIN_MESSAGE = 0x01,
        LOCATION_DATA = 0x12,
        STATUS_INFO = 0X13,
        STRING_INFO = 0X15,
        ALARM_DATA = 0X16,
        GPS_QUERY_ADDR_PHONE_NUM = 0X1A,
        COMMAND_INFO = 0X80,
        NONE
    }
    public enum UNPACK_STATUS
    {
        ERROR,
        NOT_ENOUGH_BYTES,
        BAD_CRC,
        GOOD_MESSAGE,
        DEFAULT
    }
    public enum PROCESS_STATE
    {
        ACCEPT,
        READ,
        PROCESS,
        UNPACK
    }
    public enum ALARM : Byte
    {
        NORMAL = 0,
        SHOCK_ALARM = 1,
        POWER_CUT_ALARM = 2,
        LOW_BATTERY = 3,
        SOS = 4
    }

    class Program
    {
        const string IP = "127.0.0.1";
        const int PORT = 8841;
        const Boolean test = true;

        static void Main(string[] args)
        {

            GPS gps = new GPS(IP, PORT, test);

            Console.WriteLine("Connection Ended");

        }
    }
    public class GPS
    {
        const int BUFFER_SIZE = 1024;
        const string CONNECT_STRING = @"Data Source=.\SQLEXPRESS;Initial Catalog=GPSTracker;Integrated Security=SSPI;";
        const string LOGIN_INSERT_COMMMAND_TEXT = "use GPSTracker INSERT INTO Login (TerminalID,Date) VALUES(@TerminalID,@Date)";
        const string LOCATION_INSERT_COMMMAND_TEXT = "INSERT INTO T_Tracking (IMEI,TrackTime, CurrTime, Longitude, Lattitude,speed)" +
            "VALUES (@IMEI, @TrackTime, @CurrTime, @Longitude, @Lattitude, @speed)";
        static SqlConnection conn = null;
        static SqlCommand cmdLogin = null;
        static SqlCommand cmdLocation = null;

        static byte[] loginResponse = { 0x78, 0x78, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0A };
        static byte[] alarmResponse = { 0x78, 0x78, 0x05, 0x16, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0A };
        static byte[] alarmDataAddressResponse = { 0x78, 0x78, 0x00, 0x97, 0x7E,
                                          0x00, 0x00, 0x00, 0x01,
                                          0x41, 0x4C, 0x41, 0x52, 0x4D, 0x53, 0x4D, 0x53,   //ALARMS
                                          0x26, 0x26,                                       //&&
                                          0x80, 0x00, 0x72, 0x00, 0x79, 0x00, 0x78, 0x00,   // PHONE HOME
                                          0x69, 0x00, 0x32, 0x00, 0x72, 0x00, 0x79, 0x00,
                                          0x77, 0x00, 0x69,
                                          0x26, 0x26,                                       //&&
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // Phone Numbe
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x23, 0x23,                                       //##
                                          0x00, 0x00,                                       //serial number
                                          0x00, 0x00,                                       //check bytes
                                          0x0D, 0x0A                                        //stop bytes
                                      };
        static byte[] heartbeatResponse = { 0x78, 0x78, 0x05, 0x13, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0A };
        static byte[] connectOilAndEletricity = {
                                          0x78, 0x78, 0x16, 0x80, 0x10, 0x12, 0x34, 0x56, 0x78, 0x48,  //server flag bit 0x12345678
                                          0x46, 0x59, 0x44, 0x2C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
                                          0x23, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0A
                                     }; 

        static long connectionNumber = 0;
        //mapping of connection number to StateObject
        static Dictionary<long, KeyValuePair<List<byte>, StateObject>> connectionDict = new Dictionary<long, KeyValuePair<List<byte>, StateObject>>();
        //fifo contains list of connections number wait with receive data
        public static List<long> fifo = new List<long>();

        public static AutoResetEvent allDone = new AutoResetEvent(false);
        public static AutoResetEvent acceptDone = new AutoResetEvent(false);

        public GPS(string IP, int port, Boolean test)
        {
            try
            {
                conn = new SqlConnection(CONNECT_STRING);
                conn.Open();

                cmdLogin = new SqlCommand(LOGIN_INSERT_COMMMAND_TEXT, conn);
                cmdLogin.Parameters.Add("@TerminalID", SqlDbType.NVarChar, 8);
                cmdLogin.Parameters.Add("@Date", SqlDbType.DateTime);

                cmdLocation = new SqlCommand(LOCATION_INSERT_COMMMAND_TEXT, conn);
                cmdLocation.Parameters.Add("@IMEI", SqlDbType.NVarChar, 50);
                cmdLocation.Parameters.Add("@TrackTime", SqlDbType.DateTime);
                cmdLocation.Parameters.Add("@currTime", SqlDbType.DateTime);
                cmdLocation.Parameters.Add("@Longitude", SqlDbType.NChar, 50);
                cmdLocation.Parameters.Add("@Lattitude", SqlDbType.NVarChar, 50);
                cmdLocation.Parameters.Add("@speed", SqlDbType.Float);

            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : '{0}'", ex.Message);
                //Console.ReadLine();
                return;
            }

            try
            {
                //initialize the timer for writing to database.
                WriteDBAsync.WriteDatabase();
                StartListening(IP, port, test);

                // Open 2nd listener to simulate two devices, Only for testing
                //StartListening(IP, port + 1, test);

                ProcessMessages();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : '{0}'", ex.Message);
                //Console.ReadLine();
                return;
            }
        }
        public enum DATABASE_MESSAGE_TYPE
        {
            LOGIN,
            LOCATION
        }
        public class WriteDBMessage
        {
            public DATABASE_MESSAGE_TYPE message { get; set; }
        }
        public class WriteDBMessageLogin : WriteDBMessage
        {
            public DateTime date { get; set; }
            public string IMEI { get; set; }
        }
        public class WriteDBMessageLocation : WriteDBMessage 
        {
            public string IMEI { get; set; }
            public DateTime trackTime { get; set; }
            public DateTime currTime { get; set; }
            public byte[] longitude { get; set; }
            public byte[] lattitude { get; set; }
            public float speed { get; set; }
            public byte[] courseStatus { get; set; }
        }

        public static class WriteDBAsync
        {
            public enum Mode
            {
                READ,
                WRITE
            }
            public static List<WriteDBMessage> fifo = new List<WriteDBMessage>();
            public static System.Timers.Timer timer = null;

            public static void WriteDatabase()
            {
                timer = new System.Timers.Timer(1000);
                timer.Elapsed += Timer_Elapsed;
                timer.Start();
            }
            public static WriteDBMessage ReadWriteFifo(Mode mode, WriteDBMessage message)
            {
                Object thisLock2 = new Object();

                lock (thisLock2)
                {
                    switch (mode)
                    {
                        case Mode.READ:
                            if(fifo.Count > 0)
                            {
                                message = fifo[0];
                                fifo.RemoveAt(0);
                            }
                            break;
                        case Mode.WRITE:
                            fifo.Add(message);
                            break;
                    }

                }
                return message;
            }
            static void Timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                timer.Enabled = false;
                WriteDBMessage row = null;
                int rowsAdded = 0;
                uint number = 0;
                double lat = 0;
                string latStr = "";
                double lon = 0;
                string longStr = "";
                int degrees = 0;
                double minutes = 0;
                try
                {

                    while((row = ReadWriteFifo(Mode.READ, null)) != null)
                    {
                        switch(row.message)
                        {
                            case DATABASE_MESSAGE_TYPE.LOGIN:
                                cmdLogin.Parameters["@TerminalID"].Value = ((WriteDBMessageLogin)row).IMEI;
                                cmdLogin.Parameters["@Date"].Value = ((WriteDBMessageLogin)row).date;
                                rowsAdded = cmdLogin.ExecuteNonQuery();
                                break;
                            case DATABASE_MESSAGE_TYPE.LOCATION:
                                cmdLocation.Parameters["@IMEI"].Value = ((WriteDBMessageLocation)row).IMEI;
                                cmdLocation.Parameters["@TrackTime"].Value = ((WriteDBMessageLocation)row).trackTime;
                                cmdLocation.Parameters["@currTime"].Value = ((WriteDBMessageLocation)row).currTime;

                                number = BitConverter.ToUInt32(((WriteDBMessageLocation)row).longitude.Reverse().ToArray(), 0);
                                lon = (180 * number) / 324000000.0;

                                degrees = (int)lon;
                                minutes = 60 * (lon - degrees);
                                longStr = string.Format("{0}º{1}{2}", degrees, minutes, (((WriteDBMessageLocation)row).courseStatus[0] & 0x08) == 0 ? "E" : "W");

                                cmdLocation.Parameters["@Longitude"].Value = longStr;

                                number = BitConverter.ToUInt32(((WriteDBMessageLocation)row).lattitude.Reverse().ToArray(), 0);
                                lat = (90 * number) / 162000000.0;

                                degrees = (int)lat;
                                minutes = 60 * (lat - degrees);
                                latStr = string.Format("{0}º{1}{2}", degrees, minutes, (((WriteDBMessageLocation)row).courseStatus[0] & 0x04) == 0 ? "S" : "N");

                                cmdLocation.Parameters["@Lattitude"].Value = latStr;
                                cmdLocation.Parameters["@speed"].Value = ((WriteDBMessageLocation)row).speed;
                                rowsAdded = cmdLocation.ExecuteNonQuery();
                                break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    //Console.WriteLine("Error : '{0}'", ex.Message);
                }
                timer.Enabled = true;
            }
        }

        public void StartListening(string IP, int port, Boolean test)
        {
            try
            {
                // Establish the local endpoint for the socket.
                // The DNS name of the computer
                // running the listener is "host.contoso.com".
                IPHostEntry ipHostInfo = Dns.GetHostEntry(IP);  //Dns.Resolve(Dns.GetHostName());
                IPAddress ipAddress = ipHostInfo.AddressList[0];
                //IPAddress local = IPAddress.Parse(IP);

                IPEndPoint localEndPoint = null;
                if (test)
                {
                    localEndPoint = new IPEndPoint(IPAddress.Any, port);
                }
                else
                {
                    localEndPoint = new IPEndPoint(ipAddress, port);
                }

                // Create a TCP/IP socket.
                Socket listener = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream, ProtocolType.Tcp);
                // Bind the socket to the local endpoint and listen for incoming connections.


                allDone.Reset();
                acceptDone.Reset();
                listener.Bind(localEndPoint);
                listener.Listen(100);

                //login code, wait for 1st message
                Console.WriteLine("Wait 5 seconds for login message");

                listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
jdweng
  • 33,250
  • 2
  • 15
  • 20