Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Событие возникает до завершения обработчика, Сообщение с КОМ порта приходит раньше, ч 
:(
    Опции темы
medicdim
Дата 3.9.2009, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 19.1.2007

Репутация: нет
Всего: нет



Ситуация следующая:
Есть обработчик события DataReceived КОМ-порта. От устройства подряд идут несколько сообщений с интервалом ~0.5 сек. Если я просто записываю в буфер, всё ок, но когда я добавляю в обработчик более ресурсоёмкий код, то обрабатывается только первое сообщение т.к. все последующие приходят раньше, чем выполнилась обработка первого...

такой код отрабатывает нормально:
Код

        private void GSM_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
             char[] buf = new char[1000];
            _port.Read(buf, 0, 1000);
            string s = "";
            foreach (char ch in buf)
            {
                s += ch;
                if (ch == '\n')
                {
                    tmp.Add(s);
                    s = "";
                }
            }
            
        }


а такой нет:
Код

        private void GSM_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
                        string i = "";
            SMS sms = new SMS();
            foreach (string st in tmp)
            {

                if (st.Contains("+38"))
                {
                    i = st.Substring(st.IndexOf("+38"), 13);
                    sms.From = i;
                    sms.Text = tmp[tmp.IndexOf(st) + 1];
                    SMSs.Add(sms);
                }
            }
            
        }


уже неделю ломаю мозг... помогите!
PM MAIL   Вверх
Heinzz
Дата 3.9.2009, 21:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 12.12.2008
Где: .net

Репутация: 5
Всего: 9



Мое предложение:
-организовать очередь (Quee) и при возникновении события запускать фоновый поток записи полученных данных в эту очередь
-основной поток пусть разгребается с поступившими сообщениями читая их из очереди


--------------------
user posted image
PM MAIL   Вверх
Crypton
Дата 4.9.2009, 03:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 9.10.2006
Где: США, Санкт-Петерб ург

Репутация: нет
Всего: 2



Вставлю свои пять сом.

Когда я разрабатывал свою библиотеку для сего девайса столкнулся с такой же проблемой.
Коммуникация происходит пакетами как <№ команды><Длина данных, byte><Данные, много байтов><CRC16>.
Так вот. Весь прикол в том, что ЖК монитор мог в любой момент послать пакет от напр. нажатия кнопки, и другие данные. Пытался юзать подписку на событие как ты и сказал но имхо слишком глючновато получилось.

Выход такой нашел. Создать статичный в твоем классе объект SerialPort-а и иметь два потока: обычный и читающий.
В обычном все происходит как и есть, но читающий зациклен через while читая приходящие данные по-байтово.
При открытии порта просто-напросто запускаю читающий поток и вперед.

Вот пример с библиотеки (читатель):
Код

private void incoming() {
            const int MAX_CMD = 35; // самая последняя команда
            const int MAX_LEN = 22; // самая высокая длина данных
            byte[] raw = new byte[1];
            int temp;
            byte _command = 0;
            byte _length = 0;
            byte _crclow = 0;
            byte[] _data = new byte[0];
            // state -- этап на котором мы проверяем принятый пакет. по-умолчанию, 0 (старт)
            int state = 0, dataindex = 0;
            uint CRC = 0;
            bool crcpass = false;
            // проверка, если подан сигнал Dispose классу
            while (!goingDown) {
                // читаем пока есть данные
                while (port.BytesToRead > 0) {
                    // читаем один байт и записываем в raw
                    port.Read(raw, 0, 1);
                    
                    switch (state) {
                        case 0: // начало пакета: проверить диапазон команд
                            if ((raw[0] & 0x3f) > MAX_CMD) break; // НЕТ
                            temp = raw[0] & 0xC0;
                            if (temp == 0x40 ||
                               temp == 0xC0 ||
                                (raw[0] >= 0x80 && raw[0] <= 0x82)) {
                                _command = raw[0]; // Ага, приплюсаем стейт и читаем след. байт
                                state = 1;
                            }
                            break;
                        case 1:  // проверка длины данных
                            if (raw[0] > MAX_LEN) { // много букаф :)
                                state = 0;
                                break;
                            }
                            _length = raw[0];
                            if (raw[0] > 0) {
                                _data = new byte[_length];
                                dataindex = 0;
                                state = 2;
                            } else {
                                _data = new byte[0];
                                state = 3;
                            }
                            break;
                        case 2: // качаем данные
                            if (dataindex < _length) {
                                _data[dataindex] = raw[0];
                                dataindex++;
                            }
                            if (_length == dataindex || _length >= MAX_LEN) {
                                state = 3;
                            }
                            break;
                        case 3: // CRC проверка, низкий диапазон
                            _crclow = raw[0];
                            state = 4;
                            break;
                        case 4: // CRC высок. диапазон
                            byte[] check = new byte[2 + _data.Length];
                            check[0] = _command;
                            check[1] = _length;
                            for (int i = 2; i < _data.Length + 2; i++)
                                check[i] = _data[i - 2];
                            CRC = (uint)(raw[0] << 8) + _crclow;
                            ushort here_ = (ushort)CalculateCRC(check, 0, check.Length);
                            crcpass = here_.Equals((ushort)CRC);

                            // если проверка проходит, у нас правильный пакет и далее мы можем делать, что хотим. напр выполнить события и т.д.
                            if (crcpass) {
                                _lastpacket = check;
                                if (check[0]== 0x40) {// нулевой пакет (подтверждение команды)
                                    if (PingReceived != null)
                                        PingReceived();
                                }
                                if (check[0] == 0x41) { // получить версию прошивки
                                    if(_hwinforeceived!=null){                     
                                        byte[] s = new byte[check[1]];
                                        Array.Copy(check, 2, s, 0, check[1]);
                                        string d = Encoding.ASCII.GetString(s);
                                        _hwinforeceived(d);
                                    }
                                }
                                if (check[0] == 0x42) { // получить данные в ПЗУ
                                    if (_nvramdatareceived != null) {
                                        byte[] nvram = new byte[16];
                                        Array.Copy(check, 2, nvram, 0, 16);
                                        _readflash_received = nvram;
                                        _nvramdatareceived(nvram);
                                    }
                                }
                                if (check[0] == 0x80) { // нажатие кнопки                                    
                                    object o = (KeyDown)check[2];
                                    int a = 0;
                                    if (!int.TryParse(o.ToString(), out a)) {
                                        // кнопка нажата
                                        if (KeyPressed != null)
                                            KeyPressed((KeyDown)o);
                                    } else {
                                        // кнопка отпущена
                                        if (KeyReleased != null)
                                            KeyReleased((KeyUp)o);
                                    }
                                }
#if(DEBUG)
                                ConsoleColor last = Console.ForegroundColor;
                                Console.ForegroundColor = ConsoleColor.Cyan;
                                Console.WriteLine(string.Format("<-CMD: 0x{0}, {1}d", _command.ToString("X2"), _command));
                                foreach (byte b in _data) {
                                    Console.WriteLine(string.Format("+\t Data: 0x{0}, {1}d", b.ToString("X2"), b));
                                }
                                Console.WriteLine();
                                Console.ForegroundColor = last;
#endif
                                state = 0;
                            } else {
                                state = 0;
                            }
                            break;
                    }
                   // Thread.Sleep(2);
                }
                // поспим чутка, пусть проц. отдохнет :)
                Thread.Sleep(2);
            }
        }


