RS485 Modbus RTU relay board with PowerShell

Serial comunication with a 4 Channel RS485 Modbus RTU relay board via a universal USB – RS485 dongle using PowerShell.

Relevant links:

Write-Host "Available ports:" ([System.IO.Ports.SerialPort]::getportnames());

$COM = "COM4";
$SLAVE_ID = 0x03;

# Append 2 byte MODBUS-16 CRC to binary data array
function CRC([byte[]] $data) {
    $dataCopy = @();
    $dataCopy += $data;

    $crcFull = 0xFFFF;
    for ($i = 0; $i -lt $dataCopy.Count; $i++) {
        $crcFull = ($crcFull -bxor $dataCopy[$i]) -band 0xFFFF;
        for ($j = 0; $j -lt 8; $j++) {
            $crclsb = ($crcFull -band 0x0001);
            $crcFull = (($crcFull -shr 1) -band 0x7FFF);
            if ($crclsb -eq 1) {
                $crcFull = ($crcFull -bxor 0xA001) -band 0xFFFF;
            }
        }
    }
    $dataCopy += [byte] ($crcFull -band 0xFF);
    $dataCopy += [byte] (($crcFull -shr 8) -band 0xFF);

    return $dataCopy;
}

function RelayChannel([int] $ch) {
    # Fixed serial port settings: this limits the board usage in a RS485 chain
    $port = New-Object System.IO.Ports.SerialPort $COM, 9600, None, 8, one;

    $DataReceivedHandler = {
        param([object] $sender, [System.IO.Ports.SerialDataReceivedEventArgs] $e);
        [System.IO.Ports.SerialPort] $sp = [System.IO.Ports.SerialPort] $sender;
        for ($i = 1; $i -le $sp.BytesToRead; $i++) {
            Write-Host (($sp.ReadByte()) | ForEach-Object ToString X2);
        }
    }
    $null = Register-ObjectEvent -InputObject $port -EventName "DataReceived" -Action $DataReceivedHandler -MessageData $port -SourceIdentifier "SerialPort.DataReceived";

    $port.Open();
    # Close all channels
    for ($i = 1; $i -le 4; $i++) {
        $data = [byte[]] (CRC(($SLAVE_ID,0x06,0x00,$i,0x02,0x00))); # CLOSE = 0x02;
        $port.Write($data, 0, $data.Count);
        Start-Sleep -Milliseconds 50;
    }

    # Open requested channel, if channel is out of renge do nothing
    if ($ch -ge 1 -and $ch -le 4) {
        $data = [byte[]] (CRC(($SLAVE_ID,0x06,0x00,$ch,0x01,0x00))); # OPEN = 0x01;
        $port.Write($data, 0, $data.Count);
    }
    $port.Close();

    Unregister-Event -SourceIdentifier "SerialPort.DataReceived";
}

# Switch to channel 3
RelayChannel 3

 Last update 2019-03-13 17:06