--- /dev/null
+/*
+ * ON-TRACK CAN abstraction layer library
+ * resembling and inspired by the Virtual CAN API from OCERA framework
+ *
+ * Contains parts of original Virtual/Versatile CAN API
+ * by Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * and Frantisek Vacek <vacek@rtime.felk.cvut.cz>, 2002
+ *
+ * Modified and adapted as a functional subset to run on system-less
+ * Philips LPC2xxx atop of "lpcan" CAN driver library
+ * by Marek Peca <mp@duch.cz>, 2008/04
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <types.h>
+#include <cpu_def.h>
+#include <errno.h>
+#include <can/canmsg.h>
+#include <can/lpcan.h>
+#include "lpcan_vca.h"
+
+#define valid(device) ((device >= 0) && (device < CAN_NUM_DEVICES))
+
+static struct vca_dev_t {
+ int open, flags;
+ uint32_t btr;
+ unsigned rx_ivect, tx_ivect, err_ivect;
+} vca_dev[CAN_NUM_DEVICES];
+
+inline void candev_init(int dev) {
+ can_init(dev, vca_dev[dev].btr,
+ vca_dev[dev].rx_ivect,
+ vca_dev[dev].tx_ivect,
+ vca_dev[dev].err_ivect,
+ NULL, 0);
+}
+
+inline int check_error(int dev) {
+ unsigned e = can_error(dev);
+ if (!e)
+ return 0;
+ if (e & ~CAN_ERR_RXOVER) {
+ /* CAN I/O error -- reinitialize the controller to recover operation */
+ cli();
+ can_off(dev);
+ candev_init(dev);
+ sti();
+ }
+ errno = EIO;
+ return e;
+}
+
+/**
+ * @param vcah_p points to location filled by new VCA handle
+ * @param dev CAN controller number (0, 1,...)
+ * @param flags flags modifying style of open (VCA_O_NOBLOCK)
+ * @param btr bit timing register (see LPC2xxx CAN docs), can be set by <code>lpcan_btr()</code> function from <em>lpcan</em> driver library
+ * @param rx_ivect receive interrupt vector number
+ * @param tx_ivect transmit interrupt vector number
+ * @param err_ivect error interrupt vector number
+ * @return VCA_OK in case of success
+ *
+ * Opens new VCA handle on LPC2xxx hardware.
+ *
+ * Interrupt vector numbers (see LPC2xxx VIC documentation) must be supplied
+ * by the caller in order to avoid conflicts with rest of hardware.
+ */
+int lpc_vca_open_handle(vca_handle_t *vcah_p, int dev, int flags, uint32_t btr, unsigned rx_ivect, unsigned tx_ivect, unsigned err_ivect) {
+ if (!valid(dev)) {
+ errno = ENODEV;
+ return -1;
+ }
+ vca_dev[dev].flags = flags;
+ vca_dev[dev].btr = btr;
+ vca_dev[dev].rx_ivect = rx_ivect;
+ vca_dev[dev].tx_ivect = tx_ivect;
+ vca_dev[dev].err_ivect = err_ivect;
+ vca_dev[dev].open = 1;
+ candev_init(dev);
+ *vcah_p = dev;
+ return VCA_OK;
+}
+
+/**
+ * @param vcah VCA handle
+ * @return VCA_OK in case of success
+ *
+ * Closes previously acquired VCA handle.
+ */
+int vca_close_handle(vca_handle_t vcah) {
+ if (!valid(vcah)) {
+ errno = ENODEV;
+ return -1;
+ }
+ if (!vca_dev[vcah].open) {
+ errno = EBADF;
+ return -1;
+ }
+ vca_dev[vcah].open = 0;
+ can_off(vcah);
+ return VCA_OK;
+}
+
+/**
+ * @param vcah VCA handle
+ * @param messages points to continuous array of CAN messages to send
+ * @param count count of messages in array
+ * @return Number of sucessfully sent messages or error < 0
+ *
+ * Sends sequentially block of CAN messages.
+ */
+int vca_send_msg_seq(vca_handle_t vcah, canmsg_t *messages, int count) {
+ int m, rc;
+ if (check_error(vcah))
+ return -1;
+ for (m = 0; m < count; m++) {
+ if (vca_dev[vcah].flags & VCA_O_NONBLOCK) {
+ rc = can_tx_msg(vcah, &messages[m]);
+ if (rc) {
+ if (check_error(vcah))
+ return -1;
+ errno = EAGAIN;
+ return m;
+ }
+ }
+ else {
+ do {
+ rc = can_tx_msg(vcah, &messages[m]);
+ if (check_error(vcah))
+ return -1;
+ } while (rc);
+ }
+ }
+ if (check_error(vcah))
+ return -1;
+ return m;
+}
+
+/**
+ * @param vcah VCA handle
+ * @param messages points to array for received CAN messages
+ * @param count number of message slots in array
+ * @return number of received messages or error < 0
+ *
+ * Receive sequential block of CAN messages.
+ */
+int vca_rec_msg_seq(vca_handle_t vcah, canmsg_t *messages, int count) {
+ int m, rc;
+ if (check_error(vcah))
+ return -1;
+ for (m = 0; m < count; m++) {
+ if (vca_dev[vcah].flags & VCA_O_NONBLOCK) {
+ rc = can_rx_msg(vcah, &messages[m]);
+ if (rc) {
+ if (check_error(vcah))
+ return -1;
+ errno = EAGAIN;
+ return m;
+ }
+ }
+ else {
+ do {
+ rc = can_rx_msg(vcah, &messages[m]);
+ if (check_error(vcah))
+ return -1;
+ } while (rc);
+ }
+ }
+ if (check_error(vcah))
+ return -1;
+ return m;
+}
+
+/**
+ * @param vcah VCA handle
+ * @param wait_msec number of miliseconds to wait, 0 => forever
+ * @param what 0,1 => wait for Rx message, 2 => wait for Tx - free
+ * 3 => wait for both
+ * @return Positive value if wait condition is satisfied
+ *
+ * Blocking wait for the new message(s) or sending.
+ * Currently, no timeout is implemented on LPC2xxx, so only infinite
+ * waiting (wait_msec = 0) or no waiting (wait_msec != 0) can be performed.
+ */
+int vca_wait(vca_handle_t vcah, int wait_msec, int what) {
+ if (!what)
+ what = 1;
+ do {
+ if (check_error(vcah))
+ return -1;
+ if ((what & 1) && !can_rx_empty(vcah))
+ return 1;
+ if ((what & 2) && can_tx_empty(vcah))
+ return 2;
+ } while (wait_msec == 0);
+ return 0;
+}
+
+/* EOF */