Skip to content

Commit

Permalink
Made PiJuiceInterface thread safe
Browse files Browse the repository at this point in the history
  • Loading branch information
mikegoatly committed Sep 9, 2023
1 parent eff90a3 commit 5718266
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 9 deletions.
152 changes: 152 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
[ "*.cs" ]

# IDE0058: Expression value is never used
dotnet_diagnostic.IDE0058.severity = none
csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = true:silent

[*.{cs,vb}]
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
end_of_line = crlf
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
[*.cs]
#### Naming styles ####

# Naming rules

dotnet_naming_rule.private_or_internal_field_should_be_camelcase.severity = suggestion
dotnet_naming_rule.private_or_internal_field_should_be_camelcase.symbols = private_or_internal_field
dotnet_naming_rule.private_or_internal_field_should_be_camelcase.style = camelcase

dotnet_naming_rule.private_or_internal_static_field_should_be_camelcase.severity = suggestion
dotnet_naming_rule.private_or_internal_static_field_should_be_camelcase.symbols = private_or_internal_static_field
dotnet_naming_rule.private_or_internal_static_field_should_be_camelcase.style = camelcase

# Symbol specifications

dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field
dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected
dotnet_naming_symbols.private_or_internal_field.required_modifiers =

dotnet_naming_symbols.private_or_internal_static_field.applicable_kinds = field
dotnet_naming_symbols.private_or_internal_static_field.applicable_accessibilities = internal, private, private_protected
dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = static

# Naming styles

dotnet_naming_style.camelcase.required_prefix =
dotnet_naming_style.camelcase.required_suffix =
dotnet_naming_style.camelcase.word_separator =
dotnet_naming_style.camelcase.capitalization = camel_case

dotnet_naming_style.camelcase.required_prefix =
dotnet_naming_style.camelcase.required_suffix =
dotnet_naming_style.camelcase.word_separator =
dotnet_naming_style.camelcase.capitalization = camel_case
csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = true:silent

[*.{cs,vb}]
#### Naming styles ####

# Naming rules

dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i

dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case

dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case

# Symbol specifications

dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =

dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =

dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =

# Naming styles

dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case

dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case

dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_qualification_for_field = true:suggestion
dotnet_style_qualification_for_property = true:suggestion
dotnet_style_qualification_for_method = true:suggestion
dotnet_style_qualification_for_event = true:suggestion

# Constants are UPPERCASE
dotnet_naming_rule.constants_should_be_upper_case.severity = suggestion
dotnet_naming_rule.constants_should_be_upper_case.symbols = constants
dotnet_naming_rule.constants_should_be_upper_case.style = constant_style

dotnet_naming_symbols.constants.applicable_kinds = field, local
dotnet_naming_symbols.constants.required_modifiers = const

dotnet_naming_style.constant_style.capitalization = all_upper
1 change: 1 addition & 0 deletions PiJuiceSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PiJuiceSharp", "PiJuiceShar
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{122F1D51-9A0D-4EB8-AC69-CC1992705310}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
.github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml
docs\favicon-256.png = docs\favicon-256.png
Expand Down
35 changes: 31 additions & 4 deletions PiJuiceSharp/PiJuiceInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ namespace PiJuiceSharp
{
public sealed class PiJuiceInterface : IDisposable
{
private static readonly SemaphoreSlim semaphore = new(1, 1);
private readonly I2cDevice i2cDevice;
private readonly int address;


public PiJuiceInterface(int busId = 1, int deviceAddress = 0x14)
{
var settings = new I2cConnectionSettings(busId, deviceAddress);
Expand All @@ -22,26 +24,39 @@ public void Dispose()
public byte Read(byte command)
{
Span<byte> readBuffer = stackalloc byte[1];
Read(command, readBuffer);
this.Read(command, readBuffer);
return readBuffer[0];
}

public (byte, byte) ReadPair(byte command)
{
Span<byte> readBuffer = stackalloc byte[2];
Read(command, readBuffer);
this.Read(command, readBuffer);
return (readBuffer[0], readBuffer[1]);
}

public void Read(byte command, Span<byte> readBuffer)
{
try
{

Span<byte> writeBuffer = stackalloc byte[1];

writeBuffer[0] = command;

this.i2cDevice.WriteRead(writeBuffer, readBuffer);
if (!semaphore.Wait(1000))
{
throw new PiJuiceException("COMMUNICATION_TIMEOUT");
}

try
{
this.i2cDevice.WriteRead(writeBuffer, readBuffer);
}
finally
{
_ = semaphore.Release();
}
}
catch (IOException ex)
{
Expand All @@ -58,7 +73,19 @@ public void Write(byte command, Span<byte> data)
data.CopyTo(writeBuffer[1..]);
writeBuffer[^1] = GetChecksum(data);

this.i2cDevice.Write(writeBuffer);
if (!semaphore.Wait(1000))
{
throw new PiJuiceException("COMMUNICATION_TIMEOUT");
}

try
{
this.i2cDevice.Write(writeBuffer);
}
finally
{
_ = semaphore.Release();
}
}
catch (IOException ex)
{
Expand Down
3 changes: 2 additions & 1 deletion PiJuiceSharp/PiJuiceSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<AnalysisLevel>latest-all</AnalysisLevel>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<Version>0.1.0</Version>
<Version>0.2.0</Version>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
<None Include="..\docs\favicon-256.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
Expand Down
8 changes: 4 additions & 4 deletions PiJuiceSharp/PiJuiceStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,22 @@ public int GetBatteryTemperature()

public float GetBatteryVoltage()
{
return ReadFloat(BATTERY_VOLTAGE_CMD);
return this.ReadFloat(BATTERY_VOLTAGE_CMD);
}

public float GetBatteryCurrent()
{
return ReadSignedFloat(BATTERY_CURRENT_CMD);
return this.ReadSignedFloat(BATTERY_CURRENT_CMD);
}

public float GetGpioVoltage()
{
return ReadFloat(IO_VOLTAGE_CMD);
return this.ReadFloat(IO_VOLTAGE_CMD);
}

public float GetGpioCurrent()
{
return ReadSignedFloat(IO_CURRENT_CMD);
return this.ReadSignedFloat(IO_CURRENT_CMD);
}

public Dictionary<string, object> GetFaultStatus()
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,8 @@ public record struct LedBlinkState(byte Count, Color Rgb1, short Period1, Color
```

`SetLedBlinkState(Led led, LedBlinkState state)` sets the blinking state of either the `Led.D1` or `Led.D2` LED to the given `LedBlinkState`. (Note that if the LED is not in a user configurable state, this will have no effect.)

## Thread safety

By using a single `SemaphoreSlim` instance across all instances of `PiJuiceInterface`, the library guarantees that thread safety is enforced
when communicating with the PiJuice.

0 comments on commit 5718266

Please sign in to comment.