Giter Site home page Giter Site logo

serial.nim's Introduction

serial.nim

A library to work with serial ports using pure Nim.

Installation

serial can be installed using Nimble:

nimble install serial

Or add the following to your .nimble file:

# Dependencies

requires "serial >= 1.0.0"

Usage

There are some examples in the examples directory, showing reading from and writing to a serialport.

Listing serial ports

import serial # Or: `import serial/utils`

for port in listSerialPorts():
  echo port

Reading from/writing to a serial port (echoing data)

import serial # Or: `import serial/serialport`

let port = newSerialPort("COM1")
# use 9600bps, no parity, 8 data bits and 1 stop bit
port.open(9600, Parity.None, 8, StopBits.One)

# You can modify the baud rate, parity, databits, etc. after opening the port
port.baudRate = 2400

var receiveBuffer = newString(1024)
while true:
  let numReceived = port.read(receiveBuffer)
  discard port.write(receiveBuffer[0 ..< numReceived])

Using the SerialStream

import serial # Or: `import serial/serialstream`

let port = newSerialStream("COM1", 9600, Parity.None, 8, StopBits.One, buffered=true)

while true:
  # Read a line from the serial port then write it back.
  port.writeLine(port.readLine())

Features

  • Basic port reading/writing for Windows/Posix
  • Port setting control - baud rate, stop bits, databits, parity, handshaking
  • Port listing to list available serial ports
    • Windows, using SetupDiGetClassDevs
    • Mac, using I/O Kit
    • Posix, by iterating possible device files
  • High level SerialPortStream that complies with the streams API
  • Async API using asyncdispatch for reading from and writing to a port

serial.nim's People

Contributors

accaldwell avatar centurysys avatar euantorano avatar jeff-ciesielski avatar lucawolf avatar markprocess avatar markspanbroek avatar martin-c avatar mp035 avatar rsduck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

serial.nim's Issues

undeclared identifier: 'PCustomOverlapped'

nim: 1.2.6 win32

code:

import serial

for port in listSerialPorts():
    echo port

error:

.nimble\pkgs\serial-1.1.4\serial\private\serialport\serialport_windows.nim(637, 12) Error: undeclared identifier: 'PCustomOverlapped'

All programs fail to compile with serial lib in nim 1.0

All programs are failing to compile with nim 1.0.0 with the following error:

/home/snip/.nimble/pkgs/serial-1.1.2/serial/serialstream.nim(117, 17) Error: type mismatch: got <proc (s: Stream, buffer: pointer, bufLen: int): int{.gcsafe, locks: <unknown>.}> but expected 'proc (s: Stream, buffer: pointer, bufLen: int): int{.gcsafe.}' .raise effects differ

The only thing needed to trigger this error on compilation is a one line test file:

import serial

Can't detect all serial ports on Windows 10

The library doesn't seem to be able to reliably detect all the serial ports on my Windows 10 (build 18363.657) machine.

I have three ports: an integrated serial port (via Intel chipset), a FTDI USB-serial adapter, and an Intel AMT COM port. They all show up correctly in the registry, which I understand is how they are currently being detected.

If I fuss around with enabling and disabling the ports via Device Manager, I can get one or two of them to be detected from my nim code:

let serialPorts = toSeq(listSerialPorts())
echo "Detected Ports:"
for port in serialPorts:
  echo port

But, I've never seemed to get it to detect all three at the same time when they are all enabled, so something isn't working.

I'm using nim 1.0.6 and serial 1.1.3. Let me know if there is something I can test to help debug this, or if there is an alternate method of detecting ports on Windows (I've never had issues with the above code in Linux on the same system).

Force synchronization of the serial port?

I'm running into a bizarre issue with this serial port library that I also saw in a Rust based library, maybe you can help!

I'm implemented the following test program, which just writes a command to a little Arduino I have connected over USB:

  3 import serial, streams
  4 
  5 proc main() =
  6     let port = newSerialStream("/dev/ttyUSB0"
  7         , 115200
  8         , Parity.None
  9         , 8
 10         , StopBits.One
 11         , Handshake.RequestToSend
 12         , buffered=false
 13     )
 14 
 15     defer: close(port)
 16 
 17     port.setTimeouts(1000,100)
 18 
 19 #    for i in 0..3:
 20 #        echo "tryna read"
 21 #        echo port.readline()
 22     port.write("volume up\n")
 23     port.flush()
 24 
 25 
 26 when isMainModule:
 27     main()

