• R/O
  • SSH
  • HTTPS

scip: Commit


Commit MetaInfo

Revision17 (tree)
Time2008-10-20 17:10:41
Authory_o_s

Log Message

Windows用 I/O レイヤ

Change Summary

Incremental Difference

--- libscip2/trunk/src/scipio-win32.c (nonexistent)
+++ libscip2/trunk/src/scipio-win32.c (revision 17)
@@ -0,0 +1,520 @@
1+/*!
2+ @file scipio-win32.c
3+ @brief scip I/O impl for Windows
4+
5+ @author Tomoaki Yoshida <yoshida@furo.org>
6+ @date 2008/10/05
7+ */
8+
9+#include "scipdefs.h"
10+#include <errno.h>
11+#include <fcntl.h>
12+#include <string.h>
13+#include <stdlib.h>
14+#include <stdio.h>
15+#include <windows.h>
16+#include <io.h>
17+
18+#ifdef DEBUG
19+#define D(x) x
20+#else
21+#define D(x)
22+#endif
23+
24+#define CHUNKSIZE 256
25+#define LINESIZE 128
26+
27+typedef struct {
28+ HANDLE h;
29+ DCB originalState;
30+ DCB currentState;
31+ COMMTIMEOUTS timeout;
32+ int timeoutMs;
33+ int in,out,size;
34+ char linebuf[CHUNKSIZE];
35+} tScipIOImpl;
36+
37+typedef tScipIOImpl* tScipIO;
38+
39+// プロトタイプ宣言
40+typedef int speed_t;
41+int scipIOClose(tScipIO aDev);
42+speed_t bitrate(int aBR);
43+int termSetup(tScipIO aDev, int aBitrate);
44+
45+#define INITIAL_SPEED B19200 /* オープン直後に設定する通信速度 */
46+#define LF (0x0a)
47+
48+
49+//! Open オペレーション
50+/*!
51+ デバイスをオープンし、必要ならば通信パラメータをセットアップする。
52+
53+ @retval !NULL I/Oハンドル
54+ @retval NULL 失敗
55+*/
56+tScipIO scipIOOpen(char *aDevName)
57+{
58+ char devname[2048];
59+ tScipIO handle=(tScipIOImpl*)malloc(sizeof(tScipIOImpl));
60+ if(!handle)
61+ return NULL;
62+ sprintf(devname,"\\\\.\\%s",aDevName);
63+ handle->h=CreateFileA(devname,GENERIC_READ|GENERIC_WRITE,
64+ 0,
65+ NULL,
66+ OPEN_EXISTING,
67+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
68+ NULL);
69+ if(handle->h == INVALID_HANDLE_VALUE)
70+ {
71+ LPVOID lpMsg;
72+ FormatMessage(
73+ FORMAT_MESSAGE_ALLOCATE_BUFFER|
74+ FORMAT_MESSAGE_FROM_SYSTEM|
75+ FORMAT_MESSAGE_IGNORE_INSERTS,
76+ NULL,
77+ GetLastError(),
78+ MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
79+ (LPTSTR)&lpMsg,
80+ 0,
81+ NULL);
82+ fprintf(stderr,"port open failed:%s\n",(char*)lpMsg);
83+ LocalFree(lpMsg);
84+ free(handle);
85+ return NULL;
86+ }
87+ // setup line buffer
88+ handle->in=0;
89+ handle->out=0;
90+ handle->size=0;
91+
92+ // Save I/O port state
93+ if(GetCommState(handle->h,&handle->originalState)==0){
94+ LPVOID lpMsg;
95+ FormatMessage(
96+ FORMAT_MESSAGE_ALLOCATE_BUFFER|
97+ FORMAT_MESSAGE_FROM_SYSTEM|
98+ FORMAT_MESSAGE_IGNORE_INSERTS,
99+ NULL,
100+ GetLastError(),
101+ MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
102+ (LPTSTR)&lpMsg,
103+ 0,
104+ NULL);
105+ fprintf(stderr,"portbuf::c'tor::GetCommState:%s\n",(char*)lpMsg);
106+ LocalFree(lpMsg);
107+ }
108+
109+ if(termSetup(handle,19200))
110+ {
111+ scipIOSetTimeout(handle,200);
112+ return handle;
113+ }
114+
115+ scipIOClose(handle);
116+ return NULL;
117+}
118+
119+//! Close オペレーション
120+/*!
121+ デバイスをクローズし、I/O ハンドルを破棄する。
122+ @retval 0 成功
123+ @retval !0 エラーコード
124+*/
125+int scipIOClose(tScipIO aDev)
126+{
127+ if(aDev)
128+ {
129+ SetCommState(aDev->h,&aDev->originalState);
130+ CloseHandle(aDev->h);
131+ free(aDev);
132+ return 0;
133+ }
134+ return -1;
135+}
136+
137+//! Poll in オペレーション
138+/*!
139+ 呼出時点で読み出せるデータが存在するかチェックする。
140+ この関数はブロックしない。
141+
142+ @retval 0 読み出し可能なデータが存在する
143+ @retval <0 エラーコード
144+*/
145+int scipIOPoll(tScipIO aDev)
146+{
147+
148+}
149+
150+ //! Read オペレーション
151+ /*!
152+ 呼出時点で読めるだけのデータを取得する。
153+ もし読めるデータがなければ、最大で scipIOSetTimeout で設定した時間
154+ ブロックしてデータを待つ。
155+
156+ @retval >=0 読み込んだバイト数
157+ @retval <0 エラーコード
158+ */
159+int scipIORead(tScipIO aDev, void *aBuff, size_t aCount, int aTimeoutMs)
160+{
161+ DWORD dwRead;
162+
163+ aDev->timeout.ReadTotalTimeoutConstant=aTimeoutMs;
164+ SetCommTimeouts(aDev->h,&aDev->timeout);
165+ ReadFile(aDev->h,aBuff,aCount,&dwRead,NULL);
166+ return dwRead;
167+}
168+
169+// ReadLine 用ユーティリティ
170+// aDev の linebuf を out index から順に scan して LF を探す
171+// 見つかれば out index からの文字数を、みつからなければ -1 を返す
172+int findEol(tScipIO aDev)
173+{
174+ int i;
175+ for(i=0;i<aDev->size;++i)
176+ {
177+ if(aDev->linebuf[(i+aDev->out)%CHUNKSIZE]==LF)
178+ {
179+ return i+1;
180+ }
181+ }
182+ return -1;
183+}
184+
185+// aBuffの内容を aDev の linebuff に追加する
186+// ReadLineから呼ばれるだけなので、オーバーランは考慮しない
187+void pushBytes(tScipIO aDev, char *aBuff, size_t count)
188+{
189+ size_t size, wrote=0;
190+ while(wrote<count)
191+ {
192+ size=count-wrote;
193+ if(size + aDev->in >= CHUNKSIZE)
194+ size=CHUNKSIZE - aDev->in;
195+ memcpy(aDev->linebuf + aDev->in, aBuff + wrote,size);
196+ wrote+=size;
197+ aDev->in+=size;
198+ if(aDev->in>=CHUNKSIZE) // in <= CHUNKSIZE しか起こり得ないはず
199+ aDev->in=0;
200+ }
201+ aDev->size+=wrote;
202+}
203+
204+//! 1行読み出し
205+/*!
206+ 呼出時点で読み出せる、LFで終わる1行分のデータを取得する。
207+ もし1行分のデータがなければ、最大で scipIOSetTimeout で設定した時間
208+ ブロックしてデータを待つ。
209+
210+ XXX タイミングにより最大で scipIOSetTimeout の2倍の時間ブロックする可能性がある
211+ XXX eolまでのコピーを試みるが、受け側バッファが足りなければ行の途中までコピーする
212+
213+ @retval >=0 読み込んだバイト数
214+ @retval <0 エラーコード
215+*/
216+int scipIOReadLine(tScipIO aDev, char *aBuff, size_t aCount)
217+{
218+ int eol=findEol(aDev),i;
219+ if(eol<0) // バッファ中に行末がみつからなければ受信操作を行う
220+ {
221+ int count;
222+ char linebuf[LINESIZE];
223+ count=scipIORead(aDev,linebuf,LINESIZE,aDev->timeoutMs);
224+ D(fprintf(stderr,"IOReadLine:: IORead()=%d\n",count));
225+ if(count<=0) // <=0 なら先のreadでtimeoutまでblockしてたはずなので終了
226+ {
227+ perror("scipIOReadLine");
228+ return count;
229+ }
230+
231+ pushBytes(aDev,linebuf,count);
232+ eol=findEol(aDev);
233+ D(fprintf(stderr,"IOReadLine:: findEol()=%d\n",eol));
234+ if(eol<0) // 先のreadでtimeoutまでblockしていない可能性があるので再度read
235+ {
236+ int oldcount=count;
237+ struct timeval st1,st2,sub;
238+ count=scipIORead(aDev,linebuf,LINESIZE,aDev->timeoutMs); // 再度readを試行
239+ pushBytes(aDev,linebuf,count);
240+ eol=findEol(aDev);
241+ if(eol<0)
242+ return 0; // no eol found
243+ }
244+ }
245+ D(fprintf(stderr,"IOReadLine:: eol:%d aDev->size:%d\n",eol,aDev->size));
246+ for(i=0;i<eol && i<aDev->size && i<aCount; ++i)
247+ {
248+ aBuff[i]=aDev->linebuf[(aDev->out+i)%CHUNKSIZE];
249+ D(fprintf(stderr,"IOReadLine:: read:0x%x\n",aBuff[i]));
250+ }
251+ aBuff[i]='\0';
252+ aDev->out=(aDev->out+i)%CHUNKSIZE;
253+ aDev->size-=i;
254+ return i;
255+}
256+
257+//! Write オペレーション
258+/*!
259+ デバイスへデータを出力する。
260+ 実際のデータ出力のために(例えばfflushのような)明示的なオペレーションは
261+ 必要ない。
262+ 呼出時点で以前の呼出によるデータ出力が完了していない場合にはその
263+ データ出力が完了するまでブロックする。
264+
265+ @retval >=0 書き込んだバイト数
266+ @retval <0 エラーコード (HRESULT_FROM_WIN32で変換したWIN32エラー)
267+*/
268+int scipIOWrite(tScipIO aDev, const void *aBuff, size_t count)
269+{
270+ DWORD res;
271+ if(WriteFile(aDev->h,aBuff,count,&res,NULL)==0)
272+ {
273+ return HRESULT_FROM_WIN32(GetLastError());
274+ }
275+ return res;
276+}
277+
278+//! 通信速度パラメータ設定
279+/*!
280+ デバイスの通信速度を設定する。
281+ scipIOReadで読み取られていないデータは破棄され、未送信のデータも破棄される。
282+ デバイスがUSBの場合にはデータの破棄だけを行う(scipIOClearと同じ)。
283+
284+ @retval 0 成功
285+ @retval !0 エラーコード
286+*/
287+int scipIOSetBitrate(tScipIO aDev, unsigned int aBitrate)
288+{
289+ int speed;
290+ DCB attr;
291+ if(!GetCommState(aDev->h, &attr))
292+ {
293+ LPVOID lpMsg;
294+ FormatMessage(
295+ FORMAT_MESSAGE_ALLOCATE_BUFFER|
296+ FORMAT_MESSAGE_FROM_SYSTEM|
297+ FORMAT_MESSAGE_IGNORE_INSERTS,
298+ NULL,
299+ GetLastError(),
300+ MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
301+ (LPTSTR)&lpMsg,
302+ 0,
303+ NULL);
304+ fprintf(stderr,"portbuf::termSetup::GetCommState:%s\n",(char*)lpMsg);
305+ LocalFree(lpMsg);
306+ }
307+
308+ attr.BaudRate=bitrate(aBitrate);
309+
310+ scipIOClear(aDev); // flush I/O buffer
311+
312+ if(SetCommState(aDev->h, &attr))
313+ {
314+ return 1;
315+ }
316+ {
317+ LPVOID lpMsg;
318+ FormatMessage(
319+ FORMAT_MESSAGE_ALLOCATE_BUFFER|
320+ FORMAT_MESSAGE_FROM_SYSTEM|
321+ FORMAT_MESSAGE_IGNORE_INSERTS,
322+ NULL,
323+ GetLastError(),
324+ MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
325+ (LPTSTR)&lpMsg,
326+ 0,
327+ NULL);
328+ fprintf(stderr,"portbuf::termSetup::SetCommState:%s\n",(char*)lpMsg);
329+ LocalFree(lpMsg);
330+ return 0;
331+ }
332+}
333+
334+//! 受信タイムアウト設定
335+/*!
336+ scipIORead呼出時にデータが受信されていなかった場合にデータ到着を待つ、
337+ 最長の時間を設定する。
338+ @retval 0 成功
339+ @retval !0 エラーコード
340+*/
341+int scipIOSetTimeout(tScipIO aDev, unsigned int aTimeoutMs)
342+{
343+ // setup timeout
344+ aDev->timeoutMs=aTimeoutMs;
345+ aDev->timeout.ReadIntervalTimeout=MAXDWORD;
346+ aDev->timeout.ReadTotalTimeoutConstant=aTimeoutMs;
347+ aDev->timeout.ReadTotalTimeoutMultiplier=1;
348+ aDev->timeout.WriteTotalTimeoutConstant=aTimeoutMs;
349+ aDev->timeout.WriteTotalTimeoutMultiplier=1;
350+ SetCommTimeouts(aDev->h,&aDev->timeout);
351+
352+}
353+
354+//! 状態復帰
355+/*!
356+ 未送信のデータと受信バッファ中のデータを破棄する。通信デバイスが
357+ 状態を持つ場合には初期状態に復帰し、通信可能な状態にする。
358+
359+ @retval 0 成功
360+ @retval !0 エラーコード
361+*/
362+int scipIOClear(tScipIO aDev)
363+{
364+ DWORD err;
365+ COMSTAT status;
366+ ClearCommError(aDev->h,&err,&status);
367+ aDev->in=0;aDev->out=0;aDev->size=0;
368+}
369+
370+
371+//------------------------------------------------------------
372+
373+//! 通信速度設定値取得
374+/*!
375+ @param [in] aBR 指定する通信速度 (9600-256000bps)
376+ @return SetCommState関数で設定する値
377+ 失敗したときは CBR_19200 を返す
378+ */
379+speed_t bitrate(int aBR)
380+{
381+ switch(aBR)
382+ {
383+ case 9600:
384+ return CBR_9600;
385+
386+ case 19200:
387+ return CBR_19200;
388+
389+ case 38400:
390+ return CBR_38400;
391+
392+ case 57600:
393+ return CBR_57600;
394+
395+ case 115200:
396+ return CBR_115200;
397+
398+ case 128000:
399+ return CBR_128000;
400+
401+ case 256000:
402+ return CBR_256000;
403+
404+ default:
405+ return CBR_19200;
406+ }
407+}
408+
409+//! 通信条件の設定
410+/*
411+ @retval 1 成功
412+ @retval 0 失敗
413+ */
414+int termSetup(tScipIO aDev, int aBitrate)
415+{
416+ // Set I/O parameters
417+ DCB * attr = &aDev->currentState;
418+
419+ attr->DCBlength = sizeof(DCB);
420+
421+ if(!GetCommState(aDev->h, attr))
422+ {
423+ LPVOID lpMsg;
424+ FormatMessage(
425+ FORMAT_MESSAGE_ALLOCATE_BUFFER|
426+ FORMAT_MESSAGE_FROM_SYSTEM|
427+ FORMAT_MESSAGE_IGNORE_INSERTS,
428+ NULL,
429+ GetLastError(),
430+ MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
431+ (LPTSTR)&lpMsg,
432+ 0,
433+ NULL);
434+ fprintf(stderr,"portbuf::termSetup::GetCommState:%s\n",(char*)lpMsg);
435+ LocalFree(lpMsg);
436+ }
437+
438+ //misc setting
439+ attr->fBinary = TRUE; //Binary Mode
440+ attr->fNull = FALSE; //NULL Stripping
441+ attr->fAbortOnError = FALSE;
442+
443+ // speed
444+ attr->BaudRate = bitrate(aBitrate);
445+
446+ // character length
447+ attr->ByteSize = 8;
448+
449+ // XON/XOFF
450+ attr->fOutX=FALSE;
451+ attr->fInX=FALSE;
452+
453+ // parity
454+ attr->fParity = FALSE;
455+ attr->Parity = NOPARITY;
456+
457+ // DSR/DTR
458+ attr->fOutxDsrFlow = 0;
459+ attr->fDtrControl = DTR_CONTROL_DISABLE;
460+
461+ // CTS/RTS
462+ attr->fOutxCtsFlow = 0;
463+ attr->fRtsControl = RTS_CONTROL_DISABLE;
464+
465+ // stop bit
466+ attr->StopBits=ONESTOPBIT;
467+
468+#ifdef DEBUG_SIOSETTING
469+ // hardcorded state for debug
470+ attr->DCBlength=sizeof(DCB);
471+ attr->BaudRate=CBR_115200;
472+ attr->fBinary=TRUE;
473+ attr->fParity=FALSE;
474+ attr->fOutxCtsFlow=FALSE;
475+ attr->fOutxDsrFlow=FALSE;
476+ attr->fDtrControl=DTR_CONTROL_DISABLE;
477+ attr->fDsrSensitivity=FALSE;
478+ attr->fTXContinueOnXoff=FALSE;
479+ attr->fOutX=FALSE;
480+ attr->fInX=FALSE;
481+ attr->fErrorChar=FALSE;
482+ attr->fNull=FALSE;
483+ attr->fRtsControl=RTS_CONTROL_DISABLE;
484+ attr->fAbortOnError=FALSE;
485+ attr->fDummy2=0;
486+ attr->wReserved=0;
487+ attr->XonLim=0;
488+ attr->XoffLim=0;
489+ attr->ByteSize=8;
490+ attr->Parity=NOPARITY;
491+ attr->StopBits=ONESTOPBIT;
492+ attr->XonChar=0;
493+ attr->XoffChar=0;
494+ attr->ErrorChar=0;
495+ attr->EofChar=0;
496+ attr->EvtChar=0;
497+ attr->wReserved1=0;
498+#endif // DEBUG_SIOSETTING
499+ // Commit
500+ if(SetCommState(aDev->h, attr))
501+ {
502+ return 1;
503+ }
504+ {
505+ LPVOID lpMsg;
506+ FormatMessage(
507+ FORMAT_MESSAGE_ALLOCATE_BUFFER|
508+ FORMAT_MESSAGE_FROM_SYSTEM|
509+ FORMAT_MESSAGE_IGNORE_INSERTS,
510+ NULL,
511+ GetLastError(),
512+ MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
513+ (LPTSTR)&lpMsg,
514+ 0,
515+ NULL);
516+ fprintf(stderr,"portbuf::termSetup::SetCommState:%s\n",(char*)lpMsg);
517+ LocalFree(lpMsg);
518+ }
519+ return 0;
520+}
Show on old repository browser