Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Остальные вопросы по работе с операционной системой Windows
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

Не могу победить компорт из винформ.
Если есть кто может подсказать, то может через личку если тут ОФФ.
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

Что именно интересует? с каким устройством будешь работать? Помочь легко, только информации немного побольше-бы :-)
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Аватара пользователя
Крафтер
Мастер
Сообщения: 211
Зарегистрирован: 27 мар 2015, 22:25
Репутация: 61
Настоящее имя: Андрей
Откуда: Ростов-на-Дону
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Крафтер »

Вот из моего проекта обработка ком-порта, это просто С++, но я пока не рефакторил. И тут границы пакетов проверяются. Видел где-то в нете готовый пример работы с ком портом в C#, ищи лучше.
(для просмотра содержимого нажмите на ссылку)

Код: Выделить всё

#pragma once
#include "winerror.h"
#include "windows.h"
#include <string>
#include <assert.h>
#include <fstream>

#include "IPortToDevice.h"

class ComPortConnect
{
public:
    ComPortConnect(void); //обнуляет всё
    ~ComPortConnect(void);

    int init_port(int portNumber);                       //подключается к порту
    void send_data(char *buffer, int count);             //шлёт данные
    static DWORD WINAPI receive_thread( LPVOID lpParam );//принимает данные

    HANDLE hThread;    //поток чтения
    HANDLE hCom;       //хэндл порта
    OVERLAPPED ovRead; //переменные для одновременной работы с портом
    OVERLAPPED ovWrite;

    int receiveBPS;    //число прочитанных байт
    int transmitBPS;   //число записанных байт
    int errs;          //ошибки разбиения на пакеты

    static const int RECEIVE_SIZE = 100;
    char receiveBuffer[RECEIVE_SIZE]; //текущий принимаемый пакет
    int receivedSize;                 //принято байт текущего пакета

    IPortToDevice *remoteDevice;      //устройство, принимающее пакеты

private:
    enum States
    {
        S_READY,     //очередь пуста, никто ничего не присылал
        S_CODE,      //принят управляющий символ
        S_RUN,       //вначале принят символ '\' , ждём символ 'r'
        S_RECEIVING, //приём пакета
        S_END,       //принят символ конца, проверка пакета
    };

    enum Tags
    {
        OP_CODE = '\\', //признак, что дальше идёт управляющий код, если надо послать 100, надо послать его 2 раза
        OP_STOP = 'n',  //конец пакета
        OP_RUN  = 'r',  //начало пакета
    };

    States receiveState;

    void process_bytes(char *buffer, int count);   //формирует пакет из принятых данных
};

Код: Выделить всё

#include "ComPortConnect.h"
//здесь описана связь по com порту пакетами

int ComPortConnect::init_port(int portNumber)
{
    char portName[30];
    sprintf(portName, "\\\\.\\COM%d", portNumber);

    hCom = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0,
        NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (hCom == INVALID_HANDLE_VALUE)
        throw("cant open port");

    if(!PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR))
        throw("cant purge port");

    if(!ClearCommBreak(hCom))
        throw("cant run port");

    DCB dcb;
    if (!GetCommState(hCom, &dcb))
        throw("cant read port params");

    dcb.BaudRate = 115200;//9600;//57600;//
    dcb.ByteSize = 8;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;

    //Setup the flow control
    dcb.fBinary = TRUE;
    dcb.fDsrSensitivity = FALSE;
    dcb.fOutxCtsFlow = FALSE;
    dcb.fOutxDsrFlow = FALSE;
    dcb.fOutX = FALSE;
    dcb.fInX = FALSE;
    dcb.fDtrControl = FALSE; //DTR_CONTROL_HANDSHAKE;
    dcb.fRtsControl = FALSE; //RTS_CONTROL_HANDSHAKE;
    dcb.fNull = FALSE;
    dcb.fAbortOnError = FALSE;

    if (!SetCommState(hCom, &dcb))
        throw("cant set port params");

    DWORD CommEventMask = EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY | EV_ERR | EV_BREAK;
         //| EV_CTS | EV_DSR | EV_RING | EV_RLSD;

    //GetCommMask(hCom,&CommEventMask);
    if (!SetCommMask(hCom,CommEventMask))
        throw("cant set port events");

    COMMTIMEOUTS timeouts;

    if(!GetCommTimeouts(hCom, &timeouts))
        throw("cant read port timeouts");

    timeouts.ReadIntervalTimeout = 5000;
    timeouts.ReadTotalTimeoutConstant = 5000;
    timeouts.ReadTotalTimeoutMultiplier = 5000;
    timeouts.WriteTotalTimeoutConstant = 5000;
    timeouts.WriteTotalTimeoutMultiplier = 5000;

    if(!SetCommTimeouts(hCom, &timeouts))
        throw("cant write port timeouts");

    DWORD   threadId;
    hThread = CreateThread(NULL, 0, receive_thread, this, 0, &threadId);

    receiveBPS = 0;
    transmitBPS = 0;
    errs = 0;
    return 0;
}

