Simple Linux C Driver/Header

ayergo

New member
Simple Linux C Driver/Header for CFA-635

Hello,

I didn't like the bloated C++ example included with my 635 USB LCD so i hacked it apart for useable stuff and wrote a simple C header file you can include in projects that contains useful functions. Hope this is useful to someone.

Header File:
Code:
/***********************************************************************************************
***  A bunch of handy functions for using Crystalfontz 635 serial LCD
***  Adapted by Adam Yergovich (ayergovich@yahoo.com) from code supplied by Crystalfontz
***  April 10th, 2008
***********************************************************************************************/

//Some defines for commands to use.  I only included some i found useful.

#define COM_SET_CURSOR_POS 0x0B
#define COM_SET_CURSOR_STY 0x0C
#define COM_SET_CONTRAST 0x0D
#define COM_SET_BACKLIT 0x0E
#define COM_SEND_DATA 0x1F
#define COM_SET_GPIO 0x022
#define COM_STORE_STATE 0x04
#define COM_CLEAR 0x06

int handle = 0;			//Handle for Serial Port

unsigned int rt_key = 0;	//Key press counts
unsigned int lt_key = 0;	//Only presses (not releases) used
unsigned int up_key = 0;
unsigned int dn_key = 0;
unsigned int ck_key = 0;
unsigned int xx_key = 0;

/*************************************************************************
***  Functions that may be handy for you
*************************************************************************/

/************************************************************************
***  This funtion is used by the packet handling functions to get the CRC
***  You probably don't need to use it externally but if so, pass it a 
***  pointer to the array containing the command and the length.  Seed
***  should be 0xFFFF if you're using it for the LCD.  
***  Returns an unsigned long with the CRC, so you'll likely need to bit
***  shift the value to get it into a packet to send.
************************************************************************/
unsigned long get_crc(unsigned char *bufptr, unsigned long len, unsigned long seed);
//------------------------------------------------------------------------------


/************************************************************************
***  Used to initialize the serial port @115200 with the proper settings.
***  Pass it a pointer to the string containing the device name.
***  Returns zero on success.
************************************************************************/
int Serial_Init(char * devname);
//------------------------------------------------------------------------------


/************************************************************************
***  Sends a byte to the open serial port. Prints error message if fscked
************************************************************************/
void SendByte(unsigned char datum);
//------------------------------------------------------------------------------


/************************************************************************
***  Intelligent command sending.  Issue command # from defines above
***  and data pointer as well as data length.  This funtion will then call 
***  receive packet to check for proper acknowlegement.  
***  Returns -1 if failure, 0 on success.  
***  Note that this function WILL update any button presses.
************************************************************************/
int send_command(unsigned char command, unsigned char *datum, int len);
//------------------------------------------------------------------------------


/************************************************************************
***  Checks buffer for packets intelligently.  Reads data length from 
***  stream and checks the CRC.  Updates button presses if it is a
***  report packet.  Stores the returned value in the char array
***  destination.
***  Returns -1 if packet is bad, 1 if received good report (button press)
***  and 0 if otherwise successful.
************************************************************************/
int receive_packet(unsigned char *destination);
//-----------------------------------------------------------------------------




//------------------------------------------------------------------------------

