Тонкости работы с COM портом

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Сообщение Attid » 21.11.2007 19:32:58

Код: Выделить всё
  Connect(comport); // конектимся
  if InstanceActive then // если подключились то настраиваем и работаем
  begin
    Config(9600, 8, 'N', 0, false, false);
    SendString****
  end
  else  // не подключились, ругаемся или ждем или пробуем по кругу
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2585
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение swa1 » 21.11.2007 20:05:17

Спасибо Attid.... Я просто вывел для начала сообщение о состоянии InstanceActive и LastError и получается так как я писал выше

com1 - занят
com6 - свободен
------------
1- Попытка подключения к com1 сразу после запуска
InstanceActive=False
LastError=5

2-подключение к com6
InstanceActive=True
LastError=0
Отключаемся

3-повторное подключение к com1
InstanceActive=True
LastError=0
:shock: .......Бр-р-р....нихт ферштее

Код: Выделить всё
procedure TForm1.OpenPort2Click(Sender: TObject);
var
  Str:String;
begin
   if OpenPort2.Checked=True then
   begin
    Port2:=TBlockserial.Create;
//    Port2.RaiseExcept:=true;
    Port2.Connect(SelectPort2.Text);
    if Port2.InstanceActive=True then Memo1.Lines.Add('InstanceActive=True ') else Memo1.Lines.Add('InstanceActive=False '); //  пишу состояние InstanceActive
    if Port2.LastError<>0  then
    begin
      Memo1.Lines.Add(' ОШИБКА - '+IntToStr(Port2.LastError));
      Memo1.Lines.Add(Port2.LastErrorDesc);
      OpenPort2.Checked:=False;
    end;
    Port2.EnableRTSToggle(true);
    Port2.Config(9600,8,'N',0,false,false);
    Memo1.Lines.Add('открытое устр-во'+Port2.Device); // проверяю, а то ли я открыл ?
    StrPort2.Enabled:=True;
    SendPort2.Enabled:=True;
    Vizual2:= TPort2Vizual.Create(false); // это поток для отображения состояния CTS и DSR
    Vizual2.Priority:=tpIdle;
    Read2:= TPort2Read.Create(false);  // поток чтения из порта и записи в Memo
    Read2.Priority:=tpIdle;
    RTS2.Color:=clTeal;
    DTR2.Color:=clTeal;
    Str:=' открыт';
   end
   else
   begin
    Port2.Free;
    Vizual2.Free;
    Read2.Free;
    SendPort2.Enabled:=False;
    StrPort2.Enabled:=False;
    DTR2.Color:=clNone;
    DSR2.Color:=clNone;
    RTS2.Color:=clNone;
    CTS2.Color:=clNone;
    RXD2.Color:=clNone;
    TXD2.Color:=clNone;
    LEDPort2.Color:=clNone;
    Str:=' закрыт';
   end;
   Memo1.Lines.Add('порт '+SelectPort2.Text+Str);
end;
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение Attid » 22.11.2007 00:04:53

тебе надо рефакторинг кода сделать =)
еле понял что к чему.

тут гадать только на кофейной гуще можно, но если
1 2 3
повотряются постояно
и если 1 2 (перезапускаем) 1 2 (перезапускаем) 1 2 (перезапускаем) 1 2

тогда ошибка или в коде или в днк =) если
во втором случае тоже будет ошибка, то ошибка в классе блоксериал
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2585
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение swa1 » 22.11.2007 13:29:27

Attid писал(а):тебе надо рефакторинг кода сделать =)

Нда .... Озадачил :( . Понимаеш-ли не программист я, так...учусь. Я только на прошедшей неделе немного разобрался, что такое потоки и как их синронизировать, а об этой библиотеке услышал две недельки назад.

Attid если не сложно и не в облом, покажите пример терминалки какой ни будь на основе этой библиотеки. Можно не здесь, можно на emai: swa1@mail.ru. Помоги почти земляку :) , в одном море купаемся.

На счет перезапусков:
Это не перезапускается специально...Это была проверка на защиту от дурака и она не прошла.
Конечно можно уйти от этого зашив настройки программы или в код или в какой либо конфиг. Но...как то не юзабельно получается. А вобще то вышеизложенный код не из будущей прикладной программы.
Это я пытаюсь всунуть в одну программу все функции которые возможны и визуально видеть как это все работает. Делается это все для себя, так как примеров нигде не нашел поэтому и ковыряюсь. А вобще хочется получить что то вроде RS232 Pro, но с одновременной работой по нескольким портам (минимум два).
http://www.softlinks.ru/downloads/RS232_Pro_v3.30-7317.php
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение Attid » 22.11.2007 13:46:05

