Memotech-Bill / pico-filesystem

Add support for STDIO on Files for the Raspberry Pi Pico using NEWLIB hooks
Other
17 stars 2 forks source link

remapping stdin and stdout on the fly #8

Open DarkElvenAngel opened 10 months ago

DarkElvenAngel commented 10 months ago

How do you remap stdin and stdout once the program is running.

I need to switch stdin and stdout to another device while it's connected. I've tried the following code

    fclose(stdin);
    fopen("/dev/ttytelnet","r");
    fclose(stdout);
    fopen("/dev/ttytelnet","w");

I don't know if this is fixable in pfs I've had to force printf to become fprint(stdout,...) I used a define this was the only way to get printf to correctly redirect to the selected stdout.

Memotech-Bill commented 10 months ago

The problem is that the Pico SDK includes its own version of printf. This is in import library, pico_printf. I think that this is included as part of the pico_stdio import library. You need to make sure that you don't include these in your CMakeLists.txt file.

You probably also need to ensure that the configuration option PICO_PRINTF_ALWAYS_INCLUDED is set to zero. See the SDK documentation.

DarkElvenAngel commented 10 months ago

Okay I've added this to the main CMakeLists.txt pico_set_printf_implementation(${BINARY} compiler) This makes things mostly work. I haven't done full testing but this seems like something to note in the README.

I'll comment more once I've done more testing

DarkElvenAngel commented 10 months ago

An update changing the printf to complier works only for printf the following commands don't work properly puts & putchar they don't send to stdout if it's been changed. This is something in the SDK or newlib to be aware of.

Memotech-Bill commented 10 months ago

You must still have pico_stdio amongst your link libraries in CMake, either directly or indirectly.

How this is works is convoluted:

In file pico-sdk/src/rp2_common/pico_stdio/stdio.c:

int WRAPPER_FUNC(putchar)(int c) {
    char cc = (char)c;
    stdio_put_string(&cc, 1, false, false);
    return c;
}

int WRAPPER_FUNC(puts)(const char *s) {
    int len = (int)strlen(s);
    stdio_put_string(s, len, true, false);
    stdio_flush();
    return len;
}

In pico-sdk/src/rp2_common/pico_platform/include/pico/platform.h:

#define WRAPPER_FUNC_NAME(x) __wrap_##x

Which means that WRAPPER_FUNC(putchar) becomes __wrap_putchar, Likewise for puts.

Then in pico-sdk/src/rp2_common/pico_stdio/CMakeLists.txt:

    pico_wrap_function(pico_stdio printf)
    pico_wrap_function(pico_stdio vprintf)
    pico_wrap_function(pico_stdio puts)
    pico_wrap_function(pico_stdio putchar)
    pico_wrap_function(pico_stdio getchar)

And in pico-sdk/src/CMakeLists.txt:

# add a link option to wrap the given function name; i.e. -Wl:wrap=FUNCNAME for gcc
function(pico_wrap_function TARGET FUNCNAME)
    target_link_options(${TARGET} INTERFACE "LINKER:--wrap=${FUNCNAME}")
endfunction()

So as a result of those two CMakeLists.txt files, the following two switches are included in the link options:

--wrap=puts
--wrap=putchar

The result of those switches is that the linker translates calls to puts into calls to __wrap_puts and putchar into __wrap_putchar. See near the bottom of https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html for details.

Without import library pico_stdio puts and putchar should go to the NewLib versions.

DarkElvenAngel commented 10 months ago

I found wherepico_stdio is linked in CmakeLists.txt

Is it required for pfs to work correctly?

Memotech-Bill commented 10 months ago

I think probably not. It was probably put there for initial debugging and never removed.

It should probably be in the CMakeLists.txt for pfs_test instead.

I am not set up to test myself at the moment.