unsigned long get_crc(unsigned char *bufptr,unsigned long len,unsigned long seed)
  {
  //CRC lookup table to avoid bit-shifting loops.
  static const unsigned long crcLookupTable[256] =
    {0x00000,0x01189,0x02312,0x0329B,0x04624,0x057AD,0x06536,0x074BF,
     0x08C48,0x09DC1,0x0AF5A,0x0BED3,0x0CA6C,0x0DBE5,0x0E97E,0x0F8F7,
     0x01081,0x00108,0x03393,0x0221A,0x056A5,0x0472C,0x075B7,0x0643E,
     0x09CC9,0x08D40,0x0BFDB,0x0AE52,0x0DAED,0x0CB64,0x0F9FF,0x0E876,
     0x02102,0x0308B,0x00210,0x01399,0x06726,0x076AF,0x04434,0x055BD,
     0x0AD4A,0x0BCC3,0x08E58,0x09FD1,0x0EB6E,0x0FAE7,0x0C87C,0x0D9F5,
     0x03183,0x0200A,0x01291,0x00318,0x077A7,0x0662E,0x054B5,0x0453C,
     0x0BDCB,0x0AC42,0x09ED9,0x08F50,0x0FBEF,0x0EA66,0x0D8FD,0x0C974,
     0x04204,0x0538D,0x06116,0x0709F,0x00420,0x015A9,0x02732,0x036BB,
     0x0CE4C,0x0DFC5,0x0ED5E,0x0FCD7,0x08868,0x099E1,0x0AB7A,0x0BAF3,
     0x05285,0x0430C,0x07197,0x0601E,0x014A1,0x00528,0x037B3,0x0263A,
     0x0DECD,0x0CF44,0x0FDDF,0x0EC56,0x098E9,0x08960,0x0BBFB,0x0AA72,
     0x06306,0x0728F,0x04014,0x0519D,0x02522,0x034AB,0x00630,0x017B9,
     0x0EF4E,0x0FEC7,0x0CC5C,0x0DDD5,0x0A96A,0x0B8E3,0x08A78,0x09BF1,
     0x07387,0x0620E,0x05095,0x0411C,0x035A3,0x0242A,0x016B1,0x00738,
     0x0FFCF,0x0EE46,0x0DCDD,0x0CD54,0x0B9EB,0x0A862,0x09AF9,0x08B70,
     0x08408,0x09581,0x0A71A,0x0B693,0x0C22C,0x0D3A5,0x0E13E,0x0F0B7,
     0x00840,0x019C9,0x02B52,0x03ADB,0x04E64,0x05FED,0x06D76,0x07CFF,
     0x09489,0x08500,0x0B79B,0x0A612,0x0D2AD,0x0C324,0x0F1BF,0x0E036,
     0x018C1,0x00948,0x03BD3,0x02A5A,0x05EE5,0x04F6C,0x07DF7,0x06C7E,
     0x0A50A,0x0B483,0x08618,0x09791,0x0E32E,0x0F2A7,0x0C03C,0x0D1B5,
     0x02942,0x038CB,0x00A50,0x01BD9,0x06F66,0x07EEF,0x04C74,0x05DFD,
     0x0B58B,0x0A402,0x09699,0x08710,0x0F3AF,0x0E226,0x0D0BD,0x0C134,
     0x039C3,0x0284A,0x01AD1,0x00B58,0x07FE7,0x06E6E,0x05CF5,0x04D7C,
     0x0C60C,0x0D785,0x0E51E,0x0F497,0x08028,0x091A1,0x0A33A,0x0B2B3,
     0x04A44,0x05BCD,0x06956,0x078DF,0x00C60,0x01DE9,0x02F72,0x03EFB,
     0x0D68D,0x0C704,0x0F59F,0x0E416,0x090A9,0x08120,0x0B3BB,0x0A232,
     0x05AC5,0x04B4C,0x079D7,0x0685E,0x01CE1,0x00D68,0x03FF3,0x02E7A,
     0x0E70E,0x0F687,0x0C41C,0x0D595,0x0A12A,0x0B0A3,0x08238,0x093B1,
     0x06B46,0x07ACF,0x04854,0x059DD,0x02D62,0x03CEB,0x00E70,0x01FF9,
     0x0F78F,0x0E606,0x0D49D,0x0C514,0x0B1AB,0x0A022,0x092B9,0x08330,
     0x07BC7,0x06A4E,0x058D5,0x0495C,0x03DE3,0x02C6A,0x01EF1,0x00F78};

  //Initial CRC value is 0x0FFFF.
  unsigned long newCrc;
  newCrc=seed;
  //This algorithim is based on the IrDA LAP example.
  while(len--){
    newCrc = (newCrc >> 8) ^ crcLookupTable[(newCrc ^ *bufptr++) & 0xff];
  }
  //Make this crc match the one's complement that is sent in the packet.
  return(~newCrc);
  }

  int Serial_Init(char *devname)
    {
    int
      brate = B115200;
    struct
      termios term;
    unsigned char init[30];

    //open device
    handle = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);

    if(handle <= 0)
      {
        	printf("Serial_Init:: Open() failed\n");
  	return(1);
      }

    //get device struct
    if(tcgetattr(handle, &term) != 0)
      {
      printf("Serial_Init:: tcgetattr() failed\n");
      return(3);
      }

    //input modes
    term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL
                    |IXON|IXOFF);
    term.c_iflag |= IGNPAR;

    //output modes
    term.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET|OFILL
                    |OFDEL|NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);

    //control modes
    term.c_cflag &= ~(CSIZE|PARENB|PARODD|HUPCL|CRTSCTS);
    term.c_cflag |= CREAD|CS8|CSTOPB|CLOCAL;

    //local modes
    term.c_lflag &= ~(ISIG|ICANON|IEXTEN|ECHO);
    term.c_lflag |= NOFLSH;

    //set baud rate
    cfsetospeed(&term, brate);
    cfsetispeed(&term, brate);

    //set new device settings
    if(tcsetattr(handle, TCSANOW, &term)  != 0)
      {
      printf("Serial_Init:: tcsetattr() failed\n");
      return(4);
      }

    //ReceiveBufferHead=ReceiveBufferTail=0;
    tcflush(handle, TCIOFLUSH);
    printf("Serial_Init:: success\n");
    return(0);
  }



