Unity crashes at Get- Call in RestSharp - c#

I use RestSharp to send post and get calls to a robot which is connected via LAN through a switch with my computer. My get call:
public Vector3 getEffectorPos()
{
var c = new RestClient("http://" + robotIP);
var r = new RestRequest("/present/effector_position.json", Method.GET);
List<String> queryResult = c.Execute<List<String>>(r).Data;
string[] tmp = queryResult[0].Split('[', ']');
Vector4 x = parseStringToFloat4(tmp[2]);
Vector4 y = parseStringToFloat4(tmp[4]);
Vector4 z = parseStringToFloat4(tmp[6]);
Vector3 pos = new Vector3(x.w, y.w, z.w);
effPos.setPos(x.w, y.w, z.w);
effPos.cos = x.x;
effPos.sin = -x.y;
return pos;
}
Because the robot has the static ip 192.168.200.99 I have to switch to a static ip adress in the .200 subnet every time I want to run the project. When I first started the project I would get an error like NullReference or Bad Gateway if the robot was not connected.
But now if I forget to switch from dynamic ip to a static one and the programm can't connect to the robot Unity crashes. And afterwards even if I switch back to a static ip Unity proceeds to crash and it seems like nothing helps but waiting and after some time it will just work again without me doing anything.
It seems like I don't have the same problem with the post call:
public bool postEffectroPos(Vector3 pos, float speed_n)
{
var client = new RestClient("http://" + robotIP);
var request = new RestRequest("/present/effector_position_with_speed.json", Method.POST) { RequestFormat = RestSharp.DataFormat.Json };
effectorPos a = new effectorPos();
a.x = pos.x;
a.y = pos.y;
a.z = pos.z;
a.speed = speed_n;
request.AddBody(a);
bool move = false;
try
{
client.ExecuteAsync(request, response =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
string[] tmp = response.Content.Split(':');
string t = tmp[1].Remove(tmp[1].Length - 1);
move = bool.Parse(t);
//Debug.Log(move);
}
else
{
Debug.Log(response.StatusCode);
}
});
}
catch (Exception error)
{
Debug.Log(error);
}
return move;
}
The post call is async but I didn't figure out yet how to a return a value with async(returns always zero or false, depending on type) and I need the return value of the get call.

Related

Modbus read and write value conflict