What's strange is that the Arduino receives the data immediately (evidenced by the RX LED flashing), but does not act on it until I force the program to halt. It does not halt unless I send it SIGINT (Control-C); so it appears to be hung up on closing the serial port?

This may be related to a strange RTS/CTS related issue I was seeing on my scope, where the sending party (my computer) would hold the RTS line, most likely triggering an interrupt and preventing the Arduino from processing the command until the port was forcibly closed/flushed by the OS.

Let me know if you have any suggestions, I'm all ears! So far all I've done is try all of the handshakes, and what it looks like is:

None: data is received by Arduino but it does not act on it; program terminates normally
RTS: data is received by Arduino and it does act on it but not until program is forcibly killed
XOnXOff: same as RTS
RTSXOnXOff: same as RTS

The timeouts are generous enough, as this whole transaction takes <10ms on my scope.

Asynchronous IO blocks dispatcher thread.

The async read and write operations perform an instant call to posix.read or posix.write before adding a read or write to the dispatcher queue. This causes the dispatcher thread to block under certain circumstances (no data available), preventing completion of other operations in the dispatcher queue.

A patch is attached which corrects the issue, it was tested on Ubuntu 18.04.

NOTE: it also re-implements the OSX baudrate constants which were removed in my last patch and should fix issue #17 .

Sorry for the regression.

fix_async_block.zip

Serial stream issues with current Nim compiler

Because this module does'nt compile with my ubuntu nim version I just downloaded and compiled the current git version of nim and nimble two hours ago.

I get the following error:

/home/bert/.nimble/pkgs/serial-1.1.2/serial/serialstream.nim(117, 17) Error: type mismatch: got <proc (s: Stream, buffer: pointer, bufLen: int): int{.gcsafe, locks: <unknown>.}> but expected 'proc (s: Stream, buffer: pointer, bufLen: int): int{.gcsafe.}'

Please help. I'm an absolute beginner and want to get into nim with learning by doing. But, sorry, this problem it to hard for me.

Alternatively I would be helpful if somebody can give me a nim-compiler version that runs with the current serial module.

Shouldn't the dependency section in the serial.nimble file be updated?

Thanks!!!!

Originally posted by @WoodyAtHome in #12 (comment)

Read timeout does not function correctly on windows implementation.

Hi, when using read timeouts other than 0 or TIMEOUT_INFINITE, the windows implementation behaves as outlined in the following remark from https://docs.microsoft.com/en-gb/windows/win32/api/winbase/ns-winbase-commtimeouts:

  • If there are any bytes in the input buffer, ReadFile returns immediately with the bytes in the buffer.
  • If there are no bytes in the input buffer, ReadFile waits until a byte arrives and then returns immediately.
  • If no bytes arrive within the time specified by ReadTotalTimeoutConstant, ReadFile times out.

I believe this is not the intended behaviour. With a single timeout, I would anticipate that the port reading process would simply timeout if the requested number of bytes is not received within the set timeout period (please correct me if I am wrong).

I have applied a fix which produces the expected behaviour for read timeouts other than zero and infinite (tested) to my fork. It also seems that the settings for TIMEOUT_INFINITE were not according to the specification, so I have corrected those, and have tested that the port does not timeout for about 10 minutes (this should be sufficient to confirm correct behaviour, testing for infinite is impossible). The commit is here:
mp035@836d53f

I'm happy to issue a pull request, but please note my comments on 2 of the other issues before accepting my offer.

Fails to compile on Windows with `--gc:orc`

As the title says, the following program fails to compile on Windows with --gc:orc:

import serial

for i in listSerialPorts():
   echo i

Expected behavior:

  • Sample program compiles

Actual behavior:

  • The program fails to compile with --gc:orc and we get the following message:
$HOME\.nimble\pkgs\serial-1.1.5\serial\private\utils\windows_registry.nim(89, 81) Error: expression cannot be cast to pointer

Nim Version:
1.6.12

OS:
Windows 11 Pro 22H2 Build 22621.1702

port.write fails with non-zero writeTimeout on MacOS 10.13.6

Running the example in source/serial.nim fails on MacOS 10.13.6 in port.write() with the following error:

/Users/martin/repos/martin-c/serial.nim/src/serial.nim(90) serial
/Users/martin/repos/martin-c/serial.nim/src/serial/private/serialport/serialport_posix.nim(789) write
/usr/local/Cellar/nim/1.0.6/nim/lib/pure/includes/oserr.nim(94) raiseOSError
Error: unhandled exception: Invalid argument [OSError]

So it seems select() is getting an invalid argument. I'm a Nim beginner and haven't had the time to track this error further.

