3

I am a very beginner on programming and raspberry usage, tho I think I learn fast. I am trying to convert an old program (not mine) that was written for Linux on C++ for communication with a printer chip using a standard serial port, into a python program with access to the same chip using GPIO ports. However, I am unable to understand how to translate the outb() portion of the code. To make things easier to understand, here is an example of the code (using real parts of the code, tho the code is actually way bigger):

#include <insert_all_necessary_libraries_here>
#include <lets_assume_there_is_no_error_here>

#define LPT 0x378       /*Port Addres(0x378,0x3BC,0x278)*/
#define PORT_OUT LPT+0  /*OUTPUT: Data port*/

int portdata;
int syncmask = 0x01;
int powermask = 0xE0;

void resetport(){
    outb(0,PORT_OUT);
}

void powerup(){
    portdata=portdata | powermask;
    outb(portdata,PORT_OUT);
}

void syncup(){
    portdata=portdata | syncmask;
    outb(portdata,PORT_OUT);
}

void syncdown(){
    portdata=portdata & (syncmask ^ 0xff);
    outb(portdata,PORT_OUT);
}

void main() {
    resetport();
    delay500us();
    powerup();
    syncdown();
    delay500us();
    syncup();
    delay500us();
}

As you can see, the code is based pretty much on the outb() command. I have a basic understanding of the function of this command and therefore I understand -somewhat- what the code is doing, tho how to do an equivalent job on python using GPIOs..... Looking at the answer from Malvineous on this answer for pretty much the same question I assume that it is indeed possible (at least using C++, not sure about Python). Nonetheless, I can't really understand the implementation on the example given, and the links provided on that answer are not anymore (well, the answer is from 7 years ago, what was I expecting...?)

Can someone please help me out with this one? I have been trying to get this thing to work on my own for the last couple of weeks, but I have not been successful yet, and I am running out of options on how to make this work, at least with my current understanding.

(In case you want to take a look at the original code, you can download it here)

Thanks in advance to anyone that can help!