void SendByte(unsigned char datum)
  {
  unsigned int bytes_written;
  bytes_written=0;

  if(handle)
    {
    if((bytes_written=write(handle, &datum, 1)) != 1)
      printf("SendByte(): system call \"write()\" return error.\n  Asked for %d bytes to be written, but %d bytes reported as written.\n", 1, bytes_written);
    }
  else
    printf("SendByte(): \"handle\" is null\n");
  }

int send_command(unsigned char command, unsigned char *datum, int len){
  unsigned char mes[30];
  unsigned char res[30];
  int i = 0;
  unsigned long crc = 0;
  mes[0] = command;
  mes[1] = len;
  
  for(i=0;i<len;i++){
	mes[i+2] = *datum;
	datum++;
  }
  crc = get_crc(mes,len+2,0xFFFF);
  mes[len+2]=crc;
  crc >>= 8;
  mes[len+3]=crc;

  SendByte(mes[0]);
  SendByte(mes[1]);

  for(i=0;i<len;i++){
    SendByte(mes[i+2]);
  }

  SendByte(mes[len+2]);
  SendByte(mes[len+3]);

  usleep(250000); //time needed to check for packet

  while(1){
    i = receive_packet(res);
    if(i == -1) return -1;
    else if(i == 0) return 0;
  }
  
}

int receive_packet(unsigned char * destination){
  int i = 1;
  int rerror = 0;
  unsigned char len = 0;
  unsigned long crc = 0;
  unsigned char crc_low = 0;
  unsigned char crc_hi = 0;

  rerror = read(handle, destination, 1);
  if(rerror == -1) return -1;
  while(1){
    if(read(handle,&destination[1],1) == 1) break;
    rerror++;
    if(rerror == -1) return -1;
  }
  rerror = 0;
  for(len = 0;len < destination[1] + 2; len++)
    while(1){
      if(read(handle,&destination[len+2], 1) == 1) break;
      rerror++;
      if(rerror == -1) return -1;
    }
  rerror = 0;
  crc = get_crc(destination, destination[1] + 2, 0xFFFF);
  crc_low = crc;
  crc >>= 8;
  crc_hi = crc;
    
  if((crc_hi != destination[destination[1]+3]) || (crc_low != destination[destination[1]+2])){
    return -1;
  }

  if((destination[0] & 0xC0) == 0x80){   //Is this a report?  If so update button presses if necessary
    switch (destination[2]){
      case 0x1: 
	up_key++;
	break;
      case 0x2:
	dn_key++;
	break;
      case 0x3:
	lt_key++;
        break;
      case 0x4:
	rt_key++;
	break;
      case 0x5:
	ck_key++;
	break;
      case 0x6:
	xx_key++;
	break;
    }

    return 1;
  }
  else if((destination[0] & 0xC0) == 0x40){  //Regular response
    return 0;
  }
  else {
    printf("packet has bad header\n");
    return -1;
  }
}
Sample program using said header:

