Pamoja.Hal 0.2.0

dotnet add package Pamoja.Hal --version 0.2.0
                    
NuGet\Install-Package Pamoja.Hal -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Pamoja.Hal" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pamoja.Hal" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Pamoja.Hal" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Pamoja.Hal --version 0.2.0
                    
#r "nuget: Pamoja.Hal, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Pamoja.Hal@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Pamoja.Hal&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Pamoja.Hal&version=0.2.0
                    
Install as a Cake Tool

Pamoja.Hal

The embedded-hal traits every driver takes, a bit-banged 1-Wire bus, simulated parts and scripted buses that stand in for hardware, the Linux backends over i2c-dev, spidev, and the GPIO character device, one I2C bus and one serial port a program and its drivers share, and delays that sleep or only count. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

read the guide documentation API reference

Install

dotnet add package Pamoja.Hal
using Pamoja.Hal;

This pulls in Pamoja.Native, the compiled engine. dotnet add package Pamoja is the whole framework in one package.

Example

The guide project's example, spliced here as it ran in CI.

From bindings/dotnet/samples/Pamoja.Guides/HalGuide.cs:

const byte Part = Bme280.AddressPrimary;
static string Fixed(float value) => value.ToString("F2", CultureInfo.InvariantCulture);
static string Shown(Bme280Measurement reading) =>
    $"{Fixed(reading.Celsius)} C, {Fixed(reading.Hectopascals)} hPa, {Fixed(reading.RelativeHumidityPercent)} %";
static string X(Bme280.Oversampling oversampling) => $"x{Bme280.OversamplingFactor(oversampling)}";

// A bus with one part on it: a BME280 that is not there. It holds a real part's
// calibration and one measurement that part took, and it answers from its registers,
// so the driver runs its whole datasheet sequence against it. On a Raspberry Pi the
// bus is I2cBus.Open("/dev/i2c-1") and nothing after this line changes.
using I2cPart simulated = Bme280.Sim.Part(Part);
using I2cBus bus = I2cBus.Simulated(simulated);
using var sensor = new Bme280(bus, Part);

// Reset, identify, calibrate, configure. The datasheet wants ctrl_hum written before
// ctrl_meas, and the part left asleep until a measurement is forced. The part keeps
// what the driver wrote, so the configuration reads back off the bus.
sensor.Init();
using I2cPart part = bus.Part<I2cPart>(Part)!;
Bme280.Oversampling humidity = Bme280.CtrlHumFromBits(part.Register(Bme280.Register.CtrlHum));
Bme280CtrlMeas ctrl = Bme280.CtrlMeasFromBits(part.Register(Bme280.Register.CtrlMeas));
bool asleep = ctrl.Mode == Bme280.Mode.Sleep;
Console.WriteLine(
    $"configured   humidity {X(humidity)}, temperature {X(ctrl.Temperature)}, " +
    $"pressure {X(ctrl.Pressure)}, asleep: {asleep.ToString().ToLowerInvariant()}");

// One forced measurement. The driver waits the datasheet's longest measurement time
// for these settings before it reads, and a simulated bus counts that wait rather
// than sleeping through it.
Bme280Measurement reading = sensor.Measure();
Console.WriteLine($"measured     {Shown(reading)}");
ulong waited = bus.WaitedMicros;
string waitedMs = (waited / 1000.0).ToString("F2", CultureInfo.InvariantCulture);
Console.WriteLine($"waited       {waitedMs} ms across {bus.Transfers} transfers");

// A part reports whatever it is asked to. Putting one in the first one's place is how
// a program meets a reading it would otherwise wait on the weather for, here a cold
// store at four degrees, and the driver carries on without noticing.
using (I2cPart chilled = Bme280.Sim.Reporting(Part, 4.0f, 1013.25f, 80.0f))
{
    bus.Attach(chilled);
}

Bme280Measurement cold = sensor.Measure();
Console.WriteLine($"cold store   {Shown(cold)}");

