<!doctype linuxdoc system>
 <article> 
  <titlepag>
   <title>Velleman K8000 & Linux HOWTO
   <author>
    <name>
      Heimo Schön <htmlurl url="mailto:Heimo Schön<heimo.schoen@gmx.at>" 
                          name="Heimo Schön <heimo.schoen@gmx.at>">
   </author>
   <date>Version 0.4 , 6. Feb. 2002
   <abstract>
     Setup a <htmlurl url="http://www.velleman.be/kits/k8000.htm" name="Velleman K8000"> on a
     <htmlurl url="http://www.linux.org" 
      name="Linux"> System
   </abstract>
  </titlepag>

  <sect>Overview
   <sect1>About this HOWTO
    <p>
    This document describes how to setup your
    <htmlurl url="http://www.velleman.be/kits/k8000.htm" name="Velleman K8000 Board"> on a
    <htmlurl url="http://www.linux.org" name="Linux"> system, using the
     i2c Kerneldrivers
    <p>
    If you have any suggestions to this document, than feel
    free to contact me:
    <p>
    <itemize>
      <item>Heimo Schön <htmlurl url="mailto:heimo.schoen@gmx.at"
                                 name="<heimo.schoen@gmx.at>">
      <item><htmlurl url="http://schoen.priv.at"
                    name="http://schoen.priv.at">
     </itemize>
    <p>
    Have a lot of fun with your Velleman K8000 Board.
    <p>

   <sect1>Links
    <p>
     Links to other sites with aditional information to K8000 running with Linux:
     <itemize>
       <item> <htmlurl url="http://yahoogroups.com/group/k8000" 
                      name="http://yahoogroups.com/group/k8000">
       <item> <htmlurl url="http://struyve.mine.nu:8080/pageloader.pl?block=k8000" 
                      name="http://struyve.mine.nu:8080/pageloader.pl?block=k8000">
       <item> <htmlurl url=""http://groups.yahoo.com/group/k8000/files/linux/libk8000/ 
                      name="http://groups.yahoo.com/group/k8000/files/linux/libk8000/">
     </itemize>
    <p>


   <sect1>Thanks to
    <p>
     <itemize>
       <item><htmlurl url="mailto:hihihi <hihihi@wanadoo.nl>" 
                     name="hihihi <hihihi@wanadoo.nl>">
             for his help in testing and correcting this mini-howto.
     </itemize>
    <p>


   <sect1>Version History
    <p>
     <itemize>
       <item> 0.1 08 Dec 2001 first trial
       <item> 0.2 28 Jan 2002 included a hint from Hihihi from NL to
                              rmmod the lp-driver in the startscript
       <item> 0.3 3 Feb 2002 A lot of corrections and new features from
                             <htmlurl url="mailto:hihihi <hihihi@wanadoo.nl>" 
                                     name="hihihi <hihihi@wanadoo.nl>">
                             included
       <item> 0.4 6 Feb 2002 Minor bug fix from
                             <htmlurl url="mailto:hihihi <hihihi@wanadoo.nl>" 
                                     name="hihihi <hihihi@wanadoo.nl>">
                             
     </itemize>
    <p>

  <sect>Introduction

    <p>
   In this chapter I want to discribe the history of this mini-mini-howto.

   <sect1>Target

    <p>
     In 1995 I was searching for an expansion board for my home-PC. It was a
     PC-AT with 386 CPU and at that time I was programming with clipper.
     I wanted to read some digital and analog input and I thought that I
     don't want a board in my PC. I was searching for an external solutions.
    <p>
     I found the velleman K8000 board in an electronic shop. There was a
     source code for the driver available. I compiled this code with borland-C compiler
     and linked it together with my Clipper application. This program is
     running since Summer 1995 an doing some watching of my oil-heating at
     home.
    <p>
     Today this old machine is the last DOS-based machine at home. All other
     PCs are running with Linux. I searched through the web a lot of hours
     and found only the i2c-velleman.c Kernel-driver in the kernel-tree. But
     I couldn't find any examples, how to connect from a small C-program to
     the K8000 board. So I decided, to try to hack it by myself. After the
     program(s) was(were) running I wrote this small HOWTO.
    <p>
     However, if you find I could help you learning howto connect from C to
     your Velleman K8000 board, feel free to send me a short message. I would
     be happy to hear from you - I am sure thare there are some other K8000 
     user out there :-))
    <p>
     In a discussion with 
     <htmlurl url="mailto:hihihi <hihihi@wanadoo.nl>" 
             name="hihihi <hihihi@wanadoo.nl>">
     I found out that there also exists a velleman-library called libk8000. This HOWTO does not
     support this library-solution. Here I discribe the connection via kernel-drivers.
     At this point I want to thank 
     <htmlurl url="mailto:hihihi <hihihi@wanadoo.nl>" 
             name="hihihi <hihihi@wanadoo.nl>">
     for his hints and for testing this HOWTO.

   <sect1>HW-Configuration

    <p>
     When you finished soldering your K8000, you should switch the two
     DIP-Switches to the off position.


   <sect1>SW-Configuration

    <p>
     You should prepare your system by running the following script (I
     stored it under the name "velle")
     <tscreen><verb>
