#ifndef __CAN_CODES_H__
#define __CAN_CODES_H__

/** \file can_codes.h
 * \brief Файл содержит описание структур данных и констант для работы с платами CAN200.
 * \warning Файл подключается автоматически при подключении файла can200_api.h
 */

/** \mainpage Библиотека для работы с платами CAN-200PC, CAN-200MP, CAN-200PC104, CAN-200PCI, CAN-200-104PCI и CAN-200PCIe
 *
 * Библиотека функций предназначена для предоставления доступа к ресурсам плат серии CAN-200PC, CAN-200MP, CAN-200PC104, CAN-200PCI, CAN-200-104PCI и CAN-200PCIe.
 *
 * \par Условия работы
 *
 * Установленное оборудование:
 * \li IBM PC совместимый компьютер Pentium II или выше
 *
 * Программное обеспечение:
 * \li QNX Momentics Integrated Development Environment (Version: 4.7.0)
 *
 * Поддерживаемые операционные системы:
 * \li QNX 6.5.0 (x86)
 *
 * Поддерживаемые платы:
 * \li CAN-200PCI
 * \li CAN-200-104PCI
 * \li CAN-200PCIe
 * \li CAN-200PC
 * \li CAN-200MP
 * \li CAN-200PC104
 *
 * Платы серии CAN-200 содержат два (CAN-200PC, CAN-200MP, CAN-200PC104, CAN-200PCI и CAN-200PCIe) или четыре (CAN-200-104PCI) полностью независимых CAN-канала.
 * Каждый CAN-канал построен на CAN-контроллере PCA82C200 фирмы Philips.
 * Этот CAN-контроллер поддерживает на аппаратном уровне обмен данными по протоколу CAN 2.0 part A.
 * В 2002 году CAN-контроллер PCA82C200 снят с производства и в качестве его замены на платы серии CAN-200
 * устанавливается CAN-контроллер SJA1000, поддерживающий (в режиме #PeliCAN) обмен данными по протоколу CAN 2.0 part B active.
 * Этот CAN-контроллер имеет два режима функционирования: #BasicCAN и #PeliCAN.
 * \li Режим #BasicCAN является режимом, обеспечивающим совместимость с CAN-контроллером PCA82C200.
 * В этом режиме возможен обмен только стандартными кадрами (с 11-битным идентификатором).
 * \li Режим #PeliCAN является режимом, обеспечивающим более гибкую настройку CAN-контроллера, удобный мониторинг CAN-сети
 * и предоставляет возможность обмена кадрами с расширенным идентификатором (29-битным).
 *
 * \par Драйвер плат CAN-200
 *
 * Драйвер плат CAN-200 представляет собой исполняемый файл.
 * <br>Запуск драйвера осуществляется командой <em><b>./can200 [-a base_porta1[,base_porta2...] –b base_portb1[,base_portb2...] –i interrupt1[,interrupt2...]] [-p priority] [-n counter] [-r]</b></em>, где
 * <br><em><b>base_porta1, base_porta2...</b></em> – базовые адреса канала 1 для плат CAN-200PC, CAN-200MP, CAN-200PC104 (до 10 штук);
 * <br><em><b>base_portb1, base_portb2...</b></em> – базовые адреса канала 2 для плат CAN-200PC, CAN-200MP, CAN-200PC104 (до 10 штук);
 * <br><em><b>interrupt1, interrupt2...</b></em> – номера прерываний для плат CAN-200PC, CAN-200MP, CAN-200PC104 (до 10 штук);
 * <br><em><b>priority</b></em> – приоритет потоков обслуживающих прерывания (по умолчанию – 150);
 * <br><em><b>counter</b></em> - количество попыток выдачи каждого кадра при программном повторе выдачи (по умолчанию - 128);
 * <br>флаг <em><b>r</b></em> позволяет настроить выдачу кадров с аппаратным повтором.
 *
 * По умолчанию выдача каждого кадра производится однократно, при успешной выдаче драйвер переходит к выдаче следующего кадра.
 * В случает отказа выдачи кадра драйвер уменьшает счетчик повторных попыток выдачи (задаваемых при старте драйвера флагом n)
 * и повторяет попытку выдачи кадра. При достижении счетчиком значения 0 драйвер формирует отказ выдачи.
 *
 * При использовании драйвера для плат CAN-200PC, CAN-200MP и CAN-200PC104 обязательно должны указываться параметры базовых
 * портов и номера прерываний для каждой из плат (устанавливаются перемычками на платах).
 * Платы CAN-200PCI, CAN-200-104PCI и CAN-200PCIe настраиваются автоматически.
 * Драйвер поддерживает до 10 плат серии CAN-200.
 * При работе драйвер создает в каталоге /dev файлы вида can200_n (по два или четыре файла на каждую плату).
 * Каждый такой файл представляет собой один канал платы серии CAN-200.
 *
 * \par Основы использования библиотеки
 * 1. Открыть требуемую плату для работы
 * \code
 * int hCan;
 * hCan = open(file, O_RDWR); // или hCan = open(file, O_RDWR | O_NONBLOCK);
 * if (-1 == hCan)
 * {
 *		// Обработка ошибки
 * }
 * \endcode
 * Указание флага O_NONBLOCK в вызове функции open позволяет открыть плату в неблокирующем режиме.
 * 2. Установить требуемую скорость и режим обмена по шине CAN
 * \code
 * result = CAN200_SetWorkMode(hCan, PeliCAN);
 * if (EOK != result)
 * {
 *		// Обработка ошибки
 *
 * result = CAN200_SetCANSpeed(hCan, CAN_SPEED_1000);
 * if (EOK != result)
 * {
 *		// Обработка ошибки
 * }
 * \endcode
 * 3. Установить фильтр для приема кадров
 * \code
 * // Разрешаем прием всех кадров
 * result = CAN200_P_SetFilter(hCan, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
 * if (EOK != result)
 * {
 *		// Обработка ошибки
 * }
 * \endcode
 * 4. Разрешить работу платы
 * \code
 * // Разрешаем работу платы
 * result = CAN200_SetDriverMode(hCan);
 * if (EOK != result)
 * {
 *		// Обработка ошибки
 * }
 * \endcode
 * 5. С использованием функций
 * \code
 * read, write, select
 * \endcode
 * организовать прием и выдачу CAN кадров.
 * <br>
 * Поведение функций read и write отличается в зависимости от наличия флага O_NONBLOCK при открытии платы.
 * <br>
 * Функция read в блокирующем режиме (плата открыта без указания флага O_NONBLOCK) будет ожидать приема
 * указанного пользователем кол-ва CAN пакетов. Возврат из функции возможен в двух случаях: при приеме указанного
 * пользователем кол-ва кадров или при переходе платы в режим BUS-OFF.
 * <br>
 * В неблокирующем режиме (плата открыта с указанием флага O_NONBLOCK) функция read вернет столько кадров, сколько есть
 * в буфере приема (но не более чем запросил пользователь). Если в буфере приема нет данных по функция вернет 0.
 * <br>
 * Функция write в блокирующем режиме поставит указанное пользователем кол-во CAN кадров в очередь выдачи и будет
 * ожидать окончания их выдачи. Возврат из функции возможен в двух случаях: после окончания выдачи всех переданных ей кадров
 * или при переходе платы в режим BUS-OFF.
 * <br>
 * В неблокирующем режиме функция write поставит указанное пользователем кол-во CAN кадров в очередь выдачи и
 * вернет управление не ожидаю окончания выдачи. Для определения окончания выдачи можно использовать функцию
 * #CAN200_GetTransmitStatus.
 * <br>
 * При попытке выдать следующую порцию данных (в неблокирующем режиме) до окончания выдачи предыдущей функция
 * write вернет код ошибки EAGAIN.
 * 6. После окончания работы закрыть плату
 * \code
 * result = close(hCan);
 * if (0 != result)
 * {
 *		// Обработка ошибки
 * }
 * \endcode
 */