// Nothing answers at the part's other address, and the driver says so rather than
// returning a reading.
try
{
    using var absent = new Bme280(bus, Bme280.AddressSecondary);
    absent.Init();
    Console.WriteLine("absent       a part answered");
}
catch (PamojaException error)
{
    Console.WriteLine($"absent       {error.Message}");
}

// The other half of the bus layer. A script plays one conversation and refuses
// anything else, which proves a driver follows the datasheet rather than merely
// working: the reset, the status once the calibration has loaded, the chip id, the
// two calibration blocks, the three configuration writes in the order the part
// requires, then one forced measurement.
const Bme280.Oversampling X1 = Bme280.Oversampling.X1;
var settings = new Bme280CtrlMeas(X1, X1, Bme280.Mode.Sleep);
var forced = settings with { Mode = Bme280.Mode.Forced };
var resetState = new Bme280Config(Bme280.Standby.Ms0_5, Bme280.Filter.Off, Spi3Wire: false);
byte[] idle = [Bme280.Sim.StatusIdle];
using I2cBus script = I2cBus.Scripted(
    I2cStep.Write(Part, [Bme280.Register.Reset, Bme280.ResetWord]),
    I2cStep.WriteRead(Part, [Bme280.Register.Status], idle),
    I2cStep.WriteRead(Part, [Bme280.Register.ChipId], [Bme280.ChipId]),
    I2cStep.WriteRead(Part, [Bme280.Register.CalibTempPress], Bme280.Sim.Calibration()),
    I2cStep.WriteRead(Part, [Bme280.Register.CalibHumidity], Bme280.Sim.CalibrationHumidity()),
    I2cStep.Write(Part, [Bme280.Register.Config, Bme280.ConfigBits(resetState)]),
    I2cStep.Write(Part, [Bme280.Register.CtrlHum, Bme280.CtrlHumBits(X1)]),
    I2cStep.Write(Part, [Bme280.Register.CtrlMeas, Bme280.CtrlMeasBits(settings)]),
    I2cStep.Write(Part, [Bme280.Register.CtrlMeas, Bme280.CtrlMeasBits(forced)]),
    I2cStep.WriteRead(Part, [Bme280.Register.Status], idle),
    I2cStep.WriteRead(Part, [Bme280.Register.Data], Bme280.Sim.Burst()));
using var datasheet = new Bme280(script, Part);
Bme280Measurement checkedReading = datasheet.Measure();
Console.WriteLine(
    $"datasheet    {Fixed(checkedReading.Celsius)} C after {script.Transfers} transfers, " +
    $"{script.Remaining ?? 0} steps left");

The same capability in every language

Language Package Reference
Rust pamoja-hal reference, docs.rs, install
TypeScript @pamoja/hal reference, install
Python pamoja-hal reference, install
C# Pamoja.Hal reference, install

Documentation

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on Pamoja.Hal:

Package Downloads
Pamoja.Sensors

Datasheet-anchored drivers for eleven parts, from every language: the BME280, BMP280, DS18B20, HDC1080, INA219, INA226, ADS1115, OPT3001, SCD4x, SHT3x, and TMP117.

Pamoja.Modbus

Modbus RTU for RS485 field devices: a client that polls them over a serial port with the line's timing, simulated devices that answer as real ones do, and the frames with their CRC-16/MODBUS.

Pamoja.Actuators

A PCA9685 driver for servos, LEDs, and valves, and stepper drivers for four coil lines or a step and direction chip, in every language.

Pamoja

The whole pamoja framework in one package: every capability of one memory-safe Rust core, behind an idiomatic C# facade, for IoT, robotics, and drones.

Pamoja.FieldIo

Field I/O: The wires a gateway actually has: framed serial packets, an RS485 request and the reply it draws, a CAN frame, the address a chip answers on, and the bus that carries a driver to the part.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 0 9/24/2026