надеюсь поможет чисто теоритически smile

Добавлено через 1 минуту и 28 секунд
Это в конструкторе класса

Код


private static SerialPort port;

public Cf635(string COMPort, int Baud) {
            port = new SerialPort(COMPort, Baud, Parity.None, 8, StopBits.One);
            port.Open();
            MethodInvoker mi = new MethodInvoker(incoming);
            mi.BeginInvoke(null, null);
        }

--------------------
«Все, что вы знаете — ложь» Теория мироздания 
PM MAIL WWW ICQ Skype   Вверх
medicdim
Дата 10.9.2009, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 19.1.2007

Репутация: нет
Всего: нет



Вобщем, попробовал я сделать довольно примитивно: при событии DataReceived кидаю всё, что есть в буфере ГСМ шлюза в строку, а потом по таймеру эту строку читаю и, если там что-то есть произвожу необходимые операции.
Так вот, в Windows Forms приложении эта реализация отлично работает.... Но когда я этот код включил в Windows Service, в сформированной строке получается какая-то абра-кадабра (данные не полные и порезаны на произвольные куски)
Должно быть:
at+cmgl="ALL"
+CMGL: 1,"REC READ","5400",,"09/09/09,13:07:47+0<"
Vasha energichnost i zhizneradostnost pomogut zavoevat vnimanie interesuyuschego
 vas cheloveka. Smelo proyavlyayte initsiativu.
+CMGL: 2,"REC READ","5400",,"09/09/09,15:01:46+0<"
Kiev pogoda: SR Chastichno solnechno 23 /12 , CHT Solnechnyj 25 /14 , PT Chastic
hno solnechno 23 /13
+CMGL: 3,"REC READ","+380933149917",,"09/09/09,16:00:53+12"
Ping 172.21.1.147
+CMGL: 4,"REC UNREAD","5400",,"09/09/09,19:02:25+0<"
Kiev pogoda: SR Solnechnyj 25 /13 , CHT Solnechnyj 26 /15 , PT Chastichno solnec
hno 24 /13
+CMGL: 5,"REC UNREAD","5400",,"09/09/10,09:17:29+0<"
Vy mozhete trebovat zhelaemogo, est veroyatnost, chto vashi trebovaniya budut pr
iznany obosnovannymi i dazhe udovletvoreny.
+CMGL: 6,"REC UNREAD","5400",,"09/09/10,10:10:00+0<"
Kiev pogoda: CHT Solnechnyj 26 /14 , PT Silnaja oblachnost 25 /13 , SB Solnechny
j 22 /11

OK


а получается:

+CMGL: 2,"R
Kiev pogoda: SR Solnechnyj 25 /13 , CHT Soln
10,10:10:0
/13 , SB Solnechny
j 22 /11


и всё...  smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1029 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.