void ComPortConnect::send_data(char *buffer, int count)
{
    char data[1000];
    char *pointer = data;
    *(pointer++) = OP_CODE;
    *(pointer++) = OP_RUN;
    for(int i=0;i<count;i++)
    {
        if(buffer[i] == OP_CODE)
        {
            *(pointer++) = OP_CODE;
            *(pointer++) = OP_CODE;
        }
        else
            *(pointer++) = buffer[i];
    }
    *(pointer++) = OP_CODE;
    *(pointer++) = OP_STOP;
    *(pointer++) = OP_CODE; //второй раз страховочный конец пакета
    *(pointer++) = OP_STOP;

    DWORD write;
    WriteFile(hCom, data, pointer-data, &write, &ovWrite);
    transmitBPS += pointer-data;
}

void ComPortConnect::process_bytes(char *buffer, int count)
{
    for(int i=0;i<count;i++)
    {
        char data = buffer[i];
        //printf("%c", int(data));
        switch (receiveState)
        {
            case S_READY:
                if (data == OP_CODE)
                    receiveState = S_RUN;
                break;

            case S_RUN:
                if (data == OP_RUN)
                {
                    receiveState = S_RECEIVING;
                    receivedSize = 0;
                }
                else
                {
                    receiveState = S_READY;
                    ++errs;
                }
                break;

            case S_RECEIVING:
            {
                if (data == OP_CODE)
                {
                    receiveState = S_CODE;
                    break;
                }
                else
                {
                    if(receivedSize < RECEIVE_SIZE)
                        receiveBuffer[receivedSize++] = data;
                    else
                    {
                        receivedSize = 0;
                        ++errs;
                    }
                }
                break;
            }

            case S_CODE:
            {
                switch (data)
                {
                    case OP_CODE:                 //в пересылаемом пакете случайно был байт '\'
                        if(receivedSize < RECEIVE_SIZE)
                            receiveBuffer[receivedSize++] = data;   //и мы его переслали таким образом
                        else
                        {
                            receivedSize = 0;
                            ++errs;
                        }
                        receiveState = S_RECEIVING;
                        break;
                    case OP_STOP:
                        receiveState = S_END;
                        remoteDevice->on_packet_received(receiveBuffer, receivedSize); //вот пакет наконец принят
                        receiveState = S_READY;
                        break;
                    default:
                        receiveState = S_READY;
                        ++errs;
                }
                break;
            }

            case S_END:
                break;

            default:
                break;
        }
    }
}