/**
 * \example test-read.c
 */
/**
 * \example test-write.c
 */

/**
 * \defgroup Speed Значения скорости обмена по шине CAN
 */

/**
 * \defgroup Mode Режимы работы каналов плат
 */

/**
 * \defgroup DropMode Режимы отбрасывания выдаваемыз кадров (для функции CAN200_DropTransmit)
 */

/**
 * \defgroup TransmitStatus Состояния выдачи кадра
 */

/**
 * \defgroup PeliCAN Функции для работы с платой в режиме PeliCAN
 */

/**
 * \defgroup BasicCAN Функции для работы с платой в режиме BasicCAN
 */

#include <sys/time.h>

#pragma pack(1)

/**
 * \struct CAN_info_t
 * \brief Структура для получения информации о плате.
 *
 * Поля структуры содержат информацию о плате серии CAN200
 */
struct CAN_info_t
{
	/**
	 * \brief Имя платы
	 *
	 * Строка вида CAN-200PCI(e) vX.Y, где vX.Y – номер версии платы
	 */
	char szName[128];
	/**
	 * \brief Серийный номер платы
	 */
	char szSN[10];
	/**
	 * \brief Базовый адрес
	 */
	int  wPorts;
	/**
	 * \brief Номер вектора прерывания
	 */
	int  wIRQ;
};