#! /bin/bash

echo free the Parport ...
/sbin/rmmod lp
/sbin/rmmod parport_pc
/sbin/rmmod vmppuser
/sbin/rmmod parport

echo i2c Treiber laden ...
/sbin/modprobe i2c-velleman
/sbin/modprobe i2c-dev

echo create the device-handle and free it for all users
cd /dev
rm velleman

# The following part was written by hihihi#wanadoo.nl
# Jan 31 2002
# A variation on the ./velle script of Heimo Schoen.
Filename=/proc/bus/i2c
line="not empty yet"
echo
echo "    Look for I2C devices in /proc/bus/i2c :"
echo
while [ "$line" != "" ]
do
  read line
  echo "     " $line
  if echo "$line" | grep -q "Velleman K8000"
  then
    K8000Entry=$line
  fi
done <"$Filename"

echo
echo "      Found a Velleman K8000 entry:" $K8000Entry
echo

K8000Nod=${K8000Entry#i2c-}
echo $K8000Nod 
K8000Nod=`expr match "$K8000Nod" '\([0-9]*[0-9]\)'`
echo $K8000Nod

mknod velleman c 89 $K8000Nod
chmod a+rw velleman

echo Etwas auf die K8000 jagen ...
echo hallo > /dev/velleman
     </verb></tscreen>

     You can download this script
     <htmlurl url="velleman.tgz" name="here">



   <sect>the programs

   <sect1>check-i2c.c
    <p>
     This small C-program checks all addresses from 0 to 127 if there are
     reacheable i2c-chips connected to your parallel port. Before you start
     this program, you should compile and link it by typing make all and
     load all i2c kernel modules with the above described script named "velle"

     <tscreen><verb>
/*
**   $Id: check-i2c.c,v 0.01
**
**   File:     check-i2c.c
**   Author:   Heimo Schoen / heimo.schoen@gmx.at
**
**   Abstract: Routine for testing the Kerneldriver
**             ../driver/char/i2cv-elleman.c
**
#
# Copyright (C) 2001,2002 by Heimo Schön  <heimo.schoen@gmx.at>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, BUT NOT (!!!)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
*/

# include <errno.h>
# include <stdio.h>
# include <signal.h>
# include <stdarg.h>
# include <time.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  int fh   = 0;
  unsigned int port = 0;
  int res;
  char devicename[100] = "/dev/velleman";

  if (argc == 2)
    sprintf(devicename, "%s", argv[1]);

  fh  = open(devicename, O_RDWR);

  if (fh < 3) {

    printf("\n");
    printf("check-i2c had a problem opening %s\n", devicename);
    printf("\n");
    printf("  please execute script velle included in the package check-i2c\n");
    printf("\n");
    printf("  You should have a file /dev/velleman generated with the command\n");
    printf("     mknod /dev/velleman c 89 0\n");
    printf("\n");
    printf("  You also should have loaded i2c-velleman i2c-dev i2c-core and i2c-algo-bit\n");
    printf("  into your kernel. See script velle for details how to do this\n");
    printf("\n");
    printf("usage of check-i2c:\n");
    printf("\n");
    printf("    check-i2c [devicename]\n");
    printf("\n");
    printf("    if parameter devicename is not given, check-i2c will try to open\n");
    printf("    /dev/velleman.\n");
    printf("\n");
    printf("(c) 2001,2002 by Heimo Schön / heimo.schoen@gmx.at / http://schoen.priv.at\n");
    printf("\n");
    printf("       have a lot fun ...\n");
    printf("\n");

    exit (1);

  } else {

    printf("\n");
    printf("check-i2c will search now on %s for reachable i2c-devices and will show you the addresses:\n", devicename);
    printf("\n");

    // Loop across all available 7-Bit addresses
    for (port=0; port<=127; port++) {
      
      // Try to ioctl this device-address
      if (ioctl(fh, I2C_SLAVE, port) < 0)
	perror ("IOCTL Problem");
      
      /* Using SMBus commands */
      res = i2c_smbus_write_byte(fh, 0x00); 
      if (res >= 0) 
	printf("found i2c-chip at     i2c-address: 0x%02x (%d)      (real-address: 0x%02x)\n", 
	       port, port, port*2);
      
      //usleep(1000);

    } // loop port=0-127

    printf("\n");
    printf("NOTE:\n");
    printf("the i2c-drivers in the kernel use a 7-bit adress.\n");
    printf("E.g. if you want to write to a PCF8574A at the adress 0x70\n");
    printf("than you have to divide 0x70 by two. This is 0x38, which is the\n");
    printf("address for the kernel-drivers.\n");
    printf("With other words, the kernel-driver is shifting your adress (0x38)\n");
    printf("one byte left an adds 0 if you write ore 1 if you read from the\n");
    printf("address.\n");
    printf("I know, this is a little bit complecated ;-) But this is also the\n");
    printf("reason why I wrote this small program\n");
    printf("\n");
    printf("      have a lot of fun ...\n");
    printf("\n");

    exit (0);
  }
}
     </verb></tscreen>

     You can download this program with the Makefile 
     <htmlurl url="velleman.tgz" name="here">



   <sect1>velleman.c
    <p>
     velleman.c is doing some test with digital-output on your velleman K8000.
     This program is expecting that you have a K8000 connected to your /dev/lp0
     and that all i2c drivers are loaded as described before.
     It switches all outputs on and off. There is a small help available
     (just read the source ;-)

     <tscreen><verb>
