Initial commit. Project, simple monitoring of CPU temp via "sensors" command
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
.vs/
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
Barsik.csproj.user
|
||||||
@@ -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
@@ -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
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
@@ -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>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[Server]
|
||||||
|
Port = 4500
|
||||||
|
|
||||||
|
[Unit_CPU]
|
||||||
|
Type = Sensors
|
||||||
|
BaseAddress = 1
|
||||||
|
String = CPU Temperature
|
||||||
|
Multiplier = 100
|
||||||
Reference in New Issue
Block a user