/**
 * \union CAN_status_t
 * \brief Структура описывающая статус платы
 */
union CAN_status_t
{
	struct
	{
		/**
		 * \brief Состояние буфера приема
		 *
		 * 0 - буфер приема пуст
		 *
		 * 1 - буфер приема содержит принятое сообщение
		 */
		unsigned char rbs			: 1;
		/**
		 * \brief Переполнение приемного буфера
		 *
		 * 0 - переполнения приёмного буфера нет
		 *
		 * 1 - произошло переполнение приёмного буфера
		 */
		unsigned char dos			: 1;
		/**
		 * \brief Доступность буфера передачи
		 *
		 * 0 - буфер передачи не доступен
		 *
		 * 1 - буфер передачи доступен
		 */
		unsigned char tbs			: 1;
		/**
		 * \brief Завершенность передачи
		 *
		 * 0 - последняя передача была не завершена
		 *
		 * 1 - последняя передача успешно завершена
		 */
		unsigned char tcs			: 1;
		/**
		 * \brief Состояние приёма
		 *
		 * 0 - приема данных нет
		 *
		 * 1 - CAN-контроллер принимает данные
		 */
		unsigned char rs			: 1;
		/**
		 * \brief Состояние передачи
		 *
		 * 0 - передачи данных нет
		 *
		 * 1 - CAN-контроллер передает данные
		 */
		unsigned char ts			: 1;
		/**
		 * \brief Наличие ошибок
		 *
		 * 0 - ни один из счётчиков ошибок не достиг предельного значения
		 *
		 * 1 - по крайней мере один из счётчиков ошибок достиг предельного значения
		 */
		unsigned char es			: 1;
		/**
		 * \brief Состояние шины
		 *
		 * 0 - канал участвует в работе CAN–шины
		 *
		 * 1 - канал отключен от CAN–шины
		 */
		unsigned char bs			: 1;
	} bit;
	unsigned char byte;
};

/**
 * \struct CAN_data
 * \brief Принятый/выдаваемый CAN кадр
 *
 * Поля структуры содержат информацию кадра принятого или выдаваемого платой CAN200
 */
typedef struct
{
	/**
	 * \brief Формат кадра
	 *
	 * #BasicCAN - стандартный кадр
	 *
	 * #PeliCAN - расширенный кадр
	 *
	 * #ErrorCAN - ошибка (только для приема)
	 */
	unsigned char  type;
	/**
	 * \brief Идентификатор
	 *
	 * 11-ти битный идентификатор принятого кадра (действителен только при #type = #BasicCAN)
	 *
	 * 29-ти битный идентификатор принятого кадра (действителен только при #type = #PeliCAN)
	 */
	unsigned long  id;
	/**
	 * \brief Значение бита RTR (0 или 1)
	 */
	unsigned char  rtr;
	/**
	 * \brief Количество принятых/выдаваемых байт данных (0-8)
	 */
	unsigned char  dlc;
	/**
	 * \brief Выдаваемые/принимаемые данные (от 0 до 8 байт)
	 *
	 * Реальное количество принимаемых/выдаваемых данных определяется полем #dlc
	 */
	unsigned char  data[8];
	/**
	 * \brief Время приема кадра
	 */
	struct timeval timestamp;
} CAN_data, *pCAN_data;

/**
 * \union CAN_error_t
 * \brief Структура для кода ошибки.
 */
union CAN_error_t
{
	struct
	{
		/**
		 * \brief Сегмент
		 *
		 * b00011 - начало кадра
		 *
		 * b00010 - идентификатор: биты 28-21
		 *
		 * b00110 - идентификатор: биты 20-18
		 *
		 * b00100 - бит SRTR
		 *
		 * b00101 - бит IDE
		 *
		 * b00111 - идентификатор: биты 17-13
		 *
		 * b01111 - идентификатор: биты 12-5
		 *
		 * b01110 - идентификатор: биты 4-0
		 *
		 * b01100 - бит RTR
		 *
		 * b01101 - зарезервированный бит 1
		 *
		 * b01001 - зарезервированный бит 0
		 *
		 * b01011 - код длины данных
		 *
		 * b01010 - поле данных
		 *
		 * b01000 - CRC последовательность
		 *
		 * b11000 - разделитель CRC
		 *
		 * b11001 - интервал подтверждения
		 *
		 * b11011 - разделитель подтверждения
		 *
		 * b11010 - конец кадра
		 *
		 * b10010 - перерыв на шине
		 *
		 * b10001 - флаг активной ошибки
		 *
		 * b10110 - флаг пассивной ошибки
		 *
		 * b10011 - tolerate dominant bits
		 *
		 * b10111 - разделитель ошибки
		 *
		 * b11100 - флаг переполнения
		 */
		unsigned char seg	: 5;
		/**
		 * \brief Направление
		 *
		 * 0 - TX (ошибка в тецение выдачи)
		 *
		 * 1 - RX (ошибка в течение приема)
		 */
		unsigned char dir	: 1;
		/**
		 * \brief Код ошибки
		 *
		 * 0 - битовая ошибка
		 *
		 * 1 - ошибка формы
		 *
		 * 2 - ошибка заполнения
		 *
		 * 3 - другая ошибка
		 */
		unsigned char errc	: 2;
	} bit;
	unsigned char byte;
};

