c# - Comunicación de zócalo GPS(CONCOX)
sockets (4)
1 ] 1 Tengo un dispositivo GPS que debe enviar datos GPRMC pero requiere un paquete de inicio de sesión Revise la hoja de datos Hoja de datos del dispositivo
puedo recibir el inicio de sesión 787811010 XXX739050313XXX 20200001000E0EAD0D0A
IMEI Sart With XXX
el paquete es diferente de la imagen de ejemplo
Tengo 2 preguntas 1: de acuerdo con los datos recibidos y el ejemplo, ¿qué debo enviar? 2- cómo calcular la comprobación de errores Gracias
Editar
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);
// }
}
}
}
Hoja de datos del proveedor
4.6. Verificación de errores El terminal o el servidor pueden usar un código de verificación para distinguir si la información recibida es un error o no. Para evitar que ocurran errores durante la transmisión de datos, se agrega una verificación de errores contra el mal funcionamiento de los datos, a fin de aumentar la seguridad y la eficiencia del sistema. El código de verificación es generado por el método de verificación CRC-ITU. Los códigos de verificación de datos en la estructura del protocolo, desde la Longitud del paquete hasta el Número de serie de la información (incluyendo "Longitud del paquete" y "Número de serie de la información"), son valores de CRC-ITU. Se produce un error CRC cuando se calcula la información recibida, el receptor ignorará y descartará el paquete de datos. 4 4
Tabla de base de datos
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
Tu código
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;
Aquí está el código modificado Sección 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);
}
}
Aquí está mi cliente de prueba con 5 mensajes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Globalization;
using System.Threading;
namespace ConcoxClient
{
class Program
{
const int PORT = 8841;
static void Main(string[] args)
{
string IP = "x.x.x.x";
string loginMessage1 = "7878110103587390503134452020000100196A930D0A";
string locationDataMessage1 = "78781F120B081D112E10CF027AC7EB0C46584900148F01CC00287D001FB8000380810D0A";
string alarmmMessage1 = "787825160B0B0F0E241DCF027AC8870C4657E60014020901CC00287D001F726506040101003656A40D0A";
string heartMessage1 = "78780A134401040001000508450D0A";
string heartPowerCutAlarmMessage1 = "78780A131001040001000515FC0D0A";
string connectOilMessage1 = "78781915110001A963484659443D53756363657373210002001EF8930D0A";
string[] messages1 = { loginMessage1, locationDataMessage1, alarmmMessage1, heartMessage1, heartPowerCutAlarmMessage1, connectOilMessage1 };
string loginMessage2 = "787811010358739050313446202000010091CABD0D0A";
string locationDataMessage2 = "78781F12110612112E10CF027AC7EB0C46584900148F01CC00287D001FB800039AA10D0A";
string alarmmMessage2 = "787825161106180E241DCF027AC8870C4657E60014020901CC00287D001F726506040101003606FD0D0A";
string[] messages2 = { loginMessage2, locationDataMessage2, alarmmMessage2 };
IPHostEntry ipHostInfo = Dns.GetHostEntry(IP); //Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPAddress local = IPAddress.Parse(IP);
TcpClient client1 = new TcpClient();
client1.Connect(IP, PORT);
//TcpClient client2 = new TcpClient();
//client2.Connect(IP, PORT + 1);
while (true)
{
foreach (string message in messages1)
{
byte[] messageBytes = new byte[message.Length / 2];
for (int i = 0; i < message.Length; i += 2)
{
messageBytes[i / 2] = byte.Parse(message.Substring(i, 2), NumberStyles.HexNumber);
}
client1.Client.Send(messageBytes);
//System.Threading.Thread.Sleep(1000);
}
foreach (string message in messages2)
{
byte[] messageBytes = new byte[message.Length / 2];
for (int i = 0; i < message.Length; i += 2)
{
messageBytes[i / 2] = byte.Parse(message.Substring(i, 2), NumberStyles.HexNumber);
}
//client2.Client.Send(messageBytes);
//System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Hit return to send another message");
Console.ReadLine();
}
}
}
}
Aquí está la sección 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();
}
}
}
Prueba el código a continuación.
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 class StateObjectDB
{
public string terminalID { get; set; }
public DateTime date { 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
}
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)";
static SqlConnection conn = null;
static SqlCommand cmd = null;
static byte[] loginResponse = { 0x78, 0x78, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0A };
static byte[] alarmResponse = { 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 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();
cmd = new SqlCommand(LOGIN_INSERT_COMMMAND_TEXT, conn);
cmd.Parameters.Add("@TerminalID", SqlDbType.NVarChar, 8);
cmd.Parameters.Add("@Date", SqlDbType.DateTime);
}
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 static class WriteDBAsync
{
public enum Mode
{
READ,
WRITE
}
public static List<List<object>> fifo = new List<List<object>>();
public static System.Timers.Timer timer = null;
public static void WriteDatabase()
{
timer = new System.Timers.Timer(100);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
public static List<object> ReadWriteFifo(Mode mode, StateObjectDB stateObjectDB)
{
List<object> row = null;
Object thisLock2 = new Object();
lock (thisLock2)
{
switch (mode)
{
case Mode.READ:
if (fifo.Count > 0)
{
row = fifo[0];
fifo.RemoveAt(0);
}
break;
case Mode.WRITE:
row = new List<object>() { stateObjectDB.terminalID, stateObjectDB.date };
fifo.Add(row);
break;
}
}
return row;
}
static void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Enabled = false;
List<object> row = null;
try
{
while ((row = ReadWriteFifo(Mode.READ, null)) != null)
{
cmd.Parameters["@TerminalID"].Value = row[0];
cmd.Parameters["@Date"].Value = row[1];
int rowsAdded = cmd.ExecuteNonQuery();
}
}
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);
}
}
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;
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 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);
StateObjectDB stateObjectDB = new StateObjectDB() { terminalID = terminalID, date = DateTime.Now };
WriteDBAsync.ReadWriteFifo(WriteDBAsync.Mode.WRITE, stateObjectDB);
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);
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:
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 packetLen = alarmResponse.Length - 5;
alarmResponse[2] = (byte)(packetLen & 0xFF);
serialNumber.CopyTo(alarmResponse, packetLen - 1);
sendCRC = crc_bytes(alarmResponse.Skip(2).Take(packetLen - 1).ToArray());
alarmResponse[packetLen + 1] = (byte)((sendCRC >> 8) & 0xFF);
alarmResponse[packetLen + 2] = (byte)((sendCRC) & 0xFF);
Console.WriteLine("Send Message : ''{0}''", BytesToString(alarmResponse));
Send(state.workSocket, alarmResponse);
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();
}
}
}