IPC API
1、ChannelCreate(), ChannelCreate_r()
Create a communications channel
Synopsis:
#include <sys/neutrino.h>
int ChannelCreate( unsigned flags );
int ChannelCreate_r( unsigned flags );
Arguments:
flags
Flags that can be used to request notification pulses from the kernel or request other changes in behavior; a combination of the following:
• _NTO_CHF_COID_DISCONNECT
• _NTO_CHF_DISCONNECT
• _NTO_CHF_FIXED_PRIORITY
• _NTO_CHF_NET_MSG
• _NTO_CHF_PRIVATE
• _NTO_CHF_REPLY_LEN
• _NTO_CHF_SENDER_LEN
• _NTO_CHF_THREAD_DEATH
• _NTO_CHF_UNBLOCK
For more information, see below.
Description:
The ChannelCreate() and ChannelCreate_r() kernel calls create a channel that can be used to receive messages and pulses. Once created, the channel is owned by the process and isn't bound to the creating thread.
These functions are identical, except in the way they indicate errors. See the Returns section for details.
Threads wishing to communicate with the channel attach to it by calling ConnectAttach(). The threads may be in the same process, or in another process on the same node (or a remote node if the network manager is running).
2、ConnectAttach(), ConnectAttach_r()
Establish a connection between a process and a channel
Synopsis:
#include <sys/neutrino.h>
#include <sys/netmgr.h>
int ConnectAttach( uint32_t nd,
pid_t pid,
int chid,
unsigned index,
int flags );
int ConnectAttach_r( uint32_t nd,
pid_t pid,
int chid,
unsigned index,
int flags );
Arguments:
nd
The node descriptor of the node (e.g. ND_LOCAL_NODE for the local node) on which the process that owns the channel is running; see "Node descriptors," below.
pid
The process ID of the owner of the channel. If pid is zero, the calling process is assumed.
chid
The channel ID, returned by ChannelCreate(), of the channel to connect to the process.
index
The lowest acceptable connection ID.
3、MsgReceive(), MsgReceive_r()
Synopsis:
#include <sys/neutrino.h>
int MsgReceive( int chid,
void * msg,
int bytes,
struct _msg_info * info );
int MsgReceive_r( int chid,
void * msg,
int bytes,
struct _msg_info * info );
Arguments:
chid
The ID of a channel that you established by calling ChannelCreate().
msg
A pointer to a buffer where the function can store the received data.
bytes
The size of the buffer.
info
NULL, or a pointer to a _msg_info structure where the function can store additional information about the message.
Return value:
On sucess, MsgReceive() and MsgReceive_r() return:
>0
A message was received; the returned value is a a rcvid (receive identifier). You'll use the rcvid with other Msg*() kernel calls to interact with and reply to the sending thread. MsgReceive() changes the state of the sending thread to REPLY-blocked when the message is received. When you use MsgReply*() to reply to the received message, the sending thread is made ready again. The rcvid encodes the sending thread's ID and a local connection ID.
0
A pulse was received; msg contains a pulse message of type _pulse. When a pulse is received, the kernel space allocated to hold it is immediately released. The _msg_info structure isn't updated.
4、MsgSend(), MsgSend_r()
Send a message to a channel
Synopsis:
#include <sys/neutrino.h>
int MsgSend( int coid,
const void* smsg,
int sbytes,
void* rmsg,
int rbytes );
int MsgSend_r( int coid,
const void* smsg,
int sbytes,
void* rmsg,
int rbytes );
Arguments:
coid
The ID of the channel to send the message on, which you've established by calling ConnectAttach() or name_open().
smsg
A pointer to a buffer that contains the message that you want to send.
sbytes
The number of bytes to send.
rmsg
A pointer to a buffer where the reply can be stored.
rbytes
The size of the reply buffer, in bytes.
Returns:
The only difference between the MsgSend() and MsgSend_r() functions is the way they indicate errors:
MsgSend()
Success
The value of status from MsgReply*().
-1
An error occurred (errno is set), or the server called MsgError*() (errno is set to the error value passed to MsgError()).
MsgSend_r()
Success
The value of status from MsgReply*().
negative value
An error occurred (errno is NOT set, the value is the negative of a value from the Errors section), or the server called MsgError*() (errno is NOT set, the value is the negative of the error value passed to MsgError()).
5、MsgReply(), MsgReply_r()
Reply with a message
Synopsis:
#include <sys/neutrino.h>
int MsgReply( int rcvid,
int status,
const void* msg,
int size );
int MsgReply_r( int rcvid,
int status,
const void* msg,
int size );
Arguments:
rcvid
The receive ID that MsgReceive*() returned when you received the message.
status
The status to use when unblocking the client's MsgSend*() call in the rcvid thread.
msg
A pointer to a buffer that contains the message that you want to reply with.
size
The size of the message, in bytes.
Description:
The MsgReply() and MsgReply_r() kernel calls reply with a message to the thread identified by rcvid. The thread being replied to must be in the REPLY-blocked state. Any thread in the receiving process is free to reply to the message, however, it may be replied to only once for each receive.
These functions are identical except in the way they indicate errors. See the Returns section for details.
The MsgSend*() in the rcvid thread unblocks with a return value of status.
The number of bytes transferred is the minimum of that specified by both the replier and the sender. The reply data isn't allowed to overflow the reply buffer area provided by the sender.
The data transfer occurs immediately, and the replying task doesn't block. There's no need to reply to received messages in any particular order, but you must eventually reply to each message to allow the sending thread(s) to continue execution.
6、name_open()
Open a name for a server connection
Synopsis:
#include <sys/iofunc.h>
#include <sys/dispatch.h>
int name_open( const char * name,
int flags );
Arguments:
name
The name that you want to open for a server connection.
flags
Flags that affect the function's behavior:
• NAME_FLAG_ATTACH_GLOBAL — search for the name globally instead of locally.
Description:
The name_open() function opens name for a server connection. No ordering is guaranteed when accessing resources on other nodes.
Returns:
A nonnegative integer representing a side-channel connection ID (see ConnectAttach()), or -1 if an error occurred (errno is set).
ConnectAttach(), ConnectAttach_r()
Establish a connection between a process and a channel
Synopsis:
#include <sys/neutrino.h>
#include <sys/netmgr.h>
int ConnectAttach( uint32_t nd,
pid_t pid,
int chid,
unsigned index,
int flags );
int ConnectAttach_r( uint32_t nd,
pid_t pid,
int chid,
unsigned index,
int flags );
Arguments:
nd
The node descriptor of the node (e.g. ND_LOCAL_NODE for the local node) on which the process that owns the channel is running; see "Node descriptors," below.
pid
The process ID of the owner of the channel. If pid is zero, the calling process is assumed.
chid
The channel ID, returned by ChannelCreate(), of the channel to connect to the process.
index
The lowest acceptable connection ID.
flags
If flags contains _NTO_COF_CLOEXEC, the connection is closed when your process calls an exec*() function to start a new process.
Description:
The ConnectAttach() and ConnectAttach_r() kernel calls establish a connection between the calling process and the channel specified by chid owned by the process specified by pid on the node specified by nd. Any function that passes a node descriptor can use either the value 0 or the constant ND_LOCAL_NODE to refer to the local node.
These functions are identical except in the way they indicate errors. See the Returns section for details.
Description:
The ConnectAttach() and ConnectAttach_r() kernel calls establish a connection between the calling process and the channel specified by chid owned by the process specified by pid on the node specified by nd. Any function that passes a node descriptor can use either the value 0 or the constant ND_LOCAL_NODE to refer to the local node.
These functions are identical except in the way they indicate errors. See the Returns section for details.
7、name_attach()
Register a name in the namespace and create a channel
Synopsis:
#include <sys/iofunc.h>
#include <sys/dispatch.h>
name_attach_t * name_attach( dispatch_t * dpp,
const char * path,
unsigned flags );
Arguments:
dpp
NULL, or a dispatch handle returned by a successful call to dispatch_create() or dispatch_create_channel().
path
The path that you want to register under /dev/name/[local|global]/. This name shouldn't contain any path components consisting of .. or start with a leading slash (/).
flags
Flags that affect the function's behavior:
• NAME_FLAG_ATTACH_GLOBAL — attach the name globally instead of locally. See the gns utility.
Description:
The name_attach(), name_close(), name_detach(), and name_open() functions provide the basic pathname-to-server-connection mapping, without having to become a full resource manager.
If you've already created a dispatch structure, pass it in as the dpp. If you provide your own dpp, set flags to NAME_FLAG_DETACH_SAVEDPP when calling name_detach(); otherwise, your dpp is detached and destroyed automatically.
If you choose to pass a NULL as the dpp, name_attach() calls dispatch_create() and resmgr_attach() internally to create a channel, however, it doesn't set any channel flag by itself. The created channel will have the _NTO_CHF_DISCONNECT, _NTO_CHF_COID_DISCONNECT and _NTO_CHF_UNBLOCK flags set.
The name_attach() function puts the name path into the path namespace under /dev/name/[local|global]/path. The name is attached locally by default, or globally when you set NAME_FLAG_ATTACH_GLOBAL in the flags. You can see attached names in /dev/name/local and /dev/name/global directories.
SPI Comunication API
API library
The libspi-master library provides an interface to mediate access to the SPI master. The resource manager layer registers a device name (usually /dev/spi0). Applications access the SPI master by using the functions declared in <hw/spi-master.h>.
• spi_open()
• spi_close()
• spi_setcfg()
• spi_getdevinfo()
• spi_getdrvinfo()
• spi_read()
• spi_write()
• spi_xchange()
• spi_cmdread()
• spi_dma_xchange()
spi_open()
The spi_open() function lets the application connect to the SPI resource manager. The prototype for this function is:
int spi_open( const char *path );
The argument is:
path
The path name of the SPI device, usually /dev/spi0.
This function returns a file descriptor, or -1 if the open failed.
spi_setcfg()
The spi_setcfg() function sets the configuration for a specific device on the SPI bus. The prototype for this function is:
int spi_setcfg( int fd,
uint32_t device,
spi_cfg_t *cfg );
The arguments are:
fd
The file descriptor obtained by calling spi_open().
device
The device ID. You can OR it with SPI_DEV_DEFAULT to set the device as the default for this file descriptor.
cfg
A pointer to the configuration structure. This structure is:
typedef struct {
uint32_t mode;
uint32_t clock_rate;
} spi_cfg_t;
The possible mode settings are defined in <hw/spi-master.h>.
This function returns EOK if the configuration is successful.
spi_xchange()
The spi_xchange() function exchanges data between a specific device and the SPI master. The prototype for this function is:
int spi_xchange( int fd,
uint32_t device,
void *wbuf,
void *rbuf,
int len );
The arguments are:
fd
The file descriptor returned by spi_open().
device
The device ID with at most one of the following flags optionally ORed in:
• SPI_DEV_LOCK
• SPI_DEV_UNLOCK
wbuf
A pointer to the send buffer.
rbuf
A pointer to the receive buffer.
len
The length, in bytes, of the data to be exchanged.
The function returns the number of bytes of data that it successfully exchanged between the device and the SPI master. If an error occurred, the function returns -1 and sets errno:
spi_read()
The spi_read() function reads data from a specific device on the SPI bus. The prototype for this function is:
int spi_read( int fd,
uint32_t device,
void *buf,
int len );
The arguments are:
fd
The file descriptor returned by spi_open().
device
The device ID with at most one of the following flags optionally ORed in:
• SPI_DEV_LOCK
• SPI_DEV_UNLOCK
buf
A pointer to the read buffer.
len
The length, in bytes, of the data to be read.
The function returns the number of bytes of data that it successfully read from the device. If an error occurred, the function returns -1 and sets errno:
spi_write()
The spi_write() function writes data to a specific device on the SPI bus. The prototype for this function is:
int spi_write( int fd,
uint32_t device,
void *buf,
int len );
The arguments are:
fd
The file descriptor returned by spi_open().
device
The device ID with at most one of the following flags optionally ORed in:
• SPI_DEV_LOCK
• SPI_DEV_UNLOCK
buf
A pointer to the write buffer.
len
The length, in bytes, of the data to be written.
The function returns the number of bytes of data that it successfully wrote to the device. If an error occurred, the function returns -1 and sets errno:
Interrupt API
1、InterruptAttach(), InterruptAttach_r()、
Attach an interrupt handler to an interrupt source
Synopsis:
#include <sys/neutrino.h>
int InterruptAttach( int intr,
const struct sigevent * (* handler)(void *, int),
const void * area,
int size,
unsigned flags );
int InterruptAttach_r( int intr,
const struct sigevent * (* handler)(void *, int),
const void * area,
int size,
unsigned flags );
Arguments:
intr
The interrupt that you want to attach a handler to; see "Interrupt vector numbers," below.
handler
A pointer to the handler function; see "Interrupt handler function," below.
area
A pointer to a communications area in your process, or NULL if you don't want a communications area.
size
The size of the communications area; this should be 0 if area is NULL. InterruptAttach() currently ignores this argument.
flags
Flags that specify how you want to attach the interrupt handler. For more information, see "Flags," below.
Description:
The InterruptAttach() and InterruptAttach_r() kernel calls attach the interrupt function handler to the hardware interrupt specified by intr. They automatically enable (i.e., unmask) the interrupt level.
These functions are identical except in the way they indicate errors. See the Returns section for details.
Before calling either of these functions, the thread must:
• have the PROCMGR_AID_INTERRUPT and PROCMGR_AID_IO abilities enabled. For more information, see procmgr_ability().
• request I/O privileges by calling:
• ThreadCtl( _NTO_TCTL_IO, 0 );
If the thread doesn't do all of the above, the attachment fails with an error code of EPERM.
On a multicore system, the interrupt handler runs on the CPU that takes the interrupt.
Interrupt handler function
The function to call is specified by the handler argument. This function runs in the environment of your process, and the area and size arguments define a communications area in your process. This typically is a structure containing buffers and information needed by the handler and the process when it runs.
The handler function's prototype is:
const struct sigevent* handler( void* area, int id );
where area is a pointer to the area specified by the call to InterruptAttach(), and id is the ID returned by InterruptAttach().
Follow the following guidelines when writing your handler:
• A temporary interrupt stack of limited depth is provided at interrupt time, so avoid placing large arrays or structures on the stack frame of the handler. It's safe to assume that about 200 bytes of stack are available.
• The interrupt handler runs asynchronously with the threads in the process. Any variables modified by the handler should be declared with the volatile keyword and modified with interrupts disabled or using the atomic*() functions in any thread and ISR.
• The interrupt handler should be kept as short as possible. If a significant amount of work needs to be done, the handler should deliver an event to awaken a thread to do the work.
• The handler can't call library routines that contain kernel calls except for InterruptDisable(), InterruptEnable(), InterruptLock(), InterruptMask(), InterruptUnlock(), and InterruptUnmask().
The handler can call TraceEvent(), but not all of its commands are valid.
• It isn't safe to use floating-point operations in Interrupt Service Routines.