Setting writeTimeout = 0 on line 67 seems to be a workaround.

Setting write timeout to zero results in TIMEOUT_INFINITE on windows.

Sorry for all the issues today, I have been giving the windows version a workout in my new project.

If write timeout is set to zero, the windows version applies TIMEOUT_INFINITE. Setting write timeout to zero is not actually possible in windows, so I have applied a fix which applies a 1ms timeout in the case of the user requesting zero. It's not perfect, but its better than applying infinite timeout.

The fix is here:
mp035@0db8e05

As with the other issues, let me know if you want me to file a pull request.
Thanks again for all your work on this project.

Linux implementation won't list the Bluetooth related serial ports

At least on my Fedora machine, the serial ports created by the Bluetooth driver are not listed.

I have enhanced my local copy (list_serialports_linux.nim) with:

let fullDevicePath = "/sys/class/tty" / filename / "device" # serial have this path
let fullDeviceRFPath = "/sys/class/tty" / filename / "dev" # bluetooth
...
if subsystem != "platform":
      result = true 
elif fileExists(fullDeviceRFPath):
  result = true
else:
  result = false

If these seems right to you please include the above changes in mainstream.

Thanks,
Luca

SerialPort.write returns 0 bytes written

I am trying to write to the uart that is connected to the hci/uart interface of a bluetooth chip on board a raspbian/pi3b+. When I run this program, it indicates that 0 of 3 bytes have been written.

  1. do you recognize this problem?

  2. how can I determine why 0 bytes were written instead of 3?

Thanks,
Mark

import serial, strformat

when isMainModule:
  proc main() =

    echo ""
    var portName = "/dev/ttyAMA0"

    let serialPort = newSerialPort(portName)
    serialPort.open(38400, Parity.None, 8, StopBits.One)
    defer: close(serialPort)

    echo &"Opened serial port {portName}"

    var nop = newString(3)
    var n = serialPort.write(nop)
    echo &"{n}/{len(nop)} bytes written"

  main()

raspbian baud rates not fully defined

Trying nim c -r examples/writer.nim on raspbian stretch lite/pi3b+

    /home/pi/github.com/euantorano/serial.nim/src/serial/private/serialport/
    serialport_posix.nim(242, 12) Error: undeclared identifier: 'B57600'

I'm not familiar with how to approach this. I particularly need 115200 since that is the power-on baud rate.

Thanks, Mark

IOKit/IOKitLib.h not found under macOS 10.14 (Mojave)

Hi,

I am getting the error message that IOKit/IOKitLib.h could not be found.

The code I try to compile is:

import serial 

for port in listSerialPorts():
  echo port

First I've tried it with --cincludes:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers as it contains the subdirectory IOKit.

However, after a few attempts I realized that IOKitLib.h is not there but instead inside /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Headers.

What's missing is the subdirectory IOKit that contains IOKitLib.h.

Is this problem only related to macOS Mojave or am I maybe missing some SDK settings?

Kind regards,

readme example has wrong buffer type in 0.18

From README.md:

import serial # Or: `import serial/serialport`

let port = newSerialPort("COM1")
# use 9600bps, no parity, 8 data bits and 1 stop bit
port.open(9600, Parity.None, 8, StopBits.One)

# You can modify the baud rate, parity, databits, etc. after opening the port
port.baudRate = 2400

var receiveBuffer = newString(1024)
while true:
  let numReceived = port.read(receiveBuffer, len(receiveBuffer))
  port.write(receiveBuffer, numReceived)

compile using 0.18:

test2.nim(12, 25) Error: type mismatch: got <SerialPort, string, int>
but expected one of:
proc read(port: SerialPort; buff: pointer; len: int32): int32
  first type mismatch at position: 2
  required type: pointer
  but expression 'receiveBuffer' is of type: string

expression: read(port, receiveBuffer, len(receiveBuffer))

Better serial handling on Windows

Serial port handling on Windows can be much improved, including checking whether a device is a valid serial port using GetFileType. I also want to tidy up how FFI is handled across platforms.

readTimeout = TIMEOUT_INFINITE does not work on linux

As mentioned it appears that setting readTimeout to TIMEOUT_INFINITE (which is the default) does not have the intended effect on linux. It raises an exception which seems to be the result of EAGAIN or EWOULDBLOCK being set, indicating that the port is in non-blocking mode and not tested for available characters. Eg:

import serial

for port in listSerialPorts():
  echo port

let port = newSerialPort("/dev/ttyUSB0")
# use 9600bps, no parity, 8 data bits and 1 stop bit
port.open(9600, Parity.None, 8, StopBits.One, readTimeout= TIMEOUT_INFINITE) #TIMEOUT_INFINITE is the default anyway.