/**
 * \union CAN_arbitration_lost_capture_t
 * \brief Структура определения точки потери арбитража.
 */
union CAN_arbitration_lost_capture_t
{
	struct
	{
		/**
		 * \brief Точка потери арбитража
		 *
		 * b00000 - бит 1 идентификатора
		 *
		 * b00001 - бит 2 идентификатора
		 *
		 * b00010 - бит 3 идентификатора
		 *
		 * b00011 - бит 4 идентификатора
		 *
		 * b00100 - бит 5 идентификатора
		 *
		 * b00101 - бит 6 идентификатора
		 *
		 * b00110 - бит 7 идентификатора
		 *
		 * b00111 - бит 8 идентификатора
		 *
		 * b01000 - бит 9 идентификатора
		 *
		 * b01001 - бит 10 идентификатора
		 *
		 * b01010 - бит 11 идентификатора
		 *
		 * b01011 - бит SRTR (бит RTR для кадров со стандартным идентификатором)
		 *
		 * b01100 - бит IDE
		 *
		 * b01101 - бит 12 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b01110 - бит 13 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b01111 - бит 14 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10000 - бит 15 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10001 - бит 16 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10010 - бит 17 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10011 - бит 18 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10100 - бит 19 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10101 - бит 20 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10110 - бит 21 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b10111 - бит 22 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11000 - бит 23 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11001 - бит 24 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11010 - бит 25 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11011 - бит 26 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11100 - бит 27 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11101 - бит 28 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11110 - бит 29 идентификатора (только для кадров с расширенным идентификатором)
		 *
		 * b11111 - бит RTR (только для кадров с расширенным идентификатором)
		 */
		unsigned char alc	: 5;
		/**
		 * \brief Зарезервировано
		 */
		unsigned char rsvd	: 3;
	} bit;
	unsigned char byte;
};

/** \cond */
/* Структура для задания фильтра режима BasicCAN */
struct b_filter_t
{
	unsigned char mask;
	unsigned char filter;
};

/* Структура для задания фильтра режима PeliCAN */
struct p_filter_t
{
	unsigned char mode;
	unsigned char mask[4];
	unsigned char filter[4];
};

/* Структура для получения статуса выдачи */
struct transmit_status_t
{
	int status;
	int len;
};

union devctl_req_t
{
	unsigned char            mode;			/* Режим работы канала платы */
	struct CAN_info_t        info;			/* Информация о плате */
	unsigned int             speed;			/* Скорость канала платы */
	unsigned char            status;		/* Статус канала платы */
	struct b_filter_t        b_filter;		/* Фильтр режима BasicCAN */
	struct p_filter_t        p_filter;		/* Фильтр режима PeliCAN */
	unsigned char            counter;		/* Счетчик */
	int                      over_counter;	/* Счетчик переполнений */
	struct transmit_status_t sts;			/* Статус выдачи */
	unsigned char            code;			/* Код ошибки */
	unsigned char            command;		/* Код команды для отмены выдачи */
	int                      num_channel;	/* Количество каналов в плате */
	int                      version;		/* Версия драйвера */
};
/** \endcond */

#pragma pack()

/**
 * \addtogroup TransmitStatus
 * \{
 */
#define CAN_TRANSMIT_WAIT		0		///< Ожидает начала выдачи
#define CAN_TRANSMIT			1		///< Идет выдача
#define CAN_TRANSMIT_COMPLETE	2		///< Выдача завершена успешно
#define CAN_TRANSMIT_ERROR		3		///< Выдача завершена из-за ошибки
#define CAN_TRANSMIT_DROP		4		///< Выдача отменена
/** \} */

/**
 * \addtogroup DropMode
 * \{
 */
