Показаны сообщения с ярлыком c. Показать все сообщения
Показаны сообщения с ярлыком c. Показать все сообщения

пятница, 15 сентября 2017 г.

Определить архитектуру CPU в Qt .pro-файле / detect a CPU architecture in Qt .pro-file

Очень часто надо определить архитектуру в .pro-файле Qt-проекта, чтобы прилинковать нужную версию библиотеки. У меня это обычно выбор между архитектурами x86 или x86_64. Нагуглил вот такое работающее решение:

    contains(QT_ARCH, x86_64) {
        LIBS += ../../linux.x86_64/mymodule.a
    } else {
        LIBS += ../../linux.x86/mymodule.a
    }
Очень удобно, и теперь не надо руками возиться с зависимостями от компилятора или создавать какие-то свои скрипты.

среда, 13 сентября 2017 г.

Добавить строковый дефайн в Qt pro-файле / How to add string define in qt pro-file

Добавление числовых определений для препроцессора или строк без пробело и кавычек достаточно тривиально:

DEFINES += "MYDEF=SOME_STR_1234"

А если строка с пробелами? У меня компилятору понравилось вот такое выражение:

DEFINES += "MYDEF=\"SOME  STR  123 \` *\""

То есть можно использовать бэкслеш для  экранирования спецсимволов и кавычек в том числе.

Теперь можно использовать этот дефайн как строку:

#define xstr(a) str(a)
#define str(a) #a
printf("string [%s]", xstr(MYDEF));

четверг, 10 ноября 2016 г.

Передача определений прекомпиляции из cmake

Довольно частая задача, чтобы например подключать те или иные заголовки и делать это можно конечно только во время прекомпиляции.
Допустим есть такой CMakeLists.txt файл:

set(MYTARGET  "target")
# we have some string var that we want to convert to correct define for pre-compiler
set(INTERFACES_VERSION_STR  "-2016.10.23-" )

# remove all points (".")
string(REPLACE "."   ""   MY_INTERFACES_VER   ${INTERFACES_VERSION_STR})
# remove all "-" symbols
string(REPLACE "-"   ""   MY_INTERFACES_VER   ${MY_INTERFACES_VER})
# print them
message(STATUS "INTERFACES_VERSION_STR  ${INTERFACES_VERSION_STR}")
message(STATUS "MY_INTERFACES_VER   ${MY_INTERFACES_VER}")

add_library(${MYTARGET} my_source.cpp)

add_definitions(-DMY_INTERFACES_VER=${MY_INTERFACES_VER})

Тогда в исходном файле пишем:

//...
#if MY_INTERFACES_VER==20161023
#include "v20161023/include/interfaces.h"
    std::cout << "---- MY_INTERFACES_VER==20161023 ---" << std::endl;
#else
#include "mainline/include/interfaces.h"
    std::cout << "do some by default " << std::endl;
#endif


воскресенье, 23 ноября 2014 г.

asm.js vs plain c performance test

Много читал в разных местах про asm.js как утилиту, позволяющую портировать обычный код С/С++ в нечто, что можно вставить в веб-страницу и оно там будет работать без каких-либо дополнительных усилий со стороны браузера (не нужно ставить никаких плагинов, расширений и проч.), достаточно просто поддержки javascript, которая сегодня есть у всех популярных браузеров.
 
asm.js - это, по сути, обычный javascript, который активно используется в вебе. Подмножество javascript, если быть более точным. Больше ответов на другие вопросы на официальной странице и странице компилятора.

Очень захотелось лично попробовать это. Наваял небольшую программу:

#include "md5.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
 
