/// <summary> /// Открывает драйвер порта /// </summary> /// <exception cref="InvalidOperationException"></exception> public override void Open() { String msg; F_CAN_RESULT result; F_CAN_SETTINGS settings; settings = new F_CAN_SETTINGS(); settings.acceptance_code = 0; settings.acceptance_mask = 0; settings.baud_rate = ConvertNim351.ConvertToF_CAN_BAUDRATE(this.BitRate); //settings.error_mask = CAN_OPMODE_ERRFRAME.CAN_ERR_CRTL | CAN_OPMODE_ERRFRAME.CAN_ERR_BUSOFF ; settings.error_mask = 0xFFFF; settings.opmode = (UInt16)Api.OpModeBuilder(this.Mode, this.FrameFormat, this.ErrorFrameEnable); // Инициализация библиотеки result = Api.fw_can_init(); if (!Api.f_can_success(result)) { msg = String.Format("Ошибка при иницилизации fwcan.dll, Error: {0}", result); throw new InvalidOperationException(msg); } // Открываем адаптер CAN и получаем дескриптор порта result = Api.fw_can_open(Api.GetPortNumber(this.PortName), out this._DeviceHandle); if (!Api.f_can_success(result)) { msg = String.Format("Ошибка при открытии CAN адаптера, Error: {0}", result); throw new InvalidOperationException(msg); } // Конфигурируем контроллер result = Api.fw_can_set_controller_config(_DeviceHandle, ref settings); if (!Api.f_can_success(result)) { msg = String.Format("Ошибка при записи настроек в контроллер. Error: {0}", result); throw new InvalidOperationException(msg); } // Конфигурируем таймауты result = Api.fw_can_set_timeouts(_DeviceHandle, ref _Timeouts); if (!Api.f_can_success(result)) { msg = String.Format("Ошибка при установке таймаутов. Error: {0}", result); throw new InvalidOperationException(msg); } // Обновляем и проверяем статус порта if (!this.UpdatePortStatus()) { msg = String.Format("Ошибка. При открытии порта его статус остался неизменным: {0}", this.PortStatus); throw new Exception(msg); } return; }
/// <summary> /// Читает текущий статус адаптера и сравнивает с предыдущим. Если /// отличается генерирует событие и сохраняет новый статус /// </summary> /// <returns>true - если статус изменился</returns> private Boolean UpdatePortStatus() { F_CAN_STATE newStatus; Boolean result; if (this.IsOpen) { newStatus = this.GetPortStatus(); if (this._PortStatus != newStatus) { // Статус изменился. this._PortStatus = newStatus; this.OnPortChangesStatus(ConvertNim351.ConvertToCanPortStatus(this._PortStatus)); result = true; } else { result = false; } } else { // Если порт закрыт, есго статус должен быть F_CAN_STATE.CAN_STATE_STOPPED. // Если это не так, то устанавливаем и генерируем событие if (this._PortStatus == F_CAN_STATE.CAN_STATE_STOPPED) { result = false; } else { // Статус изменился. this._PortStatus = F_CAN_STATE.CAN_STATE_STOPPED; this.OnPortChangesStatus(ConvertNim351.ConvertToCanPortStatus(this._PortStatus)); result = true; } } return(result); }
/// <summary> /// Записывает сообщение в порт /// </summary> /// <param name="message">Сообщение для оправки</param> public override void Write(Frame message) { String msg; F_CAN_RESULT result; F_CAN_TX buffer; F_CAN_STATE status; uint count = 0; // Если прот закрыт, отсылка сообщения не возможна if (!this.IsOpen) { msg = "Невозможно отправить сообщение, CAN-порт закрыт"; throw new InvalidOperationException(msg); } status = this.GetPortStatus(); if (this.PortStatus != CanPortStatus.IsActive) { msg = "Невозможно отправить сообщение, CAN-порт отключён от физической сети"; throw new InvalidOperationException(msg); } // Разбираем сообщение и подготавливаем его для отправки buffer.msg = ConvertNim351.ConvertToF_CAN_MSG(message); result = Api.fw_can_send(this._DeviceHandle, ref buffer, 1, ref count); //result = Api.fw_can_post_message(this._DeviceHandle, ref buffer); if (!Api.f_can_success(result)) { // При отправке сообщения возникла ошибка msg = String.Format("Не удалось отправить сообщение. Error: ", result); throw new InvalidOperationException(msg); } return; }
/// <summary> /// Метод для чтения порта. Запускается во вторичном потоке. Поток на чтение запускается при открытии порта /// и завершается при закрытии. /// </summary> private void HandleQueueIncomingMessages() { String msg; F_CAN_RESULT result; F_CAN_RX buffer; F_CAN_WAIT wait; UInt32 timeout = 500; // мсек Frame message; //uint count; // Если прот закрыт, чтение его буфера не возможно //if (this.IsOpen == false) //{ // msg = "Невозможно прочитать очередь сообщений, CAN-порт закрыт"; // throw new InvalidOperationException(msg); //} // Читаем порт всё время пока открыт while (this._FlagMustQuit > 0) { wait.waitMask = F_CAN_STATUS.CAN_STATUS_EMPTY | F_CAN_STATUS.CAN_STATUS_TXBUF; wait.status = F_CAN_STATUS.CAN_STATUS_EMPTY; result = Api.fw_can_wait(this._DeviceHandle, ref wait, timeout); if ((result == F_CAN_RESULT.CAN_RES_OK) || (result == F_CAN_RESULT.CAN_RES_TIMEOUT)) { if (result == F_CAN_RESULT.CAN_RES_TIMEOUT) { //Console.WriteLine("Сработал таймаут ожидания"); // Произошло что-то нехорошее, нужно анализировать и что-то делать // Проверяем текущий статус //if (wait.status == wait.waitMask) //{ } // Останавливаем порт this.Stop(); // Генерируем событие OnErrorReceived(ERROR.Other); // Закрываем порт this.Close(); // Завершаем работу потока Interlocked.Exchange(ref this._FlagMustQuit, 0); continue; } // Если флаг установлен, то есть принятые сообщения. Читаем их // и помещаем в буфер исходящих сообщений if (F_CAN_STATUS.CAN_STATUS_RXBUF == (wait.status & F_CAN_STATUS.CAN_STATUS_RXBUF)) { // Читаем буфер адаптера result = Api.fw_can_peek_message(_DeviceHandle, out buffer); // Разбираем принятое сообщение и формируем событие message = new Frame(); message = ConvertNim351.ConvertToFrame(buffer.msg); // Помещает принятое сообщение в буфер входных сообщений и генерируем событие приёма lock (_SyncRoot) { this._InputBufferMessages.Enqueue(message); } this.OnMessageReceived(); } // Произошла ошибка читаем её и сбрасываем if (F_CAN_STATUS.CAN_STATUS_ERR == (wait.status & F_CAN_STATUS.CAN_STATUS_ERR)) { F_CAN_ERRORS errors; result = Api.fw_can_get_clear_errors(this._DeviceHandle, out errors); if (Api.f_can_success(result)) { // Анализируем счётчики и генерируем событие this.OnErrorReceived(ERROR.Other); } else { msg = String.Format( "При чтении и сбросе счётчика ошибок CAN-адаптера возникла ошибка: {0}", result); throw new InvalidOperationException(msg); } } } else { msg = String.Format("При выполнении функции fw_can_wait произошла ошибка: {0}", Enum.GetName(typeof(F_CAN_RESULT), result)); throw new InvalidOperationException(msg); } } return; }