пятница, 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