int main()
{
    time_t t1;
    time(&t1);
    const unsigned int dataSize = 1024 * 1024 * 30;
    unsigned char * data;
    data = (unsigned char*) malloc (dataSize);
 
    srand((unsigned int) t1);
    for(int i = 0; i < dataSize; i++)
    {
        data[i] = rand() % 255;
    }
 
    MD5_CTX mdContext;
    for(int i = 0; i < 100; i++)
    {
        MD5Init(&mdContext);
        MD5Update(&mdContext, data, dataSize);
        MD5Final (&mdContext);
    }
 
    free(data);
 
    time_t t2;
    time(&t2);
 
    const double seconds = difftime(t2, t1);
    printf ("\n%3.2f seconds", seconds);
 
 
    return 0;
}

Что мы тут делаем. Выделяем кусок памяти в 30 мегабайт, заполняем его случайными числами, а потом 100 раз вычисляем хеш этого массива, освобождаем память. Сначала запустил как обычную консольную программу, а потом скомпилировал в html-файл, который открыл в chrome и firefox.

.pro-файл консольного приложения:
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
QMAKE_CFLAGS_RELEASE += -O3 -std=c99
SOURCES += main.c


Скрипт для компилирования html-страницы:
emcc -o2  main.c  -o md5.html -s TOTAL_MEMORY=40000000 

В скрипте параметр TOTAL_MEMORY указывает сколько памяти может потребить скрипт. С этим параметром надо обращаться осторожно и не указывать слишком больше число "про запас", без необходимости.
Файл md5.h я взял здесь.

Результаты:
console app: 14 sec, 31MB RAM
firefox: 36 sec,
chrome: 58 sec, 71 MB RAM

Обращает на себя внимание, что chrome работает заметно медленнее firefox. А последний не так радикально медленнее "чистого" си - всего в 2.5 раза. Потребление памяти тоже любопытно. Консольная программа ожидаемо заняла около 31 мегабайта памяти, страница chrome заняла 71 мегабайт. Всего в 2 раза больше, чем консольная. По-моему, очень и очень неплохо. Стоит сказать большое спасибо тем, кто создал и оптимизировал emscripten до такой степени, что javascript проигрывает C в быстродействии всего лишь в 2-4 раза и в потреблении памяти в 2 раза. Это делает возможным проивзодить некоторые достаточно тяжелые вычисления прямо на веб-странице, в браузере клиента.



пятница, 21 февраля 2014 г.

Ридер для магнитных лент KDM-96XX

Ниже представлен код для карт-ридера магнитных лент KDM-96XX.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <string.h>

#define CRTSCTS  020000000000    /* flow control */


#define KDM96XX_HEADER 0x60

#define KDM96XX_CONTROL_CLA 0x43

#define KDM96XX_CONTROL_EJECT_CMD 0x31
#define KDM96XX_CONTROL_PRESPOS_CMD 0x32
#define KDM96XX_CONTROL_INIT_CMD 0x33
#define KDM96XX_CONTROL_GETVER_CMD 0x34

#define KDM96XX_MSCARD_CLA 0x4D
#define KDM96XX_MSCARD_FREAD_CMD 0x31
#define KDM96XX_MSCARD_BREAD_CMD 0x32
#define KDM96XX_MSCARD_READCLEAR_CMD 0x33

char calculate_xor(char * data, int len)
{
    char rslt = 0;
    int i;
    for(i=0; i<len; i++)
        rslt ^= data[i];
   
    return rslt;
}

int set_interface_attribs (int fd, int speed, int parity, float timeoutSec)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
            printf("error from tcgetattr");
            return -1;
        }

        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
        // disable IGNBRK for mismatched speed tests; otherwise receive break
        // as \000 chars
        tty.c_iflag &= ~IGNBRK;         // ignore break signal
        tty.c_lflag = 0;                // no signaling chars, no echo,
                                        // no canonical processing
        tty.c_oflag = 0;                // no remapping, no delays
        tty.c_cc[VMIN]  = 0;            // read doesn't block
        tty.c_cc[VTIME] = (int)(timeoutSec * 10.0);// read timeout in sec

        tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

        tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                                        // enable reading
        tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
        tty.c_cflag |= parity;
        tty.c_cflag &= ~CSTOPB;
        //tty.c_cflag &= ~CRTSCTS;

        if (tcsetattr(fd, TCSANOW, &tty) != 0)
        {
            printf("error from tcsetattr");
            return -1;
        }
        return 0;
}