DWORD WINAPI ComPortConnect::receive_thread( LPVOID lpParam )
{
    ComPortConnect *_this = (ComPortConnect*)lpParam;

    DWORD eventMask = 0;
    DWORD readed = 0;

    const int bufferSize = 10;
    char inData[bufferSize+2];
    memset(inData, 0, sizeof(inData));

    _this->ovRead.hEvent=CreateEvent(NULL, TRUE, TRUE, NULL);

    do
    {
        int retcode = WaitCommEvent(_this->hCom, &eventMask, &_this->ovRead);
        if ( ( !retcode ) && (GetLastError()==ERROR_IO_PENDING) )
        {
            //printf("COM: wait event\n");
            WaitForSingleObject(_this->ovRead.hEvent, 1);
        }

        //printf("COM: event %d\n", eventMask);
        //print_event_mask(eventMask);

        if (eventMask & EV_ERR)
        {
            DWORD ErrorMask = 0; // сюда будет занесен код ошибки порта, если таковая была
            COMSTAT CStat;

            ClearCommError(_this->hCom, &ErrorMask, &CStat);

            //DWORD quelen = CStat.cbInQue; //размер буфера порта
        }
        if (eventMask & EV_RXCHAR)
        {
            //printf("COM: bytes received \n");
            while(true)
            {
                memset(inData, 0, sizeof(inData));
                retcode = ReadFile(_this->hCom, inData, bufferSize, &readed, &_this->ovRead);
//receiveBPS += readed;

                if( retcode == 0 && GetLastError() == ERROR_IO_PENDING ) //не успели прочитать
                {
                    WaitForSingleObject(_this->ovRead.hEvent, INFINITE);
                    retcode = GetOverlappedResult(_this->hCom, &_this->ovRead, &readed, FALSE) ;
                }

_this->receiveBPS += readed;

                if (readed > 0) //если прочитали данные
                {
                    //printf("%d байт прочитано: '%s'\n", readed, inData);
                    //printf(inData);
                    _this->process_bytes(inData, readed);
                }
                else
                    break;
                    //printf("не удалось прочитать, ошибка %d\n", GetLastError());
                //break;
            }
        }
        if (eventMask & EV_TXEMPTY)
        {
            //printf("COM: bytes sended\n");
        }


        eventMask=0;
        ResetEvent(_this->ovRead.hEvent);
    }
    while(true);

    BOOL bSuccess = CloseHandle(_this->hCom);
    _this->hCom = INVALID_HANDLE_VALUE;

    return 0;
}


ComPortConnect::ComPortConnect(void)
{
    hThread = 0;
    hCom = 0;
    memset(&ovRead,0,sizeof(ovRead));
    memset(&ovWrite,0,sizeof(ovWrite));
    receiveState = S_READY;
    receivedSize = 0;
    remoteDevice = nullptr;
}


ComPortConnect::~ComPortConnect(void)
{
    //WaitForSingleObject(hThread)
    TerminateThread(hThread, 0);   //если прервать, когда не до конца доработала обработка пакета, что будет?
    CloseHandle(hCom);
}
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

selenur писал(а):Что именно интересует? с каким устройством будешь работать? Помочь легко, только информации немного побольше-бы :-)
Делаю управление устройством через микроконтроллер, все банально, посылаю команду, жду когда мк освободится шлю следующую.
Затык на ожидании подтверждения готовности.
пишу в студии, есть готовый класс компорт, как я понял он по умолчанию исполняется в отдельном потоке, но когда я в цикле проверяю изменилась ли переменная в которую читает из порта, она не меняется.
приходится в цикле ожидания постоянно делать comport.readstring().
я так понимаю, что пока крутится while() ожидания, второй поток либо вообще не работает либо не может переменную изменить, хотя бред какойто, зачем тогда в отдельном потоке запускается.
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

Крафтер писал(а):Вот из моего проекта обработка ком-порта, это просто С++, но я пока не рефакторил. И тут границы пакетов проверяются. Видел где-то в нете готовый пример работы с ком портом в C#, ищи лучше.
Да примеров то полно, да все не то, что надо.
Аватара пользователя
Крафтер
Мастер
Сообщения: 211
Зарегистрирован: 27 мар 2015, 22:25
Репутация: 61
Настоящее имя: Андрей
Откуда: Ростов-на-Дону
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Крафтер »

Как можно найти баг, не видя код? МК ответ точно присылает?
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

Bmax77 писал(а):
Крафтер писал(а):Вот из моего проекта обработка ком-порта, это просто С++, но я пока не рефакторил. И тут границы пакетов проверяются. Видел где-то в нете готовый пример работы с ком портом в C#, ищи лучше.
Да примеров то полно, да все не то, что надо.
Как-то делал ЧПУ контроллер, с управлением по ком-порту, и вот пример реализации:
(для просмотра содержимого нажмите на ссылку)

Код: Выделить всё


        /// <summary>
        /// Буффер полученных данных с ком-порта
        /// </summary>
        static string Serial_resultstr = "";
        /// <summary>
        /// Локер для доступа к буфферу ком-порта
        /// </summary>
        static object locker = new object();

  private void serialPort_CNC_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            lock (locker)
            {
                string ss = serialPort_CNC.ReadExisting();
                Serial_resultstr += ss.Replace("\r", ""); //удалим переносы строки и добавим в буффер результирующую строку 

               // Serial_resultstr = ChechStatusDevice(Serial_resultstr);//извлечем статусы контроллера
            }            
        }

Между контроллером и компьютером у меня передавались данные блоками разного размера, но всегда начинались на ! и заканчивались на &.
У компоненты компорт есть событие DataReceived, которое вызывается если из компорта получены новые данные, т.к. эти данные часто приходят не одной целой строкой, а с разбивкой по кускам, то я собирал полученные данные в строку, а потом уже проверял с помощью ChechStatusDevice есть ли хотя-бы один блок данных который начинался на ! и заканчивались на &, и т.д....
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

Если нужно то все исходники, доступны тут: https://github.com/selenur там можешь посмотреть полную реализацию работы с ком портом
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

selenur писал(а):У компоненты компорт есть событие DataReceived,
Я шлю с компа фиксированным блоком, потому как МК принимает через ДМА в буфер, а вот обратно шлю Error, Busy, Ready.
Проблем с пересылом нет, есть проблема, что обработчик DataReceived, не может прервать работу while(!rx == Ready).
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

А можете выложить свой код, что-бы понятнее было :-)
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

Код: Выделить всё

private string rxString;
        private void plotBtn_Click(object sender, EventArgs e)
        {
            byte[] Buff = new byte[20];
            int x = 0, y = 0, x1 = 0, y1 = 0, y_revert, _x, _y, flag = 0;
            g.Clear(Color.White);
            g = pictureBox1.CreateGraphics();

            y_revert = pictureBox1.Height;

            
            Sended.Text = "";
            for (var m = 0; m < lines.Count; m++)
            {
                if (lines[m].StartsWith("PU") == true)
                {
                    Buff[0] = 1;
                    pens = pen1;
                    flag = 1;                    
                    rxLabel.Text = rxString;
                }
                else if (lines[m].StartsWith("PD") == true)
                {
                    Buff[0] = 2;
                    pens = pen2;
                    flag = 1;
                    rxLabel.Text = rxString;
                }
                else if (lines[m].StartsWith("PA") == true)
                {
                    var splits = new[] { "PA", ",", ";" };
                    var tmp = lines[m];
                    var num = tmp.Split(splits, StringSplitOptions.RemoveEmptyEntries);
                    x1 = System.Convert.ToInt16(num[0]);
                    y1 = System.Convert.ToInt16(num[1]);
                    _x = System.Convert.ToUInt16(x1 * 2.666666);
                    _y = System.Convert.ToUInt16(y1 * 2.666666);
                    Buff[0] = 3;
                    Buff[1] = 0;
                    Buff[2] = (byte)_x;
                    Buff[3] = (byte)(_x >> 8);
                    Buff[4] = (byte)_y;
                    Buff[5] = (byte)(_y >> 8);
                    x1 /= 5;
                    y1 = y_revert - y1 / 5;
                    g.DrawLine(pens, x, y, x1, y1);
                    x = x1;
                    y = y1;
                    flag = 1;
                    rxLabel.Text = rxString;
                }
                if (flag == 1)
                {
                    if (myPort.IsOpen)
                    {
                        myPort.Write(Buff, 0, 20);
                        rxString = "Busy";
                        
                        //System.Threading.Thread.Sleep(250);   
                        while (rxString != "Ready")
                        {
                            rxString = myPort.ReadLine(); - пришлось сюда запихнуть и принудительно дергать чтение из порта.
                           rxLabel.Text = "Busy";

                        }
                        
                        rxLabel.Text = rxString;
                    }
                    else
                    {
                        MessageBox.Show("COM port ERROR", "COM", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    flag = 0;
                }
                Sended.AppendText(lines[m] + "\r\n");                

            }

        }

        private void myPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
           // this.Invoke(new EventHandler(rxString_e));
        }

        private void rxString_e(object o, EventArgs e)                                      ---------------------это все не работает если работает while
        {
            rxString = myPort.ReadLine();                      
          rxLabel.Text = rxString;
        }
Аватара пользователя
Крафтер
Мастер
Сообщения: 211
Зарегистрирован: 27 мар 2015, 22:25
Репутация: 61
Настоящее имя: Андрей
Откуда: Ростов-на-Дону
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Крафтер »

selenur писал(а):Если нужно то все исходники, доступны тут: https://github.com/selenur там можешь посмотреть полную реализацию работы с ком портом
Ничёсе. Сколько код всего проекта весит? И где почитать описание программы, доступные возможности, а то может зря я свой пишу :lol1: ?
Аватара пользователя
Крафтер
Мастер
Сообщения: 211
Зарегистрирован: 27 мар 2015, 22:25
Репутация: 61
Настоящее имя: Андрей
Откуда: Ростов-на-Дону
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Крафтер »

Если порт читает/пишет в асинхронном режиме, а тебе надо синхронно дождаться ответа, то надо вместо while запустить какой-то аналог WaitForSingleObject(okEvt) . При приходе данных порт вызывает обработчик, в нём прочитать строку и вызвать аналог SetEvent(okEvt); Или как-то настроить работу в синхронном режиме.
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

Я не думаю что надо прям синхронно, но хотя бы как то, из простейшей задачи вылез такой головняк. Через тот костыль, что есть в программе оно конечно работает, но как мне кажется это не правильно.
Я понимаю, что не ловлю микросекунды в своей проге, но мне казалось, что раз обработчик события работает в другом потоке, то проблем с обработкой события быть не должно.Тут ждем, а там как только в порт что то пришло, сообщаем об этом через переменную сюда.))))
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

При нажатии кнопки такой код будет приводить к зависанию всей программы, т.к. не всегда метод readline() у компорта тебе вернет строку "ready". Т.к. скорость работы компьютера и обращение к компорту происходит быстрее, чем контроллер успевает послать всю фразу, то получается примерно так: контроллер по символу бросает в компорт фразу ready, а на компьтере уже успевает вызваться медод readline пару раз, который из компьютерного буфера ком порта изъял "rea" а потом "dy" и поэтому у тебя цикл повиснет.
Вариантов решения много, первый плохой способ, это ставить паузу например на пару секунд, что-бы буфер компорта успел наполниться всей фразой.
Второй вариант как у меня, дополнительный поток собирает полученные данные, а в другом потоке уже анализируешь.
Так-же нужно учесть что нужные данные от контроллера можешь и недождаться! и программа не должна от этого зависнуть ;-)
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

Крафтер писал(а):
selenur писал(а):Если нужно то все исходники, доступны тут: https://github.com/selenur там можешь посмотреть полную реализацию работы с ком портом
Ничёсе. Сколько код всего проекта весит? И где почитать описание программы, доступные возможности, а то может зря я свой пишу :lol1: ?
Весит в принципе не много, более менее информация тут http://www.cnc-club.ru/forum/viewtopic.php?f=41&t=4215 это я делал для саморазвия в чпу, и там много ещё косяков, т.к. проект забросил...
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