My colleague and I working on project, where some physical devices are connected to Modbus interface(e.g. Lamp), and an desktop app where we sending requests to modbus using NModbus package, and also from time to time(e.g. after every 1 second) reading data from Modbus. We have a classic read/write conflict. Reading has no issue, but sometimes when we writing new value to modbus, the physical lamp going crazy and changing his state every 1 second.
Reading data from modbus is in different task, so do writing new values to modbus.
What we`ve tried:
lock critical section(only writing), and ignoring reading data when new value comes. After that we have a problem with queue and very slow working
CancellationToken - had no effect, or I writing it bad
Currently we have a class that collects property date of last state change(registered in IoC) and when new writing value comes, then we updating this property, and blocking from reading data from Modbus. Unfortunately this code sometimes working, sometimes not.
Please help. We are going crazy with this issue and we don`t know how to fix it.
Edit: I posting current code.
This is task, where we executing GetCurrentState handler
public void Start()
{
var cancellationToken = _cancellationTokenSource.Token;
Task.Run(async () =>
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(ReadStateDelayInMiliseconds).ConfigureAwait(false);
if ((DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds < _userCommandThresholdInMiliseconds)
continue;
try
{
await _service.GetCurrentState().ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.Error($"Error while checking current state. Message '{ex.Message}', Stack trace: '{ex.StackTrace}'.");
}
}
}, cancellationToken);
}
This is GetCurrentState handler, where we reading data from Modbus
protected override IgnisLightState Handle(GetState request)
{
if ((DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds <= _configuration.UserCommandThresholdInMiliseconds)
{
Logger.Debug($"Ignore before read state from lights, time after last execution: '{(DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds}'.");
return _state;
}
var currentLightState = _state.DeepClone();
foreach (var head in currentLightState.Heads)
{
try
{
ushort startAddress = 0x0000;
ushort numberOfPointsToRead = 0x0006;
var values = _modbusMaster.ReadHoldingRegisters((byte)head.UniqueId, startAddress, numberOfPointsToRead);
var isOn = values[IgnisRegistry.On.Value];
var isEndo = values[IgnisRegistry.Endo.Value];
var isCentrum = values[IgnisRegistry.Centrum.Value];
var tempValue = values[IgnisRegistry.Temp.Value];
var illuminanceValue = values[IgnisRegistry.Vol.Value];
head.ColorValue = Convert.ToInt32(tempValue);
head.IlluminanceValue = Convert.ToInt32(illuminanceValue);
head.IsCentrumOn = Convert.ToBoolean(isCentrum);
head.IsEndoOn = Convert.ToBoolean(isEndo);
head.IsTurnedOn = Convert.ToBoolean(isOn);
if (currentLightState.CameraState != null &&
_configuration.CameraHeadId.HasValue &&
_configuration.CameraHeadId.Value == head.UniqueId)
{
var camMode = values[IgnisRegistry.Cam.Value];
currentLightState.CameraState.IsTurnedOn = Convert.ToBoolean(isOn);
currentLightState.CameraState.CurrentMode = (IgnisCameraMode)Convert.ToInt32(camMode);
}
}
catch (Exception ex)
{
Logger.ErrorFixed(ex, $"Error while getting data from headId {head.UniqueId}.");
}
}
if (_state.Equals(currentLightState)
|| (DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds < _configuration.UserCommandThresholdInMiliseconds)
{
Logger.Debug($"Ignore after read state from lights, time after last execution: '{(DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds}'.");
return _state;
}
foreach (var currentHeadState in currentLightState.Heads)
{
_lightHeadStateUpdater.UpdateState(currentHeadState);
}
Logger.Debug($"Broadcast new state to clients '{JsonConvert.SerializeObject(currentLightState)}'.");
_hubContext.Clients.All.StateChanged(currentLightState);
return currentLightState;
}
This is an Turn on lamp handler where we writing new value to modbus:
protected override Response Handle(TurnOn request)
{
_lastCommandExecutionTimeContainer.SetLastCommandExecutionTime(DateTime.Now);
if (request.HeadId <= 0
|| !_state.Heads.Any(x=>x.UniqueId == request.HeadId))
{
return ResponseFactory.FromError(Error.NotExist);
}
var headState = _state.Heads.Single(x=>x.UniqueId == request.HeadId);
if (headState.IsTurnedOn)
return ResponseFactory.FromError(Error.AlreadyAsRequested);
_modbusMaster.WriteSingleRegister((byte)request.HeadId, IgnisRegistry.On.Value, 0x0001);
headState.IsTurnedOn = true;
if (_state.CameraState != null &&
_ignisLightConfiguration.CameraHeadId.HasValue &&
_ignisLightConfiguration.CameraHeadId.Value == request.HeadId)
{
_state.CameraState.IsTurnedOn = true;
}
Logger.Trace($"Turn head lamp {request.HeadId} on.");
_hubContext.Clients.All.HeadStateChanged(headState);
return ResponseFactory.Success;
}

How to get all devices in Network within Unity?

For around 8 hours now already I am trying to find a way so that I can receive all devices which are in the same network as I am. I've already found a few ways to do this, but all of them boil down to ping all IPs in the network. That wouldn't be a big problem if Unity allowed multithreading. Due to the fact that it does not / basically only allows IEnumerator I have the problem that I have to execute each ping after another which needs alot of time in which you cant even use the GUI.
My Current Code looks like this:
public class AddressFinder {
private List<Ping> pingers = new List<Ping>();
private List<IPAddress> addresses = new List<IPAddress>();
private int timeOut = 250;
private int ttl = 5;
private int instances;
private MonoBehaviour m;
public void Scan(MonoBehaviour mono, IPSegment ips, Action<List<IPAddress>> callback) {
this.m = mono;
m.StartCoroutine(ScanAsync(ips, callback)); // New Coroutine so the UI should not freeze
}
private IEnumerator ScanAsync(IPSegment ips, Action<List<IPAddress>> callback) {
PingOptions po = new PingOptions(ttl, true);
byte[] data = new System.Text.ASCIIEncoding().GetBytes("abababababababababababababababab");
instances = 0;
foreach(uint host in ips.Hosts()) { // Itterate through all IPs in that network
m.StartCoroutine(Send(IPHelper.ToIpString(host) // IP as String, data, po));
}
WaitForSeconds wait = new WaitForSeconds(0.05f);
while(instances > 0) {
yield return wait;
}
callback(addresses);
}
private IEnumerator Send(string ip, byte[] data, PingOptions po) {
instances++;
Ping p = new Ping();
PingReply rep = p.Send(ip, timeOut, data, po);
p.Dispose();
if(rep.Status == IPStatus.Success)
addresses.Add(IPAddress.Parse(ip));
instances--;
yield return new WaitForSeconds(0);
}
}
This wcode will actually work but needs like 4 mins to test all 253 IPs in my network. Also the UI freezes during this time.
I also tried using the unity Ping which seemed very inconsistent and also did not work that well, cause it also needed much to long for 254 pings.
Does anyone have an idea what the problem is or has another idea to get all devices in the network?
I have found a way with threads. I actually thought one should not use threads in Unity but it seems to just not use Unity Operations outside of the main Thread, mean others are allowed. Anyways here is my Code:
using Ping = System.Net.NetworkInformation.Ping;
public class AddressFinder {
public List<string> addresses = new List<string>();
private MonoBehaviour m;
Thread myThread = null;
public int instances = 0;
public AddressFinder(MonoBehaviour mono) {
m = mono;
}
public void Scan(List<IPSegment> iPSegments, Action<List<string>> addresses) {
myThread = new Thread(() => ScanThreads(iPSegments, addresses));
myThread.Start();
}
private void ScanThreads(List<IPSegment> iPSegments, Action<List<string>> callback) {
Ping myPing;
PingReply reply;
instances = 0;
foreach(IPSegment ips in iPSegments) {
foreach(uint hosta in ips.Hosts()) {
string ip = IPHelper.ToIpString(hosta);
Task.Factory.StartNew(() => {
myPing = new Ping();
instances++;
reply = myPing.Send(ip, 250);
if(reply.Status == IPStatus.Success) {
addresses.Add(ip);
}
instances--;
}, TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning);
}
}
int i = 0;
while(instances > 0) {
if(i > 100)
break;
i++;
Thread.Sleep(10);
}
callback(addresses);
}
}
public class LobbyManager : MonoBehaviour {
public UnityEngine.Object[] Games;
private List<string> localAddresses = new List<string>();
private List<string> hostAddresses = new List<string>();
private Ping p;
AddressFinder af;
public void Start() {
List<IPSegment> iPSegments = GetInterfaces(true);
af = new AddressFinder(this);
af.Scan(
iPSegments,
(addresses) => {
localAddresses = addresses;
foreach(string address in localAddresses) {
Debug.Log(address.ToString());
}
}
);
}
public void Update() {
}
public List<IPSegment> GetInterfaces(bool showVPN) {
List<IPSegment> ipsList = new List<IPSegment>();
foreach(NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) {
if(ni.Name.Contains("VM") || ni.Name.Contains("Loopback"))
continue;
if(!showVPN && ni.Name.Contains("VPN"))
continue;
foreach(UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) {
if(ip.Address.AddressFamily == AddressFamily.InterNetwork) {
IPSegment ips = new IPSegment(ip.Address.ToString(), ip.IPv4Mask.ToString());
ipsList.Add(ips);
}
}
}
return ipsList;
}
}
IPSegment is a class where all IPs in this segment according to the subnetmask are saved in.
This code works kinda well but is not that performent which means that there should not be a higher Subnetmask than 255.255.255.0 or it will need ages.

Error when pulling from database to create objects after successful creation

Let me start by apologizing for the complexity of this post. hopefully I am missing something simple but in order to find out I have to make a lengthy explanation.
I'm building a staff tracking app that allows users to draw polygons on a map. The polygon is used as a zone. If the device location is inside the zone it will set them to one status such as "In" and then set them to another status like "Out" when they leave. I'm using several nugets; SQLite, TK.CustomMap, PopupPlugin, to accomplish as much of this as possible in the Shared Project. The SQLite data model is based on the structure of the remote database for the solution which also has a desktop application, web app, and many other interfaces so that structure must be maintained.
The tables involved in this operation are Zones, ZonePoints and StatusClass. When the Zone is saved the Points of the TK.Polygon are saved into the points table. The Statuses assigned to the in and out status of the Zone are assigned to the zone as is the zone name.
The process works this way - first the user clicks on a button to add the zone. This creates a new zone, saves it to the database and gets its id from the table. For now, the ZoneSys (Primary Key in the remote db) is also set to the id although when the API is ready this will be Auto Incremented in the remote db. Here is that command and the objects it references. I did not include the database method definitions given that they work on the first time through, but if anyone thinks they will help solve this riddle please let me know -
public static List<Position> ActiveZonePositions = new List<Position>();
public static int ActiveZoneID;
public static Zone ActiveZone;
public static int PointCount;
public static bool NewZoneOpen = false;
public Command<EventArgs> OpenNewZone
{
get
{
return new Command<EventArgs>(async e =>
{
NewZoneOpen = true;
PointCount = 0;
ActiveZonePositions.Clear();
Zone ZoneToAdd = new Zone
{
Contactsys = MobileUser.ContactSys,
ZoneTypeSys = 1,
OrganizationSys = MobileUser.OrganizationSys,
ZoneName = null
};
ActiveZoneID = await AddZoneToDBAsync(ZoneToAdd);
ZoneToAdd.ID = ActiveZoneID;
ZoneToAdd.ZoneSys = ActiveZoneID;
await AddZoneToDBAsync(ZoneToAdd);
ActiveZone = await App.Database.GetZoneAsync(ActiveZoneID);
});
}
}
As the user click points in the map the polygon is drawn using those positions and those positions are also used to create points which are added to a static list. Here is the MapClicked_Command -
public Command<Position> MapClickedCommand
{
get
{
return new Command<Position>(async position =>
{
if (NewZoneOpen)
{
bool isPointInPolygon = IsPointInAnyPolygon(position);
if (isPointInPolygon)
{
var action = await Application.Current.MainPage.DisplayActionSheet(
"Region Collides with Another Region",
"Cancel",
null,
"Try Again",
"Close Zone Editor");
if (action == "Close Zone Editor")
{
await RemoveZoneAsync(ActiveZoneID);
}
if (action == "Try Again")
{
return;
}
}
else if (!isPointInPolygon)
{
ActiveZonePositions.Add(position);
}
if (ActiveZonePositions.Count == 2)
{
ZonePolyLine.LineCoordinates = ActiveZonePositions;
_lines.Remove(ZonePolyLine);
_lines.Add(ZonePolyLine);
}
else if (ActiveZonePositions.Count == 3)
{
ActiveZonePositions.Add(position);
_lines.Remove(ZonePolyLine);
TKPolygon poly = new TKPolygon
{
StrokeColor = System.Drawing.Color.CornflowerBlue,
StrokeWidth = 2f,
Color = System.Drawing.Color.CornflowerBlue
};
foreach (Position pos in ActiveZonePositions)
{
poly.Coordinates.Add(pos);
}
_polygons.Add(poly);
_currentPolygon.Clear();
_currentPolygon.Add(poly);
currentPolygonRendering = true;
}
else if (ActiveZonePositions.Count > 3)
{
ActiveZonePositions.Add(position);
TKPolygon poly = new TKPolygon
{
StrokeColor = System.Drawing.Color.CornflowerBlue,
StrokeWidth = 2f,
Color = System.Drawing.Color.CornflowerBlue
};
foreach (Position pos in ActiveZonePositions)
{
poly.Coordinates.Add(pos);
}
_polygons.Remove(_polygons.Last());
_polygons.Add(poly);
_currentPolygon.Clear();
_currentPolygon.Add(poly);
}
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
Title = string.Format("Pin {0}, {1}", position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = true
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
}
else if (EditZoneOpen)
{
ActiveZonePositions.Add(position);
var poly = _polygons[0];
poly.Coordinates.Clear();
foreach (Position pos in ActiveZonePositions)
{
poly.Coordinates.Add(pos);
}
_polygons.Remove(_polygons.Last());
_polygons.Add(poly);
_currentPolygon.Clear();
_currentPolygon.Add(poly);
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
Title = string.Format("Pin {0}, {1}", position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = true
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
}
});
}
}
Here is the CreatePointAsyncMethod -
public async Task CreatePointAsync(TK.CustomMap.Position position)
{
var zone = await RetrieveZoneAsync(ActiveZoneID);
Model.Point PointToAdd = new Model.Point
{
ZoneSys = zone.ZoneSys,
PointName = "",
Latitude = position.Latitude,
Longitude = position.Longitude,
PointOrder = PointCount + 1
};
ActiveZonePoints.Add(PointToAdd);
}
Here is the IsPointInAnyPolygon method that checks against the list of polygons to ensure the point clicked is not inside any of them as well as its supporting methods.
private bool IsPointInAnyPolygon(Position position)
{
bool inBounds = false;
for (var i = 0; i < ZonePolygons.Count(); i++)
foreach (ZonePolygon zpoly in ZonePolygons)
{
TKPolygon tkpoly = zpoly.Zpolygon;
inBounds = IsPointInPolygon(position, tkpoly.Coordinates);
if (inBounds)
{
ActiveZoneID = zpoly.ID;
return inBounds;
}
}
return inBounds;
}
private bool IsPointInPolygon(TK.CustomMap.Position position, List<Position> coords)
{
int intersectCount = 0;
for (int j = 0; j < coords.Count() - 1; j++)
{
if (j+1 >= coords.Count())
{
if (rayCastIntersect(position, coords[j], coords[0]))
{
intersectCount++;
}
} else if (rayCastIntersect(position, coords[j], coords[j + 1]))
{
intersectCount++;
}
}
return ((intersectCount % 2) == 1); // odd = inside, even = outside;
}
private bool rayCastIntersect(TK.CustomMap.Position position, TK.CustomMap.Position vertA, TK.CustomMap.Position vertB)
{
double aY = vertA.Latitude;
double bY = vertB.Latitude;
double aX = vertA.Longitude;
double bX = vertB.Longitude;
double pY = position.Latitude;
double pX = position.Longitude;
if ((aY > pY && bY > pY) | (aY < pY && bY < pY)
| (aX < pX && bX < pX))
{
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
Upon clicking the save button a popup opens that allows the user to give the Zone a name, define the statuses it will be assigned and the points are added to the database. There is a ZoneSys column in the Points table which allows the points to be matched to their respective zones when retrieved. This is done withe the UpdateZone command
public Command<EventArgs> UpdateZone
{
get
{
return new Command<EventArgs>(async e =>
{
Zone zone = await App.Database.GetZoneAsync(ActiveZoneID);
zone.ZoneName = ZoneParameters.ZoneName;
zone.StatusSys = ZoneParameters.InStatus.StatusSys;
zone.OutOfZoneStatusSys = ZoneParameters.OutStatus.StatusSys;
await AddZoneToDBAsync(zone);
if (MapPage.SaveZoneInfoPopupPageOpen)
{
SavePointsOnExit();
MapPage.SaveZoneInfoPopupPageOpen = false;
}
});
}
}
The UpdateZone command calls the SavePointsOnExit method
private async void SavePointsOnExit()
{
ActiveZonePoints.OrderBy(o => o.PointOrder);
for (var i = 0; i < ActiveZonePoints.Count(); i++)
{
Model.Point PointToAdd = new Model.Point();
PointToAdd = ActiveZonePoints[i];
ActivePointID = await AddPointToDBAsync(PointToAdd);
PointToAdd.ID = ActivePointID;
PointToAdd.PointSys = ActivePointID;
await AddPointToDBAsync(PointToAdd);
}
try
{
Zone zone = await RetrieveZoneAsync(ActiveZoneID);
}
catch
{
await Application.Current.MainPage.DisplayActionSheet("no zone returned", "database error", "cancel");
}
try
{
Zone zone = await RetrieveZoneAsync(ActiveZoneID);
await CreateZonedPolygonAsync(zone);
}
catch
{
await Application.Current.MainPage.DisplayActionSheet("Could not create ZonePolygon", "object error", "cancel");
}
ActiveZonePoints.Clear();
ActiveZonePositions.Clear();
NewZoneOpen = false;
ClearPins();
PointCount = 0;
PopulatePoints();
}
In addition to saving the points to the db the SaveZonePointsOnExit method also creates the ZonePolygon and adds it to an observable collection using the CreateZonedPolygonAsync method -
private async Task<ZonePolygon> CreateZonedPolygonAsync(Zone zone)
{
int StatusSys = zone.StatusSys;
var status = await App.Database.GetStatusBySysAsync(StatusSys);
int OutStatusSys = zone.OutOfZoneStatusSys;
var outStatus = await App.Database.GetStatusBySysAsync(OutStatusSys);
var points = await App.Database.GetZonePointsAsync(zone.ZoneSys);
ZonePolygon zonePolygon = new ZonePolygon
{
ID = zone.ID
};
TKPolygon poly = new TKPolygon();
foreach (Model.Point point in points)
{
poly.Coordinates.Add(new Position(point.Latitude, point.Longitude));
}
poly.Color = Color.FromHex(status.ColorCode);
poly.StrokeColor = Color.Firebrick;
poly.StrokeWidth = 5f;
_polygons.Add(poly);
ZonePolygons.Add(zonePolygon);
return zonePolygon;
}
So far all of this works to a point. I have been successful in creating the first Polygon. I don't run into a problem until I attempt to create a second Zone. When I click on the AddZone button a second time that works fine but when I click on the map to begin creating the second zone a nullreference exception occurs.
Given that the first zone is created without issue I think the problem must be arising from something that occurs when the IsPointInAnyPolygon method no longer immediately returns false because the ZonePolygons list is no longer empty. So something about the retrieving of zones from the database to check against is the problem or possibly adding coordinates when the TKPolygon is created. I don't know what has a null reference. I would think that since I am creating the Zones directly from the database that all the objects would be saved properly and their previous references wouldn't matter. I'm very stuck on this.
TL;DR there is an issue with either the CreateZonedPolygonAsync Method or the IsPointInAnyPolygon method
I figured this out. I feel rather silly because I have been stuck on this for several hours spread out over a couple of weeks. Kept coming back to it and couldn't figure it out. The issue was that in the CreateZonedPolygonAsync method I never assigned the TKPolygon created via points to the ZonePolygon object being created. So when I tried to reference it it didn't exist. All that existed was the ID. Can't believe I missed this for this long.
Of course now I'm having brand new problems but at least this is fixed.
All I had to do was add zonePolygon.Zpolygon = poly; as shown here and it works now
private async Task<ZonePolygon> CreateZonedPolygonAsync(Zone zone)
{
int StatusSys = zone.StatusSys;
var status = await App.Database.GetStatusBySysAsync(StatusSys);
int OutStatusSys = zone.OutOfZoneStatusSys;
var outStatus = await App.Database.GetStatusBySysAsync(OutStatusSys);
var points = await App.Database.GetZonePointsAsync(zone.ZoneSys);
ZonePolygon zonePolygon = new ZonePolygon
{
ID = zone.ID
};
TKPolygon poly = new TKPolygon();
foreach (Model.Point point in points)
{
poly.Coordinates.Add(new Position(point.Latitude, point.Longitude));
}
poly.Color = Color.FromHex(status.ColorCode);
poly.StrokeColor = Color.Firebrick;
poly.StrokeWidth = 5f;
zonePolygon.Zpolygon = poly;
_polygons.Add(poly);
ZonePolygons.Add(zonePolygon);
return zonePolygon;
}

Change value in try c#

I have a function which sends a Vector3 pos to a robot via RestSharp and the response of the POST call looks like this:
{present_effector_pos: true/false}
I want to parse the true or false and return it as boolean.
public bool postEffectroPos(Vector3 pos, float speed_n)
{
var client = new RestClient("http://"+robotIP);
var request = new RestRequest("/present/effector_position_with_speed.json", Method.POST) { RequestFormat = RestSharp.DataFormat.Json };
effectorPos a = new effectorPos();
a.x = pos.x;
a.y = pos.z;
a.z = pos.y;
a.speed = speed_n;
request.AddBody(a);
bool move = false;
try
{
client.ExecuteAsync(request, response =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
string[] tmp = response.Content.Split(':');
string t = tmp[1].Remove(tmp[1].Length - 1);
move = bool.Parse(t);
Debug.Log(move);
}
else
{
Debug.Log(response.StatusCode);
}
});
}
catch (Exception error)
{
Debug.Log(error);
}
return move;
}
But no matter to what value the variable move is changed in the if clause through parsing the method always returns false.

Getting an exception while trying to receive objects over TCP with c#

I am trying to receive objects with TCP using C# and serialization. I am receiving objects constantly and each object is sent to a new task. I chose not to use threads because its too expensive. The problem is that if I am receiving only 1 object at a time everything goes just fine but if I am trying to receive more than 1 object, after a few seconds I am getting:
"the input stream is not a valid binary format. the starting contents (in bytes) are: ..."
This is my listening function:
public void Listen()
{
try
{
TcpObject tcpObject = new TcpObject();
IFormatter formatter = new BinaryFormatter();
bool offline = true;
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(() => offline = Offline));
while (!offline)
{
tcpObject = (TcpObject)formatter.Deserialize(serverStream);
if (tcpObject.Command == Command.Transfer)
{
#region Task
Task.Factory.StartNew(() =>
{
SentAntenna sentAntenna = (SentAntenna)tcpObject.Object;
string antennaName = sentAntenna.Name;
if (MainWindow.SpectrumList.ContainsKey(antennaName))
{
PointCollection pointCollection = new PointCollection();
float minChan = sentAntenna.Min;
float maxChan = sentAntenna.Max;
if (MainWindow.SpectrumList[antennaName].spectrumViewModel.AbsoluteMinimum == -1)
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(delegate
{
MainWindow.SpectrumList[antennaName].spectrumViewModel.AbsoluteMinimum = minChan;
MainWindow.SpectrumList[antennaName].spectrumViewModel.AbsoluteMaximum = maxChan;
MainWindow.SpectrumList[antennaName].spectrumViewModel.TBMinRange = minChan.ToString();
MainWindow.SpectrumList[antennaName].spectrumViewModel.TBMaxRange = maxChan.ToString();
MainWindow.SpectrumList[antennaName].spectrumViewModel.MinRange = minChan;
MainWindow.SpectrumList[antennaName].spectrumViewModel.MaxRange = maxChan;
MainWindow.SpectrumList[antennaName].spectrumViewModel.UpdateRange();
}));
}
float gap = maxChan - minChan;
foreach (Frequency f in sentAntenna.Frequencies)
{
float chan = ((f.Channel - minChan) / gap) * 310;
float inten = ((f.Intensity - 1) / 599) * 100;
pointCollection.Add(new Point(chan, inten));
}
pointCollection.Freeze();
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(() => MainWindow.SpectrumList[antennaName].spectrumViewModel.AllAntennaPoints = pointCollection.Clone()));
}
Thread.Sleep(50);
});
#endregion
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); // raise an event
}
}
What am I doing wrong?
Try moving
SentAntenna sentAntenna = (SentAntenna)tcpObject.Object;
to the line before the StartNew(). I believe this will fix your issue.
I don't think you want concurrent access to the tcpObject, since it's global to all the tasks.
Alternatively you could instantiate the TcpObject inside the while loop, which would then keep it local to each task.
There are several reasons for this error:
When two objects concurently writes to one connection
When somthing goes wrong with serverStream: stream have received a part of data or received 0 length data
You concurently acces to tcpObject. it's a bad idea.

Categories