Initial commit. Project, simple monitoring of CPU temp via "sensors" command

This commit is contained in:
ftc
2020-08-25 23:34:18 +03:00
commit 092cba1cee
10 changed files with 379 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
.vs/
bin/
obj/
Barsik.csproj.user
+14
View File
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<ApplicationIcon />
<StartupObject>Barsik.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ini-parser" Version="2.5.2" />
</ItemGroup>
</Project>
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29209.62
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Barsik", "Barsik.csproj", "{71549955-D26F-4B4F-BC3C-0D144DEAA2F7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{71549955-D26F-4B4F-BC3C-0D144DEAA2F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71549955-D26F-4B4F-BC3C-0D144DEAA2F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71549955-D26F-4B4F-BC3C-0D144DEAA2F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71549955-D26F-4B4F-BC3C-0D144DEAA2F7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F1F24D24-CD2E-47A6-87E0-3EBCD13C4D58}
EndGlobalSection
EndGlobal
+134
View File
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Barsik
{
class ModbusServer
{
private RegistersContainer registers;
public int Port { get; set; }
public ModbusServer(RegistersContainer registers)
{
this.registers = registers;
}
internal void Run()
{
var listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
var worker = new ModbusServerWorker(registers, client);
Thread clientThread = new Thread(new ThreadStart(worker.Run));
clientThread.Start();
}
}
}
class ModbusServerWorker
{
const int RECEIVE_TIMEOUT = 10000; // 10 seconds
private RegistersContainer registers;
private TcpClient client;
public ModbusServerWorker(RegistersContainer registers, TcpClient client)
{
this.registers = registers;
this.client = client;
}
List<byte> received;
ManualResetEvent readCompleted;
int currentReceived;
NetworkStream stream;
byte[] buffer = new byte[256];
public void Run()
{
received = new List<byte>();
try
{
client.ReceiveTimeout = RECEIVE_TIMEOUT;
stream = client.GetStream();
readCompleted = new ManualResetEvent(false);
while (true)
{
readCompleted.Reset();
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(this.OnReadCompleted), this);
readCompleted.WaitOne();
if (currentReceived < 0)
{
client.Close();
return;
}
ProcessReceivedData();
}
}
catch (IOException)
{
client.Close();
}
}
private void ProcessReceivedData()
{
lock (received)
{
if (received.Count < 6) return;
int len = (((int)received[4] << 8) | (int)received[5]);
if (received.Count < 6 + len) return;
if (len < 2) throw new Exception("Wrong length");
int transactionId = (((int)received[0] << 8) | (int)received[1]);
byte unitId = received[6];
byte function = received[7];
List<byte> response = new List<byte>();
if (function == 0x03) // read holding registers
{
int addr = (((int)received[8] << 8) | (int)received[9]);
int amount = (((int)received[10] << 8) | (int)received[11]);
for (int a = addr; a < addr + amount; a++)
{
int value = registers[a];
response.Add((byte)((value >> 8) & 0xFF));
response.Add((byte)(value & 0xFF));
}
}
else
{
throw new Exception("Unsupported function: " + function);
}
List<byte> fullResponse = new List<byte>();
fullResponse.Add(received[0]);
fullResponse.Add(received[1]); // transaction id
fullResponse.Add(received[2]);
fullResponse.Add(received[3]); // protocol id
int responseLength = 3 + response.Count;
fullResponse.Add((byte)((responseLength >> 8) & 0xFF));
fullResponse.Add((byte)((responseLength) & 0xFF));
fullResponse.Add(unitId);
fullResponse.Add(function);
fullResponse.Add((byte)response.Count);
fullResponse.AddRange(response);
received.RemoveRange(0, 6 + len);
stream.Write(fullResponse.ToArray(), 0, fullResponse.Count);
}
}
private void OnReadCompleted(IAsyncResult ar)
{
currentReceived = stream.EndRead(ar);
lock (received)
{
for (int i = 0; i < currentReceived; i++) received.Add(buffer[i]);
}
readCompleted.Set();
}
}
}
+96
View File
@@ -0,0 +1,96 @@
using IniParser.Model;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Barsik
{
class BaseMonitoringUnit
{
protected SectionData config;
protected RegistersContainer registers;
protected int baseAddress;
public BaseMonitoringUnit(SectionData config, RegistersContainer registers)
{
this.config = config;
this.registers = registers;
baseAddress = int.Parse(config.Keys["BaseAddress"]);
}
public virtual void Run()
{
}
public static BaseMonitoringUnit Create(SectionData config, RegistersContainer registers)
{
var type = config.Keys["Type"];
if (type == "Sensors")
{
return new SensorsMonitoringUnit(config, registers);
}
else
{
Console.WriteLine("Unknown unit type " + type);
return null;
}
}
}
class SensorsMonitoringUnit : BaseMonitoringUnit
{
public SensorsMonitoringUnit(SectionData config, RegistersContainer registers) : base(config, registers)
{
}
public override void Run()
{
var stringToFind = config.Keys["String"];
var multiplier = float.Parse(config.Keys["Multiplier"]);
while (true)
{
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("sensors");
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
while (!proc.HasExited)
{
Thread.Sleep(100);
}
string result = proc.StandardOutput.ReadToEnd();
var lines = result.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains(stringToFind))
{
var value = ExtractValue(lines[i]);
registers[baseAddress] = (int)(value * multiplier);
}
}
}
}
bool Good(char c)
{
if (c == '-' || c == '+' || c == '.') return true;
if (c >= '0' && c <= '9') return true;
return false;
}
private float ExtractValue(string v)
{
int pos = 0;
while (pos < v.Length && !Good(v[pos])) pos++;
int pos2 = pos;
while (pos2 < v.Length && Good(v[pos2])) pos2++;
float res = 0;
float.TryParse(v.Substring(pos, pos2 - pos), out res);
return res;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
using IniParser;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Barsik
{
class Program
{
private static RegistersContainer registers;
private static List<BaseMonitoringUnit> units;
static void Main(string[] args)
{
registers = new RegistersContainer();
var server = new ModbusServer(registers);
units = new List<BaseMonitoringUnit>();
var configParser = new FileIniDataParser();
var data = configParser.ReadFile("barsik.ini");
foreach (var section in data.Sections)
{
if (section.SectionName.StartsWith("Unit"))
{
var unit = BaseMonitoringUnit.Create(section, registers);
if (unit != null)
{
units.Add(unit);
Thread unitThread = new Thread(new ThreadStart(unit.Run));
unitThread.Start();
}
}
}
server.Port = int.Parse(data["Server"]["Port"]);
while (true)
{
server.Run();
Thread.Sleep(1000);
}
}
}
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PublishDir>bin\Debug\netcoreapp2.1\publish\</PublishDir>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<_IsPortable>false</_IsPortable>
</PropertyGroup>
</Project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
+34
View File
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
namespace Barsik
{
class RegistersContainer
{
private Dictionary<int, int> registers;
public RegistersContainer()
{
registers = new Dictionary<int, int>();
}
public int this[int address]
{
get
{
lock(registers)
{
if (registers.ContainsKey(address)) return registers[address];
return 0;
}
}
set
{
lock (registers)
{
registers[address] = value;
}
}
}
}
}
+8
View File
@@ -0,0 +1,8 @@
[Server]
Port = 4500
[Unit_CPU]
Type = Sensors
BaseAddress = 1
String = CPU Temperature
Multiplier = 100