Code:
/***********************************************************************
***  Simple test program for the Crystalfonts 635 USB LCD
***  demonstrating the use of the LCD.h 
***  Allows for control of the LEDs on front using button arrow keys.
***  Up/Down to switch LED and die color
***  Left/Right to add or delete to duty cycle
***  X key exits.  Check does nothing.
***  Adam Yergovich (ayergovich@yahoo.com)
***  April 10, 2008
***********************************************************************/
#include  <termios.h>
#include  <fcntl.h>
#include  <stdio.h>
#include  <string.h>
#include  "LCD.h"

int main(void){
	unsigned char mes[30];  //Buffer for packets to send
	int i = 0;
	int die = 0;		//Duty cycle for LEDs
	int pos = 12;		//Which LED we're on

	Serial_Init("/dev/ttyUSB0");

	memcpy(&mes[2], "Adam Test Program",17);	//Fill data
	mes[0] = 0;					//First column
	mes[1] = 1;					//Second row

	i = send_command(COM_CLEAR,0x00,0x00);
	sleep(1);	
	i = send_command(COM_SEND_DATA,mes,19);		//len = 17 + 2
	sleep(1);
	i = 0;
	while(xx_key == 0){ 
	  mes[0] = pos;
	  mes[1] = die;
	  send_command(COM_SET_GPIO,mes,2);
	  if(up_key){
	    pos++;
	    if(pos == 13) pos =12;
	    send_command(COM_CLEAR,0x00,0x00);
	    mes[0] = 0;
	    mes[1] = ((((pos+1)/2) - 6) * -1);		//Display in row next to LED
	    if(pos % 2 == 0){ 
	      memcpy(&mes[2],"RED DIE",7);
	      send_command(COM_SEND_DATA,mes,9);
	    }
	    else{
	      memcpy(&mes[2],"GRN DIE",7);
	      send_command(COM_SEND_DATA,mes,9);
	    }
	    up_key = 0;
	  }
	  if(dn_key){
	    pos--;
	    if(pos <= 5) pos =5;
	    send_command(COM_CLEAR,0x00,0x00);
	    mes[0] = 0;
	    mes[1] = ((((pos+1)/2) - 6) * -1);
	    if(pos % 2 == 0){ 
	      memcpy(&mes[2],"RED DIE",7);
	      send_command(COM_SEND_DATA,mes,9);
	    }
	    else{
	      memcpy(&mes[2],"GRN DIE",7);
	      send_command(COM_SEND_DATA,mes,9);
	    }
	    dn_key = 0;
	  }
	  if(rt_key){
	    die = die +10;
	    if(die >= 100) die = 100;
	    rt_key = 0;
	  }
	  if(lt_key){
	    die = die -10;
	    if(die <= 0) die = 0;
	    lt_key = 0;
	  }
	}
	return 0;
}
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

CF Tech

Administrator
Thank you for your sample code. I am sure people using the CFA-635 under Linux will find it useful.
 

infomedialab

New member
Help me:Missing code

Hello thare are missing a part of code on this condition

FILE LCD.H

int send_command(unsigned char command, unsigned char *datum, int len){
unsigned char mes[30];
unsigned char res[30];
int i = 0;
unsigned long crc = 0;
mes[0] = command;
mes[1] = len;

for(i=0;i>= 8; * Missing

Thank you for your sample code and support me
 

ayergo

New member
It appears to all be there to me. The code following what you describe in sendcommand function shows up for me, anyone else not seeing it?
 

CF Tech

Administrator
It might be some HTML browser thing I used the ampersand lt semicolon to replace the less than characters. Maybe it will be OK now.
 

infomedialab

New member
Now is ok!

Thanks a lot Adam!is very professional,very very good source code:):):):):):D:D:D

Compiled with arm-gcc-linux ver 4.1 !! is ok!

I've upload precompiled source code for arm solution!with Adam's source code!
 

Attachments

Top