#define CAN_DROP_CURRENT	0		///< Удаление из очереди выдачи пакетов, добавленных в нее текущим потоком
#define CAN_DROP_ALL		1		///< Полная очистка очереди выдачи
/** \} */

/**
 * \addtogroup Mode
 * \{
 */
#define BasicCAN			0		///< Основной режим
#define PeliCAN				1		///< Расширенный режим
#define ErrorCAN			2		///< Состояние ошибки
/** \} */

/**
 * \addtogroup Speed
 * \{
 */
#define CAN_SPEED_USER_DEFINED(btr0, btr1)	(0xffff | (((btr0) & 0xff) << 24) | (((btr1) & 0xff) << 16))	///< Скорость определенная пользователем
#define IS_CAN_SPEED_USER_DEFINED(speed)	((0xffff == ((speed) & 0xffff)) ? 1 : 0)	///< 1 - скорость определяемая пользователем, 0 - одна из стандартных скоростей
#define CAN_SPEED_GET_BTR0(speed)	(((speed) >> 24) & 0xff)	///< Возвращает значение регсистра BTR0 для скоростей задаваемых пользователем
#define CAN_SPEED_GET_BTR1(speed)	(((speed) >> 16) & 0xff)	///< Возвращает значение регсистра BTR1 для скоростей задаваемых пользователем
#define CAN_SPEED_1000			1000	///< Скорость 1 Mbit/sec
#define CAN_SPEED_800			800		///< Скорость 800 kbit/sec
#define CAN_SPEED_500			500		///< Скорость 500 kbit/sec
#define CAN_SPEED_250			250		///< Скорость 250 kbit/sec
#define CAN_SPEED_125			125		///< Скорость 125 kbit/sec
#define CAN_SPEED_50			50		///< Скорость 50 kbit/sec
#define CAN_SPEED_20			20		///< Скорость 20 kbit/sec
#define CAN_SPEED_10			10		///< Скорость 10 kbit/sec
/** \} */

// Команды управления платами
/** \cond */
#define CAN_HARDRESET						0	// Аппаратный сброс контроллера канала платы
#define CAN_SETWORKMODE						1	// Установка режима работы канала платы
#define CAN_GETWORKMODE						2	// Получение режима работы канала платы
#define CAN_SETDRIVERMODE					3	// Настройка выходного формирователя CAN-контроллера
#define CAN_GETCANSPEED						4	// Получение скорости работы канала платы
#define CAN_SETCANSPEED						5	// Установка скорости работы канала платы
#define CAN_GETSTATUS						6	// Получение статуса канала платы
#define CAN_GETCONFIG						7	// Получение конфигурации платы
#define CAN_B_SETFILTER						8	// Установка фильтра режима BasicCAN канала платы
#define CAN_P_SETFILTER						9	// Установка фильтра режима PeliCAN канала платы
#define CAN_P_GETRXERRORCOUNTER				10	// Получение счетчика ошибок приема режима PeliCAN канала платы
#define CAN_P_SETRXERRORCOUNTER				11	// Установка счетчика ошибок приема режима PeliCAN канала платы
#define CAN_P_GETTXERRORCOUNTER				12	// Получение счетчика ошибок выдача режима PeliCAN канала платы
#define CAN_P_SETTXERRORCOUNTER				13	// Установка счетчика ошибок выдачи режима PeliCAN канала платы
#define CAN_P_GETERRORWARNINGLIMIT			14	// Получение верхнего предела счетчиков ошибок режима PeliCAN канала платы
#define CAN_P_SETERRORWARNINGLIMIT			15	// Установка верхнего предела счетчиков ошибок режима PeliCAN канала платы
#define CAN_B_GETFILTER						16	// Получение фильтра режима BasicCAN канала платы
#define CAN_P_GETFILTER						17	// Получение фильтра режима PeliCAN канала платы
#define CAN_GETOVERCOUNTER					18	// Получение счетчика переполнений приема канала платы
#define CAN_SETBUSON						19	// Переключение канала в рабочий режим, после Bus Off
#define CAN_GETTRANSMITSTATUS				20	// Получение статуса выдачи пакета
#define CAN_P_GETERRORCODE					21	// Получение кода ошибки
#define CAN_P_GETEARBITRATIONLOSTCAPTURE	22	// Получение точки потери данных
#define CAN_DROPTRANSMIT					23	// Отмена выдачи
#define CAN_GETNUMCHANNEL					24	// Запрос количества каналов в плате
#define CAN_GETDRIVERVERSION				25	// Получение версии драйвера
/** \endcond */

#endif /* __CAN_CODES_H__ */