1. ты близко к серцу не принимай я там смайлики ставлю.
2, у меня самолет через 3 часа так что про примеры забуть
3, еще раз говорю что если вариант

com1 - занят
com6 - свободен
------------
1- Попытка подключения к com1 сразу после запуска
InstanceActive=False
LastError=5

2-подключение к com6
InstanceActive=True
LastError=0
Отключаемся

3-повторное подключение к com1
InstanceActive=True
LastError=0


у тебя имеет повторяемость то попробуй перезапускать программу после 1-2, чтоб узнать где проблема !!

4, в линуксе с подобным не сталкиваюсь, ставить венду для эксперементов не буду ! =)
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2585
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение swa1 » 22.11.2007 15:16:08

Attid писал(а):ты близко к серцу не принимай я там смайлики ставлю.

Да я так... Особо не заморачиваюсь пока разбираюсь. А об оптимзации все одно думать нужно.
Attid писал(а):у меня самолет через 3 час

Счастливого пути!
Attid писал(а):про примеры забуть

Может кто еще поможет....Ведь поэтому и хочу наваять програмку где все будет видно, что там, да как.

А проблема в том, что если я хоть раз удачно подключаюсь к любому порту, то после этого больше ошибок не получаю. Т.е. программа считает, что все порты свободны.
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение Sergei I. Gorelkin » 22.11.2007 17:23:42

Можно взять утилиты от М.Русиновича (procexp и/или portmon) и с их помощью отследить, какие порты когда открыты/закрыты.

После отключения InstanceActive становится равным False?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1400
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение swa1 » 22.11.2007 17:40:07

Sergei I. Gorelkin писал(а):После отключения InstanceActive становится равным False?

Не проверял пока, но похоже нашел ошибку. Опять же проблема в незнании и\или отсутсвии опыта. Главная в том, что я просто собирал программу, а не запускал в отладке.
Далее похоже проблема не в synаser, а в том как я вызывал свойства и функции этого класса. Я еще не убежден, буду проверять, отчитаюсь позже.
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение swa1 » 23.11.2007 17:29:20

Sergei I. Gorelkin писал(а):с их помощью отследить, какие порты когда открыты/закрыты.

Мне не нужно отслеживать состояние портов сторонними утилитами, я и так это знаю. Мне нужно, что бы программа делала это сама.
swa1 писал(а):буду проверять, отчитаюсь позже.

Ну вот, написал все заново, только для того, что бы определить где бяки:
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics,
  Dialogs, StdCtrls, Synaser, ExtCtrls;

type
  {Threads }
    TPotok1 = class(TThread)
    private
    protected
    procedure Execute; override;
    end;
   
    TPotok2 = class(TThread)
    private
    protected
    procedure Execute; override;
    end;

  { TForm1 }

  TForm1 = class(TForm)
    Memo1: TMemo;
    NamePort1: TEdit;
    NamePort2: TEdit;
    Start1: TCheckBox;
    Start2: TCheckBox;
    P1: TPanel;
    P2: TPanel;
    DSR1: TPanel;
    DSR2: TPanel;
    CTS1: TPanel;
    CTS2: TPanel;

    procedure FormCreate(Sender: TObject);
    procedure Start1Click(Sender: TObject);
    procedure Start2Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;
  Potok1: TPotok1;
  Potok2: TPotok2;
  ser1:TBlockSerial;
 
implementation

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin

end;

procedure TForm1.Start1Click(Sender: TObject);
begin
  if Start1.Checked then
  begin
     ser1:=TBlockserial.Create;
     if ser1.InstanceActive then Memo1.Lines.Add('1-1True') else Memo1.Lines.Add('1-1False');
     ser1.Connect(Form1.NamePort1.Text);
     Memo1.Lines.Add(IntToStr(ser1.LastError)+'-'+ser1.LastErrorDesc);
     if ser1.LastError<>0 then
     begin
     Start1.Checked:=False;
     Exit;
     end;
     ser1.Config(115200,8,'N',0,false,false);
     if ser1.InstanceActive then Memo1.Lines.Add('1-2True') else Memo1.Lines.Add('1-2False');
     Memo1.Lines.Add('открыт порт - '+ser1.Device);
     Potok1:= TPotok1.Create(false);
     Potok1.Priority:=tpIdle;
  end
  else
  begin
     ser1.Free;
     Memo1.Lines.Add(IntToStr(ser1.LastError)+'-'+ser1.LastErrorDesc);
     if ser1.InstanceActive then Memo1.Lines.Add('1-3True') else Memo1.Lines.Add('1-3False');
     Memo1.Lines.Add(IntToStr(ser1.LastError)+'-'+ser1.LastErrorDesc);
  end;
     
