Merge branch 'main' of https://git.innov.energy/Innovenergy/git_trunk
This commit is contained in:
commit
c4eb538132
|
@ -1,19 +1,49 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using InnovEnergy.App.Backend.Model;
|
using InnovEnergy.App.Backend.Model;
|
||||||
using InnovEnergy.App.Backend.Model.Relations;
|
using InnovEnergy.App.Backend.Model.Relations;
|
||||||
using InnovEnergy.App.Backend.Utils;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
public partial class Db : IDisposable
|
public static partial class Db
|
||||||
{
|
{
|
||||||
internal const String DbPath = "./db.sqlite";
|
internal const String DbPath = "./db.sqlite";
|
||||||
|
|
||||||
private readonly SQLiteConnection _Db; // internal handle to the connection, disposable
|
public static SQLiteConnection Connection { get; } = new SQLiteConnection(DbPath);
|
||||||
|
|
||||||
|
public static TableQuery<Session> Sessions => Connection.Table<Session>();
|
||||||
|
public static TableQuery<Folder> Folders => Connection.Table<Folder>();
|
||||||
|
public static TableQuery<Installation> Installations => Connection.Table<Installation>();
|
||||||
|
public static TableQuery<User> Users => Connection.Table<User>();
|
||||||
|
public static TableQuery<User2Folder> User2Folder => Connection.Table<User2Folder>();
|
||||||
|
public static TableQuery<User2Installation> User2Installation => Connection.Table<User2Installation>();
|
||||||
|
|
||||||
|
public static Int32 NbUser2Installation => User2Installation.Count();
|
||||||
|
public static Int32 NbUser2Folder => User2Folder.Count();
|
||||||
|
public static Int32 NbFolders => Folders.Count();
|
||||||
|
public static Int32 NbInstallations => Installations.Count();
|
||||||
|
public static Int32 NbUsers => Users.Count();
|
||||||
|
|
||||||
|
|
||||||
|
public static Folder? GetFolderById(Int64 id)
|
||||||
|
{
|
||||||
|
return Folders
|
||||||
|
.FirstOrDefault(f => f.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Installation? GetInstallationById(Int64 id)
|
||||||
|
{
|
||||||
|
return Installations
|
||||||
|
.FirstOrDefault(i => i.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User? GetUserById(Int64 id)
|
||||||
|
{
|
||||||
|
return Users
|
||||||
|
.FirstOrDefault(u => u.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
private TableQuery<Session> Sessions => _Db.Table<Session>();
|
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "AccessToDisposedClosure")]
|
[SuppressMessage("ReSharper", "AccessToDisposedClosure")]
|
||||||
static Db()
|
static Db()
|
||||||
|
@ -33,21 +63,14 @@ public partial class Db : IDisposable
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// private, force access through Connect()
|
|
||||||
private Db() => _Db = new SQLiteConnection(DbPath);
|
|
||||||
|
|
||||||
public static Db Connect() => new Db();
|
|
||||||
|
|
||||||
public void Dispose() => _Db.Dispose();
|
|
||||||
|
|
||||||
|
|
||||||
// the C in CRUD
|
// the C in CRUD
|
||||||
private Int64 Create(TreeNode treeNode)
|
private static Int64 Create(TreeNode treeNode)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Db.Insert(treeNode);
|
Connection.Insert(treeNode);
|
||||||
return SQLite3.LastInsertRowid(_Db.Handle);
|
return SQLite3.LastInsertRowid(Connection.Handle);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -56,11 +79,11 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Boolean Create(Session session)
|
private static Boolean Create(Session session)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Db.Insert(session);
|
Connection.Insert(session);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -70,11 +93,11 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// the U in CRUD
|
// the U in CRUD
|
||||||
private Boolean Update(TreeNode treeNode)
|
private static Boolean Update(TreeNode treeNode)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Db.InsertOrReplace(treeNode);
|
Connection.InsertOrReplace(treeNode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -84,11 +107,11 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// the D in CRUD
|
// the D in CRUD
|
||||||
private Boolean Delete(TreeNode treeNode)
|
private static Boolean Delete(TreeNode treeNode)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Db.Delete(treeNode);
|
Connection.Delete(treeNode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -97,49 +120,49 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Installation> GetAllAccessibleInstallations(User user)
|
public static IEnumerable<Installation> GetAllAccessibleInstallations(User user)
|
||||||
{
|
{
|
||||||
var direct = GetDirectlyAccessibleInstallations(user);
|
var direct = GetDirectlyAccessibleInstallations(user);
|
||||||
var fromFolders = GetAllAccessibleFolders(user)
|
var fromFolders = GetAllAccessibleFolders(user)
|
||||||
.SelectMany(GetChildInstallations);
|
.SelectMany(GetChildInstallations);
|
||||||
|
|
||||||
return direct
|
return direct
|
||||||
.Concat(fromFolders)
|
.Concat(fromFolders)
|
||||||
.Distinct();
|
.Distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Folder> GetAllAccessibleFolders(User user)
|
public static IEnumerable<Folder> GetAllAccessibleFolders(User user)
|
||||||
{
|
{
|
||||||
return GetDirectlyAccessibleFolders(user)
|
return GetDirectlyAccessibleFolders(user)
|
||||||
.SelectMany(GetDescendantFolders)
|
.SelectMany(GetDescendantFolders)
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
// Distinct because the user might have direct access
|
// Distinct because the user might have direct access
|
||||||
// to a child folder of a folder he has already access to
|
// to a child folder of a folder he has already access to
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public IEnumerable<Installation> GetDirectlyAccessibleInstallations(User user)
|
public static IEnumerable<Installation> GetDirectlyAccessibleInstallations(User user)
|
||||||
{
|
{
|
||||||
return User2Installation
|
return User2Installation
|
||||||
.Where(r => r.UserId == user.Id)
|
.Where(r => r.UserId == user.Id)
|
||||||
.Select(r => r.InstallationId)
|
.Select(r => r.InstallationId)
|
||||||
.Select(GetInstallationById)
|
.Select(GetInstallationById)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.Do(i => i.ParentId = 0); // hide inaccessible parents from calling user
|
.Do(i => i.ParentId = 0); // hide inaccessible parents from calling user
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Folder> GetDirectlyAccessibleFolders(User user)
|
public static IEnumerable<Folder> GetDirectlyAccessibleFolders(User user)
|
||||||
{
|
{
|
||||||
return User2Folder
|
return User2Folder
|
||||||
.Where(r => r.UserId == user.Id)
|
.Where(r => r.UserId == user.Id)
|
||||||
.Select(r => r.FolderId)
|
.Select(r => r.FolderId)
|
||||||
.Select(GetFolderById)
|
.Select(GetFolderById)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.Do(i => i.ParentId = 0); // hide inaccessible parents from calling user;
|
.Do(i => i.ParentId = 0); // hide inaccessible parents from calling user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId)
|
public static Boolean AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId)
|
||||||
{
|
{
|
||||||
var con = new User2Installation
|
var con = new User2Installation
|
||||||
{
|
{
|
||||||
|
@ -149,7 +172,7 @@ public partial class Db : IDisposable
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Db.Insert(con);
|
Connection.Insert(con);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -158,7 +181,7 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId)
|
public static Boolean AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId)
|
||||||
{
|
{
|
||||||
var con = new User2Folder
|
var con = new User2Folder
|
||||||
{
|
{
|
||||||
|
@ -168,7 +191,7 @@ public partial class Db : IDisposable
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Db.Insert(con);
|
Connection.Insert(con);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -178,7 +201,7 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public User? GetUserByToken(String token)
|
public static User? GetUserByToken(String token)
|
||||||
{
|
{
|
||||||
return Sessions
|
return Sessions
|
||||||
.Where(s => s.Token == token).ToList()
|
.Where(s => s.Token == token).ToList()
|
||||||
|
@ -189,9 +212,9 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Boolean NewSession(Session ses) => Create(ses);
|
public static Boolean NewSession(Session ses) => Create(ses);
|
||||||
|
|
||||||
public Boolean DeleteSession(Int64 id)
|
public static Boolean DeleteSession(Int64 id)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -204,13 +227,14 @@ public partial class Db : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object? GetInstallationS3Key(Int64 installationId)
|
public static String? GetInstallationS3Key(Int64 installationId)
|
||||||
{
|
{
|
||||||
return Installations
|
return Installations
|
||||||
.FirstOrDefault(installation => installation.Id == installationId).S3Key;
|
.FirstOrDefault(i => i.Id == installationId)?
|
||||||
|
.S3Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteS3KeysDaily()
|
public static void DeleteAllS3Keys()
|
||||||
{
|
{
|
||||||
foreach (var installation in Installations.ToList())
|
foreach (var installation in Installations.ToList())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
using InnovEnergy.App.Backend.Model;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO ?
|
|
||||||
public struct DbConnection
|
|
||||||
{
|
|
||||||
public DbConnection(SQLiteConnection connection, User caller)
|
|
||||||
{
|
|
||||||
Connection = connection;
|
|
||||||
Caller = caller;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SQLiteConnection Connection { get;}
|
|
||||||
public User Caller { get;}
|
|
||||||
}
|
|
|
@ -2,11 +2,11 @@ using InnovEnergy.App.Backend.Model.Relations;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
public partial class Db
|
public static partial class Db
|
||||||
{
|
{
|
||||||
public void CreateFakeRelations()
|
public static void CreateFakeRelations()
|
||||||
{
|
{
|
||||||
_Db.RunInTransaction(() =>
|
Connection.RunInTransaction(() =>
|
||||||
{
|
{
|
||||||
CreateFakeUserTree();
|
CreateFakeUserTree();
|
||||||
CreateFakeFolderTree();
|
CreateFakeFolderTree();
|
||||||
|
@ -16,7 +16,7 @@ public partial class Db
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateFakeUserTree()
|
private static void CreateFakeUserTree()
|
||||||
{
|
{
|
||||||
foreach (var userId in Enumerable.Range(1, NbUsers))
|
foreach (var userId in Enumerable.Range(1, NbUsers))
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@ public partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateFakeFolderTree()
|
private static void CreateFakeFolderTree()
|
||||||
{
|
{
|
||||||
foreach (var folderId in Enumerable.Range(1, NbFolders))
|
foreach (var folderId in Enumerable.Range(1, NbFolders))
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ public partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LinkFakeInstallationsToFolders()
|
private static void LinkFakeInstallationsToFolders()
|
||||||
{
|
{
|
||||||
var nFolders = NbFolders;
|
var nFolders = NbFolders;
|
||||||
|
|
||||||
|
@ -59,10 +59,10 @@ public partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GiveFakeUsersAccessToFolders()
|
private static void GiveFakeUsersAccessToFolders()
|
||||||
{
|
{
|
||||||
foreach (var uf in User2Folder) // remove existing relations
|
foreach (var uf in User2Folder) // remove existing relations
|
||||||
_Db.Delete(uf);
|
Connection.Delete(uf);
|
||||||
|
|
||||||
var nFolders = NbFolders;
|
var nFolders = NbFolders;
|
||||||
var nUsers = NbUsers;
|
var nUsers = NbUsers;
|
||||||
|
@ -75,14 +75,14 @@ public partial class Db
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
FolderId = Random.Shared.Next(nFolders) + 1
|
FolderId = Random.Shared.Next(nFolders) + 1
|
||||||
};
|
};
|
||||||
_Db.Insert(relation);
|
Connection.Insert(relation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GiveFakeUsersAccessToInstallations()
|
private static void GiveFakeUsersAccessToInstallations()
|
||||||
{
|
{
|
||||||
foreach (var ui in User2Installation) // remove existing relations
|
foreach (var ui in User2Installation) // remove existing relations
|
||||||
_Db.Delete(ui);
|
Connection.Delete(ui);
|
||||||
|
|
||||||
var nbInstallations = NbInstallations;
|
var nbInstallations = NbInstallations;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ public partial class Db
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
InstallationId = Random.Shared.Next(nbInstallations) + 1
|
InstallationId = Random.Shared.Next(nbInstallations) + 1
|
||||||
};
|
};
|
||||||
_Db.Insert(relation);
|
Connection.Insert(relation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,76 +1,80 @@
|
||||||
using InnovEnergy.App.Backend.Model;
|
using InnovEnergy.App.Backend.Model;
|
||||||
using InnovEnergy.App.Backend.Utils;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
public partial class Db
|
public static partial class Db
|
||||||
{
|
{
|
||||||
private TableQuery<Folder> Folders => _Db.Table<Folder>();
|
public static IEnumerable<Folder> GetChildFolders(this Folder parent)
|
||||||
|
|
||||||
public Int32 NbFolders => Folders.Count();
|
|
||||||
|
|
||||||
public Folder? GetFolderById(Int64 id)
|
|
||||||
{
|
|
||||||
return Folders.FirstOrDefault(u => u.Id == id);
|
|
||||||
|
|
||||||
// if (folder is null)
|
|
||||||
// return null;
|
|
||||||
|
|
||||||
//return PopulateDescendants(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Folder> GetChildFolders(Folder parent)
|
|
||||||
{
|
{
|
||||||
return Folders.Where(f => f.ParentId == parent.Id);
|
return Folders.Where(f => f.ParentId == parent.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Folder> GetDescendantFolders(Folder parent)
|
public static IEnumerable<Installation> GetChildInstallations(this Folder parent)
|
||||||
{
|
|
||||||
return parent.Traverse(GetChildFolders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Installation> GetChildInstallations(Folder parent)
|
|
||||||
{
|
{
|
||||||
return Installations.Where(f => f.ParentId == parent.Id);
|
return Installations.Where(f => f.ParentId == parent.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<User> GetChildUsers(User parent)
|
public static IEnumerable<Folder> GetDescendantFolders(this Folder parent)
|
||||||
{
|
{
|
||||||
return Users.Where(f => f.ParentId == parent.Id);
|
return parent.Traverse(GetChildFolders);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<User> GetDescendantUsers(User parent)
|
public static Boolean IsDescendantOf(this Folder folder, Int64 ancestorFolderId)
|
||||||
{
|
{
|
||||||
return parent.Traverse(GetChildUsers);
|
return Ancestors(folder)
|
||||||
|
.Any(u => u.Id == ancestorFolderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int64 CreateFolder(Folder folder)
|
public static Boolean IsDescendantOf(this Folder folder, Folder ancestor)
|
||||||
|
{
|
||||||
|
return IsDescendantOf(folder, ancestor.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Folder> Ancestors(this Folder child)
|
||||||
|
{
|
||||||
|
return child.Unfold(GetParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Folder? GetParent(this Folder f)
|
||||||
|
{
|
||||||
|
return IsRoot(f)
|
||||||
|
? null
|
||||||
|
: GetFolderById(f.ParentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean IsRoot(this Folder f)
|
||||||
|
{
|
||||||
|
return f.ParentId == 0; // root has ParentId 0 by definition
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int64 CreateFolder(Folder folder)
|
||||||
{
|
{
|
||||||
return Create(folder);
|
return Create(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean UpdateFolder(Folder folder)
|
public static Boolean UpdateFolder(Folder folder)
|
||||||
{
|
{
|
||||||
// TODO: no circles in path
|
// TODO: no circles in path
|
||||||
|
|
||||||
return Update(folder);
|
return Update(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean ChangeParent(Installation child, Int64 parentId)
|
// These should not be necessary, just Update folder/installation with new parentId
|
||||||
{
|
|
||||||
child.ParentId = parentId;
|
|
||||||
return UpdateInstallation(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean ChangeParent(Folder child, Int64 parentId)
|
|
||||||
{
|
|
||||||
child.ParentId = parentId;
|
|
||||||
return UpdateFolder(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean DeleteFolder(Folder folder)
|
// public Boolean ChangeParent(Installation child, Int64 parentId)
|
||||||
|
// {
|
||||||
|
// child.ParentId = parentId;
|
||||||
|
// return UpdateInstallation(child);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public Boolean ChangeParent(Folder child, Int64 parentId)
|
||||||
|
// {
|
||||||
|
// child.ParentId = parentId;
|
||||||
|
// return UpdateFolder(child);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static Boolean DeleteFolder(Folder folder)
|
||||||
{
|
{
|
||||||
// Delete direct children
|
// Delete direct children
|
||||||
User2Folder .Delete(f => f.FolderId == folder.Id);
|
User2Folder .Delete(f => f.FolderId == folder.Id);
|
||||||
|
|
|
@ -1,37 +1,47 @@
|
||||||
using InnovEnergy.App.Backend.Model;
|
using InnovEnergy.App.Backend.Model;
|
||||||
using InnovEnergy.App.Backend.Utils;
|
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
public partial class Db
|
public static partial class Db
|
||||||
{
|
{
|
||||||
|
public static IEnumerable<Folder> Ancestors(this Installation installation)
|
||||||
private TableQuery<Installation> Installations => _Db.Table<Installation>();
|
{
|
||||||
|
var parentFolder = GetParent(installation);
|
||||||
public Int32 NbInstallations => Installations.Count();
|
|
||||||
|
|
||||||
public Installation? GetInstallationById(Int64 id) => Installations
|
|
||||||
.FirstOrDefault(u => u.Id == id);
|
|
||||||
|
|
||||||
public Int64 CreateInstallation(Installation installation)
|
return parentFolder is null
|
||||||
|
? Enumerable.Empty<Folder>()
|
||||||
|
: Ancestors(parentFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Folder? GetParent(this Installation installation)
|
||||||
|
{
|
||||||
|
return IsRoot(installation)
|
||||||
|
? null
|
||||||
|
: GetFolderById(installation.ParentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean IsRoot(this Installation i)
|
||||||
|
{
|
||||||
|
return i.ParentId == 0; // root has ParentId 0 by definition
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int64 CreateInstallation(this Installation installation)
|
||||||
{
|
{
|
||||||
return Create(installation);
|
return Create(installation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean UpdateInstallation(Installation installation)
|
public static Boolean UpdateInstallation(this Installation installation)
|
||||||
{
|
{
|
||||||
return Update(installation);
|
return Update(installation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean DeleteInstallation(this Installation installation)
|
||||||
public Boolean DeleteInstallation(Installation installation)
|
|
||||||
{
|
{
|
||||||
User2Installation.Delete(i => i.InstallationId == installation.Id);
|
User2Installation.Delete(i => i.InstallationId == installation.Id);
|
||||||
|
|
||||||
return Delete(installation);
|
return Delete(installation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,50 +7,68 @@ using System.Text.RegularExpressions;
|
||||||
using InnovEnergy.App.Backend.Model;
|
using InnovEnergy.App.Backend.Model;
|
||||||
using InnovEnergy.App.Backend.Utils;
|
using InnovEnergy.App.Backend.Utils;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
#pragma warning disable CS0472
|
|
||||||
#pragma warning disable CS8602
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
public partial class Db
|
public static partial class Db
|
||||||
{
|
{
|
||||||
private TableQuery<User> Users => _Db.Table<User>();
|
public static IEnumerable<User> GetChildUsers(this User parent)
|
||||||
|
|
||||||
public Int32 NbUsers => Users.Count();
|
|
||||||
|
|
||||||
public User? GetUserById(Int64 id)
|
|
||||||
{
|
{
|
||||||
return Users.FirstOrDefault(u => u.Id == id);
|
return Users
|
||||||
|
.Where(f => f.ParentId == parent.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean IsParentOfChild(Int64 parentId, User child)
|
public static IEnumerable<User> GetDescendantUsers(this User parent)
|
||||||
{
|
{
|
||||||
return Ancestors(child)
|
return parent.Traverse(GetChildUsers);
|
||||||
.Any(u => u.Id == parentId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<User> Ancestors(User child)
|
public static Boolean IsDescendantOf(this User user, User ancestor)
|
||||||
|
{
|
||||||
|
return Ancestors(user)
|
||||||
|
.Any(u => u.Id == ancestor.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<User> Ancestors(this User child)
|
||||||
{
|
{
|
||||||
return child.Unfold(GetParent);
|
return child.Unfold(GetParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public User? GetParent(User u)
|
public static User? GetParent(this User u)
|
||||||
{
|
{
|
||||||
return IsRoot(u)
|
return IsRoot(u)
|
||||||
? null
|
? null
|
||||||
: GetUserById(u.ParentId);
|
: GetUserById(u.ParentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Boolean IsRoot(User u)
|
public static Boolean IsRoot(this User u)
|
||||||
{
|
{
|
||||||
return u.ParentId == 0; // root has ParentId 0 by definition
|
return u.ParentId == 0; // root has ParentId 0 by definition
|
||||||
}
|
}
|
||||||
|
|
||||||
public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email);
|
public static Boolean HasDirectAccessToFolder(this User user, Folder folder)
|
||||||
|
{
|
||||||
|
return HasDirectAccessToFolder(user, folder.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean HasDirectAccessToFolder(this User user, Int64 folderId)
|
||||||
|
{
|
||||||
|
return User2Folder.Any(r => r.FolderId == folderId && r.UserId == user.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean HasAccessToFolder(this User user, Int64 folderId)
|
||||||
|
{
|
||||||
|
var folder = GetFolderById(folderId);
|
||||||
|
if (folder is null)
|
||||||
|
return false;
|
||||||
|
|
||||||
public Int64 CreateUser(User user)
|
return Ancestors(folder).Any(f => HasDirectAccessToFolder(user, f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email);
|
||||||
|
|
||||||
|
public static Int64 CreateUser(User user)
|
||||||
{
|
{
|
||||||
if (GetUserByEmail(user.Email) is not null)
|
if (GetUserByEmail(user.Email) is not null)
|
||||||
return -1; // TODO: User with that email already exists
|
return -1; // TODO: User with that email already exists
|
||||||
|
@ -69,13 +87,12 @@ public partial class Db
|
||||||
|
|
||||||
private static Byte[] HmacSha256Digest(String message, String secret)
|
private static Byte[] HmacSha256Digest(String message, String secret)
|
||||||
{
|
{
|
||||||
var encoding = new UTF8Encoding();
|
var encoding = new UTF8Encoding();
|
||||||
var keyBytes = encoding.GetBytes(secret);
|
var keyBytes = encoding.GetBytes(secret);
|
||||||
var messageBytes = encoding.GetBytes(message);
|
var messageBytes = encoding.GetBytes(message);
|
||||||
var cryptographer = new HMACSHA256(keyBytes);
|
var cryptographer = new HMACSHA256(keyBytes);
|
||||||
|
|
||||||
var bytes = cryptographer.ComputeHash(messageBytes);
|
return cryptographer.ComputeHash(messageBytes);
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String BuildSignature(String method, String path, String data, Int64 time, String secret)
|
private static String BuildSignature(String method, String path, String data, Int64 time, String secret)
|
||||||
|
@ -93,7 +110,6 @@ public partial class Db
|
||||||
|
|
||||||
Console.WriteLine("Message to sign:\n" + messageToSign);
|
Console.WriteLine("Message to sign:\n" + messageToSign);
|
||||||
|
|
||||||
|
|
||||||
var hmac = HmacSha256Digest(messageToSign, secret);
|
var hmac = HmacSha256Digest(messageToSign, secret);
|
||||||
return Convert.ToBase64String(hmac);
|
return Convert.ToBase64String(hmac);
|
||||||
}
|
}
|
||||||
|
@ -149,7 +165,7 @@ public partial class Db
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public Object? CreateAndSaveInstallationS3ApiKey(Installation installation)
|
public static Object CreateAndSaveInstallationS3ApiKey(Installation installation)
|
||||||
{
|
{
|
||||||
//EXOSCALE API URL
|
//EXOSCALE API URL
|
||||||
const String url = "https://api-ch-dk-2.exoscale.com/v2/";
|
const String url = "https://api-ch-dk-2.exoscale.com/v2/";
|
||||||
|
@ -192,7 +208,7 @@ public partial class Db
|
||||||
return newKey;
|
return newKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean UpdateUser(User user)
|
public static Boolean UpdateUser(User user)
|
||||||
{
|
{
|
||||||
var oldUser = GetUserById(user.Id);
|
var oldUser = GetUserById(user.Id);
|
||||||
if (oldUser == null)
|
if (oldUser == null)
|
||||||
|
@ -208,7 +224,7 @@ public partial class Db
|
||||||
return Update(user);
|
return Update(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean DeleteUser(User user)
|
public static Boolean DeleteUser(User user)
|
||||||
{
|
{
|
||||||
User2Folder.Delete(u => u.UserId == user.Id);
|
User2Folder.Delete(u => u.UserId == user.Id);
|
||||||
User2Installation.Delete(u => u.UserId == user.Id);
|
User2Installation.Delete(u => u.UserId == user.Id);
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
using InnovEnergy.App.Backend.Model.Relations;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
|
||||||
|
|
||||||
public partial class Db
|
|
||||||
{
|
|
||||||
private TableQuery<User2Folder> User2Folder => _Db.Table<User2Folder>();
|
|
||||||
public Int32 NbUser2Folder => User2Folder.Count();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
using InnovEnergy.App.Backend.Model.Relations;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
|
||||||
|
|
||||||
public partial class Db
|
|
||||||
{
|
|
||||||
private TableQuery<User2Installation> User2Installation => _Db.Table<User2Installation>();
|
|
||||||
public Int32 NbUser2Installation => User2Installation.Count();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum Endianness
|
|
||||||
{
|
|
||||||
LittleEndian32BitIntegers = 0,
|
|
||||||
LittleEndian32Floats = 0,
|
|
||||||
BigEndian32BitIntegers = 1,
|
|
||||||
BigEndian32Floats = 2,
|
|
||||||
}
|
|
|
@ -1,6 +1,8 @@
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
||||||
using static InnovEnergy.Lib.Protocols.Modbus.Clients.Endianness;
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol;
|
||||||
|
using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness;
|
||||||
|
using static InnovEnergy.Lib.Protocols.Modbus.Protocol.RegisterIndexing;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||||
|
|
||||||
|
@ -11,9 +13,10 @@ using Coils = IReadOnlyList<Boolean>;
|
||||||
|
|
||||||
public abstract class ModbusClient
|
public abstract class ModbusClient
|
||||||
{
|
{
|
||||||
protected ModbusConnection Connection { get; }
|
protected ModbusConnection Connection { get; }
|
||||||
protected Byte SlaveId { get; }
|
protected Byte SlaveId { get; }
|
||||||
protected Endianness Endianness { get; }
|
protected RegisterIndexing RegisterIndexing { get; }
|
||||||
|
protected MultiRegisterEndianness Endianness { get; }
|
||||||
|
|
||||||
|
|
||||||
// TODO: add additional functions: coils...
|
// TODO: add additional functions: coils...
|
||||||
|
@ -41,12 +44,20 @@ public abstract class ModbusClient
|
||||||
return WriteRegisters(writeAddress, (IReadOnlyList<UInt16>)values);
|
return WriteRegisters(writeAddress, (IReadOnlyList<UInt16>)values);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ModbusClient(ModbusConnection connection, Byte slaveId, Endianness endianness = LittleEndian32BitIntegers | LittleEndian32Floats)
|
protected ModbusClient(ModbusConnection connection,
|
||||||
|
Byte slaveId,
|
||||||
|
RegisterIndexing registerIndexing = OneBased,
|
||||||
|
MultiRegisterEndianness endianness = LittleEndian)
|
||||||
{
|
{
|
||||||
Connection = connection;
|
Connection = connection;
|
||||||
SlaveId = slaveId;
|
SlaveId = slaveId;
|
||||||
Endianness = endianness;
|
RegisterIndexing = registerIndexing;
|
||||||
|
Endianness = endianness;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseConnection() => Connection.Close();
|
public void CloseConnection() => Connection.Close();
|
||||||
}
|
|
||||||
|
protected UInt16 LogicToWire(UInt16 address) => RegisterIndexing.LogicToSerialized(address);
|
||||||
|
protected UInt16 SerializedToLogic(UInt16 address) => RegisterIndexing.SerializedToLogic(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,9 @@ public class ModbusRtuClient : ModbusClient
|
||||||
|
|
||||||
public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues)
|
public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues)
|
||||||
{
|
{
|
||||||
var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues);
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
|
|
||||||
|
var cmd = new ReadInputRegistersCommandFrame(SlaveId, wireReadAddress, nValues);
|
||||||
var crc = CalcCrc(cmd);
|
var crc = CalcCrc(cmd);
|
||||||
|
|
||||||
// TX
|
// TX
|
||||||
|
@ -54,7 +56,9 @@ public class ModbusRtuClient : ModbusClient
|
||||||
|
|
||||||
public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues)
|
public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues)
|
||||||
{
|
{
|
||||||
var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues);
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
|
|
||||||
|
var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, wireReadAddress, nValues);
|
||||||
var crc = CalcCrc(cmd.Data);
|
var crc = CalcCrc(cmd.Data);
|
||||||
|
|
||||||
// TX
|
// TX
|
||||||
|
@ -82,7 +86,9 @@ public class ModbusRtuClient : ModbusClient
|
||||||
|
|
||||||
public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values)
|
public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values)
|
||||||
{
|
{
|
||||||
var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values);
|
var wireWriteAddress = LogicToWire(writeAddress);
|
||||||
|
|
||||||
|
var cmd = new WriteRegistersCommandFrame(SlaveId, wireWriteAddress, values);
|
||||||
var crc = CalcCrc(cmd);
|
var crc = CalcCrc(cmd);
|
||||||
var nToRead = cmd.ExpectedResponseSize + CrcSize;
|
var nToRead = cmd.ExpectedResponseSize + CrcSize;
|
||||||
|
|
||||||
|
@ -105,10 +111,16 @@ public class ModbusRtuClient : ModbusClient
|
||||||
|
|
||||||
public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite)
|
public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite)
|
||||||
{
|
{
|
||||||
var cmd = new ReadWriteRegistersCommandFrame(SlaveId, readAddress, nbToRead, writeAddress, registersToWrite);
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
|
var wireWriteAddress = LogicToWire(writeAddress);
|
||||||
|
|
||||||
|
var cmd = new ReadWriteRegistersCommandFrame(SlaveId,
|
||||||
|
wireReadAddress,
|
||||||
|
nbToRead,
|
||||||
|
wireWriteAddress,
|
||||||
|
registersToWrite);
|
||||||
var crc = CalcCrc(cmd);
|
var crc = CalcCrc(cmd);
|
||||||
|
|
||||||
|
|
||||||
// TX
|
// TX
|
||||||
cmd.Data.Concat(crc).Apply(Connection.Transmit);
|
cmd.Data.Concat(crc).Apply(Connection.Transmit);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands;
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies;
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Tcp;
|
using InnovEnergy.Lib.Protocols.Modbus.Tcp;
|
||||||
using static InnovEnergy.Lib.Protocols.Modbus.Clients.Endianness;
|
using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||||
|
|
||||||
|
@ -20,16 +21,21 @@ public class ModbusTcpClient : ModbusClient
|
||||||
private UInt16 NextId() => unchecked(++_Id);
|
private UInt16 NextId() => unchecked(++_Id);
|
||||||
|
|
||||||
|
|
||||||
public ModbusTcpClient(ModbusConnection connection, Byte slaveId, Endianness endianness = LittleEndian32BitIntegers | LittleEndian32Floats) : base(connection, slaveId, endianness)
|
public ModbusTcpClient(ModbusConnection connection,
|
||||||
|
Byte slaveId,
|
||||||
|
RegisterIndexing registerIndexing = RegisterIndexing.OneBased,
|
||||||
|
MultiRegisterEndianness endianness = LittleEndian) : base(connection, slaveId, registerIndexing, endianness)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override IReadOnlyList<Boolean> ReadDiscreteInputs(UInt16 readAddress, UInt16 nValues)
|
public override IReadOnlyList<Boolean> ReadDiscreteInputs(UInt16 readAddress, UInt16 nValues)
|
||||||
{
|
{
|
||||||
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
|
|
||||||
var id = NextId(); // TODO: check response id
|
var id = NextId(); // TODO: check response id
|
||||||
|
|
||||||
var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, readAddress, nValues);
|
var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, wireReadAddress, nValues);
|
||||||
var hdr = new MbapHeader(id, cmd.Data.Count);
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
||||||
var frm = new ModbusTcpFrame(hdr, cmd);
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
||||||
|
|
||||||
|
@ -46,9 +52,10 @@ public class ModbusTcpClient : ModbusClient
|
||||||
|
|
||||||
public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues)
|
public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues)
|
||||||
{
|
{
|
||||||
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
var id = NextId(); // TODO: check response id
|
var id = NextId(); // TODO: check response id
|
||||||
|
|
||||||
var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues);
|
var cmd = new ReadInputRegistersCommandFrame(SlaveId, wireReadAddress, nValues);
|
||||||
var hdr = new MbapHeader(id, cmd.Data.Count);
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
||||||
var frm = new ModbusTcpFrame(hdr, cmd);
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
||||||
|
|
||||||
|
@ -65,12 +72,15 @@ public class ModbusTcpClient : ModbusClient
|
||||||
return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray());
|
return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues)
|
public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues)
|
||||||
{
|
{
|
||||||
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
|
|
||||||
var id = NextId(); // TODO: check response id
|
var id = NextId(); // TODO: check response id
|
||||||
|
var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, wireReadAddress, nValues);
|
||||||
var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues);
|
|
||||||
var hdr = new MbapHeader(id, cmd.Data.Count);
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
||||||
var frm = new ModbusTcpFrame(hdr, cmd);
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
||||||
|
|
||||||
|
@ -84,14 +94,15 @@ public class ModbusTcpClient : ModbusClient
|
||||||
|
|
||||||
var verified = cmd.VerifyResponse(rxFrm);
|
var verified = cmd.VerifyResponse(rxFrm);
|
||||||
|
|
||||||
return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray());
|
return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
public override UInt16 WriteMultipleCoils(UInt16 writeAddress, Coils coils)
|
public override UInt16 WriteMultipleCoils(UInt16 writeAddress, Coils coils)
|
||||||
{
|
{
|
||||||
|
var wireWriteAddress = LogicToWire(writeAddress);
|
||||||
|
|
||||||
var id = NextId(); // TODO: check response id
|
var id = NextId(); // TODO: check response id
|
||||||
|
var cmd = new WriteCoilsCommandFrame(SlaveId, wireWriteAddress, coils);
|
||||||
var cmd = new WriteCoilsCommandFrame(SlaveId, writeAddress, coils);
|
|
||||||
var hdr = new MbapHeader(id, cmd.Data.Count);
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
||||||
var frm = new ModbusTcpFrame(hdr, cmd);
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
||||||
|
|
||||||
|
@ -109,9 +120,10 @@ public class ModbusTcpClient : ModbusClient
|
||||||
|
|
||||||
public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values)
|
public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values)
|
||||||
{
|
{
|
||||||
|
var wireWriteAddress = LogicToWire(writeAddress);
|
||||||
|
|
||||||
var id = NextId(); // TODO: check response id
|
var id = NextId(); // TODO: check response id
|
||||||
|
var cmd = new WriteRegistersCommandFrame(SlaveId, wireWriteAddress, values);
|
||||||
var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values);
|
|
||||||
var hdr = new MbapHeader(id, cmd.Data.Count);
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
||||||
var frm = new ModbusTcpFrame(hdr, cmd);
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
||||||
|
|
||||||
|
@ -130,9 +142,17 @@ public class ModbusTcpClient : ModbusClient
|
||||||
|
|
||||||
public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite)
|
public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite)
|
||||||
{
|
{
|
||||||
|
var wireReadAddress = LogicToWire(readAddress);
|
||||||
|
var wireWriteAddress = LogicToWire(writeAddress);
|
||||||
|
|
||||||
var id = NextId(); // TODO: check response id
|
var id = NextId(); // TODO: check response id
|
||||||
|
|
||||||
var cmd = new ReadWriteRegistersCommandFrame(SlaveId, readAddress, nbToRead, writeAddress, registersToWrite);
|
var cmd = new ReadWriteRegistersCommandFrame(SlaveId,
|
||||||
|
wireReadAddress,
|
||||||
|
nbToRead,
|
||||||
|
wireWriteAddress,
|
||||||
|
registersToWrite);
|
||||||
|
|
||||||
var hdr = new MbapHeader(id, cmd.Data.Count);
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
||||||
var frm = new ModbusTcpFrame(hdr, cmd);
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
||||||
|
|
||||||
|
@ -146,7 +166,7 @@ public class ModbusTcpClient : ModbusClient
|
||||||
|
|
||||||
var verified = cmd.VerifyResponse(rxFrm);
|
var verified = cmd.VerifyResponse(rxFrm);
|
||||||
|
|
||||||
return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray());
|
return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,16 +2,9 @@ namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors;
|
||||||
|
|
||||||
public static class Accessors
|
public static class Accessors
|
||||||
{
|
{
|
||||||
public static MbByte ByteAt(this Byte[] data, Byte i) => new MbByte(new ArraySegment<Byte>(data), i);
|
|
||||||
public static MbWord WordAt(this Byte[] data, Byte i) => new MbWord(new ArraySegment<Byte>(data), i);
|
|
||||||
|
|
||||||
public static MbByte ByteAt (this ArraySegment<Byte> data, Byte i) => new MbByte(data, i);
|
public static MbByte ByteAt (this ArraySegment<Byte> data, Byte i) => new MbByte(data, i);
|
||||||
public static MbWord WordAt (this ArraySegment<Byte> data, Byte i) => new MbWord(data, i);
|
public static MbWord WordAt (this ArraySegment<Byte> data, Byte i) => new MbWord(data, i);
|
||||||
public static MbAddress AddressAt(this ArraySegment<Byte> data, Byte i) => new MbAddress(data, i);
|
public static MbWords WordsAt (this ArraySegment<Byte> data, Byte i) => new MbWords(data, i);
|
||||||
|
public static MbBits BitsAt (this ArraySegment<Byte> data, Byte i) => new MbBits(data, i);
|
||||||
public static MbRegisters RegistersAt(this ArraySegment<Byte> data, Byte i) => new MbRegisters(data, i);
|
|
||||||
public static MbBits BitsAt (this ArraySegment<Byte> data, Byte i) => new MbBits(data, i);
|
|
||||||
|
|
||||||
|
|
||||||
public static MbByte<T> ByteAt<T>(this ArraySegment<Byte> data,Byte i) where T : struct, IConvertible => new MbByte<T>(data, i);
|
public static MbByte<T> ByteAt<T>(this ArraySegment<Byte> data,Byte i) where T : struct, IConvertible => new MbByte<T>(data, i);
|
||||||
}
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors;
|
|
||||||
|
|
||||||
public readonly struct MbAddress
|
|
||||||
{
|
|
||||||
private readonly MbWord _MbWord;
|
|
||||||
|
|
||||||
internal MbAddress(ArraySegment<Byte> data, Byte index)
|
|
||||||
{
|
|
||||||
_MbWord = new MbWord(data, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal UInt16 Get() => (UInt16)(_MbWord.Get() + 1);
|
|
||||||
|
|
||||||
internal UInt16 Set(UInt16 address) => _MbWord.Set(address - 1);
|
|
||||||
internal UInt16 Set(IConvertible value) => value.ConvertTo<UInt16>().Apply(Set);
|
|
||||||
|
|
||||||
public static implicit operator UInt16(MbAddress w) => w.Get();
|
|
||||||
|
|
||||||
public override String ToString() => Get().ToString();
|
|
||||||
}
|
|
|
@ -1,75 +1,105 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness;
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors;
|
namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors;
|
||||||
|
|
||||||
public readonly struct MbRegisters : IReadOnlyList<UInt16>
|
using Float32 = Single;
|
||||||
|
|
||||||
|
public struct MbRegisters : IReadOnlyList<UInt16>
|
||||||
{
|
{
|
||||||
private readonly ArraySegment<Byte> _Data;
|
private MbWords Words { get; }
|
||||||
|
private UInt16 StartRegister { get; }
|
||||||
internal MbRegisters(ArraySegment<Byte> data, Byte startIndex) : this(data, startIndex, CountWords(data, startIndex))
|
private MultiRegisterEndianness Endianness { get; }
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal MbRegisters(ArraySegment<Byte> data, Byte startIndex, UInt16 wordCount) : this(data.Array!, startIndex, wordCount)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MbRegisters(Byte[] data, Byte startIndex, UInt16 wordCount)
|
|
||||||
{
|
|
||||||
_Data = new ArraySegment<Byte>(data, startIndex, wordCount * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UInt16 CountWords(ArraySegment<Byte> data, Byte startIndex)
|
public MbRegisters(MbWords words,
|
||||||
|
UInt16 startRegister,
|
||||||
|
MultiRegisterEndianness endianness,
|
||||||
|
RegisterIndexing registerIndexing)
|
||||||
{
|
{
|
||||||
var wordCount = (data.Count - startIndex) / 2;
|
Words = words;
|
||||||
return wordCount.ConvertTo<UInt16>();
|
Endianness = endianness;
|
||||||
|
|
||||||
|
var start = startRegister - (Int16) registerIndexing; // TODO: check
|
||||||
|
|
||||||
|
if (start < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(startRegister));
|
||||||
|
|
||||||
|
StartRegister = (UInt16)start;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IReadOnlyCollection<UInt16> Set(IReadOnlyCollection<UInt16> values)
|
public IEnumerator<UInt16> GetEnumerator() => Words.GetEnumerator();
|
||||||
{
|
|
||||||
if (values.Count != _Data.Count / 2)
|
|
||||||
throw new ArgumentException($"Expecting an list of size {values.Count}!", nameof(values));
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
foreach (var value in values)
|
|
||||||
{
|
|
||||||
_Data[i++] = (Byte) (value >> 8);
|
|
||||||
_Data[i++] = (Byte) (value & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public IEnumerator<UInt16> GetEnumerator()
|
|
||||||
{
|
|
||||||
var end = _Data.Count;
|
|
||||||
|
|
||||||
for (var i = 0; i < end; )
|
|
||||||
{
|
|
||||||
var hi = _Data[i++] << 8;
|
|
||||||
var lo = _Data[i++];
|
|
||||||
|
|
||||||
yield return (UInt16) (hi | lo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
public Int32 Count => _Data.Count / 2;
|
public Int32 Count => Words.Count;
|
||||||
|
|
||||||
public UInt16 this[Int32 index]
|
public UInt16 this[Int32 index] => Words[index];
|
||||||
|
|
||||||
|
private Byte MapIndex(UInt16 index)
|
||||||
{
|
{
|
||||||
get
|
var i = index - StartRegister;
|
||||||
{
|
if (i is < Byte.MinValue or > Byte.MaxValue)
|
||||||
var i = index * 2;
|
throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
var hi = _Data[i] << 8;
|
return (Byte)i;
|
||||||
var lo = _Data[i+1];
|
|
||||||
|
|
||||||
return (UInt16) (hi | lo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UInt16 GetUInt16(UInt16 index)
|
||||||
|
{
|
||||||
|
return index
|
||||||
|
.Apply(MapIndex)
|
||||||
|
.Apply(Words.GetUInt16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUInt16(UInt16 index, UInt16 value)
|
||||||
|
{
|
||||||
|
Words.SetUInt16(MapIndex(index), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Int16 GetInt16(UInt16 index)
|
||||||
|
{
|
||||||
|
return (Int16) GetUInt16(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUInt16(UInt16 index, Int16 value)
|
||||||
|
{
|
||||||
|
SetUInt16(index, (UInt16)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 GetUInt32(UInt16 index)
|
||||||
|
{
|
||||||
|
var i = MapIndex(index);
|
||||||
|
|
||||||
|
var hi = (UInt32) GetUInt16(i);
|
||||||
|
var lo = (UInt32) GetUInt16(++i);
|
||||||
|
|
||||||
|
if (Endianness == LittleEndian)
|
||||||
|
(lo, hi) = (hi, lo);
|
||||||
|
|
||||||
|
return hi << 16 | lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// public void SetUInt32(UInt32 index, UInt32 value)
|
||||||
|
|
||||||
|
public Int32 GetInt32(UInt16 index) => (Int32)GetUInt32(index);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// public void SetInt32(Int32 index, Int32 value)
|
||||||
|
|
||||||
|
|
||||||
|
public Float32 GetFloat32(UInt16 index)
|
||||||
|
{
|
||||||
|
return index
|
||||||
|
.Apply(GetInt32)
|
||||||
|
.Apply(BitConverter.Int32BitsToSingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// public void SetFloat32(Float32 index, Float32 value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
using System.Collections;
|
||||||
|
using InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
|
namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors;
|
||||||
|
|
||||||
|
public readonly struct MbWords : IReadOnlyList<UInt16>
|
||||||
|
{
|
||||||
|
internal readonly ArraySegment<Byte> Data;
|
||||||
|
|
||||||
|
internal MbWords(ArraySegment<Byte> data, Byte startIndex = 0) :
|
||||||
|
this(data, startIndex, CountWords(data, startIndex))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
internal MbWords(ArraySegment<Byte> data, Byte startIndex, UInt16 wordCount)
|
||||||
|
{
|
||||||
|
Data = new ArraySegment<Byte>(data.Array!, startIndex + data.Offset, wordCount * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UInt16 CountWords(ArraySegment<Byte> data, Byte startIndex)
|
||||||
|
{
|
||||||
|
var wordCount = (data.Count - startIndex) / 2;
|
||||||
|
return wordCount.ConvertTo<UInt16>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IReadOnlyCollection<UInt16> Set(IReadOnlyCollection<UInt16> values)
|
||||||
|
{
|
||||||
|
if (values.Count != Data.Count / 2)
|
||||||
|
throw new ArgumentException($"Expecting an list of size {values.Count}!", nameof(values));
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
Data[i++] = (Byte) (value >> 8);
|
||||||
|
Data[i++] = (Byte) (value & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IEnumerator<UInt16> GetEnumerator()
|
||||||
|
{
|
||||||
|
var end = Data.Count;
|
||||||
|
|
||||||
|
for (var i = 0; i < end; )
|
||||||
|
{
|
||||||
|
var hi = Data[i++] << 8;
|
||||||
|
var lo = Data[i++];
|
||||||
|
|
||||||
|
yield return (UInt16) (hi | lo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
public Int32 Count => Data.Count / 2;
|
||||||
|
|
||||||
|
public UInt16 this[Int32 index]
|
||||||
|
{
|
||||||
|
// a single register is always big endian (according to standard)
|
||||||
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var i = index * 2;
|
||||||
|
|
||||||
|
var hi = Data[i] << 8;
|
||||||
|
var lo = Data[i+1];
|
||||||
|
|
||||||
|
return (UInt16) (hi | lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt16 GetUInt16(Byte index) => this[index];
|
||||||
|
|
||||||
|
public void SetUInt16(Byte index, UInt16 value)
|
||||||
|
{
|
||||||
|
var i = index * 2;
|
||||||
|
Data[i + 0] = (Byte)(value >> 8);
|
||||||
|
Data[i + 1] = (Byte)(value & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,8 +13,8 @@ internal class ReadDiscreteInputsCommandFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
private const Int32 Size = 6;
|
private const Int32 Size = 6;
|
||||||
|
|
||||||
private MbAddress ReadAddress => Data.AddressAt(2);
|
private MbWord ReadAddress => Data.WordAt(2);
|
||||||
private MbWord QuantityOfInputs => Data.WordAt(4);
|
private MbWord QuantityOfInputs => Data.WordAt(4);
|
||||||
|
|
||||||
|
|
||||||
public ReadDiscreteInputsCommandFrame(Byte slave, UInt16 readAddress, UInt16 nBits) : base(Size)
|
public ReadDiscreteInputsCommandFrame(Byte slave, UInt16 readAddress, UInt16 nBits) : base(Size)
|
||||||
|
|
|
@ -14,8 +14,8 @@ internal class ReadHoldingRegistersCommandFrame : ModbusFrame
|
||||||
|
|
||||||
internal const Int32 Size = 6;
|
internal const Int32 Size = 6;
|
||||||
|
|
||||||
public MbAddress ReadAddress => Data.AddressAt(2);
|
public MbWord ReadAddress => Data.WordAt(2);
|
||||||
public MbWord NbToRead => Data.WordAt(4);
|
public MbWord NbToRead => Data.WordAt(4);
|
||||||
|
|
||||||
public Int32 ExpectedResponseSize => ReadHoldingRegistersResponseFrame.ExpectedSize(NbToRead);
|
public Int32 ExpectedResponseSize => ReadHoldingRegistersResponseFrame.ExpectedSize(NbToRead);
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ internal class ReadInputRegistersCommandFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
internal const Int32 Size = 6;
|
internal const Int32 Size = 6;
|
||||||
|
|
||||||
public MbAddress ReadAddress => Data.AddressAt(2);
|
public MbWord ReadAddress => Data.WordAt(2);
|
||||||
public MbWord NbToRead => Data.WordAt(4);
|
public MbWord NbToRead => Data.WordAt(4);
|
||||||
|
|
||||||
public Int32 ExpectedResponseSize => ReadInputRegistersResponseFrame.ExpectedSize(NbToRead);
|
public Int32 ExpectedResponseSize => ReadInputRegistersResponseFrame.ExpectedSize(NbToRead);
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ internal class ReadWriteRegistersCommandFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
internal new const Int32 MinSize = 11;
|
internal new const Int32 MinSize = 11;
|
||||||
|
|
||||||
public MbAddress ReadAddress => Data.AddressAt(2);
|
public MbWord ReadAddress => Data.WordAt(2);
|
||||||
public MbWord NbToRead => Data.WordAt(4);
|
public MbWord NbToRead => Data.WordAt(4);
|
||||||
public MbAddress WriteAddress => Data.AddressAt(6);
|
public MbWord WriteAddress => Data.WordAt(6);
|
||||||
public MbWord NbToWrite => Data.WordAt(8);
|
public MbWord NbToWrite => Data.WordAt(8);
|
||||||
public MbByte ByteCount => Data.ByteAt(10);
|
public MbByte ByteCount => Data.ByteAt(10);
|
||||||
public MbRegisters RegistersToWrite => Data.RegistersAt(11);
|
public MbWords RegistersToWrite => Data.WordsAt(11);
|
||||||
|
|
||||||
public Int32 ExpectedResponseSize => ReadWriteRegistersResponseFrame.ExpectedSize(NbToRead);
|
public Int32 ExpectedResponseSize => ReadWriteRegistersResponseFrame.ExpectedSize(NbToRead);
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ public class WriteCoilsCommandFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
private new const Int32 MinSize = 7;
|
private new const Int32 MinSize = 7;
|
||||||
|
|
||||||
private MbAddress WriteAddress => Data.AddressAt(2);
|
private MbWord WriteAddress => Data.WordAt(2);
|
||||||
private MbWord NbOfCoils => Data.WordAt(4);
|
private MbWord NbOfCoils => Data.WordAt(4);
|
||||||
private MbByte ByteCount => Data.ByteAt(6);
|
private MbByte ByteCount => Data.ByteAt(6);
|
||||||
public MbBits CoilsToWrite => Data.BitsAt(7);
|
public MbBits CoilsToWrite => Data.BitsAt(7);
|
||||||
|
|
||||||
public WriteCoilsCommandFrame(Byte slave, UInt16 writeAddress, Booleans coils) : base(MinSize + NbBytes(coils))
|
public WriteCoilsCommandFrame(Byte slave, UInt16 writeAddress, Booleans coils) : base(MinSize + NbBytes(coils))
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,10 +11,10 @@ internal class WriteRegistersCommandFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
internal new const Int32 MinSize = 7;
|
internal new const Int32 MinSize = 7;
|
||||||
|
|
||||||
public MbAddress WriteAddress => Data.AddressAt(2);
|
public MbWord WriteAddress => Data.WordAt(2);
|
||||||
public MbWord NbOfRegisters => Data.WordAt(4);
|
public MbWord NbOfRegisters => Data.WordAt(4);
|
||||||
public MbByte ByteCount => Data.ByteAt(6);
|
public MbByte ByteCount => Data.ByteAt(6);
|
||||||
public MbRegisters RegistersToWrite => Data.RegistersAt(7);
|
public MbWords RegistersToWrite => Data.WordsAt(7);
|
||||||
|
|
||||||
public Int32 ExpectedResponseSize => WriteRegistersResponseFrame.ExpectedSize();
|
public Int32 ExpectedResponseSize => WriteRegistersResponseFrame.ExpectedSize();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class ModbusFrame
|
||||||
|
|
||||||
internal ModbusFrame(Int32 size)
|
internal ModbusFrame(Int32 size)
|
||||||
{
|
{
|
||||||
Data = new ArraySegment<Byte>(new Byte[size]);
|
Data = new Byte[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ internal class ReadHoldingRegistersResponseFrame : ModbusFrame
|
||||||
internal new const Int32 MinSize = 3;
|
internal new const Int32 MinSize = 3;
|
||||||
|
|
||||||
public MbByte ByteCount => Data.ByteAt(2);
|
public MbByte ByteCount => Data.ByteAt(2);
|
||||||
public MbRegisters RegistersRead => Data.RegistersAt(3);
|
public MbWords RegistersRead => Data.WordsAt(3);
|
||||||
|
|
||||||
|
|
||||||
public ReadHoldingRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count))
|
public ReadHoldingRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count))
|
||||||
|
|
|
@ -12,7 +12,7 @@ internal class ReadInputRegistersResponseFrame : ModbusFrame
|
||||||
internal new const Int32 MinSize = 3;
|
internal new const Int32 MinSize = 3;
|
||||||
|
|
||||||
public MbByte ByteCount => Data.ByteAt(2);
|
public MbByte ByteCount => Data.ByteAt(2);
|
||||||
public MbRegisters RegistersRead => Data.RegistersAt(3);
|
public MbWords RegistersRead => Data.WordsAt(3);
|
||||||
|
|
||||||
public ReadInputRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count))
|
public ReadInputRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count))
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@ internal class ReadWriteRegistersResponseFrame : ModbusFrame
|
||||||
internal new const Int32 MinSize = 3;
|
internal new const Int32 MinSize = 3;
|
||||||
|
|
||||||
public MbByte ByteCount => Data.ByteAt(2);
|
public MbByte ByteCount => Data.ByteAt(2);
|
||||||
public MbRegisters RegistersRead => Data.RegistersAt(3);
|
public MbWords RegistersRead => Data.WordsAt(3);
|
||||||
|
|
||||||
public ReadWriteRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count))
|
public ReadWriteRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count))
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,8 +7,8 @@ public class WriteCoilsResponseFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
private const Int32 Size = 6;
|
private const Int32 Size = 6;
|
||||||
|
|
||||||
public MbAddress WriteAddress => Data.AddressAt(2);
|
public MbWord WriteAddress => Data.WordAt(2);
|
||||||
public MbWord NbWritten => Data.WordAt(4);
|
public MbWord NbWritten => Data.WordAt(4);
|
||||||
|
|
||||||
internal static Int32 ExpectedSize() => Size;
|
internal static Int32 ExpectedSize() => Size;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ internal class WriteRegistersResponseFrame : ModbusFrame
|
||||||
{
|
{
|
||||||
private const Int32 Size = 6;
|
private const Int32 Size = 6;
|
||||||
|
|
||||||
public MbAddress WriteAddress => Data.AddressAt(2);
|
public MbWord WriteAddress => Data.WordAt(2);
|
||||||
public MbWord NbWritten => Data.WordAt(4);
|
public MbWord NbWritten => Data.WordAt(4);
|
||||||
|
|
||||||
internal static Int32 ExpectedSize() => Size;
|
internal static Int32 ExpectedSize() => Size;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue