PyObjC を EPD にインストールしようとしたところ、ちょっとしたコツがいたのでメモ。
事前に /usr/lib/libpython.dylib にリンクが当たらないようにファイル名を変更するなどの処置をとっておく。
/Library/Frameworks/Python.Framework, /System/Library/Frameworks/Python.Framework のパスも一時的に変更しておく。
その上で easy_install でまずパッケージをインストール。
sudo easy_install pyobjc-core pyobjc
そうすると、インストールは完了するものの、次のようなワーニングが出て
Modules/objc/fsref.m: In function ‘fsref_as_path’: Modules/objc/fsref.m:73: warning: implicit declaration of function ‘PyMac_Error’ Modules/objc/fsref.m:73: warning: nested extern declaration of ‘PyMac_Error’
実行時には、次のようなImport Error が起こる。
ImportError: dlopen(/Library/Frameworks/EPD64.framework/Versions/7.2/lib/python2.7/site-packages/pyobjc_core-2.3-py2.7-macosx-10.5-x86_64.egg/objc/_objc.so, 2): Symbol not found: _PyMac_Error
また,同様に下記のエラーも出る。
ImportError: dlopen(/Library/Frameworks/EPD64.framework/Versions/7.2/lib/python2.7/site-packages/pyobjc_framework_Cocoa-2.3-py2.7-macosx-10.5-x86_64.egg/Foundation/_Foundation.so, 2): Symbol not found: _PyMac_GetOSType
nm で調べてみると、EPD の libpython2.7.dylib には PyMac_Error, PyMac_GetOSType が無い。
nm /Library/Frameworks/EPD64.framework/Versions/Current/lib/libpython2.7.dylib | grep PyMac_Error
逆に,システム標準の python (2.7.1) や ports の python (2.7.2) には存在する。
nm /System/Library/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib | grep PyMac_Error 00000000000b144d T _PyMac_Error nm /opt/local/lib/libpython2.7.dylib | grep PyMac_Error 00000000000d5450 T _PyMac_Error
従って,EPD 独自の仕様が原因なようなので,fsref.m を直接修正すると動きそう。
そこで,まずは easy_install がインストールしている pyobjc-core のソースコードを下記URLからダウンロードする。
wget http://pypi.python.org/packages/source/p/pyobjc-core/pyobjc-core-2.3.tar.gz wget http://pypi.python.org/packages/source/p/pyobjc-framework-Cocoa/pyobjc-framework-Cocoa-2.3.tar.gz
問題の Modules/fsref.m では、プリプロセッサで処理を分けているが、patchlevel.h で定義されている PY_MAJOR_VERSION は EPD も同じ 2 なため下記コードは PyMac_Errorを参照してしまい実際の処理では落ちる。
#if PY_MAJOR_VERSION == 2
PyMac_Error(rc);
#else
PyErr_Format(PyExc_OSError, "MAC Error %d", rc);
#endif
何か EPD で定義されている特別なプリプロセッサが無いか調べたが、見つけられなかったため、PyErr_Format を使用する方向で調整することに。
一応、PyErr_Format は nm コマンドで調べた結果、EPDの libpython2.7.dylib にも存在するので、PyErr_Format を使用するように上記コードを下記のように修正。
PyErr_Format(PyExc_OSError, "MAC Error %d", rc);
次に、pyobjc-framework-Cocoa-2.3 の Modules/_Foundation_typecode.m にて、PyMac_GetOSType の関数宣言を有効化する。
さらに Modules/_AppKit_carbon.m の下記の部分を修正。
#if PY_MAJOR_VERSION == 2 #ifndef __LP64__ #include "pymactoolbox.h" #else /* FIXME: the bits of pymactoolbox.h that we need, * because said header doesn't work in 64-bit mode */ extern PyObject *WinObj_New(WindowPtr); extern int WinObj_Convert(PyObject *, WindowPtr *); extern PyObject *WinObj_WhichWindow(WindowPtr); #endif
全く薦められないやり方だが、WinObj_ConvertとWinObj_Newに関して、_Winmodule.c
を参考にして下記のように書き換える。
#if PY_MAJOR_VERSION == 2
#include "pymactoolbox.h"
/* Function to dispose a window, with a "normal" calling sequence */
static void
PyMac_AutoDisposeWindow(WindowPtr w)
{
DisposeWindow(w);
}
PyTypeObject Window_Type;
#define WinObj_Check(x) ((x)->ob_type == &Window_Type || PyObject_TypeCheck((x), &Window_Type))
typedef struct WindowObject {
PyObject_HEAD
WindowPtr ob_itself;
void (*ob_freeit)(WindowPtr ptr);
} WindowObject;
PyObject *WinObj_New(WindowPtr itself)
{
WindowObject *it;
if (itself == NULL) return PyErr_Format(PyExc_OSError, "MAC Error %d",resNotFound);
/* XXXX Or should we use WhichWindow code here? */
it = PyObject_NEW(WindowObject, &Window_Type);
if (it == NULL) return NULL;
it->ob_itself = itself;
it->ob_freeit = NULL;
if (GetWRefCon(itself) == 0)
{
//SetWRefCon(itself, (long)it);
it->ob_freeit = PyMac_AutoDisposeWindow;
}
return (PyObject *)it;
}
int WinObj_Convert(PyObject *v, WindowPtr *p_itself)
{
if (v == Py_None) { *p_itself = NULL; return 1; }
if (PyInt_Check(v)) { *p_itself = (WindowPtr)PyInt_AsLong(v); return 1; }
{
DialogRef dlg;
if (DlgObj_Convert(v, &dlg) && dlg) {
*p_itself = GetDialogWindow(dlg);
return 1;
}
PyErr_Clear();
}
if (!WinObj_Check(v))
{
PyErr_SetString(PyExc_TypeError, "Window required");
return 0;
}
*p_itself = ((WindowObject *)v)->ob_itself;
return 1;
}
static PyObject *Dlg_Error;
PyTypeObject Dialog_Type;
#define DlgObj_Check(x) ((x)->ob_type == &Dialog_Type || PyObject_TypeCheck((x), &Dialog_Type))
typedef struct DialogObject {
PyObject_HEAD
DialogPtr ob_itself;
} DialogObject;
int DlgObj_Convert(PyObject *v, DialogPtr *p_itself)
{
if (v == Py_None) { *p_itself = NULL; return 1; }
if (PyInt_Check(v)) { *p_itself = (DialogPtr)PyInt_AsLong(v);
return 1; }
if (!DlgObj_Check(v))
{
PyErr_SetString(PyExc_TypeError, "Dialog required");
return 0;
}
*p_itself = ((DialogObject *)v)->ob_itself;
return 1;
}
PyObject *DlgObj_New(DialogPtr itself)
{
DialogObject *it;
if (itself == NULL) { Py_INCREF(Py_None); return Py_None; }
it = PyObject_NEW(DialogObject, &Dialog_Type);
if (it == NULL) return NULL;
it->ob_itself = itself;
//SetWRefCon(GetDialogWindow(itself), (long)it);
return (PyObject *)it;
}
この修正後に pyobjc-core-2.3, pyobjc-framework-Cocoa-2.3 双方を手動でインストール
sudo python setup.py install
Mac ports で手に入る dylib を別環境で使用する際,依存関係が絶対パス指定になっていると別環境でも同様のパスを構成しなければならず、配布の際に面倒。
そこで、下記のようにしてdylib内部の依存関係のパスを書き換えることが可能。
これにより,Mac ports とかでコンパイルされた dylib とかも別環境で任意のパスで動かすことができる
例えば、libsndfile.dylibの依存関係は下記のように記述可能。
install_name_tool -change /opt/local/lib/libogg.0.dylib libogg.0.dylib libvorbisenc.2.dylib
install_name_tool で自分自身のIDを書き換える
install_name_tool -id libsndfile.1.dylib lib/darwin/libsndfile.1.dylib
dylib を読み込む時は、current working directory を dylib のパスに移動してから読み込むとOK
from os.path import join,dirname
from os import getcwd,chdir
import inspect
_curf=inspect.currentframe()
_modpath=dirname(_curf.f_code.co_filename)
from sys import platform
sndfile=None
if platform=='darwin':
librpath=join('lib','darwin')
cwd=getcwd(); chdir(join(_modpath,librpath))
sndfile=CDLL('libsndfile.1.dylib')
chdir(cwd)
ちなみに,dylibbundler というコマンドを使用すると,上記の作業を一括でやってくれるっぽいですね。
ちなみに、Kinect のスペックは下記の通りです。
これは PortAudio のデバッグ情報を使用して調べました。
SDKからWASAPIのサンプルを使用して調べても良かったのですが、その後の事を考えると面倒なので、今回は PortAudio を使うことにしました。
SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
Samples.wValidBitsPerSample=32
nChannels=4
nSamplesPerSec=16000
nBlockAlign=16
対応 API ですが、Windows のカーネルストリーミングは64bit環境では動きませんでした。内部のソースをデバッガで追ったのですが、デバイス自体は見つかるものの、指定したサンプルフォーマットが対応していないということで動きません。唯一、WASAPIのみで動くようになっているようです。
ちなみに、PortAudio++を使用するとこんな感じで初期化できます。
int N=4;
int fs=16000;
AutoSystem autoSys;
System &sys = System::instance();
// Set up the parameters required to open a (Callback)Stream:
HostApi& index = sys.hostApiByTypeId(paWASAPI);
portaudio::HostApi::DeviceIterator i ;
for(i=index.devicesBegin();i!=index.devicesEnd();i++){
if((*i).defaultSampleRate()==16000 && (*i).maxInputChannels()==4 && (*i).maxOutputChannels()==0 ) break ;
}
Device& dev=*i ;
DirectionSpecificStreamParameters inParams(dev,
N, FLOAT32,true,dev.defaultLowInputLatency(), NULL);
StreamParameters params( inParams,
DirectionSpecificStreamParameters::null(),
fs, 1024, paClipOff);
MemFunCallbackStream stream(params, record, callback);
注意すべきは、DirectionSpecificStreamParameters (これはCAPIでは AD変換器のpaStreamParametersの設定に当たります) の設定で,wav なんかにデータを落としたい時は interleaved 引数を true にすること。
もちろん、non-interleaved でも動きますが、データの書き込み時に時間方向とチャネル方向への書き込み方向が反転し、interleaved なデータの並びを仮定している wav フォーマットと inputBuffer 内部のデータの並びが合わなくなります。
逆に、リアルタイムアレイ処理をしたいのならば、ここを false に設定して non-interleaved を選ぶべきでしょう。チャネル毎にデータが分離されるので、後の処理が高速に実行できます。
詳細はここを参照して下さい。
callbackはいつも通りこんな感じです。
int callback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
{
return paContinue;
}
内蔵されているマイクアレイはこんな感じの構造をしている。
これはKinectを真正面から見たときのアレイの構造。
一応、ノギスで測ったモノの、38mmは機体の誤差で40mmかも。意図的にやってるかどうかはわかりません。
マイク本体はこんな感じで、ゴム製のインシュレータに包まれています。
絶縁対策と、モーターの振動がマイクに拾われないようにするためでしょうか。
ばらしてみるとこんな感じです。
マイク本体は CZ034GU という単一指向性コンデンサマイクが使用されています。
本体の寸法など詳細なスペックはここを参考のこと。
これらのマイクは下図のように一つのコネクタにまとめられ、Kinectの本体基盤に接続されています。その先で,WM8737というプリアンプ内蔵AD変換器2台にそれぞれ二つつず接続されています。WM8737についてはここを参照。
本体側のコネクタはバランスになってるんですが、マイク側でCOLDをGNDに落としてるんでしょうね。マイク付近の線の変な盛り上がりはそのためかと。なので、全体はアンバランスで駆動しています。
もしKinectのマイクアレイの音質を上げたいなら、この構造なら一応は色んなマイクに換装はできるようです。
研究室のソフトウェア管理の関係で作成しなければならなくなったので、覚え書き.
QtGui.QSystemTrayIcon を使用する.
PyQt4 でもほぼ一緒.
# coding:utf-8
from PySide import QtCore, QtGui, QtUiTools
from PySide.QtCore import SLOT,SIGNAL
import sys
class Window(QtGui.QDialog):
def __init__(self,parent=None):
super(Window,self).__init__(parent)
self.quitAction = QtGui.QAction("&Quit",self)
self.connect(self.quitAction,SIGNAL('triggered()'),QtGui.qApp,SLOT('quit()'))
self.quitAction.triggered.connect(QtGui.qApp.quit)
self.trayIconMenu = QtGui.QMenu(self)
self.trayIconMenu.addAction(self.quitAction)
self.trayIcon = QtGui.QSystemTrayIcon(self)
self.trayIcon.setContextMenu(self.trayIconMenu)
self.trayIcon.setIcon(QtGui.QIcon("heart.svg"))
self.trayIcon.show()
return
def _main():
app = QtGui.QApplication(sys.argv)
if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
raise OSError("We couldn't detect any system tray on this system.")
QtGui.QApplication.setQuitOnLastWindowClosed(False)
window=Window()
return app.exec_()
if __name__ == "__main__" : _main()
Python を使用して Windows のインストール済みソフトを列挙する時、意外と64bit に対応したコードが少なかったので載せておきます。
あと、もうそろそろ _winreg のページはいい加減消したほうがよいと思う・・・
#coding:utf-8
from win32api import RegOpenKeyEx,RegEnumKeyEx,RegQueryValueEx
from win32con import HKEY_LOCAL_MACHINE,KEY_READ
from platform import architecture
def getInstalledSoftwareList():
softname = []
softver = []
ROOTS=['SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',]
if int(architecture()[0][:2])==64:
ROOTS.append('SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall')
for ROOT in ROOTS:
hkey=RegOpenKeyEx(HKEY_LOCAL_MACHINE,
ROOT,
0, KEY_READ )
for subkey in RegEnumKeyEx(hkey):
try:
subkey=RegOpenKeyEx(HKEY_LOCAL_MACHINE,
ROOT+'\\'+subkey[0],
0, KEY_READ)
softname.append(RegQueryValueEx(subkey,'DisplayName')[0])
softver.append(RegQueryValueEx(subkey,'DisplayVersion')[0])
except:
pass
return softname,softver
def _main():
print getInstalledSoftwareList()
return
if __name__=="__main__" : _main()
意外に知られていないようなので、記事にします。
ssh 接続時に su して X11 を使用しようとすると、下記のようなエラーメッセージが出てコマンドが通りません。
X11 connection rejected because of wrong authentication.
で、この対処法ですが、xauth でごにょごにょしても良いのですが、もっと簡単な方法があります。su コマンドの代わりに xsu コマンドを使用することです。
Debian では xsu は aptitude でインストールできます。
aptitude install xsu
EPD付属の PySerial 2.5 が 64bit windows 環境で動かない。
raise SerialException(“WriteFile failed (%s)” % ctypes.WinError()) serial.serialutil.SerialException: WriteFile failed ([Error 6] ハンドルが無効です。)
同様のバグもここで報告されているよう。
これの問題は、シリアルポートを開く際に内部で呼び出している win32.CreateFile が返すハンドルが 32bit であるということ。
というわけで、python-win32 モジュールを調べてみると win32.CreateFile ではなく、win32file.CreateFile を呼び出せば 64bit ハンドルを取得できる模様。
というわけで、site-packages\serial\serialwin32.py の先頭で
import win32file import win32con
として、
CreateFile, SetupComm, GetCommTimeouts, CloseHandle, SetCommTimeouts, SetCommMask, GetCommState, PurgeComm, etc…
などのwin32モジュールに依存している部分を書き換える。
あと、win32 で良くあるエラーコード取得のための返礼値占領問題も、win32file モジュール中ではポインタ渡しを一部返礼値に変更しているので、ここの部分も修正が必要。
修正にはこのサイトが役立つ。
http://tgolden.sc.sabren.com/pywin32-docs/win32.html
以下、修正後のソース
#! python
# Python Serial Port Extension for Win32, Linux, BSD, Jython
# serial driver for win32
# see __init__.py
#
# (C) 2001-2009 Chris Liechti <cliechti@gmx.net>
# this is distributed under a free software license, see license.txt
#
# Initial patch to use ctypes by Giovanni Bajo <rasky@develer.com>
import ctypes
import win32
import win32file
import win32con
import pywintypes
from serialutil import *
def device(portnum):
"""Turn a port number into a device name"""
return 'COM%d' % (portnum+1) # numbers are transformed to a string
class Win32Serial(SerialBase):
"""Serial port implementation for Win32 based on ctypes."""
BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200)
def __init__(self, *args, **kwargs):
self.hComPort = None
SerialBase.__init__(self, *args, **kwargs)
def open(self):
"""Open port with current settings. This may throw a SerialException
if the port cannot be opened."""
if self._port is None:
raise SerialException("Port must be configured before it can be used.")
# the "\\.\COMx" format is required for devices other than COM1-COM8
# not all versions of windows seem to support this properly
# so that the first few ports are used with the DOS device name
port = self.portstr
try:
if port.upper().startswith('COM') and int(port[3:]) > 8:
port = '\\\\.\\' + port
except ValueError:
# for like COMnotanumber
pass
self.hComPort = win32file.CreateFile(port,
win32con.GENERIC_READ | win32con.GENERIC_WRITE,
0, # exclusive access
None, # no security
win32con.OPEN_EXISTING,
win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_FLAG_OVERLAPPED,
0)
if self.hComPort == win32.INVALID_HANDLE_VALUE:
self.hComPort = None # 'cause __del__ is called anyway
raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
# Setup a 4k buffer
win32file.SetupComm(self.hComPort, 4096, 4096)
# Save original timeout values:
tos = win32file.GetCommTimeouts(self.hComPort)
self._orgTimeouts = win32.COMMTIMEOUTS(*tos)
self._rtsState = win32.RTS_CONTROL_ENABLE
self._dtrState = win32.DTR_CONTROL_ENABLE
self._reconfigurePort()
# Clear buffers:
# Remove anything that was there
win32file.PurgeComm(self.hComPort,
win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
self._overlappedRead = pywintypes.OVERLAPPED()
self._overlappedRead.hEvent = win32.CreateEvent(None, 1, 0, None)
self._overlappedWrite = pywintypes.OVERLAPPED()
#~ self._overlappedWrite.hEvent = win32.CreateEvent(None, 1, 0, None)
self._overlappedWrite.hEvent = win32.CreateEvent(None, 0, 0, None)
self._isOpen = True
def _reconfigurePort(self):
"""Set communication parameters on opened port."""
if not self.hComPort:
raise SerialException("Can only operate on a valid port handle")
# Set Windows timeout values
# timeouts is a tuple with the following items:
# (ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
# ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
# WriteTotalTimeoutConstant)
if self._timeout is None:
timeouts = (0, 0, 0, 0, 0)
elif self._timeout == 0:
timeouts = (win32.MAXDWORD, 0, 0, 0, 0)
else:
timeouts = (0, 0, int(self._timeout*1000), 0, 0)
if self._timeout != 0 and self._interCharTimeout is not None:
timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
if self._writeTimeout is None:
pass
elif self._writeTimeout == 0:
timeouts = timeouts[:-2] + (0, win32.MAXDWORD)
else:
timeouts = timeouts[:-2] + (0, int(self._writeTimeout*1000))
win32file.SetCommTimeouts(self.hComPort, timeouts)
win32file.SetCommMask(self.hComPort, win32.EV_ERR)
# Setup the connection info.
# Get state and modify it:
comDCB = win32file.GetCommState(self.hComPort)
comDCB.BaudRate = self._baudrate
if self._bytesize == FIVEBITS:
comDCB.ByteSize = 5
elif self._bytesize == SIXBITS:
comDCB.ByteSize = 6
elif self._bytesize == SEVENBITS:
comDCB.ByteSize = 7
elif self._bytesize == EIGHTBITS:
comDCB.ByteSize = 8
else:
raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
if self._parity == PARITY_NONE:
comDCB.Parity = win32.NOPARITY
comDCB.fParity = 0 # Disable Parity Check
elif self._parity == PARITY_EVEN:
comDCB.Parity = win32.EVENPARITY
comDCB.fParity = 1 # Enable Parity Check
elif self._parity == PARITY_ODD:
comDCB.Parity = win32.ODDPARITY
comDCB.fParity = 1 # Enable Parity Check
elif self._parity == PARITY_MARK:
comDCB.Parity = win32.MARKPARITY
comDCB.fParity = 1 # Enable Parity Check
elif self._parity == PARITY_SPACE:
comDCB.Parity = win32.SPACEPARITY
comDCB.fParity = 1 # Enable Parity Check
else:
raise ValueError("Unsupported parity mode: %r" % self._parity)
if self._stopbits == STOPBITS_ONE:
comDCB.StopBits = win32.ONESTOPBIT
elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
comDCB.StopBits = win32.ONE5STOPBITS
elif self._stopbits == STOPBITS_TWO:
comDCB.StopBits = win32.TWOSTOPBITS
else:
raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
comDCB.fBinary = 1 # Enable Binary Transmission
# Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE)
if self._rtscts:
comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE
else:
comDCB.fRtsControl = self._rtsState
if self._dsrdtr:
comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE
else:
comDCB.fDtrControl = self._dtrState
comDCB.fOutxCtsFlow = self._rtscts
comDCB.fOutxDsrFlow = self._dsrdtr
comDCB.fOutX = self._xonxoff
comDCB.fInX = self._xonxoff
comDCB.fNull = 0
comDCB.fErrorChar = 0
comDCB.fAbortOnError = 0
comDCB.XonChar = XON
comDCB.XoffChar = XOFF
win32file.SetCommState(self.hComPort, comDCB)
#~ def __del__(self):
#~ self.close()
def close(self):
"""Close port"""
if self._isOpen:
if self.hComPort:
# Restore original timeout values:
win32file.SetCommTimeouts(self.hComPort, self._orgTimeouts)
# Close COM-Port:
win32file.CloseHandle(self.hComPort)
win32file.CloseHandle(self._overlappedRead.hEvent)
win32file.CloseHandle(self._overlappedWrite.hEvent)
self.hComPort = None
self._isOpen = False
def makeDeviceName(self, port):
return device(port)
# - - - - - - - - - - - - - - - - - - - - - - - -
def inWaiting(self):
"""Return the number of characters currently in the input buffer."""
flags = win32.DWORD()
comstat = win32.COMSTAT()
if not win32file.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
raise SerialException('call to ClearCommError failed')
return comstat.cbInQue
def read(self, size=1):
"""Read size bytes from the serial port. If a timeout is set it may
return less characters as requested. With no timeout it will block
until the requested number of bytes is read."""
if not self.hComPort: raise portNotOpenError
if size > 0:
win32.ResetEvent(self._overlappedRead.hEvent)
if not win32file.ClearCommError(self.hComPort):
raise SerialException('call to ClearCommError failed')
if self.timeout == 0:
n = min(comstat.cbInQue, size)
if n > 0:
rc,buf = win32file.ReadFile(self.hComPort, n, self._overlappedRead)
if win32.GetLastError() != win32.ERROR_IO_PENDING:
raise SerialException("ReadFile failed (%s)" % ctypes.WinError())
err = win32.WaitForSingleObject(self._overlappedRead.hEvent, win32.INFINITE)
read = buf[:rc]
else:
read = bytes()
else:
rc,buf = win32file.ReadFile(self.hComPort, size, self._overlappedRead)
rc = win32file.GetOverlappedResult(self.hComPort, self._overlappedRead, True)
read = buf[:rc]
else:
read = bytes()
return bytes(read)
def write(self, data):
"""Output the given string over the serial port."""
if not self.hComPort: raise portNotOpenError
#~ if not isinstance(data, (bytes, bytearray)):
#~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
# convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
if data:
#~ win32event.ResetEvent(self._overlappedWrite.hEvent)
err,n = win32file.WriteFile(self.hComPort, data, self._overlappedWrite)
if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
raise SerialException("WriteFile failed (%s)" % ctypes.WinError())
# Wait for the write to complete.
#~ win32.WaitForSingleObject(self._overlappedWrite.hEvent, win32.INFINITE)
n = win32file.GetOverlappedResult(self.hComPort, self._overlappedWrite, True)
if n != len(data):
raise writeTimeoutError
return n
else:
return 0
def flushInput(self):
"""Clear input buffer, discarding all that is in the buffer."""
if not self.hComPort: raise portNotOpenError
win32.PurgeComm(self.hComPort, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
def flushOutput(self):
"""Clear output buffer, aborting the current output and
discarding all that is in the buffer."""
if not self.hComPort: raise portNotOpenError
win32.PurgeComm(self.hComPort, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
def sendBreak(self, duration=0.25):
"""Send break condition. Timed, returns to idle state after given duration."""
if not self.hComPort: raise portNotOpenError
import time
win32.SetCommBreak(self.hComPort)
time.sleep(duration)
win32.ClearCommBreak(self.hComPort)
def setBreak(self, level=1):
"""Set break: Controls TXD. When active, to transmitting is possible."""
if not self.hComPort: raise portNotOpenError
if level:
win32.SetCommBreak(self.hComPort)
else:
win32.ClearCommBreak(self.hComPort)
def setRTS(self, level=1):
"""Set terminal status line: Request To Send"""
if not self.hComPort: raise portNotOpenError
if level:
self._rtsState = win32.RTS_CONTROL_ENABLE
win32.EscapeCommFunction(self.hComPort, win32.SETRTS)
else:
self._rtsState = win32.RTS_CONTROL_DISABLE
win32.EscapeCommFunction(self.hComPort, win32.CLRRTS)
def setDTR(self, level=1):
"""Set terminal status line: Data Terminal Ready"""
if not self.hComPort: raise portNotOpenError
if level:
self._dtrState = win32.DTR_CONTROL_ENABLE
win32.EscapeCommFunction(self.hComPort, win32.SETDTR)
else:
self._dtrState = win32.DTR_CONTROL_DISABLE
win32.EscapeCommFunction(self.hComPort, win32.CLRDTR)
def _GetCommModemStatus(self):
stat = win32.DWORD()
win32.GetCommModemStatus(self.hComPort, ctypes.byref(stat))
return stat.value
def getCTS(self):
"""Read terminal status line: Clear To Send"""
if not self.hComPort: raise portNotOpenError
return win32.MS_CTS_ON & self._GetCommModemStatus() != 0
def getDSR(self):
"""Read terminal status line: Data Set Ready"""
if not self.hComPort: raise portNotOpenError
return win32.MS_DSR_ON & self._GetCommModemStatus() != 0
def getRI(self):
"""Read terminal status line: Ring Indicator"""
if not self.hComPort: raise portNotOpenError
return win32.MS_RING_ON & self._GetCommModemStatus() != 0
def getCD(self):
"""Read terminal status line: Carrier Detect"""
if not self.hComPort: raise portNotOpenError
return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0
# - - platform specific - - - -
def setXON(self, level=True):
"""Platform specific - set flow state."""
if not self.hComPort: raise portNotOpenError
if level:
win32.EscapeCommFunction(self.hComPort, win32.SETXON)
else:
win32.EscapeCommFunction(self.hComPort, win32.SETXOFF)
def outWaiting(self):
"""return how many characters the in the outgoing buffer"""
flags = win32.DWORD()
comstat = win32.COMSTAT()
if not win32.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
raise SerialException('call to ClearCommError failed')
return comstat.cbOutQue
# assemble Serial class with the platform specific implementation and the base
# for file-like behavior. for Python 2.6 and newer, that provide the new I/O
# library, derive from io.RawIOBase
try:
import io
except ImportError:
# classic version with our own file-like emulation
class Serial(Win32Serial, FileLike):
pass
else:
# io library present
class Serial(Win32Serial, io.RawIOBase):
pass
# Nur Testfunktion!!
if __name__ == '__main__':
s = Serial(0)
sys.stdout.write("%s\n" % s)
s = Serial()
sys.stdout.write("%s\n" % s)
s.baudrate = 19200
s.databits = 7
s.close()
s.port = 0
s.open()
sys.stdout.write("%s\n" % s)
今年も宜しくお願い致します。
vcvarsall.bat でx64バイナリをクロスコンパイルした際に、vcvarsx86_amd64.batが無いと怒られた。以前、VIsual Studio 2008 をインストールした際に、vcvarsx86_amd64.batがC:\Program Files\Microsoft Visual Studio 9.0\VC\bin にあったはずなので、下記URLを参考に10.0(2010)のフォルダにvcvarsx86_amd64.batをコピー。
http://d.hatena.ne.jp/moriyoshi/20100219
中身で9.0となっている部分を10.0に、.Net frameworkのバージョンを自分の開発環境に合わせて4あたりに書き直すと問題なくコンパイルが通る。
ここでも同じようなことが叫ばれてますね。




