Bluetooth printing in Xamarin - c#

I've a Bluetooth thermal printer and i am trying to send a print command using Xamarin.
I've tried the following code
BluetoothSocket socket = null;
BufferedReader inReader = null;
BufferedWriter outReader = null;
BluetoothDevice device = (from bd in BluetoothAdapter.DefaultAdapter?.BondedDevices
where bd?.Name == deviceName
select bd).FirstOrDefault();
//BluetoothDevice hxm = BluetoothAdapter.DefaultAdapter.GetRemoteDevice (bt_printer);
UUID applicationUUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
socket = device.CreateRfcommSocketToServiceRecord(applicationUUID);
socket.Connect();
inReader = new BufferedReader(new InputStreamReader(socket.InputStream));
outReader = new BufferedWriter(new OutputStreamWriter(socket.OutputStream));
outReader.Write("hhhh");
outReader.Flush();
Thread.Sleep(5 * 1000);
var s = inReader.Ready();
inReader.Skip(0);
//close all
inReader.Close();
socket.Close();
outReader.Close();
The screen on the printer shows 'Working' and then back to ready and nothing gets printed out.
As you see i am trying to print the text 'hhhh' do i have to append anything extra for the message.
The printer is an RD-G80 Radall thermal printer.
Hope you can help I've been trying for a week now.
Thanks

I used something like the code below to send the cod to a Zebra
Mobile Printer on a application that i worked some time ago.
Its important to point that u have to know the right code pattern to send to the printer. Usually they have a documentation about it.
In the> application, i send the product code to our backend-end and it
retrieves and build the code pattern that i needed to send from my
mobile application to the printer.
Code below. hope this helps you:
**
private enum msgRet
{
conectionERROR,
sendERROR,
sucess
}
public int Print(string codToSend, string Print)
{
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.DefaultAdapter;
BluetoothSocket btSocket = null;
UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
BluetoothDevice device = null;
Stream outStream = null;
int ret = -1;
try
{
MessagingCenter.Send(this, "Print");
var MacAdress = mBluetoothAdapter.BondedDevices.ToList().Find(x => x.Name == Print).Address;
if(string.IsNullOrEmpty(MacAdress))
return ret = (int)msgRet.sendERROR;
if (!mBluetoothAdapter.IsEnabled)
{
BluetoothAdapter mBluetoothAdapter =
BluetoothAdapter.DefaultAdapter;
if(!mBluetoothAdapter.IsEnabled)
{
mBluetoothAdapter.Enable();
}
}
device = mBluetoothAdapter.GetRemoteDevice(MacAdress);
btSocket = device.CreateInsecureRfcommSocketToServiceRecord(MY_UUID);
if (!btSocket.IsConnected)
{
btSocket.Connect();
}
if (btSocket.IsConnected)
{
Thread.Sleep(200);
try
{
byte[] msgBuffer = Encoding.ASCII.GetBytes(codToSend);
outStream = btSocket.OutputStream;
outStream.Write(msgBuffer, 0, msgBuffer.Length);
}
catch (Exception e)
{
Debug.WriteLine("sendERROR" + e.Message);
ret = (int)msgRet.sendERROR;
}
}
} catch (Exception ex) {
Debug.WriteLine("conectionERROR:" + ex.Message);
ret = (int)msgRet.conectionERROR;
}
finally
{
if (outStream != null) { outStream.Close(); outStream.Dispose();}
mBluetoothAdapter.Dispose();
if (btSocket!=null) { btSocket.Close(); btSocket.Dispose(); }
}
if (ret == -1) { ret = (int)msgRet.sucess; }
return ret;
}

Related

how to implement retry mechanism when I got gsm modem Exception: No data received from phone?