void set_blocking (int fd, int should_block, float timeoutSec)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
            printf ("error from tcgetattr");
            return;
        }

        tty.c_cc[VMIN]  = should_block ? 1 : 0;
        tty.c_cc[VTIME] = (int)(timeoutSec * 10.0);  // read timeout in sec

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
            printf("error setting term attributes");
}

void show_char_vect_as_hex(char * buf, int size)
{
    printf("[");
    int i;
    for(i=0; i<size; i++)
    {
        printf("x%02x", (unsigned int) buf[i]);
        if(i != size-1)
            printf(", ");
    }
    printf("]");
}

void show_char_vect_as_dec(char * buf, int size)
{
    printf("[");
    int i;
    for(i=0; i<size; i++)
    {
        printf("%02d", (unsigned int) buf[i]);
        if(i != size-1)
            printf(", ");
    }
    printf("]");
}

void send_init_cmd(int fd)
{
    int len = 6;
    char data[len];
    data[0] = KDM96XX_HEADER;//header
    data[1] = 0x00;
    data[2] = 0x02;//data field size
    data[3] = KDM96XX_CONTROL_CLA;//instructions class
    data[4] = KDM96XX_CONTROL_INIT_CMD;//command
    data[5] = calculate_xor(data, len-1);
    int rslt = write(fd, data, len);   
    printf("\n'init', sent bytes: ");
    show_char_vect_as_hex(data, len);
    if(rslt < 0)
    {
        printf(" write error!!");
    }
}

void send_getver_cmd(int fd)
{
    int len = 6;
    char data[len];
    data[0] = KDM96XX_HEADER;//header
    data[1] = 0x00;
    data[2] = 0x02;//data field size
    data[3] = KDM96XX_CONTROL_CLA;//instructions class
    data[4] = KDM96XX_CONTROL_GETVER_CMD; //command
    data[5] = calculate_xor(data, len-1);
    int rslt = write(fd, data, len);   
    printf("\n'getver', sent bytes: ");
    show_char_vect_as_hex(data, len);
    if(rslt < 0)
    {
        printf(" write error!!");
    }
}
void send_report_the_presence_and_pos_cmd(int fd)
{
    int len = 6;
    char data[len];
    data[0] = KDM96XX_HEADER;//header
    data[1] = 0x00;
    data[2] = 0x02;//data field size
    data[3] = KDM96XX_CONTROL_CLA;//instructions class
    data[4] = KDM96XX_CONTROL_PRESPOS_CMD;//command
    data[5] = calculate_xor(data, len-1);   
    int rslt = write(fd, data, len);
    if(rslt < 0)
    {
        printf(" send_report_the_presence_and_pos_cmd(), write error\n");
        return;
    }
    printf("\n'presence and position', sent bytes: ");
    show_char_vect_as_hex(data, len);
}

void send_fread_cmd(int fd)
{
    int len = 6;
    char data[len];
    data[0] = KDM96XX_HEADER;//header
    data[1] = 0x00;
    data[2] = 0x02;//data field size
    data[3] = KDM96XX_MSCARD_CLA;//instructions class
    data[4] = KDM96XX_MSCARD_FREAD_CMD;//command
    data[5] = calculate_xor(data, len-1);
    int rslt = write(fd, data, len);
    if(rslt < 0)
    {
        printf("send_fread_cmd(), write error\n");
        return;
    }
    printf("\n'fread', sent bytes: ");
    show_char_vect_as_hex(data, len);
}