/*
**   $Id: velleman.c,v 0.01
**
**   File:     velleman.c
**   Author:   Heimo Schoen / heimo.schoen@gmx.at
**
**   Abstract: Routine for testing the Kerneldriver
**             ../driver/char/i2cv-elleman.c
**
#
# Copyright (C) 2001,2002 by Heimo Schön  <heimo.schoen@gmx.at>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
*/

# include <errno.h>
# include <stdio.h>
# include <signal.h>
# include <stdarg.h>
# include <time.h>

# include <sys/types.h>
# include <sys/time.h>
# include <sys/socket.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <unistd.h>

// ----------------------------------------------------------
int p_i2c_write(unsigned int  vf_fh, 
		unsigned int  vf_port, 
		unsigned char vf_data)
{
  int vp_res;

  if (ioctl(vf_fh,I2C_SLAVE,vf_port))
    perror ("IOCTL Problem");
  vp_res = i2c_smbus_write_byte(vf_fh, ~vf_data);
  if (vp_res < 0) 
    perror("i2c_smbus_write_byte");
  return (vp_res);
}



// ----------------------------------------------------------
int p_write(unsigned int  vf_fh, 
	    unsigned int  vf_port, 
	    unsigned char vf_data)
{
  int vp_res;
  unsigned char vp_buf[10];

  if (ioctl(vf_fh,I2C_SLAVE,vf_port))
    perror ("IOCTL Problem");
  vp_buf[0] = ~vf_data;
  vp_res = write(vf_fh, vp_buf, 1);
  return (vp_res);
}