public class GSMModemConnection
{
I made a windows service for receiving SMS I'm using Wavecom Gsm modem 1306B. But after some second I got an
Exception: No data received from phone. I have searched in StackOverflow I found this link Exception: No data received from phone
someone pointed about to create a retry mechanism but I don't know how to implement it.
static void Main(string[] args)
{
GSMModemConnection gsm = new GSMModemConnection();
var result = gsm.OpenPort();
Console.WriteLine(result.PortName);
while (true)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
ShortMessage execResult = gsm.ReadSMS(result, "AT+CMGL=\"ALL\"");
Console.WriteLine(execResult.Message);
Console.WriteLine(execResult.Status);
}
}
public class GSMModemConnection
{
public AutoResetEvent receiveNow;
//string strPortName, string strBaudRate
public SerialPort OpenPort()
{
receiveNow = new AutoResetEvent(false);
SerialPort port = new SerialPort();
port.PortName = "COM3";
port.BaudRate = 115200 /*Convert.ToInt32(strBaudRate)*/; //updated by Anila (9600)
port.DataBits = 8;
port.StopBits = StopBits.One;
port.Parity = Parity.None;
port.ReadTimeout = 300;
port.WriteTimeout = 300;
port.Encoding = Encoding.GetEncoding("iso-8859-1");
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
port.DtrEnable = true;
port.RtsEnable = true;
return port;
}
//Close Port
public void ClosePort(SerialPort port)
{
port.Close();
port.DataReceived -= new SerialDataReceivedEventHandler(port_DataReceived);
port = null;
}
//Execute AT Command
public string ExecCommand(SerialPort port, string command, int responseTimeout, string errorMessage)
{
try
{
//receiveNow = new AutoResetEvent();
port.DiscardOutBuffer();
port.DiscardInBuffer();
receiveNow.Reset();
port.Write(command + "\r");
//Thread.Sleep(3000); //3 seconds
string input = ReadResponse(port, responseTimeout);
if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
throw new ApplicationException("No success message was received.");
return input;
}
catch (Exception ex)
{
throw new ApplicationException(errorMessage, ex);
}
}
//Receive data from port
public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (e.EventType == SerialData.Chars)
receiveNow.Set();
}
public string ReadResponse(SerialPort port, int timeout)
{
string buffer = string.Empty;
do
{
if (receiveNow.WaitOne(timeout, false))
{
string t = port.ReadExisting();
buffer += t;
}
else
{
if (buffer.Length > 0)
throw new ApplicationException("Response received is incomplete.");
else
throw new ApplicationException("No data received from phone.");
}
}
while (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\n> ") && !buffer.EndsWith("\r\nERROR\r\n"));
return buffer;
}
public ShortMessage ReadSMS(SerialPort port, string p_strCommand)
{
// Set up the phone and read the messages
ShortMessage messages = null;
try
{
#region Execute Command
// Check connection
var a = ExecCommand(port, "AT", 300, "No phone connected");
// Use message format "Text mode"
var b = ExecCommand(port, "AT+CMGF=1\r", 300, "Failed to set message format.");
// Use character set "PCCP437"
//var c = ExecCommand(port, "AT+CSCS=\"PCCP437\"", 300, "Failed to set character set.");
// Select SIM storage
//var d = ExecCommand(port, "AT+CPMS=\"SM\"", 300, "Failed to select message storage.");
// Read the messages
string input = ExecCommand(port, p_strCommand, 5000, "Failed to read the messages.");
#endregion
#region Parse messages
messages = ParseMessages(input);
#endregion
}
catch (Exception ex)
{
throw ex;
}
if (messages != null)
return messages;
else
return null;
}
public ShortMessage ParseMessages(string input)
{
ShortMessage msg = new ShortMessage();
//ShortMessageCollection messages = new ShortMessageCollection();
try
{
Regex r = new Regex(#"\+CMGL: (\d+),""(.+)"",""(.+)"",(.*),""(.+)""\r\n(.+)\r\n");
Match m = r.Match(input);
while (m.Success)
{
//msg.Index = int.Parse(m.Groups[1].Value);
msg.Index = int.Parse(m.Groups[1].Value);
msg.Status = m.Groups[2].Value;
msg.Sender = m.Groups[3].Value;
msg.Alphabet = m.Groups[4].Value;
msg.Sent = m.Groups[5].Value;
msg.Message = m.Groups[6].Value;
//messages.Add(msg);
m = m.NextMatch();
}
}
catch (Exception ex)
{
throw ex;
}
return msg;
}
}
You DO have a retry mechanism in place with the DO-WHILE loop from the following expression:
public string ReadResponse(SerialPort port, int timeout)
{
string buffer = string.Empty;
do
{
if (receiveNow.WaitOne(timeout, false))
{
string t = port.ReadExisting();
buffer += t;
}
else
{
if (buffer.Length > 0)
throw new ApplicationException("Response received is incomplete.");
else
throw new ApplicationException("No data received from phone.");
}
}
while (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\n> ") && !buffer.EndsWith("\r\nERROR\r\n"));
return buffer;
}
What you can do is reduce the granularity of the error report mechanism.
In this case, for example, the line throw new ApplicationException() will break the loop and get captured in the Exec() function, then thrown again. If you just want to wait for the loop to close and the DO-WHILE loop to get executed, I would replace the following part of the code:
else
{
if (buffer.Length > 0)
throw new ApplicationException("Response received is incomplete.");
else
throw new ApplicationException("No data received from phone.");
}
With:
else
{
if (buffer.Length > 0)
bufferError += "Response received is incomplete.\n";
else
bufferError += "No data received from phone.\n";
}
Why?
After the DO-WHILE loop, the buffer will either return string.Empty or some value.
Up in the code, you have:
string input = ReadResponse(port, responseTimeout);
if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
throw new ApplicationException("No success message was received.");
return input;
Basically, if the returned buffer is string.Empty an Exception will be thrown again.
By returning the buffer Error, you can decide later how you want to handle it but the DO-WHILE loop will run at least once up until the condition from the WHILE expression is met.
Rest of the code should look like this:
//Thread.Sleep(3000); //3 seconds
string bufferErrors = string.Empty;
string input = ReadResponse(port, responseTimeout, bufferErrors);
if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
throw new ApplicationException("No success message was received.");
if (!string.IsNullOrWhiteSpace(bufferErrors))
{
//Handle bufferErrors
}
return input;
Remember to declare the out parameter in ReadResponse
public string ReadResponse(SerialPort port, int timeout, out string bufferError)
{
string buffer = string.Empty;
bufferError = string.Empty;

Get the live data on TCP server from UWP (UPDATED)

Below is one method that basically sends the data to TCP Server.
UPDATE BEGINS HERE:
//////////////////////////////////
private string FormatValueByPresentation(IBuffer buffer, GattPresentationFormat format)
{
// BT_Code: For the purpose of this sample, this function converts only UInt32 and
// UTF-8 buffers to readable text. It can be extended to support other formats if your app needs them.
byte[] data;
CryptographicBuffer.CopyToByteArray(buffer, out data);
if (format != null)
{
if (format.FormatType == GattPresentationFormatTypes.UInt32 && data.Length >= 4)
{
return BitConverter.ToInt32(data, 0).ToString();
}
else if (format.FormatType == GattPresentationFormatTypes.Utf8)
{
try
{
return Encoding.UTF8.GetString(data);
}
catch (ArgumentException)
{
return "(error: Invalid UTF-8 string)";
}
}
else
{
// Add support for other format types as needed.
return "Unsupported format: " + CryptographicBuffer.EncodeToHexString(buffer);
}
}
else if (data != null)
{
// We don't know what format to use. Let's try some well-known profiles, or default back to UTF-8.
if (selectedCharacteristic.Uuid.Equals(GattCharacteristicUuids.HeartRateMeasurement))
{
try
{
///////LOOK HERE/////
**string b = ParseHeartRateValue(data).ToString();
TrySend(b);
//return "Heart Rate: " + ParseHeartRateValue(data).ToString();
return "Heart Rate: " + b;**
}
catch (ArgumentException)
{
return "Heart Rate: (unable to parse)";
}
}
else if (selectedCharacteristic.Uuid.Equals(GattCharacteristicUuids.BatteryLevel))
{
try
{
// battery level is encoded as a percentage value in the first byte according to
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.battery_level.xml
return "Battery Level: " + data[0].ToString() + "%";
}
catch (ArgumentException)
{
return "Battery Level: (unable to parse)";
}
}
// This is our custom calc service Result UUID. Format it like an Int
else if (selectedCharacteristic.Uuid.Equals(Constants.ResultCharacteristicUuid))
{
return BitConverter.ToInt32(data, 0).ToString();
}
// No guarantees on if a characteristic is registered for notifications.
else if (registeredCharacteristic != null)
{
// This is our custom calc service Result UUID. Format it like an Int
if (registeredCharacteristic.Uuid.Equals(Constants.ResultCharacteristicUuid))
{
return BitConverter.ToInt32(data, 0).ToString();
}
}
else
{
try
{
return "Unknown format: " + Encoding.UTF8.GetString(data);
}
catch (ArgumentException)
{
return "Unknown format";
}
}
}
else
{
return "Empty data received";
}
return "Unknown format";
}
///////// END OF UPDATE //////
private async void TrySend(string data)
{
// Create the StreamSocket and establish a connection to the echo server.
StreamSocket socket = new StreamSocket();
try
{
var streamSocket = new Windows.Networking.Sockets.StreamSocket();
{
//The server hostname that we will be establishing a connection to. In this example, the server and client are in the same process.
var hostName = new Windows.Networking.HostName("127.0.0.1");
await streamSocket.ConnectAsync((new Windows.Networking.HostName("127.0.0.1")), "9999");
// Send a request to the echo server.
using (Stream outputStream = streamSocket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
while (true)
{
await streamWriter.WriteLineAsync(data);
await streamWriter.FlushAsync();
}
//await streamWriter.WriteLineAsync(data);
//await streamWriter.FlushAsync();
}
}
}
}
catch (Exception)
{
}
}
And here is my TCP Server code that receives the data:
public class EchoServer {
public static void Main() {
TcpListener listener = null;
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9999);
listener.Start();
Console.WriteLine("TCP Server Has Started....");
while (true)
{
Console.WriteLine(" ");
Console.WriteLine("Waiting for incoming client connections....");
Console.WriteLine(" ");
Console.WriteLine("A message will display below once the client starts and establishes a connection ");
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine(" ");
Console.WriteLine("Okay, Accepting Client connection now");
Console.WriteLine(" ");
Console.WriteLine("Accepted new client connection.....");
StreamReader reader = new StreamReader(client.GetStream());
StreamWriter writer = new StreamWriter(client.GetStream());
string s = string.Empty;
while (!(s = reader.ReadLine()).Equals("Exit") || (s == null)) {
Console.WriteLine("From client -> " + s);
writer.WriteLine("From server -> " + s);
writer.Flush();
}
reader.Close();
writer.Close();
client.Close();
}
} catch (Exception e)
{
Console.WriteLine(e);
} finally
{
if (listener != null)
{
listener.Stop();
}
}
}
}
Now, the data I am trying to get are the heart rates and it changes every two seconds. However on TCP server I only get the first recorded value of a heart rate and it keeps repeating instead of getting new one.
There is a similar post I saw here on stackoverflow : UWP TCP receive data continuously
and someone suggested to use while loop which I did as you can see in the code.
Are there any other suggestions on what should I do?
Thanks
while (true)
{
await streamWriter.WriteLineAsync(data);
await streamWriter.FlushAsync();
}
The while(true) will keep repeating, meaning that it will always send 'data' at its current value. This is what causes your issue.
In my opinion, you should keep a connection to your TCP server open outside of your 'TrySend' method, and use this method only to send the data. This way you won't need to use this loop.
EDIT :
Try this :
private async void CharacteristicReadButton_Click()
{
while(true)
{
// BT_Code: Read the actual value from the device by using Uncached.
GattReadResult result = await selectedCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
if (result.Status == GattCommunicationStatus.Success)
{
string formattedResult = FormatValueByPresentation(result.Value, presentationFormat);
rootPage.NotifyUser($"Read result: {formattedResult}", NotifyType.StatusMessage);
//string formattedResult = FormatValueByPresentation(result.Value, presentationFormat);
//rootPage.NotifyUser($"Read result: {formattedResult}", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser($"Read failed: {result.Status}", NotifyType.ErrorMessage);
}
}
}

