3

I'm trying to receive serial data from Arduino asynchronously via "DataReceived" event, but it $event.messageData is always empty.

Here's my code so far:

$port = New-Object System.IO.Ports.SerialPort COM7,9600,None,8,one
$port.Open()
$port | Format-List -Property *
Register-ObjectEvent -InputObject $port -EventName "DataReceived" -Action {
  $event | Format-List -Property * | Out-Host
}

Here's the output:

PORT

BaseStream             : System.IO.Ports.SerialStream
BaudRate               : 9600
BreakState             : False
BytesToWrite           : 0
BytesToRead            : 0
CDHolding              : False
CtsHolding             : False
DataBits               : 8
DiscardNull            : False
DsrHolding             : False
DtrEnable              : False
Encoding               : System.Text.ASCIIEncoding
Handshake              : None
IsOpen                 : True
NewLine                :

Parity                 : None
ParityReplace          : 63
PortName               : COM7
ReadBufferSize         : 4096
ReadTimeout            : -1
ReceivedBytesThreshold : 1
RtsEnable              : False
StopBits               : One
WriteBufferSize        : 2048
WriteTimeout           : -1
Site                   :
Container              :

EVENT

ComputerName     :
RunspaceId       : 67c40d50-5a9b-4022-974e-0a6a6518c2af
EventIdentifier  : 11
Sender           : System.IO.Ports.SerialPort
SourceEventArgs  : System.IO.Ports.SerialDataReceivedEventArgs
SourceArgs       : {COM7, System.IO.Ports.SerialDataReceivedEventArgs}
SourceIdentifier : 26c24bdb-8085-4e88-828e-44cb7897e416
TimeGenerated    : 6/16/2019 12:52:39 AM
MessageData      :

On the arduino side the code is:

Serial.printlf("ready")

When I use syncronous approach everything works

$port = New-Object System.IO.Ports.SerialPort COM7,9600,None,8,one
$port.Open()
$port.ReadLine()

Output

ready
ready
ready
...

Please, help!

0

2 Answers 2

4

$event.MessageData is not the right property to query - it contains custom data passed to the
-MessageData parameter when raising a custom event via the New-Event cmdlet.

For .NET-originated events, it is generally the automatic $EventArgs variable that contains the event-specific data.

In the specific case of the [System.IO.Ports.SerialPort] type's DataReceived event, however, it seems that the data isn't actually passed as an event argument, and you must instead use the $Sender object to gain access to the originating [System.IO.Ports.SerialPort] instance in order to call its .ReadExisting() method, judging by the sample code in the official docs:

$eventJob = 
  Register-ObjectEvent -InputObject $port -EventName "DataReceived" -Action {
    $Sender.ReadExisting() | Out-Host
  }
Sign up to request clarification or add additional context in comments.

3 Comments

How do you write this in powershell? I don't get it. All the docs referring to this, are all about C#, nothing useful for powershell. I would love to see a functioning powersehll implementation for writing and reading on the COM port. E.g. connecting to a serial modem and sending AT commands and being able to receive the response.
@not2qubit, I see that you've since posted a new question, which was the right thing to do. (I personally won't be of much help in this subject matter.)
I solved it there now. And you should always add a name to the handler via -SourceIdentifier SOME_NAME. Thanks.
0

Register-ObjectEvent has quite some flaws. Works in Powershell ISE, copy pasted into powershell, but not as normal script. My result was as strange as yours. Possibly related: https://github.com/PowerShell/PowerShell/issues/13999 . Solution: Don't use Register-ObjectEvent for this usage scenario. Here my example for reading Growatt MIC series "current Watt" via RS485 without Register-ObjectEvent - albeit sending and getting binary data, not string.

$Timeout = 4

# Modbus command for "give me your data"
[byte[]]$GetGrowattStatus=(0x01,0x04,0x0b,0xb8,0x00,0x7d,0xb2,0x2a)

$port = New-Object System.IO.Ports.SerialPort "COM3",9600,None,8,one
$port.Open()
$port.Write($GetGrowattStatus,0,$GetGrowattStatus.Count)
# Response is not fast, but wait no more than $Timeout seconds
for ($i=0;$i -lt $Timeout*4;$i++) {
    Start-Sleep -Milliseconds 250
    if ($port.BytesToRead -gt 0) {
        #Write-Verbose $i -Verbose
        $Data=@()
        while ($port.BytesToRead -gt 0) {
           $Data += [byte]$port.ReadByte()
        }
        $GrowattWatt = ($Data[7] * 256 + $Data[8])/10
        $i=[int]::MaxValue
    }
}
$port.Close()
$GrowattWatt

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.