// ----------------------------------------------------------
int main(int argc, char *argv[])
{
  int fh  = 0;
  int res;
  int i;
  unsigned int port1 = 0x38;
  unsigned int port2 = 0x39;
  unsigned char buf[10];
  char devicename[100] = "/dev/velleman";
  unsigned char testmode = 0;

  if (argc >= 2) {
    if (strlen(argv[1]) > 1)
      sprintf(devicename, "%s", argv[1]);
    if (strlen(argv[1]) == 1)
      testmode = atoi(argv[1]);
  }

  if (argc >= 3) {
    if (strlen(argv[2]) > 1)
      sprintf(devicename, "%s", argv[2]);
    if (strlen(argv[2]) == 1)
      testmode = atoi(argv[2]);
  }

  fh  = open(devicename, O_RDWR);

  if (fh < 3) {

    printf("\n");
    printf("velleman had a problem opening %s\n", devicename);
    printf("\n");
    printf("  please execute script velle included in the package velleman\n");
    printf("\n");
    printf("  You should have a file /dev/velleman generated with the command\n");
    printf("     mknod /dev/velleman c 89 0\n");
    printf("\n");
    printf("  You also should have loaded i2c-velleman i2c-dev i2c-core and i2c-algo-bit\n");
    printf("  into your kernel. See script velle for details how to do this\n");
    printf("\n");
    printf("usage of velleman:\n");
    printf("\n");
    printf("    velleman [devicename] [test]\n");
    printf("\n");
    printf("    if parameter devicename is not given, velleman will try to open\n");
    printf("    /dev/velleman.\n");
    printf("\n");
    printf("    parameter [test] has to be numeric and tells which testnumber you want\n");
    printf("    If Parameter [test] is not found, velleman will only check the PCF8574A if present\n");
    printf("\n");
    printf("example:  velleman /dev/i2c-0 2\n");
    printf("\n");
    printf("(c) 2001,2002 by Heimo Schön / heimo.schoen@gmx.at / http://schoen.priv.at\n");
    printf("\n");
    printf("       have a lot fun ...\n");
    printf("\n");

    exit (1);

  } else {

    // checking if we can find the two PCF5874A

    if (ioctl(fh,I2C_SLAVE,port1) < 0)
      perror ("IOCTL Problem");
    res = i2c_smbus_write_byte(fh, 0x00); 
    if (res >= 0)
      printf("found i2c-chip at     i2c-address: 0x%02x (%d)      (real-address: 0x%02x)\n", 
	     port1, port1, port1*2);

    if (ioctl(fh,I2C_SLAVE,port2) < 0)
      perror ("IOCTL Problem");
    res = i2c_smbus_write_byte(fh, 0x00); 
    if (res >= 0)
      printf("found i2c-chip at     i2c-address: 0x%02x (%d)      (real-address: 0x%02x)\n", 
	     port2, port2, port2*2);

    sleep(1);
    
    if (testmode == 1) {
      printf("Starting testmode 1 : Counter    (stop test with CTRL-C)\n");
      while (1) {
	/* Using SMBus commands */
	for (i=0; i<=0xff; i++) {
	  p_i2c_write(fh, port1, i);
	  p_i2c_write(fh, port2, i);
	  
	  usleep(5);
	}
      }
    }

    if (testmode == 2) {
      printf("Starting testmode 2 : Knightrider    (stop test with CTRL-C)\n");
      while (1) {
	for (i=1; i<=15; i++) {
	  
	  if (i<=7) {
	    p_write(fh, port1, 1<<i);
	    p_write(fh, port2, 0);
	  } else {
	    p_write(fh, port2, 1<<(i-8));
	    p_write(fh, port1, 0);
	  }
	  usleep(1);
	}
	for (i=14; i>=0; i--) {
	  
	  if (i<=7) {
	    p_write(fh, port1, 1<<i);
	    p_write(fh, port2, 0);
	  } else {
	    p_write(fh, port2, 1<<(i-8));
	    p_write(fh, port1, 0);
	  }
	  usleep(1);
	}
      }
    }
    
/*     ioctl(fh,I2C_UDELAY,5); */
/*     ioctl(fh,I2C_MDELAY, 2); */
/*     ioctl(fh,I2C_RETRIES,3); */
    
    if (ioctl(fh,I2C_SLAVE,port1) /* ioctl(fh, I2C_SLAVE, port1) */ < 0)
      perror ("IOCTL Problem");
    
    errno = 0;
    res = ~ i2c_smbus_read_byte(fh); 
    if (errno != 0) 
      perror("i2c_smbus_read_byte");
    else
      printf("i2c_smbus_read_byte: 0x%02x\n",
	     res);
    
    sleep(1);
    
    /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
    res = read(fh,buf,1);
    if ( res == 1)
      printf("POSIX-Read: %d bytes buf[0]=0x%02x\n",
	     res, ~ buf[0]);
    
  }


  return 0;
}
     </verb></tscreen>

     You can download this program with the Makefile 
     <htmlurl url="velleman.tgz" name="here">

   <sect1>Makefile
    <p>
     Last but not least, the Makefile to the above two sources

     <tscreen><verb>