# You can modify the baud rate, parity, databits, etc. after opening the port
port.baudRate = 2400

var receiveBuffer = newString(1024)
discard port.write("hello world\n")
while true:
  let numReceived = port.read(receiveBuffer)
  discard port.write(receiveBuffer[0 ..< numReceived])
  echo $receiveBuffer

Results in:

/dev/ttyUSB0
Traceback (most recent call last)
main.nim(16)             main
serialport.nim(15)       read
serialport_posix.nim(571) read
oserr.nim(113)           raiseOSError
Error: unhandled exception: Resource temporarily unavailable [OSError]

Serial library wont compile on Windows

Attempting to compile any program that imports serial is failing on Windows:

C:\Users\Adam\.nimble\pkgs\serial-#head\serial\private\ffi\ffi_windows.nim(29, 27) Error: cannot convert 4294967295 to DWORD

I think maybe the specified code should be changed to:

MAXDWORD*: DWORD = DWORD(high(int32))

since winlean defines a DWORD as being of type int32. But, I might be misunderstanding something.

Either way, that change gets rid of the above error, but leads to further errors about invalid else clauses. Commenting out those just gets to yet another error:

C:\Users\Adam\.nimble\pkgs\serial-#head\serial\private\utils\list_serialports_windows.nim(65, 26) Error: -1 can't be converted to HKEY

HKEY is a uint, so the error makes sense, but I'm unsure what exactly you were doing originally here, so that's as far as I got.

I'm using nim 1.0.0 and serial 1da4cc1.

Windows 7 implementation won't list the serial USB related serial ports.

For some reason the SetupDiGetClassDevs with GUID_DEVINTERFACE_COMPORT approach won't list the ports created by the sys serial Usb driver (mostly used by embedded devices). Tested on Win7, both pro and home editions.

Opening (once the com name is known) and data transfer works fine.

If you have serial USB devices to test with, could you please confirm it works for you?

Thanks,
Luca

Build fails on MacOS 10.13.6 with clang error: use of undeclared identifier 'IUCLC'

Thanks for this excellent Nim package!
Unfortunately the latest version v1.1.3 (and master 17fbff9) fails to build on MacOS 10.13.6. Here's the full clang error:

/Users/martin/.cache/nim/serial_d/@[email protected]:1136:111: error: use of undeclared identifier 'IUCLC'
                settings.c_iflag = (NU32)(settings.c_iflag & (NU32)((NU32) ~((NU32)((NU32)((NU32)(INLCR | IGNCR) | ICRNL) | IUCLC))));

I read up on the meaning of IUCLC here: http://man7.org/linux/man-pages/man3/termios.3.html and noted that the man page states that

IUCLC (not in POSIX) Map uppercase characters to lowercase on input.'

So should we remove it from the serialport_posix.nim file?
Changing line 599 to remove IUCLC fixes the error.

How can I write data to serial while reading data from it

I am rolling a simple serial term which has simple functions:

  • Reading text from serial port and print it to stdout.
  • Reading user's input from stdin and write it to serial port.

How can I get both work together?
My experience from other language is to use multithread or async IO.
Multithread seems not a way due to Nim's per-thread gc. Also serial.nim does not support asyncio yet.
What's the best solution for now?

Implement some CI

At the moment there is no continuous integration for this project at all. We should add some unit tests and make use of com0com (on Windows) to test. I'm not sure if there's anything similar for other platforms to test on, but having Windows support at least will be a big improvement.

Checking data before reading (non-blocking)

I would like to combine serial.nim and Arduino for a project of mine yet the line

port.readLine() is blocking and unless I create a second thread for handling other things the code does not work (it just waits for data). I would like to have something like Arduino Serial.available() or python ser.in_waiting so that I don't have to split the code into multiple threads

ffi_windows.nim(29, 27) Error: cannot convert 4294967295 to DWORD

Using NIM 1.0.0 on Windows10. Did a nimble install serial this morning.

I'm new to NIM and simply tried the following snippet from your examples to see what happens:

import serial # Or: `import serial/utils`

for port in listSerialPorts():
  echo port

I get the error in the title.
I did some searching and found out that DWORD is an int32, but the referenced line in the error attempts to use uint32. So I ran a quick sanity check:

echo high(int32)    => 2147483647
echo high(uint32)   => 4294967295

I'm pretty sure I understand what's going on here (impressed by it, actually), but I don't have any idea how to fix it for you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.