Module gen_serial

Description

Generic serial port interface.

The gen_serial API allows Erlang programs to make use of standard RS-232 serial ports on both Windows and UNIX platforms, from a common interface module.

External port processes are used to connect to the host serial port APIs, thereby placing each serial port connection in its own memory-protected sandbox. Should the serial port process crash, only that port will be shutdown; the Erlang node will continue to function properly, as will all other serial ports. On Windows the serial port processes are named COMn_esock.exe, where the COMn part indicates the name of the serial port being accessed by the program. On UNIX, the first argument to the program serial_esock has the serial device's name.

Much of the API should be similiar to gen_tcp and ssl, making the switch to serial communications easy on Erlang developers.

Unlike other Erlang communication APIs, gen_serial only allows use of binaries and lists of binaries. Character lists (aka strings or IO lists) are just simply not supported at this time.

Disclaimer: This is alpha level code. Have fun!

Port Owner Messages:

The port owner (see set_owner/2) is sent a series of messages containing data packets (when the port is active) and close and error messages, when the port is closed or an error related to the port occurs.

{serial, PortRef, Packet}

Sent when a packet of data has been received and decoded by the serial port driver. If there is a packet level protocol being used by the driver, Packet will contain one complete packet of data. If no packet level protocol is using, Packet will typically be a single byte, as the port driver is significantly faster than the serial port.

This message is only sent when the port has the 'active' option set to 'true' or 'once'. See {active, When} for more information.

{serial_error, PortRef, Error}

Sent when the port driver has detected a problem with the serial port. The error may be critical and cause the port to close.

{serial_closed, PortRef}

Sent when the port is being closed, before the port process goes down.

Available Options:

The following options can be used in an option_list() to configure the serial port for communications with another device.

{rcvbuf, Bytes}

Size of the OS receive buffer (for data coming in from the serial port). Specified in bytes, must be between 32 and 32,768. Not all OSes will allow all values in this range. Default is 4096, which should work on all platforms.

{sndbuf, Bytes}

Size of the OS send buffer (for data going out the serial port). Specified in bytes, must be between 32 and 32,768. Not all OSes will allow all values in this range. Default is 4096, which should work on all platforms.

{bufsz, Bytes}

Size of the packet buffers. If using delimited packets or line-oriented packets, the packet buffer must be sized larger than the largest input line expected, or else the application will receive fragmented packets. If fixed size packets are being used the bufsz may be set larger or smaller than the actual packet size. Default is 8192, large enough for most applications.

{register, Name}

Register the interface process as a named process, making it visible in the shell tools, etc. If the atom 'true' is supplied the actual name registered will be a mangled form of the device name. If 'false' is supplied, no name will be registered for the interface process. Default is 'false'.

register

Same as {register, true}.

{baud, BitsPerSecond}

Set the baud rate of the serial port, as the number of bits to transfer per second. Most serial ports will only accept a subset of the baud rates listed above, but this driver will accept any baud rate over 1 bit per second and attempt to configure the OS for that rate. If a rate is rejected, its because the OS cannot support that rate, or the hardware cannot support that rate. Default is 9600 as this is extremely common.

{bytesz, BitsPerByte}

Set the number of bits per data byte. Default is 8.

{parity, Parity}

Enable or disable parity checking. Default is none.

{stop_bits, StopBits}

Set the number of stop bits used. Default is 1.

{flow_control, Type}

Select the type of flow control which will be used by the serial port. Default is hardware as it is the most reliable form.

{packet, none}

No packet formatting is handled by the driver. All bytes are delivered as they are received, typically one byte at a time (however if the system is very busy multiple bytes may be sent in a single binary). If the application needs to assemble packets from the data, it is up to the application developer to properly buffer data and assemble the packets prior to processing.

{packet, cr}

Packets are line oriented, terminated by a single carriage return ($\r, ASCII value 13, hex 0D). If this packet format is used, the option 'bufsz' must be set large enough to hold the longest line, including the carriage return character. The carriage return is stripped from the data packet before the packet is delivered to the application.

Same as {packet, {delimited, <<"\r">>}}.

{packet, lf}

Packets are line oriented, terminated by a single line feed ($\n, ASCII value 10, hex 0A). If this packet format is used, the option 'bufsz' must be set large enough to hold the longest line, including the line feed character. The line feed is stripped from the data packet before the packet is delivered to the application.

Same as {packet, {delimited, <<"\n">>}}.

{packet, crlf}

