Страницы

среда, 4 августа 2010 г.

Symbian OS. Асинхронные вызовы: как не надо делать.

Столкнувшись с необходимостью чтения большого файла, я решил воспользоваться кодом, который приведен в примере парсинга XML на форуме нокиа. Ключевыми там являются методы CXmlHandler::StartParsingWithAoL() и, естественно, callback-функция CXmlHandler::RunL(). Именно в этих методах производятся вызовы асинхронного метода RFile::Read().

void CXmlHandler::StartParsingWithAoL( const TDesC& aFileName )
    {
     // Отмена всех невыполненных задач.
    if ( IsActive() )
        {
        Cancel();
        }
    User::LeaveIfError( iFile.Open( CCoeEnv::Static()->FsSession(), aFileName,
        EFileRead ) );
    // Создание буфера для хранения содержимого файла.
    delete iBuffer;
    iBuffer = 0;
    iBuffer = HBufC8::NewL( KFileBufferSize );
    // !!! Такая реализация может быть причиной возникновения
    //     ошибки времени выполнения !!!
    TPtr8 bufferPtr( iBuffer->Des() ); 
    iFile.Read( bufferPtr, KFileBufferSize, iStatus );
    SetActive();
    // Приведение парсера в состояние готовности.    
    iParser->ParseBeginL();
    }

void CXmlHandler::RunL()
    {
    if ( KErrNone == iStatus.Int() )
        {
        // Если длина содержимого буфера равна 0 - достигнут
        // конец файла
        if ( iBuffer->Length() == 0)
            {
            iParser->ParseEndL();
            iFile.Close();
            delete iBuffer;
            iBuffer = 0;
            }
        // Иначе продолжаем чтение следующего отрезка XML-файла.
        else
            {
            // Парсинг прочитанного содержимого.
            iParser->ParseL( *iBuffer );

            // Чтение следующего отрезка.
            // !!! Такая реализация может быть причиной
            //     возникновения ошибки !!!
            TPtr8 bufferPtr( iBuffer->Des() );
            iFile.Read( bufferPtr, KFileBufferSize, iStatus );
 
            // Индикация невыполненной задачи
            SetActive();
            }
        }
    else
        {
        // Обработка ошибки.
        }
    }

Однако, запустив программу на эмуляторе, обнаружил, что не все так гладко, как описал автор. После чтения нескольких фрагментов (причем не важно, какого размера), программа "вылетала" с кодом -38: A non-descriptor parameter was passed by a client interface, when a server expected a descriptor. Из описания ошибки, в общем-то, стало понятно, что проблемы с автоматической переменной bufferPtr. Действительно, может произойти следующее (а в моем случае именно это и произошло). Метод RunL() завершает свое выполнение раньше, чем завершится асинхронная операция чтения содержимого файла, и вместе с этим методом прекращает свое существование переменная bufferPtr. Чтобы исправить ситуацию, я добавил в класс (в данном примере это класс CXmlHandler) переменную-член iBufferPtr, используя ее в приведенных выше методах вместо bufferPtr.


class CXmlHandler : public CActive, MContentHandler
{
    ...
    private:

        TPtr8 iBufferPtr;
    ...
};

Нужно отметить, что эта ошибка проявилась не сразу, программа нормально работала, пока размер файла не превысил 10 кбайт.

суббота, 31 июля 2010 г.

Kappa X-Motion под управлением PC

Я начинаю свой блог с описания недавнего интересного проекта, который позволил мне работать и решать проблемы на стыке двух инженерных дисциплин: разработки программного обеспечения и проектирования систем управления промышленным оборудованием.

Передо мной стояла задача построить систему управления рейкой форматно-раскроечного станка Felder Format 4 Kappa взамен вышедшего из строя блока управления Sigmatek, которая, помимо выполнения всех стандартных функций по команде оператора (а именно, ввод координаты в миллиметрах и установка суппорта), могла быть интегрирована с технологическим программным обеспечением и базами данных изделий, используемыми на производстве, в единый комплекс, обеспечивая тем самым автоматизацию раскроя листов ДСП для заготовок Помимо того, наличие программного интерфейса для записи отчета о выполненных операциях, давало возможность оптимизации управления производственным процессом в целом

Станок серии Kappa
В приводе суппорта используется электродвигатель Dunkermotoren GR63x25 со встроенным инкрементным энкодером RE30-500TI. Для управления двигателем решено было использовать модуль AWD10 производства российской компании ЗАО "Лаборатория электроники" из-за его относительно низкой стоимости и возможности управления им по интерфейсу RS-485.

Контроллер AWD10
Первое, что было сделано - написана библиотека Awd10.lib, содержащая реализацию класса CAwd10, который инкапсулирует протокол обмена данными с модулем AWD10 по последовательному порту, обработку ошибок и т. д., предоставляя методы, которые имеют имена, идентичные названиям команд, описанных в спецификации модуля, для осуществления управления им.

Для обратной связи энкодера с программой управления используется LPT-порт. Его скорости достаточно для обеспечения точности установки рейки 0.1 мм. Обмен данными с портом в Windows XP обеспечивается драйвером hwinterface.sys и библиотекой inpout32.dll. Для соединения энкодера с LPT-портом был сделан формирователь импульсов, собранный на одной плате с блоком питания двигателя и контроллера AWD10.

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




В пользовательской версии все вышеперечисленные возможности отсутствуют. Эта версия предназначена для использования рабочими в цеху и оптимизирована для работы с клавиатурой.







Вкладка "Настройка" предназначена, в основном, для установки параметров регулятора AWD10. Есть возможность изменить 31 параметр контроллера, а также режим его работы, который задается 16-битным значением.

Окно настройки  ПИД-регулятора
Параметры сопряжения с энкодером
Управление режимом контроллера





















В процессе работы над приложением и отладки системы управления, весь узел рейки был демонтирован и перенесен в специально выделенное помещение. Первоначальные оценочные испытания были проведены там, а эффективность такой системы покажет непосредственно эксплуатация в производственных условиях.