Я пытаюсь получить данные из неповторяющегося вызова функции C, сделанного из библиотеки ctypes, обратно в python.
Стек C получает входные данные от func A (), вызывает func B () для обработки ивызывает func C () для отправки вывода через аппаратное обеспечение (например, UART).
Я вызываю func A () из python, используя библиотеку ctypes.В настоящий момент func C - это код-обертка, который печатает данные на консоль.Это прекрасно работает, но у меня есть графический интерфейс (PyQt5), на котором я хотел бы показать эти данные (строка).
В настоящее время я использую перенаправление StdOut согласно этой статье.https://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/ Но перенаправление stdout у меня не работает, некоторые выходы все еще работают на stdout и перестают работать после некоторых выходов.
Это то, что я сейчас использую.
Cfile.c:
#include "stdio.h"
#include "stdint.h"
void test_consoleout()
{
fprintf(stdout,"0xDE,0xAD,0xBE,0xEF\n");
fflush(stdout);
}
Pythonfile.py
from ctypes import *
import ctypes.util
import time, sys, threading, os, io, tempfile
from contextlib import contextmanager
import platform
if platform.system() == "Linux":
libc = ctypes.CDLL(None)
c_stdout = ctypes.c_void_p.in_dll(libc, 'stdout')
if platform.system() == "Windows":
class FILE(ctypes.Structure):
_fields_ = [
("_ptr", c_char_p),
("_cnt", c_int),
("_base", c_char_p),
("_flag", c_int),
("_file", c_int),
("_charbuf", c_int),
("_bufsize", c_int),
("_tmpfname", c_char_p),
]
ucrtbase = CDLL("ucrtbase")
libc = ucrtbase
iob_func = ucrtbase.__acrt_iob_func
iob_func.restype = c_void_p
iob_func.argtypes = [c_int]
s_stdin = iob_func(0)
c_stdout = iob_func(1)
@contextmanager
def stdout_redirector(stream):
# The original fd stdout points to. Usually 1 on POSIX systems.
original_stdout_fd = sys.stdout.fileno()
def _redirect_stdout(to_fd):
"""Redirect stdout to the given file descriptor."""
# Flush the C-level buffer stdout
libc.fflush(c_stdout)
# Flush and close sys.stdout - also closes the file descriptor (fd)
sys.stdout.close()
# Make original_stdout_fd point to the same file as to_fd
os.dup2(to_fd, original_stdout_fd)
# Create a new sys.stdout that points to the redirected fd
sys.stdout = io.TextIOWrapper(os.fdopen(original_stdout_fd, 'wb'))
# Save a copy of the original stdout fd in saved_stdout_fd
saved_stdout_fd = os.dup(original_stdout_fd)
try:
# Create a temporary file and redirect stdout to it
tfile = tempfile.TemporaryFile(mode='w+b')
_redirect_stdout(tfile.fileno())
# Yield to caller, then redirect stdout back to the saved fd
yield
_redirect_stdout(saved_stdout_fd)
# Copy contents of temporary file to the given stream
tfile.flush()
tfile.seek(0, io.SEEK_SET)
stream.write(tfile.read())
finally:
tfile.close()
os.close(saved_stdout_fd)
C_STACK = CDLL(".\CStack.dll")
while(True):
f = io.BytesIO()
with stdout_redirector(f):
C_STACK .test_consoleout()
time.sleep(0.05)
print('Got stdout: "{0}"'.format(f.getvalue()))
Рекомендуется ли это?Есть ли лучший метод (надежный и минимальные накладные расходы)?Я использую Windows.