Packets are line oriented, terminated by a carriage return / line feed pair ("\r\n", ASCII value 13, hex 0D followed by ASCII value 10 hex 16#0A). If this packet format is used, the option 'bufsz' must be set large enough to hold the longest line, including the carriage return and line feed characters. The carriage return and line feed are both stripped from the data packet before the packet is delivered to the application.

Same as {packet, {delimited, <<"\r\n">>}}.

{packet, {delimited, Delimiter}}

Packets are variable length and delimited by a sequence of one or more bytes. All bytes in Delimiter must occur in order to form a packet boundary. The Delimiter cannot exceed 8 bytes in length due to internal limitations in the driver. If this packet format is used, the 'bufsz' option must specify a buffer large enough to hold the largest packet and the complete Delimiter.

Delimiter may contain any binary data sequence necessary, as the driver is fully 8 bit clean.

{packet, {fixed, Bytes}}

Packets are fixed length in size, with every packet being exactly Bytes number of bytes in length. The application will not be given a packet until exactly Bytes number of bytes have been received by the serial port. If this option is used, 'bufsz' may be smaller than Bytes, the driver is smart enough to not fragment the packet.

{active, When}

Just like the active option to ssl or gen_tcp. When set to 'true' the port owner will receive all data packets as Erlang messages. If set to 'once' the port owner will receive a single data packet, and the active setting will be set to 'false'. The 'once' option prevents the port owner from being flooded with data on a fast link. If 'false', the port owner will not receive any data packets at all, until set to 'true' or 'once'.

Homepage:

http://www.spearce.org/projects/erlang/gen_serial/

Function Index

Exported Functions
asend/2Asynchronous data transmission.
bsend/2See bsend/3.
bsend/3Synchronous data transmission.
close/1See close/2.
close/2Close an open serial port.
flush/1See flush/2.
flush/2Wait until buffered data has been transmitted to the endpoint.
init/3This is an internal function: do not use. Sets up a newly spawned interface process.
loop/4This is an internal function: do not use. Main loop of an interface process.
open/2Open a serial port for communications.
recv/2See recv/3.
recv/3Read data from an open serial port.
send/2Partially asynchronous data transmission.
set_owner/1See set_owner/2.
set_owner/2Change the owner of the serial port to another process.
setopts/2Change the current options on the serial port.

Data Types

device_name() = string() | atom() | integer()

The name of a serial port on the host operating system. On Windows machines this is frequently of the form "COMn" where n is some integer >= 1. On UNIX systems this may be a tty device, for example "/dev/ttya".

Either atoms or strings are allowed, making it easy to spec 'com1' or "COM1". On UNIX atoms will automatically have "/dev/" prefixed to them, forming a proper device path, however case does matter. With the prefixing, 'tty0' becomes the full path "/dev/tty0".

If an integer is supplied, the ordinal is used with an OS specific prefix to locate the serial port. This does not work on all platforms, and on some like Windows may not work for all serial ports as not all serial ports start with the "COM" prefix.

option_list() = [option()]

A list of options to configure the serial port and how Erlang reads and writes data from it. The option list allows setting baud rate, buffer size, packet formatting, and other options.

See Available Options.

option() = Name | {Name, Value}

All items in an option_list() value must be single atoms or name/value pair tuples. (A standard Erlang property list.) The type of Value and its range of values depends on the specific Name atom paired with it.

See Available Options.

port_ref() = term()

Opaque term returned by open/2 to allow callers to interact with an open serial port. The internals of the term should not be directly accessed or modified by the caller; and the caller should not rely on the term format as it may change in the future without notice.

time_in_ms() = integer()

A length of time, expressed as a number of milliseconds. The special atom infinity is not accepted as a valid value for this type.

Exported Functions

asend/2

asend(PortRef, Packet) -> ok

Asynchronous data transmission.

Sends data through the serial port. The data is first sent to the interface process, which means the caller should never block when this method is called, even if flow control has broken down and all IO buffers are full (as the interface process' message queue can grow to an infinite length).

When this call returns, the data may only be queued for delivery. There is no assurances that the data was actually transmitted out the serial port. Use flush/1, flush/2 or bsend/2 to wait for the data to have actually been sent out the serial port to the endpoint.

See also: bsend/3, send/2.

bsend/2

bsend(PortRef, Packet) -> ok | {error, Reason}

Equivalent to bsend(PortRef, Packet, infinity).

bsend/3

bsend(PortRef, Packet, Timeout) -> ok | {error, timeout} | {error, Reason}

Synchronous data transmission.

Sends data through the serial port. Unlike all other forms of the send call, bsend/2 and bsend/3 wait until the endpoint has received the data before returning to the caller. This may take some time, depending on the speed of the serial port and how much data is already queued up in the output queues.

Callers are encouraged to use this form rather than bsend/2, as it allows specification of a timeout, in case flow control has broken down and the data already buffered cannot be sent.

This function is roughly equivalent to (but easier to use):

 		case send(PortRef, Packet) of
 		ok ->    flush(PortRef, Timeout);
 		Other -> Other
 		end
  

See also: asend/2, bsend/3, send/2.

close/1

close(PortRef) -> ok | killed

Equivalent to close(PortRef, 3000).

close/2

close(PortRef, Timeout) -> ok | killed

Close an open serial port.

This call is not really necessary, as the port will automatically close when the port owner terminates.

A timeout can be supplied, as this call blocks until it receives confirmation from the serial port process that all pending output has been transferred to the endpoint, and the port has closed down gracefully.

If the port's output buffer is full (because the endpoint has stopped receiving data, or flow control has been broken), the close command may not be able to be processed in a timely fashion. In this case, this function will wait for Timeout to expire, and then brutually kill the serial port. Brutally killing the port will release all resources correctly, but data will be lost when the output buffers are destroyed. If the brutal kill is required, the atom killed is returned instead of ok. The brutal kill version of this function will not cause the port owner process to crash, as the exit reason used is normal.

Special note: If the caller attempts to use the special atom 'infinity' as the Timeout value, it will be silently converted to 60 seconds to prevent locking up the caller indefinately.

flush/1

flush(PortRef) -> ok | {error, Reason}

Equivalent to flush(PortRef, infinity).

flush/2

flush(PortRef, Timeout) -> ok | {error, timeout} | {error, Reason}

Wait until buffered data has been transmitted to the endpoint.

Waits until the port's outgoing data buffers have been fully drained and transmitted to the endpoint. If any error is detected during transmission (while waiting for the data to finish being sent), the error will both be returned by this function and sent to the port owner as a message (unless the caller is the port owner, in which case the error is returned and no message is sent).

init/3

init(Arg1, Arg2, Arg3) -> term()

This is an internal function: do not use. Sets up a newly spawned interface process.

Sets up a newly spawned process to act as the interface between the Erlang port driver and the rest of the Erlang environment. The interface process owns the actual port object, and keeps track of the externally running port process which performs the low level operating system calls.

See also: loop/3.

loop/4

loop(Arg1, Arg2, Arg3, Arg4) -> term()

This is an internal function: do not use. Main loop of an interface process.

See also: init/3.

open/2

open(Device, Options) -> {ok, PortRef} | {error, Reason}

Open a serial port for communications.

When a serial port is opened, the caller is setup as the port owner. (See set_owner/1, set_owner/2.) At open, the port is linked to the owner, ensuring that if the owner terminates, the port will be automatically closed as well.

recv/2

recv(PortRef, Length) -> {ok, Packet} | {error, Reason}

Equivalent to recv(PortRef, Length, infinity).

recv/3

recv(PortRef, Length, Timeout) -> {ok, Packet} | {error, Reason}

Read data from an open serial port.

Reads exactly Length bytes from the serial port and returns them as a single binary object. If the port has less than Length bytes immediately available in the receive buffers, this call will block until the timeout expires or the total number of bytes requested has been received.

If the caller doesn't want to block while waiting for data, the caller should either use a short timeout, or use an active mode port instead of using recv/2 or recv/3.

send/2

send(PortRef, Packet) -> ok

Partially asynchronous data transmission.

Sends data through the serial port. The caller sends the data out the port directly, which means the caller may block indefinately if all IO buffers are full and flow control has broken down. This is the fastest way to send data to the serial port, as it does not have to pass through the interface process first, but may be risky due to the flow control issues.

When this call returns, the data may only be queued for delivery. There is no assurances that the data was actually transmitted out the serial port. Use flush/1, flush/2 or bsend/2 to wait for the data to have actually been sent out the serial port to the endpoint.

If the caller wants true nonblocking sends, see asend/2.

See also: asend/2, bsend/2, bsend/3.

set_owner/1

set_owner(PortRef) -> ok | {error, Reason}

Equivalent to set_owner(PortRef, self()).

set_owner/2

set_owner(PortRef, To) -> ok | {error, Reason}

Change the owner of the serial port to another process.

The owner of the serial port receives a set of messages, similiar to the messages sent by the gen_tcp or ssl modules. The messages are defined above in Port Owner Messages.

The port is always linked to the port owner process. If the port owner exits, the serial port will automatically close, ensuring resources are freed up automatically.

See also: set_owner/1.

setopts/2

setopts(PortRef, Opts) -> ok | {error, Reason}

Change the current options on the serial port.

Currently on the active flag can be changed.

See {active, When}.