void send_bread_cmd(int fd)
{
    int len = 6;
    char data[len];
    data[0] = KDM96XX_HEADER;//header
    data[1] = 0x00;
    data[2] = 0x02;//data field size
    data[3] = KDM96XX_MSCARD_CLA;//instructions class
    data[4] = KDM96XX_MSCARD_BREAD_CMD;//command
    data[5] = calculate_xor(data, len-1);
    int rslt = write(fd, data, len);
    if(rslt < 0)
    {
        printf("send_bread_cmd(), write error\n");
        return;
    }
    printf("\n'bread', sent bytes: ");
    show_char_vect_as_hex(data, len);
}

void send_cread_cmd(int fd)
{
    int len = 6;
    char data[len];
    data[0] = KDM96XX_HEADER;//header
    data[1] = 0x00;
    data[2] = 0x02;//data field size
    data[3] = KDM96XX_MSCARD_CLA;//instructions class
    data[4] = KDM96XX_MSCARD_READCLEAR_CMD; //command
    data[5] = calculate_xor(data, len-1);
    int rslt = write(fd, data, len);
    if(rslt < 0)
    {
        printf("send_cread_cmd(), write error\n");
        return;
    }
    printf("\n'cread', sent bytes: ");
    show_char_vect_as_hex(data, len);
}

void read_and_show_resp(int fd)
{
    //read first 4 bytes (message header)
    int transmitted = -1;
    int headerSize = 3;
    char header[headerSize];
    memset(header, 0, headerSize);
    transmitted = read(fd, header, headerSize);
    if(transmitted < 0)
    {
        printf("read_and_show_resp(), read header error\n");
        return;
    }
    printf("\nheader: ");
    show_char_vect_as_hex(header, transmitted);
    //calculate message body size and read it
    int dataSize = ((unsigned int)header[1]) * 256 + (unsigned int) header[2] + 1; //plus 1 byte for LRC
    char data[dataSize];
    memset(data, 0, dataSize);
    transmitted = read(fd, data, dataSize);
    if(transmitted < 0)
    {
        printf("read_and_show_resp(), read message body error\n");
        return;
    }
    printf("\nbody: ");
    show_char_vect_as_hex(data, transmitted);
}

void show_help()
{
    printf("program {serial port device} {command name} [timeout in seconds] \n");
    printf("command name : fread, bread, cread, getver, init, pres \n");   
    printf("usage example: \n");
    printf("./program /dev/ttyS0 fread 2.5 \n");
}

void clear_buf(int fd)
{
    set_interface_attribs (fd, B9600, 0, 0.1);  // set speed to 9600 bps, 8n1 (no parity)
    set_blocking (fd, 0, 0.1);                // set no blocking
    int bufSize = 1024;
    char buf[bufSize];
    read(fd, buf, bufSize);
}

int main(int argc, char *argv[])
{
    float timeoutSec = 2.5;

    if(argc < 2)
    {
        printf("serial port name was omitted\n");
        show_help();
        return 0;
    }   
    if(argc < 3)
    {
        printf("command name was omitted\n");
        show_help();
        return 0;
    }   
   
    char *portname = argv[1];   // like "/dev/ttyS0"
    char *cmdStr = argv[2]; // "read", "init", "pres"
   
    if(argc >= 4) //if there is timeout in command line - set it
    {
        timeoutSec = atof(argv[3]);
    }

    int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0)
    {
        printf("error opening %s, retval %d\n", portname, fd);
        return -1;
    }
   
    clear_buf(fd);

    set_interface_attribs (fd, B9600, 0, timeoutSec);  // set speed to 9600 bps, 8n1 (no parity)
    set_blocking (fd, 0, timeoutSec);                // set no blocking
       
    if(strcmp("init", cmdStr) == 0)
    {
        send_init_cmd(fd);
    }
    if(strcmp("getver", cmdStr) == 0)
    {
        send_getver_cmd(fd);
    }
    if(strcmp("pres", cmdStr) == 0)
    {
        send_report_the_presence_and_pos_cmd(fd);
    }
    if(strcmp("fread", cmdStr) == 0)
    {
        send_fread_cmd(fd);
    }
    if(strcmp("bread", cmdStr) == 0)
    {
        send_bread_cmd(fd);
    }
    if(strcmp("cread", cmdStr) == 0)
    {
        send_cread_cmd(fd);
    }
   
    read_and_show_resp(fd);

    printf("\n");
   
    close(fd);

    return 0;
}

