Import LinuxCNC source tree
This commit is contained in:
156
lib/python/raster.py
Normal file
156
lib/python/raster.py
Normal file
@@ -0,0 +1,156 @@
|
||||
"""
|
||||
The raster module is useful for controlling the raster realtime component.
|
||||
"""
|
||||
from re import match
|
||||
from enum import Enum
|
||||
import hal
|
||||
from struct import *
|
||||
import time
|
||||
|
||||
class ProgrammerException(Exception):
|
||||
"""exception type raised by the raster programmer"""
|
||||
pass
|
||||
|
||||
class FaultCodes(Enum):
|
||||
OK = 0
|
||||
InvalidOffset = 1
|
||||
InvalidBPP = 2
|
||||
InvalidPPU = 3
|
||||
InvalidCount = 4
|
||||
BadPixelData = 5
|
||||
ProgramWrongSize = 6
|
||||
WrongDirection = 7
|
||||
|
||||
"""the fault code representing no error from raster"""
|
||||
|
||||
|
||||
class RasterProgrammer(object):
|
||||
"""
|
||||
The programmer component is used to program the realtime raster component
|
||||
|
||||
The raster component operates one line at a time.
|
||||
|
||||
Example:
|
||||
Assuming rastering is done across the X axis.
|
||||
A simple raster program would be from X=0.0 Power=0.0 to X=1.0 Power=100.0
|
||||
As the x axis passes from x0.0 to x1.0 the power will rise from 0 to 100 linearly.
|
||||
|
||||
Because positional data at the hal level is joint position the program must be relative
|
||||
to the current position that the machine is at when programming the line.
|
||||
|
||||
Because a port can become full each command waits until the port is available for writing. The commands will
|
||||
raise a ProgrammerException if too much time passes before the write completes. This is usually an indication
|
||||
that your PORT buffer isn't large enough
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
"""
|
||||
Initializes a user space component with name.
|
||||
|
||||
This component exports pins:
|
||||
program - PORT OUT - link to the raster's program port pin. Make sure to size the PORT signal prior to running.
|
||||
fault-code - UNSIGNED IN - link to the raster's fault-code pin. Raster programmer uses this to detect errors
|
||||
enabled - BIT IN - link to the raster's enabled pin. Raster programmer uses this to wait on rasters activation
|
||||
"""
|
||||
self.__timeout = 5.0
|
||||
self.component = hal.component(name)
|
||||
self.port = self.component.newpin("program", hal.HAL_PORT, hal.HAL_OUT)
|
||||
self.faultCode = self.component.newpin("fault-code", hal.HAL_S32, hal.HAL_IN)
|
||||
self.enabled = self.component.newpin("enabled", hal.HAL_BIT, hal.HAL_IN)
|
||||
self.run = self.component.newpin("run", hal.HAL_BIT, hal.HAL_OUT)
|
||||
self.component.ready()
|
||||
self.run.value = False
|
||||
|
||||
def __del__(self):
|
||||
if None != self.component:
|
||||
self.component.exit()
|
||||
|
||||
def exit(self):
|
||||
"""unloads this programmer component from hal"""
|
||||
self.component.exit()
|
||||
self.component = None
|
||||
|
||||
def __waitEnabled(self, enabled):
|
||||
timeout = time.process_time() + self.__timeout
|
||||
while self.enabled.value != enabled:
|
||||
time.sleep(0.001)
|
||||
if time.process_time() > timeout:
|
||||
self.run.value = False
|
||||
raise ProgrammerException("Raster failed to respond before the timeout was reached")
|
||||
|
||||
if self.faultCode.value != FaultCodes.OK.value:
|
||||
self.run.value = False
|
||||
raise ProgrammerException("Raster faulted with error {0}".format(FaultCodes(self.faultCode.value)))
|
||||
|
||||
def begin(self, offset, bpp, ppu, count):
|
||||
"""
|
||||
Sends the program begin command along with relevant parameters.
|
||||
|
||||
offset - The relative starting position that the incoming data starts. Data is always programmed from most negative on the axis to most positive.
|
||||
bpp - Bits per pixel in increments of 4 bits, up to 32 bits
|
||||
ppu - pixels per unit. The number of pixels per machine unit. count * dpu gives the total span of the raster line
|
||||
count - the number of pixels that will be programmed on the line
|
||||
"""
|
||||
self.run.value = False
|
||||
self.__waitEnabled(False)
|
||||
|
||||
allowedbpp = set([4, 8, 12, 16, 20, 24, 28, 32])
|
||||
if not isinstance(bpp, int):
|
||||
raise ProgrammerException("bpp must be an integer")
|
||||
|
||||
if not bpp in allowedbpp:
|
||||
raise ProgrammerException("bpp must be one of {0}. Given: {1}".format(allowedbpp, bpp))
|
||||
|
||||
if ppu <= 0.0:
|
||||
raise ProgrammerException("dpu must be greater than 0. Given: {0}".format(dpu))
|
||||
|
||||
if not isinstance(count, int):
|
||||
raise ProgrammerException("count must be an integer")
|
||||
|
||||
if count <= 0.0:
|
||||
raise ProgrammerException("count must be greater than 0. Given: {0}".format(count))
|
||||
|
||||
self.bpp = bpp
|
||||
self.ppu = ppu
|
||||
self.countBytes = count * (bpp / 4)
|
||||
if not self.port.write("{0:f};{1};{2:.5f};{3};".format(offset, bpp, ppu, count)):
|
||||
raise ProgrammerException("raster port appears to be full. Try enlarging the port buffer size")
|
||||
|
||||
|
||||
def data(self, data):
|
||||
"""
|
||||
Sends raster data to the raster component. data is a string of hexadecimal characters
|
||||
"""
|
||||
|
||||
self.__waitEnabled(False)
|
||||
|
||||
pixelLen = self.bpp / 4
|
||||
|
||||
if (len(data) % pixelLen) != 0:
|
||||
raise ProgrammerException("Improper data format.")
|
||||
|
||||
if not match("[a-fA-F0-9]+", data):
|
||||
raise ProgrammerException("Data must be in hexadecimal format A-F,a-f,0-9")
|
||||
|
||||
if not self.port.write(data):
|
||||
raise ProgrammerException("raster port appears to be full. Try enlarging the port buffer size")
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Commands the raster to begin running the program
|
||||
Waits until the raster is enabled and running
|
||||
"""
|
||||
if self.enabled.value:
|
||||
self.enabled.value = False
|
||||
raise ProgrammerException("Raster cannot start. It is already running.")
|
||||
|
||||
self.run.value = True
|
||||
self.__waitEnabled(True)
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Commands the raster to stop running the program
|
||||
Waits until the raster is disabled
|
||||
"""
|
||||
self.run.value = False
|
||||
self.__waitEnabled(False)
|
||||
Reference in New Issue
Block a user