From db04ba167d5b83990418a9658ff82d50dc63eaf3 Mon Sep 17 00:00:00 2001 From: Alan Aguiar Date: Sun, 03 Mar 2013 19:58:37 +0000 Subject: same changes that in gtk2 version: replace bobot by pybot --- diff --git a/activity.py b/activity.py index 6a86d3a..aa78433 100755 --- a/activity.py +++ b/activity.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # FollowMe Butia -# Copyright (C) 2010, 2011, 2012 +# Copyright (C) 2010-2013 # This program was created to use with the robot Butia. # Butia is a project from Facultad de Ingenieria - Uruguay # Facultad de Ingenieria web site: @@ -27,8 +27,6 @@ # Rodrigo Dearmas -import sys -sys.path.insert(0, "lib") import gi from gi.repository import Gtk from sugar3.activity import activity diff --git a/butiaAPI.py b/butiaAPI.py deleted file mode 100755 index 4bb6ca3..0000000 --- a/butiaAPI.py +++ /dev/null @@ -1,326 +0,0 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- -# -# ButiaAPI -# Copyright (c) 2009, 2010, 2011, 2012 Butiá Team butia@fing.edu.uy -# Butia is a free open plataform for robotics projects -# www.fing.edu.uy/inco/proyectos/butia -# Facultad de Ingenieria - Universidad de la República - Uruguay -# -# Implements abstractions for the comunications with the bobot-server -# -# 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 of the License, 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 -# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -import socket -import string -import math -import threading - -ERROR_SENSOR_READ = -1 - -BUTIA_1 = 20 - -BOBOT_HOST = 'localhost' -BOBOT_PORT = 2009 - -class robot: - - - def __init__(self, host = BOBOT_HOST, port = BOBOT_PORT): - """ - init the robot class - """ - self.lock = threading.Lock() - self.host = host - self.port = port - self.client = None - self.fclient = None - self.ver = BUTIA_1 - self.reconnect() - self.getVersion() - - - def doCommand(self, msg): - """ - Executes a command in butia. - @param msg message to be executed - """ - msg = msg +'\n' - ret = ERROR_SENSOR_READ - self.lock.acquire() - try: - self.client.send(msg) - ret = self.fclient.readline() - ret = ret[:-1] - except: - ret = ERROR_SENSOR_READ # Doesn't return here to release the lock - self.lock.release() - - if ((ret == 'nil value') or (ret == None) or (ret == 'fail') or (ret == 'missing driver')): - ret = ERROR_SENSOR_READ - return ret - - # connect o reconnect the bobot - def reconnect(self): - self.close() - try: - self.client = socket.socket() - self.client.connect((self.host, self.port)) - self.fclient = self.client.makefile() - msg = 'INIT' - #bobot server instance is running, but we have to check for new or remove hardware - self.doCommand(msg) - except: - return ERROR_SENSOR_READ - return 0 - - # ask bobot for refresh is state of devices connected - def refresh(self): - if (self.ver == BUTIA_1) or (self.ver == ERROR_SENSOR_READ): - msg = 'INIT' - else: - msg = 'REFRESH' - return self.doCommand(msg) - - # close the comunication with the bobot - def close(self): - try: - if self.fclient != None: - self.fclient.close() - self.fclient = None - if self.client != None: - self.client.close() - self.client = None - except: - return ERROR_SENSOR_READ - return 0 - - ####################################################################### - ### Operations to the principal module - ####################################################################### - - - # call the module 'modulename' - def callModule(self, modulename, function , params = ''): - msg = 'CALL ' + modulename + ' ' + function - if params != '' : - msg += ' ' + params - ret = self.doCommand(msg) - try: - ret = int(ret) - except: - ret = ERROR_SENSOR_READ - return ret - - # Close bobot service - def closeService(self): - msg = 'QUIT' - return self.doCommand(msg) - - ####################################################################### - ### Useful functions - ####################################################################### - - # returns if the module_name is present - def isPresent(self, module_name): - module_list = self.get_modules_list() - return (module_name in module_list) - - # returns a list of modules - def get_modules_list(self): - msg = 'LIST' - l = [] - ret = self.doCommand(msg) - if not (ret == '' or ret == ERROR_SENSOR_READ): - l = ret.split(',') - return l - - # loopBack: send a message to butia and wait to recibe the same - def loopBack(self, data): - msg = 'lback send ' + data - ret = self.doCommand(msg) - if ret != -1 : - msg = 'CALL lback read' - return self.doCommand(msg) - else: - return ERROR_SENSOR_READ - - - ####################################################################### - ### Operations for motores.lua driver - ####################################################################### - - def set2MotorSpeed(self, leftSense = '0', leftSpeed = '0', rightSense = '0', rightSpeed = '0'): - msg = leftSense + ' ' + leftSpeed + ' ' + rightSense + ' ' + rightSpeed - if self.ver == BUTIA_1: - return self.callModule('motores', 'setvel2mtr', msg) - else: - return self.callModule('motors', 'setvel2mtr', msg) - - def setMotorSpeed(self, idMotor = '0', sense = '0', speed = '0'): - msg = idMotor + ' ' + sense + ' ' + speed - if self.ver == BUTIA_1: - return self.callModule('motores', 'setvelmtr', msg) - else: - return self.callModule('motors', 'setvelmtr', msg) - - ####################################################################### - ### Operations for ax.lua driver - ####################################################################### - - def wheel_mode(self, idMotor = '0'): - msg = idMotor - if self.ver == BUTIA_1: - return self.callModule('ax', 'wheel_mode', msg) ##TODO implement - else: - return self.callModule('ax', 'wheel_mode', msg) - - def joint_mode(self, idMotor = '0', min = '0', max = '1023'): - msg = idMotor + ' ' + min + ' ' + max - if self.ver == BUTIA_1: - return self.callModule('ax', 'joint_mode', msg) ##TODO implement - else: - return self.callModule('ax', 'joint_mode', msg) - - def set_speed(self, idMotor = '0', speed = '0'): - msg = idMotor + ' ' + speed - if self.ver == BUTIA_1: - return self.callModule('ax', 'set_speed', msg) ##TODO implement - else: - return self.callModule('ax', 'set_speed', msg) - - def set_position(self, idMotor = '0', pos = '0'): - msg = idMotor + ' ' + pos - if self.ver == BUTIA_1: - return self.callModule('ax', 'set_position', msg) ##TODO implement - else: - return self.callModule('ax', 'set_position', msg) - - def get_position(self, idMotor = '0'): - msg = idMotor - if self.ver == BUTIA_1: - return self.callModule('ax', 'get_position', msg) ##TODO implement - else: - return self.callModule('ax', 'get_position', msg) - - - - ####################################################################### - ### Operations for butia.lua driver - ####################################################################### - - def ping(self): - return self.callModule('placa', 'ping') - - # returns the approximate charge of the battery - def getBatteryCharge(self): - return self.callModule('butia', 'get_volt') - - # returns the firmware version - def getVersion(self): - ver = self.callModule('butia', 'read_ver') - if not(ver == ERROR_SENSOR_READ): - self.ver = ver - return ver - - # set de motor idMotor on determinate angle - def setPosition(self, idMotor = 0, angle = 0): - msg = str(idMotor) + ' ' + str(angle) - return self.callModule('placa', 'setPosicion' , msg ) - - # return the value of button: 1 if pressed, 0 otherwise - def getButton(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('boton' + str(number), 'getValue') - else: - return self.callModule('button:' + str(number), 'getValue') - - # return the value en ambient light sensor - def getAmbientLight(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('luz' + str(number), 'getValue') - else: - return self.callModule('light:' + str(number), 'getValue') - - # return the value of the distance sensor - def getDistance(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('dist' + str(number), 'getValue') - else: - return self.callModule('distanc:' + str(number), 'getValue') - - # return the value of the grayscale sensor - def getGrayScale(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('grises' + str(number), 'getValue') - else: - return self.callModule('grey:' + str(number), 'getValue') - - # return the value of the temperature sensor - def getTemperature(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('temp' + str(number), 'getValue') - else: - return self.callModule('temp:' + str(number), 'getValue') - - # return the value of the vibration sensor - def getVibration(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('vibra' + str(number), 'getValue') - else: - return self.callModule('vibra:' + str(number), 'getValue') - - # return the value of the resistance sensor - def getResistance(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('resist' + str(number), 'getValue') #TODO implement - else: - return self.callModule('resist:' + str(number), 'getValue') - - # return the value of the tilt sensor - def getTilt(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('tilt' + str(number), 'getValue') - else: - return self.callModule('tilt:' + str(number), 'getValue') - - # FIXME: the name of the module and the function... - # return the value of the capacitive touch sensor - def getCapacitive(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('capacitive' + str(number), 'getValue') - else: - return self.callModule('capacitive:' + str(number), 'getValue') - - # return the value of the magnetic induction sensor - def getMagneticInduction(self, number=''): - if self.ver == BUTIA_1: - return self.callModule('magnet' + self.aux + str(number), 'getValue') - else: - return self.callModule('magnet:' + self.aux + str(number), 'getValue') - - # set the led intensity - def setLed(self, nivel = 255, number= ''): - if self.ver == BUTIA_1: - return self.callModule('led' + self.aux + str(number), 'setLight', str(math.trunc(nivel))) - else: - return self.callModule('led:' + self.aux + str(number), 'setLight', str(math.trunc(nivel))) - - # FIXME: check the lenght of text? - # write a text in LCD display - def writeLCD(self, text): - text = str(text) - text = text.replace(' ', '_') - self.callModule('display', 'escribir' , text) - diff --git a/followme.py b/followme.py index 522d624..745e2af 100755 --- a/followme.py +++ b/followme.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # FollowMe Butia - FollowMe -# Copyright (C) 2010, 2011, 2012 +# Copyright (C) 2010-2013 # This program was created to use with the robot Butia. # Butia is a project from Facultad de Ingenieria - Uruguay # Facultad de Ingenieria web site: diff --git a/lib/support/bobot-server.lua b/lib/support/bobot-server.lua deleted file mode 100644 index fcaa55b..0000000 --- a/lib/support/bobot-server.lua +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/lua - ---[[ - -Syntax - - # lua bobot-server.lua [DEBUG] [connection]* - -Parameters: - DEBUG enables debug printing in bobot - connection a list of connection services to attempt. Supported - values in bobot (for now) are usb, serial and chotox - -If no connection services are provided, defaults to usb and serial. - -Examples: - Start with debug disabled and the dummy chotox service, only: - # lua bobot-server.lua chotox - - Start with debug enabled and the serial services only: - # lua bobot-server.lua DEBUG serial - - Start with debug disabled and the usb and serial services (same as default): - # lua bobot-server.lua usb serial - ---]] - ---package.path=package.path..";./bobot_server/?.lua" -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] or "./" -package.path=package.path..";"..my_path.."bobot_server/?.lua;" - ..my_path.."lib/?.lua;"..my_path.."?.lua" - ---tcp listening address -local N_PROTOCOLS = 2 -local ADDRESS = "*" -local PORT_B = 2009 --B is for bobot -local PORT_H = 2010 --H is for http - -local TIMEOUT_REFRESH = 3 - -local socket = require("socket") -local process = require("bobot-server-process").process -local http_serve = require("bobot-server-http").serve - -local bobot = require("bobot") - -local set_debug -for i, v in ipairs(arg) do - if v=="DEBUG" then - set_debug=true - table.remove(arg, i) - break - end -end -if set_debug then - bobot.debugprint = print - bobot.debugprint("Debugging messages enabled") -else - bobot.debugprint = function() end -end - - -local server_b = assert(socket.bind(ADDRESS, PORT_B)) -local server_h = assert(socket.bind(ADDRESS, PORT_H)) - -local recvt={[1]=server_b, [2]=server_h} - -devices = {} - -local function get_device_name(d) - ---print("DEVICENAME", d.module, d.hotplug, d.handler) - local board_id, port_id = '', '' - if #bobot.baseboards>1 then - board_id='@'..d.baseboard.idBoard - end - if d.hotplug then - port_id = ':'..d.handler - end - - local n=d.module..board_id..port_id - - if not devices[n] then - return n - end - - local i=2 - local nn=n.."#"..i - while devices[nn] do - i=i+1 - nn=n.."#"..i - end - - return nn -end - -local function read_devices_list() - bobot.debugprint("=Listing Devices") - local bfound - devices={} - for _, bb in ipairs(bobot.baseboards) do - bobot.debugprint("===board ", bb.idBoard) - for _,d in ipairs(bb.devices) do - local regname = get_device_name(d) - devices[regname]=d - devices[#devices+1]=d - d.name=regname - bobot.debugprint("=====module ",d.module," name",regname) - end - bfound = true - end - if not bfound then bobot.debugprint("ls:WARN: No Baseboard found.") end -end - -local function split_words(s) - local words={} - - for p in string.gmatch(s, "%S+") do - words[#words+1]=p - end - - return words -end - -local socket_handlers = {} -setmetatable(socket_handlers, { __mode = 'k' }) -socket_handlers[server_b]=function() - local client, err=server_b:accept() - if not client then return end - bobot.debugprint ("bs:New bobot client", client, client:getpeername()) - table.insert(recvt,client) - socket_handlers[client] = function () - local line,err = client:receive() - if err=='closed' then - bobot.debugprint ("bs:Closing bobot client", client) - for k, v in ipairs(recvt) do - if client==v then - table.remove(recvt,k) - return - end - end - end - if line then - local words=split_words(line) - local command=words[1] - if not command then - bobot.debugprint("bs:Error parsing line:", line, command) - else - if not process[command] then - bobot.debugprint("bs:Command not supported:", command) - else - if command=="QUIT" and #recvt>N_PROTOCOLS+1 then - client:send("server in use\n") - return - end - local ret = process[command](words) or "" - client:send(ret .. "\n") - end - end - end - end -end - -socket_handlers[server_h]=function() - local client, err=server_h:accept() - if not client then return end - bobot.debugprint ("bs:New http client", client, client:getpeername()) - client:setoption ("tcp-nodelay", true) - --client:settimeout(5) - table.insert(recvt,client) - socket_handlers[client] = function () - local ret,err=http_serve(client) - if err=='closed' then - bobot.debugprint ("bs:Closing http client", client) - for k, v in ipairs(recvt) do - if client==v then - table.remove(recvt,k) - return - end - end - end - if ret then - client:send(ret) - end - end -end - -function server_refresh () - local refreshed - for i, bb in ipairs(bobot.baseboards) do - --if bb.refresh and not (bb.comms.type=='serial' and bb.devices) then - if bb.refresh and bb.hotplug then - if not bb:refresh() then - bobot.baseboards[i]=nil - end - refreshed=true - end - end - if refreshed then read_devices_list() end -end - -function server_init () - bobot.init(arg) - read_devices_list() -end - - -server_init() -bobot.debugprint("Listening...") --- loop forever waiting for clients - -while 1 do - local recvt_ready, _, err=socket.select(recvt, nil, TIMEOUT_REFRESH) - if err=='timeout' then - if #bobot.baseboards==0 then - server_init () - else - server_refresh () - end - else - local skt=recvt_ready[1] - socket_handlers[skt]() - end -end - - - diff --git a/lib/support/bobot.lua b/lib/support/bobot.lua deleted file mode 100644 index c7dd062..0000000 --- a/lib/support/bobot.lua +++ /dev/null @@ -1,55 +0,0 @@ ---[[ -bobot library - -Example usage: - bobot=require("bobot") - bobot.init() - -init() can receive a list of connectors to use. Supported values are "usb", "serial" and "chotox". -For example, to only use de dummy chotox driver, use init({"chotox"}) -If no parameter is provided, behaves like init({"usb","serial"}). - ---]] - -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] or "./" -package.path=package.path..";"..my_path.."lib/?.lua" - -local socket=require('socket') - -local B = {} - -B.debugprint = print --function() end --do not print anything by default - ---baseboards[iSerial] = BaseBoard ---B.baseboards = {} - ---Returns number of baseboards detected. -B.init = function ( comms ) - if not comms or #comms==0 then comms = {"usb","serial"} end - - B.baseboards={} --flush the baseboard because this function could be call after hardware remove or adition - - local n_boards, n_boards_total = {}, 0 - local start_time = os.time() - - repeat - for _, comm in ipairs(comms) do - B.debugprint ("Querying for baseboards:", comm) - local comm_lib = require('comms_'..comm) - if not comm_lib then - B.debugprint("Could not open library:", comm) - else - comm_lib.type=comm - n_boards[comm] = comm_lib.init(B.baseboards) - n_boards_total = n_boards_total + n_boards[comm] - end - end - if n_boards_total == 0 then socket.sleep(1) end - until n_boards_total > 0 or os.time()-start_time > 3 - - return n_boards_total -end - ---B.init() - -return B diff --git a/lib/support/bobot_server/bobot-server-http.lua b/lib/support/bobot_server/bobot-server-http.lua deleted file mode 100644 index efa239d..0000000 --- a/lib/support/bobot_server/bobot-server-http.lua +++ /dev/null @@ -1,211 +0,0 @@ -module(..., package.seeall); - -local bobot = require("bobot") - ---local devices=devices -local process = require("bobot-server-process").process -local butia = require("butia/butia_http") -local util = require("http-util") - -local parse_params = util.parse_params -local load_template = util.load_file -local find_page = util.find_page - ---enable to cache in RAM ---[[ -local index_template=load_template('indextemplate.txt') -local dump_template=load_template('dumptemplate.txt') -local dump_template_descr=load_template('dumptemplate_descr.txt') -local dump_template_descr_row=load_template('dumptemplate_descr_row.txt') ---]] - -local function check_open_device(d, ep1, ep2) - if not d then return end - if d.handler then return true end - -- if the device is not open, then open the device - bobot.debugprint ("Opening", d.name, d.handler) - return d:open(ep1 or 1, ep2 or 1) --TODO asignacion de ep? -end - -local html_list_devices = function (params) - local ret,comma = "", "" - local dsel=params['dsel'] - for d_name, d in pairs(devices) do - local broken="" - if not check_open_device(d, ep1, ep2) then - broken=" (failed to open)" - bobot.debugprint ("bs: WARN! Failure opening", d_name) - end - if dsel==d_name then - ret = ret .. comma .. '' .. d_name .. broken .. '' - else - ret = ret .. comma .. ''..d_name..broken..'' - end - comma=", " - end - return ret -end - -local html_describe_device = function (params) - --borrar - dump_template_descr_row=load_template('dumptemplate_descr_row.txt') - - local dsel=params['dsel'] - local command=params['command'] - if not dsel then return "" end - - local device=devices[dsel] - - if not device then return "Missing Device!" end - if not device.api then return "Missing Driver for Device!" end - - local ret = "" - for fname, fdef in pairs(device.api) do - local row=dump_template_descr_row - - local result,ok - --print ("::",command,fname) - if command==fname then - --preparar parametros - local fparams={} - for i,param in ipairs(fdef.parameters) do - local rname=param['rname'] - local rtype=param['rtype'] - if rtype=="int" or rtype=="number" or rtype=="numeric" then - fparams[i]=tonumber(params[rname]) - else - fparams[i]=params[rname] - end - end - - --ejecutar - ok, result= pcall( fdef.call, unpack(fparams) ) - if not ok then bobot.debugprint ("Error calling", ret) end - --imprimir - bobot.debugprint ("::::",result) - end - - local returns='' - local comma='' - for i,rets in ipairs(fdef.returns) do - returns = returns..comma..rets['rtype']..' '..rets['rname'] - comma=',' - end - local formfields='' - local parameters='' - local comma='' - for i,rets in ipairs(fdef.parameters) do - local rname=rets['rname'] - formfields=formfields..rname..':
' - parameters = parameters..comma..rets['rtype']..' '..rname - comma=',' - end - - local rep = { - ['COMMAND'] = fname, - ['RETURNS'] = returns, - ['PARAMETERS'] = parameters, - ['RESULT'] = result, - ['MODULENAME'] = dsel, - ['FORMFIELDS'] = formfields, - } - local generated_row=string.gsub(row, '', rep) - - ret=ret..generated_row - - end - - return ret -end - -local get_page={} -setmetatable(get_page, {__index = function(_,page) bobot.debugprint ("======", page);return find_page(page) end}) -get_page["/index.htm"] = function (p) - local index_template=load_template('indextemplate.txt') - - local params=parse_params(p) - local rep = { - ['DATA1'] = params['campo'], - ['DATA2'] = tostring(params['unboton'])..', '..tostring(params['otroboton']), - } - local page=string.gsub(index_template, '', rep) - return "HTTP/1.1 200/OK\r\nContent-Type:text/html\r\nContent-Length: "..#page.."\r\n\r\n"..page -end -get_page["/"]=get_page["/index.htm"] -get_page["/dump.htm"] = function (p) - --remove this - dump_template=load_template('dumptemplate.txt') - dump_template_descr=load_template('dumptemplate_descr.txt') - - local params=parse_params(p) - local dsel=params['dsel'] - - local usetemplate - if dsel then - usetemplate=dump_template_descr - else - usetemplate=dump_template - end - - local rep = { - ['LIST'] = html_list_devices(params), - ['MODULENAME'] = dsel or "(empty dsel)", - ['ROWS'] = html_describe_device(params), - } - local page=string.gsub(usetemplate, '', rep) - return "HTTP/1.1 200/OK\r\nContent-Type:text/html\r\nContent-Length: "..#page.."\r\n\r\n"..page -end -get_page["/favicon.ico"] = function () - local served, err = io.open('bobot_server/favicon.ico', "rb") - if served ~= nil then - local content = served:read("*all") - return "HTTP/1.1 200/OK\r\nContent-Type:image/x-icon\r\nContent-Length: " - ..#content.."\r\n\r\n" .. content - else - bobot.debugprint("Error opening favicon:", err) - return default_page() - end -end -get_page["/bobot.png"] = function () - local served, err = io.open('bobot_server/bobot.png', "rb") - if served ~= nil then - local content = served:read("*all") - return "HTTP/1.1 200/OK\r\nContent-Type:image/png\r\nContent-Length: " - ..#content.."\r\n\r\n" .. content - else - bobot.debugprint("Error opening logo:", err) - return default_page() - end -end -butia.init(get_page) - -function serve(skt) - local line,err = skt:receive('*l') --read first line, must be GET or POST - if err then return nil, err end - - local f,p=string.match(line, '^GET ([%/%.%d%w%-_]+)[%?]?(.-) HTTP/1.1$') - if f then - repeat - --skip headers we don't care - line,err=skt:receive() - until line=='' or line==nil - if err then return end - local s=get_page[f](p) - return(s..'\r\n') - end - - local f,p=string.match(line, '^POST ([%/%.%d%w%-_]+) HTTP/1.1$') - if f then - local length - repeat - --skip headers we don't care - line,err=skt:receive() - length=length or string.match(line, '^Content%-Length%: (%d+)$') - until line=='' or line==nil - if err then return end - local p=skt:receive(tonumber(length)) - local s=get_page[f](p) - return(s..'\r\n') - end -end - diff --git a/lib/support/bobot_server/bobot-server-process.lua b/lib/support/bobot_server/bobot-server-process.lua deleted file mode 100644 index 18231cb..0000000 --- a/lib/support/bobot_server/bobot-server-process.lua +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/lua - -module(..., package.seeall); - -local bobot = require("bobot") - ---local devices=devices ---local DEBUG = false - -local function check_open_device(d, ep1, ep2) - if not d then return end - if d.handler or d.name=='pnp' then return true end - - -- if the device is not open, then open the device - bobot.debugprint ("Opening", d.name, d.handler) - return d:open(ep1 or 1, ep2 or 1) --TODO asignacion de ep? -end - -process = {} - -process["INIT"] = function () --to check the new state of hardware on the fly - server_init() -end -process["REFRESH"] = function () --to check the new state of hardware on the fly - --for _, bb in ipairs(bobot.baseboards) do - -- bb:refresh() - --end - server_refresh() - return 'ok' -end - - -process["LIST"] = function () - local ret,comma = "", "" - for _, d in ipairs(devices) do - ret = ret .. comma .. d.name - comma="," - end - return ret -end - - -process["LISTI"] = function () - if bobot.baseboards then - bobot.debugprint("listing instanced modules...") - for _, bb in ipairs(bobot.baseboards) do - local handler_size=bb:get_handler_size() - for i=1, handler_size do - t_handler = bb:get_handler_type(i) - bobot.debugprint("handler=", i-1 ," type=" ,t_handler) - end - end - end -end - - -process["OPEN"] = function (parameters) - local d = parameters[2] - local ep1= tonumber(parameters[3]) - local ep2= tonumber(parameters[4]) - - if not d then - bobot.debugprint("ls:Missing 'device' parameter") - return - end - - local device = devices[d] - if check_open_device(device, ep1, ep2) then - return "ok" - else - return "fail" - end -end -process["DESCRIBE"] = function (parameters) - local d = parameters[2] - local ep1= tonumber(parameters[3]) - local ep2= tonumber(parameters[4]) - - if not d then - bobot.debugprint("ls:Missing \"device\" parameter") - return - end - - local device = devices[d] - if not check_open_device(device, ep1, ep2) then - return "fail" - end - if not device.api then - return "missing driver" - end - - local ret = "{" - for fname, fdef in pairs(device.api) do - ret = ret .. fname .. "={" - ret = ret .. " parameters={" - for i,pars in ipairs(fdef.parameters) do - ret = ret .. "[" ..i.."]={" - for k, v in pairs(pars) do - ret = ret .."['".. k .."']='"..tostring(v).."'," - end - ret = ret .. "}," - end - ret = ret .. "}, returns={" - for i,rets in ipairs(fdef.returns) do - ret = ret .. "[" ..i.."]={" - for k, v in pairs(rets) do - ret = ret .."['".. k .."']='"..tostring(v).."'," - end - ret = ret .. "}," - end - ret = ret .. "}}," - end - ret=ret.."}" - - return ret -end -process["CALL"] = function (parameters) - local d = parameters[2] - local call = parameters[3] - - if not (d and call) then - bobot.debugprint("ls:Missing parameters", d, call) - return - end - - local device = devices[d] - if not check_open_device(device, nil, nil) then - return "fail" - end - - if not device.api then return "missing driver" end - local api_call=device.api[call]; - if not api_call then return "missing call" end - - if api_call.call then - --local tini=socket.gettime() - local ok, ret = pcall (api_call.call, unpack(parameters,4)) - if not ok then bobot.debugprint ("Error calling", ret) end - --print ('%%%%%%%%%%%%%%%% bobot-server',socket.gettime()-tini) - return ret - end -end -process["CLOSEALL"] = function () - if bobot.baseboards then - for _, bb in ipairs(bobot.baseboards) do - --this command closes all the open user modules - --it does not have sense with plug and play - bb:force_close_all() --modif andrew - end - end - return "ok" -end -process["BOOTLOADER"] = function () - if bobot.baseboards then - for _, bb in ipairs(bobot.baseboards) do - bb:switch_to_bootloader() - end - end - return "ok" -end -process["DEBUG"] = function (parameters) --disable debug mode Andrew code! - local debug = parameters[2] - if not debug then return "missing parameter" end - if debug=="ON" then - bobot.debugprint = print --function(...) print (...) end --enable printing - elseif debug=="OFF" then - bobot.debugprint = function() end --do not print anything - end - return "ok" -end -process["QUIT"] = function () - bobot.debugprint("Requested EXIT...") - os.exit() - return "ok" -end - diff --git a/lib/support/bobot_server/bobot.png b/lib/support/bobot_server/bobot.png deleted file mode 100644 index 2de1124..0000000 --- a/lib/support/bobot_server/bobot.png +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/butia.htm b/lib/support/bobot_server/butia/butia.htm deleted file mode 100644 index ca86673..0000000 --- a/lib/support/bobot_server/butia/butia.htm +++ /dev/null @@ -1,17 +0,0 @@ - - - Robot Butia - - - - - - - - - - - - - - diff --git a/lib/support/bobot_server/butia/butia_http.lua b/lib/support/bobot_server/butia/butia_http.lua deleted file mode 100644 index 6a0b1ff..0000000 --- a/lib/support/bobot_server/butia/butia_http.lua +++ /dev/null @@ -1,32 +0,0 @@ -module(..., package.seeall); - ---local devices=devices -local process = require("bobot-server-process").process -local util = require("http-util") - -local parse_params = util.parse_params -local load_template = util.load_file - -local butia_template=load_template('butia/butia.htm') or "Error loading template butia.htm" -local header_template=load_template('butia/header.htm') or "Error loading template header.htm" - -function init (get_page) - get_page["/butia.htm"] = function (p) - local params=parse_params(p) - local rep = { - ['DATA1'] = params['campo'], - ['DATA2'] = tostring(params['unboton'])..', '..tostring(params['otroboton']), - } - local page=string.gsub(butia_template, '', rep) - return "HTTP/1.1 200/OK\r\nContent-Type:text/html\r\nContent-Length: "..#page.."\r\n\r\n"..page - end - - get_page["/header.htm"] = function (p) - local params=parse_params(p) - local rep = { - } - local page=string.gsub(header_template, '', rep) - return "HTTP/1.1 200/OK\r\nContent-Type:text/html\r\nContent-Length: "..#page.."\r\n\r\n"..page - end - -end diff --git a/lib/support/bobot_server/butia/command.htm b/lib/support/bobot_server/butia/command.htm deleted file mode 100644 index 9cec722..0000000 --- a/lib/support/bobot_server/butia/command.htm +++ /dev/null @@ -1,36 +0,0 @@ - - - -
-

Haz click en los botones para dirigir el robot

-
-
- - - - -
- - - - - - - - - - - - - - - - -
-
-

- -

- - - diff --git a/lib/support/bobot_server/butia/describeButia.htm b/lib/support/bobot_server/butia/describeButia.htm deleted file mode 100644 index b147468..0000000 --- a/lib/support/bobot_server/butia/describeButia.htm +++ /dev/null @@ -1,88 +0,0 @@ - - - - -butia (Describe) - - - - -
- - - - - -
- - - - - - - - -
 DESCRIBE butia  DESCRIBE lback  DESCRIBE dist 
-
-Butia
Robot Educativo
-
-
-

- -Funciones disponibles en -
-butia

- -
- -

-A continuación se lista las funciones disponibles en este módulo. -
-Puedes invocar la función ingresando los datos necesarios y presionando el botón Submit. -

- -

- - - - - - - - - - - - - - - - - - -
-Resumen de Funciones
- data (String)read_ver(data number) - -
-           -
- -data: - - -
- data (String)get_volt() - -
-           -
- - - -
-  -

- - - \ No newline at end of file diff --git a/lib/support/bobot_server/butia/header.htm b/lib/support/bobot_server/butia/header.htm deleted file mode 100644 index 7d64136..0000000 --- a/lib/support/bobot_server/butia/header.htm +++ /dev/null @@ -1,10 +0,0 @@ - - - -

-

ROBOT BUTIA

-Butia

-


-
- - diff --git a/lib/support/bobot_server/butia/images/btar_dn.gif b/lib/support/bobot_server/butia/images/btar_dn.gif deleted file mode 100644 index 7f6b4f3..0000000 --- a/lib/support/bobot_server/butia/images/btar_dn.gif +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/images/btar_lft.gif b/lib/support/bobot_server/butia/images/btar_lft.gif deleted file mode 100644 index e104fe4..0000000 --- a/lib/support/bobot_server/butia/images/btar_lft.gif +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/images/btar_rgt.gif b/lib/support/bobot_server/butia/images/btar_rgt.gif deleted file mode 100644 index 4cc5ae0..0000000 --- a/lib/support/bobot_server/butia/images/btar_rgt.gif +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/images/btar_up.gif b/lib/support/bobot_server/butia/images/btar_up.gif deleted file mode 100644 index e3180df..0000000 --- a/lib/support/bobot_server/butia/images/btar_up.gif +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/images/butiaRobot3.png b/lib/support/bobot_server/butia/images/butiaRobot3.png deleted file mode 100644 index f7e74cf..0000000 --- a/lib/support/bobot_server/butia/images/butiaRobot3.png +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/images/clase07.jpg b/lib/support/bobot_server/butia/images/clase07.jpg deleted file mode 100644 index acc498f..0000000 --- a/lib/support/bobot_server/butia/images/clase07.jpg +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/butia/sensors.htm b/lib/support/bobot_server/butia/sensors.htm deleted file mode 100644 index dca9244..0000000 --- a/lib/support/bobot_server/butia/sensors.htm +++ /dev/null @@ -1,40 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/support/bobot_server/butia/view.htm b/lib/support/bobot_server/butia/view.htm deleted file mode 100644 index 0fda3dc..0000000 --- a/lib/support/bobot_server/butia/view.htm +++ /dev/null @@ -1,10 +0,0 @@ - - - -
- -Butia

- -

- - \ No newline at end of file diff --git a/lib/support/bobot_server/dumptemplate.txt b/lib/support/bobot_server/dumptemplate.txt deleted file mode 100644 index b1c1dfa..0000000 --- a/lib/support/bobot_server/dumptemplate.txt +++ /dev/null @@ -1,11 +0,0 @@ - -Bobot dump - -

Bobot

-home | modules -
-Modules:
- -
- - diff --git a/lib/support/bobot_server/dumptemplate_descr.txt b/lib/support/bobot_server/dumptemplate_descr.txt deleted file mode 100644 index e34df38..0000000 --- a/lib/support/bobot_server/dumptemplate_descr.txt +++ /dev/null @@ -1,37 +0,0 @@ - -Bobot dump - -

Bobot dump

-home | dump -
-Modules:
- -
-

- -Funciones disponibles en -
-

- -
- -

-A continuación se lista las funciones disponibles en este módulo. -
-Puedes invocar la función ingresando los datos necesarios y presionando el botón Submit. -

- -

- - -

Sensor Name - Type (A/D) - Value - Other -
Temperature - D - 23 - C -
Pote - A - 100 - -
Gas - A - 15 - -
Button - D - 1 - Pressed -
- - - - - -
-
- - diff --git a/lib/support/bobot_server/dumptemplate_descr_row.txt b/lib/support/bobot_server/dumptemplate_descr_row.txt deleted file mode 100644 index ade4736..0000000 --- a/lib/support/bobot_server/dumptemplate_descr_row.txt +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/lib/support/bobot_server/favicon.ico b/lib/support/bobot_server/favicon.ico deleted file mode 100644 index 3834805..0000000 --- a/lib/support/bobot_server/favicon.ico +++ /dev/null Binary files differ diff --git a/lib/support/bobot_server/http-util.lua b/lib/support/bobot_server/http-util.lua deleted file mode 100644 index c8b9a6c..0000000 --- a/lib/support/bobot_server/http-util.lua +++ /dev/null @@ -1,41 +0,0 @@ -module(..., package.seeall); - -local bobot = require("bobot") - -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] - ---local devices=devices -function load_file (filename) - local served, err = io.open(my_path..filename, "r") - if served then - return served:read("*all") - else - bobot.debugprint("Error opening", my_path..filename,":", err) - end -end - -function parse_params(s) - local params={} - for k,v in string.gmatch(s, '([%w%%%_%-]+)=([%w%%%_%-]+)') do - bobot.debugprint('param', k, v) - params[k]=v - end - return params -end - -local page404="404 Not Found

404 Not Found!


bobot" -local http404="HTTP/1.1 404 Not Found\r\nContent-Type:text/html\r\nContent-Length: "..#page404.."\r\n\r\n" .. page404 -page404=nil -local function error_page() - return http404 -end - -function find_page (page) - local page=string.sub(page,2) - local file=load_file(page) - if file then - return function() return file end - else - return error_page - end -end diff --git a/lib/support/bobot_server/indextemplate.txt b/lib/support/bobot_server/indextemplate.txt deleted file mode 100644 index 24b2245..0000000 --- a/lib/support/bobot_server/indextemplate.txt +++ /dev/null @@ -1,16 +0,0 @@ - -Bobot - -

Bobot

-home | modules -
- -bobot logo -

-Grupo MINA
-In.Co., Facultad de Ingeniería
-Universidad de la República
-Uruguay

-
- - diff --git a/lib/support/drivers/admin.lua b/lib/support/drivers/admin.lua deleted file mode 100644 index c3e3da9..0000000 --- a/lib/support/drivers/admin.lua +++ /dev/null @@ -1,11 +0,0 @@ -local device = _G -local RESET = string.char(0xFF) - -api={} -api.reset = {} -api.reset.parameters = {} -api.reset.returns = {} -api.reset.call = function (data) - device:send(RESET) -end - diff --git a/lib/support/drivers/ax.lua b/lib/support/drivers/ax.lua deleted file mode 100644 index d505511..0000000 --- a/lib/support/drivers/ax.lua +++ /dev/null @@ -1,118 +0,0 @@ -local device = _G -local WRITE_INFO = 0x01 -local READ_INFO = 0x02 -local GET_RAW_POS = 0x03 -local char000 = string.char(0,0,0) -local mode='wheel' - ---byte id,byte regstart, int value -api={} -api.write_info = {} -api.write_info.parameters = {[1]={rname="id", rtype="number", min=0, max=255},[2]={rname="regstart", rtype="number", min=0, max=255},[3]={rname="value", rtype="number", min=0, max=65536}} ----byte id,byte regstart, int value -api.write_info.returns = {[1]={rname="write_info_return", rtype="number"}} --one return -api.write_info.call = function (id, regstart, value) - id, regstart, value = tonumber(id), tonumber(regstart), tonumber(value) - local write_info_payload = string.char(WRITE_INFO, id, regstart, math.floor(value / 256),value % 256) - device:send(write_info_payload) - local write_info_response = device:read(2) or char000 - local raw_val = (string.byte(write_info_response, 2) or 0) - return raw_val -end - ---- Set wheel mode. ---Set the motor to continuous rotation mode. -api.wheel_mode = {} -api.wheel_mode.parameters = {[1]={rname="id", rtype="number", min=0, max=255}} -api.wheel_mode.returns = {} -api.wheel_mode.call = function (id ) - id = tonumber(id) - local ret = device:send(string.char(WRITE_INFO,id,0x06,0x00,0x00)) - local write_info_response = device:read(1) or string.char(0,0) - local ret = device:send(string.char(WRITE_INFO,id,0x08,0x00,0x00)) - local write_info_response = device:read(1) or string.char(0,0) - mode='wheel' - end - ---- Set joint mode. --- Set the motor to joint mode. Angles are provided in degrees, --- in the full servo coverage (0 - 300 degrees arc) --- @param min the minimum joint angle (defaults to 0) --- @param max the maximum joint angle (defaults to 300) -api.joint_mode = {} -api.joint_mode.parameters = {[1]={rname="id", rtype="number", min=0, max=255},[2]={rname="minimo", rtype="number", min=0, max=1023},[3]={rname="maximo", rtype="number", min=0, max=1023}} -api.joint_mode.returns = {} -api.joint_mode.call = function (id ,minimo, maximo) - id = tonumber(id) - minimo=tonumber(minimo) - maximo=tonumber(maximo) - local ret = device:send(string.char(WRITE_INFO,id,0x06,math.floor(minimo / 256),minimo % 256)) - local write_info_response = device:read(1) or string.char(0,0) - local ret = device:send(string.char(WRITE_INFO,id,0x08,math.floor(maximo / 256),maximo % 256)) - local write_info_response = device:read(1) or string.char(0,0) - mode='joint' - end - - ---- Set motor position. --- Set the target position for the motor's axle. Only works in --- joint mode. --- @param value Angle in degrees, in the 0 .. 300deg range. -api.set_position = {} -api.set_position.parameters = {[1]={rname="id", rtype="number", min=0, max=255},[2]={rname="pos", rtype="number", min=0, max=1023}} -api.set_position.returns = {} -api.set_position.call = function (id, pos ) - id = tonumber(id) - pos = tonumber(pos) - local ret = device:send(string.char(WRITE_INFO,id,0x1E,math.floor(pos / 256),pos % 256)) - local write_info_response = device:read(1) or string.char(0,0) - end - - ---- Get motor position. --- Read the axle position from the motor. --- @return The angle in deg. The reading is only valid in the --- 0 .. 300deg range -api.get_position = {} -api.get_position.parameters = {[1]={rname="id", rtype="number", min=0, max=255},[2]={rname="pos", rtype="number", min=0, max=1023}} -api.get_position.returns = {[1]={rname="motor_position", rtype="number"}} --one return -api.get_position.call = function(id) - local send_response = device:send(string.char(GET_RAW_POS,id)) - local value = device:read(3) or string.char(0,0,0) - local h_value = string.byte(value, 2) - local l_value = string.byte(value, 3) - local raw_angle = 256 * h_value + l_value - local ang=0.29*(raw_angle) -- deg ? - return raw_angle - - end - - ---- Set motor speed. --- @param value If motor in joint mode, speed in deg/sec in the 1 .. 684 range --- (0 means max available speed). --- If in wheel mode, as a fraction of max torque (in the -1 .. 1 range). -api.set_speed = {} -api.set_speed.parameters = {[1]={rname="id", rtype="number", min=0, max=255},[2]={rname="speed", rtype="number", min=-1, max=684}} -api.set_speed.returns = {} --no return -api.set_speed.call = function(id, speed) - --if mode=='joint' then - -- 0 .. 684 deg/sec - local vel=math.floor(speed * 1.496) - local lowb = math.floor(vel/ 256) - local highb = vel % 256 - - - --local lowb, highb = get2bytes_unsigned(vel) - local ret = device:send(id,0x20,string.char(lowb,highb)) - print ("ret= ",ret, " lowb= ", lowb, " highb= ", highb) - if ret then return ret:byte() end - --else --mode=='wheel' - -- -1 .. +1 max torque - --local vel=math.floor(speed * 1023) - --local lowb, highb = get2bytes_signed(vel) - --local ret = device:send(id,0x20,string.char(lowb,highb)) - --if ret then return ret:byte() end - --end -end - - diff --git a/lib/support/drivers/boot.lua b/lib/support/drivers/boot.lua deleted file mode 100644 index 2471ab9..0000000 --- a/lib/support/drivers/boot.lua +++ /dev/null @@ -1,11 +0,0 @@ -local device = _G -local RESET = string.char(0xFF) - -api={} -api.reset = {} -api.reset.parameters = {} --no parameters -api.reset.returns = {} --no returns -api.reset.call = function () - device:send(RESET) -end - diff --git a/lib/support/drivers/boton.lua b/lib/support/drivers/boton.lua deleted file mode 100644 index 4f846c9..0000000 --- a/lib/support/drivers/boton.lua +++ /dev/null @@ -1,19 +0,0 @@ -local device = _G - -local GET_VALUE=string.char(0x00) -local string_byte=string.byte - --- description: lets us know button's current status --- input: empty --- output: button's current status. Possible status: 1 pressed - 0 not pressed -api={} -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="state", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get button's status - local sen_dig_response = device:read(2) -- 2 bytes to read (opcode, data) - if not sen_dig_response or #sen_dig_response~=2 then return -1 end - local raw_val = string_byte(sen_dig_response, 2) or 0 -- keep data - return raw_val -end diff --git a/lib/support/drivers/butia.lua b/lib/support/drivers/butia.lua deleted file mode 100644 index b29c9f1..0000000 --- a/lib/support/drivers/butia.lua +++ /dev/null @@ -1,39 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x02) -- lee la versión del firmware de la placa (Igual para 1.0 y 2.0) -local GET_VOLT = string.char(0x03) -- obtiene el voltage de la batería (Igual para 1.0 y 2.0) - -api={} -api.read_ver = {} -api.read_ver.parameters = {} -api.read_ver.returns = {[1]={rname="data", rtype="string"}} -api.read_ver.call = function (data) - device:send(RD_VERSION) - local devolver = -1 - local ret = device:read(2) - if ret then - devolver = string.byte(ret , 2) --leo el segundo byte obtenido que tiene la versión (el primero tiene el opcode) - end - --local devolver = (string.byte(version_response,2) or 0) + (string.byte(version_response,3) or 0)* 256 - return devolver -end - -api.get_volt = {} -api.get_volt.parameters = {} -- no se envian parámetros -api.get_volt.returns = {[1]={rname="volts", rtype="string"}} --nos devuelve el voltaje de las baterías -api.get_volt.call = function () - device:send(GET_VOLT) --envío el código de operación - local data_in = device:read(2) --leo 2 bytes, primero el código de operación y segundo el voltaje - local voltaje = string.byte(data_in or "00000000" , 2) --leo el segundo byte obtenido que es el que tiene el voltaje - --local resultado = string.char(math.floor(voltNum / 10),".",tonumber(volNum) % 256, " volts") - return voltaje -end - ---[[ -function bytesToString(data) - local data_hex = "" - for i=1, string.len(data) do - data_hex = data_hex .. string.format('%02X', (string.byte(data, i))) - end - return data_hex -end ---]] diff --git a/lib/support/drivers/buzzer.lua b/lib/support/drivers/buzzer.lua deleted file mode 100644 index a2ede05..0000000 --- a/lib/support/drivers/buzzer.lua +++ /dev/null @@ -1,51 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local PRENDER = string.char(0x01) -local APAGAR = string.char(0x02) -local BUZZER_CORTO = string.char(0x03) -local BUZZER_TRIPLE = string.char(0x04) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.prender = {} -api.prender.parameters = {} --no parameters -api.prender.returns = {} --no return -api.prender.call = function () - local write_res, err = device:send(PRENDER) - if write_res then return 1 else return 0 end -end - -api.apagar = {} -api.apagar.parameters = {} --no parameters -api.apagar.returns = {} --no return -api.apagar.call = function () - local write_res, err = device:send(APAGAR) - if write_res then return 1 else return 0 end -end - -api.buzzer_corto = {} -api.buzzer_corto.parameters = {[1]={rname="num", rtype="number"}} -api.buzzer_corto.returns = {} --no return -api.buzzer_corto.call = function (num) - local write_res, err = device:send(BUZZER_CORTO .. string.char(num)) - if write_res then return 1 else return 0 end -end - -api.buzzer_triple = {} -api.buzzer_triple.parameters = {[1]={rname="tiempo1", rtype="number"}, [2]={rname="tiempo2", rtype="number"}, [3]={rname="tiempo3", rtype="number"}} -api.buzzer_triple.returns = {} --no return -api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3) - local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3)) - if write_res then return 1 else return 0 end -end diff --git a/lib/support/drivers/debug.lua b/lib/support/drivers/debug.lua deleted file mode 100644 index d8191ec..0000000 --- a/lib/support/drivers/debug.lua +++ /dev/null @@ -1,39 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local RD_DEBUG = string.char(0x01) -local MESSAGE = string.char(0x02) - - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - --return raw_val - return version_response -end - -api.rd_debug = {} -api.rd_debug.parameters = {} --no parameters -api.rd_debug.returns = {[1]={rname="data", rtype="string"}} --debug message -api.rd_debug.call = function () - local write_res, err = device:send(RD_DEBUG) - local len = 4 - local ret = device:read(len) or "" - print("====",ret, string.len(ret)) - return ret -end - -api.message = {} -api.message.parameters = {} --no parameters -api.message.returns = {} -api.message.call = function () - local write_res, err = device:send(MESSAGE) - return write_res -end - diff --git a/lib/support/drivers/display.lua b/lib/support/drivers/display.lua deleted file mode 100644 index 3629cb9..0000000 --- a/lib/support/drivers/display.lua +++ /dev/null @@ -1,99 +0,0 @@ -local device = _G - -local string_char=string.char - -local RD_VERSION = string_char(0x00) -local ESCRIBIR = string_char(0x01) -local PRUEBA = string_char(0x02) -local BORRAR = string_char(0x03) -local INICIAR = string_char(0x04) -local PRENDER_BKL = string_char(0x08) -local APAGAR_BKL = string_char(0x09) -local AGENDAR_MSG = string_char(0x0A) -local SET_TICKS = string_char(0x0B) -local ESPACIO = string_char(0x20) - - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - device:send(RD_VERSION) - local version_response = device:read(2) - local raw_val = string.byte(temperature_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.escribir = {} -api.escribir.parameters = {[1]={rname="message", rtype="string"}} -api.escribir.returns = {} -api.escribir.call = function (str) - local msg = ESCRIBIR .. str - device:send(msg) - --device:read() -end - -api.prueba = {} -api.prueba.parameters = {} --no parameters -api.prueba.returns = {} --no return -api.prueba.call = function () - device:send(PRUEBA) -end - -api.borrar = {} -api.borrar.parameters = {} --no parameters -api.borrar.returns = {} --no return -api.borrar.call = function () - device:send(BORRAR) -end - -api.iniciar = {} -api.iniciar.parameters = {} --no parameters -api.iniciar.returns = {} --no return -api.iniciar.call = function () - device:send(INICIAR) -end - -api.prender_bkl = {} -api.prender_bkl.parameters = {} --no parameters -api.prender_bkl.returns = {} --no return -api.prender_bkl.call = function () - device:send(PRENDER_BKL) -end - -api.apagar_bkl = {} -api.apagar_bkl.parameters = {} --no parameters -api.apagar_bkl.returns = {} --no return -api.apagar_bkl.call = function () - device:send(APAGAR_BKL) -end - -api.set_ticks = {} -api.set_ticks.parameters = {[1]={rname="cantTicks", rtype="numeric"}} --how many timmers ticks have to pass before display agendar_msg screen -api.set_ticks.returns = {} --no return -api.set_ticks.call = function (ticks) - device:send(SET_TICKS .. string_char(ticks)) -end - -api.agendar_msg = {} -api.agendar_msg.parameters = { - [1]={rname="message", rtype="string"}, -- first parameter is the message - [2]={rname="isCiclic", rtype="numeric"}, -- 1 in case of a ciclic message 0 elsewere - [3]={rname="isEnd", rtype="numeric"}} -- 1 in case of end of message, so previously calls to agendar_msg could be concatenated -api.agendar_msg.returns = {[1]={rname="isFull", rtype="boolean"}} --If it is no more space in the event buffer returns true, false elsewere -api.agendar_msg.call = function (str, isCiclic, isEnd) - device:send(AGENDAR_MSG .. string_char(32) .. string_char(isEnd) .. string_char(isCiclic) .. str) - print("despues del send") - local ret = device:read(3) or char0000 --el tercer byte recibido indica con un 1 si el buffer circuilar que se utiliza para mantener los mensajes esta lleno, 0 en caso controario - print("despues del read") - local error = (string.byte(ret,3) or 0) - print("despues de capturar el 3er byte") - if(error == 1) then - print "error, buffer lleno" - else - print "ok" - end - return error -end diff --git a/lib/support/drivers/dist.lua b/lib/support/drivers/dist.lua deleted file mode 100644 index 5b8a247..0000000 --- a/lib/support/drivers/dist.lua +++ /dev/null @@ -1,25 +0,0 @@ -local device = _G - -local GET_VALUE=string.char(0x00) -local string_byte=string.byte - --- description: lets us know dist sensor's current value --- input: empty --- output: dist sensor's current value. -api={} -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="par1", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get distance of object - local sen_anl_response = device:read(3) -- operation code and data - if not sen_anl_response or #sen_anl_response~=3 then return -1 end - --local raw_val = (string_byte(sen_anl_response, 2) or 0) + (string_byte(sen_anl_response, 3) or 0)* 256 - raw_val = string.byte(sen_anl_response, 2)* 256 + string.byte(sen_anl_response, 3) - raw_val = 1024 - raw_val - return raw_val -end - - - - diff --git a/lib/support/drivers/dynamix.lua b/lib/support/drivers/dynamix.lua deleted file mode 100644 index 52ea4ba..0000000 --- a/lib/support/drivers/dynamix.lua +++ /dev/null @@ -1,34 +0,0 @@ -local device = _G -local WRITE_INFO = 0x01 -local SEND_BUS = 0x01 -local READ_INFO = 0x02 -local GET_RAW_POS = 0x03 -local char000 = string.char(0,0,0) - ---byte id,byte regstart, int value -api={} -api.write_info = {} -api.write_info.parameters = {[1]={rname="id", rtype="number", min=0, max=255},[2]={rname="regstart", rtype="number", min=0, max=255},[3]={rname="value", rtype="number", min=0, max=65536}} ----byte id,byte regstart, int value -api.write_info.returns = {[1]={rname="write_info_return", rtype="number"}} --one return -api.write_info.call = function (id, regstart, value) - id, regstart, value = tonumber(id), tonumber(regstart), tonumber(value) - local write_info_payload = string.char(WRITE_INFO, id, regstart, math.floor(value / 256),value % 256) - device:send(write_info_payload) - local write_info_response = device:read(2) or char000 - local raw_val = (string.byte(write_info_response, 2) or 0) - return raw_val -end - -api.pasarela = {} -api.pasarela.parameters = {[1]={rname="packet", rtype="string", min=0, max=255}} -api.pasarela.returns = {} -api.pasarela.call = function (value) - local valueN = tonumber(value) - local checksum = 255 - ((0xfe + 0x04 + 0x03 + 0x19 +valueN)%256) - print (checksum) - local paquete = string.char(SEND_BUS, 0xff, 0xff,0xfe, 0x04, 0x03, 0x19, valueN, checksum) - device:send(paquete) -end - - - diff --git a/lib/support/drivers/gas.lua b/lib/support/drivers/gas.lua deleted file mode 100644 index a056759..0000000 --- a/lib/support/drivers/gas.lua +++ /dev/null @@ -1,20 +0,0 @@ -local device = _G -local RD_GAS = string.char(0x01) -local char000 = string.char(0,0,0) - -api={} -api.get_gas = {} -api.get_gas.parameters = {} --no parameter -api.get_gas.returns = {[1]={rname="gas level", rtype="number"}} --one return -api.get_gas.call = function () - local get_payload = RD_GAS - device:send(get_payload) - local response = device:read(3) - if not response then - print ('WARN: api.get_gas.call failure on device:read(3)') - response=char000 - end - local raw_val = string.byte(response, 2) + 255*string.byte(response, 3) - return raw_val -end - diff --git a/lib/support/drivers/grises.lua b/lib/support/drivers/grises.lua deleted file mode 100644 index a680266..0000000 --- a/lib/support/drivers/grises.lua +++ /dev/null @@ -1,19 +0,0 @@ -local device = _G - -local GET_VALUE=string.char(0x00) -local string_byte=string.byte - --- description: lets us know grey sensor's current value --- input: empty --- output: grey sensor's current value. -api={} -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="par1", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get grey level - local sen_anl_response = device:read(3) -- operation code and data - if not sen_anl_response or #sen_anl_response~=3 then return -1 end - local raw_val = math.floor(((string_byte(sen_anl_response, 2) or 0) + (string_byte(sen_anl_response, 3) or 0)* 256)/ 100) - return raw_val -end diff --git a/lib/support/drivers/hotplug/button.lua b/lib/support/drivers/hotplug/button.lua deleted file mode 100644 index 9ddba48..0000000 --- a/lib/support/drivers/hotplug/button.lua +++ /dev/null @@ -1,32 +0,0 @@ -local device = _G - -local RD_VERSION=string.char(0x00) -local GET_VALUE=string.char(0x01) -local string_byte=string.byte - --- description: lets us know button module's version -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string_byte(version_response,2) or 0) + (string_byte(version_response,3) or 0)* 256 - return raw_val -end - --- description: lets us know button's current status --- input: empty --- output: button's current status. Possible status: 1 pressed - 0 not pressed -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="state", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get button's status - local sen_dig_response = device:read(2) -- 2 bytes to read (opcode, data) - if not sen_dig_response or #sen_dig_response~=2 then return -1 end - local raw_val = string_byte(sen_dig_response, 2) or 0 -- keep data - return raw_val -end diff --git a/lib/support/drivers/hotplug/distanc.lua b/lib/support/drivers/hotplug/distanc.lua deleted file mode 100644 index 2340796..0000000 --- a/lib/support/drivers/hotplug/distanc.lua +++ /dev/null @@ -1,32 +0,0 @@ -local device = _G - -local RD_VERSION=string.char(0x00) -local GET_VALUE=string.char(0x01) -local string_byte=string.byte - --- description: lets us know dist module's version -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string_byte(version_response,2) or 0) + (string_byte(version_response,3) or 0)* 256 - return raw_val -end - --- description: lets us know dist sensor's current value --- input: empty --- output: dist sensor's current value. -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="par1", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get distance of object - local sen_anl_response = device:read(3) -- operation code and data - if not sen_anl_response or #sen_anl_response~=3 then return -1 end - local raw_val = (string_byte(sen_anl_response, 2) or 0) + (string_byte(sen_anl_response, 3) or 0)* 256 - return raw_val -end diff --git a/lib/support/drivers/hotplug/gpio.lua b/lib/support/drivers/hotplug/gpio.lua deleted file mode 100644 index 331efb3..0000000 --- a/lib/support/drivers/hotplug/gpio.lua +++ /dev/null @@ -1,19 +0,0 @@ -local device = _G - -local RD_VERSION=string.char(0x00) -local string_byte=string.byte - --- description: lets us know button module's version -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string_byte(version_response,2) or 0) + (string_byte(version_response,3) or 0)* 256 - return raw_val -end - - diff --git a/lib/support/drivers/hotplug/grey.lua b/lib/support/drivers/hotplug/grey.lua deleted file mode 100644 index eb24f36..0000000 --- a/lib/support/drivers/hotplug/grey.lua +++ /dev/null @@ -1,32 +0,0 @@ -local device = _G - -local RD_VERSION=string.char(0x00) -local GET_VALUE=string.char(0x01) -local string_byte=string.byte - --- description: lets us know grey module's version -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string_byte(version_response,2) or 0) + (string_byte(version_response,3) or 0)* 256 - return raw_val -end - --- description: lets us know grey sensor's current value --- input: empty --- output: grey sensor's current value. -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="par1", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get grey level - local sen_anl_response = device:read(3) -- operation code and data - if not sen_anl_response or #sen_anl_response~=3 then return -1 end - local raw_val = (string_byte(sen_anl_response, 2) or 0) + (string_byte(sen_anl_response, 3) or 0)* 256 - return raw_val -end diff --git a/lib/support/drivers/hotplug/light.lua b/lib/support/drivers/hotplug/light.lua deleted file mode 100644 index ce953b2..0000000 --- a/lib/support/drivers/hotplug/light.lua +++ /dev/null @@ -1,32 +0,0 @@ -local device = _G - -local RD_VERSION=string.char(0x00) -local GET_VALUE=string.char(0x01) -local string_byte=string.byte - --- description: lets us know light module's version -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string_byte(version_response,2) or 0) + (string_byte(version_response,3) or 0)* 256 - return raw_val -end - --- description: lets us know light sensor's current value --- input: empty --- output: light sensor's current value. -api.getValue = {} -api.getValue.parameters = {} -- no input parameters -api.getValue.returns = {[1]={rname="par1", rtype="int"}} -api.getValue.call = function () - device:send(GET_VALUE) -- operation code 1 = get light level - local sen_anl_response = device:read(3) -- operation code and data - if not sen_anl_response or #sen_anl_response~=3 then return -1 end - local raw_val = (string_byte(sen_anl_response, 2) or 0) + (string_byte(sen_anl_response, 3) or 0)* 256 - return raw_val -end diff --git a/lib/support/drivers/hotplug/port.lua b/lib/support/drivers/hotplug/port.lua deleted file mode 100644 index 331efb3..0000000 --- a/lib/support/drivers/hotplug/port.lua +++ /dev/null @@ -1,19 +0,0 @@ -local device = _G - -local RD_VERSION=string.char(0x00) -local string_byte=string.byte - --- description: lets us know button module's version -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string_byte(version_response,2) or 0) + (string_byte(version_response,3) or 0)* 256 - return raw_val -end - - diff --git a/lib/support/drivers/hotplug/tilt.lua b/lib/support/drivers/hotplug/tilt.lua deleted file mode 100644 index 1076479..0000000 --- a/lib/support/drivers/hotplug/tilt.lua +++ /dev/null @@ -1,19 +0,0 @@ -local device = _G - -api={} -api.getTilt = {} -api.getTilt.parameters = {} -- -- no input parameters -api.getTilt.returns = {[1]={rname="par1", rtype="int"}} -api.getTilt.call = function () - device:send(string.char(0x00)) -- codigo de operacion 0 - local sen_dig_response = device:read(3) - local raw_val - if not sen_dig_response or string.byte(sen_dig_response or "00000000", 2) == nil or string.byte(sen_dig_response or "00000000", 3) == nil - then - raw_val = "nil value" - else - raw_val = string.byte(sen_dig_response, 3) % 2 - end - return raw_val - -end diff --git a/lib/support/drivers/hotplug/vibra.lua b/lib/support/drivers/hotplug/vibra.lua deleted file mode 100644 index 0c3d985..0000000 --- a/lib/support/drivers/hotplug/vibra.lua +++ /dev/null @@ -1,19 +0,0 @@ -local device = _G - -api={} -api.getVibra = {} -api.getVibra.parameters = {} -- -- no input parameters -api.getVibra.returns = {[1]={rname="par1", rtype="int"}} -api.getVibra.call = function () - device:send(string.char(0x00)) -- codigo de operacion 0 - local sen_dig_response = device:read(3) - local raw_val - if not sen_dig_response or string.byte(sen_dig_response or "00000000", 2) == nil or string.byte(sen_dig_response or "00000000", 3) == nil - then - raw_val = "nil value" - else - raw_val = string.byte(sen_dig_response, 3) % 2 - end - return raw_val - -end diff --git a/lib/support/drivers/lback.lua b/lib/support/drivers/lback.lua deleted file mode 100644 index 9f903b1..0000000 --- a/lib/support/drivers/lback.lua +++ /dev/null @@ -1,21 +0,0 @@ -local device = _G - -api={} -api.send = {} -api.send.parameters = {[1]={rname="data", rtype="string"}} -api.send.returns = {} -api.send.call = function (data) - --print("####", data, string.len(data)) - device:send(data) -end - -api.read = {} -api.read.parameters = {[1]={rname="len", rtype="int", default=64, min=0, max=255}} -api.read.returns = {[1]={rname="data", rtype="string"}} -api.read.call = function (len) - local len = len or 64 - local ret = device:read(len) --- print("====",ret, string.len(ret)) - return ret -end - diff --git a/lib/support/drivers/led.lua b/lib/support/drivers/led.lua deleted file mode 100644 index 1095d93..0000000 --- a/lib/support/drivers/led.lua +++ /dev/null @@ -1,17 +0,0 @@ -local device = _G - -local string_char=string.char - -api={} -api.setLight = {} -api.setLight.parameters = {[1]={rname="message", rtype="string"}} -api.setLight.returns = {} -api.setLight.call = function (intensidad) - intensidad=tonumber(intensidad) - if (not intensidad) or intensidad<0 then intensidad=0 - elseif intensidad>255 then intensidad=255 end - - local msg = string_char(0x00) .. string_char(math.floor(intensidad)) -- entre 0 y 255 - device:send(msg) - local version_response = device:read() -end diff --git a/lib/support/drivers/ledA.lua b/lib/support/drivers/ledA.lua deleted file mode 100644 index f76b501..0000000 --- a/lib/support/drivers/ledA.lua +++ /dev/null @@ -1,46 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local PRENDER = string.char(0x01) -local APAGAR = string.char(0x02) -local BLINK = string.char(0x03) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.prender = {} -api.prender.parameters = {} --no parameters -api.prender.returns = {} --no return -api.prender.call = function () - device:send(PRENDER) --- local response = device:read(2) --- print("[",string.byte(response, 1),",", string.byte(response, 2),"]") --- print("-----------------------------------------------") --- if (string.byte(response, 1) ~= nil or string.byte(response, 2) ~= nil) then --- print("vino data") --- end -end - -api.apagar = {} -api.apagar.parameters = {} --no parameters -api.apagar.returns = {} --no return -api.apagar.call = function () - device:send(APAGAR) -end - -api.blink = {} -api.blink.parameters = {[1]={rname="time", rtype="number"}, [2]={rname="blinks", rtype="number"}} -api.blink.returns = {} --no return -api.blink.call = function (time, blinks) - local msg = BLINK .. string.char(time) .. string.char(blinks) - device:send(msg) -end diff --git a/lib/support/drivers/ledR.lua b/lib/support/drivers/ledR.lua deleted file mode 100644 index 1d3e726..0000000 --- a/lib/support/drivers/ledR.lua +++ /dev/null @@ -1,31 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local PRENDER = string.char(0x01) -local APAGAR = string.char(0x02) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.prender = {} -api.prender.parameters = {} --no parameters -api.prender.returns = {} --no return -api.prender.call = function () - device:send(PRENDER) -end - -api.apagar = {} -api.apagar.parameters = {} --no parameters -api.apagar.returns = {} --no return -api.apagar.call = function () - device:send(APAGAR) -end diff --git a/lib/support/drivers/ledV.lua b/lib/support/drivers/ledV.lua deleted file mode 100644 index 1d3e726..0000000 --- a/lib/support/drivers/ledV.lua +++ /dev/null @@ -1,31 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local PRENDER = string.char(0x01) -local APAGAR = string.char(0x02) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.prender = {} -api.prender.parameters = {} --no parameters -api.prender.returns = {} --no return -api.prender.call = function () - device:send(PRENDER) -end - -api.apagar = {} -api.apagar.parameters = {} --no parameters -api.apagar.returns = {} --no return -api.apagar.call = function () - device:send(APAGAR) -end diff --git a/lib/support/drivers/leds.lua b/lib/support/drivers/leds.lua deleted file mode 100644 index 7e55ce6..0000000 --- a/lib/support/drivers/leds.lua +++ /dev/null @@ -1,43 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local PRENDER = string.char(0x01) -local APAGAR = string.char(0x02) -local BLINK = string.char(0x03) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.prender = {} -api.prender.parameters = {[1]={rname="numLed", rtype="number"}} --recibe the led number -api.prender.returns = {} --no return -api.prender.call = function (ledNumber) - local write_res, err = device:send(PRENDER .. string.char(ledNumber)) - if write_res then return 1 else return 0 end -end - -api.apagar = {} -api.apagar.parameters = {[1]={rname="numLed", rtype="number"}} --recibe the led number -api.apagar.returns = {} --no return -api.apagar.call = function (ledNumber) - local write_res, err = device:send(APAGAR .. string.char(ledNumber)) - if write_res then return 1 else return 0 end -end - -api.blink = {} -api.blink.parameters = {[1]={rname="time", rtype="number"}, [2]={rname="blinks", rtype="number"}, [3]={rname="numLed", rtype="number"}} -api.blink.returns = {} --no return -api.blink.call = function (time, blinks, ledNumber) - local msg = BLINK .. string.char(time) .. string.char(blinks) .. string.char(ledNumber) - local write_res, err = device:send(msg) - if write_res then return 1 else return 0 end -end diff --git a/lib/support/drivers/luz.lua b/lib/support/drivers/luz.lua deleted file mode 100644 index ed14e26..0000000 --- a/lib/support/drivers/luz.lua +++ /dev/null @@ -1,21 +0,0 @@ -local device = _G - -api={} -api.getLuz = {} -api.getLuz.parameters = {} -- -- no input parameters -api.getLuz.returns = {[1]={rname="par1", rtype="int"}} -api.getLuz.call = function () - device:send(string.char(0x00)) -- codigo de operacion 0 - local sen_anl_response = device:read(3) - local raw_val - if not sen_anl_response or string.byte(sen_anl_response or "00000000", 2) == nil or string.byte(sen_anl_response or "00000000", 3) == nil - then - raw_val = "nil value" - else - raw_val = string.byte(sen_anl_response, 2)* 256 + string.byte(sen_anl_response, 3) - raw_val = 1024 - raw_val - - end - return raw_val - -end diff --git a/lib/support/drivers/magnet.lua b/lib/support/drivers/magnet.lua deleted file mode 100644 index e70b69c..0000000 --- a/lib/support/drivers/magnet.lua +++ /dev/null @@ -1,21 +0,0 @@ -local device = _G - --- descripción: permite conocer el estado el botón en un momento dado. --- entrada: no tiene. --- salida: estado del botón. Posibles estados: 1 presionado, 0 libre. -api={} -api.getCampo = {} -api.getCampo.parameters = {} -- no tiene parámetros de entrada -api.getCampo.returns = {[1]={rname="par1", rtype="int"}} -- 1 = presionado, 0 = libre -api.getCampo.call = function () - device:send(string.char(0x00)) -- codigo de operacion = 0 - local sen_dig_response = device:read(3) -- leo 2 bytes (opcode, data) - local raw_val - if not sen_dig_response or string.byte(sen_dig_response or "00000000", 2) == nil or string.byte(sen_dig_response or "00000000", 3) == nil - then - raw_val = "nil value" - else - raw_val = 1 - (string.byte(sen_dig_response, 3) % 2) - end - return raw_val -end diff --git a/lib/support/drivers/motor.lua b/lib/support/drivers/motor.lua deleted file mode 100644 index c1a86d6..0000000 --- a/lib/support/drivers/motor.lua +++ /dev/null @@ -1,42 +0,0 @@ -local device = _G -local SET_VEL_ADL = 0x00 -- código de op para mover el motor hacia adelante -local SET_VEL_ATR = 0x01 -- código de op para mover el motor hacia atrás - - -api={} -api.setveladl = {} -api.setveladl.parameters = {[1]={rname="id", rtype="int"}, [2]={rname="vel", rtype="int"}} --primer parametro id motor, segundo velocidad -api.setveladl.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setveladl.call = function (id, vel) - local msg = string.char(SET_VEL_ADL,id, math.floor(vel / 256),vel % 256) - device:send(msg) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - -api.setvelatr = {} -api.setvelatr.parameters = {[1]={rname="id", rtype="int"}, [2]={rname="vel", rtype="int"}} --primer parametro id motor, segundo velocidad -api.setvelatr.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvelatr.call = function (id, vel) - local msg = string.char(SET_VEL_ATR,id, math.floor(vel / 256),vel % 256) - device:send(msg) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - - -api.setvelatr2 = {} -api.setvelatr2.parameters = {[1]={rname="id", rtype="int"}, [2]={rname="vel", rtype="int"}} --primer parametro id motor, segundo velocidad -api.setvelatr2.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvelatr2.call = function (vel) - local msg = string.char(SET_VEL_ATR,0, math.floor(vel / 256),vel % 256) - device:send(msg) - local msg = string.char(SET_VEL_ATR,1, math.floor(vel / 256),vel % 256) - device:send(msg) - local ret = device:read(1) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end diff --git a/lib/support/drivers/motorTm.lua b/lib/support/drivers/motorTm.lua deleted file mode 100644 index 9343855..0000000 --- a/lib/support/drivers/motorTm.lua +++ /dev/null @@ -1,47 +0,0 @@ -local device = _G - -api={} -api.step = {} -api.step.parameters = {[1]={rname="step", rtype="int", min=0, max=65536}} -api.step.returns = {} -api.step.call = function (freq) - local msg = string.char(0x02) .. string.char(math.floor(freq / 256)) .. string.char(freq % 256) - device:send(msg) - device:read(1) -end - -api.steps = {} -api.steps.parameters = {[1]={rname="number", rtype="int", min=0, max=65536}} -api.steps.returns = {} -api.steps.call = function (number) - local msg = string.char(0x03) .. string.char(math.floor(number / 256)) .. string.char(number % 256) - device:send(msg) - device:read(1) -end - -api.phasetype = {} -api.phasetype.parameters = {[1]={rname="phasetype", rtype="int", min=0, max=2}} -api.phasetype.returns = {} -api.phasetype.call = function (phasetype) - local msg = string.char(0x04) .. string.char(phasetype) - device:send(msg) -end - -api.power_on = {} -api.power_on.parameters = {[1]={rname="power_on", rtype="int", min=0, max=1}} -api.power_on.returns = {} -api.power_on.call = function (on) - local msg = string.char(0x06) .. string.char(on) - device:send(msg) -end - -api.direction = {} -api.direction.parameters = {[1]={rname="direction", rtype="int", min=-1, max=1}} -api.direction.returns = {} -api.direction.call = function (dir) - if dir==-1 then dir=2 end - local msg = string.char(0x07) .. string.char(dir+1) - device:send(msg) -end - - diff --git a/lib/support/drivers/motores.lua b/lib/support/drivers/motores.lua deleted file mode 100644 index 45d2967..0000000 --- a/lib/support/drivers/motores.lua +++ /dev/null @@ -1,48 +0,0 @@ -local device = _G -local SET_VEL_MTR = 0x00 -- código de op para mover un motor con vel y sentido -local SET_VEL_2MTR = 0x01 -- código de op para mover dos motores con vel y sentido - - -api={} -api.setvelmtr = {} -api.setvelmtr.parameters = {[1]={rname="id", rtype="int"},[2]={rname="sentido", rtype="int"},[3]={rname="vel", rtype="int"}} --parametros, id sentido vel -api.setvelmtr.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvelmtr.call = function (id, sentido, vel) - vel=tonumber(vel) - if vel>1023 then vel=1023 end - local msg = string.char(SET_VEL_MTR,id, sentido, math.floor(vel / 256),vel % 256) - device:send(msg) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - -api.setvel2mtr = {} -api.setvel2mtr.parameters = {[1]={rname="sentido", rtype="int"},[2]={rname="vel", rtype="int"},[3]={rname="sentido", rtype="int"},[4]={rname="vel", rtype="int"}} -api.setvel2mtr.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvel2mtr.call = function (sentido1, vel1, sentido2, vel2) - vel1, vel2 = tonumber(vel1), tonumber(vel2) - if vel1>1023 then vel1=1023 end - if vel2>1023 then vel2=1023 end - local msg = string.char(SET_VEL_2MTR,sentido1, math.floor(vel1 / 256),vel1 % 256, sentido2, math.floor(vel2 / 256),vel2 % 256) - device:send(msg) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - - -api.setvelatr2 = {} -api.setvelatr2.parameters = {[1]={rname="id", rtype="int"}, [2]={rname="vel", rtype="int"}} --primer parametro id motor, segundo velocidad -api.setvelatr2.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvelatr2.call = function (vel) - local vdiv, vmod = math.floor(vel / 256),vel % 256 - local msg = string.char(SET_VEL_ATR, 0, vdiv, vmod) - device:send(msg) - msg = string.char(SET_VEL_ATR, 1, vdiv, vmod) - device:send(msg) - local ret = device:read(1) - ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end diff --git a/lib/support/drivers/motorin.lua b/lib/support/drivers/motorin.lua deleted file mode 100644 index 042f3cc..0000000 --- a/lib/support/drivers/motorin.lua +++ /dev/null @@ -1,28 +0,0 @@ -local device = _G - -api={} -api.speed = {} -api.speed.parameters = {[1]={rname="freq", rtype="int", min=0, max=65536}} -api.speed.returns = {} -api.speed.call = function (freq) - local msg = string.char(0x02) .. string.char(math.floor(freq / 256)) .. string.char(freq % 256) - device:send(msg) - device:read(1) -end - -api.steps = {} -api.steps.parameters = {[1]={rname="number", rtype="int", min=0, max=65536}} -api.steps.returns = {} -api.steps.call = function (number) - local msg = string.char(0x03) .. string.char(math.floor(number / 256)) .. string.char(number % 256) - device:send(msg) - device:read(1) -end - -api.on = {} -api.on.parameters = {[1]={rname="direction", rtype="int", min=-1, max=1}} -api.on.returns = {} -api.on.call = function (dir) - local msg = string.char(0x01) .. string.char(dir+1) - device:send(msg) -end diff --git a/lib/support/drivers/motors.lua b/lib/support/drivers/motors.lua deleted file mode 100644 index a7c9a05..0000000 --- a/lib/support/drivers/motors.lua +++ /dev/null @@ -1,70 +0,0 @@ -local device = _G -local RD_VERSION=string.char(0x00) -local SET_VEL_2MTR=0x01 -- código de op para mover dos motores con vel y sentido -local TEST_MOTORS=string.char(0x02) -local SET_VEL_MTR = 0x01 -- código de op para mover un motor con vel y sentido - -api={} -api.getVersion = {} -api.getVersion.parameters = {} -- no input parameters -api.getVersion.returns = {[1]={rname="version", rtype="int"}} -api.getVersion.call = function () - device:send(RD_VERSION) -- operation code 0 = get version - local version_response = device:read(3) -- 3 bytes to read (opcode, data) - if not version_response or #version_response~=3 then return -1 end - local raw_val = (string.byte(version_response,2) or 0) + (string.byte(version_response,3) or 0)* 256 - return raw_val -end - -api.setvelmtr = {} -- no impl en firmware -api.setvelmtr.parameters = {[1]={rname="id", rtype="int"},[2]={rname="sentido", rtype="int"},[3]={rname="vel", rtype="int"}} --parametros, id sentido vel -api.setvelmtr.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvelmtr.call = function (id, sentido, vel) - vel=tonumber(vel) - if vel>1023 then vel=1023 end - local msg = string.char(SET_VEL_MTR,id, sentido, math.floor(vel / 256),vel % 256) - device:send(msg) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - -api.setvel2mtr = {} -api.setvel2mtr.parameters = {[1]={rname="sentido", rtype="int"},[2]={rname="vel", rtype="int"},[3]={rname="sentido", rtype="int"},[4]={rname="vel", rtype="int"}} -api.setvel2mtr.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvel2mtr.call = function (sentido1, vel1, sentido2, vel2) - vel1, vel2 = tonumber(vel1), tonumber(vel2) - if vel1>1023 then vel1=1023 end - if vel2>1023 then vel2=1023 end - local msg = string.char(SET_VEL_2MTR,sentido1, math.floor(vel1 / 256),vel1 % 256, sentido2, math.floor(vel2 / 256),vel2 % 256) - device:send(msg) - local ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - -api.setvelatr2 = {} -- no impl en firmware -api.setvelatr2.parameters = {[1]={rname="id", rtype="int"}, [2]={rname="vel", rtype="int"}} --primer parametro id motor, segundo velocidad -api.setvelatr2.returns = {[1]={rname="dato", rtype="int"}} --codigo de operación -api.setvelatr2.call = function (vel) - local vdiv, vmod = math.floor(vel / 256),vel % 256 - local msg = string.char(SET_VEL_ATR, 0, vdiv, vmod) - device:send(msg) - msg = string.char(SET_VEL_ATR, 1, vdiv, vmod) - device:send(msg) - local ret = device:read(1) - ret = device:read(1) - local raw_val = string.byte(ret or " ", 1) - return raw_val -end - -api.testMotors = {} -api.testMotors.parameters = {} -- no input parameters -api.testMotors.returns = {[1]={rname="dato", rtype="int"}} -api.testMotors.call = function () - device:send(TEST_MOTORS) -- operation code 2 = test motors - local ret = device:read(1) -- 1 byte to read (opcode) - if not ret or #ret~=1 then return -1 end - local ret = string.byte(ret, 1) - return ret -end diff --git a/lib/support/drivers/move.lua b/lib/support/drivers/move.lua deleted file mode 100644 index 7c361e3..0000000 --- a/lib/support/drivers/move.lua +++ /dev/null @@ -1,16 +0,0 @@ -local device = _G -local GET_MOVE = string.char(0x01) -local char000 = string.char(0,0,0) - -api={} -api.get_move = {} -api.get_move.parameters = {} --no parameter -api.get_move.returns = {[1]={rname="digital_value", rtype="number"}} --one return -api.get_move.call = function () - local get_move_payload = GET_MOVE - device:send(get_move_payload) - local move_response = device:read(2) or char000 - local raw_val = (string.byte(move_response, 2) or 0) - return raw_val -end - diff --git a/lib/support/drivers/pnp.lua b/lib/support/drivers/pnp.lua deleted file mode 100644 index e69de29..0000000 --- a/lib/support/drivers/pnp.lua +++ /dev/null diff --git a/lib/support/drivers/pote.lua b/lib/support/drivers/pote.lua deleted file mode 100644 index fac23cf..0000000 --- a/lib/support/drivers/pote.lua +++ /dev/null @@ -1,16 +0,0 @@ -local device = _G -local RD_POTE = string.char(0x01) -local char000 = string.char(0,0,0) - -api={} -api.get_pote = {} -api.get_pote.parameters = {} --no parameter -api.get_pote.returns = {[1]={rname="analog_value", rtype="number"}} --one return -api.get_pote.call = function () - local get_pote_payload = RD_POTE - device:send(get_pote_payload) - local pote_response = device:read(3) or char000 - local raw_val = (string.byte(pote_response, 2) or 0) + 255*(string.byte(pote_response, 3) or 0) - return raw_val -end - diff --git a/lib/support/drivers/puerta.lua b/lib/support/drivers/puerta.lua deleted file mode 100644 index 1d3e726..0000000 --- a/lib/support/drivers/puerta.lua +++ /dev/null @@ -1,31 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local PRENDER = string.char(0x01) -local APAGAR = string.char(0x02) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(2) - local raw_val = string.byte(version_response, 2) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.prender = {} -api.prender.parameters = {} --no parameters -api.prender.returns = {} --no return -api.prender.call = function () - device:send(PRENDER) -end - -api.apagar = {} -api.apagar.parameters = {} --no parameters -api.apagar.returns = {} --no return -api.apagar.call = function () - device:send(APAGAR) -end diff --git a/lib/support/drivers/sec.lua b/lib/support/drivers/sec.lua deleted file mode 100644 index e89646b..0000000 --- a/lib/support/drivers/sec.lua +++ /dev/null @@ -1,87 +0,0 @@ -local device = _G -local RD_VERSION = string.char(0x00) -local GET_SEC = string.char(0X01) -local INTRUSION = string.char(0x02) -local RESET_FLAG = string.char(0x03) -local CONT_INT = string.char(0x04) -local MESS = string.char(0x05) -local RESET = string.char(0xFF) - -api={} -api.read_version = {} -api.read_version.parameters = {} --no parameters -api.read_version.returns = {[1]={rname="version", rtype="number"}} --one return -api.read_version.call = function () - local get_read_version = RD_VERSION - device:send(get_read_version) - local version_response = device:read(4) - local raw_val = string.byte(version_response, 3) - --print("rawval, deg_temp: ", raw_val, deg_temp) - return raw_val -end - -api.get_sec = {} -api.get_sec.parameters = {} --no parameters ---api.get_sec.returns = {[1]={rname="error", rtype="string"},[2]={rname="SecSensorValue_1", rtype="number"},[3]={rname="SecSensorValue_2", rtype="number"}} -api.get_sec.returns = {[1]={rname="SecSensorValue_1", rtype="number"},[2]={rname="SecSensorValue_2", rtype="number"}} -api.get_sec.call = function () - local send_res, err - send_res, err = device:send(GET_SEC) - local ret = device:read(3) - local SecSensorValue_1 = (string.byte(ret,2) or 0) - local SecSensorValue_2 = (string.byte(ret,3) or 0) --- local SecSensorValue_1 = (string.byte(ret,2)) --- local SecSensorValue_2 = (string.byte(ret,3)) - if ((SecSensorValue_1 == 0) and (SecSensorValue_2 == 0)) then - alarma = "00" - elseif ((SecSensorValue_1 == 0) and (SecSensorValue_2 == 1)) then - alarma = "01" - elseif ((SecSensorValue_1 == 1) and (SecSensorValue_2 == 0)) then - alarma = "10" - else - alarma = "11" - end - return alarma - --if ret then return true, SecSensorValue_1, SecSensorValue_2 else return false end -end - -api.intrusion = {} -api.intrusion.parameters = {} --no parameters -api.intrusion.returns = {[1]={rname="alarma", rtype="number"}} --one return -api.intrusion.call = function () - local intrusion = INTRUSION - device:send(intrusion) - local alarma = device:read(1) - if (alarma == string.char(0x00)) then - alarma = 0 - else - alarma = 1 - end - return alarma -end - -api.reset_flag = {} -api.reset_flag.parameters = {} --no parameters -api.reset_flag.returns = {[1]={rname="borrado", rtype="number"}} --one return -api.reset_flag.call = function () - local reset_flag = RESET_FLAG - device:send(reset_flag) - local borrado = device:read(1) - if (borrado == string.char(0x00)) then - borrado = 0 - else - borrado = 1 - end - - return borrado -end - -api.cont_int = {} -api.cont_int.parameters = {} --no parameters -api.cont_int.returns = {[1]={rname="cantidad", rtype="number"}} --one return -api.cont_int.call = function () - local cont_int = CONT_INT - device:send(cont_int) - local cantidad = device:read(1) - return string.byte(cantidad) -end diff --git a/lib/support/drivers/sensor.lua b/lib/support/drivers/sensor.lua deleted file mode 100644 index d4df8d4..0000000 --- a/lib/support/drivers/sensor.lua +++ /dev/null @@ -1,52 +0,0 @@ -local device = _G -local SEN_DIG = string.char(0x03) -- consulta un sensor digital -local SEN_ANL = string.char(0x00) -- consulta un sensor analogico -local SEN_ I2C = string.char(0x02) -- consulta un sensor i2c - -api={} -api.senanl = {} -api.senanl.parameters = {[1]={rname="idPin", rtype="int"}} -- -- el parámetro indica el pin que queremos leer de la arduino -api.senanl.returns = {[1]={rname="par1", rtype="int"}} --{[1]={rname="par1", rtype="int"}, [2]={rname="par2", rtype="int"}} --two return -api.senanl.call = function (idPin) - device:send(string.char(0x00, idPin)) -- codigo de operacion 0 - local sen_anl_response = device:read(3) - local raw_val - if not sen_anl_response or string.byte(sen_anl_response or "00000000", 2) == nil or string.byte(sen_anl_response or "00000000", 3) == nil - then - raw_val = "nil value" - else - raw_val = string.byte(sen_anl_response or "00000000", 2)* 256 + string.byte(sen_anl_response or "00000000", 3) - end - --local raw_val2 = string.byte(set_anl_response or " ", 3) - return raw_val --string.char(raw_val ,raw_val2) -end - -api.sendig = {} -api.sendig.parameters = {[1]={rname="idPin", rtype="int"}} -- el parámetro indica el pin que queremos leer de la arduino -api.sendig.returns = {[1]={rname="lecturaSensor", rtype="int"}} -api.sendig.call = function (idPin) - device:send(string.char(0x01, idPin)) -- codigo de operacion 1 - local sen_dig_response = device:read(3) - local raw_val - --if not sen_dig_response - --then - -- raw_val = "nil value" - --else - raw_val = string.byte(sen_dig_response or "0000", 2)* 256 + string.byte(sen_dig_response or "0000", 3) + 0 - --end - return raw_val - -end - - ---api.seni2c = {} ---api.seni2c.parameters = {} -- no params ---api.seni2c.returns = {[1]={rname="par1", rtype="int"}, [2]={rname="par2", rtype="int"}} --two return ---api.seni2c.call = function () --- local get_sen_i2c = SET_I2C --- device:send(get_sen_i2c) --- local sen_i2c_response = device:read(2) --- local raw_val = string.byte(set_i2c_response, 2) --- return raw_val ---end - diff --git a/lib/support/drivers/stmtr.lua b/lib/support/drivers/stmtr.lua deleted file mode 100644 index 9bd9b40..0000000 --- a/lib/support/drivers/stmtr.lua +++ /dev/null @@ -1,46 +0,0 @@ -local device = _G - -api={} -api.rawspeed = {} -api.rawspeed.parameters = {[1]={rname="speed1", rtype="int", min=-5, max=5}, [2]={rname="speed2", rtype="int", min=-5, max=5}} -api.rawspeed.returns = {} -api.rawspeed.call = function (speed1, speed2) - local msg = string.char(0x02,speed1,speed2) - device:send(msg) - device:read() -end - -api.t0cfg = {} -api.t0cfg.parameters = {[1]={rname="t0_low", rtype="int", min=0, max=255}, [2]={rname="t0_high", rtype="int", min=0, max=255}} -api.t0cfg.returns = {} -api.t0cfg.call = function (t0_low, t0_high) - local msg = string.char(0x01,t0_low,t0_high) - device:send(msg) - device:read() -end - -api={} -api.speed = {} -api.speed.parameters = {[1]={rname="vel1", rtype="float", min=-127, max=127}, - [2]={rname="vel2", rtype="float", min=-127, max=127}} -api.speed.returns = {} -api.speed.call = function (vel1, vel2) - vel1=tonumber(vel1) - vel2=tonumber(vel2) - - local speed1, speed2 - if vel1>=0 then - speed1=vel1 - else - speed1=0xFF + vel1 + 1 - end - if vel2>=0 then - speed2=vel2 - else - speed2=0xFF + vel2 + 1 - end - - local msg = string.char(0x02,speed1,speed2) - device:send(msg) - device:read() -end diff --git a/lib/support/drivers/temp.lua b/lib/support/drivers/temp.lua deleted file mode 100644 index 09ffe9f..0000000 --- a/lib/support/drivers/temp.lua +++ /dev/null @@ -1,28 +0,0 @@ -local device = _G - -api={} -api.getTemp = {} -api.getTemp.parameters = {} -- -- no input parameters -api.getTemp.returns = {[1]={rname="par1", rtype="int"}} -api.getTemp.call = function () - device:send(string.char(0x00)) -- codigo de operacion 0 - local sen_anl_response = device:read(3) - local raw_val - if not sen_anl_response or string.byte(sen_anl_response or "00000000", 2) == nil or string.byte(sen_anl_response or "00000000", 3) == nil - then - raw_val = "nil value" - else - raw_val = string.byte(sen_anl_response, 2)* 256 + string.byte(sen_anl_response, 3) - - local aux = (raw_val * 500) / 1024 --- obtengo la temperatura en grados - - if aux > 180 then - raw_val = (raw_val * 45) / 1024 - else - raw_val = aux - end - - end - return raw_val - -end diff --git a/lib/support/drivers/temp_lubot.lua b/lib/support/drivers/temp_lubot.lua deleted file mode 100644 index dd22fc4..0000000 --- a/lib/support/drivers/temp_lubot.lua +++ /dev/null @@ -1,20 +0,0 @@ -local device = _G -local RD_TEMP = string.char(0x34, 0x02) -local char000 = string.char(0,0,0) - - -api={} -api.get_temperature = {} -api.get_temperature.parameters = {} --no parameters -api.get_temperature.returns = {[1]={rname="temperature", rtype="number"}} --one return -api.get_temperature.call = function () - local get_temp_payload = RD_TEMP - device:send(get_temp_payload) - local temperature_response = device:read(3) or char000 - local raw_val = string.byte(temperature_response, 2) + (string.byte(temperature_response, 3) * 256) - local raw_temp = raw_val / 8 - local deg_temp = raw_temp * 0.0625 - --print("rawval, deg_temp: ", raw_val, deg_temp) - return deg_temp -end - diff --git a/lib/support/lib/bobot_baseboard.lua b/lib/support/lib/bobot_baseboard.lua deleted file mode 100644 index 757731a..0000000 --- a/lib/support/lib/bobot_baseboard.lua +++ /dev/null @@ -1,393 +0,0 @@ -#!/usr/bin/lua - ---module(..., package.seeall); - -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] - -local bobot_device = require("bobot_device") -local bobot = require("bobot") - -local NULL_BYTE = string.char(0x00) -local DEFAULT_PACKET_SIZE = 0x04 -local GET_USER_MODULES_SIZE_COMMAND = string.char(0x05) -local GET_USER_MODULE_LINE_COMMAND = string.char(0x06) -local GET_HANDLER_SIZE_COMMAND = string.char(0x0A) -local GET_HANDLER_TYPE_COMMAND = string.char(0x0B) -local GET_LINES_RESPONSE_PACKET_SIZE = 5 -local GET_LINE_RESPONSE_PACKET_SIZE = 12 -local GET_HANDLER_TYPE_PACKET_SIZE = 5 -local GET_HANDLER_RESPONSE_PACKET_SIZE = 5 -- -local ADMIN_HANDLER_SEND_COMMAND = string.char(0x00) -local ADMIN_MODULE_IN_ENDPOINT = 0x01 -local ADMIN_MODULE_OUT_ENDPOINT = 0x81 -local GET_USER_MODULE_LINE_PACKET_SIZE = 0x05 -local CLOSEALL_BASE_BOARD_COMMAND = string.char(0x07) -local CLOSEALL_BASE_BOARD_RESPONSE_PACKET_SIZE = 5 -local TIMEOUT = 250 --ms -local MAX_RETRY = 5 - -local BaseBoard = {} - - ---executes s on the console and returns the output -local function run_shell (s) - local f = io.popen(s) -- runs command - local l = f:read("*a") -- read output of command - f:close() - return l -end - -openable = {} -hotplug = {} - -local function parse_drivers() - local driver_files=run_shell("sh -c 'ls "..my_path.."../drivers/*.lua 2> /dev/null'") - for filename in driver_files:gmatch('drivers%/(%S+)%.lua') do - --print ("Driver openable", filename) - openable[filename] = true - end - driver_files=run_shell("sh -c 'ls "..my_path.."../drivers/hotplug/*.lua 2> /dev/null'") - for filename in driver_files:gmatch('drivers%/hotplug%/(%S+)%.lua') do - --print ("Driver hotplug", filename) - hotplug[filename] = true - end -end -parse_drivers() - -local function load_modules(bb) - local retry = 0 - bb.modules = {} - - local n_modules=bb:get_user_modules_size() - while n_modules == nil and retry < MAX_RETRY do - n_modules=bb:get_user_modules_size() - bobot.debugprint("u4b:the module list size returned a nil value, trying to recover...") - retry = retry+1 - end - if not n_modules then return nil end - retry=0 - bobot.debugprint ("Reading modules:", n_modules) - for i = 1, n_modules do - local modulename=bb:get_user_module_line(i) - while modulename == nil and retry < MAX_RETRY do - bobot.debugprint("u4b:the module returned a nil value, trying to recover...") - modulename=bb:get_handler_type(i) - retry = retry+1 - end - if not modulename then return nil end - if openable[modulename] then - bb.modules[i]=modulename - local d = bobot_device:new({ - module=modulename, - --name=module, - baseboard=bb, - hotplug=false, - in_endpoint=0x01, out_endpoint=0x01, - }) -- in_endpoint=0x01, out_endpoint=0x01}) - bb.devices[d]=true - bb.devices[#bb.devices+1]=d - - bb.modules[modulename]=d - elseif hotplug[modulename] then - bb.modules[i]=modulename - bb.modules[modulename]=true - bb.hotplug = true -- bb has a hotplug module - else - bobot.debugprint("Loading modules: missing driver for",modulename) - end - end - return true -end - -local function load_module_handlers(bb) - local retry = 0 - - local n_module_handlers=bb:get_handler_size() - while n_module_handlers == nil and retry < MAX_RETRY do - n_module_handlers=bb:get_handler_size() - bobot.debugprint("u4b:the module handler list size returned a nil value, trying to recover...") - retry = retry+1 - end - if (not n_module_handlers) or (n_module_handlers > 32) then return nil end - retry=0 - bobot.debugprint ("Reading moduleshandlers:", n_module_handlers) - for i=1, n_module_handlers do - local t_handler = bb:get_handler_type(i) - while(t_handler == nil and retry < MAX_RETRY) do - bobot.debugprint("u4b:the module handler returned a nil value, trying to recover...") - t_handler = bb:get_handler_type(i) - retry = retry+1 - end - if not t_handler then return nil end - if t_handler<255 then - local modulename=bb.modules[t_handler+1] - local moduledev=bb.modules[modulename] - if type(moduledev)=='table' - and not moduledev.handler then - moduledev.handler=i-1 - elseif moduledev==true then - --name=name.."@"..(i-1) - local d = bobot_device:new({ - handler=i-1, - module=modulename, - --name=name, - baseboard=bb, - hotplug=(hotplug[modulename]), - in_endpoint=0x01, out_endpoint=0x01, - }) -- in_endpoint=0x01, out_endpoint=0x01}) - if d then - bb.devices[d]=true - bb.devices[#bb.devices+1]=d - end - else - bobot.debugprint ("No opened device!") - end - end - end - return true -end - - -function BaseBoard:refresh() - self.devices = {} - - if not load_modules(self) then - return nil,"failure reading modules" - end - - if not load_module_handlers(self) then - return nil,"failure reading module handlers" - end - return true -end - ---Instantiates BaseBoard object. ---Loads list of modules installed on baseboard -function BaseBoard:new(bb) - --parameters sanity check - assert(type(bb)=="table") - assert(type(bb.comms)=="table") - - --OO boilerplate - setmetatable(bb, self) - self.__index = self - - bb:refresh() - ---bobot.debugprint ('----------------') - --bb:force_close_all() ---bobot.debugprint ('================') - return bb -end - ---Closes all modules opened on baseboard -function BaseBoard:close() - --state sanity check - assert(type(self.devices)=="table") - - for _,d in ipairs(self.devices) do - if type(d.handler)=="number" then - bobot.debugprint ("closing", d.name, d.handler) - d:close() - end - end - - --TODO actually close the baseboard -end - ---returns number of modules present on baseboard -function BaseBoard:get_user_modules_size() - --state sanity check - assert(type(self.comms)=="table") - - local comms=self.comms - - -- In case of get_user_modules_size command is atended by admin module in handler 0 and send operation is 000 - - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. string.char(DEFAULT_PACKET_SIZE) .. NULL_BYTE - local admin_packet = GET_USER_MODULES_SIZE_COMMAND - local get_user_modules_size_packet = handler_packet .. admin_packet - - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, get_user_modules_size_packet, TIMEOUT) - if write_res then - local data, err = comms.read(ADMIN_MODULE_OUT_ENDPOINT, GET_LINES_RESPONSE_PACKET_SIZE, TIMEOUT) - if not data then - bobot.debugprint("u4b:get_user_modules_size:comunication with I/O board read error", err) - return 0 - else - local user_modules_size = string.byte(data, 5) - return user_modules_size - end - else - bobot.debugprint("u4b:get_user_modules_size:comunication with I/O board write error", write_res) - return 0 - end -end - ---returns thename of a given (by a 1-based index)module -function BaseBoard:get_user_module_line(index) - --state & parameter sanity check - assert(type(index)=="number") - assert(index>0) - assert(type(self.comms)=="table") - - - local comms=self.comms - - -- In case of get_user_module_line command is atended by admin module in handler 0 and send operation is 000 - local get_user_module_line_packet_length = string.char(GET_USER_MODULE_LINE_PACKET_SIZE) - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. get_user_module_line_packet_length .. NULL_BYTE - local admin_packet = GET_USER_MODULE_LINE_COMMAND .. string.char(index-1) - local get_user_module_line_packet = handler_packet .. admin_packet - - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, get_user_module_line_packet, TIMEOUT) - if write_res then - local data, err = comms.read(ADMIN_MODULE_OUT_ENDPOINT, GET_LINE_RESPONSE_PACKET_SIZE, TIMEOUT) - if not data then - bobot.debugprint("u4b:get_user_modules_line:comunication with I/O board read error", err) - return - end - --the name is between a header and a null - local end_mark = string.find(data, "\000", GET_USER_MODULE_LINE_PACKET_SIZE, true) - if not end_mark then - bobot.debugprint ("u4b:get_user_module_line:Error parsing module name") - return - end - local module_name = string.sub(data, GET_USER_MODULE_LINE_PACKET_SIZE, end_mark-1) - return module_name - else - bobot.debugprint("u4b:get_user_module_line:comunication with I/O board write error", write_res) - end -end - -function BaseBoard:get_handler_size() ------ NEW LISTI ------ - --state sanity check - assert(type(self.comms)=="table") - - local comms=self.comms - - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. string.char(DEFAULT_PACKET_SIZE) .. NULL_BYTE - local admin_packet = GET_HANDLER_SIZE_COMMAND - local get_handler_size_packet = handler_packet .. admin_packet - - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, get_handler_size_packet, TIMEOUT) - if write_res then - local data, err = comms.read(ADMIN_MODULE_OUT_ENDPOINT, GET_HANDLER_RESPONSE_PACKET_SIZE, TIMEOUT) - if not data then - bobot.debugprint("u4b:get_handler_size:comunication with I/O board read error", err) - return 0 - else - local handler_size = string.byte(data, 5) - return handler_size - end - else - bobot.debugprint("u4b:get_handler_type:comunication with I/O board write error", write_res) - end -end -function BaseBoard:get_handler_type(index) ------ NEW LISTI ------ - --state & parameter sanity check - assert(type(index)=="number") - assert(index>0) - assert(type(self.comms)=="table") - - local comms=self.comms - - -- In case of get_handler_type command is atended by admin module in handler 0 and send operation is 000 - local get_handler_type_packet_length = string.char(GET_HANDLER_TYPE_PACKET_SIZE) --GET_USER_MODULE_LINE_PACKET_SIZE - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. get_handler_type_packet_length .. NULL_BYTE - local admin_packet = GET_HANDLER_TYPE_COMMAND .. string.char(index-1) - local get_handler_type_packet = handler_packet .. admin_packet - - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, get_handler_type_packet, TIMEOUT) - if write_res then - local data, err = comms.read(ADMIN_MODULE_OUT_ENDPOINT, GET_HANDLER_RESPONSE_PACKET_SIZE, TIMEOUT) - if not data then - bobot.debugprint("u4b:get_handler_type:comunication with I/O board read error", err) - return 0 - else - local handler_type = string.byte(data, 5) - return handler_type - end - else - bobot.debugprint("u4b:get_handler_type:comunication with I/O board write error", write_res) - end -end - --- resets the baseboard, after this operation the baseboard will claim reenumeration to the operative system --- this function is deprecated by force_close_all -function BaseBoard:close_all() - for _,d in ipairs(self.devices) do - --bobot.debugprint ("===", d.name,d.handler) - if d.handler then d:close() end - end -end - --- switch the baseboard to the bootloader program implementend as a usb4all command to the admin module -function BaseBoard:switch_to_bootloader() - --state & parameter sanity check - assert(type(self.comms)=="table") - - local comms=self.comms - -- In case of reset_base_board command is atended by admin module in handler 0 and send operation is 000 - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. string.char(DEFAULT_PACKET_SIZE) .. NULL_BYTE - local admin_packet = string.char(0x09) --SWITCH_TO_BOOT_BASE_BOARD_COMMAND - local boot_base_board_packet = handler_packet .. admin_packet - - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, boot_base_board_packet, TIMEOUT) - --from this moment the board is reseted, so there is nothing more to do -end - -function BaseBoard:reset() - --state & parameter sanity check - assert(type(self.comms)=="table") - - local comms=self.comms - -- In case of reset_base_board command is atended by admin module in handler 0 and send operation is 000 - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. string.char(DEFAULT_PACKET_SIZE) .. NULL_BYTE - local admin_packet = string.char(0xFF) --RESET_BASE_BOARD_COMMAND - local reset_base_board_packet = handler_packet .. admin_packet - - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, reset_base_board_packet, TIMEOUT) - if write_res then - -- no tego que leer respuesta porque se reseteo - --libusb.close(libusb_handler) - --self.libusb_handler=nil - --for d_name,d in pairs(self.devices) do - --bobot.debugprint ("===", d.name,d.handler) - -- d.handler=nil - --end - else - bobot.debugprint("u4b:reset:comunication with I/O board write error", write_res) - end -end - -function BaseBoard:force_close_all() - --state & parameter sanity check - assert(type(self.comms)=="table") - - local comms=self.comms - -- In case of reset_base_board command is atended by admin module in handler 0 and send operation is 000 - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. string.char(DEFAULT_PACKET_SIZE) .. NULL_BYTE - local admin_packet = CLOSEALL_BASE_BOARD_COMMAND - local reset_base_board_packet = handler_packet .. admin_packet - ---bobot.debugprint ('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') - local write_res = comms.send(ADMIN_MODULE_IN_ENDPOINT, reset_base_board_packet, TIMEOUT) ---bobot.debugprint ('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') - if write_res then - local data, err = comms.read(ADMIN_MODULE_OUT_ENDPOINT, CLOSEALL_BASE_BOARD_RESPONSE_PACKET_SIZE, TIMEOUT) - if err then - bobot.debugprint("u4b:force_close_all:comunication with I/O board read error",err) - else - --bobot.debugprint("u4b:force_close_all:libusb read",string.byte(data,1,string.len(data))) - end - for _,d in ipairs(self.devices) do - --bobot.debugprint ("===", d.name,d.handler) - d.handler=nil - end - else - bobot.debugprint("u4b:force_close_all:comunication with I/O board write error", write_res) - end -end - -return BaseBoard diff --git a/lib/support/lib/bobot_device.lua b/lib/support/lib/bobot_device.lua deleted file mode 100644 index b560255..0000000 --- a/lib/support/lib/bobot_device.lua +++ /dev/null @@ -1,216 +0,0 @@ ---module(..., package.seeall); - -local bobot = require("bobot") - -local string_char = string.char -local string_len = string.len -local string_byte = string.byte - -local OPEN_COMMAND = string_char(0x00) -local CLOSE_COMMAND = string_char(0x01) -local HEADER_PACKET_SIZE = 6 -local NULL_BYTE = string_char(0x00) -local ADMIN_MODULE_IN_ENDPOINT = 0x01 -local ADMIN_MODULE_OUT_ENDPOINT = 0x81 -local ADMIN_HANDLER_SEND_COMMAND = string_char(0x00) -local OPEN_RESPONSE_PACKET_SIZE = 5 -local CLOSE_RESPONSE_PACKET_SIZE = 2 -local TIMEOUT = 200 --ms - -local READ_HEADER_SIZE = 3 - -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] - -local Device = { - --some usefull stuff for the drivers to use - string=string, - print=bobot.debugprint, - math=math, - tonumber=tonumber, - tostring=tostring -} - - -local drivers_cache = setmetatable({}, {__mode='kv'}) -local function load_driver(d) - local modulename=d.module - if drivers_cache[modulename] then return drivers_cache[modulename] end - - local drivername=string.match(modulename, '^(.-)%d*$') - local f, err - if d.hotplug then - f, err = loadfile(my_path.."../drivers/hotplug/"..drivername..".lua") - else - f, err = loadfile(my_path.."../drivers/"..drivername..".lua") - end - drivers_cache[modulename] = f - return f, err -end - ---Instantiates Device object. ---Attempts to load api from driver -function Device:new(d) - --parameters sanity check - assert(type(d)=="table") - --assert(type(d.name)=="string") - assert(type(d.module)=="string") - assert(type(d.baseboard)=="table") - assert(type(d.baseboard.comms)=="table") - assert(type(d.baseboard.comms.send)=="function") - assert(type(d.baseboard.comms.read)=="function") - - --OO boilerplate - setmetatable(d, self) - self.__index = self - - --store locally, save 2 indirections - d.comms_send = d.baseboard.comms.send - d.comms_read = d.baseboard.comms.read - - --attempt to load api from driver - local f, err = load_driver(d) - if f then - d._G=d - - setfenv(f, d) --the driver's environment is the device - local status, err=pcall(f) - if status then - bobot.debugprint("u4d:new:Success loading driver:", d.module) - else - bobot.debugprint("u4d:new:Error initializing driver:", tostring(err)) - end - else - bobot.debugprint("u4d:new:Error loading driver:", err) - return nil - end - - return d -end - ---opens the device. must be done before sending / reading / etc. ---receives endpoints, which can be ommited if they were provided at Device creation -function Device:open(in_endpoint, out_endpoint) - --state & parameter sanity check - assert(self.handler==nil) - --assert(type(self.name)=="string") - assert(type(in_endpoint)=="number" or type(self.in_endpoint)=="number") - assert(type(self.comms_send)=="function") - assert(type(self.comms_read)=="function") - assert(type(out_endpoint)=="number" or type(self.out_endpoint)=="number") - - --save for later use - if in_endpoint then self.in_endpoint = in_endpoint end - if out_endpoint then self.out_endpoint = out_endpoint end - - local module_name=self.module .."\000" -- usb4all expect null terminated names - - local open_packet_length = string_char(HEADER_PACKET_SIZE + string_len(module_name)) - - local module_in_endpoint = string_char(self.in_endpoint) - local module_out_endpoint = string_char(self.out_endpoint) - - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. open_packet_length .. NULL_BYTE - local admin_packet = OPEN_COMMAND .. module_in_endpoint .. module_out_endpoint .. module_name - local open_packet = handler_packet .. admin_packet - local write_res = self.comms_send(ADMIN_MODULE_IN_ENDPOINT, open_packet, TIMEOUT) - - if not write_res then - bobot.debugprint("u4d:open:comunication with I/O board write error", write_res) - return false - end - - local data, err = self.comms_read(ADMIN_MODULE_OUT_ENDPOINT, OPEN_RESPONSE_PACKET_SIZE, TIMEOUT) - if not data then - bobot.debugprint ("u4d:open:comunication with I/O boardread error", err) - return false - end - - local handler = string_byte(data, 5) - --hander -1 meand error - if handler==255 then - bobot.debugprint ("u4d:open:Already open!",self.module,self.handler) - return - else - bobot.debugprint ("u4d:open:Success!",self.module,handler) - self.handler = handler --self.handler set means device is open - return true - end - -end - ---closes the device -function Device:close() - if not self.handler then return end --already closed - - --state sanity check - assert(type(self.handler)=="number") - assert(type(self.comms_send)=="function") - assert(type(self.comms_read)=="function") - - local close_packet_length = string_char(0x04) --string.char(HEADER_PACKET_SIZE + string.len(module_name)) - local handler_packet = ADMIN_HANDLER_SEND_COMMAND .. close_packet_length .. NULL_BYTE - local admin_packet = CLOSE_COMMAND .. string_char(self.handler) - local close_packet = handler_packet .. admin_packet - - local write_res = self.comms_send(ADMIN_MODULE_IN_ENDPOINT, close_packet, TIMEOUT) - if not write_res then - bobot.debugprint("u4d:close:comunication with I/O board write error", write_res) - return - end - local data, err = self.comms_read(ADMIN_MODULE_OUT_ENDPOINT, CLOSE_RESPONSE_PACKET_SIZE, TIMEOUT) - - self.handler = nil -end - ---sends data (a string) to device -function Device:send(data) - --state & parameter sanity check - data=tostring(data) - assert(type(data)=="string") - assert(type(self.handler)=="number") - assert(type(self.in_endpoint)=="number") - assert(type(self.comms_send)=="function") - assert(type(self.comms_read)=="function") - - local len=string_len(data) - - local shifted_handler = self.handler * 8 - assert(shifted_handler<256, "u4d:send:shifted_handler vale " .. shifted_handler .. " excede el tamaño maximo representable en un byte (255)") - local user_module_handler_send_command = string_char(shifted_handler) - local send_packet_length = string_char(0x03 + len) - local send_packet = user_module_handler_send_command .. send_packet_length .. NULL_BYTE .. data - - --local tini=socket.gettime() - local write_res, err = self.comms_send(self.in_endpoint, send_packet, TIMEOUT) - --bobot.debugprint ('%%%%%%%%%%%%%%%% device send',socket.gettime()-tini) - - if not write_res then - bobot.debugprint("u4d:send:comunication with I/O board write error", err) - end - - return write_res, err -end - ---read data (len bytes max) from device -function Device:read(len) - len = len or 255 - --state & parameter sanity check - assert(type(len)=="number") - assert(type(self.handler)=="number") - assert(type(self.out_endpoint)=="number") - assert(type(self.comms_send)=="function") - assert(type(self.comms_read)=="function") - - local data, err = self.comms_read(self.out_endpoint, len+READ_HEADER_SIZE, TIMEOUT) - if not data then - bobot.debugprint("u4d:read:comunication with I/O board read error", err) - return nil, err - end - - local data_h = string.sub(data, READ_HEADER_SIZE+1, -1) --discard header - - return data_h, err -end - -return Device - diff --git a/lib/support/lib/comms_chotox.lua b/lib/support/lib/comms_chotox.lua deleted file mode 100644 index 18e02bf..0000000 --- a/lib/support/lib/comms_chotox.lua +++ /dev/null @@ -1,39 +0,0 @@ -local bobot_device = require("bobot_device") - -local comms_chotox = {} - -function comms_chotox.send(endpoint, data, timeout) -end - -function comms_chotox.read(endpoint, len, timeout) -end - - -function comms_chotox.init(baseboards) - --parameters sanity check - assert(type(baseboards)=="table") - - local n_boards=1 - --local bb = bobot_baseboard.BaseBoard:new({idBoard=iSerial, comms=comms_usb}) - local bb = {idBoard=1, comms=comms_chotox} - local devices={} - local is_hotplug= {button=true, led=true, grey=true, distanc=true} - for i, name in ipairs({"button", "grey", "distanc","butia"}) do - local dd={name=name, module=name, baseboard=bb, handler=i} - dd.open = function() return true end - dd.close = function() end - dd.read = function() return "" end - dd.send = function() return true end - if is_hotplug[name] then dd.hotplug=true end - - local d = bobot_device:new(dd) -- in_endpoint=0x01, out_endpoint=0x01}) - - devices[name]=true - devices[#devices+1]=d - end - bb.devices=devices - baseboards[1]=bb - return n_boards -end - -return comms_chotox diff --git a/lib/support/lib/comms_serial.lua b/lib/support/lib/comms_serial.lua deleted file mode 100644 index 4bd3bb0..0000000 --- a/lib/support/lib/comms_serial.lua +++ /dev/null @@ -1,94 +0,0 @@ ---module(..., package.seeall); - ---local socket=require("socket") - -local bobot_baseboard = require("bobot_baseboard") -local bobot = require("bobot") - -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] -assert(package.loadlib(my_path .. "lua_serialcomm.so","luaopen_serialcomm"))() -local serialcomm=_G.serialcomm; _G.serialcomm=nil - -local serial_handler - ---executes s on the console and returns the output -local function run_shell (s) - local f = io.popen(s) -- runs command - local l = f:read("*a") -- read output of command - f:close() - return l -end - -local function split_words(s) - local words={} - for p in string.gmatch(s, "%S+") do - words[#words+1]=p - end - return words -end - -local comms_serial = {} - -function comms_serial.send(endpoint, data, timeout) - --parameters sanity check - assert(type(serial_handler)=="number") - --assert(type(endpoint)=="number") - assert(type(data)=="string") - assert(type(timeout)=="number") - - --local tini=socket.gettime() - local ret = serialcomm.send_msg(serial_handler, data) - --bobot.debugprint ('%%%%%%%%%%%%%%%% comms serial send',socket.gettime()-tini) - return ret -end - -function comms_serial.read(endpoint, len, timeout) - --parameters sanity check - assert(type(serial_handler)=="number") - --assert(type(endpoint)=="number") - --assert(type(len)=="number") - --assert(type(timeout)=="number") - - return serialcomm.read_msg(serial_handler, len, timeout) -end - - -function comms_serial.init(baseboards) - --parameters sanity check - assert(type(baseboards)=="table") - - --FIXME leer ttyusbs... - --local tty_s=run_shell("ls /dev/ttyUSB* ") - local tty_s=run_shell("sh -c 'ls /dev/ttyUSB* 2> /dev/null'") --supress errors - local tty_t=split_words(tty_s) - local tty - local err - if (#tty_t == 0) then - return 0,"no ttyUSB found" - end - - -- tty="/dev/ttyUSB0" - --for i=1, #tty_t do - for _, ttyI in ipairs(tty_t) do - bobot.debugprint ("Trying to connect to", ttyI) - serial_handler, err = serialcomm.init(ttyI, 115200) - if serial_handler then - tty=ttyI - break - else - bobot.debugprint("Error connecting:", err) - end - end - if not serial_handler then - bobot.debugprint("cs:", "no ttyUSB could be open") - return 0, err - end - bobot.debugprint ("cs:", tty) - local bb = bobot_baseboard:new({idBoard=tty, comms=comms_serial}) - - baseboards[#baseboards+1]=bb - - return 1 -end - -return comms_serial diff --git a/lib/support/lib/comms_usb.lua b/lib/support/lib/comms_usb.lua deleted file mode 100644 index 91d64b5..0000000 --- a/lib/support/lib/comms_usb.lua +++ /dev/null @@ -1,99 +0,0 @@ ---module(..., package.seeall); - -local bobot_baseboard = require("bobot_baseboard") -local bobot = require("bobot") - -local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] -assert(package.loadlib(my_path .. "libluausb.so","luaopen_libusb"))() -local libusb=_G.libusb; _G.libusb=nil - -local usb_bulk_write = libusb.bulk_write -local usb_bulk_read = libusb.bulk_read - -local USB4ALL_VENDOR = 0x04d8 -local USB4ALL_PRODUCT = 0x000c -local USB4ALL_CONFIGURATION = 1 -local USB4ALL_INTERFACE = 0 - -local READ_HEADER_SIZE = 3 - -local libusb_handler - - -local comms_usb = {} - -function comms_usb.send(endpoint, data, timeout) - --parameters sanity check - assert(type(libusb_handler)=="userdata") - assert(type(endpoint)=="number") - assert(type(data)=="string") - assert(type(timeout)=="number") - - return usb_bulk_write(libusb_handler, endpoint, data, timeout) -end - -function comms_usb.read(endpoint, len, timeout) - --parameters sanity check - assert(type(libusb_handler)=="userdata") - assert(type(endpoint)=="number") - assert(type(len)=="number") - assert(type(timeout)=="number") - - return usb_bulk_read(libusb_handler, endpoint, len+READ_HEADER_SIZE, timeout) -end - - -function comms_usb.init(baseboards) - --parameters sanity check - assert(type(baseboards)=="table") - - - --refresh devices and buses - libusb.find_busses() - libusb.find_devices() - local n_boards = 0 - - local buses=libusb.get_busses() - for dirname, bus in pairs(buses) do --iterate buses - local devices=libusb.get_devices(bus) - for filename, device in pairs(devices) do --iterate devices - local descriptor = libusb.device_descriptor(device) - - --if device is baseboard... - if ((descriptor.idVendor == USB4ALL_VENDOR) and (descriptor.idProduct == USB4ALL_PRODUCT)) then - --try to intialize baseboard - bobot.debugprint("Initializing Baseboard:", descriptor.idVendor, descriptor.idProduct) - libusb_handler = libusb.open(device) - - if not libusb_handler then - bobot.debugprint("Error opening device") - break - end - if not libusb.set_configuration(libusb_handler, USB4ALL_CONFIGURATION) then - bobot.debugprint("Error configuring device, retrying after a reset") - libusb.reset(libusb_handler) - if not libusb.set_configuration(libusb_handler, USB4ALL_CONFIGURATION) then - bobot.debugprint("Error configuring device.") - break - end - end - if not libusb.claim_interface(libusb_handler, USB4ALL_INTERFACE) then - bobot.debugprint("Error seting device interface") - break - end - - --success initializing, instantiate BaseBoard object and register - local iSerial=descriptor.iSerialNumber - local bb = bobot_baseboard:new({idBoard=iSerial, comms=comms_usb}) - --bb:force_close_all() - --bobot.debugprint("Baseboard:", iSerial) - - baseboards[#baseboards+1]=bb - n_boards = n_boards + 1 - end - end - end - return n_boards -end - -return comms_usb diff --git a/lib/support/lib/libluausb.so b/lib/support/lib/libluausb.so deleted file mode 100755 index a7c9406..0000000 --- a/lib/support/lib/libluausb.so +++ /dev/null Binary files differ diff --git a/lib/support/lib/lua_serialcomm.so b/lib/support/lib/lua_serialcomm.so deleted file mode 100755 index cb79295..0000000 --- a/lib/support/lib/lua_serialcomm.so +++ /dev/null Binary files differ diff --git a/lib/support/lib/mime/core.so b/lib/support/lib/mime/core.so deleted file mode 100755 index 696b7d9..0000000 --- a/lib/support/lib/mime/core.so +++ /dev/null Binary files differ diff --git a/lib/support/lib/socket/core.so b/lib/support/lib/socket/core.so deleted file mode 100755 index ddfc8c3..0000000 --- a/lib/support/lib/socket/core.so +++ /dev/null Binary files differ diff --git a/lib/support/libluausb.so b/lib/support/libluausb.so deleted file mode 100755 index a7c9406..0000000 --- a/lib/support/libluausb.so +++ /dev/null Binary files differ diff --git a/lib/support/lua b/lib/support/lua deleted file mode 100755 index a36f550..0000000 --- a/lib/support/lua +++ /dev/null Binary files differ diff --git a/lib/support/lua_serialcomm.so b/lib/support/lua_serialcomm.so deleted file mode 100755 index cb79295..0000000 --- a/lib/support/lua_serialcomm.so +++ /dev/null Binary files differ diff --git a/lib/support/share/ltn12.lua b/lib/support/share/ltn12.lua deleted file mode 100644 index b42689a..0000000 --- a/lib/support/share/ltn12.lua +++ /dev/null @@ -1,292 +0,0 @@ ------------------------------------------------------------------------------ --- LTN12 - Filters, sources, sinks and pumps. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local table = require("table") -local base = _G -module("ltn12") - -filter = {} -source = {} -sink = {} -pump = {} - --- 2048 seems to be better in windows... -BLOCKSIZE = 2048 -_VERSION = "LTN12 1.0.1" - ------------------------------------------------------------------------------ --- Filter stuff ------------------------------------------------------------------------------ --- returns a high level filter that cycles a low-level filter -function filter.cycle(low, ctx, extra) - base.assert(low) - return function(chunk) - local ret - ret, ctx = low(ctx, chunk, extra) - return ret - end -end - --- chains a bunch of filters together --- (thanks to Wim Couwenberg) -function filter.chain(...) - local n = table.getn(arg) - local top, index = 1, 1 - local retry = "" - return function(chunk) - retry = chunk and retry - while true do - if index == top then - chunk = arg[index](chunk) - if chunk == "" or top == n then return chunk - elseif chunk then index = index + 1 - else - top = top+1 - index = top - end - else - chunk = arg[index](chunk or "") - if chunk == "" then - index = index - 1 - chunk = retry - elseif chunk then - if index == n then return chunk - else index = index + 1 end - else base.error("filter returned inappropriate nil") end - end - end - end -end - ------------------------------------------------------------------------------ --- Source stuff ------------------------------------------------------------------------------ --- create an empty source -local function empty() - return nil -end - -function source.empty() - return empty -end - --- returns a source that just outputs an error -function source.error(err) - return function() - return nil, err - end -end - --- creates a file source -function source.file(handle, io_err) - if handle then - return function() - local chunk = handle:read(BLOCKSIZE) - if not chunk then handle:close() end - return chunk - end - else return source.error(io_err or "unable to open file") end -end - --- turns a fancy source into a simple source -function source.simplify(src) - base.assert(src) - return function() - local chunk, err_or_new = src() - src = err_or_new or src - if not chunk then return nil, err_or_new - else return chunk end - end -end - --- creates string source -function source.string(s) - if s then - local i = 1 - return function() - local chunk = string.sub(s, i, i+BLOCKSIZE-1) - i = i + BLOCKSIZE - if chunk ~= "" then return chunk - else return nil end - end - else return source.empty() end -end - --- creates rewindable source -function source.rewind(src) - base.assert(src) - local t = {} - return function(chunk) - if not chunk then - chunk = table.remove(t) - if not chunk then return src() - else return chunk end - else - table.insert(t, chunk) - end - end -end - -function source.chain(src, f) - base.assert(src and f) - local last_in, last_out = "", "" - local state = "feeding" - local err - return function() - if not last_out then - base.error('source is empty!', 2) - end - while true do - if state == "feeding" then - last_in, err = src() - if err then return nil, err end - last_out = f(last_in) - if not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - elseif last_out ~= "" then - state = "eating" - if last_in then last_in = "" end - return last_out - end - else - last_out = f(last_in) - if last_out == "" then - if last_in == "" then - state = "feeding" - else - base.error('filter returned ""') - end - elseif not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - else - return last_out - end - end - end - end -end - --- creates a source that produces contents of several sources, one after the --- other, as if they were concatenated --- (thanks to Wim Couwenberg) -function source.cat(...) - local src = table.remove(arg, 1) - return function() - while src do - local chunk, err = src() - if chunk then return chunk end - if err then return nil, err end - src = table.remove(arg, 1) - end - end -end - ------------------------------------------------------------------------------ --- Sink stuff ------------------------------------------------------------------------------ --- creates a sink that stores into a table -function sink.table(t) - t = t or {} - local f = function(chunk, err) - if chunk then table.insert(t, chunk) end - return 1 - end - return f, t -end - --- turns a fancy sink into a simple sink -function sink.simplify(snk) - base.assert(snk) - return function(chunk, err) - local ret, err_or_new = snk(chunk, err) - if not ret then return nil, err_or_new end - snk = err_or_new or snk - return 1 - end -end - --- creates a file sink -function sink.file(handle, io_err) - if handle then - return function(chunk, err) - if not chunk then - handle:close() - return 1 - else return handle:write(chunk) end - end - else return sink.error(io_err or "unable to open file") end -end - --- creates a sink that discards data -local function null() - return 1 -end - -function sink.null() - return null -end - --- creates a sink that just returns an error -function sink.error(err) - return function() - return nil, err - end -end - --- chains a sink with a filter -function sink.chain(f, snk) - base.assert(f and snk) - return function(chunk, err) - if chunk ~= "" then - local filtered = f(chunk) - local done = chunk and "" - while true do - local ret, snkerr = snk(filtered, err) - if not ret then return nil, snkerr end - if filtered == done then return 1 end - filtered = f(done) - end - else return 1 end - end -end - ------------------------------------------------------------------------------ --- Pump stuff ------------------------------------------------------------------------------ --- pumps one chunk from the source to the sink -function pump.step(src, snk) - local chunk, src_err = src() - local ret, snk_err = snk(chunk, src_err) - if chunk and ret then return 1 - else return nil, src_err or snk_err end -end - --- pumps all data from a source to a sink, using a step function -function pump.all(src, snk, step) - base.assert(src and snk) - step = step or pump.step - while true do - local ret, err = step(src, snk) - if not ret then - if err then return nil, err - else return 1 end - end - end -end - diff --git a/lib/support/share/mime.lua b/lib/support/share/mime.lua deleted file mode 100644 index 169eda2..0000000 --- a/lib/support/share/mime.lua +++ /dev/null @@ -1,87 +0,0 @@ ------------------------------------------------------------------------------ --- MIME support for the Lua language. --- Author: Diego Nehab --- Conforming to RFCs 2045-2049 --- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local ltn12 = require("ltn12") -local mime = require("mime.core") -local io = require("io") -local string = require("string") -module("mime") - --- encode, decode and wrap algorithm tables -encodet = {} -decodet = {} -wrapt = {} - --- creates a function that chooses a filter by name from a given table -local function choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then - base.error("unknown key (" .. base.tostring(name) .. ")", 3) - else return f(opt1, opt2) end - end -end - --- define the encoding filters -encodet['base64'] = function() - return ltn12.filter.cycle(b64, "") -end - -encodet['quoted-printable'] = function(mode) - return ltn12.filter.cycle(qp, "", - (mode == "binary") and "=0D=0A" or "\r\n") -end - --- define the decoding filters -decodet['base64'] = function() - return ltn12.filter.cycle(unb64, "") -end - -decodet['quoted-printable'] = function() - return ltn12.filter.cycle(unqp, "") -end - -local function format(chunk) - if chunk then - if chunk == "" then return "''" - else return string.len(chunk) end - else return "nil" end -end - --- define the line-wrap filters -wrapt['text'] = function(length) - length = length or 76 - return ltn12.filter.cycle(wrp, length, length) -end -wrapt['base64'] = wrapt['text'] -wrapt['default'] = wrapt['text'] - -wrapt['quoted-printable'] = function() - return ltn12.filter.cycle(qpwrp, 76, 76) -end - --- function that choose the encoding, decoding or wrap algorithm -encode = choose(encodet) -decode = choose(decodet) -wrap = choose(wrapt) - --- define the end-of-line normalization filter -function normalize(marker) - return ltn12.filter.cycle(eol, 0, marker) -end - --- high level stuffing filter -function stuff() - return ltn12.filter.cycle(dot, 2) -end diff --git a/lib/support/share/socket.lua b/lib/support/share/socket.lua deleted file mode 100644 index 211adcd..0000000 --- a/lib/support/share/socket.lua +++ /dev/null @@ -1,133 +0,0 @@ ------------------------------------------------------------------------------ --- LuaSocket helper module --- Author: Diego Nehab --- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local math = require("math") -local socket = require("socket.core") -module("socket") - ------------------------------------------------------------------------------ --- Exported auxiliar functions ------------------------------------------------------------------------------ -function connect(address, port, laddress, lport) - local sock, err = socket.tcp() - if not sock then return nil, err end - if laddress then - local res, err = sock:bind(laddress, lport, -1) - if not res then return nil, err end - end - local res, err = sock:connect(address, port) - if not res then return nil, err end - return sock -end - -function bind(host, port, backlog) - local sock, err = socket.tcp() - if not sock then return nil, err end - sock:setoption("reuseaddr", true) - local res, err = sock:bind(host, port) - if not res then return nil, err end - res, err = sock:listen(backlog) - if not res then return nil, err end - return sock -end - -try = newtry() - -function choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) - else return f(opt1, opt2) end - end -end - ------------------------------------------------------------------------------ --- Socket sources and sinks, conforming to LTN12 ------------------------------------------------------------------------------ --- create namespaces inside LuaSocket namespace -sourcet = {} -sinkt = {} - -BLOCKSIZE = 2048 - -sinkt["close-when-done"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then - sock:close() - return 1 - else return sock:send(chunk) end - end - }) -end - -sinkt["keep-open"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if chunk then return sock:send(chunk) - else return 1 end - end - }) -end - -sinkt["default"] = sinkt["keep-open"] - -sink = choose(sinkt) - -sourcet["by-length"] = function(sock, length) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if length <= 0 then return nil end - local size = math.min(socket.BLOCKSIZE, length) - local chunk, err = sock:receive(size) - if err then return nil, err end - length = length - string.len(chunk) - return chunk - end - }) -end - -sourcet["until-closed"] = function(sock) - local done - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if done then return nil end - local chunk, err, partial = sock:receive(socket.BLOCKSIZE) - if not err then return chunk - elseif err == "closed" then - sock:close() - done = 1 - return partial - else return nil, err end - end - }) -end - - -sourcet["default"] = sourcet["until-closed"] - -source = choose(sourcet) - diff --git a/lib/support/share/socket/ftp.lua b/lib/support/share/socket/ftp.lua deleted file mode 100644 index 598f65d..0000000 --- a/lib/support/share/socket/ftp.lua +++ /dev/null @@ -1,281 +0,0 @@ ------------------------------------------------------------------------------ --- FTP support for the Lua language --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local table = require("table") -local string = require("string") -local math = require("math") -local socket = require("socket") -local url = require("socket.url") -local tp = require("socket.tp") -local ltn12 = require("ltn12") -module("socket.ftp") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- timeout in seconds before the program gives up on a connection -TIMEOUT = 60 --- default port for ftp service -PORT = 21 --- this is the default anonymous password. used when no password is --- provided in url. should be changed to your e-mail. -USER = "ftp" -PASSWORD = "anonymous@anonymous.org" - ------------------------------------------------------------------------------ --- Low level FTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function open(server, port, create) - local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create)) - local f = base.setmetatable({ tp = tp }, metat) - -- make sure everything gets closed in an exception - f.try = socket.newtry(function() f:close() end) - return f -end - -function metat.__index:portconnect() - self.try(self.server:settimeout(TIMEOUT)) - self.data = self.try(self.server:accept()) - self.try(self.data:settimeout(TIMEOUT)) -end - -function metat.__index:pasvconnect() - self.data = self.try(socket.tcp()) - self.try(self.data:settimeout(TIMEOUT)) - self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) -end - -function metat.__index:login(user, password) - self.try(self.tp:command("user", user or USER)) - local code, reply = self.try(self.tp:check{"2..", 331}) - if code == 331 then - self.try(self.tp:command("pass", password or PASSWORD)) - self.try(self.tp:check("2..")) - end - return 1 -end - -function metat.__index:pasv() - self.try(self.tp:command("pasv")) - local code, reply = self.try(self.tp:check("2..")) - local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" - local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) - self.try(a and b and c and d and p1 and p2, reply) - self.pasvt = { - ip = string.format("%d.%d.%d.%d", a, b, c, d), - port = p1*256 + p2 - } - if self.server then - self.server:close() - self.server = nil - end - return self.pasvt.ip, self.pasvt.port -end - -function metat.__index:port(ip, port) - self.pasvt = nil - if not ip then - ip, port = self.try(self.tp:getcontrol():getsockname()) - self.server = self.try(socket.bind(ip, 0)) - ip, port = self.try(self.server:getsockname()) - self.try(self.server:settimeout(TIMEOUT)) - end - local pl = math.mod(port, 256) - local ph = (port - pl)/256 - local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") - self.try(self.tp:command("port", arg)) - self.try(self.tp:check("2..")) - return 1 -end - -function metat.__index:send(sendt) - self.try(self.pasvt or self.server, "need port or pasv first") - -- if there is a pasvt table, we already sent a PASV command - -- we just get the data connection into self.data - if self.pasvt then self:pasvconnect() end - -- get the transfer argument and command - local argument = sendt.argument or - url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) - if argument == "" then argument = nil end - local command = sendt.command or "stor" - -- send the transfer command and check the reply - self.try(self.tp:command(command, argument)) - local code, reply = self.try(self.tp:check{"2..", "1.."}) - -- if there is not a a pasvt table, then there is a server - -- and we already sent a PORT command - if not self.pasvt then self:portconnect() end - -- get the sink, source and step for the transfer - local step = sendt.step or ltn12.pump.step - local readt = {self.tp.c} - local checkstep = function(src, snk) - -- check status in control connection while downloading - local readyt = socket.select(readt, nil, 0) - if readyt[tp] then code = self.try(self.tp:check("2..")) end - return step(src, snk) - end - local sink = socket.sink("close-when-done", self.data) - -- transfer all data and check error - self.try(ltn12.pump.all(sendt.source, sink, checkstep)) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - -- done with data connection - self.data:close() - -- find out how many bytes were sent - local sent = socket.skip(1, self.data:getstats()) - self.data = nil - return sent -end - -function metat.__index:receive(recvt) - self.try(self.pasvt or self.server, "need port or pasv first") - if self.pasvt then self:pasvconnect() end - local argument = recvt.argument or - url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) - if argument == "" then argument = nil end - local command = recvt.command or "retr" - self.try(self.tp:command(command, argument)) - local code = self.try(self.tp:check{"1..", "2.."}) - if not self.pasvt then self:portconnect() end - local source = socket.source("until-closed", self.data) - local step = recvt.step or ltn12.pump.step - self.try(ltn12.pump.all(source, recvt.sink, step)) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - self.data:close() - self.data = nil - return 1 -end - -function metat.__index:cwd(dir) - self.try(self.tp:command("cwd", dir)) - self.try(self.tp:check(250)) - return 1 -end - -function metat.__index:type(type) - self.try(self.tp:command("type", type)) - self.try(self.tp:check(200)) - return 1 -end - -function metat.__index:greet() - local code = self.try(self.tp:check{"1..", "2.."}) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - return 1 -end - -function metat.__index:quit() - self.try(self.tp:command("quit")) - self.try(self.tp:check("2..")) - return 1 -end - -function metat.__index:close() - if self.data then self.data:close() end - if self.server then self.server:close() end - return self.tp:close() -end - ------------------------------------------------------------------------------ --- High level FTP API ------------------------------------------------------------------------------ -local function override(t) - if t.url then - local u = url.parse(t.url) - for i,v in base.pairs(t) do - u[i] = v - end - return u - else return t end -end - -local function tput(putt) - putt = override(putt) - socket.try(putt.host, "missing hostname") - local f = open(putt.host, putt.port, putt.create) - f:greet() - f:login(putt.user, putt.password) - if putt.type then f:type(putt.type) end - f:pasv() - local sent = f:send(putt) - f:quit() - f:close() - return sent -end - -local default = { - path = "/", - scheme = "ftp" -} - -local function parse(u) - local t = socket.try(url.parse(u, default)) - socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") - socket.try(t.host, "missing hostname") - local pat = "^type=(.)$" - if t.params then - t.type = socket.skip(2, string.find(t.params, pat)) - socket.try(t.type == "a" or t.type == "i", - "invalid type '" .. t.type .. "'") - end - return t -end - -local function sput(u, body) - local putt = parse(u) - putt.source = ltn12.source.string(body) - return tput(putt) -end - -put = socket.protect(function(putt, body) - if base.type(putt) == "string" then return sput(putt, body) - else return tput(putt) end -end) - -local function tget(gett) - gett = override(gett) - socket.try(gett.host, "missing hostname") - local f = open(gett.host, gett.port, gett.create) - f:greet() - f:login(gett.user, gett.password) - if gett.type then f:type(gett.type) end - f:pasv() - f:receive(gett) - f:quit() - return f:close() -end - -local function sget(u) - local gett = parse(u) - local t = {} - gett.sink = ltn12.sink.table(t) - tget(gett) - return table.concat(t) -end - -command = socket.protect(function(cmdt) - cmdt = override(cmdt) - socket.try(cmdt.host, "missing hostname") - socket.try(cmdt.command, "missing command") - local f = open(cmdt.host, cmdt.port, cmdt.create) - f:greet() - f:login(cmdt.user, cmdt.password) - f.try(f.tp:command(cmdt.command, cmdt.argument)) - if cmdt.check then f.try(f.tp:check(cmdt.check)) end - f:quit() - return f:close() -end) - -get = socket.protect(function(gett) - if base.type(gett) == "string" then return sget(gett) - else return tget(gett) end -end) - diff --git a/lib/support/share/socket/http.lua b/lib/support/share/socket/http.lua deleted file mode 100644 index ad8db1e..0000000 --- a/lib/support/share/socket/http.lua +++ /dev/null @@ -1,350 +0,0 @@ ------------------------------------------------------------------------------ --- HTTP/1.1 client support for the Lua language. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: http.lua,v 1.71 2007/10/13 23:55:20 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies -------------------------------------------------------------------------------- -local socket = require("socket") -local url = require("socket.url") -local ltn12 = require("ltn12") -local mime = require("mime") -local string = require("string") -local base = _G -local table = require("table") -module("socket.http") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- connection timeout in seconds -TIMEOUT = 60 --- default port for document retrieval -PORT = 80 --- user agent field sent in request -USERAGENT = socket._VERSION - ------------------------------------------------------------------------------ --- Reads MIME headers from a connection, unfolding where needed ------------------------------------------------------------------------------ -local function receiveheaders(sock, headers) - local line, name, value, err - headers = headers or {} - -- get first line - line, err = sock:receive() - if err then return nil, err end - -- headers go until a blank line is found - while line ~= "" do - -- get field-name and value - name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) - if not (name and value) then return nil, "malformed reponse headers" end - name = string.lower(name) - -- get next line (value might be folded) - line, err = sock:receive() - if err then return nil, err end - -- unfold any folded values - while string.find(line, "^%s") do - value = value .. line - line = sock:receive() - if err then return nil, err end - end - -- save pair in table - if headers[name] then headers[name] = headers[name] .. ", " .. value - else headers[name] = value end - end - return headers -end - ------------------------------------------------------------------------------ --- Extra sources and sinks ------------------------------------------------------------------------------ -socket.sourcet["http-chunked"] = function(sock, headers) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - -- get chunk size, skip extention - local line, err = sock:receive() - if err then return nil, err end - local size = base.tonumber(string.gsub(line, ";.*", ""), 16) - if not size then return nil, "invalid chunk size" end - -- was it the last chunk? - if size > 0 then - -- if not, get chunk and skip terminating CRLF - local chunk, err, part = sock:receive(size) - if chunk then sock:receive() end - return chunk, err - else - -- if it was, read trailers into headers table - headers, err = receiveheaders(sock, headers) - if not headers then return nil, err end - end - end - }) -end - -socket.sinkt["http-chunked"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then return sock:send("0\r\n\r\n") end - local size = string.format("%X\r\n", string.len(chunk)) - return sock:send(size .. chunk .. "\r\n") - end - }) -end - ------------------------------------------------------------------------------ --- Low level HTTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function open(host, port, create) - -- create socket with user connect function, or with default - local c = socket.try((create or socket.tcp)()) - local h = base.setmetatable({ c = c }, metat) - -- create finalized try - h.try = socket.newtry(function() h:close() end) - -- set timeout before connecting - h.try(c:settimeout(TIMEOUT)) - h.try(c:connect(host, port or PORT)) - -- here everything worked - return h -end - -function metat.__index:sendrequestline(method, uri) - local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) - return self.try(self.c:send(reqline)) -end - -function metat.__index:sendheaders(headers) - local h = "\r\n" - for i, v in base.pairs(headers) do - h = i .. ": " .. v .. "\r\n" .. h - end - self.try(self.c:send(h)) - return 1 -end - -function metat.__index:sendbody(headers, source, step) - source = source or ltn12.source.empty() - step = step or ltn12.pump.step - -- if we don't know the size in advance, send chunked and hope for the best - local mode = "http-chunked" - if headers["content-length"] then mode = "keep-open" end - return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) -end - -function metat.__index:receivestatusline() - local status = self.try(self.c:receive(5)) - -- identify HTTP/0.9 responses, which do not contain a status line - -- this is just a heuristic, but is what the RFC recommends - if status ~= "HTTP/" then return nil, status end - -- otherwise proceed reading a status line - status = self.try(self.c:receive("*l", status)) - local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) - return self.try(base.tonumber(code), status) -end - -function metat.__index:receiveheaders() - return self.try(receiveheaders(self.c)) -end - -function metat.__index:receivebody(headers, sink, step) - sink = sink or ltn12.sink.null() - step = step or ltn12.pump.step - local length = base.tonumber(headers["content-length"]) - local t = headers["transfer-encoding"] -- shortcut - local mode = "default" -- connection close - if t and t ~= "identity" then mode = "http-chunked" - elseif base.tonumber(headers["content-length"]) then mode = "by-length" end - return self.try(ltn12.pump.all(socket.source(mode, self.c, length), - sink, step)) -end - -function metat.__index:receive09body(status, sink, step) - local source = ltn12.source.rewind(socket.source("until-closed", self.c)) - source(status) - return self.try(ltn12.pump.all(source, sink, step)) -end - -function metat.__index:close() - return self.c:close() -end - ------------------------------------------------------------------------------ --- High level HTTP API ------------------------------------------------------------------------------ -local function adjusturi(reqt) - local u = reqt - -- if there is a proxy, we need the full url. otherwise, just a part. - if not reqt.proxy and not PROXY then - u = { - path = socket.try(reqt.path, "invalid path 'nil'"), - params = reqt.params, - query = reqt.query, - fragment = reqt.fragment - } - end - return url.build(u) -end - -local function adjustproxy(reqt) - local proxy = reqt.proxy or PROXY - if proxy then - proxy = url.parse(proxy) - return proxy.host, proxy.port or 3128 - else - return reqt.host, reqt.port - end -end - -local function adjustheaders(reqt) - -- default headers - local lower = { - ["user-agent"] = USERAGENT, - ["host"] = reqt.host, - ["connection"] = "close, TE", - ["te"] = "trailers" - } - -- if we have authentication information, pass it along - if reqt.user and reqt.password then - lower["authorization"] = - "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) - end - -- override with user headers - for i,v in base.pairs(reqt.headers or lower) do - lower[string.lower(i)] = v - end - return lower -end - --- default url parts -local default = { - host = "", - port = PORT, - path ="/", - scheme = "http" -} - -local function adjustrequest(reqt) - -- parse url if provided - local nreqt = reqt.url and url.parse(reqt.url, default) or {} - -- explicit components override url - for i,v in base.pairs(reqt) do nreqt[i] = v end - if nreqt.port == "" then nreqt.port = 80 end - socket.try(nreqt.host and nreqt.host ~= "", - "invalid host '" .. base.tostring(nreqt.host) .. "'") - -- compute uri if user hasn't overriden - nreqt.uri = reqt.uri or adjusturi(nreqt) - -- ajust host and port if there is a proxy - nreqt.host, nreqt.port = adjustproxy(nreqt) - -- adjust headers in request - nreqt.headers = adjustheaders(nreqt) - return nreqt -end - -local function shouldredirect(reqt, code, headers) - return headers.location and - string.gsub(headers.location, "%s", "") ~= "" and - (reqt.redirect ~= false) and - (code == 301 or code == 302) and - (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") - and (not reqt.nredirects or reqt.nredirects < 5) -end - -local function shouldreceivebody(reqt, code) - if reqt.method == "HEAD" then return nil end - if code == 204 or code == 304 then return nil end - if code >= 100 and code < 200 then return nil end - return 1 -end - --- forward declarations -local trequest, tredirect - -function tredirect(reqt, location) - local result, code, headers, status = trequest { - -- the RFC says the redirect URL has to be absolute, but some - -- servers do not respect that - url = url.absolute(reqt.url, location), - source = reqt.source, - sink = reqt.sink, - headers = reqt.headers, - proxy = reqt.proxy, - nredirects = (reqt.nredirects or 0) + 1, - create = reqt.create - } - -- pass location header back as a hint we redirected - headers = headers or {} - headers.location = headers.location or location - return result, code, headers, status -end - -function trequest(reqt) - -- we loop until we get what we want, or - -- until we are sure there is no way to get it - local nreqt = adjustrequest(reqt) - local h = open(nreqt.host, nreqt.port, nreqt.create) - -- send request line and headers - h:sendrequestline(nreqt.method, nreqt.uri) - h:sendheaders(nreqt.headers) - -- if there is a body, send it - if nreqt.source then - h:sendbody(nreqt.headers, nreqt.source, nreqt.step) - end - local code, status = h:receivestatusline() - -- if it is an HTTP/0.9 server, simply get the body and we are done - if not code then - h:receive09body(status, nreqt.sink, nreqt.step) - return 1, 200 - end - local headers - -- ignore any 100-continue messages - while code == 100 do - headers = h:receiveheaders() - code, status = h:receivestatusline() - end - headers = h:receiveheaders() - -- at this point we should have a honest reply from the server - -- we can't redirect if we already used the source, so we report the error - if shouldredirect(nreqt, code, headers) and not nreqt.source then - h:close() - return tredirect(reqt, headers.location) - end - -- here we are finally done - if shouldreceivebody(nreqt, code) then - h:receivebody(headers, nreqt.sink, nreqt.step) - end - h:close() - return 1, code, headers, status -end - -local function srequest(u, b) - local t = {} - local reqt = { - url = u, - sink = ltn12.sink.table(t) - } - if b then - reqt.source = ltn12.source.string(b) - reqt.headers = { - ["content-length"] = string.len(b), - ["content-type"] = "application/x-www-form-urlencoded" - } - reqt.method = "POST" - end - local code, headers, status = socket.skip(1, trequest(reqt)) - return table.concat(t), code, headers, status -end - -request = socket.protect(function(reqt, body) - if base.type(reqt) == "string" then return srequest(reqt, body) - else return trequest(reqt) end -end) diff --git a/lib/support/share/socket/smtp.lua b/lib/support/share/socket/smtp.lua deleted file mode 100644 index 8f3cfcf..0000000 --- a/lib/support/share/socket/smtp.lua +++ /dev/null @@ -1,251 +0,0 @@ ------------------------------------------------------------------------------ --- SMTP client support for the Lua language. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: smtp.lua,v 1.46 2007/03/12 04:08:40 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local coroutine = require("coroutine") -local string = require("string") -local math = require("math") -local os = require("os") -local socket = require("socket") -local tp = require("socket.tp") -local ltn12 = require("ltn12") -local mime = require("mime") -module("socket.smtp") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- timeout for connection -TIMEOUT = 60 --- default server used to send e-mails -SERVER = "localhost" --- default port -PORT = 25 --- domain used in HELO command and default sendmail --- If we are under a CGI, try to get from environment -DOMAIN = os.getenv("SERVER_NAME") or "localhost" --- default time zone (means we don't know) -ZONE = "-0000" - ---------------------------------------------------------------------------- --- Low level SMTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function metat.__index:greet(domain) - self.try(self.tp:check("2..")) - self.try(self.tp:command("EHLO", domain or DOMAIN)) - return socket.skip(1, self.try(self.tp:check("2.."))) -end - -function metat.__index:mail(from) - self.try(self.tp:command("MAIL", "FROM:" .. from)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:rcpt(to) - self.try(self.tp:command("RCPT", "TO:" .. to)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:data(src, step) - self.try(self.tp:command("DATA")) - self.try(self.tp:check("3..")) - self.try(self.tp:source(src, step)) - self.try(self.tp:send("\r\n.\r\n")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:quit() - self.try(self.tp:command("QUIT")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:close() - return self.tp:close() -end - -function metat.__index:login(user, password) - self.try(self.tp:command("AUTH", "LOGIN")) - self.try(self.tp:check("3..")) - self.try(self.tp:command(mime.b64(user))) - self.try(self.tp:check("3..")) - self.try(self.tp:command(mime.b64(password))) - return self.try(self.tp:check("2..")) -end - -function metat.__index:plain(user, password) - local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) - self.try(self.tp:command("AUTH", auth)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:auth(user, password, ext) - if not user or not password then return 1 end - if string.find(ext, "AUTH[^\n]+LOGIN") then - return self:login(user, password) - elseif string.find(ext, "AUTH[^\n]+PLAIN") then - return self:plain(user, password) - else - self.try(nil, "authentication not supported") - end -end - --- send message or throw an exception -function metat.__index:send(mailt) - self:mail(mailt.from) - if base.type(mailt.rcpt) == "table" then - for i,v in base.ipairs(mailt.rcpt) do - self:rcpt(v) - end - else - self:rcpt(mailt.rcpt) - end - self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) -end - -function open(server, port, create) - local tp = socket.try(tp.connect(server or SERVER, port or PORT, - TIMEOUT, create)) - local s = base.setmetatable({tp = tp}, metat) - -- make sure tp is closed if we get an exception - s.try = socket.newtry(function() - s:close() - end) - return s -end - --- convert headers to lowercase -local function lower_headers(headers) - local lower = {} - for i,v in base.pairs(headers or lower) do - lower[string.lower(i)] = v - end - return lower -end - ---------------------------------------------------------------------------- --- Multipart message source ------------------------------------------------------------------------------ --- returns a hopefully unique mime boundary -local seqno = 0 -local function newboundary() - seqno = seqno + 1 - return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), - math.random(0, 99999), seqno) -end - --- send_message forward declaration -local send_message - --- yield the headers all at once, it's faster -local function send_headers(headers) - local h = "\r\n" - for i,v in base.pairs(headers) do - h = i .. ': ' .. v .. "\r\n" .. h - end - coroutine.yield(h) -end - --- yield multipart message body from a multipart message table -local function send_multipart(mesgt) - -- make sure we have our boundary and send headers - local bd = newboundary() - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or 'multipart/mixed' - headers['content-type'] = headers['content-type'] .. - '; boundary="' .. bd .. '"' - send_headers(headers) - -- send preamble - if mesgt.body.preamble then - coroutine.yield(mesgt.body.preamble) - coroutine.yield("\r\n") - end - -- send each part separated by a boundary - for i, m in base.ipairs(mesgt.body) do - coroutine.yield("\r\n--" .. bd .. "\r\n") - send_message(m) - end - -- send last boundary - coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") - -- send epilogue - if mesgt.body.epilogue then - coroutine.yield(mesgt.body.epilogue) - coroutine.yield("\r\n") - end -end - --- yield message body from a source -local function send_source(mesgt) - -- make sure we have a content-type - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or - 'text/plain; charset="iso-8859-1"' - send_headers(headers) - -- send body from source - while true do - local chunk, err = mesgt.body() - if err then coroutine.yield(nil, err) - elseif chunk then coroutine.yield(chunk) - else break end - end -end - --- yield message body from a string -local function send_string(mesgt) - -- make sure we have a content-type - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or - 'text/plain; charset="iso-8859-1"' - send_headers(headers) - -- send body from string - coroutine.yield(mesgt.body) -end - --- message source -function send_message(mesgt) - if base.type(mesgt.body) == "table" then send_multipart(mesgt) - elseif base.type(mesgt.body) == "function" then send_source(mesgt) - else send_string(mesgt) end -end - --- set defaul headers -local function adjust_headers(mesgt) - local lower = lower_headers(mesgt.headers) - lower["date"] = lower["date"] or - os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) - lower["x-mailer"] = lower["x-mailer"] or socket._VERSION - -- this can't be overriden - lower["mime-version"] = "1.0" - return lower -end - -function message(mesgt) - mesgt.headers = adjust_headers(mesgt) - -- create and return message source - local co = coroutine.create(function() send_message(mesgt) end) - return function() - local ret, a, b = coroutine.resume(co) - if ret then return a, b - else return nil, a end - end -end - ---------------------------------------------------------------------------- --- High level SMTP API ------------------------------------------------------------------------------ -send = socket.protect(function(mailt) - local s = open(mailt.server, mailt.port, mailt.create) - local ext = s:greet(mailt.domain) - s:auth(mailt.user, mailt.password, ext) - s:send(mailt) - s:quit() - return s:close() -end) diff --git a/lib/support/share/socket/tp.lua b/lib/support/share/socket/tp.lua deleted file mode 100644 index 0683869..0000000 --- a/lib/support/share/socket/tp.lua +++ /dev/null @@ -1,123 +0,0 @@ ------------------------------------------------------------------------------ --- Unified SMTP/FTP subsystem --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local socket = require("socket") -local ltn12 = require("ltn12") -module("socket.tp") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ -TIMEOUT = 60 - ------------------------------------------------------------------------------ --- Implementation ------------------------------------------------------------------------------ --- gets server reply (works for SMTP and FTP) -local function get_reply(c) - local code, current, sep - local line, err = c:receive() - local reply = line - if err then return nil, err end - code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) - if not code then return nil, "invalid server reply" end - if sep == "-" then -- reply is multiline - repeat - line, err = c:receive() - if err then return nil, err end - current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) - reply = reply .. "\n" .. line - -- reply ends with same code - until code == current and sep == " " - end - return code, reply -end - --- metatable for sock object -local metat = { __index = {} } - -function metat.__index:check(ok) - local code, reply = get_reply(self.c) - if not code then return nil, reply end - if base.type(ok) ~= "function" then - if base.type(ok) == "table" then - for i, v in base.ipairs(ok) do - if string.find(code, v) then - return base.tonumber(code), reply - end - end - return nil, reply - else - if string.find(code, ok) then return base.tonumber(code), reply - else return nil, reply end - end - else return ok(base.tonumber(code), reply) end -end - -function metat.__index:command(cmd, arg) - if arg then - return self.c:send(cmd .. " " .. arg.. "\r\n") - else - return self.c:send(cmd .. "\r\n") - end -end - -function metat.__index:sink(snk, pat) - local chunk, err = c:receive(pat) - return snk(chunk, err) -end - -function metat.__index:send(data) - return self.c:send(data) -end - -function metat.__index:receive(pat) - return self.c:receive(pat) -end - -function metat.__index:getfd() - return self.c:getfd() -end - -function metat.__index:dirty() - return self.c:dirty() -end - -function metat.__index:getcontrol() - return self.c -end - -function metat.__index:source(source, step) - local sink = socket.sink("keep-open", self.c) - local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) - return ret, err -end - --- closes the underlying c -function metat.__index:close() - self.c:close() - return 1 -end - --- connect with server and return c object -function connect(host, port, timeout, create) - local c, e = (create or socket.tcp)() - if not c then return nil, e end - c:settimeout(timeout or TIMEOUT) - local r, e = c:connect(host, port) - if not r then - c:close() - return nil, e - end - return base.setmetatable({c = c}, metat) -end - diff --git a/lib/support/share/socket/url.lua b/lib/support/share/socket/url.lua deleted file mode 100644 index 0e31d8a..0000000 --- a/lib/support/share/socket/url.lua +++ /dev/null @@ -1,297 +0,0 @@ ------------------------------------------------------------------------------ --- URI parsing, composition and relative URL resolution --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: url.lua,v 1.38 2006/04/03 04:45:42 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local base = _G -local table = require("table") -module("socket.url") - ------------------------------------------------------------------------------ --- Module version ------------------------------------------------------------------------------ -_VERSION = "URL 1.0.1" - ------------------------------------------------------------------------------ --- Encodes a string into its escaped hexadecimal representation --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -function escape(s) - return string.gsub(s, "([^A-Za-z0-9_])", function(c) - return string.format("%%%02x", string.byte(c)) - end) -end - ------------------------------------------------------------------------------ --- Protects a path segment, to prevent it from interfering with the --- url parsing. --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -local function make_set(t) - local s = {} - for i,v in base.ipairs(t) do - s[t[i]] = 1 - end - return s -end - --- these are allowed withing a path segment, along with alphanum --- other characters must be escaped -local segment_set = make_set { - "-", "_", ".", "!", "~", "*", "'", "(", - ")", ":", "@", "&", "=", "+", "$", ",", -} - -local function protect_segment(s) - return string.gsub(s, "([^A-Za-z0-9_])", function (c) - if segment_set[c] then return c - else return string.format("%%%02x", string.byte(c)) end - end) -end - ------------------------------------------------------------------------------ --- Encodes a string into its escaped hexadecimal representation --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -function unescape(s) - return string.gsub(s, "%%(%x%x)", function(hex) - return string.char(base.tonumber(hex, 16)) - end) -end - ------------------------------------------------------------------------------ --- Builds a path from a base path and a relative path --- Input --- base_path --- relative_path --- Returns --- corresponding absolute path ------------------------------------------------------------------------------ -local function absolute_path(base_path, relative_path) - if string.sub(relative_path, 1, 1) == "/" then return relative_path end - local path = string.gsub(base_path, "[^/]*$", "") - path = path .. relative_path - path = string.gsub(path, "([^/]*%./)", function (s) - if s ~= "./" then return s else return "" end - end) - path = string.gsub(path, "/%.$", "/") - local reduced - while reduced ~= path do - reduced = path - path = string.gsub(reduced, "([^/]*/%.%./)", function (s) - if s ~= "../../" then return "" else return s end - end) - end - path = string.gsub(reduced, "([^/]*/%.%.)$", function (s) - if s ~= "../.." then return "" else return s end - end) - return path -end - ------------------------------------------------------------------------------ --- Parses a url and returns a table with all its parts according to RFC 2396 --- The following grammar describes the names given to the URL parts --- ::= :///;?# --- ::= @: --- ::= [:] --- :: = {/} --- Input --- url: uniform resource locator of request --- default: table with default values for each field --- Returns --- table with the following fields, where RFC naming conventions have --- been preserved: --- scheme, authority, userinfo, user, password, host, port, --- path, params, query, fragment --- Obs: --- the leading '/' in {/} is considered part of ------------------------------------------------------------------------------ -function parse(url, default) - -- initialize default parameters - local parsed = {} - for i,v in base.pairs(default or parsed) do parsed[i] = v end - -- empty url is parsed to nil - if not url or url == "" then return nil, "invalid url" end - -- remove whitespace - -- url = string.gsub(url, "%s", "") - -- get fragment - url = string.gsub(url, "#(.*)$", function(f) - parsed.fragment = f - return "" - end) - -- get scheme - url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", - function(s) parsed.scheme = s; return "" end) - -- get authority - url = string.gsub(url, "^//([^/]*)", function(n) - parsed.authority = n - return "" - end) - -- get query stringing - url = string.gsub(url, "%?(.*)", function(q) - parsed.query = q - return "" - end) - -- get params - url = string.gsub(url, "%;(.*)", function(p) - parsed.params = p - return "" - end) - -- path is whatever was left - if url ~= "" then parsed.path = url end - local authority = parsed.authority - if not authority then return parsed end - authority = string.gsub(authority,"^([^@]*)@", - function(u) parsed.userinfo = u; return "" end) - authority = string.gsub(authority, ":([^:]*)$", - function(p) parsed.port = p; return "" end) - if authority ~= "" then parsed.host = authority end - local userinfo = parsed.userinfo - if not userinfo then return parsed end - userinfo = string.gsub(userinfo, ":([^:]*)$", - function(p) parsed.password = p; return "" end) - parsed.user = userinfo - return parsed -end - ------------------------------------------------------------------------------ --- Rebuilds a parsed URL from its components. --- Components are protected if any reserved or unallowed characters are found --- Input --- parsed: parsed URL, as returned by parse --- Returns --- a stringing with the corresponding URL ------------------------------------------------------------------------------ -function build(parsed) - local ppath = parse_path(parsed.path or "") - local url = build_path(ppath) - if parsed.params then url = url .. ";" .. parsed.params end - if parsed.query then url = url .. "?" .. parsed.query end - local authority = parsed.authority - if parsed.host then - authority = parsed.host - if parsed.port then authority = authority .. ":" .. parsed.port end - local userinfo = parsed.userinfo - if parsed.user then - userinfo = parsed.user - if parsed.password then - userinfo = userinfo .. ":" .. parsed.password - end - end - if userinfo then authority = userinfo .. "@" .. authority end - end - if authority then url = "//" .. authority .. url end - if parsed.scheme then url = parsed.scheme .. ":" .. url end - if parsed.fragment then url = url .. "#" .. parsed.fragment end - -- url = string.gsub(url, "%s", "") - return url -end - ------------------------------------------------------------------------------ --- Builds a absolute URL from a base and a relative URL according to RFC 2396 --- Input --- base_url --- relative_url --- Returns --- corresponding absolute url ------------------------------------------------------------------------------ -function absolute(base_url, relative_url) - if base.type(base_url) == "table" then - base_parsed = base_url - base_url = build(base_parsed) - else - base_parsed = parse(base_url) - end - local relative_parsed = parse(relative_url) - if not base_parsed then return relative_url - elseif not relative_parsed then return base_url - elseif relative_parsed.scheme then return relative_url - else - relative_parsed.scheme = base_parsed.scheme - if not relative_parsed.authority then - relative_parsed.authority = base_parsed.authority - if not relative_parsed.path then - relative_parsed.path = base_parsed.path - if not relative_parsed.params then - relative_parsed.params = base_parsed.params - if not relative_parsed.query then - relative_parsed.query = base_parsed.query - end - end - else - relative_parsed.path = absolute_path(base_parsed.path or "", - relative_parsed.path) - end - end - return build(relative_parsed) - end -end - ------------------------------------------------------------------------------ --- Breaks a path into its segments, unescaping the segments --- Input --- path --- Returns --- segment: a table with one entry per segment ------------------------------------------------------------------------------ -function parse_path(path) - local parsed = {} - path = path or "" - --path = string.gsub(path, "%s", "") - string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) - for i = 1, table.getn(parsed) do - parsed[i] = unescape(parsed[i]) - end - if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end - if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end - return parsed -end - ------------------------------------------------------------------------------ --- Builds a path component from its segments, escaping protected characters. --- Input --- parsed: path segments --- unsafe: if true, segments are not protected before path is built --- Returns --- path: corresponding path stringing ------------------------------------------------------------------------------ -function build_path(parsed, unsafe) - local path = "" - local n = table.getn(parsed) - if unsafe then - for i = 1, n-1 do - path = path .. parsed[i] - path = path .. "/" - end - if n > 0 then - path = path .. parsed[n] - if parsed.is_directory then path = path .. "/" end - end - else - for i = 1, n-1 do - path = path .. protect_segment(parsed[i]) - path = path .. "/" - end - if n > 0 then - path = path .. protect_segment(parsed[n]) - if parsed.is_directory then path = path .. "/" end - end - end - if parsed.is_absolute then path = "/" .. path end - return path -end diff --git a/lib/support/socket.lua b/lib/support/socket.lua deleted file mode 100644 index 211adcd..0000000 --- a/lib/support/socket.lua +++ /dev/null @@ -1,133 +0,0 @@ ------------------------------------------------------------------------------ --- LuaSocket helper module --- Author: Diego Nehab --- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local math = require("math") -local socket = require("socket.core") -module("socket") - ------------------------------------------------------------------------------ --- Exported auxiliar functions ------------------------------------------------------------------------------ -function connect(address, port, laddress, lport) - local sock, err = socket.tcp() - if not sock then return nil, err end - if laddress then - local res, err = sock:bind(laddress, lport, -1) - if not res then return nil, err end - end - local res, err = sock:connect(address, port) - if not res then return nil, err end - return sock -end - -function bind(host, port, backlog) - local sock, err = socket.tcp() - if not sock then return nil, err end - sock:setoption("reuseaddr", true) - local res, err = sock:bind(host, port) - if not res then return nil, err end - res, err = sock:listen(backlog) - if not res then return nil, err end - return sock -end - -try = newtry() - -function choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) - else return f(opt1, opt2) end - end -end - ------------------------------------------------------------------------------ --- Socket sources and sinks, conforming to LTN12 ------------------------------------------------------------------------------ --- create namespaces inside LuaSocket namespace -sourcet = {} -sinkt = {} - -BLOCKSIZE = 2048 - -sinkt["close-when-done"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then - sock:close() - return 1 - else return sock:send(chunk) end - end - }) -end - -sinkt["keep-open"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if chunk then return sock:send(chunk) - else return 1 end - end - }) -end - -sinkt["default"] = sinkt["keep-open"] - -sink = choose(sinkt) - -sourcet["by-length"] = function(sock, length) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if length <= 0 then return nil end - local size = math.min(socket.BLOCKSIZE, length) - local chunk, err = sock:receive(size) - if err then return nil, err end - length = length - string.len(chunk) - return chunk - end - }) -end - -sourcet["until-closed"] = function(sock) - local done - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if done then return nil end - local chunk, err, partial = sock:receive(socket.BLOCKSIZE) - if not err then return chunk - elseif err == "closed" then - sock:close() - done = 1 - return partial - else return nil, err end - end - }) -end - - -sourcet["default"] = sourcet["until-closed"] - -source = choose(sourcet) - diff --git a/lib/support/socket/core.so b/lib/support/socket/core.so deleted file mode 100755 index ddfc8c3..0000000 --- a/lib/support/socket/core.so +++ /dev/null Binary files differ diff --git a/main.py b/main.py index 5040560..8931938 100755 --- a/main.py +++ b/main.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # FollowMe Butia - Main -# Copyright (C) 2010, 2011, 2012 +# Copyright (C) 2010-2013 # This program was created to use with the robot Butia. # Butia is a project from Facultad de Ingenieria - Uruguay # Facultad de Ingenieria web site: diff --git a/pybot/__init__.py b/pybot/__init__.py new file mode 100755 index 0000000..d908414 --- /dev/null +++ b/pybot/__init__.py @@ -0,0 +1,27 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2012-2013 Butiá Team butia@fing.edu.uy +# Butia is a free and open robotic platform +# www.fing.edu.uy/inco/proyectos/butia +# Facultad de Ingeniería - Universidad de la República - Uruguay +# +# 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 of the License, 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 +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import sys +# Make sure that can import all files +sys.path.insert(0, os.path.dirname(__file__)) + diff --git a/pybot/baseboard.py b/pybot/baseboard.py new file mode 100755 index 0000000..fe5bba5 --- /dev/null +++ b/pybot/baseboard.py @@ -0,0 +1,275 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# Baseboard abstraction for USB4butia +# +# Copyright (c) 2012-2013 Butiá Team butia@fing.edu.uy +# Butia is a free and open robotic platform +# www.fing.edu.uy/inco/proyectos/butia +# Facultad de Ingeniería - Universidad de la República - Uruguay +# +# 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 of the License, 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 +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +NULL_BYTE = 0x00 +DEFAULT_PACKET_SIZE = 0x04 +GET_USER_MODULES_SIZE_COMMAND = 0x05 +GET_USER_MODULE_LINE_COMMAND = 0x06 +GET_HANDLER_SIZE_COMMAND = 0x0A +GET_HANDLER_TYPE_COMMAND = 0x0B +ADMIN_HANDLER_SEND_COMMAND = 0x00 +CLOSEALL_BASE_BOARD_COMMAND = 0x07 +SWITCH_TO_BOOT_BASE_BOARD_COMMAND = 0x09 +RESET_BASE_BOARD_COMMAND = 0xFF + +ADMIN_MODULE_IN_ENDPOINT = 0x01 +ADMIN_MODULE_OUT_ENDPOINT = 0x81 +GET_USER_MODULE_LINE_PACKET_SIZE = 0x05 + +GET_LINES_RESPONSE_PACKET_SIZE = 5 +GET_LINE_RESPONSE_PACKET_SIZE = 12 +GET_HANDLER_TYPE_PACKET_SIZE = 5 +GET_HANDLER_RESPONSE_PACKET_SIZE = 5 +CLOSEALL_BASE_BOARD_RESPONSE_PACKET_SIZE = 5 + +ERROR = -1 + +class Baseboard(): + + def __init__(self, dev, debug=False): + self.dev = dev + self.debug = debug + self.listi = {} + self.devices = {} + self.openables_loaded = [] + + def open_baseboard(self): + """ + Open the baseboard + """ + self.dev.open_device() + + def close_baseboard(self): + """ + Close the baseboard + """ + self.dev.close_device() + + def get_info(self): + """ + Get baseboard info: manufacture.. + """ + return self.dev.get_info() + + def add_device(self, handler, device): + """ + Add a device with handler: handler to the dictionary + """ + self.devices[handler] = device + + def reset_device_list(self): + """ + Cleans the device dictionary + """ + self.devices = {} + + def add_openable_loaded(self, name): + """ + Add the name of device that was opened to prevent open twice + """ + if not(name in self.openables_loaded): + self.openables_loaded.append(name) + + def get_openables_loaded(self): + """ + Get the list of modules that was openened (no pnp) + """ + return self.openables_loaded + + def reset_openables_loaded(self): + """ + Reset the list of openables modules + """ + self.openables_loaded = [] + + def add_to_listi(self, number, name): + """ + Add a device to listi + """ + self.listi[number] = name + + def get_listi(self): + """ + Get the listi: the list of modules present in the board that can be + opened (or pnp module opens) + """ + if (self.listi == {}): + self.generate_listi() + return self.listi + + def generate_listi(self): + """ + Generate the listi: the list of modules present in the board that can be + opened (or pnp module opens) + """ + self.listi = {} + try: + s = self.get_user_modules_size() + for m in range(s): + name = self.get_user_module_line(m) + self.listi[m] = name + except: + self.listi = {} + if self.debug: + print 'error listi' + + def get_device_handler(self, name): + """ + Get the handler of device with name: name + """ + for e in self.devices: + if self.devices[e].name == name: + return e + return ERROR + + def get_device_name(self, handler): + """ + Get the name of device with handler: handler + """ + if self.devices.has_key(handler): + return self.devices[handler].name + else: + return '' + + def get_user_modules_size(self): + """ + Get the size of the list of user modules (listi) + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(DEFAULT_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(GET_USER_MODULES_SIZE_COMMAND) + self.dev.write(w) + + raw = self.dev.read(GET_USER_MODULE_LINE_PACKET_SIZE) + + if self.debug: + print 'baseboard:get_user_modules_size return', raw + + return raw[4] + + def get_user_module_line(self, index): + """ + Get the name of device with index: index (listi) + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(GET_USER_MODULE_LINE_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(GET_USER_MODULE_LINE_COMMAND) + w.append(index) + self.dev.write(w) + + raw = self.dev.read(GET_LINE_RESPONSE_PACKET_SIZE) + + if self.debug: + print 'baseboard:get_user_module_line return', raw + + c = raw[4:len(raw)] + t = '' + for e in c: + if not(e == NULL_BYTE): + t = t + chr(e) + + return t + + def get_handler_size(self): + """ + Get the number of handlers opened + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(DEFAULT_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(GET_HANDLER_SIZE_COMMAND) + self.dev.write(w) + + raw = self.dev.read(GET_HANDLER_RESPONSE_PACKET_SIZE) + + if self.debug: + print 'baseboard:get_handler_size return', raw + + return raw[4] + + def get_handler_type(self, index): + """ + Get the type of the handler: index (return listi index) + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(GET_HANDLER_TYPE_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(GET_HANDLER_TYPE_COMMAND) + w.append(index) + self.dev.write(w) + + raw = self.dev.read(GET_HANDLER_RESPONSE_PACKET_SIZE) + + if self.debug: + print 'baseboard:get_handler_type return', raw + + return raw[4] + + def switch_to_bootloader(self): + """ + Admin module command to switch to bootloader + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(DEFAULT_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(SWITCH_TO_BOOT_BASE_BOARD_COMMAND) + self.dev.write(w) + + def reset(self): + """ + Admin module command to reset the board + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(DEFAULT_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(RESET_BASE_BOARD_COMMAND) + self.dev.write(w) + + def force_close_all(self): + """ + Admin module command to force close all opened modules + """ + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(DEFAULT_PACKET_SIZE) + w.append(NULL_BYTE) + w.append(CLOSEALL_BASE_BOARD_COMMAND) + self.dev.write(w) + + raw = self.dev.read(CLOSEALL_BASE_BOARD_RESPONSE_PACKET_SIZE) + + if self.debug: + print 'baseboard:force_close_all return', raw + + return raw[4] + + diff --git a/pybot/com_usb.py b/pybot/com_usb.py new file mode 100755 index 0000000..54305ba --- /dev/null +++ b/pybot/com_usb.py @@ -0,0 +1,127 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# USB comunication with USB4butia (USB4all) board +# +# Copyright (c) 2012-2013 Butiá Team butia@fing.edu.uy +# Butia is a free and open robotic platform +# www.fing.edu.uy/inco/proyectos/butia +# Facultad de Ingeniería - Universidad de la República - Uruguay +# +# 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 of the License, 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 +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import usb + +USB4ALL_VENDOR = 0x04d8 +USB4ALL_PRODUCT = 0x000c +USB4ALL_CONFIGURATION = 1 +USB4ALL_INTERFACE = 0 + +ADMIN_MODULE_IN_ENDPOINT = 0x01 +ADMIN_MODULE_OUT_ENDPOINT = 0x81 + +READ_HEADER_SIZE = 3 + +TIMEOUT = 250 + +ERROR = -1 + +class usb_device(): + + def __init__(self, dev): + self.device = dev + self.handle = None + self.debug = True + + def open_device(self): + """ + Open the baseboard, configure the interface + """ + try: + self.handle = self.device.open() + self.handle.setConfiguration(USB4ALL_CONFIGURATION) + self.handle.claimInterface(USB4ALL_INTERFACE) + except usb.USBError, err: + if self.debug: + print err + self.handle = None + raise + return self.handle + + def close_device(self): + """ + Close the comunication with the baseboard + """ + try: + if self.handle: + self.handle.releaseInterface() + except Exception, err: + if self.debug: + print err + raise + self.handle = None + self.device = None + + def read(self, length): + """ + Read from the device length bytes + """ + try: + return self.handle.bulkRead(ADMIN_MODULE_OUT_ENDPOINT, length, TIMEOUT) + except: + if self.debug: + print 'Exception in read usb' + raise + + def write(self, data): + """ + Write in the device: data + """ + try: + return self.handle.bulkWrite(ADMIN_MODULE_IN_ENDPOINT, data, TIMEOUT) + except: + if self.debug: + print 'Exception in write usb' + raise + + def get_info(self): + """ + Get the device info such as manufacturer, etc + """ + try: + names = self.handle.getString(1, 255) + copy = self.handle.getString(2, 255) + sn = self.handle.getString(3, 255) + return [names, copy, sn] + except Exception, err: + if self.debug: + print 'Exception in get_info', err + raise + +def find(): + """ + List all busses and returns a list of baseboards detected + """ + l = [] + try: + for bus in usb.busses(): + for dev in bus.devices: + if dev.idVendor == USB4ALL_VENDOR and dev.idProduct == USB4ALL_PRODUCT: + l.append(usb_device(dev)) + except Exception, err: + if self.debug: + print 'find gives the error:', err + return l + diff --git a/pybot/device.py b/pybot/device.py new file mode 100755 index 0000000..81a9e57 --- /dev/null +++ b/pybot/device.py @@ -0,0 +1,154 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# Device abstraction for USB4butia +# +# Copyright (c) 2012-2013 Butiá Team butia@fing.edu.uy +# Butia is a free and open robotic platform +# www.fing.edu.uy/inco/proyectos/butia +# Facultad de Ingeniería - Universidad de la República - Uruguay +# +# 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 of the License, 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 +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +NULL_BYTE = 0x00 +OPEN_COMMAND = 0x00 +CLOSE_COMMAND = 0x01 +HEADER_PACKET_SIZE = 0x06 + +ADMIN_HANDLER_SEND_COMMAND = 0x00 + +OPEN_RESPONSE_PACKET_SIZE = 5 +CLOSE_RESPONSE_PACKET_SIZE = 2 + +READ_HEADER_SIZE = 3 +MAX_BYTES = 64 + +ERROR = -1 + +class Device(): + + def __init__(self, baseboard, name, handler=None): + self.baseboard = baseboard + self.name = name + self.handler = handler + if not(self.handler == None): + self.handler_tosend = self.handler * 8 + self.functions = {} + self.debug = False + + def add_functions(self, func_list): + """ + Add the functions to current device + """ + for f in func_list: + self.functions[f['name']] = f + + def module_send(self, call, params_length, params): + """ + Send to the device the specifiy call and parameters + """ + if len(params) == 1: + if type(params[0]) == str: + params = to_ord(params[0]) + + send_packet_length = 0x04 + len(params) + + w = [] + w.append(self.handler_tosend) + w.append(send_packet_length) + w.append(NULL_BYTE) + w.append(call) + for p in params: + w.append(p) + + self.baseboard.dev.write(w) + + def module_read(self): + """ + Read the device data + """ + raw = self.baseboard.dev.read(MAX_BYTES) + if self.debug: + print 'device:module_rad return', raw + if raw[1] == 5: + if raw[4] == 255: + return -1 + else: + return raw[4] + elif raw[1] == 6: + return raw[4] + raw[5] * 256 + else: + ret = '' + for r in raw[4:]: + if not(r == 0): + ret = ret + chr(r) + return ret + + def module_open(self): + """ + Open this device. Return the handler + """ + module_name = to_ord(self.name) + module_name.append(0) + + open_packet_length = HEADER_PACKET_SIZE + len(module_name) + + module_in_endpoint = 0x01 + module_out_endpoint = 0x01 + + w = [] + w.append(ADMIN_HANDLER_SEND_COMMAND) + w.append(open_packet_length) + w.append(NULL_BYTE) + w.append(OPEN_COMMAND) + w.append(module_in_endpoint) + w.append(module_out_endpoint) + w = w + module_name + self.baseboard.dev.write(w) + + raw = self.baseboard.dev.read(OPEN_RESPONSE_PACKET_SIZE) + + if self.debug: + print 'device:module_open return', raw + + h = raw[4] + self.handler = h + self.handler_tosend = self.handler * 8 + return h + + def has_function(self, func): + """ + Check if this device has func function + """ + return self.functions.has_key(func) + + def call_function(self, func, params): + """ + Call specify func function with params parameters + """ + self.module_send(self.functions[func]['call'], self.functions[func]['params'], params) + return self.module_read() + +def to_ord(string): + """ + Useful function to convert characters into ordinal Unicode + """ + s = [] + for l in string: + o = ord(l) + if not(o == 0): + s.append(o) + return s + diff --git a/pybot/drivers/admin.py b/pybot/drivers/admin.py new file mode 100644 index 0000000..5e4e192 --- /dev/null +++ b/pybot/drivers/admin.py @@ -0,0 +1,19 @@ + +RESET = 0xFF +GET_FIRMWARE_VERSION = 0xFE + +f1 = { + 'name': 'reset', + 'call': RESET, + 'params': 0, + 'read': 0 +} + +f2 = { + 'name': 'getVersion', + 'call': GET_FIRMWARE_VERSION, + 'params': 0, + 'read': 1 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/butia.py b/pybot/drivers/butia.py new file mode 100644 index 0000000..74f6f0f --- /dev/null +++ b/pybot/drivers/butia.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x02 +GET_VOLT = 0x03 + +f1 = { + 'name': 'read_ver', + 'call': RD_VERSION, + 'params': 0, + 'read': 2 +} + +f2 = { + 'name': 'get_volt', + 'call': GET_VOLT, + 'params': 0, + 'read': 2 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hackp.py b/pybot/drivers/hackp.py new file mode 100644 index 0000000..4e9c963 --- /dev/null +++ b/pybot/drivers/hackp.py @@ -0,0 +1,40 @@ + +RD_VERSION = 0x00 +SET_MODE = 0x01 +READ = 0x02 +WRITE = 0x03 +WRITE_PORT = 0x04 +PORT_IN = 0x05 +PORT_OUT = 0x06 + + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'setMode', + 'call': SET_MODE, + 'params': 2, + 'read': 1 +} + +f3 = { + 'name': 'read', + 'call': READ, + 'params': 1, + 'read': 1 +} + +f4 = { + 'name': 'write', + 'call': WRITE, + 'params': 2, + 'read': 1 +} + +FUNCTIONS = [f1, f2, f3, f4] + diff --git a/pybot/drivers/hotplug/button.py b/pybot/drivers/hotplug/button.py new file mode 100644 index 0000000..f714ecf --- /dev/null +++ b/pybot/drivers/hotplug/button.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +GET_VALUE = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'getValue', + 'call': GET_VALUE, + 'params': 0, + 'read': 2 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hotplug/distanc.py b/pybot/drivers/hotplug/distanc.py new file mode 100644 index 0000000..db7e1c1 --- /dev/null +++ b/pybot/drivers/hotplug/distanc.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +GET_VALUE = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'getValue', + 'call': GET_VALUE, + 'params': 0, + 'read': 3 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hotplug/grey.py b/pybot/drivers/hotplug/grey.py new file mode 100644 index 0000000..db7e1c1 --- /dev/null +++ b/pybot/drivers/hotplug/grey.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +GET_VALUE = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'getValue', + 'call': GET_VALUE, + 'params': 0, + 'read': 3 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hotplug/led.py b/pybot/drivers/hotplug/led.py new file mode 100644 index 0000000..0703d54 --- /dev/null +++ b/pybot/drivers/hotplug/led.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +TURN = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'turn', + 'call': TURN, + 'params': 1, + 'read': 1 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hotplug/light.py b/pybot/drivers/hotplug/light.py new file mode 100644 index 0000000..db7e1c1 --- /dev/null +++ b/pybot/drivers/hotplug/light.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +GET_VALUE = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'getValue', + 'call': GET_VALUE, + 'params': 0, + 'read': 3 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hotplug/res.py b/pybot/drivers/hotplug/res.py new file mode 100644 index 0000000..db7e1c1 --- /dev/null +++ b/pybot/drivers/hotplug/res.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +GET_VALUE = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'getValue', + 'call': GET_VALUE, + 'params': 0, + 'read': 3 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/hotplug/volt.py b/pybot/drivers/hotplug/volt.py new file mode 100644 index 0000000..db7e1c1 --- /dev/null +++ b/pybot/drivers/hotplug/volt.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +GET_VALUE = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'getValue', + 'call': GET_VALUE, + 'params': 0, + 'read': 3 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/lback.py b/pybot/drivers/lback.py new file mode 100644 index 0000000..859eedb --- /dev/null +++ b/pybot/drivers/lback.py @@ -0,0 +1,19 @@ + +RD_VERSION = 0x00 +SEND_DATA = 0x01 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'send', + 'call': SEND_DATA, + 'params': 1, + 'read': 1 +} + +FUNCTIONS = [f1, f2] diff --git a/pybot/drivers/motors.py b/pybot/drivers/motors.py new file mode 100644 index 0000000..02421d9 --- /dev/null +++ b/pybot/drivers/motors.py @@ -0,0 +1,27 @@ + +RD_VERSION = 0x00 +SET_VEL_2MTR = 0x01 +SET_VEL_MTR = 0x02 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +f2 = { + 'name': 'setvel2mtr', + 'call': SET_VEL_2MTR, + 'params': 6, + 'read': 1 +} + +f3 = { + 'name': 'setvelmtr', + 'call': SET_VEL_MTR, + 'params': 4, + 'read': 1 +} + +FUNCTIONS = [f1, f2, f3] diff --git a/pybot/drivers/pnp.py b/pybot/drivers/pnp.py new file mode 100644 index 0000000..3457126 --- /dev/null +++ b/pybot/drivers/pnp.py @@ -0,0 +1,11 @@ + +RD_VERSION = 0x00 + +f1 = { + 'name': 'getVersion', + 'call': RD_VERSION, + 'params': 0, + 'read': 3 +} + +FUNCTIONS = [f1] diff --git a/pybot/pybot_server.py b/pybot/pybot_server.py new file mode 100755 index 0000000..0b6000d --- /dev/null +++ b/pybot/pybot_server.py @@ -0,0 +1,146 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# Pybot server +# +# Copyright (c) 2012-2013 Butiá Team butia@fing.edu.uy +# Butia is a free and open robotic platform +# www.fing.edu.uy/inco/proyectos/butia +# Facultad de Ingeniería - Universidad de la República - Uruguay +# +# 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 of the License, 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 +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import select +import socket +import usb4butia + +argv = sys.argv[:] + +PYBOT_HOST = 'localhost' +PYBOT_PORT = 2009 +BUFSIZ = 1024 +MAX_CLIENTS = 4 + + +class Server(): + + def __init__(self, debug=False): + self.debug = debug + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.bind((PYBOT_HOST, PYBOT_PORT)) + self.socket.listen(MAX_CLIENTS) + self.clients = {} + self.robot = usb4butia.USB4Butia(self.debug) + + def call_aux(self, modulename, board_number, number, function, params): + if modulename == 'lback': + par = params + else: + par = [] + for e in params: + par.append(int(e)) + return self.robot.callModule(modulename, board_number, number, function, par) + + def init_server(self): + + inputs = [self.socket] + + run = True + while run: + + try: + inputready,outputready,exceptready = select.select(inputs, [], []) + except Exception, err: + print 'Error in select', err + break + + for s in inputready: + if s == self.socket: + client, addr = self.socket.accept() + print 'New client: ', str(addr) + inputs.append(client) + self.clients[client] = addr + else: + data = s.recv(BUFSIZ) + if data: + result = '' + # remove end line characters if become from telnet + r = data.replace('\r', '') + r = r.replace('\n', '') + r = r.split(' ') + + #print 'split', r + + if len(r) > 0: + if r[0] == 'QUIT': + result = 'BYE' + run = False + elif r[0] == 'CLIENTS': + first = True + for c in self.clients: + addr = self.clients[c] + if first: + result = result + str(addr[0]) + ', ' + str(addr[1]) + first = False + else: + result = result + '\n' + str(addr[0]) + ', ' + str(addr[1]) + elif r[0] == 'LIST': + l = self.robot.get_modules_list() + result = ','.join(l) + elif r[0] == 'REFRESH': + self.robot.refresh() + elif r[0] == 'BUTIA_COUNT': + result = self.robot.get_butia_count() + elif r[0] == 'CALL': + if len(r) >= 3: + board = 0 + number = 0 + mbn = r[1] + if mbn.count('@') > 0: + modulename, bn = mbn.split('@') + board, number = bn.split(':') + else: + if mbn.count(':') > 0: + modulename, number = mbn.split(':') + else: + modulename = mbn + function = r[2] + par = r[3:] + result = self.call_aux(modulename, int(board), int(number), function, par) + + result = str(result) + try: + s.send(result + '\n') + except: + print 'Send fails' + + else: + s.close() + inputs.remove(s) + self.clients.pop(s) + + print 'Closing server' + self.socket.close() + self.robot.close() + + +if __name__ == "__main__": + if 'DEBUG' in argv: + s = Server(True) + else: + s = Server() + s.init_server() + diff --git a/pybot/usb/__init__.py b/pybot/usb/__init__.py new file mode 100644 index 0000000..8909cf2 --- /dev/null +++ b/pybot/usb/__init__.py @@ -0,0 +1,92 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +r"""PyUSB - Easy USB access in Python + +This package exports the following modules and subpackages: + + core - the main USB implementation + legacy - the compatibility layer with 0.x version + backend - the support for backend implementations. + +Since version 1.0, main PyUSB implementation lives in the 'usb.core' +module. New applications are encouraged to use it. +""" + +import logging +import os + +__author__ = 'Wander Lairson Costa' + +__all__ = ['legacy', 'core', 'backend', 'util'] + + +def _setup_log(): + from usb import _debug + logger = logging.getLogger('usb') + debug_level = os.getenv('PYUSB_DEBUG_LEVEL') + + if debug_level is not None: + _debug.enable_tracing(True) + filename = os.getenv('PYUSB_LOG_FILENAME') + + LEVELS = {'debug': logging.DEBUG, + 'info': logging.INFO, + 'warning': logging.WARNING, + 'error': logging.ERROR, + 'critical': logging.CRITICAL} + + level = LEVELS.get(debug_level, logging.CRITICAL + 10) + logger.setLevel(level = level) + + try: + handler = logging.FileHandler(filename) + except: + handler = logging.StreamHandler() + + fmt = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s') + handler.setFormatter(fmt) + logger.addHandler(handler) + else: + class NullHandler(logging.Handler): + def emit(self, record): + pass + + # We set the log level to avoid delegation to the + # parent log handler (if there is one). + # Thanks to Chris Clark to pointing this out. + logger.setLevel(logging.CRITICAL + 10) + + logger.addHandler(NullHandler()) + + +_setup_log() + +# We import all 'legacy' module symbols to provide compatility +# with applications that use 0.x versions. +from usb.legacy import * diff --git a/pybot/usb/_debug.py b/pybot/usb/_debug.py new file mode 100644 index 0000000..13b0ced --- /dev/null +++ b/pybot/usb/_debug.py @@ -0,0 +1,77 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +__author__ = 'Wander Lairson Costa' + +__all__ = ['methodtrace', 'functiontrace'] + +import logging +import usb._interop as _interop + +_enable_tracing = False + +def enable_tracing(enable): + global _enable_tracing + _enable_tracing = enable + +def _trace_function_call(logger, fname, *args, **named_args): + logger.debug( + # TODO: check if 'f' is a method or a free function + fname + '(' + \ + ', '.join((str(val) for val in args)) + \ + ', '.join((name + '=' + str(val) for name, val in named_args.items())) + ')' + ) + +# decorator for methods calls tracing +def methodtrace(logger): + def decorator_logging(f): + if not _enable_tracing: + return f + def do_trace(*args, **named_args): + # this if is just a optimization to avoid unecessary string formatting + if logging.DEBUG >= logger.getEffectiveLevel(): + fn = type(args[0]).__name__ + '.' + f.__name__ + _trace_function_call(logger, fn, *args[1:], **named_args) + return f(*args, **named_args) + _interop._update_wrapper(do_trace, f) + return do_trace + return decorator_logging + +# decorator for methods calls tracing +def functiontrace(logger): + def decorator_logging(f): + if not _enable_tracing: + return f + def do_trace(*args, **named_args): + # this if is just a optimization to avoid unecessary string formatting + if logging.DEBUG >= logger.getEffectiveLevel(): + _trace_function_call(logger, f.__name__, *args, **named_args) + return f(*args, **named_args) + _interop._update_wrapper(do_trace, f) + return do_trace + return decorator_logging diff --git a/pybot/usb/_interop.py b/pybot/usb/_interop.py new file mode 100644 index 0000000..d6d0a6c --- /dev/null +++ b/pybot/usb/_interop.py @@ -0,0 +1,137 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +# All the hacks necessary to assure compatibility across all +# supported versions come here. +# Please, note that there is one version check for each +# hack we need to do, this makes maintenance easier... ^^ + +import sys +import array + +__all__ = ['_reduce', '_set', '_next', '_groupby', '_sorted', '_update_wrapper'] + +# we support Python >= 2.3 +assert sys.hexversion >= 0x020300f0 + +# On Python 3, reduce became a functools module function +try: + import functools + _reduce = functools.reduce +except (ImportError, AttributeError): + _reduce = reduce + +# we only have the builtin set type since 2.5 version +try: + _set = set +except NameError: + import sets + _set = sets.Set + +# On Python >= 2.6, we have the builtin next() function +# On Python 2.5 and before, we have to call the iterator method next() +def _next(iter): + try: + return next(iter) + except NameError: + return iter.next() + +# groupby is available only since 2.4 version +try: + import itertools + _groupby = itertools.groupby +except (ImportError, AttributeError): + # stolen from Python docs + class _groupby(object): + # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B + # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D + def __init__(self, iterable, key=None): + if key is None: + key = lambda x: x + self.keyfunc = key + self.it = iter(iterable) + self.tgtkey = self.currkey = self.currvalue = object() + def __iter__(self): + return self + def next(self): + while self.currkey == self.tgtkey: + self.currvalue = _next(self.it) # Exit on StopIteration + self.currkey = self.keyfunc(self.currvalue) + self.tgtkey = self.currkey + return (self.currkey, self._grouper(self.tgtkey)) + def _grouper(self, tgtkey): + while self.currkey == tgtkey: + yield self.currvalue + self.currvalue = _next(self.it) # Exit on StopIteration + self.currkey = self.keyfunc(self.currvalue) + +# builtin sorted function is only availale since 2.4 version +try: + _sorted = sorted +except NameError: + def _sorted(l, key=None, reverse=False): + # sort function on Python 2.3 does not + # support 'key' parameter + class KeyToCmp(object): + def __init__(self, K): + self.key = K + def __call__(self, x, y): + kx = self.key(x) + ky = self.key(y) + if kx < ky: + return reverse and 1 or -1 + elif kx > ky: + return reverse and -1 or 1 + else: + return 0 + tmp = list(l) + tmp.sort(KeyToCmp(key)) + return tmp + +try: + import functools + _update_wrapper = functools.update_wrapper +except (ImportError, AttributeError): + def _update_wrapper(wrapper, wrapped): + wrapper.__name__ = wrapped.__name__ + wrapper.__module__ = wrapped.__module__ + wrapper.__doc__ = wrapped.__doc__ + wrapper.__dict__ = wrapped.__dict__ + +def as_array(data=None): + if data is None: + return array.array('B') + try: + return array.array('B', data) + except TypeError: + # When you pass a unicode string or a character sequence, + # you get a TypeError if first parameter does not match + a = array.array('B') + a.fromstring(data) + return a + diff --git a/pybot/usb/backend/__init__.py b/pybot/usb/backend/__init__.py new file mode 100644 index 0000000..67ee00f --- /dev/null +++ b/pybot/usb/backend/__init__.py @@ -0,0 +1,368 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +r"""usb.backend - Backend interface. + +This module exports: + +IBackend - backend interface. + +Backends are Python objects which implement the IBackend interface. +The easiest way to do so is inherinting from IBackend. + +PyUSB already provides backends for libusb versions 0.1 and 1.0, +and OpenUSB library. Backends modules included with PyUSB are required to +export the get_backend() function, which returns an instance of a backend +object. You can provide your own customized backend if you +want to. Bellow you find a skeleton of a backend implementation module: + +import usb.backend + +class MyBackend(usb.backend.IBackend): + pass + +def get_backend(): + return MyBackend() + +You can use your customized backend by passing it as the backend parameter of the +usb.core.find() function. For example: + +import custom_backend +import usb.core + +myidVendor = 0xfffe +myidProduct = 0x0001 + +mybackend = custom_backend.get_backend() + +dev = usb.core.find(backend = mybackend, idProduct=myidProduct, + idVendor=myidVendor) + +For custom backends, you are not required to supply the get_backend() function, +since the application code will instantiate the backend. + +If you do not provide a backend to the find() function, it will use one of the +defaults backend according to its internal rules. For details, consult the +find() function documentation. +""" + +__author__ = 'Wander Lairson Costa' + +__all__ = ['IBackend', 'libusb01', 'libusb10', 'openusb'] + +def _not_implemented(func): + raise NotImplementedError(func.__name__) + +class IBackend(object): + r"""Backend interface. + + IBackend is the basic interface for backend implementations. By default, + the methods of the interface raise a NotImplementedError exception. A + backend implementation should replace the methods to provide the funcionality + necessary. + + As Python is a dynamic typed language, you are not obligated to inherit from + IBackend: everything that bahaves like an IBackend is an IBackend. But you + are strongly recommended to do so, inheriting from IBackend provides consistent + default behavior. + """ + def enumerate_devices(self): + r"""This function is required to return an iterable object which + yields an implementation defined device identification for each + USB device found in the system. + + The device identification object is used as argument to other methods + of the interface. + """ + _not_implemented(self.enumerate_devices) + + def get_device_descriptor(self, dev): + r"""Return the device descriptor of the given device. + + The object returned is required to have all the Device Descriptor + fields accessible as member variables. They must be convertible (but + not required to be equal) to the int type. + + dev is an object yielded by the iterator returned by the enumerate_devices() + method. + """ + _not_implemented(self.get_device_descriptor) + + def get_configuration_descriptor(self, dev, config): + r"""Return a configuration descriptor of the given device. + + The object returned is required to have all the Configuration Descriptor + fields acessible as member variables. They must be convertible (but + not required to be equal) to the int type. + + The dev parameter is the already described device identification object. + config is the logical index of the configuration (not the bConfigurationValue + field). By "logical index" we mean the relative order of the configurations + returned by the peripheral as a result of GET_DESCRIPTOR request. + """ + _not_implemented(self.get_configuration_descriptor) + + def get_interface_descriptor(self, dev, intf, alt, config): + r"""Return an interface descriptor of the given device. + + The object returned is required to have all the Interface Descriptor + fields accessible as member variables. They must be convertible (but + not required to be equal) to the int type. + + The dev parameter is the already described device identification object. + The intf parameter is the interface logical index (not the bInterfaceNumber field) + and alt is the alternate setting logical index (not the bAlternateSetting value). + Not every interface has more than one alternate setting. In this case, the alt + parameter should be zero. config is the configuration logical index (not the + bConfigurationValue field). + """ + _not_implemented(self.get_interface_descriptor) + + def get_endpoint_descriptor(self, dev, ep, intf, alt, config): + r"""Return an endpoint descriptor of the given device. + + The object returned is required to have all the Endpoint Descriptor + fields acessible as member variables. They must be convertible (but + not required to be equal) to the int type. + + The ep parameter is the endpoint logical index (not the bEndpointAddress + field) of the endpoint descriptor desired. intf, alt and config are the same + values already described in the get_interface_descriptor() method. + """ + _not_implemented(self.get_endpoint_descriptor) + + def open_device(self, dev): + r"""Open the device for data exchange. + + This method opens the device identified by the dev parameter for communication. + This method must be called before calling any communication related method, such + as transfer methods. + + It returns a handle identifying the communication instance. This handle must be + passed to the communication methods. + """ + _not_implemented(self.open_device) + + def close_device(self, dev_handle): + r"""Close the device handle. + + This method closes the device communication channel and releases any + system resources related to it. + """ + _not_implemented(self.close_device) + + def set_configuration(self, dev_handle, config_value): + r"""Set the active device configuration. + + This method should be called to set the active configuration + of the device. The dev_handle parameter is the value returned + by the open_device() method and the config_value parameter is the + bConfigurationValue field of the related configuration descriptor. + """ + _not_implemented(self.set_configuration) + + def get_configuration(self, dev_handle): + r"""Get the current active device configuration. + + This method returns the bConfigurationValue of the currently + active configuration. Depending on the backend and the OS, + either a cached value may be returned or a control request may + be issued. The dev_handle parameter is the value returned by + the open_device method. + """ + _not_implemented(self.get_configuration) + + def set_interface_altsetting(self, dev_handle, intf, altsetting): + r"""Set the interface alternate setting. + + This method should only be called when the interface has more than + one alternate setting. The dev_handle is the value returned by the + open_device() method. intf and altsetting are respectivelly the + bInterfaceNumber and bAlternateSetting fields of the related interface. + """ + _not_implemented(self.set_interface_altsetting) + + def claim_interface(self, dev_handle, intf): + r"""Claim the given interface. + + Interface claiming is not related to USB spec itself, but it is + generally an necessary call of the USB libraries. It requests exclusive + access to the interface on the system. This method must be called + before using one of the transfer methods. + + dev_handle is the value returned by the open_device() method and + intf is the bInterfaceNumber field of the desired interface. + """ + _not_implemented(self.claim_interface) + + def release_interface(self, dev_handle, intf): + r"""Release the claimed interface. + + dev_handle and intf are the same parameters of the claim_interface + method. + """ + _not_implemented(self.release_interface) + + def bulk_write(self, dev_handle, ep, intf, data, timeout): + r"""Perform a bulk write. + + dev_handle is the value returned by the open_device() method. + The ep parameter is the bEndpointAddress field whose endpoint + the data will be sent to. intf is the bInterfaceNumber field + of the interface containing the endpoint. The data parameter + is the data to be sent. It must be an instance of the array.array + class. The timeout parameter specifies a time limit to the operation + in miliseconds. + + The method returns the number of bytes written. + """ + _not_implemented(self.bulk_write) + + def bulk_read(self, dev_handle, ep, intf, size, timeout): + r"""Perform a bulk read. + + dev_handle is the value returned by the open_device() method. + The ep parameter is the bEndpointAddress field whose endpoint + the data will be received from. intf is the bInterfaceNumber field + of the interface containing the endpoint. The size parameter + is the number of bytes to be read. The timeout parameter specifies + a time limit to the operation in miliseconds. + + The method returns an array.array object containing the data read. + """ + _not_implemented(self.bulk_read) + + def intr_write(self, dev_handle, ep, intf, data, timeout): + r"""Perform an interrupt write. + + dev_handle is the value returned by the open_device() method. + The ep parameter is the bEndpointAddress field whose endpoint + the data will be sent to. intf is the bInterfaceNumber field + of the interface containing the endpoint. The data parameter + is the data to be sent. It must be an instance of the array.array + class. The timeout parameter specifies a time limit to the operation + in miliseconds. + + The method returns the number of bytes written. + """ + _not_implemented(self.intr_write) + + def intr_read(self, dev_handle, ep, intf, size, timeout): + r"""Perform an interrut read. + + dev_handle is the value returned by the open_device() method. + The ep parameter is the bEndpointAddress field whose endpoint + the data will be received from. intf is the bInterfaceNumber field + of the interface containing the endpoint. The size parameter + is the number of bytes to be read. The timeout parameter specifies + a time limit to the operation in miliseconds. + + The method returns an array.array object containing the data read. + """ + _not_implemented(self.intr_read) + + def iso_write(self, dev_handle, ep, intf, data, timeout): + r"""Perform an isochronous write. + + dev_handle is the value returned by the open_device() method. + The ep parameter is the bEndpointAddress field whose endpoint + the data will be sent to. intf is the bInterfaceNumber field + of the interface containing the endpoint. The data parameter + is the data to be sent.It must be an instance of the array.array + class. The timeout parameter specifies a time limit to the operation + in miliseconds. + + The method returns the number of bytes written. + """ + _not_implemented(self.iso_write) + + def iso_read(self, dev_handle, ep, intf, size, timeout): + r"""Perform an isochronous read. + + dev_handle is the value returned by the open_device() method. + The ep parameter is the bEndpointAddress field whose endpoint + the data will be received from. intf is the bInterfaceNumber field + of the interface containing the endpoint. The size parameter + is the number of bytes to be read. The timeout parameter specifies + a time limit to the operation in miliseconds. + + The method returns an array.array object containing the data read. + """ + _not_implemented(self.iso_read) + + def ctrl_transfer(self, + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + data_or_wLength, + timeout): + r"""Perform a control transfer on the endpoint 0. + + The direction of the transfer is inferred from the bmRequestType + field of the setup packet. + + dev_handle is the value returned by the open_device() method. + bmRequestType, bRequest, wValue and wIndex are the same fields + of the setup packet. data_or_wLength is either the payload to be sent + to the device, if any, as an array.array object (None there is no + payload) for OUT requests in the data stage or the wLength field + specifying the number of bytes to read for IN requests in the data + stage. The timeout parameter specifies a time limit to the operation + in miliseconds. + + Return the number of bytes written (for OUT transfers) or the data + read (for IN transfers), as an array.array object. + """ + _not_implemented(self.ctrl_transfer) + + def reset_device(self, dev_handle): + r"""Reset the device.""" + _not_implemented(self.reset_device) + + def is_kernel_driver_active(self, dev_handle, intf): + r"""Determine if a kernel driver is active on an interface. + + If a kernel driver is active, you cannot claim the interface, + and the backend will be unable to perform I/O. + """ + _not_implemented(self.is_kernel_driver_active) + + def detach_kernel_driver(self, dev_handle, intf): + r"""Detach a kernel driver from an interface. + + If successful, you will then be able to claim the interface + and perform I/O. + """ + _not_implemented(self.detach_kernel_driver) + + def attach_kernel_driver(self, dev_handle, intf): + r"""Re-attach an interface's kernel driver, which was previously + detached using detach_kernel_driver().""" + _not_implemented(self.attach_kernel_driver) diff --git a/pybot/usb/backend/libusb0.py b/pybot/usb/backend/libusb0.py new file mode 100644 index 0000000..a9271c6 --- /dev/null +++ b/pybot/usb/backend/libusb0.py @@ -0,0 +1,586 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +from ctypes import * +import ctypes.util +import os +import usb.backend +import usb.util +import sys +from usb.core import USBError +from usb._debug import methodtrace +import usb._interop as _interop +import logging + +__author__ = 'Wander Lairson Costa' + +__all__ = ['get_backend'] + +_logger = logging.getLogger('usb.backend.libusb0') + +# usb.h + +_PC_PATH_MAX = 4 + +if sys.platform.find('bsd') != -1 or sys.platform.find('mac') != -1 or \ + sys.platform.find('darwin') != -1: + _PATH_MAX = 1024 +elif sys.platform == 'win32' or sys.platform == 'cygwin': + _PATH_MAX = 511 +else: + _PATH_MAX = os.pathconf('.', _PC_PATH_MAX) + +# libusb-win32 makes all structures packed, while +# default libusb only does for some structures +# _PackPolicy defines the structure packing according +# to the platform. +class _PackPolicy(object): + pass + +if sys.platform == 'win32' or sys.platform == 'cygwin': + _PackPolicy._pack_ = 1 + +# Data structures + +class _usb_descriptor_header(Structure): + _pack_ = 1 + _fields_ = [('blength', c_uint8), + ('bDescriptorType', c_uint8)] + +class _usb_string_descriptor(Structure): + _pack_ = 1 + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('wData', c_uint16)] + +class _usb_endpoint_descriptor(Structure, _PackPolicy): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bEndpointAddress', c_uint8), + ('bmAttributes', c_uint8), + ('wMaxPacketSize', c_uint16), + ('bInterval', c_uint8), + ('bRefresh', c_uint8), + ('bSynchAddress', c_uint8), + ('extra', POINTER(c_uint8)), + ('extralen', c_int)] + +class _usb_interface_descriptor(Structure, _PackPolicy): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bInterfaceNumber', c_uint8), + ('bAlternateSetting', c_uint8), + ('bNumEndpoints', c_uint8), + ('bInterfaceClass', c_uint8), + ('bInterfaceSubClass', c_uint8), + ('bInterfaceProtocol', c_uint8), + ('iInterface', c_uint8), + ('endpoint', POINTER(_usb_endpoint_descriptor)), + ('extra', POINTER(c_uint8)), + ('extralen', c_int)] + +class _usb_interface(Structure, _PackPolicy): + _fields_ = [('altsetting', POINTER(_usb_interface_descriptor)), + ('num_altsetting', c_int)] + +class _usb_config_descriptor(Structure, _PackPolicy): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('wTotalLength', c_uint16), + ('bNumInterfaces', c_uint8), + ('bConfigurationValue', c_uint8), + ('iConfiguration', c_uint8), + ('bmAttributes', c_uint8), + ('bMaxPower', c_uint8), + ('interface', POINTER(_usb_interface)), + ('extra', POINTER(c_uint8)), + ('extralen', c_int)] + +class _usb_device_descriptor(Structure, _PackPolicy): + _pack_ = 1 + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bcdUSB', c_uint16), + ('bDeviceClass', c_uint8), + ('bDeviceSubClass', c_uint8), + ('bDeviceProtocol', c_uint8), + ('bMaxPacketSize0', c_uint8), + ('idVendor', c_uint16), + ('idProduct', c_uint16), + ('bcdDevice', c_uint16), + ('iManufacturer', c_uint8), + ('iProduct', c_uint8), + ('iSerialNumber', c_uint8), + ('bNumConfigurations', c_uint8)] + +class _usb_device(Structure, _PackPolicy): + pass + +class _usb_bus(Structure, _PackPolicy): + pass + +_usb_device._fields_ = [('next', POINTER(_usb_device)), + ('prev', POINTER(_usb_device)), + ('filename', c_int8 * (_PATH_MAX + 1)), + ('bus', POINTER(_usb_bus)), + ('descriptor', _usb_device_descriptor), + ('config', POINTER(_usb_config_descriptor)), + ('dev', c_void_p), + ('devnum', c_uint8), + ('num_children', c_ubyte), + ('children', POINTER(POINTER(_usb_device)))] + +_usb_bus._fields_ = [('next', POINTER(_usb_bus)), + ('prev', POINTER(_usb_bus)), + ('dirname', c_char * (_PATH_MAX + 1)), + ('devices', POINTER(_usb_device)), + ('location', c_uint32), + ('root_dev', POINTER(_usb_device))] + +_usb_dev_handle = c_void_p + +class _DeviceDescriptor: + def __init__(self, dev): + desc = dev.descriptor + self.bLength = desc.bLength + self.bDescriptorType = desc.bDescriptorType + self.bcdUSB = desc.bcdUSB + self.bDeviceClass = desc.bDeviceClass + self.bDeviceSubClass = desc.bDeviceSubClass + self.bDeviceProtocol = desc.bDeviceProtocol + self.bMaxPacketSize0 = desc.bMaxPacketSize0 + self.idVendor = desc.idVendor + self.idProduct = desc.idProduct + self.bcdDevice = desc.bcdDevice + self.iManufacturer = desc.iManufacturer + self.iProduct = desc.iProduct + self.iSerialNumber = desc.iSerialNumber + self.bNumConfigurations = desc.bNumConfigurations + self.address = dev.devnum + self.bus = dev.bus[0].location + + self.port_number = None +_lib = None + +def _load_library(): + if sys.platform != 'cygwin': + candidates = ('usb-0.1', 'usb', 'libusb0') + for candidate in candidates: + libname = ctypes.util.find_library(candidate) + if libname is not None: break + else: + # corner cases + # cygwin predefines library names with 'cyg' instead of 'lib' + try: + return CDLL('cygusb0.dll') + except: + _logger.error('Libusb 0 could not be loaded in cygwin', exc_info=True) + + raise OSError('USB library could not be found') + return CDLL(libname) + +def _setup_prototypes(lib): + # usb_dev_handle *usb_open(struct usb_device *dev); + lib.usb_open.argtypes = [POINTER(_usb_device)] + lib.usb_open.restype = _usb_dev_handle + + # int usb_close(usb_dev_handle *dev); + lib.usb_close.argtypes = [_usb_dev_handle] + + # int usb_get_string(usb_dev_handle *dev, + # int index, + # int langid, + # char *buf, + # size_t buflen); + lib.usb_get_string.argtypes = [ + _usb_dev_handle, + c_int, + c_int, + c_char_p, + c_size_t + ] + + # int usb_get_string_simple(usb_dev_handle *dev, + # int index, + # char *buf, + # size_t buflen); + lib.usb_get_string_simple.argtypes = [ + _usb_dev_handle, + c_int, + c_char_p, + c_size_t + ] + + # int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, + # int ep, + # unsigned char type, + # unsigned char index, + # void *buf, + # int size); + lib.usb_get_descriptor_by_endpoint.argtypes = [ + _usb_dev_handle, + c_int, + c_ubyte, + c_ubyte, + c_void_p, + c_int + ] + + # int usb_get_descriptor(usb_dev_handle *udev, + # unsigned char type, + # unsigned char index, + # void *buf, + # int size); + lib.usb_get_descriptor.argtypes = [ + _usb_dev_handle, + c_ubyte, + c_ubyte, + c_void_p, + c_int + ] + + # int usb_bulk_write(usb_dev_handle *dev, + # int ep, + # const char *bytes, + # int size, + # int timeout); + lib.usb_bulk_write.argtypes = [ + _usb_dev_handle, + c_int, + c_char_p, + c_int, + c_int + ] + + # int usb_bulk_read(usb_dev_handle *dev, + # int ep, + # char *bytes, + # int size, + # int timeout); + lib.usb_bulk_read.argtypes = [ + _usb_dev_handle, + c_int, + c_char_p, + c_int, + c_int + ] + + # int usb_interrupt_write(usb_dev_handle *dev, + # int ep, + # const char *bytes, + # int size, + # int timeout); + lib.usb_interrupt_write.argtypes = [ + _usb_dev_handle, + c_int, + c_char_p, + c_int, + c_int + ] + + # int usb_interrupt_read(usb_dev_handle *dev, + # int ep, + # char *bytes, + # int size, + # int timeout); + lib.usb_interrupt_read.argtypes = [ + _usb_dev_handle, + c_int, + c_char_p, + c_int, + c_int + ] + + # int usb_control_msg(usb_dev_handle *dev, + # int requesttype, + # int request, + # int value, + # int index, + # char *bytes, + # int size, + # int timeout); + lib.usb_control_msg.argtypes = [ + _usb_dev_handle, + c_int, + c_int, + c_int, + c_int, + c_char_p, + c_int, + c_int + ] + + # int usb_set_configuration(usb_dev_handle *dev, int configuration); + lib.usb_set_configuration.argtypes = [_usb_dev_handle, c_int] + + # int usb_claim_interface(usb_dev_handle *dev, int interface); + lib.usb_claim_interface.argtypes = [_usb_dev_handle, c_int] + + # int usb_release_interface(usb_dev_handle *dev, int interface); + lib.usb_release_interface.argtypes = [_usb_dev_handle, c_int] + + # int usb_set_altinterface(usb_dev_handle *dev, int alternate); + lib.usb_set_altinterface.argtypes = [_usb_dev_handle, c_int] + + # int usb_resetep(usb_dev_handle *dev, unsigned int ep); + lib.usb_resetep.argtypes = [_usb_dev_handle, c_int] + + # int usb_clear_halt(usb_dev_handle *dev, unsigned int ep); + lib.usb_clear_halt.argtypes = [_usb_dev_handle, c_int] + + # int usb_reset(usb_dev_handle *dev); + lib.usb_reset.argtypes = [_usb_dev_handle] + + # char *usb_strerror(void); + lib.usb_strerror.argtypes = [] + lib.usb_strerror.restype = c_char_p + + # void usb_set_debug(int level); + lib.usb_set_debug.argtypes = [c_int] + + # struct usb_device *usb_device(usb_dev_handle *dev); + lib.usb_device.argtypes = [_usb_dev_handle] + lib.usb_device.restype = POINTER(_usb_device) + + # struct usb_bus *usb_get_busses(void); + lib.usb_get_busses.restype = POINTER(_usb_bus) + +def _check(retval): + if retval is None: + errmsg = _lib.usb_strerror() + else: + ret = int(retval) + if ret < 0: + errmsg = _lib.usb_strerror() + # No error means that we need to get the error + # message from the return code + # Thanks to Nicholas Wheeler to point out the problem... + # Also see issue #2860940 + if errmsg.lower() == 'no error': + errmsg = os.strerror(-ret) + else: + return ret + raise USBError(errmsg, ret) + +# implementation of libusb 0.1.x backend +class _LibUSB(usb.backend.IBackend): + @methodtrace(_logger) + def enumerate_devices(self): + _check(_lib.usb_find_busses()) + _check(_lib.usb_find_devices()) + bus = _lib.usb_get_busses() + while bool(bus): + dev = bus[0].devices + while bool(dev): + yield dev[0] + dev = dev[0].next + bus = bus[0].next + + @methodtrace(_logger) + def get_device_descriptor(self, dev): + return _DeviceDescriptor(dev) + + @methodtrace(_logger) + def get_configuration_descriptor(self, dev, config): + if config >= dev.descriptor.bNumConfigurations: + raise IndexError('Invalid configuration index ' + str(config)) + return dev.config[config] + + @methodtrace(_logger) + def get_interface_descriptor(self, dev, intf, alt, config): + cfgdesc = self.get_configuration_descriptor(dev, config) + if intf >= cfgdesc.bNumInterfaces: + raise IndexError('Invalid interface index ' + str(interface)) + interface = cfgdesc.interface[intf] + if alt >= interface.num_altsetting: + raise IndexError('Invalid alternate setting index ' + str(alt)) + return interface.altsetting[alt] + + @methodtrace(_logger) + def get_endpoint_descriptor(self, dev, ep, intf, alt, config): + interface = self.get_interface_descriptor(dev, intf, alt, config) + if ep >= interface.bNumEndpoints: + raise IndexError('Invalid endpoint index ' + str(ep)) + return interface.endpoint[ep] + + @methodtrace(_logger) + def open_device(self, dev): + return _check(_lib.usb_open(dev)) + + @methodtrace(_logger) + def close_device(self, dev_handle): + _check(_lib.usb_close(dev_handle)) + + @methodtrace(_logger) + def set_configuration(self, dev_handle, config_value): + _check(_lib.usb_set_configuration(dev_handle, config_value)) + + @methodtrace(_logger) + def set_interface_altsetting(self, dev_handle, intf, altsetting): + _check(_lib.usb_set_altinterface(dev_handle, altsetting)) + + @methodtrace(_logger) + def get_configuration(self, dev_handle): + bmRequestType = usb.util.build_request_type( + usb.util.CTRL_IN, + usb.util.CTRL_TYPE_STANDARD, + usb.util.CTRL_RECIPIENT_DEVICE + ) + return self.ctrl_transfer(dev_handle, + bmRequestType, + 0x08, + 0, + 0, + 1, + 100 + )[0] + + + @methodtrace(_logger) + def claim_interface(self, dev_handle, intf): + _check(_lib.usb_claim_interface(dev_handle, intf)) + + @methodtrace(_logger) + def release_interface(self, dev_handle, intf): + _check(_lib.usb_release_interface(dev_handle, intf)) + + @methodtrace(_logger) + def bulk_write(self, dev_handle, ep, intf, data, timeout): + return self.__write(_lib.usb_bulk_write, + dev_handle, + ep, + intf, + data, timeout) + + @methodtrace(_logger) + def bulk_read(self, dev_handle, ep, intf, size, timeout): + return self.__read(_lib.usb_bulk_read, + dev_handle, + ep, + intf, + size, + timeout) + + @methodtrace(_logger) + def intr_write(self, dev_handle, ep, intf, data, timeout): + return self.__write(_lib.usb_interrupt_write, + dev_handle, + ep, + intf, + data, + timeout) + + @methodtrace(_logger) + def intr_read(self, dev_handle, ep, intf, size, timeout): + return self.__read(_lib.usb_interrupt_read, + dev_handle, + ep, + intf, + size, + timeout) + + @methodtrace(_logger) + def ctrl_transfer(self, + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + data_or_wLength, + timeout): + if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: + address, length = data_or_wLength.buffer_info() + length *= data_or_wLength.itemsize + return _check(_lib.usb_control_msg( + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + cast(address, c_char_p), + length, + timeout + )) + else: + data = _interop.as_array((0,) * data_or_wLength) + read = int(_check(_lib.usb_control_msg( + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + cast(data.buffer_info()[0], + c_char_p), + data_or_wLength, + timeout + ))) + return data[:read] + + @methodtrace(_logger) + def reset_device(self, dev_handle): + _check(_lib.usb_reset(dev_handle)) + + @methodtrace(_logger) + def detach_kernel_driver(self, dev_handle, intf): + _check(_lib.usb_detach_kernel_driver_np(dev_handle, intf)) + + def __write(self, fn, dev_handle, ep, intf, data, timeout): + address, length = data.buffer_info() + length *= data.itemsize + return int(_check(fn( + dev_handle, + ep, + cast(address, c_char_p), + length, + timeout + ))) + + def __read(self, fn, dev_handle, ep, intf, size, timeout): + data = _interop.as_array((0,) * size) + address, length = data.buffer_info() + length *= data.itemsize + ret = int(_check(fn( + dev_handle, + ep, + cast(address, c_char_p), + length, + timeout + ))) + return data[:ret] + +def get_backend(): + global _lib + try: + if _lib is None: + _lib = _load_library() + _setup_prototypes(_lib) + _lib.usb_init() + return _LibUSB() + except Exception: + _logger.error('Error loading libusb 0.1 backend', exc_info=True) + return None diff --git a/pybot/usb/backend/libusb1.py b/pybot/usb/backend/libusb1.py new file mode 100644 index 0000000..bd7d16f --- /dev/null +++ b/pybot/usb/backend/libusb1.py @@ -0,0 +1,670 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +from ctypes import * +import ctypes.util +import usb.util +import sys +import logging +from usb._debug import methodtrace +import usb._interop as _interop +import errno + +__author__ = 'Wander Lairson Costa' + +__all__ = [ + 'get_backend', + 'LIBUSB_SUCESS', + 'LIBUSB_ERROR_IO', + 'LIBUSB_ERROR_INVALID_PARAM', + 'LIBUSB_ERROR_ACCESS', + 'LIBUSB_ERROR_NO_DEVICE', + 'LIBUSB_ERROR_NOT_FOUND', + 'LIBUSB_ERROR_BUSY', + 'LIBUSB_ERROR_TIMEOUT', + 'LIBUSB_ERROR_OVERFLOW', + 'LIBUSB_ERROR_PIPE', + 'LIBUSB_ERROR_INTERRUPTED', + 'LIBUSB_ERROR_NO_MEM', + 'LIBUSB_ERROR_NOT_SUPPORTED', + 'LIBUSB_ERROR_OTHER' + ] + +_logger = logging.getLogger('usb.backend.libusb1') + +# libusb.h + +# return codes + +LIBUSB_SUCCESS = 0 +LIBUSB_ERROR_IO = -1 +LIBUSB_ERROR_INVALID_PARAM = -2 +LIBUSB_ERROR_ACCESS = -3 +LIBUSB_ERROR_NO_DEVICE = -4 +LIBUSB_ERROR_NOT_FOUND = -5 +LIBUSB_ERROR_BUSY = -6 +LIBUSB_ERROR_TIMEOUT = -7 +LIBUSB_ERROR_OVERFLOW = -8 +LIBUSB_ERROR_PIPE = -9 +LIBUSB_ERROR_INTERRUPTED = -10 +LIBUSB_ERROR_NO_MEM = -11 +LIBUSB_ERROR_NOT_SUPPORTED = -12 +LIBUSB_ERROR_OTHER = -99 + +# map return codes to strings +_str_error = { + LIBUSB_SUCCESS:'Success (no error)', + LIBUSB_ERROR_IO:'Input/output error', + LIBUSB_ERROR_INVALID_PARAM:'Invalid parameter', + LIBUSB_ERROR_ACCESS:'Access denied (insufficient permissions)', + LIBUSB_ERROR_NO_DEVICE:'No such device (it may have been disconnected)', + LIBUSB_ERROR_NOT_FOUND:'Entity not found', + LIBUSB_ERROR_BUSY:'Resource busy', + LIBUSB_ERROR_TIMEOUT:'Operation timed out', + LIBUSB_ERROR_OVERFLOW:'Overflow', + LIBUSB_ERROR_PIPE:'Pipe error', + LIBUSB_ERROR_INTERRUPTED:'System call interrupted (perhaps due to signal)', + LIBUSB_ERROR_NO_MEM:'Insufficient memory', + LIBUSB_ERROR_NOT_SUPPORTED:'Operation not supported or unimplemented on this platform', + LIBUSB_ERROR_OTHER:'Unknown error' +} + +# map return code to errno values +_libusb_errno = { + LIBUSB_SUCCESS:None, + LIBUSB_ERROR_IO:errno.__dict__.get('EIO', None), + LIBUSB_ERROR_INVALID_PARAM:errno.__dict__.get('EINVAL', None), + LIBUSB_ERROR_ACCESS:errno.__dict__.get('EACCES', None), + LIBUSB_ERROR_NO_DEVICE:errno.__dict__.get('ENODEV', None), + LIBUSB_ERROR_NOT_FOUND:errno.__dict__.get('ENOENT', None), + LIBUSB_ERROR_BUSY:errno.__dict__.get('EBUSY', None), + LIBUSB_ERROR_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None), + LIBUSB_ERROR_OVERFLOW:errno.__dict__.get('EOVERFLOW', None), + LIBUSB_ERROR_PIPE:errno.__dict__.get('EPIPE', None), + LIBUSB_ERROR_INTERRUPTED:errno.__dict__.get('EINTR', None), + LIBUSB_ERROR_NO_MEM:errno.__dict__.get('ENOMEM', None), + LIBUSB_ERROR_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None), + LIBUSB_ERROR_OTHER:None +} + +# Data structures + +class _libusb_endpoint_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bEndpointAddress', c_uint8), + ('bmAttributes', c_uint8), + ('wMaxPacketSize', c_uint16), + ('bInterval', c_uint8), + ('bRefresh', c_uint8), + ('bSynchAddress', c_uint8), + ('extra', POINTER(c_ubyte)), + ('extra_length', c_int)] + +class _libusb_interface_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bInterfaceNumber', c_uint8), + ('bAlternateSetting', c_uint8), + ('bNumEndpoints', c_uint8), + ('bInterfaceClass', c_uint8), + ('bInterfaceSubClass', c_uint8), + ('bInterfaceProtocol', c_uint8), + ('iInterface', c_uint8), + ('endpoint', POINTER(_libusb_endpoint_descriptor)), + ('extra', POINTER(c_ubyte)), + ('extra_length', c_int)] + +class _libusb_interface(Structure): + _fields_ = [('altsetting', POINTER(_libusb_interface_descriptor)), + ('num_altsetting', c_int)] + +class _libusb_config_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('wTotalLength', c_uint16), + ('bNumInterfaces', c_uint8), + ('bConfigurationValue', c_uint8), + ('iConfiguration', c_uint8), + ('bmAttributes', c_uint8), + ('bMaxPower', c_uint8), + ('interface', POINTER(_libusb_interface)), + ('extra', POINTER(c_ubyte)), + ('extra_length', c_int)] + +class _libusb_device_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bcdUSB', c_uint16), + ('bDeviceClass', c_uint8), + ('bDeviceSubClass', c_uint8), + ('bDeviceProtocol', c_uint8), + ('bMaxPacketSize0', c_uint8), + ('idVendor', c_uint16), + ('idProduct', c_uint16), + ('bcdDevice', c_uint16), + ('iManufacturer', c_uint8), + ('iProduct', c_uint8), + ('iSerialNumber', c_uint8), + ('bNumConfigurations', c_uint8)] + +_lib = None +_init = None + +_libusb_device_handle = c_void_p + +def _load_library(): + if sys.platform != 'cygwin': + candidates = ('usb-1.0', 'libusb-1.0', 'usb') + for candidate in candidates: + libname = ctypes.util.find_library(candidate) + if libname is not None: break + else: + # corner cases + # cygwin predefines library names with 'cyg' instead of 'lib' + try: + return CDLL('cygusb-1.0.dll') + except Exception: + _logger.error('Libusb 1.0 could not be loaded in cygwin', exc_info=True) + + raise OSError('USB library could not be found') + # Windows backend uses stdcall calling convention + if sys.platform == 'win32': + l = WinDLL(libname) + else: + l = CDLL(libname) + # On FreeBSD 8/9, libusb 1.0 and libusb 0.1 are in the same shared + # object libusb.so, so if we found libusb library name, we must assure + # it is 1.0 version. We just try to get some symbol from 1.0 version + if not hasattr(l, 'libusb_init'): + raise OSError('USB library could not be found') + return l + +def _setup_prototypes(lib): + # void libusb_set_debug (libusb_context *ctx, int level) + lib.libusb_set_debug.argtypes = [c_void_p, c_int] + + # int libusb_init (libusb_context **context) + lib.libusb_init.argtypes = [POINTER(c_void_p)] + + # void libusb_exit (struct libusb_context *ctx) + lib.libusb_exit.argtypes = [c_void_p] + + # ssize_t libusb_get_device_list (libusb_context *ctx, + # libusb_device ***list) + lib.libusb_get_device_list.argtypes = [ + c_void_p, + POINTER(POINTER(c_void_p)) + ] + + # void libusb_free_device_list (libusb_device **list, + # int unref_devices) + lib.libusb_free_device_list.argtypes = [ + POINTER(c_void_p), + c_int + ] + + # libusb_device *libusb_ref_device (libusb_device *dev) + lib.libusb_ref_device.argtypes = [c_void_p] + lib.libusb_ref_device.restype = c_void_p + + # void libusb_unref_device(libusb_device *dev) + lib.libusb_unref_device.argtypes = [c_void_p] + + # int libusb_open(libusb_device *dev, libusb_device_handle **handle) + lib.libusb_open.argtypes = [c_void_p, POINTER(_libusb_device_handle)] + + # void libusb_close(libusb_device_handle *dev_handle) + lib.libusb_close.argtypes = [_libusb_device_handle] + + # int libusb_set_configuration(libusb_device_handle *dev, + # int configuration) + lib.libusb_set_configuration.argtypes = [_libusb_device_handle, c_int] + + # int libusb_get_configuration(libusb_device_handle *dev, + # int *config) + lib.libusb_get_configuration.argtypes = [_libusb_device_handle, POINTER(c_int)] + + # int libusb_claim_interface(libusb_device_handle *dev, + # int interface_number) + lib.libusb_claim_interface.argtypes = [_libusb_device_handle, c_int] + + # int libusb_release_interface(libusb_device_handle *dev, + # int interface_number) + lib.libusb_release_interface.argtypes = [_libusb_device_handle, c_int] + + # int libusb_set_interface_alt_setting(libusb_device_handle *dev, + # int interface_number, + # int alternate_setting) + lib.libusb_set_interface_alt_setting.argtypes = [ + _libusb_device_handle, + c_int, + c_int + ] + + # int libusb_reset_device (libusb_device_handle *dev) + lib.libusb_reset_device.argtypes = [_libusb_device_handle] + + # int libusb_kernel_driver_active(libusb_device_handle *dev, + # int interface) + lib.libusb_kernel_driver_active.argtypes = [ + _libusb_device_handle, + c_int + ] + + # int libusb_detach_kernel_driver(libusb_device_handle *dev, + # int interface) + lib.libusb_detach_kernel_driver.argtypes = [ + _libusb_device_handle, + c_int + ] + + # int libusb_attach_kernel_driver(libusb_device_handle *dev, + # int interface) + lib.libusb_attach_kernel_driver.argtypes = [ + _libusb_device_handle, + c_int + ] + + # int libusb_get_device_descriptor( + # libusb_device *dev, + # struct libusb_device_descriptor *desc + # ) + lib.libusb_get_device_descriptor.argtypes = [ + c_void_p, + POINTER(_libusb_device_descriptor) + ] + + # int libusb_get_config_descriptor( + # libusb_device *dev, + # uint8_t config_index, + # struct libusb_config_descriptor **config + # ) + lib.libusb_get_config_descriptor.argtypes = [ + c_void_p, + c_uint8, + POINTER(POINTER(_libusb_config_descriptor)) + ] + + # void libusb_free_config_descriptor( + # struct libusb_config_descriptor *config + # ) + lib.libusb_free_config_descriptor.argtypes = [ + POINTER(_libusb_config_descriptor) + ] + + # int libusb_get_string_descriptor_ascii(libusb_device_handle *dev, + # uint8_t desc_index, + # unsigned char *data, + # int length) + lib.libusb_get_string_descriptor_ascii.argtypes = [ + _libusb_device_handle, + c_uint8, + POINTER(c_ubyte), + c_int + ] + + # int libusb_control_transfer(libusb_device_handle *dev_handle, + # uint8_t bmRequestType, + # uint8_t bRequest, + # uint16_t wValue, + # uint16_t wIndex, + # unsigned char *data, + # uint16_t wLength, + # unsigned int timeout) + lib.libusb_control_transfer.argtypes = [ + _libusb_device_handle, + c_uint8, + c_uint8, + c_uint16, + c_uint16, + POINTER(c_ubyte), + c_uint16, + c_uint + ] + + #int libusb_bulk_transfer( + # struct libusb_device_handle *dev_handle, + # unsigned char endpoint, + # unsigned char *data, + # int length, + # int *transferred, + # unsigned int timeout + # ) + lib.libusb_bulk_transfer.argtypes = [ + _libusb_device_handle, + c_ubyte, + POINTER(c_ubyte), + c_int, + POINTER(c_int), + c_uint + ] + + # int libusb_interrupt_transfer( + # libusb_device_handle *dev_handle, + # unsigned char endpoint, + # unsigned char *data, + # int length, + # int *actual_length, + # unsigned int timeout + # ); + lib.libusb_interrupt_transfer.argtypes = [ + _libusb_device_handle, + c_ubyte, + POINTER(c_ubyte), + c_int, + POINTER(c_int), + c_uint + ] + + # uint8_t libusb_get_bus_number(libusb_device *dev) + lib.libusb_get_bus_number.argtypes = [c_void_p] + lib.libusb_get_bus_number.restype = c_uint8 + + # uint8_t libusb_get_device_address(libusb_device *dev) + lib.libusb_get_device_address.argtypes = [c_void_p] + lib.libusb_get_device_address.restype = c_uint8 + try: + # uint8_t libusb_get_port_number(libusb_device *dev) + lib.libusb_get_port_number.argtypes = [c_void_p] + lib.libusb_get_port_number.restype = c_uint8 + except AttributeError: + pass + +# check a libusb function call +def _check(retval): + if isinstance(retval, int): + retval = c_int(retval) + if isinstance(retval, c_int): + if retval.value < 0: + from usb.core import USBError + ret = retval.value + raise USBError(_str_error[ret], ret, _libusb_errno[ret]) + return retval + +# wrap a device +class _Device(object): + def __init__(self, devid): + self.devid = _lib.libusb_ref_device(devid) + def __del__(self): + _lib.libusb_unref_device(self.devid) + +# wrap a descriptor and keep a reference to another object +# Thanks to Thomas Reitmayr. +class _WrapDescriptor(object): + def __init__(self, desc, obj = None): + self.obj = obj + self.desc = desc + def __getattr__(self, name): + return getattr(self.desc, name) + +# wrap a configuration descriptor +class _ConfigDescriptor(object): + def __init__(self, desc): + self.desc = desc + def __del__(self): + _lib.libusb_free_config_descriptor(self.desc) + def __getattr__(self, name): + return getattr(self.desc.contents, name) + +# initialize and finalize the library +class _Initializer(object): + def __init__(self): + _check(_lib.libusb_init(None)) + def __del__(self): + _lib.libusb_exit(None) + + +# iterator for libusb devices +class _DevIterator(object): + def __init__(self): + self.dev_list = POINTER(c_void_p)() + self.num_devs = _check(_lib.libusb_get_device_list( + None, + byref(self.dev_list)) + ).value + def __iter__(self): + for i in range(self.num_devs): + yield _Device(self.dev_list[i]) + def __del__(self): + _lib.libusb_free_device_list(self.dev_list, 1) + +# implementation of libusb 1.0 backend +class _LibUSB(usb.backend.IBackend): + @methodtrace(_logger) + def enumerate_devices(self): + return _DevIterator() + + @methodtrace(_logger) + def get_device_descriptor(self, dev): + dev_desc = _libusb_device_descriptor() + _check(_lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc))) + dev_desc.bus = _lib.libusb_get_bus_number(dev.devid) + dev_desc.address = _lib.libusb_get_device_address(dev.devid) + #Only available i newer versions of libusb + try: + dev_desc.port_number = _lib.libusb_get_port_number(dev.devid) + except AttributeError: + dev_desc.port_number = None + return dev_desc + + @methodtrace(_logger) + def get_configuration_descriptor(self, dev, config): + cfg = POINTER(_libusb_config_descriptor)() + _check(_lib.libusb_get_config_descriptor(dev.devid, + config, byref(cfg))) + return _ConfigDescriptor(cfg) + + @methodtrace(_logger) + def get_interface_descriptor(self, dev, intf, alt, config): + cfg = self.get_configuration_descriptor(dev, config) + if intf >= cfg.bNumInterfaces: + raise IndexError('Invalid interface index ' + str(intf)) + i = cfg.interface[intf] + if alt >= i.num_altsetting: + raise IndexError('Invalid alternate setting index ' + str(alt)) + return _WrapDescriptor(i.altsetting[alt], cfg) + + @methodtrace(_logger) + def get_endpoint_descriptor(self, dev, ep, intf, alt, config): + i = self.get_interface_descriptor(dev, intf, alt, config) + if ep > i.bNumEndpoints: + raise IndexError('Invalid endpoint index ' + str(ep)) + return _WrapDescriptor(i.endpoint[ep], i) + + @methodtrace(_logger) + def open_device(self, dev): + handle = _libusb_device_handle() + _check(_lib.libusb_open(dev.devid, byref(handle))) + return handle + + @methodtrace(_logger) + def close_device(self, dev_handle): + _lib.libusb_close(dev_handle) + + @methodtrace(_logger) + def set_configuration(self, dev_handle, config_value): + _check(_lib.libusb_set_configuration(dev_handle, config_value)) + + @methodtrace(_logger) + def get_configuration(self, dev_handle): + config = c_int() + _check(_lib.libusb_get_configuration(dev_handle, byref(config))) + return config.value + + @methodtrace(_logger) + def set_interface_altsetting(self, dev_handle, intf, altsetting): + _check(_lib.libusb_set_interface_alt_setting(dev_handle, + intf, + altsetting)) + + @methodtrace(_logger) + def claim_interface(self, dev_handle, intf): + _check(_lib.libusb_claim_interface(dev_handle, intf)) + + @methodtrace(_logger) + def release_interface(self, dev_handle, intf): + _check(_lib.libusb_release_interface(dev_handle, intf)) + + @methodtrace(_logger) + def bulk_write(self, dev_handle, ep, intf, data, timeout): + return self.__write(_lib.libusb_bulk_transfer, + dev_handle, + ep, + intf, + data, + timeout) + + @methodtrace(_logger) + def bulk_read(self, dev_handle, ep, intf, size, timeout): + return self.__read(_lib.libusb_bulk_transfer, + dev_handle, + ep, + intf, + size, + timeout) + + @methodtrace(_logger) + def intr_write(self, dev_handle, ep, intf, data, timeout): + return self.__write(_lib.libusb_interrupt_transfer, + dev_handle, + ep, + intf, + data, + timeout) + + @methodtrace(_logger) + def intr_read(self, dev_handle, ep, intf, size, timeout): + return self.__read(_lib.libusb_interrupt_transfer, + dev_handle, + ep, + intf, + size, + timeout) + +# TODO: implement isochronous +# @methodtrace(_logger) +# def iso_write(self, dev_handle, ep, intf, data, timeout): +# pass + + +# @methodtrace(_logger) +# def iso_read(self, dev_handle, ep, intf, size, timeout): +# pass + + @methodtrace(_logger) + def ctrl_transfer(self, + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + data_or_wLength, + timeout): + if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: + buff = data_or_wLength + else: + buff = _interop.as_array((0,) * data_or_wLength) + + addr, length = buff.buffer_info() + length *= buff.itemsize + + ret = _check(_lib.libusb_control_transfer(dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + cast(addr, + POINTER(c_ubyte)), + length, + timeout)) + + if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: + return ret.value + else: + return buff[:ret.value] + + @methodtrace(_logger) + def reset_device(self, dev_handle): + _check(_lib.libusb_reset_device(dev_handle)) + + @methodtrace(_logger) + def is_kernel_driver_active(self, dev_handle, intf): + return bool(_check(_lib.libusb_kernel_driver_active(dev_handle, intf))) + + @methodtrace(_logger) + def detach_kernel_driver(self, dev_handle, intf): + _check(_lib.libusb_detach_kernel_driver(dev_handle, intf)) + + @methodtrace(_logger) + def attach_kernel_driver(self, dev_handle, intf): + _check(_lib.libusb_attach_kernel_driver(dev_handle, intf)) + + def __write(self, fn, dev_handle, ep, intf, data, timeout): + address, length = data.buffer_info() + length *= data.itemsize + transferred = c_int() + retval = fn(dev_handle, + ep, + cast(address, POINTER(c_ubyte)), + length, + byref(transferred), + timeout) + # do not assume LIBUSB_ERROR_TIMEOUT means no I/O. + if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT): + _check(retval) + + return transferred.value + + def __read(self, fn, dev_handle, ep, intf, size, timeout): + data = _interop.as_array((0,) * size) + address, length = data.buffer_info() + length *= data.itemsize + transferred = c_int() + retval = fn(dev_handle, + ep, + cast(address, POINTER(c_ubyte)), + length, + byref(transferred), + timeout) + # do not assume LIBUSB_ERROR_TIMEOUT means no I/O. + if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT): + _check(retval) + return data[:transferred.value] + +def get_backend(): + global _lib, _init + try: + if _lib is None: + _lib = _load_library() + _setup_prototypes(_lib) + _init = _Initializer() + return _LibUSB() + except Exception: + _logger.error('Error loading libusb 1.0 backend', exc_info=True) + return None diff --git a/pybot/usb/backend/openusb.py b/pybot/usb/backend/openusb.py new file mode 100644 index 0000000..474eecb --- /dev/null +++ b/pybot/usb/backend/openusb.py @@ -0,0 +1,708 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +from ctypes import * +import ctypes.util +import usb.util +from usb._debug import methodtrace +import logging +import errno + +__author__ = 'Wander Lairson Costa' + +__all__ = [ + 'get_backend' + 'OPENUSB_SUCCESS' + 'OPENUSB_PLATFORM_FAILURE' + 'OPENUSB_NO_RESOURCES' + 'OPENUSB_NO_BANDWIDTH' + 'OPENUSB_NOT_SUPPORTED' + 'OPENUSB_HC_HARDWARE_ERROR' + 'OPENUSB_INVALID_PERM' + 'OPENUSB_BUSY' + 'OPENUSB_BADARG' + 'OPENUSB_NOACCESS' + 'OPENUSB_PARSE_ERROR' + 'OPENUSB_UNKNOWN_DEVICE' + 'OPENUSB_INVALID_HANDLE' + 'OPENUSB_SYS_FUNC_FAILURE' + 'OPENUSB_NULL_LIST' + 'OPENUSB_CB_CONTINUE' + 'OPENUSB_CB_TERMINATE' + 'OPENUSB_IO_STALL' + 'OPENUSB_IO_CRC_ERROR' + 'OPENUSB_IO_DEVICE_HUNG' + 'OPENUSB_IO_REQ_TOO_BIG' + 'OPENUSB_IO_BIT_STUFFING' + 'OPENUSB_IO_UNEXPECTED_PID' + 'OPENUSB_IO_DATA_OVERRUN' + 'OPENUSB_IO_DATA_UNDERRUN' + 'OPENUSB_IO_BUFFER_OVERRUN' + 'OPENUSB_IO_BUFFER_UNDERRUN' + 'OPENUSB_IO_PID_CHECK_FAILURE' + 'OPENUSB_IO_DATA_TOGGLE_MISMATCH' + 'OPENUSB_IO_TIMEOUT' + 'OPENUSB_IO_CANCELED' + ] + +_logger = logging.getLogger('usb.backend.openusb') + +OPENUSB_SUCCESS = 0 +OPENUSB_PLATFORM_FAILURE = -1 +OPENUSB_NO_RESOURCES = -2 +OPENUSB_NO_BANDWIDTH = -3 +OPENUSB_NOT_SUPPORTED = -4 +OPENUSB_HC_HARDWARE_ERROR = -5 +OPENUSB_INVALID_PERM = -6 +OPENUSB_BUSY = -7 +OPENUSB_BADARG = -8 +OPENUSB_NOACCESS = -9 +OPENUSB_PARSE_ERROR = -10 +OPENUSB_UNKNOWN_DEVICE = -11 +OPENUSB_INVALID_HANDLE = -12 +OPENUSB_SYS_FUNC_FAILURE = -13 +OPENUSB_NULL_LIST = -14 +OPENUSB_CB_CONTINUE = -20 +OPENUSB_CB_TERMINATE = -21 +OPENUSB_IO_STALL = -50 +OPENUSB_IO_CRC_ERROR = -51 +OPENUSB_IO_DEVICE_HUNG = -52 +OPENUSB_IO_REQ_TOO_BIG = -53 +OPENUSB_IO_BIT_STUFFING = -54 +OPENUSB_IO_UNEXPECTED_PID = -55 +OPENUSB_IO_DATA_OVERRUN = -56 +OPENUSB_IO_DATA_UNDERRUN = -57 +OPENUSB_IO_BUFFER_OVERRUN = -58 +OPENUSB_IO_BUFFER_UNDERRUN = -59 +OPENUSB_IO_PID_CHECK_FAILURE = -60 +OPENUSB_IO_DATA_TOGGLE_MISMATCH = -61 +OPENUSB_IO_TIMEOUT = -62 +OPENUSB_IO_CANCELED = -63 + +_openusb_errno = { + OPENUSB_SUCCESS:None, + OPENUSB_PLATFORM_FAILURE:None, + OPENUSB_NO_RESOURCES:errno.__dict__.get('ENOMEM', None), + OPENUSB_NO_BANDWIDTH:None, + OPENUSB_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None), + OPENUSB_HC_HARDWARE_ERROR:errno.__dict__.get('EIO', None), + OPENUSB_INVALID_PERM:errno.__dict__.get('EBADF', None), + OPENUSB_BUSY:errno.__dict__.get('EBUSY', None), + OPENUSB_BADARG:errno.__dict__.get('EINVAL', None), + OPENUSB_NOACCESS:errno.__dict__.get('EACCES', None), + OPENUSB_PARSE_ERROR:None, + OPENUSB_UNKNOWN_DEVICE:errno.__dict__.get('ENODEV', None), + OPENUSB_INVALID_HANDLE:errno.__dict__.get('EINVAL', None), + OPENUSB_SYS_FUNC_FAILURE:None, + OPENUSB_NULL_LIST:None, + OPENUSB_CB_CONTINUE:None, + OPENUSB_CB_TERMINATE:None, + OPENUSB_IO_STALL:errno.__dict__.get('EIO', None), + OPENUSB_IO_CRC_ERROR:errno.__dict__.get('EIO', None), + OPENUSB_IO_DEVICE_HUNG:errno.__dict__.get('EIO', None), + OPENUSB_IO_REQ_TOO_BIG:errno.__dict__.get('E2BIG', None), + OPENUSB_IO_BIT_STUFFING:None, + OPENUSB_IO_UNEXPECTED_PID:errno.__dict__.get('ESRCH', None), + OPENUSB_IO_DATA_OVERRUN:errno.__dict__.get('EOVERFLOW', None), + OPENUSB_IO_DATA_UNDERRUN:None, + OPENUSB_IO_BUFFER_OVERRUN:errno.__dict__.get('EOVERFLOW', None), + OPENUSB_IO_BUFFER_UNDERRUN:None, + OPENUSB_IO_PID_CHECK_FAILURE:None, + OPENUSB_IO_DATA_TOGGLE_MISMATCH:None, + OPENUSB_IO_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None), + OPENUSB_IO_CANCELED:errno.__dict__.get('EINTR', None) +} + +class _usb_endpoint_desc(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bEndpointAddress', c_uint8), + ('bmAttributes', c_uint8), + ('wMaxPacketSize', c_uint16), + ('bInterval', c_uint8), + ('bRefresh', c_uint8), + ('bSynchAddress', c_uint8)] + +class _usb_interface_desc(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bInterfaceNumber', c_uint8), + ('bAlternateSetting', c_uint8), + ('bNumEndpoints', c_uint8), + ('bInterfaceClass', c_uint8), + ('bInterfaceSubClass', c_uint8), + ('bInterfaceProtocol', c_uint8), + ('iInterface', c_uint8)] + +class _usb_config_desc(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('wTotalLength', c_uint16), + ('bNumInterfaces', c_uint8), + ('bConfigurationValue', c_uint8), + ('iConfiguration', c_uint8), + ('bmAttributes', c_uint8), + ('bMaxPower', c_uint8)] + +class _usb_device_desc(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bcdUSB', c_uint16), + ('bDeviceClass', c_uint8), + ('bDeviceSubClass', c_uint8), + ('bDeviceProtocol', c_uint8), + ('bMaxPacketSize0', c_uint8), + ('idVendor', c_uint16), + ('idProduct', c_uint16), + ('bcdDevice', c_uint16), + ('iManufacturer', c_uint8), + ('iProduct', c_uint8), + ('iSerialNumber', c_uint8), + ('bNumConfigurations', c_uint8)] + +class _openusb_request_result(Structure): + _fields_ = [('status', c_int32), + ('transfered_bytes', c_uint32)] + +class _openusb_ctrl_request(Structure): + class _openusb_ctrl_setup(Structure): + _fields_ = [('bmRequestType', c_uint8), + ('bRequest', c_uint8), + ('wValue', c_uint16), + ('wIndex', c_uint16)] + _fields_ = [('payload', POINTER(c_uint8)), + ('length', c_uint32), + ('timeout', c_uint32), + ('flags', c_uint32), + ('result', _openusb_request_result), + ('next', c_void_p)] + +class _openusb_intr_request(Structure): + _fields_ = [('interval', c_uint16), + ('payload', POINTER(c_uint8)), + ('length', c_uint32), + ('timeout', c_uint32), + ('flags', c_uint32), + ('result', _openusb_request_result), + ('next', c_void_p)] + +class _openusb_bulk_request(Structure): + _fields_ = [('payload', POINTER(c_uint8)), + ('length', c_uint32), + ('timeout', c_uint32), + ('flags', c_uint32), + ('result', _openusb_request_result), + ('next', c_void_p)] + +class _openusb_isoc_pkts(Structure): + class _openusb_isoc_packet(Structure): + _fields_ = [('payload', POINTER(c_uint8)), + ('length', c_uint32)] + _fields_ = [('num_packets', c_uint32), + ('packets', POINTER(_openusb_isoc_packet))] + +class _openusb_isoc_request(Structure): + _fields_ = [('start_frame', c_uint32), + ('flags', c_uint32), + ('pkts', _openusb_isoc_pkts), + ('isoc_results', POINTER(_openusb_request_result)), + ('isoc_status', c_int32), + ('next', c_void_p)] + +_openusb_devid = c_uint64 +_openusb_busid = c_uint64 +_openusb_handle = c_uint64 +_openusb_dev_handle = c_uint64 + +_lib = None +_ctx = None + +def _load_library(): + libname = ctypes.util.find_library('openusb') + if libname is None: + raise OSError('USB library could not be found') + return CDLL(libname) + +def _setup_prototypes(lib): + # int32_t openusb_init(uint32_t flags , openusb_handle_t *handle); + lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)] + lib.openusb_init.restype = c_int32 + + # void openusb_fini(openusb_handle_t handle ); + lib.openusb_fini.argtypes = [_openusb_handle] + + # uint32_t openusb_get_busid_list(openusb_handle_t handle, + # openusb_busid_t **busids, + # uint32_t *num_busids); + lib.openusb_get_busid_list.argtypes = [ + _openusb_handle, + POINTER(POINTER(_openusb_busid)), + POINTER(c_uint32) + ] + + # void openusb_free_busid_list(openusb_busid_t * busids); + lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)] + + # uint32_t openusb_get_devids_by_bus(openusb_handle_t handle, + # openusb_busid_t busid, + # openusb_devid_t **devids, + # uint32_t *num_devids); + lib.openusb_get_devids_by_bus.argtypes = [ + _openusb_handle, + _openusb_busid, + POINTER(POINTER(_openusb_devid)), + POINTER(c_uint32) + ] + + lib.openusb_get_devids_by_bus.restype = c_int32 + + # void openusb_free_devid_list(openusb_devid_t * devids); + lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)] + + # int32_t openusb_open_device(openusb_handle_t handle, + # openusb_devid_t devid , + # uint32_t flags, + # openusb_dev_handle_t *dev); + lib.openusb_open_device.argtypes = [ + _openusb_handle, + _openusb_devid, + c_uint32, + POINTER(_openusb_dev_handle) + ] + + lib.openusb_open_device.restype = c_int32 + + # int32_t openusb_close_device(openusb_dev_handle_t dev); + lib.openusb_close_device.argtypes = [_openusb_dev_handle] + lib.openusb_close_device.restype = c_int32 + + # int32_t openusb_set_configuration(openusb_dev_handle_t dev, + # uint8_t cfg); + lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8] + lib.openusb_set_configuration.restype = c_int32 + + # int32_t openusb_get_configuration(openusb_dev_handle_t dev, + # uint8_t *cfg); + lib.openusb_get_configuration.argtypes = [_openusb_dev_handle, POINTER(c_uint8)] + lib.openusb_get_configuration.restype = c_int32 + + # int32_t openusb_claim_interface(openusb_dev_handle_t dev, + # uint8_t ifc, + # openusb_init_flag_t flags); + lib.openusb_claim_interface.argtypes = [ + _openusb_dev_handle, + c_uint8, + c_int + ] + + lib.openusb_claim_interface.restype = c_int32 + + # int32_t openusb_release_interface(openusb_dev_handle_t dev, + # uint8_t ifc); + lib.openusb_release_interface.argtypes = [ + _openusb_dev_handle, + c_uint8 + ] + + lib.openusb_release_interface.restype = c_int32 + + # int32_topenusb_set_altsetting(openusb_dev_handle_t dev, + # uint8_t ifc, + # uint8_t alt); + lib.openusb_set_altsetting.argtypes = [ + _openusb_dev_handle, + c_uint8, + c_uint8 + ] + lib.openusb_set_altsetting.restype = c_int32 + + # int32_t openusb_reset(openusb_dev_handle_t dev); + lib.openusb_reset.argtypes = [_openusb_dev_handle] + lib.openusb_reset.restype = c_int32 + + # int32_t openusb_parse_device_desc(openusb_handle_t handle, + # openusb_devid_t devid, + # uint8_t *buffer, + # uint16_t buflen, + # usb_device_desc_t *devdesc); + lib.openusb_parse_device_desc.argtypes = [ + _openusb_handle, + _openusb_devid, + POINTER(c_uint8), + c_uint16, + POINTER(_usb_device_desc) + ] + + lib.openusb_parse_device_desc.restype = c_int32 + + # int32_t openusb_parse_config_desc(openusb_handle_t handle, + # openusb_devid_t devid, + # uint8_t *buffer, + # uint16_t buflen, + # uint8_t cfgidx, + # usb_config_desc_t *cfgdesc); + lib.openusb_parse_config_desc.argtypes = [ + _openusb_handle, + _openusb_devid, + POINTER(c_uint8), + c_uint16, + c_uint8, + POINTER(_usb_config_desc) + ] + lib.openusb_parse_config_desc.restype = c_int32 + + # int32_t openusb_parse_interface_desc(openusb_handle_t handle, + # openusb_devid_t devid, + # uint8_t *buffer, + # uint16_t buflen, + # uint8_t cfgidx, + # uint8_t ifcidx, + # uint8_t alt, + # usb_interface_desc_t *ifcdesc); + lib.openusb_parse_interface_desc.argtypes = [ + _openusb_handle, + _openusb_devid, + POINTER(c_uint8), + c_uint16, + c_uint8, + c_uint8, + c_uint8, + POINTER(_usb_interface_desc) + ] + + lib.openusb_parse_interface_desc.restype = c_int32 + + # int32_t openusb_parse_endpoint_desc(openusb_handle_t handle, + # openusb_devid_t devid, + # uint8_t *buffer, + # uint16_t buflen, + # uint8_t cfgidx, + # uint8_t ifcidx, + # uint8_t alt, + # uint8_t eptidx, + # usb_endpoint_desc_t *eptdesc); + lib.openusb_parse_endpoint_desc.argtypes = [ + _openusb_handle, + _openusb_devid, + POINTER(c_uint8), + c_uint16, + c_uint8, + c_uint8, + c_uint8, + c_uint8, + POINTER(_usb_endpoint_desc) + ] + + lib.openusb_parse_interface_desc.restype = c_int32 + + # const char *openusb_strerror(int32_t error ); + lib.openusb_strerror.argtypes = [c_int32] + lib.openusb_strerror.restype = c_char_p + + # int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev, + # uint8_t ifc, + # uint8_t ept, + # openusb_ctrl_request_t *ctrl); + lib.openusb_ctrl_xfer.argtypes = [ + _openusb_dev_handle, + c_uint8, + c_uint8, + POINTER(_openusb_ctrl_request) + ] + + lib.openusb_ctrl_xfer.restype = c_int32 + + # int32_t openusb_intr_xfer(openusb_dev_handle_t dev, + # uint8_t ifc, + # uint8_t ept, + # openusb_intr_request_t *intr); + lib.openusb_intr_xfer.argtypes = [ + _openusb_dev_handle, + c_uint8, + c_uint8, + POINTER(_openusb_intr_request) + ] + + lib.openusb_bulk_xfer.restype = c_int32 + + # int32_t openusb_bulk_xfer(openusb_dev_handle_t dev, + # uint8_t ifc, + # uint8_t ept, + # openusb_bulk_request_t *bulk); + lib.openusb_bulk_xfer.argtypes = [ + _openusb_dev_handle, + c_uint8, + c_uint8, + POINTER(_openusb_bulk_request) + ] + + lib.openusb_bulk_xfer.restype = c_int32 + + # int32_t openusb_isoc_xfer(openusb_dev_handle_t dev, + # uint8_t ifc, + # uint8_t ept, + # openusb_isoc_request_t *isoc); + lib.openusb_isoc_xfer.argtypes = [ + _openusb_dev_handle, + c_uint8, + c_uint8, + POINTER(_openusb_isoc_request) + ] + + lib.openusb_isoc_xfer.restype = c_int32 + +def _check(retval): + ret = retval.value + if ret != 0: + from usb.core import USBError + raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret]) + return retval + +class _Context(object): + def __init__(self): + self.handle = _openusb_handle() + _check(_lib.openusb_init(0, byref(self.handle))) + def __del__(self): + _lib.openusb_fini(self.handle) + +class _BusIterator(object): + def __init__(self): + self.buslist = POINTER(openusb_busid)() + num_busids = c_uint32() + _check(_lib.openusb_get_busid_list(_ctx.handle, + byref(self.buslist), + byref(num_busids))) + self.num_busids = num_busids.value + def __iter__(self): + for i in range(self.num_busids): + yield self.buslist[i] + def __del__(self): + _lib.openusb_free_busid_list(self.buslist) + +class _DevIterator(object): + def __init__(self, busid): + self.devlist = POINTER(_openusb_devid)() + num_devids = c_uint32() + _check(_lib.openusb_get_devids_by_bus(_ctx.handle, + busid, + byref(self.devlist), + byref(num_devids))) + self.num_devids = num_devids.value + def __iter__(self): + for i in range(self.num_devids): + yield self.devlist[i] + def __del__(self): + _lib.openusb_free_devid_list(self.devlist) + +class _OpenUSB(usb.backend.IBackend): + @methodtrace(_logger) + def enumerate_devices(self): + for bus in _BusIterator(): + for devid in _DevIterator(bus): + yield devid + + @methodtrace(_logger) + def get_device_descriptor(self, dev): + desc = _usb_device_desc() + _check(_lib.openusb_parse_device_desc(_ctx.handle, + dev, + None, + 0, + byref(desc))) + desc.bus = None + desc.address = None + desc.port_number = None + return desc + + @methodtrace(_logger) + def get_configuration_descriptor(self, dev, config): + desc = _usb_config_desc() + _check(_lib.openusb_parse_config_desc(_ctx.handle, + dev, + None, + 0, + config, + byref(desc))) + return desc + + @methodtrace(_logger) + def get_interface_descriptor(self, dev, intf, alt, config): + desc = _usb_interface_desc() + _check(_lib.openusb_parse_interface_desc(_ctx.handle, + dev, + None, + 0, + config, + intf, + alt, + byref(desc))) + return desc + + @methodtrace(_logger) + def get_endpoint_descriptor(self, dev, ep, intf, alt, config): + desc = _usb_endpoint_desc() + _check(_lib.openusb_parse_endpoint_desc(_ctx.handle, + dev, + None, + 0, + config, + intf, + alt, + ep, + byref(desc))) + return desc + + @methodtrace(_logger) + def open_device(self, dev): + handle = _openusb_dev_handle() + _check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle))) + return handle + + @methodtrace(_logger) + def close_device(self, dev_handle): + _lib.openusb_close_device(dev_handle) + + @methodtrace(_logger) + def set_configuration(self, dev_handle, config_value): + _check(_lib.openusb_set_configuration(dev_handle, config_value)) + + @methodtrace(_logger) + def get_configuration(self, dev_handle): + config = c_uint8() + _check(_lib.openusb_get_configuration(dev_handle, byref(config))) + return config.value + + @methodtrace(_logger) + def set_interface_altsetting(self, dev_handle, intf, altsetting): + _check(_lib.set_altsetting(dev_handle, intf, altsetting)) + + @methodtrace(_logger) + def claim_interface(self, dev_handle, intf): + _check(_lib.openusb_claim_interface(dev_handle, intf, 0)) + + @methodtrace(_logger) + def release_interface(self, dev_handle, intf): + _lib.openusb_release_interface(dev_handle, intf) + + @methodtrace(_logger) + def bulk_write(self, dev_handle, ep, intf, data, timeout): + request = _openusb_bulk_request() + memset(byref(request), 0, sizeof(request)) + request.payload, request.length = data.buffer_info() + request.timeout = timeout + _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request))) + return request.transfered_bytes.value + + @methodtrace(_logger) + def bulk_read(self, dev_handle, ep, intf, size, timeout): + request = _openusb_bulk_request() + buffer = array.array('B', '\x00' * size) + memset(byref(request), 0, sizeof(request)) + request.payload, request.length = buffer.buffer_info() + request.timeout = timeout + _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request))) + return buffer[:request.transfered_bytes.value] + + @methodtrace(_logger) + def intr_write(self, dev_handle, ep, intf, data, timeout): + request = _openusb_intr_request() + memset(byref(request), 0, sizeof(request)) + payload, request.length = data.buffer_info() + request.payload = cast(payload, POINTER(c_uint8)) + request.timeout = timeout + _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request))) + return request.transfered_bytes.value + + @methodtrace(_logger) + def intr_read(self, dev_handle, ep, intf, size, timeout): + request = _openusb_intr_request() + buffer = array.array('B', '\x00' * size) + memset(byref(request), 0, sizeof(request)) + payload, request.length = buffer.buffer_info() + request.payload = cast(payload, POINTER(c_uint8)) + request.timeout = timeout + _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request))) + return buffer[:request.transfered_bytes.value] + +# TODO: implement isochronous +# @methodtrace(_logger) +# def iso_write(self, dev_handle, ep, intf, data, timeout): +# pass + +# @methodtrace(_logger) +# def iso_read(self, dev_handle, ep, intf, size, timeout): +# pass + + @methodtrace(_logger) + def ctrl_transfer(self, + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + data_or_wLength, + timeout): + request = _openusb_ctrl_request() + request.setup.bmRequestType = bmRequestType + request.setup.bRequest = bRequest + request.setup.wValue + request.setup.wIndex + request.timeout = timeout + + direction = usb.util.ctrl_direction(bmRequestType) + + if direction == ENDPOINT_OUT: + buffer = data_or_wLength + else: + buffer = array.array('B', '\x00' * data_or_wLength) + + payload, request.length = buffer.buffer_info() + request.payload = cast(payload, POINTER(c_uint8)) + + ret = _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request))) + + if direction == ENDPOINT_OUT: + ret + else: + buffer[:ret] + + @methodtrace(_logger) + def reset_device(self, dev_handle): + _check(_lib.openusb_reset(dev_handle)) + +def get_backend(): + try: + global _lib, _ctx + if _lib is None: + _lib = _load_library() + _setup_prototypes(_lib) + _ctx = _Context() + return _OpenUSB() + except Exception: + _logger.error('Error loading OpenUSB backend', exc_info=True) + return None diff --git a/pybot/usb/control.py b/pybot/usb/control.py new file mode 100644 index 0000000..8647c14 --- /dev/null +++ b/pybot/usb/control.py @@ -0,0 +1,252 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +r"""usb.control - USB standard control requests + +This module exports: + +get_status - get recipeint status +clear_feature - clear a recipient feature +set_feature - set a recipient feature +get_descriptor - get a device descriptor +set_descriptor - set a device descriptor +get_configuration - get a device configuration +set_configuration - set a device configuration +get_interface - get a device interface +set_interface - set a device interface +""" + +__author__ = 'Wander Lairson Costa' + +__all__ = ['get_status', + 'clear_feature', + 'set_feature', + 'get_descriptor', + 'set_descriptor', + 'get_configuration', + 'set_configuration', + 'get_interface', + 'set_interface', + 'ENDPOINT_HALT', + 'FUNCTION_SUSPEND', + 'DEVICE_REMOTE_WAKEUP', + 'U1_ENABLE', + 'U2_ENABLE', + 'LTM_ENABLE'] + +import usb.util as util +import usb.core as core + +def _parse_recipient(recipient, direction): + if recipient is None: + r = util.CTRL_RECIPIENT_DEVICE + wIndex = 0 + elif isinstance(recipient, core.Interface): + r = util.CTRL_RECIPIENT_INTERFACE + wIndex = recipient.bInterfaceNumber + elif isinstance(recipient, core.Endpoint): + r = util.CTRL_RECIPIENT_ENDPOINT + wIndex = recipient.bEndpointAddress + else: + raise ValueError('Invalid recipient.') + bmRequestType = util.build_request_type( + direction, + util.CTRL_TYPE_STANDARD, + r + ) + return (bmRequestType, wIndex) + +# standard feature selectors from USB 2.0/3.0 +ENDPOINT_HALT = 0 +FUNCTION_SUSPEND = 0 +DEVICE_REMOTE_WAKEUP = 1 +U1_ENABLE = 48 +U2_ENABLE = 49 +LTM_ENABLE = 50 + +def get_status(dev, recipient = None): + r"""Return the status for the specified recipient. + + dev is the Device object to which the request will be + sent to. + + The recipient can be None (on which the status will be queried + on the device), an Interface or Endpoint descriptors. + + The status value is returned as an integer with the lower + word being the two bytes status value. + """ + bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_IN) + ret = dev.ctrl_transfer(bmRequestType = bmRequestType, + bRequest = 0x00, + wIndex = wIndex, + data_or_wLength = 2) + return ret[0] | (ret[1] << 8) + +def clear_feature(dev, feature, recipient = None): + r"""Clear/disable a specific feature. + + dev is the Device object to which the request will be + sent to. + + feature is the feature you want to disable. + + The recipient can be None (on which the status will be queried + on the device), an Interface or Endpoint descriptors. + """ + bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT) + dev.ctrl_transfer(bmRequestType = bmRequestType, + bRequest = 0x01, + wIndex = wIndex, + wValue = feature) + +def set_feature(dev, feature, recipient = None): + r"""Set/enable a specific feature. + + dev is the Device object to which the request will be + sent to. + + feature is the feature you want to enable. + + The recipient can be None (on which the status will be queried + on the device), an Interface or Endpoint descriptors. + """ + bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT) + dev.ctrl_transfer(bmRequestType = bmRequestType, + bRequest = 0x03, + wIndex = wIndex, + wValue = feature) + +def get_descriptor(dev, desc_size, desc_type, desc_index, wIndex = 0): + r"""Return the specified descriptor. + + dev is the Device object to which the request will be + sent to. + + desc_size is the descriptor size. + + desc_type and desc_index are the descriptor type and index, + respectively. wIndex index is used for string descriptors + and represents the Language ID. For other types of descriptors, + it is zero. + """ + wValue = desc_index | (desc_type << 8) + bmRequestType = util.build_request_type( + util.CTRL_IN, + util.CTRL_TYPE_STANDARD, + util.CTRL_RECIPIENT_DEVICE + ) + return dev.ctrl_transfer( + bmRequestType = bmRequestType, + bRequest = 0x06, + wValue = wValue, + wIndex = wIndex, + data_or_wLength = desc_size + ) + +def set_descriptor(dev, desc, desc_type, desc_index, wIndex = None): + r"""Update an existing descriptor or add a new one. + + dev is the Device object to which the request will be + sent to. + + The desc parameter is the descriptor to be sent to the device. + desc_type and desc_index are the descriptor type and index, + respectively. wIndex index is used for string descriptors + and represents the Language ID. For other types of descriptors, + it is zero. + """ + wValue = desc_index | (desc_type << 8) + bmRequestType = util.build_request_type( + util.CTRL_OUT, + util.CTRL_TYPE_STANDARD, + util.CTRL_RECIPIENT_DEVICE + ) + dev.ctrl_transfer( + bmRequestType = bmRequestType, + bRequest = 0x07, + wValue = wValue, + wIndex = wIndex, + data_or_wLength = desc + ) + +def get_configuration(dev): + r"""Get the current active configuration of the device. + + dev is the Device object to which the request will be + sent to. + + This function differs from the Device.get_active_configuration + method because the later may use cached data, while this + function always does a device request. + """ + bmRequestType = util.build_request_type( + util.CTRL_IN, + util.CTRL_TYPE_STANDARD, + util.CTRL_RECIPIENT_DEVICE + ) + return dev.ctrl_transfer( + bmRequestType, + bRequest = 0x08, + data_or_wLength = 1 + )[0] + +def set_configuration(dev, bConfigurationNumber): + r"""Set the current device configuration. + + dev is the Device object to which the request will be + sent to. + """ + dev.set_configuration(bConfigurationNumber) + +def get_interface(dev, bInterfaceNumber): + r"""Get the current alternate setting of the interface. + + dev is the Device object to which the request will be + sent to. + """ + bmRequestType = util.build_request_type( + util.CTRL_IN, + util.CTRL_TYPE_STANDARD, + util.CTRL_RECIPIENT_INTERFACE + ) + return dev.ctrl_transfer( + bmRequestType = bmRequestType, + bRequest = 0x0a, + wIndex = bInterfaceNumber, + data_or_wLength = 1 + )[0] + +def set_interface(dev, bInterfaceNumber, bAlternateSetting): + r"""Set the alternate setting of the interface. + + dev is the Device object to which the request will be + sent to. + """ + dev.set_interface_altsetting(bInterfaceNumber, bAlternateSetting) + diff --git a/pybot/usb/core.py b/pybot/usb/core.py new file mode 100644 index 0000000..597637f --- /dev/null +++ b/pybot/usb/core.py @@ -0,0 +1,871 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +r"""usb.core - Core USB features. + +This module exports: + +Device - a class representing a USB device. +Configuration - a class representing a configuration descriptor. +Interface - a class representing an interface descriptor. +Endpoint - a class representing an endpoint descriptor. +find() - a function to find USB devices. +""" + +__author__ = 'Wander Lairson Costa' + +__all__ = ['Device', 'Configuration', 'Interface', 'Endpoint', 'find'] + +import usb.util as util +import copy +import operator +import usb._interop as _interop +import logging + +_logger = logging.getLogger('usb.core') + +_DEFAULT_TIMEOUT = 1000 + +def _set_attr(input, output, fields): + for f in fields: + setattr(output, f, getattr(input, f)) + +class _ResourceManager(object): + def __init__(self, dev, backend): + self.backend = backend + self._active_cfg_index = None + self.dev = dev + self.handle = None + self._claimed_intf = _interop._set() + self._alt_set = {} + self._ep_type_map = {} + + def managed_open(self): + if self.handle is None: + self.handle = self.backend.open_device(self.dev) + return self.handle + + def managed_close(self): + if self.handle is not None: + self.backend.close_device(self.handle) + self.handle = None + + def managed_set_configuration(self, device, config): + if config is None: + cfg = device[0] + elif isinstance(config, Configuration): + cfg = config + elif config == 0: # unconfigured state + class FakeConfiguration(object): + def __init__(self): + self.index = None + self.bConfigurationValue = 0 + cfg = FakeConfiguration() + else: + cfg = util.find_descriptor(device, bConfigurationValue=config) + self.managed_open() + self.backend.set_configuration(self.handle, cfg.bConfigurationValue) + # cache the index instead of the object to avoid cyclic references + # of the device and Configuration (Device tracks the _ResourceManager, + # which tracks the Configuration, which tracks the Device) + self._active_cfg_index = cfg.index + # after changing configuration, our alternate setting and endpoint type caches + # are not valid anymore + self._ep_type_map.clear() + self._alt_set.clear() + + def managed_claim_interface(self, device, intf): + self.managed_open() + if intf is None: + cfg = self.get_active_configuration(device) + i = cfg[(0,0)].bInterfaceNumber + elif isinstance(intf, Interface): + i = intf.bInterfaceNumber + else: + i = intf + if i not in self._claimed_intf: + self.backend.claim_interface(self.handle, i) + self._claimed_intf.add(i) + + def managed_release_interface(self, device, intf): + if intf is None: + cfg = self.get_active_configuration(device) + i = cfg[(0,0)].bInterfaceNumber + elif isinstance(intf, Interface): + i = intf.bInterfaceNumber + else: + i = intf + if i in self._claimed_intf: + self.backend.release_interface(self.handle, i) + self._claimed_intf.remove(i) + + def managed_set_interface(self, device, intf, alt): + if isinstance(intf, Interface): + i = intf + else: + cfg = self.get_active_configuration(device) + if intf is None: + intf = cfg[(0,0)].bInterfaceNumber + if alt is not None: + i = util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=alt) + else: + i = util.find_descriptor(cfg, bInterfaceNumber=intf) + self.managed_claim_interface(device, i) + if alt is None: + alt = i.bAlternateSetting + self.backend.set_interface_altsetting(self.handle, i.bInterfaceNumber, alt) + self._alt_set[i.bInterfaceNumber] = alt + + def get_interface(self, device, intf): + # TODO: check the viability of issuing a GET_INTERFACE + # request when we don't have a alternate setting cached + if isinstance(intf, Interface): + return intf + else: + cfg = self.get_active_configuration(device) + if intf is None: + intf = cfg[(0,0)].bInterfaceNumber + if intf in self._alt_set: + return util.find_descriptor(cfg, + bInterfaceNumber=intf, + bAlternateSetting=self._alt_set[intf]) + else: + return util.find_descriptor(cfg, bInterfaceNumber=intf) + + def get_active_configuration(self, device): + if self._active_cfg_index is None: + self.managed_open() + cfg = util.find_descriptor( + device, + bConfigurationValue=self.backend.get_configuration(self.handle) + ) + if cfg is None: + raise USBError('Configuration not set') + self._active_cfg_index = cfg.index + return cfg + return device[self._active_cfg_index] + + def get_endpoint_type(self, device, address, intf): + intf = self.get_interface(device, intf) + key = (address, intf.bInterfaceNumber, intf.bAlternateSetting) + try: + return self._ep_type_map[key] + except KeyError: + e = util.find_descriptor(intf, bEndpointAddress=address) + etype = util.endpoint_type(e.bmAttributes) + self._ep_type_map[key] = etype + return etype + + def release_all_interfaces(self, device): + claimed = copy.copy(self._claimed_intf) + for i in claimed: + self.managed_release_interface(device, i) + + def dispose(self, device, close_handle = True): + self.release_all_interfaces(device) + if close_handle: + self.managed_close() + self._ep_type_map.clear() + self._alt_set.clear() + self._active_cfg_index = None + +class USBError(IOError): + r"""Exception class for USB errors. + + Backends must raise this exception when USB related errors occur. + The backend specific error code is available through the + 'backend_error_code' member variable. + """ + + def __init__(self, strerror, error_code = None, errno = None): + r"""Initialize the object. + + This initializes the USBError object. The strerror and errno are passed + to the parent object. The error_code parameter is attributed to the + backend_error_code member variable. + """ + IOError.__init__(self, errno, strerror) + self.backend_error_code = error_code + +class Endpoint(object): + r"""Represent an endpoint object. + + This class contains all fields of the Endpoint Descriptor + according to the USB Specification. You may access them as class + properties. For example, to access the field bEndpointAddress + of the endpoint descriptor: + + >>> import usb.core + >>> dev = usb.core.find() + >>> for cfg in dev: + >>> for i in cfg: + >>> for e in i: + >>> print e.bEndpointAddress + """ + + def __init__(self, device, endpoint, interface = 0, + alternate_setting = 0, configuration = 0): + r"""Initialize the Endpoint object. + + The device parameter is the device object returned by the find() + function. endpoint is the endpoint logical index (not the endpoint address). + The configuration parameter is the logical index of the + configuration (not the bConfigurationValue field). The interface + parameter is the interface logical index (not the bInterfaceNumber field) + and alternate_setting is the alternate setting logical index (not the + bAlternateSetting value). Not every interface has more than one alternate + setting. In this case, the alternate_setting parameter should be zero. + By "logical index" we mean the relative order of the configurations returned by the + peripheral as a result of GET_DESCRIPTOR request. + """ + self.device = device + intf = Interface(device, interface, alternate_setting, configuration) + self.interface = intf.bInterfaceNumber + self.index = endpoint + + backend = device._ctx.backend + + desc = backend.get_endpoint_descriptor( + device._ctx.dev, + endpoint, + interface, + alternate_setting, + configuration + ) + + _set_attr( + desc, + self, + ( + 'bLength', + 'bDescriptorType', + 'bEndpointAddress', + 'bmAttributes', + 'wMaxPacketSize', + 'bInterval', + 'bRefresh', + 'bSynchAddress' + ) + ) + + def write(self, data, timeout = None): + r"""Write data to the endpoint. + + The parameter data contains the data to be sent to the endpoint and + timeout is the time limit of the operation. The transfer type and + endpoint address are automatically inferred. + + The method returns the number of bytes written. + + For details, see the Device.write() method. + """ + return self.device.write(self.bEndpointAddress, data, self.interface, timeout) + + def read(self, size, timeout = None): + r"""Read data from the endpoint. + + The parameter size is the number of bytes to read and timeout is the + time limit of the operation.The transfer type and endpoint address + are automatically inferred. + + The method returns an array.array object with the data read. + + For details, see the Device.read() method. + """ + return self.device.read(self.bEndpointAddress, size, self.interface, timeout) + +class Interface(object): + r"""Represent an interface object. + + This class contains all fields of the Interface Descriptor + according to the USB Specification. You may access them as class + properties. For example, to access the field bInterfaceNumber + of the interface descriptor: + + >>> import usb.core + >>> dev = usb.core.find() + >>> for cfg in dev: + >>> for i in cfg: + >>> print i.bInterfaceNumber + """ + + def __init__(self, device, interface = 0, + alternate_setting = 0, configuration = 0): + r"""Initialize the interface object. + + The device parameter is the device object returned by the find() + function. The configuration parameter is the logical index of the + configuration (not the bConfigurationValue field). The interface + parameter is the interface logical index (not the bInterfaceNumber field) + and alternate_setting is the alternate setting logical index (not the + bAlternateSetting value). Not every interface has more than one alternate + setting. In this case, the alternate_setting parameter should be zero. + By "logical index" we mean the relative order of the configurations returned by the + peripheral as a result of GET_DESCRIPTOR request. + """ + self.device = device + self.alternate_index = alternate_setting + self.index = interface + self.configuration = configuration + + backend = device._ctx.backend + + desc = backend.get_interface_descriptor( + self.device._ctx.dev, + interface, + alternate_setting, + configuration + ) + + _set_attr( + desc, + self, + ( + 'bLength', + 'bDescriptorType', + 'bInterfaceNumber', + 'bAlternateSetting', + 'bNumEndpoints', + 'bInterfaceClass', + 'bInterfaceSubClass', + 'bInterfaceProtocol', + 'iInterface', + ) + ) + + def set_altsetting(self): + r"""Set the interface alternate setting.""" + self.device.set_interface_altsetting( + self.bInterfaceNumber, + self.bAlternateSetting + ) + + def __iter__(self): + r"""Iterate over all endpoints of the interface.""" + for i in range(self.bNumEndpoints): + yield Endpoint( + self.device, + i, + self.index, + self.alternate_index, + self.configuration + ) + def __getitem__(self, index): + r"""Return the Endpoint object in the given position.""" + return Endpoint( + self.device, + index, + self.index, + self.alternate_index, + self.configuration + ) + +class Configuration(object): + r"""Represent a configuration object. + + This class contains all fields of the Configuration Descriptor + according to the USB Specification. You may access them as class + properties. For example, to access the field bConfigurationValue + of the configuration descriptor: + + >>> import usb.core + >>> dev = usb.core.find() + >>> for cfg in dev: + >>> print cfg.bConfigurationValue + """ + + def __init__(self, device, configuration = 0): + r"""Initialize the configuration object. + + The device parameter is the device object returned by the find() + function. The configuration parameter is the logical index of the + configuration (not the bConfigurationValue field). By "logical index" + we mean the relative order of the configurations returned by the + peripheral as a result of GET_DESCRIPTOR request. + """ + self.device = device + self.index = configuration + + backend = device._ctx.backend + + desc = backend.get_configuration_descriptor( + self.device._ctx.dev, + configuration + ) + + _set_attr( + desc, + self, + ( + 'bLength', + 'bDescriptorType', + 'wTotalLength', + 'bNumInterfaces', + 'bConfigurationValue', + 'iConfiguration', + 'bmAttributes', + 'bMaxPower' + ) + ) + + def set(self): + r"""Set this configuration as the active one.""" + self.device.set_configuration(self.bConfigurationValue) + + def __iter__(self): + r"""Iterate over all interfaces of the configuration.""" + for i in range(self.bNumInterfaces): + alt = 0 + try: + while True: + yield Interface(self.device, i, alt, self.index) + alt += 1 + except (USBError, IndexError): + pass + def __getitem__(self, index): + r"""Return the Interface object in the given position. + + index is a tuple of two values with interface index and + alternate setting index, respectivally. Example: + + >>> interface = config[(0, 0)] + """ + return Interface(self.device, index[0], index[1], self.index) + + +class Device(object): + r"""Device object. + + This class contains all fields of the Device Descriptor according + to the USB Specification. You may access them as class properties. + For example, to access the field bDescriptorType of the device + descriptor: + + >>> import usb.core + >>> dev = usb.core.find() + >>> dev.bDescriptorType + + Additionally, the class provides methods to communicate with + the hardware. Typically, an application will first call the + set_configuration() method to put the device in a known configured + state, optionally call the set_interface_altsetting() to select the + alternate setting (if there is more than one) of the interface used, + and call the write() and read() method to send and receive data. + + When working in a new hardware, one first try would be like this: + + >>> import usb.core + >>> dev = usb.core.find(idVendor=myVendorId, idProduct=myProductId) + >>> dev.set_configuration() + >>> dev.write(1, 'test') + + This sample finds the device of interest (myVendorId and myProductId should be + replaced by the corresponding values of your device), then configures the device + (by default, the configuration value is 1, which is a typical value for most + devices) and then writes some data to the endpoint 0x01. + + Timeout values for the write, read and ctrl_transfer methods are specified in + miliseconds. If the parameter is omitted, Device.default_timeout value will + be used instead. This property can be set by the user at anytime. + """ + + def __init__(self, dev, backend): + r"""Initialize the Device object. + + Library users should normally get a Device instance through + the find function. The dev parameter is the identification + of a device to the backend and its meaning is opaque outside + of it. The backend parameter is a instance of a backend + object. + """ + self._ctx = _ResourceManager(dev, backend) + self.__default_timeout = _DEFAULT_TIMEOUT + + desc = backend.get_device_descriptor(dev) + + _set_attr( + desc, + self, + ( + 'bLength', + 'bDescriptorType', + 'bcdUSB', + 'bDeviceClass', + 'bDeviceSubClass', + 'bDeviceProtocol', + 'bMaxPacketSize0', + 'idVendor', + 'idProduct', + 'bcdDevice', + 'iManufacturer', + 'iProduct', + 'iSerialNumber', + 'bNumConfigurations', + 'address', + 'bus', + 'port_number' + ) + ) + + if desc.bus is not None: + self.bus = int(desc.bus) + else: + self.bus = None + + if desc.address is not None: + self.address = int(desc.address) + else: + self.address = None + + if desc.port_number is not None: + self.port_number = int(desc.port_number) + else: + self.port_number = None + + def set_configuration(self, configuration = None): + r"""Set the active configuration. + + The configuration parameter is the bConfigurationValue field of the + configuration you want to set as active. If you call this method + without parameter, it will use the first configuration found. + As a device hardly ever has more than one configuration, calling + the method without parameter is enough to get the device ready. + """ + self._ctx.managed_set_configuration(self, configuration) + + def get_active_configuration(self): + r"""Return a Configuration object representing the current configuration set.""" + return self._ctx.get_active_configuration(self) + + def set_interface_altsetting(self, interface = None, alternate_setting = None): + r"""Set the alternate setting for an interface. + + When you want to use an interface and it has more than one alternate setting, + you should call this method to select the alternate setting you would like + to use. If you call the method without one or the two parameters, it will + be selected the first one found in the Device in the same way of set_configuration + method. + + Commonly, an interface has only one alternate setting and this call is + not necessary. For most of the devices, either it has more than one alternate + setting or not, it is not harmful to make a call to this method with no arguments, + as devices will silently ignore the request when there is only one alternate + setting, though the USB Spec allows devices with no additional alternate setting + return an error to the Host in response to a SET_INTERFACE request. + + If you are in doubt, you may want to call it with no arguments wrapped by + a try/except clause: + + >>> try: + >>> dev.set_interface_altsetting() + >>> except usb.core.USBError: + >>> pass + """ + self._ctx.managed_set_interface(self, interface, alternate_setting) + + def reset(self): + r"""Reset the device.""" + self._ctx.managed_open() + self._ctx.dispose(self, False) + self._ctx.backend.reset_device(self._ctx.handle) + self._ctx.dispose(self, True) + + def write(self, endpoint, data, interface = None, timeout = None): + r"""Write data to the endpoint. + + This method is used to send data to the device. The endpoint parameter + corresponds to the bEndpointAddress member whose endpoint you want to + communicate with. The interface parameter is the bInterfaceNumber field + of the interface descriptor which contains the endpoint. If you do not + provide one, the first one found will be used, as explained in the + set_interface_altsetting() method. + + The data parameter should be a sequence like type convertible to + array type (see array module). + + The timeout is specified in miliseconds. + + The method returns the number of bytes written. + """ + backend = self._ctx.backend + + fn_map = { + util.ENDPOINT_TYPE_BULK:backend.bulk_write, + util.ENDPOINT_TYPE_INTR:backend.intr_write, + util.ENDPOINT_TYPE_ISO:backend.iso_write + } + + intf = self._ctx.get_interface(self, interface) + fn = fn_map[self._ctx.get_endpoint_type(self, endpoint, intf)] + self._ctx.managed_claim_interface(self, intf) + + return fn( + self._ctx.handle, + endpoint, + intf.bInterfaceNumber, + _interop.as_array(data), + self.__get_timeout(timeout) + ) + + def read(self, endpoint, size, interface = None, timeout = None): + r"""Read data from the endpoint. + + This method is used to receive data from the device. The endpoint parameter + corresponds to the bEndpointAddress member whose endpoint you want to + communicate with. The interface parameter is the bInterfaceNumber field + of the interface descriptor which contains the endpoint. If you do not + provide one, the first one found will be used, as explained in the + set_interface_altsetting() method. The size parameters tells how many + bytes you want to read. + + The timeout is specified in miliseconds. + + The method returns an array object with the data read. + """ + backend = self._ctx.backend + + fn_map = { + util.ENDPOINT_TYPE_BULK:backend.bulk_read, + util.ENDPOINT_TYPE_INTR:backend.intr_read, + util.ENDPOINT_TYPE_ISO:backend.iso_read + } + + intf = self._ctx.get_interface(self, interface) + fn = fn_map[self._ctx.get_endpoint_type(self, endpoint, intf)] + self._ctx.managed_claim_interface(self, intf) + + return fn( + self._ctx.handle, + endpoint, + intf.bInterfaceNumber, + size, + self.__get_timeout(timeout) + ) + + + def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0, + data_or_wLength = None, timeout = None): + r"""Do a control transfer on the endpoint 0. + + This method is used to issue a control transfer over the + endpoint 0(endpoint 0 is required to always be a control endpoint). + + The parameters bmRequestType, bRequest, wValue and wIndex are the + same of the USB Standard Control Request format. + + Control requests may or may not have a data payload to write/read. + In cases which it has, the direction bit of the bmRequestType + field is used to infere the desired request direction. For + host to device requests (OUT), data_or_wLength parameter is + the data payload to send, and it must be a sequence type convertible + to an array object. In this case, the return value is the number of data + payload written. For device to host requests (IN), data_or_wLength + is the wLength parameter of the control request specifying the + number of bytes to read in data payload. In this case, the return + value is the data payload read, as an array object. + """ + if util.ctrl_direction(bmRequestType) == util.CTRL_OUT: + a = _interop.as_array(data_or_wLength) + elif data_or_wLength is None: + a = 0 + else: + a = data_or_wLength + + self._ctx.managed_open() + + return self._ctx.backend.ctrl_transfer( + self._ctx.handle, + bmRequestType, + bRequest, + wValue, + wIndex, + a, + self.__get_timeout(timeout) + ) + + def is_kernel_driver_active(self, interface): + r"""Determine if there is kernel driver associated with the interface. + + If a kernel driver is active, and the object will be unable to perform I/O. + """ + self._ctx.managed_open() + return self._ctx.backend.is_kernel_driver_active(self._ctx.handle, + self._ctx.get_interface(self, interface).bInterfaceNumber) + + def detach_kernel_driver(self, interface): + r"""Detach a kernel driver. + + If successful, you will then be able to perform I/O. + """ + self._ctx.managed_open() + self._ctx.backend.detach_kernel_driver(self._ctx.handle, + self._ctx.get_interface(self, interface).bInterfaceNumber) + + def attach_kernel_driver(self, interface): + r"""Re-attach an interface's kernel driver, which was previously + detached using detach_kernel_driver().""" + self._ctx.managed_open() + self._ctx.backend.attach_kernel_driver(self._ctx.handle, + self._ctx.get_interface(self, interface).bInterfaceNumber) + + def __iter__(self): + r"""Iterate over all configurations of the device.""" + for i in range(self.bNumConfigurations): + yield Configuration(self, i) + + def __getitem__(self, index): + r"""Return the Configuration object in the given position.""" + return Configuration(self, index) + + def __del__(self): + self._ctx.dispose(self) + + def __get_timeout(self, timeout): + if timeout is not None: + return timeout + return self.__default_timeout + + def __set_def_tmo(self, tmo): + if tmo < 0: + raise ValueError('Timeout cannot be a negative value') + self.__default_timeout = tmo + + def __get_def_tmo(self): + return self.__default_timeout + + default_timeout = property( + __get_def_tmo, + __set_def_tmo, + doc = 'Default timeout for transfer I/O functions' + ) + +def find(find_all=False, backend = None, custom_match = None, **args): + r"""Find an USB device and return it. + + find() is the function used to discover USB devices. + You can pass as arguments any combination of the + USB Device Descriptor fields to match a device. For example: + + find(idVendor=0x3f4, idProduct=0x2009) + + will return the Device object for the device with + idVendor Device descriptor field equals to 0x3f4 and + idProduct equals to 0x2009. + + If there is more than one device which matchs the criteria, + the first one found will be returned. If a matching device cannot + be found the function returns None. If you want to get all + devices, you can set the parameter find_all to True, then find + will return an list with all matched devices. If no matching device + is found, it will return an empty list. Example: + + printers = find(find_all=True, bDeviceClass=7) + + This call will get all the USB printers connected to the system. + (actually may be not, because some devices put their class + information in the Interface Descriptor). + + You can also use a customized match criteria: + + dev = find(custom_match = lambda d: d.idProduct=0x3f4 and d.idvendor=0x2009) + + A more accurate printer finder using a customized match would be like + so: + + def is_printer(dev): + import usb.util + if dev.bDeviceClass == 7: + return True + for cfg in dev: + if usb.util.find_descriptor(cfg, bInterfaceClass=7) is not None: + return True + + printers = find(find_all=True, custom_match = is_printer) + + Now even if the device class code is in the interface descriptor the + printer will be found. + + You can combine a customized match with device descriptor fields. In this + case, the fields must match and the custom_match must return True. In the our + previous example, if we would like to get all printers belonging to the + manufacturer 0x3f4, the code would be like so: + + printers = find(find_all=True, idVendor=0x3f4, custom_match=is_printer) + + If you want to use find as a 'list all devices' function, just call + it with find_all = True: + + devices = find(find_all=True) + + Finally, you may pass a custom backend to the find function: + + find(backend = MyBackend()) + + PyUSB has builtin backends for libusb 0.1, libusb 1.0 and OpenUSB. + If you do not supply a backend explicitly, find() function will select + one of the predefineds backends according to system availability. + + Backends are explained in the usb.backend module. + """ + + def device_iter(k, v): + for dev in backend.enumerate_devices(): + d = Device(dev, backend) + if _interop._reduce( + lambda a, b: a and b, + map( + operator.eq, + v, + map(lambda i: getattr(d, i), k) + ), + True + ) and (custom_match is None or custom_match(d)): + yield d + + if backend is None: + import usb.backend.libusb1 as libusb1 + import usb.backend.libusb0 as libusb0 + import usb.backend.openusb as openusb + + for m in (libusb1, openusb, libusb0): + backend = m.get_backend() + if backend is not None: + _logger.info('find(): using backend "%s"', m.__name__) + break + else: + raise ValueError('No backend available') + + k, v = args.keys(), args.values() + + if find_all: + return [d for d in device_iter(k, v)] + else: + try: + return _interop._next(device_iter(k, v)) + except StopIteration: + return None diff --git a/pybot/usb/legacy.py b/pybot/usb/legacy.py new file mode 100644 index 0000000..9a9fb95 --- /dev/null +++ b/pybot/usb/legacy.py @@ -0,0 +1,344 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +import usb.core as core +import usb.util as util +import usb._interop as _interop +import usb.control as control + +__author__ = 'Wander Lairson Costa' + +USBError = core.USBError + +CLASS_AUDIO = 1 +CLASS_COMM = 2 +CLASS_DATA = 10 +CLASS_HID = 3 +CLASS_HUB = 9 +CLASS_MASS_STORAGE = 8 +CLASS_PER_INTERFACE = 0 +CLASS_PRINTER = 7 +CLASS_VENDOR_SPEC = 255 +DT_CONFIG = 2 +DT_CONFIG_SIZE = 9 +DT_DEVICE = 1 +DT_DEVICE_SIZE = 18 +DT_ENDPOINT = 5 +DT_ENDPOINT_AUDIO_SIZE = 9 +DT_ENDPOINT_SIZE = 7 +DT_HID = 33 +DT_HUB = 41 +DT_HUB_NONVAR_SIZE = 7 +DT_INTERFACE = 4 +DT_INTERFACE_SIZE = 9 +DT_PHYSICAL = 35 +DT_REPORT = 34 +DT_STRING = 3 +ENDPOINT_ADDRESS_MASK = 15 +ENDPOINT_DIR_MASK = 128 +ENDPOINT_IN = 128 +ENDPOINT_OUT = 0 +ENDPOINT_TYPE_BULK = 2 +ENDPOINT_TYPE_CONTROL = 0 +ENDPOINT_TYPE_INTERRUPT = 3 +ENDPOINT_TYPE_ISOCHRONOUS = 1 +ENDPOINT_TYPE_MASK = 3 +ERROR_BEGIN = 500000 +MAXALTSETTING = 128 +MAXCONFIG = 8 +MAXENDPOINTS = 32 +MAXINTERFACES = 32 +RECIP_DEVICE = 0 +RECIP_ENDPOINT = 2 +RECIP_INTERFACE = 1 +RECIP_OTHER = 3 +REQ_CLEAR_FEATURE = 1 +REQ_GET_CONFIGURATION = 8 +REQ_GET_DESCRIPTOR = 6 +REQ_GET_INTERFACE = 10 +REQ_GET_STATUS = 0 +REQ_SET_ADDRESS = 5 +REQ_SET_CONFIGURATION = 9 +REQ_SET_DESCRIPTOR = 7 +REQ_SET_FEATURE = 3 +REQ_SET_INTERFACE = 11 +REQ_SYNCH_FRAME = 12 +TYPE_CLASS = 32 +TYPE_RESERVED = 96 +TYPE_STANDARD = 0 +TYPE_VENDOR = 64 + +class Endpoint(object): + r"""Endpoint descriptor object.""" + def __init__(self, ep): + self.address = ep.bEndpointAddress + self.interval = ep.bInterval + self.maxPacketSize = ep.wMaxPacketSize + self.type = util.endpoint_type(ep.bmAttributes) + +class Interface(object): + r"""Interface descriptor object.""" + def __init__(self, intf): + self.alternateSetting = intf.bAlternateSetting + self.interfaceNumber = intf.bInterfaceNumber + self.iInterface = intf.iInterface + self.interfaceClass = intf.bInterfaceClass + self.interfaceSubClass = intf.bInterfaceSubClass + self.interfaceProtocol = intf.bInterfaceProtocol + self.endpoints = [Endpoint(e) for e in intf] + +class Configuration(object): + r"""Configuration descriptor object.""" + def __init__(self, cfg): + self.iConfiguration = cfg.iConfiguration + self.maxPower = cfg.bMaxPower << 2 + self.remoteWakeup = (cfg.bmAttributes >> 5) & 1 + self.selfPowered = (cfg.bmAttributes >> 6) & 1 + self.totalLength = cfg.wTotalLength + self.value = cfg.bConfigurationValue + self.interfaces = [ + list(g) for k, g in _interop._groupby( + _interop._sorted( + [Interface(i) for i in cfg], + key=lambda i: i.interfaceNumber + ), + lambda i: i.alternateSetting) + ] + +class DeviceHandle(object): + def __init__(self, dev): + self.dev = dev + self.__claimed_interface = -1 + + def bulkWrite(self, endpoint, buffer, timeout = 100): + r"""Perform a bulk write request to the endpoint specified. + + Arguments: + endpoint: endpoint number. + buffer: sequence data buffer to write. + This parameter can be any sequence type. + timeout: operation timeout in miliseconds. (default: 100) + Returns the number of bytes written. + """ + return self.dev.write(endpoint, buffer, self.__claimed_interface, timeout) + + def bulkRead(self, endpoint, size, timeout = 100): + r"""Performs a bulk read request to the endpoint specified. + + Arguments: + endpoint: endpoint number. + size: number of bytes to read. + timeout: operation timeout in miliseconds. (default: 100) + Return a tuple with the data read. + """ + return self.dev.read(endpoint, size, self.__claimed_interface, timeout) + + def interruptWrite(self, endpoint, buffer, timeout = 100): + r"""Perform a interrupt write request to the endpoint specified. + + Arguments: + endpoint: endpoint number. + buffer: sequence data buffer to write. + This parameter can be any sequence type. + timeout: operation timeout in miliseconds. (default: 100) + Returns the number of bytes written. + """ + return self.dev.write(endpoint, buffer, self.__claimed_interface, timeout) + + def interruptRead(self, endpoint, size, timeout = 100): + r"""Performs a interrupt read request to the endpoint specified. + + Arguments: + endpoint: endpoint number. + size: number of bytes to read. + timeout: operation timeout in miliseconds. (default: 100) + Return a tuple with the data read. + """ + return self.dev.read(endpoint, size, self.__claimed_interface, timeout) + + def controlMsg(self, requestType, request, buffer, value = 0, index = 0, timeout = 100): + r"""Perform a control request to the default control pipe on a device. + + Arguments: + requestType: specifies the direction of data flow, the type + of request, and the recipient. + request: specifies the request. + buffer: if the transfer is a write transfer, buffer is a sequence + with the transfer data, otherwise, buffer is the number of + bytes to read. + value: specific information to pass to the device. (default: 0) + index: specific information to pass to the device. (default: 0) + timeout: operation timeout in miliseconds. (default: 100) + Return the number of bytes written. + """ + return self.dev.ctrl_transfer( + requestType, + request, + wValue = value, + wIndex = index, + data_or_wLength = buffer, + timeout = timeout + ) + + def clearHalt(self, endpoint): + r"""Clears any halt status on the specified endpoint. + + Arguments: + endpoint: endpoint number. + """ + cfg = self.dev.get_active_configuration() + intf = util.find_descriptor(cfg, bInterfaceNumber = self.__claimed_interface) + e = util.find_descriptor(intf, bEndpointAddress = endpoint) + control.clear_feature(self.dev, control.ENDPOINT_HALT, e) + + def claimInterface(self, interface): + r"""Claims the interface with the Operating System. + + Arguments: + interface: interface number or an Interface object. + """ + if isinstance(interface, Interface): + if_num = interface.interfaceNumber + else: + if_num = interface + + util.claim_interface(self.dev, if_num) + self.__claimed_interface = if_num + + def releaseInterface(self): + r"""Release an interface previously claimed with claimInterface.""" + util.release_interface(self.dev, self.__claimed_interface) + self.__claimed_interface = -1 + + def reset(self): + r"""Reset the specified device by sending a RESET + down the port it is connected to.""" + self.dev.reset() + + def resetEndpoint(self, endpoint): + r"""Reset all states for the specified endpoint. + + Arguments: + endpoint: endpoint number. + """ + self.clearHalt(endpoint) + + def setConfiguration(self, configuration): + r"""Set the active configuration of a device. + + Arguments: + configuration: a configuration value or a Configuration object. + """ + self.dev.set_configuration(configuration) + + def setAltInterface(self, alternate): + r"""Sets the active alternate setting of the current interface. + + Arguments: + alternate: an alternate setting number or an Interface object. + """ + self.dev.set_interface_altsetting(self.__claimed_interface, alternate) + + def getString(self, index, length, langid = None): + r"""Retrieve the string descriptor specified by index + and langid from a device. + + Arguments: + index: index of descriptor in the device. + length: number of bytes of the string + langid: Language ID. If it is omittedi, will be + used the first language. + """ + return util.get_string(self.dev, length, index, langid).encode('ascii') + + def getDescriptor(self, desc_type, desc_index, length, endpoint = -1): + r"""Retrieves a descriptor from the device identified by the type + and index of the descriptor. + + Arguments: + desc_type: descriptor type. + desc_index: index of the descriptor. + len: descriptor length. + endpoint: ignored. + """ + return control.get_descriptor(self.dev, length, desc_type, desc_index) + + def detachKernelDriver(self, interface): + r"""Detach a kernel driver from the interface (if one is attached, + we have permission and the operation is supported by the OS) + + Arguments: + interface: interface number or an Interface object. + """ + self.dev.detach_kernel_driver(interface) + +class Device(object): + r"""Device descriptor object""" + def __init__(self, dev): + self.deviceClass = dev.bDeviceClass + self.deviceSubClass = dev.bDeviceSubClass + self.deviceProtocol = dev.bDeviceProtocol + self.deviceVersion = str((dev.bcdDevice >> 12) & 0xf) + \ + str((dev.bcdDevice >> 8) & 0xf) + \ + '.' + \ + str((dev.bcdDevice >> 4) & 0xf) + \ + str(dev.bcdDevice & 0xf) + self.devnum = None + self.filename = '' + self.iManufacturer = dev.iManufacturer + self.iProduct = dev.iProduct + self.iSerialNumber = dev.iSerialNumber + self.idProduct = dev.idProduct + self.idVendor = dev.idVendor + self.maxPacketSize = dev.bMaxPacketSize0 + self.usbVersion = str((dev.bcdUSB >> 12) & 0xf) + \ + str((dev.bcdUSB >> 8) & 0xf) + \ + '.' + \ + str((dev.bcdUSB >> 4) & 0xf) + \ + str(dev.bcdUSB & 0xf) + self.configurations = [Configuration(c) for c in dev] + self.dev = dev + + def open(self): + r"""Open the device for use. + + Return a DeviceHandle object + """ + return DeviceHandle(self.dev) + +class Bus(object): + r"""Bus object.""" + def __init__(self): + self.dirname = '' + self.location = 0 + self.devices = [Device(d) for d in core.find(find_all=True)] + +def busses(): + r"""Return a tuple with the usb busses.""" + return (Bus(),) + diff --git a/pybot/usb/util.py b/pybot/usb/util.py new file mode 100644 index 0000000..da4cb0e --- /dev/null +++ b/pybot/usb/util.py @@ -0,0 +1,260 @@ +# Copyright (C) 2009-2011 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +r"""usb.util - Utility functions. + +This module exports: + +endpoint_address - return the endpoint absolute address. +endpoint_direction - return the endpoint transfer direction. +endpoint_type - return the endpoint type +ctrl_direction - return the direction of a control transfer +build_request_type - build a bmRequestType field of a control transfer. +find_descriptor - find an inner descriptor. +claim_interface - explicitly claim an interface. +release_interface - explicitly release an interface. +dispose_resources - release internal resources allocated by the object. +get_string - retrieve a string descriptor from the device. +""" + +__author__ = 'Wander Lairson Costa' + +import operator +import usb._interop as _interop + +# descriptor type +DESC_TYPE_DEVICE = 0x01 +DESC_TYPE_CONFIG = 0x02 +DESC_TYPE_STRING = 0x03 +DESC_TYPE_INTERFACE = 0x04 +DESC_TYPE_ENDPOINT = 0x05 + +# endpoint direction +ENDPOINT_IN = 0x80 +ENDPOINT_OUT = 0x00 + +# endpoint type +ENDPOINT_TYPE_CTRL = 0x00 +ENDPOINT_TYPE_ISO = 0x01 +ENDPOINT_TYPE_BULK = 0x02 +ENDPOINT_TYPE_INTR = 0x03 + +# control request type +CTRL_TYPE_STANDARD = (0 << 5) +CTRL_TYPE_CLASS = (1 << 5) +CTRL_TYPE_VENDOR = (2 << 5) +CTRL_TYPE_RESERVED = (3 << 5) + +# control request recipient +CTRL_RECIPIENT_DEVICE = 0 +CTRL_RECIPIENT_INTERFACE = 1 +CTRL_RECIPIENT_ENDPOINT = 2 +CTRL_RECIPIENT_OTHER = 3 + +# control request direction +CTRL_OUT = 0x00 +CTRL_IN = 0x80 + +_ENDPOINT_ADDR_MASK = 0x0f +_ENDPOINT_DIR_MASK = 0x80 +_ENDPOINT_TRANSFER_TYPE_MASK = 0x03 +_CTRL_DIR_MASK = 0x80 + +def endpoint_address(address): + r"""Return the endpoint absolute address. + + The address parameter is the bEndpointAddress field + of the endpoint descriptor. + """ + return address & _ENDPOINT_ADDR_MASK + +def endpoint_direction(address): + r"""Return the endpoint direction. + + The address parameter is the bEndpointAddress field + of the endpoint descriptor. + The possible return values are ENDPOINT_OUT or ENDPOINT_IN. + """ + return address & _ENDPOINT_DIR_MASK + +def endpoint_type(bmAttributes): + r"""Return the transfer type of the endpoint. + + The bmAttributes parameter is the bmAttributes field + of the endpoint descriptor. + The possible return values are: ENDPOINT_TYPE_CTRL, + ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR. + """ + return bmAttributes & _ENDPOINT_TRANSFER_TYPE_MASK + +def ctrl_direction(bmRequestType): + r"""Return the direction of a control request. + + The bmRequestType parameter is the value of the + bmRequestType field of a control transfer. + The possible return values are CTRL_OUT or CTRL_IN. + """ + return bmRequestType & _CTRL_DIR_MASK + +def build_request_type(direction, type, recipient): + r"""Build a bmRequestType field for control requests. + + These is a conventional function to build a bmRequestType + for a control request. + + The direction parameter can be CTRL_OUT or CTRL_IN. + The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS, + CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values. + The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE, + CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER. + + Return the bmRequestType value. + """ + return recipient | type | direction + +def find_descriptor(desc, find_all=False, custom_match=None, **args): + r"""Find an inner descriptor. + + find_descriptor works in the same way the core.find() function does, + but it acts on general descriptor objects. For example, suppose you + have a Device object called dev and want a Configuration of this + object with its bConfigurationValue equals to 1, the code would + be like so: + + >>> cfg = util.find_descriptor(dev, bConfigurationValue=1) + + You can use any field of the Descriptor as a match criteria, and you + can supply a customized match just like core.find() does. The + find_descriptor function also accepts the find_all parameter to get + a list of descriptor instead of just one. + """ + def desc_iter(k, v): + for d in desc: + if (custom_match is None or custom_match(d)) and \ + _interop._reduce( + lambda a, b: a and b, + map( + operator.eq, + v, + map(lambda i: getattr(d, i), k) + ), + True + ): + yield d + + k, v = args.keys(), args.values() + + if find_all: + return [d for d in desc_iter(k, v)] + else: + try: + return _interop._next(desc_iter(k, v)) + except StopIteration: + return None + +def claim_interface(device, interface): + r"""Explicitly claim an interface. + + PyUSB users normally do not have to worry about interface claiming, + as the library takes care of it automatically. But there are situations + where you need deterministic interface claiming. For these uncommon + cases, you can use claim_interface. + + If the interface is already claimed, either through a previously call + to claim_interface or internally by the device object, nothing happens. + """ + device._ctx.managed_claim_interface(device, interface) + +def release_interface(device, interface): + r"""Explicitly release an interface. + + This function is used to release an interface previously claimed, + either through a call to claim_interface or internally by the + device object. + + Normally, you do not need to worry about claiming policies, as + the device object takes care of it automatically. + """ + device._ctx.managed_release_interface(device, interface) + +def dispose_resources(device): + r"""Release internal resources allocated by the object. + + Sometimes you need to provide deterministic resources + freeing, for example to allow another application to + talk to the device. As Python does not provide deterministic + destruction, this function releases all internal resources + allocated by the device, like device handle and interface + policy. + + After calling this function, you can continue using the device + object normally. If the resources will be necessary again, it + will allocate them automatically. + """ + device._ctx.dispose(device) + +def get_string(dev, length, index, langid = None): + r"""Retrieve a string descriptor from the device. + + dev is the Device object to which the request will be + sent to. + + length is the maximum length of the string in number of characters. + + index is the string descriptor index and langid is the Language + ID of the descriptor. If langid is omitted, the string descriptor + of the first Language ID will be returned. + + The return value is the unicode string present in the descriptor. + """ + from usb.control import get_descriptor + if langid is None: + # Asking for the zero'th index is special - it returns a string + # descriptor that contains all the language IDs supported by the device. + # Typically there aren't many - often only one. The language IDs are 16 + # bit numbers, and they start at the third byte in the descriptor. See + # USB 2.0 specification section 9.6.7 for more information. + # + # Note from libusb 1.0 sources (descriptor.c) + buf = get_descriptor( + dev, + 254, + DESC_TYPE_STRING, + 0 + ) + assert len(buf) >= 4 + langid = buf[2] | (buf[3] << 8) + + buf = get_descriptor( + dev, + length * 2 + 2, # string is utf16 + 2 bytes of the descriptor + DESC_TYPE_STRING, + index, + langid + ) + return buf[2:buf[0]].tostring().decode('utf-16-le') diff --git a/pybot/usb4butia.py b/pybot/usb4butia.py new file mode 100755 index 0000000..eb964d7 --- /dev/null +++ b/pybot/usb4butia.py @@ -0,0 +1,375 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# USB4Butia main +# +# Copyright (c) 2012-2013 Butiá Team butia@fing.edu.uy +# Butia is a free and open robotic platform +# www.fing.edu.uy/inco/proyectos/butia +# Facultad de Ingeniería - Universidad de la República - Uruguay +# +# 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 of the License, 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 +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import imp +import com_usb +from baseboard import Baseboard +from device import Device + +ERROR = -1 + +class USB4Butia(): + + def __init__(self, debug=False, get_modules=True): + self._debug = debug + self._hotplug = [] + self._openables = [] + self._drivers_loaded = {} + self._bb = [] + self._modules = [] + self._get_all_drivers() + self.find_butias(get_modules) + + def get_butia_count(self): + """ + Gets the number of boards detected + """ + return len(self._bb) + + def find_butias(self, get_modules=True): + """ + Search for connected USB4Butia boards and open it + """ + devices = com_usb.find() + for dev in devices: + b = Baseboard(dev) + try: + b.open_baseboard() + self._bb.append(b) + except: + if self._debug: + print 'error open baseboard' + if get_modules: + self.get_modules_list() + + def get_modules_list(self, normal=True): + """ + Get the list of modules loaded in the board + """ + self._modules = [] + n_boards = self.get_butia_count() + + if self._debug: + print '=Listing Devices' + + for i, b in enumerate(self._bb): + try: + listi = b.get_listi() + s = b.get_handler_size() + + if self._debug: + print '===board', i + + for m in range(0, s + 1): + module_name = listi[b.get_handler_type(m)] + if n_boards > 1: + complete_name = module_name + '@' + str(i) + ':' + str(m) + else: + complete_name = module_name + ':' + str(m) + + if self._debug: + print '=====module', module_name, (8 - len(module_name)) * ' ', complete_name + + if not(module_name == 'port'): + + if normal: + self._modules.append(complete_name) + else: + self._modules.append((str(m), module_name, str(i))) + + if not(b.devices.has_key(m) and (b.devices[m].name == module_name)): + d = Device(b, module_name, m) + d.add_functions(self._drivers_loaded[module_name]) + b.add_device(m, d) + + if module_name in self._openables: + b.add_openable_loaded(module_name) + else: + if b.devices.has_key(m): + b.devices.pop(m) + + except Exception, err: + if self._debug: + print 'error module list', err + + return self._modules + + def _get_all_drivers(self): + """ + Load the drivers for the differents devices + """ + # current folder + path_drivers = os.path.join(os.path.dirname(__file__), 'drivers') + if self._debug: + print 'Searching drivers in: ', path_drivers + # normal drivers + tmp = os.listdir(path_drivers) + tmp.sort() + for d in tmp: + if d.endswith('.py'): + name = d.replace('.py', '') + self._openables.append(name) + self._get_driver(path_drivers, name) + # hotplug drivers + path = os.path.join(path_drivers, 'hotplug') + tmp = os.listdir(path) + tmp.sort() + for d in tmp: + if d.endswith('.py'): + name = d.replace('.py', '') + self._hotplug.append(name) + self._get_driver(path, name) + + def _get_driver(self, path, driver): + """ + Get a specify driver + """ + if self._debug: + print 'Loading driver %s...' % driver + abs_path = os.path.abspath(os.path.join(path, driver + '.py')) + f = None + try: + f = imp.load_source(driver, abs_path) + except: + if self._debug: + print 'Cannot load %s' % driver, abs_path + if f and hasattr(f, 'FUNCTIONS'): + self._drivers_loaded[driver] = f.FUNCTIONS + else: + if self._debug: + print 'Driver not have FUNCTIONS' + + def callModule(self, modulename, board_number, number, function, params = []): + """ + Call one function: function for module: modulename in board: board_name + with handler: number (only if the module is pnp, else, the parameter is + None) with parameteres: params + """ + try: + board = self._bb[board_number] + if board.devices.has_key(number) and (board.devices[number].name == modulename): + return board.devices[number].call_function(function, params) + else: + if modulename in self._openables: + if modulename in board.get_openables_loaded(): + number = board.get_device_handler(modulename) + else: + board.add_openable_loaded(modulename) + dev = Device(board, modulename) + number = dev.module_open() + dev.add_functions(self._drivers_loaded[modulename]) + board.add_device(number, dev) + return board.devices[number].call_function(function, params) + else: + if self._debug: + print 'no open and no openable' + return ERROR + except Exception, err: + if self._debug: + print 'error call module', err + return ERROR + + def reconnect(self): + """ + Not implemented + """ + pass + + def refresh(self): + """ + Refresh: if no boards presents, search for them.. else, check if + the boards continues present + """ + if self._bb == []: + self.find_butias(False) + else: + for b in self._bb: + info = ERROR + try: + info = b.get_info() + except: + if self._debug: + print 'error refresh getinfo' + + if info == ERROR: + self._bb.remove(b) + try: + b.close_baseboard() + except: + pass + + def close(self): + """ + Closes all open baseboards + """ + for b in self._bb: + try: + b.close_baseboard() + except: + if self._debug: + print 'error in close baseboard' + self._bb = [] + + def isPresent(self, module_name): + """ + Check if module: module_name is present + """ + module_list = self.get_modules_list() + return (module_name in module_list) + + def loopBack(self, data, board=0): + """ + LoopBack command: send data to the board and get the result. If all is ok + the return must be exactly of the data parameter + """ + return self.callModule('lback', board, 0, 'send', [data]) + + ################################ Movement calls ################################ + + def set2MotorSpeed(self, leftSense = 0, leftSpeed = 0, rightSense = 0, rightSpeed = 0, board = 0): + """ + Set the speed of 2 motors. The sense is 0 or 1, and the speed is + between 0 and 1023 + """ + msg = [int(leftSense), int(leftSpeed / 256.0), leftSpeed % 256, int(rightSense), int(rightSpeed / 256.0) , rightSpeed % 256] + return self.callModule('motors', board, 0, 'setvel2mtr', msg) + + def setMotorSpeed(self, idMotor = 0, sense = 0, speed = 0, board = 0): + """ + Set the speed of one motor. idMotor = 0 for left motor and 1 for the + right motor. The sense is 0 or 1, and the speed is between 0 and 1023 + """ + msg = [idMotor, sense, int(speed / 256.0), speed % 256] + return self.callModule('motors', board, 0, 'setvelmtr', msg) + + ############################### General calls ############################### + + def getBatteryCharge(self, board=0): + """ + Gets the battery level charge + """ + return self.callModule('butia', board, 0, 'get_volt') + + def getVersion(self, board=0): + """ + Gets the version of Butiá module. 22 for new version + """ + return self.callModule('butia', board, 0, 'read_ver') + + def getFirmwareVersion(self, board=0): + """ + Gets the version of the Firmware + """ + return self.callModule('admin', board, 0, 'getVersion') + + ############################### Sensors calls ############################### + + def getButton(self, number, board=0): + """ + Gets the value of the button connected in port: number + """ + res = self.callModule('button', board, number, 'getValue') + if res != ERROR: + return (1 - res) + else: + return res + + def getLight(self, number, board=0): + """ + Gets the value of the light sensor connected in port: number + """ + m = 65535 + res = self.callModule('light', board, number, 'getValue') + if res != ERROR: + return (m - res) + else: + return res + + def getDistance(self, number, board=0): + """ + Gets the value of the distance sensor connected in port: number + """ + return self.callModule('distanc', board, number, 'getValue') + + def getGray(self, number, board=0): + """ + Gets the value of the gray sensor connected in port: number + """ + return self.callModule('grey', board, number, 'getValue') + + def getTemperature(self, number, board=0): + """ + Gets the value of the temperature sensor connected in port: number + """ + return self.callModule('temp', board, number, 'getValue') + + def getResistance(self, number, board=0): + """ + Gets the value of the resistance sensor connected in port: number + """ + vcc = 65535 + raw = self.callModule('res', board, number, 'getValue') + if not(raw == ERROR): + return raw * 6800 / (vcc - raw) + return raw + + def getVoltage(self, number, board=0): + """ + Gets the value of the voltage sensor connected in port: number + """ + vcc = 65535 + raw = self.callModule('volt', board, number, 'getValue') + if not(raw == ERROR): + return raw * 5 / vcc + return raw + + def setLed(self, number, on_off, board=0): + """ + Sets on or off the LED connected in port: number (0 is off, 1 is on) + """ + return self.callModule('led', board, number, 'turn', [int(on_off)]) + + ################################ Extras ################################ + + def modeHack(self, pin, mode, board = 0): + """ + Sets the mode of hack pin. If mode 0 = input, mode 1 = output + """ + msg = [int(pin), int(mode)] + return self.callModule('hackp', board, 0, 'setMode', msg) + + def setHack(self, pin, value, board = 0): + """ + Sets the value of hack pin configured as output. Value is 0 or 1 + """ + msg = [int(pin), int(value)] + return self.callModule('hackp', board, 0, 'write', msg) + + def getHack(self, pin, board = 0): + """ + Gets the value of hack pin configured as input. Returns 0 or 1 + """ + return self.callModule('hackp', board, 0, 'read', [int(pin)]) + diff --git a/robot.py b/robot.py index ab76693..b422842 100755 --- a/robot.py +++ b/robot.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # FollowMe Butia - Robot -# Copyright (C) 2010, 2011, 2012 +# Copyright (C) 2010-2013 # This program was created to use with the robot Butia. # Butia is a project from Facultad de Ingenieria - Uruguay # Facultad de Ingenieria web site: @@ -27,8 +27,7 @@ # Rodrigo Dearmas import time -import commands -import butiaAPI +from pybot import usb4butia import subprocess from gettext import gettext as _ @@ -45,19 +44,8 @@ class Robot(object): def bobot_launch(self): print 'Initialising butia...' - output = commands.getoutput('ps -ax | grep lua') - if 'bobot-server' in output: - print 'bobot is alive!' - else: - try: - print 'creating bobot' - self.bobot = subprocess.Popen(['./lua', 'bobot-server.lua'], cwd='./lib/support') - except: - print 'ERROR creating bobot' - - time.sleep(1) - self.butia = butiaAPI.robot() + self.butia = usb4butia.USB4Butia() self.modules = self.butia.get_modules_list() @@ -131,8 +119,8 @@ class Robot(object): vel_actual = (0, 600, 0, 900) - self.butia.set2MotorSpeed(str(vel_actual[0]), str(vel_actual[1]), str(vel_actual[2]), str(vel_actual[3])) + self.butia.set2MotorSpeed(vel_actual[0], vel_actual[1], vel_actual[2], vel_actual[3]) def stop_robot(self): - self.butia.set2MotorSpeed('0', '0', '0', '0') + self.butia.set2MotorSpeed(0, 0, 0, 0) diff --git a/lib/sugargame/__init__.py b/sugargame/__init__.py index 439eb0c..439eb0c 100755 --- a/lib/sugargame/__init__.py +++ b/sugargame/__init__.py diff --git a/lib/sugargame/canvas.py b/sugargame/canvas.py index 1ce0250..1ce0250 100755 --- a/lib/sugargame/canvas.py +++ b/sugargame/canvas.py diff --git a/lib/sugargame/event.py b/sugargame/event.py index 431a600..431a600 100755 --- a/lib/sugargame/event.py +++ b/sugargame/event.py -- cgit v0.9.1
-Resumen de Funciones
-()() - -
-           -
- - - - -
- -           - - -