//The values for speed are B115200, B230400, B9600, B19200, B38400, B57600, B1200

пятница, 19 апреля 2013 г.

Работа в Linux с последовательным портом.

Для работы с последовательным портом удобнее всего использовать библиотеки типа boost, но только в том случае, если писать на C++, который на данный момент менее популярен, чем старый добрый C. Еще в преимущества можно добавить тот факт, что понятность кода, использующего синтаксис, созданный пару дестяков лет назад, заметно выше, чем всякие биндинги, плейсхолдеры и модели событийного программиования, которые густо замешаны с шаблонами в библиотеке boost. Простейший пример открытия, чтения и записи см. ниже.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <string.h>
 
int openSerialPort(const char * devName)
{
    //read and write in sync mode
    int hSerial = open(devName, O_RDWR | O_NOCTTY | O_SYNC);
    if(hSerial < 0)
        printf("open device \"%s\" error: %d\n", devName, hSerial);
 
    struct termios port_settings;
    bzero(&port_settings, sizeof(port_settings));
    //
    port_settings.c_cflag |= CREAD;
    port_settings.c_cflag |= CLOCAL;
    //
    port_settings.c_cc[VMIN] = 100;
    //delay, x0.2 sec
    port_settings.c_cc[VTIME] = 2;
    //flush serial port
    int fres = tcflush(hSerial, TCIFLUSH);
    if (fres < 0)
    {
        printf("tcflush() error %d\n", fres);
    }
    //set baud rate
    fres = cfsetispeed(&port_settings, B9600);
    if (fres < 0)
    {
        printf("cfsetispeed() error %d\n", fres);
    }
    fres = cfsetospeed(&port_settings, B9600);
    if (fres < 0)
    {
        printf("cfsetospeed() error %d\n", fres);
    }
    //set character size: 8.
    port_settings.c_cflag &= ~CSIZE;
    port_settings.c_cflag |= CS8;
    //set flow cotrol: none
    port_settings.c_cflag &= ~(CRTSCTS);
    //set parity: none
    port_settings.c_cflag &= ~(PARENB);
    port_settings.c_iflag |= IGNPAR;
    //set stop bits: 1
    port_settings.c_cflag &= ~(CSTOPB);
 
 
    //apply port settings
    fres = tcsetattr(hSerial, TCSANOW, &port_settings);
    if (fres < 0)
    {
        printf("tcsetattr() error %d\n", fres);
    }
    return hSerial;
}
 
int main(int argc, char* argv[])
{
    if(argc < 2) 
    {
        printf("One parameter is omitted\n");
        return -1;
    }
    const char * devName = argv[1]; // "/dev/ttyS0"
    int hSerial = openSerialPort(devName);  
    if(hSerial < 0) 
    {
        return hSerial;
    }        
 
    const char sendVect[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
 
    int byteCount = write(hSerial, sendVect, sizeof(sendVect));
    if (byteCount < 0)
    {
        printf("write error %d\n", byteCount);
    }
 
    char buf[250];
    bzero(buf, sizeof(buf));
 
    byteCount = read(hSerial, buf, sizeof(buf));
    if (byteCount < 0)
    {
        printf("read error %d\n", byteCount);
    }
    else 
    {
        printf("response: \"%s\" \n", buf);
    }     
 
    close(hSerial);
 
    return 0;
}


Как использовать VMIN и VTIME читать здесь:
http://www.unixwiz.net/techtips/termios-vmin-vtime.html

Остальное должно быть ясно из комментариев к коду.