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