2010-07-12 49 views
7

Vì vậy, tôi có mã kiểm tra này để gửi "HELLO" trên một cổng nối tiếp USB:C write() không gửi dữ liệu cho đến gần (fd) được gọi

int fd; 
struct termios tty; 

if((fd = open("/dev/ttyUSB0", O_WRONLY|O_NONBLOCK|O_NOCTTY)) == -1){ 
err(1, "Cannot open write on /dev/ttyUSB0"); 
} 

tcgetattr(fd, &tty); 
tty.c_iflag = 0; 
tty.c_oflag = 0; 
tty.c_lflag = 0; 
tty.c_cflag = 0; 
tty.c_cc[VMIN] = 0; 
tty.c_cc[VTIME] = 0; 
cfsetospeed(&tty, B19200); 
cfsetispeed(&tty, B19200); 
tty.c_cflag |= CREAD|CRTSCTS|HUPCL|CS8; 
tcsetattr(fd, TCSANOW, &tty); 

printf("Write: %i\n", write(fd, "HELLO", 5)); 

sleep(5); 

if(close(fd) != 0){ 
warn("Could not close write fd"); 
} 

Chương trình thực hiện tốt và "HELLO "được gửi nhưng có một vấn đề. "HELLO" dường như không được gửi khi hàm write() được gọi, mà đúng hơn là khi bộ mô tả tệp được đóng lại. Tôi đã thêm dòng ngủ (5) ở trên để kiểm tra lý thuyết này và chắc chắn rằng, "HELLO" được gửi ~ 5 giây sau khi chương trình được thực hiện. Làm thế nào tôi có thể nhận được "HELLO" để được gửi ngay lập tức sau khi lệnh write() thay vì trên close()?

+0

bạn có kiểm tra ' Giá trị trả về tcsetattr' – jweyrich

+0

tcsetattr trả về 0 – Ryan

+0

Bạn nói "HELLO" có ** dường như ** được gửi khi hàm write() được gọi. Bạn thiết lập chính xác điều này như thế nào? Bạn có chắc chắn nó không được gửi ngay lập tức không? và thiết bị không được xử lý i t? –

Trả lời

5

Từ trang người đàn ông của write():

Tờ khai thành công từ write() không thực hiện bất kỳ sự đảm bảo rằng dữ liệu đã được cam kết vào đĩa. Trong thực tế, trên một số triển khai lỗi, nó thậm chí không đảm bảo rằng không gian đã được dành riêng cho dữ liệu. Cách duy nhất để chắc chắn là gọi fsync (2) sau khi bạn đã viết xong tất cả dữ liệu của mình.

Bạn cần gọi số fsync() trên bộ mô tả tệp để đảm bảo dữ liệu thực sự được cam kết.

+0

Thêm "fsync (fd);" ngay sau dòng ghi (fd) trả về -1: "Đối số không hợp lệ". – Ryan

+0

'errno' nói gì? –

+7

Không liên quan. Vấn đề là thiết bị đầu cuối đang ở chế độ đệm đường. –

0

bộ đệm không bị xóa. fflush.

+1

fflush cần một TẬPTIN *, ở đây OP có một bộ mô tả tập tin (và có thể không muốn sử dụng stdio) –

+0

'fdopen' có thể được sử dụng; nếu điều này giải quyết vấn đề OP và anh ta không có lý do tại sao không sử dụng trình xử lý tệp thay vì bộ mô tả tệp. – ShinTakezou

0

Vui lòng xem this question. BAsically bạn cần phải tuôn ra các tập tin để cho IO diễn ra khi bạn muốn.

0

Hãy thử làm một

fflush(NULL); 

sau write(). Có lẽ có một số bộ đệm bên trong mà không phải là đỏ bừng.

+1

không thể giải quyết được vấn đề vì 2 lý do: 1) có quan tâm đến các tệp được mở bằng cách mở fflush không?có lẽ một fdopen là bắt buộc; 2) ghi chú từ trang người đàn ông: fflush() chỉ xóa bộ đệm không gian người dùng được cung cấp bởi thư viện C. Để đảm bảo dữ liệu được lưu trữ trên đĩa vật lý, bộ đệm hạt nhân cũng phải được xóa, ví dụ, với đồng bộ (2) hoặc fsync (2) – ShinTakezou

2

Cổng đầu ra thường được đệm, để có khoảng cách lớn hơn hoặc nhỏ hơn giữa bạn ghi vào luồng đầu ra và nội dung thực sự được gửi tới đĩa, đường hoặc bất kỳ thứ gì. Điều này nói chung là hiệu quả.

Xem fflush (3) để buộc bộ đệm được cam kết với đầu ra.

Bạn cũng có thể mở bộ mô tả đầu ra theo cách khiến nó không bị đệm, nhưng sử dụng fflush để nói 'đó là, tôi đã hoàn thành', có lẽ tốt hơn.

+0

Rất tiếc, có, fflush (3) là cho 'FILE *' và những người khác đã chỉ ra, fsync (2) có lẽ là những gì bạn muốn nếu bạn cần sử dụng FDs. –

+0

Thực tế, hãy xem fcntl (2) trên nền tảng của bạn. Trên một số nền tảng, điều đó sẽ cho phép bạn vô hiệu hóa bộ đệm cho đầu ra, nhưng đó không phải là di động. Nếu bạn muốn từ bỏ hoàn toàn tính di động, thì ioctls cho thiết bị của bạn có thể sẽ giúp ích cho việc này, nhưng điều đó đang trở nên tuyệt vọng. –

+0

fd -> fdopen -> fh; fh -> fileno -> fd ... sự cố không có "FILE *" hoặc fd (nếu tuân thủ cho POSIX và không nghiêm ngặt C89/C99) – ShinTakezou

0

Thay đổi dòng này:

tty.c_cc[VMIN] = 0; 

này:

tty.c_cc[VMIN] = 1; 
+0

Chỉ cần thử điều đó và nó không giúp được – Ryan

7

Thiết bị này là một thiết bị tty, vì vậy fsync sẽ không giúp đỡ, có lẽ không fflush một trong hai.

Theo mặc định, thiết bị đang hoạt động ở chế độ chuẩn, có nghĩa là dữ liệu được đóng gói thành các đơn vị của dòng. Có thể bạn sẽ thấy rằng việc thêm một cặp cr/lf vào dữ liệu của bạn sẽ khiến nó được gửi đi.

Bạn cần đảm bảo chế độ chuẩn bị tắt. Ngoài ra, câu trả lời của R sẽ được sử dụng.

http://en.wikibooks.org/wiki/Serial_Programming/termios

+0

Bạn có thể đăng bài của mình không cấu hình thích hợp ở đây? –

2

trước hết, không biết lý do tại sao bạn đầu tiên đặt tất cả các lĩnh vực termios đến 0, và sau đó, mà không cần bất kỳ sửa đổi để 0 rằng trước đó, quyết định thành lập các cờ rs232 thông thường trên cflag. (thay vì làm điều đó mà không có OR trực tiếp, bây giờ bạn đặt nó là 0, ở trên).

những gì bạn có thể thích - cài đặt tất cả các cờ đó chỉ là cfmakeraw() các trường termios.

cũng đồng bộ hóa(); mà không có bất kỳ tham số nào (NOT fsync!;) dường như gửi tất cả các kết quả đang chờ xử lý tới TẤT CẢ các trình ghi, không chỉ chặn các thiết bị. cũng tcp sockets and rs232 ..

và cũng mở() có một tùy chọn O_SYNC (O_SYNC và O_ASYNC có các tên khó hiểu nhưng không liên quan gì đến giao thức dòng nối tiếp đang được định giờ hay không, lệnh này ngay lập tức cam kết write() ' s và người kia tạo ra một tín hiệu cho bẫy khi đầu vào trở nên có sẵn (kinda như rS232 dựa irq trên dos;)

thiết O_SYNC trong open() có thể đã khắc phục sự cố

cũng 'bằng cách đọc dữ liệu. ở đầu kia '... có những thứ gọi là' led 'và' resistors 'mà bạn có thể kết nối với TXD và SEE dữ liệu;) cũng có những thứ gọi là' rs232 breakout box 'hoặc một phạm vi có thể làm cho nó - trực tiếp có thể nhìn thấy-;) dễ dàng hơn nhiều so với 'đoán' bên nào không hoạt động đúng cách.

CẢNH BÁO: DID NOT TEST CODE. nó biên dịch. nhưng tôi có tất cả các cáp ttyUSB0 của tôi trong một tòa nhà khác. nhưng tôi nghĩ vấn đề chính của bạn là O_SYNC. thiết lập tất cả các thuật ngữ crap thành 0 là khá nhiều giống như cfmakeraw() ... cũng tại sao thiết lập CREAD nếu bạn sẽ mở nó chỉ viết? (tại sao mở nó chỉ viết chứ không phải là ghi đè dù sao? - và cũng với chỉ viết bạn sẽ không phải sợ nó trở thành một tty kiểm soát (O_NOCTTY;) vì vậy trong trường hợp chỉ viết, điều đó không chính xác cần thiết, hoặc .. .

chỉ nhận thấy% i (tương tự cho% d btw) định dạng cũng gây nên một loại không phù hợp cảnh báo giá trị ssize_t trở lại của write() để đúc đó để (int)

#include<termios.h> 
#include<stdio.h> 
#include<unistd.h> 
#include<fcntl.h> 

void main(){ 
int fd; 
struct termios tty; 
fd=-1; 
while(fd<0){fd=open("/dev/ttyUSB0",O_WRONLY|O_NONBLOCK|O_NOCTTY|O_SYNC);sleep(1);}; 
cfmakeraw(&tty); 
tty.c_cflag=CREAD|CRTSCTS|HUPCL|CS8; 
cfsetospeed(&tty,B19200); 
cfsetispeed(&tty,B19200); 
tcsetattr(fd,TCSANOW,&tty); 
printf("Write: %i\n",(int)write(fd,"HELLO",5)); 
sync();//if all else fails, also try without, O_SYNC should already fix that. 
close(fd); 
}; 
Các vấn đề liên quan