How to make sure I wont lose data from TCP?

I'm sorry if I'm asking something asked before.
I'm developing a program that reads data received via TCP and using a StreamReader, and I just can't find how to make sure that any data won't be missed. Is there any way to create a middle buffer to read from there or something like that?
Here are the methods I've created for receiving data and write it to a text box:
public static void Connect(string IP, string port)
{
try
{
client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse(IP), int.Parse(port));
client.Connect(IP_End);
if (client.Connected)
{
connected = "Connected to Exemys!" + "\r\n";
STR = new StreamReader(client.GetStream());
bgWorker = true;
}
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
-
public static void MessageReceiving(TextBox textBox)
{
try
{
string values =Conection.STR.ReadLine();
textBox.Invoke(new MethodInvoker(delegate () { textBox.AppendText("Exemys : " + values.Substring(2) + Environment.NewLine); }));
try
{
string messagetype = values.Substring(5, 1);
string ID = values.Substring(3, 2);
string checksum = values.Substring(values.Length - 2, 2);
if (checksum == CalcularChecksum(values.Substring(3, values.Length - 5)))
{
if (messagetype == "N")
{
if (ID == "01")
{
ID1 = values.Substring(3, 2);
messagetype1 = values.Substring(5, 1);
capacity1 = values.Substring(6, 1);
pressure1 = values.Split(',')[1];
sequencetime1 = values.Split(',')[2];
runstatus1 = values.Split(',')[3];
mode1 = values.Split(',')[4].Substring(0, 1);
checksum1 = CalcularChecksum(values.Substring(3, values.Length - 5));
}
if (ID == "02")
{
ID2 = values.Substring(3, 2);
messagetype2 = values.Substring(5, 1);
capacity2 = values.Substring(6, 1);
pressure2 = values.Split(',')[1];
sequencetime2 = values.Split(',')[2];
runstatus2 = values.Split(',')[3];
mode2 = values.Split(',')[4].Substring(0, 1);
checksum2 = CalcularChecksum(values.Substring(3, values.Length - 5));
}
}
}
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
catch (Exception)
{
MessageBox.Show("Client disconnected.");
}
}
Edit: what I'm trying to ask is how to always process the entire data before continue receiving? That would be the question.
A TCP stream is a stream of bytes that ends when the socket is closed by you or the remote peer or breaks because of network issues. In order to get everything from the stream you need to call the StreamReader.ReadLine method inside a loop into a buffer until some stop condition applies.
...
try
{
while(true)
{
...
input = STR.ReadLine();
if (input == <some stop condition>)
break;
...
}
}
...
That's a highly simplified example. TCP reading with partial buffer handling can be a complex beast so I recommend to use a library or framework if you're doing more than some hobby project.
Thanks for the response, but after searching, I've found what I was looking for. I wanted to store those messages (data) that were entering to make sure that I won't lose them (for any reason, more precisely that the receiving process would be faster than the message processing operation), so I used Queue to achieve this.
public static void RecepcionMensajes(TextBox textBox)
{
if (client.Connected == true)
{
try
{
string fifo = Conexion.STR.ReadLine();
Queue mensajes = new Queue();
//AquĆ­ se ponen en cola los mensajes que van llegando, utilizando el sistema FIFO.
mensajes.Enqueue(fifo);
string values = mensajes.Dequeue().ToString();
textBox.Invoke(new MethodInvoker(delegate () { textBox.AppendText("Exemys : " + values.Substring(2) + Environment.NewLine); }));

Bluetooth transmission

I'm trying to make an program that send a file to a mobile device encrypted, and the device will get it in another program and decrypt it.
So far I've done the bluetooth connection:
private void Connect()
{
using (SelectBluetoothDeviceDialog bldialog = new SelectBluetoothDeviceDialog())
{
bldialog.ShowAuthenticated = true;
bldialog.ShowRemembered = true;
bldialog.ShowUnknown = true;
if (bldialog.ShowDialog() == System.Windows.Forms.DialogResult.OK )
{
if (bldialog.SelectedDevice == null)
{
System.Windows.Forms.MessageBox.Show("No device selected", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
BluetoothDeviceInfo selecteddevice = bldialog.SelectedDevice;
BluetoothEndPoint remoteEndPoint = new BluetoothEndPoint(selecteddevice.DeviceAddress, BluetoothService.ObexFileTransfer);
client = new BluetoothClient();
client.Connect(remoteEndPoint);
session = new ObexClientSession(client.GetStream(), UInt16.MaxValue);
session.Connect(ObexConstant.Target.FolderBrowsing);
tbConnectionDet.Text = string.Format("Connected to: {0}", selecteddevice.DeviceName);
}
}
}
Also I'm sending the file this way:
private void UploadFiles(string[] files)
{
long size = 0;
List<string> filestoupload = new List<string>();
foreach (string filename in files)
{
if (File.Exists(filename))
{
FileInfo info = new FileInfo(filename);
filestoupload.Add(filename);
size += info.Length;
}
}
using (FileForm upform = new FileForm(new List<string>(filestoupload),
false, session, size, null))
{
upform.ExceptionMethod = ExceptionHandler;
upform.ShowDialog();
lsvExplorer.BeginUpdate();
for (int i = 0; i <= upform.FilesUploaded; i++)
{
ListViewItem temp = new ListViewItem(new string[]{ Path.GetFileName(filestoupload[i]),
FormatSize(new FileInfo(filestoupload[i]).Length, false)},
GetIconIndex(Path.GetExtension(filestoupload[i]), false));
temp.Tag = false;
lsvExplorer.Items.Add(temp);
}
lsvExplorer.EndUpdate();
}
}
I'm using 32feet and BrechamObex libraries .
I have the following questions :
I want to send a public key from my phone to my computer then encrypt a file and send it back to my phone. After I receive the file, I want to decrypt it so I will need another program in order to do this. How can I send information from one program to another using bluetooth?
Whenever I send a file, the phone gets it, but the size it always 0

Exception: Acess Violation in client C#

I am trying to learn C# through trials and errors. I have a server in Python, and the client in C#.
The client is supposed to get data from the server, save it to disk ((which it doesn't)), then continue using that data to communicate until the user decides to exit it.
Unfortunately, it has been raising an Exception Access Violation for quite some time, and provides no helpful information as to why.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Scripting.Hosting;
using System.Threading;
using Rage;
using System.Net.Sockets;
using System.IO;
[assembly: Rage.Attributes.Plugin("LSPDFROnlineClient", Description = "LSPDFR Online Client. Used to connect to LSPDFR Online.", Author = "Thecheater887")]
namespace LSPDFROnlineClient
{
public class EntryPoint
{
private static int IsDead;
public static void Main()
{
IsDead = 0;
Thread mt = new Thread(new ThreadStart(Run));
mt.Start();
while (true)
{
if (IsDead == 1)
{
break;
}
GameFiber.Yield();
}
return;
}
public static void Run()
{
File.WriteAllText("C:/ProgramData/dbg.log","1");
try
{
Byte[] header;
Byte[] packet;
Byte[] data;
Byte[] kad;
Byte[] td;
int paylen;
String rd;
String nd;
String msgid;
File.WriteAllText("C:/ProgramData/dbg.log", "2");
TcpClient connector = new TcpClient();
connector.Connect("127.0.0.1", 5773);
NetworkStream conn = connector.GetStream();
try {
File.WriteAllText("C:/ProgramData/dbg.log", "3");
FileStream savedat = File.OpenRead("C:/Users/Public/Documents/save.dat");
BinaryReader savdat = new BinaryReader(savedat);
nd = savdat.ReadString();
savdat.Close();
if (nd.Length == 16)
{
} else {
File.WriteAllText("C:/ProgramData/save.dat", "user000000000000");
nd = "user000000000000";
}
}
catch
{
File.WriteAllText("C:/ProgramData/save.dat", "user000000000000");
nd = "user000000000000";
}
File.WriteAllText("C:/ProgramData/dbg.log", "4");
data = new Byte[26];
data = Encoding.ASCII.GetBytes("clogr00000" + nd);
conn.Write(data, 0, data.Length);
while (true)
{
try
{
// Get header of packet
header = new Byte[26];
Int32 rcvhead = conn.Read(header, 0, header.Length);
String hd = Encoding.ASCII.GetString(header, 0, rcvhead);
//Deal with it 8-)
msgid = hd.Substring(0, 5);
paylen = Convert.ToInt32(hd.Substring(5, 5));
string servkey = hd.Substring(10, 16);
}
catch
{
continue;
}
File.WriteAllText("C:/ProgramData/dbg.log", "5");
try
{
//Receive packet data
if (paylen > 0)
{
packet = new Byte[paylen];
Int32 newdata = conn.Read(packet, 0, packet.Length);
rd = Encoding.ASCII.GetString(packet, 0, newdata);
}
else
{
rd = null;
}
File.WriteAllText("C:/ProgramData/dbg.log", "6");
if (msgid == "ConOK")
{
File.WriteAllText("C:/ProgramData/dbg.log", "7");
string userid = rd.Substring(0, 16);
Game.DisplayHelp(rd.Substring(16, (rd.Length - 16)));
File.WriteAllText("C:/ProgramData/save.dat", userid);
File.WriteAllText("C:/ProgramData/dbg.log", "8");
}
else if (msgid == "savdt")
{
File.WriteAllText("C:/ProgramData/dbg.log", "9");
string[] tnd = rd.Split(',');
var nud = new List<string>();
nud.Add("Player1");
nud.AddRange(tnd);
File.WriteAllText("C:/ProgramData/dbg.log", "A");
string name = nud[0];
string streetname = nud[1];
int money = Convert.ToInt32(nud[2]);
int bounty = Convert.ToInt32(nud[3]);
int playerrep = Convert.ToInt32(nud[4]);
File.WriteAllText("C:/ProgramData/dbg.log", "B");
int rep = Convert.ToInt32(nud[5]);
string pclass = nud[6];
bool canbecop = Convert.ToBoolean(nud[7]);
int rank = Convert.ToInt32(nud[8]);
int stars = Convert.ToInt32(nud[9]);
int cites = Convert.ToInt32(nud[10]);
File.WriteAllText("C:/ProgramData/dbg.log", "C");
int citesgiven = Convert.ToInt32(nud[11]);
int citesdismissed = Convert.ToInt32(nud[12]);
int arrestsmade = Convert.ToInt32(nud[13]);
int arrested = Convert.ToInt32(nud[14]);
int convictionsmade = Convert.ToInt32(nud[15]);
int convitced = Convert.ToInt32(nud[16]);
string warrant = nud[17];
File.WriteAllText("C:/ProgramData/dbg.log", "D");
int prisontimeremaining = Convert.ToInt32(nud[18]);
int copskilled = Convert.ToInt32(nud[19]);
int crimskilled = Convert.ToInt32(nud[20]);
int civskilled = Convert.ToInt32(nud[21]);
int bountyclaimed = Convert.ToInt32(nud[22]);
int overflowprep = Convert.ToInt32(nud[23]);
string title = nud[24];
bool banned = Convert.ToBoolean(nud[25]);
bool vip = Convert.ToBoolean(nud[26]);
int viprank = Convert.ToInt32(nud[27]);
File.WriteAllText("C:/ProgramData/dbg.log", "E");
var v3 = new Vector3();
float posx = Convert.ToSingle(nud[29]);
float posy = Convert.ToSingle(nud[30]);
float posz = Convert.ToSingle(nud[31]);
v3.X = posx;
v3.Y = posy;
v3.Z = posz;
File.WriteAllText("C:/ProgramData/dbg.log", "EE");
int rot = Convert.ToInt32(nud[32]);
File.WriteAllText("C:/ProgramData/dbg.log", "FF");
World.TeleportLocalPlayer(v3, false);
File.WriteAllText("C:/ProgramData/dbg.log", "F");
string custommessage = nud[28];
if (custommessage == "null")
{
} else {
Game.DisplayNotification(custommessage);
}
}
else if (msgid == "isalv")
{
kad = new Byte[26];
kad = Encoding.ASCII.GetBytes("yesil00000" + nd);
conn.Write(kad, 0, kad.Length);
}
else if (msgid == "pospk")
{
}
else
{
Game.DisplayNotification("Unknown packet recieved! ID: " + msgid);
}
//send end client turn
td = new Byte[26];
td = Encoding.ASCII.GetBytes("endmt00000" + nd);
conn.Write(td, 0,td.Length);
File.WriteAllText("C:/ProgramData/dbg.log", "0");
//
}
catch (Exception e)
{
Game.DisplayHelp(Convert.ToString(e));
Game.DisplayNotification("LSPDFR Online has crashed. Try reloading it maybe..?");
}
}
} catch (Exception e) {
Game.DisplayHelp(Convert.ToString(e));
Game.DisplayNotification("Connection interrupted! Reconnecting....");
IsDead = 1;
return;
}
}
}
}
The protocol goes as such;
Client -> Server: LoginRequest
Server -> Client: LoginOkay
Client -> Server: EndTurnMessage
Server -> Client: SaveDataMessage
Client -> Server: EndTurnMessage
Server -> Client: PositionUpdatePacket
Client -> Server: EndTurnMessage
Then continue routine, however, the server only receives one of these EndTurnMessage packets, which means it is choking on the save data portion, right?
Possibly, but that was working at an earlier time without flaw, and hasn't been modified since.
It is a class file, so it can't be debugged, and I've been tearing my hair out as to what is causing it.
Yes, it is crap-code, and needs rewritten at some point, I am aware, but I'd like it to work before I rewrite it entirely.
TL;DR: Why is this code raising an Access Violation? It's around the savdt sector or after.
UPDATE: I fixed the issue posted in the first answer, however, that didn't do much, so, as posted in both the answer and comments, it's rather difficult to debug with a program, so I'll try the old fashioned route of logging info every so many lines of code. I'll keep this updated.
UPDATE 2: I have figured out from the log debugging, that the line causing the error is World.TeleportLocalPlayer(v3, false);. Unfortunatley, World can't be inherited, and the documentation claims that Vector3 requires you to set it's internal values using get and set. I saw that on MSDN previously, but have no clue about how to search it, and there is nor get or set methods available within that Vector3 object.
You might have a stream that remained open, which prevents a new one to be created. If the msgid is "ConOK" you are creating a new instance without closing it after the write operation is done.
if (msgid == "ConOK"){
string userid = rd.Substring(0, 16);
Game.DisplayHelp(rd.Substring(16, (rd.Length - 16)));
FileStream savedat = File.OpenWrite(("C:/ProgramData/save.dat"));
BinaryWriter savdat = new BinaryWriter(savedat);
savdat.Write(userid);
// Close file stream here
}
But that's just a first guess. You can help us and yourself by making use of the debugger. The fact that your code is contained by a "class file" is no problem but a requirement.
Hava a look at this article for more information about debugging in the world of C#:
http://www.dotnetperls.com/debugging
At a first glance, you can have different class of bugs. Disregarding the logic flows and intended behaviour of the program, let's start with basic debugging.
at this step, don't use threads and fibers, from Main just call Run
there isn't strong input validation
use a lot more of try catch, isolating small pieces of code
in the catch, print ex.Message and ex.StackTrace
read carefully the docs about the methods you call and their possible exceptions
it is weird you write a file inside a exception (catch)
possible race conditions on global variables?
inside Run to set IsDead use Interlocked.Increment
https://msdn.microsoft.com/en-us/library/dd78zt0c(v=vs.110).aspx
...
remove the unused ( I think like Microsoft.Scripting.Hosting ), it only confuse-a-cat

Categories

Resources