selenur писал(а):При нажатии кнопки такой код будет приводить к зависанию всей программы, т.к. не всегда метод readline() у компорта тебе вернет строку "ready". Т.к. скорость работы компьютера и обращение к компорту происходит быстрее, чем контроллер успевает послать всю фразу, то получается примерно так: контроллер по символу бросает в компорт фразу ready, а на компьтере уже успевает вызваться медод readline пару раз, который из компьютерного буфера ком порта изъял "rea" а потом "dy" и поэтому у тебя цикл повиснет.
Вариантов решения много, первый плохой способ, это ставить паузу например на пару секунд, что-бы буфер компорта успел наполниться всей фразой.
Второй вариант как у меня, дополнительный поток собирает полученные данные, а в другом потоке уже анализируешь.
Так-же нужно учесть что нужные данные от контроллера можешь и недождаться! и программа не должна от этого зависнуть ;-)
Вообще readline вернет тогда когда встретит в буфере "\n", но я допускаю, что могут быть косяки. Второй поток, вроде как работа с компортом по умолчанию в другом потоке идет, по этому например из обработчика нельзя напрямую на форме менять значения например текстовых полей, возможно лиш изменить значение переменной, но почему то у меня это не работает.
проверял даже таким образом, заставлял мк постоянно слать строку Ready, так вот пока whail крутится, переменная не меняется. Хз в чем косяк.

https://www.youtube.com/watch?v=MmvzElor0s8
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4604
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1621
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение selenur »

Можешь запустить отладку с остановкой в нутри цикла, и показать что у тебя в переменной??
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Instagram https://www.instagram.com/zheigurov/
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

Имеешь в виду так как сейчас работает или когда через event?
Bmax77
Мастер
Сообщения: 400
Зарегистрирован: 13 авг 2013, 11:05
Репутация: 39
Контактная информация:

Re: Прошу прощения за возможный ОФФтоп, есть знатоки C#?

Сообщение Bmax77 »

Вот так переписал обработчик с эвентом, отлично работает пока на форме ничего не нажимаешь (сделал циклическую посылку статуса с мк).

Код: Выделить всё

        private void myPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string status = myPort.ReadLine();
            this.BeginInvoke(new LineReceivedEvent(LineReceived), status);
            // this.Invoke(new EventHandler(rxString_e));
        }
        private delegate void LineReceivedEvent(string status);
        private void LineReceived(string status)
        {
            //rxString = myPort.ReadLine();                      
            rxLabel.Text = rxString = status;
        }

        private void clearBtn_Click(object sender, EventArgs e)
        {
            lines.Clear();
            g.Clear(Color.White);
            Sended.Text = null;
            plotBtn.Enabled = false;
        }

    }
Вот так выглядит посылка команды и ожидание:

Код: Выделить всё

 if (myPort.IsOpen)
            {
                if (myPort.IsOpen)
                {
                    myPort.Write(Buff, 0, 20);
                    rxString = "Busy";

                    //System.Threading.Thread.Sleep(250);   
                    while (rxString != "Ready")
                    {
                        //rxString = myPort.ReadLine();
                        rxLabel.Text = "Busy"; --------------- и вот тут код крутится бесконечно потому что значение переменной не меняется. 

                    }

                    //rxLabel.Text = rxString;
                }
                //rxLabel.Text = "Ready";
            }
            else
            {
                MessageBox.Show("COM port ERROR", "COM", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
Вычитал, что для того чтобы из другого потока изменить что то на форме во время работы основного потока, нужно их вручную синхронизировать.
Короче костыль на костыле, чувствую для таких задач надо поискать какой то другой способ разработки.
Ответить

Вернуться в «Прочие вопросы Windows»