dblokillo
  • 31
  • 2
  • Raspberry Pi has serial ports. Can you use that? https://www.instructables.com/id/Read-and-write-from-serial-port-with-Raspberry-Pi/ – Brick Jun 04 '19 at 21:21
  • It is a bit confusing that you say it is a serial port, but you are sending 8 bit data out. For Arduino like MPU, there are write port function that can send a databyte to 8 GPIO pins. For Rpi, we need to write our own write port function (not difficult though). If you can let us know the printer schematic and/or printer IC chip, then we can make less wrong guesses. – tlfong01 Jun 05 '19 at 03:46
  • What exactly do you want to achieve? Send data to a standard printer? Use the parallel port for something different? – RalfFriedl Jun 05 '19 at 06:02
  • Your original code link seems wrong. – tlfong01 Jun 05 '19 at 07:18
  • Why do you want to convert to Python? If you have a working C++ program, why not port that directly as C++? There's nothing especially good about Python to make it worth re-inventing this wheel that you seem to have (mostly) already. – Brick Jun 05 '19 at 16:57
  • @Brick I can try that, tho I think the pi has only 2 serial ports, am I wrong? If so, I need 3 (or so I understand). – dblokillo Jun 06 '19 at 10:43
  • @RalfFriedl Take a look at this site (http://eddiem.com/photo/printer/chipreset/resetchip.html). This is what I am trying to accomplish. – dblokillo Jun 06 '19 at 10:43
  • @tlfong01 The link works fine for me.... try going to the above mentioned link, at the end under section "A Unix port by By Benoy George.". – dblokillo Jun 06 '19 at 10:43
  • Also @Brick I want to convert to Python because I understand it better than C++... I'm a self learner, and Python is just a little easier for me. Tho if it is possible to do it on C++ then that would be fine as well. – dblokillo Jun 06 '19 at 10:44
  • @dblokillo Well, the original post's link is this: http://eddiem.com/photo/printer/chipreset/chipset.tgz You then gave this:

    eddiem.com/photo/printer/chipreset/resetchip.html

    – tlfong01 Jun 06 '19 at 11:43
  • Why can't you just run the C++ code that you have? I'm unclear what obstacle you have to just compiling it and using it as-is. – Brick Jun 06 '19 at 13:48
  • @Brick The program was built for a computer with serial port. Mine does not have, thus I can't just use it as is. In the pi I must use the GPIO for that purpose, so the code must be modified. Am I correct? – dblokillo Jun 06 '19 at 13:51
  • Your Pi does have serial, it's just exposed on the GPIO header pins. (That's not really the same as to "use the GPIO", which maybe is a critical mistake that you're making?) Your code looks to me, without going deep, like it only uses one port, the one assigned to LPT. Figure out the port address and assign it to LPT and give it a whirl? Serial (aka UART) is an alternate function available on some pins on the header. See also Milliways answer at https://raspberrypi.stackexchange.com/questions/96697/how-many-serial-ports-are-on-the-pi-3 – Brick Jun 06 '19 at 14:03

1 Answers1

2

Question

Convert linux C++ printer program to Rpi python

Answer

The slightly tricky part is that Rpi has no write 8 bit port function. So we need to DIY our own virtual 8 bit port by abstracting 8 GPIO pins as one fake 8 bit port. We can then write a fake write fake 8 bit port function, ...

References

Centronics/Parallel Port Printer Cable - Wikipedia

centronics printer cable

Rpi GPIO Pinout rpi pinout

Serial to Parallel Printer Interface - Dan JulioDan Julio

What is outb() function call in Linux?

System calls are described in section 2 of the man pages: man 2 outb

void outb(unsigned char value, unsigned short int port);

Description

This family of functions is used to do low-level port input and output. The out* functions do port output, the in* functions do port input; the b-suffix functions are byte-width and the w-suffix functions word-width; the _p-suffix functions pause until the I/O completes.

Espon InkJet Chips

epson inkjet chips

YouTube Video of gpioPinTest program (See Appendix E)

gpioPinlist picture

Appendices

Appendix A - First Draft of Suggested Python Program

First draft

Printer Test Program Version Buggy b0.1 tlfong01 2019jun05hkt1130

# *** Import ***

import Rpi.GPIO
from time import sleep

# *** Constants and Variblles Declaration and Initialization ***

controlPort = 0x378
dataPort    = 0x379

resetByte = 0x00
synMask   = 0x01  # bit 0 (0b00000001) = clock/sync/control pulse signal
pwrMsk    = 0xe0  # bit 6 (0b01000000) = power on/off signal

# *** System control functions ***

def delay500uS(): # sleep 500uS
    ...
    return

def synUp(): # set clock pulse High
    ...
    return

def synDown(): # set clock pulse Low
    ...
    return

def sendOneDownGoingClockPulse():
    synDown()
    delay500uS()
    synUp()
    delay500uS()
    return

# *** Higher Level Write Virtual Port (abstracting 8 GPIO output ports to one 8 bit Arduino like output port) ***

def writePort(dataByte, controlPort):
    synDown()
    # set High or Low according to dataByte GPIO output pins 13, 14, 15, 16, 17, 18, 19 (arbitrary assigned)
    synUp()
    return

def resetPrinter():
    dataByte = resetByte
    writePort(dataByte, controlPort)
    return

def powerOnPrinter():
    dataByte = pwrMask
    writePort(dataByte, controlPort)
    return

def printChar(dataByte):
    writePort(dataByte, dataPort)
    return   

# *** Main program to print just one character to printer ***

powerOnPrinter()
resetPrinter()
dataByte = 'A'
printChar(dataByte)

# *** End of Program ***

Appendix B - Printer Test Program Buggy Version 0.2

# parallel_printer_test_02 tlfong01 2019jun05hkt1448 ***
# Rpi3B+ stretch 2019apr08, IDLE python 3.5.3 

# *** Import ***

import Rpi.GPIO as GPIO
from time import sleep

# *****************************************************************************
# *** GPIO Functions ***
# *****************************************************************************

# *** GPIO General Setup/Cleanup Functions ***

def generalSetupGPIO():
    GPIO.setwarnings(False) 
    GPIO.setmode(GPIO.BCM)
    return

def generalCleanupGpio(): 
    GPIO.cleanup()
    return

# *** GPIO Pin Setup Putput Mode ***

def setupGpioPinOutputMode(gpioPin):
    GPIO.setup(gpioPin, GPIO.OUT)
    return

# *** GPIO Pin Set High or Low ***

def setGpioPinHigh(gpioPin):  
    GPIO.output(gpioPin, GPIO.HIGH)
    return

def setGpioPinLow(gpioPin): 
    GPIO.output(gpioPin, GPIO.LOW)
    return

# *** Init GPIO Pin Output Mode And Set Low ***

def intiGpioPinOutputModeSetLow(gpioPin):
    setGpioPinOutputMode(gpioPin)
    setGpioPinLow(gpioPin)
    return

# *** Init GPIO Pin List Output Mode And Set Low  ***

def intiGpioPinListOutputModeSetLow(gpioPinList):
    for gpioPin in gpioPinList:
       initGpioPinOutputModeSetLow(gpioPin)
    return

# *** Toggle GPIO Pin Functions ***

def toggleGpioPin(gpioPin, highSeconds, lowSeconds, toggleCount): 
    for i in range(toggleCount):
        setgpioPinHigh(gpioPin)
        sleep(highSeconds)
        setGpioPinLow(gpioPin)
        sleep.(lowSeconds)
    return

def toggleGpioPinList(gpioPinList, highSeconds, lowSeconds, toggleCount):
    for gpioP in gpioPinList:
        togglegpioPin(gpioPin, highSeconds, lowSeconds, toggleCount)
    fprint.printEndExecution(9, 27)    
    return


# *****************************************************************************
# *** Parallel Printer Configuration ***
# *****************************************************************************

controlPortPinList = [17, 18, 27, 22, 23, 24, 25,  4]
dataPortPinList    = [ 5,  6, 13, 19, 26, 16, 20, 21]

resetByte          = 0x00
clockBitHighByte   = 0x01  
clockBitLowByte    = 0x00 
powerOnByte        = 0xe0
powerOffByte       = 0x00  

# *****************************************************************************
# *** Parallel Printer Functions ***
# *****************************************************************************

def initParallelPort(gpioPinList):
    intiGpioPinListOutputModeSetLow(gpioPinList)
    return

def writeParallelPort(dataByte, gpioPinList):
    for bitCount in range(7):
        bitValue = dataByte >> bitCount
        gpioPin  = gpioPinList[bitCount]
    if bitValue == 1:
        setGpioPinHigh(gpioPin)
    elseif
        setGpioPinLow(gpioPin)
    sendControlPulse()
    return

def delay500uS(): 
    sleep(0.005)
    return

def sendControlPulse():
    writeParallelPort(clockBitLowByte, controlPortPinList)
    delay500uS()
    writeParallelPort(clockBitHighByte, controlPortPinList)
    delay500uS()
    return

def resetPrinter():
    writeParallelPort(resetByte, controlPortPinList)
    return

def powerOnPrinter():
    writeParallelPort(dataByte, controlPortPinList)
    return

def printChar(dataByte):
    writeParallelPort(dataByte, dataPortPinList)
    return  

def initPrinter():
    initParallelPort(controlPortPinList)
    initParallelPort(dataPortPinList)
    powerOnPrinter()
    resetPrinter()
    return

def printChar(dataByte):
    writeParallelPort(dataByte, dataPortPinList) 
    return

def testPrinter():
    initPrinter():
    printChar('A')
    return

# *** Main ***

testPrinter()

# *** End of Program ***

Appendix C - Printer Test Program version 0.3 tlfong01 2019jun06hkt1341

# parallel_printer_test_05 tlfong01 2019jun06hkt1148 ***
# Rpi3B+ stretch 2019apr08, python 3.5.3 

# *** Import ***

import RPi.GPIO as GPIO
from time import sleep

# *****************************************************************************
# *** GPIO Functions ***
# *****************************************************************************

# *** GPIO General Setup/Cleanup ***

def gpioGeneralSetup():
    GPIO.setwarnings(False) 
    GPIO.setmode(GPIO.BCM)
    return

def gpioGeneralCleanup(): 
    GPIO.cleanup()
    return

# *** GPIO Pin Setup Output Mode ***

def setGpioPinOutputMode(gpioPin):
    GPIO.setup(gpioPin, GPIO.OUT)
    return

# *** GPIO Pin Set High or Low ***

def setGpioPinHigh(gpioPin):  
    GPIO.output(gpioPin, GPIO.HIGH)
    return

def setGpioPinLow(gpioPin): 
    GPIO.output(gpioPin, GPIO.LOW)
    return

# *** Init GPIO Pin Output Mode And Set Low ***

def initGpioPinOutputModeSetLow(gpioPin):
    setGpioPinOutputMode(gpioPin)
    setGpioPinLow(gpioPin)
    return

# *** Init GPIO Pin List Output Mode And Set Low  ***

def intiGpioPinListOutputModeSetLow(gpioPinList):
    for gpioPin in gpioPinList:
       initGpioPinOutputModeSetLow(gpioPin)
    return

# *** Toggle GPIO Pin Functions ***

def toggleGpioPin(gpioPin, highSeconds, lowSeconds, toggleCount): 
    for i in range(toggleCount):
        setgpioPinHigh(gpioPin)
        sleep(highSeconds)
        setGpioPinLow(gpioPin)
        sleep(lowSeconds)
    return

def toggleGpioPinList(gpioPinList, highSeconds, lowSeconds, toggleCount):
    for gpioPin in gpioPinList:
        togglegpioPin(gpioPin, highSeconds, lowSeconds, toggleCount)
    return

# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

# *** Above are general GPIO functions, independent of parallel printer app ***

# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

# *** Below are parallel printer specific functions ***

# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

# *****************************************************************************
# *** Parallel Printer Configuration ***
# *****************************************************************************

controlPortPinList = [17, 18, 27, 22, 23, 24, 25,  4]
dataPortPinList    = [ 5,  6, 13, 19, 26, 16, 20, 21]

resetByte          = 0x00
clockBitHighByte   = 0x01  
clockBitLowByte    = 0x00 
powerOnByte        = 0xe0
powerOffByte       = 0x00  

# *****************************************************************************
# *** Parallel Printer Functions ***
# *****************************************************************************

def initParallelPort(gpioPinList):
    intiGpioPinListOutputModeSetLow(gpioPinList)
    return

def writeParallelPort(gpioPinList, dataByte):
    pinNum = 0
    for gpioPin in gpioPinList:
        logicLevel = dataByte & (0x01 << pinNum)
        if logicLevel == 0:
            setGpioPinLow(gpioPin)
        else:
            setGpioPinHigh(gpioPin)
        #sendControlPulse()
        pinNum = pinNum + 1
    return

def controlPulseDelay(): 
    controlPulsePeriod = 0.005
    sleep(controlPulsePeriod)
    return

def sendControlPulse():
    writeParallelPort(controlPortPinList, clockBitHighByte)
    controlPulseDelay()
    writeParallelPort(controlPortPinList, clockBitLowByte)
    controlPulseDelay()
    return

def resetPrinter():
    writeParallelPort(controlPortPinList, resetByte)
    return

def powerOnPrinter():
    writeParallelPort(controlPortPinList, powerOnByte)
    return

def printChar(dataByte):
    writeParallelPort(dataPortPinList, dataByte)
    return  

def initPrinter():
    initParallelPort(controlPortPinList)
    initParallelPort(dataPortPinList)
    powerOnPrinter()
    resetPrinter()
    return

def printDataByte(char):
    dataByte = ord(char)
    writeParallelPort(dataPortPinList, dataByte) 
    return

def testPrinter():
    print('Begin testPrinter(), ...')
    initPrinter()
    printDataByte('A')
    print('End   testPrinter().')
    return

# *** Setup ***

gpioGeneralSetup()

# *** Main ***

testPrinter()

# *** Cleanup ***

gpioGeneralCleanup()


'''
Sample output - 2019jun06hkt1325
>>> 
= RESTART: /home/pi/Python Programs/test1202/printer_test_03_2019jun0601.py =
Begin testPrinter(), ...
End   testPrinter().
>>> 
...

# *** End of Program ***

Appendix D - GpioPinListTestProgram Listing

I started the parallel printer program writing using the “Structured P{rogramming" and "Top Down Design, Bottom Up Implementation" Approach. I design the program into two parts the "Gpio” part, and the “Parallel Port“。 Now I have started implementation, so I focused on the GPIO part, using the following step:

(1) Single GPIO pin,

(2) Eight GPIO pin list (equivalent of a parallel port (control and data)

(3) Writing to GPIO pin list (or parallel port)

The following program can now blink a pin, sequentially blink a pin in a ponList.

(4) Parallel blink a pinList

# gpiopinlist_test_07 tlfong01 2019jun07hkt1631 ***
# Rpi3B+ stretch 2019apr08, python 3.5.3 

# *** Import ***

import RPi.GPIO as GPIO
from time import sleep

# *** GPIO Functions ***

# *** GPIO General Setup/Cleanup ***

def gpioGeneralSetup():
    GPIO.setwarnings(False) 
    GPIO.setmode(GPIO.BCM)
    return

def gpioGeneralCleanup(): 
    GPIO.cleanup()
    return

# *** GPIO Pin Setup Output Mode ***

def setGpioPinOutputMode(gpioPin):
    GPIO.setup(gpioPin, GPIO.OUT)
    return

# *** GPIO Pin Set High or Low ***

def setGpioPinHigh(gpioPin):  
    GPIO.output(gpioPin, GPIO.HIGH)
    return

def setGpioPinLow(gpioPin): 
    GPIO.output(gpioPin, GPIO.LOW)
    return

# *** Init GPIO Pin Output Mode And Set Low ***

def initGpioPinOutputModeSetLow(gpioPin):
    setGpioPinOutputMode(gpioPin)
    setGpioPinLow(gpioPin)
    return

# *** Init GPIO Pin List Output Mode And Set Low  ***

def intiGpioPinListOutputModeSetLow(gpioPinList):
    for gpioPin in gpioPinList:
       initGpioPinOutputModeSetLow(gpioPin)
    return

# *** Toggle GPIO Pin Functions ***

def toggleGpioPin(gpioPin, highSeconds, lowSeconds, toggleCount): 
    for i in range(toggleCount):
        setGpioPinHigh(gpioPin)
        sleep(highSeconds)
        setGpioPinLow(gpioPin)
        sleep(lowSeconds)
    return

def sequentialToggleGpioPinList(gpioPinList, highSeconds, lowSeconds, toggleCount):
    for gpioPin in gpioPinList:
        toggleGpioPin(gpioPin, highSeconds, lowSeconds, toggleCount)
    return

# *** Gpio Pin List Functions *** 

def initGpioPinList(gpioPinList):
    intiGpioPinListOutputModeSetLow(gpioPinList)
    return

def initTwoGpioPinLists():
    initGpioPinList(gpioPinList = gpioPinList0)
    initGpioPinList(gpioPinList = gpioPinList1)
    return

def writeGpioPinList(gpioPinList, dataByte):
    pinNum = 0
    for gpioPin in gpioPinList:
        logicLevel = dataByte & (0x01 << pinNum)
        if logicLevel == 0:
            setGpioPinLow(gpioPin)
        else:
            setGpioPinHigh(gpioPin)
        pinNum = pinNum + 1
    return

def parallelToggleGpioPinList(gpioPinList, dataByte0, dataByte1, dataByteSeconds0, dataByteSeconds1, toggleCount):
    for count in range(toggleCount):
        writeGpioPinList(gpioPinList, dataByte0)
        sleep(dataByteSeconds0)
        writeGpioPinList(gpioPinList, dataByte1)
        sleep(dataByteSeconds1)       
    return

# *** Test Functions ***

def toggleGpioPin17():
    toggleGpioPin(gpioPin = 17, highSeconds = 0.5, lowSeconds = 0.5, toggleCount = 8)
    return

def sequentialToggleGpioPinList0():
    sequentialToggleGpioPinList(gpioPinList = gpioPinList0, highSeconds = 0.5, lowSeconds = 0.5, \
                      toggleCount = 2)
    return

def parallelToggleGpioPinList0():
    parallelToggleGpioPinList(gpioPinList = gpioPinList0, \
                       dataByte0 = 0x55, dataByteSeconds0 = 0.5, \
                       dataByte1 = 0xaa, dataByteSeconds1 = 0.5, \
                       toggleCount = 4)
    return

# gpioPnList Config ***

gpioPinList0 = [17, 18, 27, 22, 23, 24, 25,  4]
gpioPinList1 = [ 5,  6, 13, 19, 26, 16, 20, 21]

# *** Main Test ***

def test0():

    print('Begin test0(), ...')

    initTwoGpioPinLists()

    toggleGpioPin17()

    sequentialToggleGpioPinList0()

    parallelToggleGpioPinList0()   

    print('End   test0().')

    return

# *** Setup ***

gpioGeneralSetup()

# *** Main ***

test0()

# *** Cleanup ***

gpioGeneralCleanup()


# *** Sample output ***
'''
>>> 
RESTART: /home/pi/Python Programs/test1202/gpio_pin_list_test_06_2019jun0701.py 
Begin test0(), ...
End   test0().
>>> 
'''
#*** End of Program ***

Appendix E - YouTube Video of Appendix D gpioPinTest program

def test0():

    print('Begin test0(), ...')

    initTwoGpioPinLists()

    toggleGpioPin17()

    sequentialToggleGpioPinList0()

    parallelToggleGpioPinList0()   

    print('End   test0().')

    return
tlfong01
  • 4,665
  • 3
  • 10
  • 24
  • Thanks for the reply! I kind of get the main point of it, tho I don't understand how is the writePort function able to write into the chip. Also, Is the output going to be the same on all 8 ports, or it's just virtually 8 but physically 1? – dblokillo Jun 05 '19 at 04:34
  • Well, tell me the printer model number, or chip IC number, then I can make more informed guesses. I can draft the write port function later. – tlfong01 Jun 05 '19 at 04:45
  • So I have scribbled the second draft (Appendix B). It is "a bit" buggy. You might like to debug it for me. :) Please feel free to ask me any question about my buggy program. Take your time. Go slowly. I guess it might take you another couple of weeks to digest everything. So see you July. :) – tlfong01 Jun 05 '19 at 07:11
  • Thanks @tlfong01, I will take a look at them and test them if possible, and let you know how it goes. – dblokillo Jun 06 '19 at 10:45
  • As I said, no hurry at all. You need to go very slowly, otherwise you won't appreciate how others code. You can try code your own, and come back from time to time to see how I code, to compare and contrast. – tlfong01 Jun 06 '19 at 11:37
  • And if your going to do some GPIO program writing, you might like to read my Appendix D, E. which blinks controlPort like this: https://youtu.be/FOcLfRqV6nE – tlfong01 Jun 07 '19 at 14:10