end;

procedure TForm1.Start2Click(Sender: TObject);
begin
     if Start2.Checked then
     begin
     Potok2:= TPotok2.Create(false);
     Potok2.Priority:=tpIdle;
     end

end;

{ TPotok }

procedure TPotok1.Execute;
begin
     repeat
     if ser1.CTS=True then Form1.CTS1.Color:=clteal else Form1.CTS1.Color:=clcream ;
     if ser1.DSR=True then Form1.DSR1.Color:=clteal else Form1.DSR1.Color:=clcream ;
     if Form1.P1.Color<>clLime then Form1.P1.Color:=clLime else Form1.P1.Color:=clRed ;
     sleep(50);
     until Form1.Start1.Checked=False;
end;

procedure TPotok2.Execute;
var
   ser2:TBlockSerial;
begin
     ser2:=TBlockserial.Create;
     if ser2.InstanceActive then Form1.Memo1.Lines.Add('2-1True') else Form1.Memo1.Lines.Add('2-1False');
    ser2.RaiseExcept:=true;
     ser2.Connect(Form1.NamePort2.Text);
     Form1.Memo1.Lines.Add(IntToStr(ser2.LastError)+'-'+ser2.LastErrorDesc);
     ser2.EnableRTSToggle(true);
     ser2.Config(115200,8,'N',0,false,false);
     if ser2.InstanceActive then Form1.Memo1.Lines.Add('2-2True') else Form1.Memo1.Lines.Add('2-2False');
     Form1.Memo1.Lines.Add('открыт порт - '+ser2.Device);
     repeat
     if ser2.CTS then Form1.CTS2.Color:=clteal else Form1.CTS2.Color:=clcream ;
     if ser2.DSR then Form1.DSR2.Color:=clteal else Form1.DSR2.Color:=clcream ;
     if Form1.P2.Color<>clLime then Form1.P2.Color:=clLime else Form1.P2.Color:=clRed ;
     sleep(50);
     until Form1.Start2.Checked=False;
     Form1.Memo1.Lines.Add(IntToStr(ser2.LastError)+'-'+ser2.LastErrorDesc);
     ser2.Free;
     if ser2.InstanceActive then Form1.Memo1.Lines.Add('2-3True') else Form1.Memo1.Lines.Add('2-3False');
end;


initialization
  {$I unit1.lrs}

end.


Порты 1 и 6. 1-занят, 6-свободен.
Вначале использую 1 вариант - все что с индексом 1.
подключаюсь к com1
1-1False
5-Отказано в доступе.

0-
1-3False
0-

подключаюсь к com6
1-1False
0-OK
1-2True
открыт порт - \\.\COM6

работаю -отключаюсь
0-
1-3False
0-

подключаюсь опять к com1
1-1False
0-OK
1-2True
открыт порт - \\.\COM1

и сразу отключаюсь т.к. это ложь и при любой попытке меня вы
0-
1-3False
0-

Для чистоты, перезапускаю программу
подключаюсь к com1
2-1False
0-OK
2-2True
открыт порт - \\.\COM1
0-OK
2-3False

Это все...полный alles - такого быть не должно.
Пытаюсь подключиться из первого окна и
1-1False
0-OK
1-2True
открыт порт - \\.\COM1
0-
1-3False
0-

Приехали...
Мой вывод (прошу поправлять если не прав):
1-производить подключение из потока - плохо, бо не понимает, что порт занят и подходит в основном только для чтения данных из\о порта\е;
2-после любого удачного подключения, где то запоминается, что все хорошо и все порты отныне свободны. В результате можно подключиться к занятому порту или даже к несуществующему => потеря данных, ошибки и никакой дуракоустойчивости.

ps Если где то не прав, прошу бить не жалея :) . За конструктивную критику буду только благодарен.
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение Sergei I. Gorelkin » 23.11.2007 18:34:37