#
# Makefile for the velleman testprogram
#
# Copyright (C) 2001,2002 Heimo Schön <heimo.schoen@telecom.at>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

           CFLAGS        =  -pedantic -Wall -O -g

           LDOPTIONS     = -g -DYY_SKIP_YYWRAP
	   RM            = rm -f
	   CP            = cp -v
	   STRIP         = strip --verbose

           VELLEMANSRCS = velleman.c
           VELLEMANOBJS = $(patsubst %.c,%.o,$(VELLEMANSRCS))
           CHECKSRCS    = check-i2c.c
           CHECKOBJS    = $(patsubst %.c,%.o,$(CHECKSRCS))

all:: velleman check-i2c

tags: 
	etags *.[hc]

velleman:  $(VELLEMANOBJS) $(DEPLIBS)
	$(RM) $@
	$(CC) -o $@ $(VELLEMANOBJS) $(LDOPTIONS) -O0 -g -L/usr/lib/termcap -lreadline -lhistory -ltermcap

check-i2c:  $(CHECKOBJS) $(DEPLIBS)
	$(RM) $@
	$(CC) -o $@ $(CHECKOBJS) $(LDOPTIONS) -O0 -g -L/usr/lib/termcap -lreadline -lhistory -ltermcap

clean::
	$(RM) velleman check-i2c *.o *~

depend::
	@if [ -n "$(VELLEMANSRCS)" ] ; then set -x;\
	  $(DEPEND) $(DEPENDFLAGS) $(VELLEMANSRCS);\
	fi
	@if [ -n "$(CHECKSRCS)" ] ; then set -x;\
	  $(DEPEND) $(DEPENDFLAGS) $(CHECKSRCS);\
	fi
     </verb></tscreen>




   <sect1>notes
    <p>
     If you dont want to use the kernel-drivers, you find a solution
     for a user-space program 
     <htmlurl url="http://struyve.mine.nu:8080/pageloader.pl?block=k8000" name="here">



<sect>Allgemeines

<sect1>Copyright 
<p>
Dieses Dokument ist urheberrechtlich geschützt. Das Copyright 
liegt bei Heimo Schön. 
<p>
Das Dokument darf gemäß der GNU General Public License verbreitet 
werden. Insbesondere bedeutet dieses, daß der Text sowohl über 
elektronische wie auch physikalische Medien ohne die Zahlung von 
Lizenzgebühren verbreitet werden darf, solange dieser Copyright 
Hinweis nicht entfernt wird. Eine kommerzielle Verbreitung ist 
erlaubt und ausdrücklich erwünscht. Bei einer Publikation in 
Papierform ist der Autor zu informieren. 
<p>
This howto is free documentation; you can redistribute it and/or 
modify it under the terms of the GNU General Public License as 
published by the Free Software Foundation; either version 2 of 
the License, BUT NO later version. 
<p>
This document is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
GNU General Public License for more details. 
<p>
You should have received a copy of the GNU General Public License 
along with this document; if not, write to the: 
Free Software Foundation, Inc., 675
Mass Ave, Cambridge, MA 02139, USA. 
<p>




 </article>
 <!-- Keep this comment at the end of the file
 Local variables:
 mode: sgml
 sgml-omittag:t
 sgml-shorttag:t
 sgml-minimize-attributes:nil
 sgml-always-quote-attributes:t
 sgml-indent-step:1
 sgml-indent-data:t
 sgml-parent-document:nil
 sgml-exposed-tags:nil
 sgml-local-catalogs:("/usr/lib/sgml-tools/dtd/catalog")
 sgml-local-ecat-files:nil
 End:
 -->