Я бы не стал связываться с потоками на данном этапе... С ними можно наловить проблем по самое нехочу, даже если все остальное правильно работает.

Но вообще справедливо примерно следующее: подключаться, передавать/принимать и потом отключаться надо из одного и того же потока, неважно какого именно (в вышеприведенной программе это условие вроде бы выполняется).

swa1 писал(а):Мне не нужно отслеживать состояние портов сторонними утилитами, я и так это знаю. Мне нужно, что бы программа делала это сама.

Я рекомендую использовать утилиты именно для проверки правильности своей программы. Т.е. если в программе порт закрыли, а утилита показывает, что он открыт -- повод задуматься...

swa1 писал(а):2-после любого удачного подключения, где то запоминается, что все хорошо и все порты отныне свободны. В результате можно подключиться к занятому порту или даже к несуществующему => потеря данных, ошибки и никакой дуракоустойчивости.

В это верится с трудом, но совсем такой возможности я бы не стал исключать.
Вариант 1 - проверить на обычном компе с двумя com-портами и стандартными драйверами.
Вариант 2 - взять исходники работающей программы на Дельфи и сравнить ее с кодом synaser.
Вариант 3 - коль скоро написанная программа является кроссплатформенной, пойти и проверить на Линуксе :)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1400
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Attid » 24.11.2007 22:46:57

2-после любого удачного подключения, где то запоминается, что все хорошо и все порты отныне свободны. В результате можно подключиться к занятому порту или даже к несуществующему => потеря данных, ошибки и никакой дуракоустойчивости.


не верю =) про дуракоустойчивость возможно. код не смотрел. пока некогда.
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2585
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение swa1 » 26.11.2007 12:08:51

Sergei I. Gorelkin писал(а): подключаться, передавать/принимать и потом отключаться надо из одного и того же потока, неважно какого именно (в вышеприведенной программе это условие вроде бы выполняется).

Это для случая 1 или 2 (Potok1 или Potok2)...где правильнее ?

Sergei I. Gorelkin писал(а):Т.е. если в программе порт закрыли, а утилита показывает, что он открыт -- повод задуматься...

Нашел, скачал, проверил:
Portmon could not attach to Serial0 - the device may be in use
То биш занят порт 1....
Attid писал(а):не верю =)

Ну прям Станиславский :) .... А чему не верить то... Что есть вероятность подключения к занятому порту.... Так это реально. Потеря каких либо данных или их искажение.
- На счет этого не уверен, но исходя из моего опыта работы с железками, а я в первую очередь железячик...Вероятность очень велика. Ведь тут все зависит от протоколовработы устройсв подключенных к портам. И если он без каких либо проверок на качество принятой\переданной информации, то.... Потери могут быть с большой вероятностью. А если проверки есть, то возможны повторы (дубли) информации, что тоже есть не очень хорошо.
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение Attid » 26.11.2007 16:28:29

swa1
ты без потоков проверил ?
потоки на редкость глучная весчь, в том же DC шаманствами занимались чтоб все работало.
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2585
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение swa1 » 13.12.2007 11:23:06

Извиняюсь за долголе умалчивание, все времени не хватало проверить....Работа понимаетшь ли :) . Потом ставил Delphi... Настриивал.
Attid писал(а):ты без потоков проверил ?

Нет пока, но зато проверил два практически одинаковых кода в Lazarus и Delphi... Результат меня огорчил :(
В Lazarus все как было описано выше. В Delphi все работает - т.е. происходит четкая отработка ошибок.
Выходит так, что это баг lazarusa (FPC)..... Млин, хреново если я прав.

PS Кто подскажет? почему в потоках при вызове процедуры через Synchronize - в Lazarus перед именем процедуры необходимо ставит @, а в Delphi нет.... Причем в обоих случаях обратная ситуация вызывает ошибку при проверке.
Что это за @ и зачем оно?
Аватара пользователя
swa1
новенький
 
Сообщения: 80
Зарегистрирован: 25.09.2007 11:04:08
Откуда: Ялта

Сообщение Attid » 13.12.2007 11:49:39

чтоб не ставить @ поставь вместо {$mode objfpc} - {$mode delphi}

Выходит так, что это баг lazarusa (FPC)

еще раз говорю там есть баги с потоками и пока без потоков не проверишь ничего тебе не поможет.
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2585
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Пред.След.

Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru