DusteDdk / u64view

Viewer for Ultimate64 VIC network stream
Other
36 stars 6 forks source link

Use TCP command interface instead of telnet for controlling U64 #4

Open Grrrolf opened 3 years ago

Grrrolf commented 3 years ago

While trying to find out why u64view is no longer able to enable and disable the video and audio stream I noticed that it is using telnet + simulated key presses to do this. In firmware v1.37 the menu structure has been changed, so the simulated key presses no longer work.

However, there is a better (less fragile) way to enable and disable the video and audio streams. You can use the TCP command interface. More information and explanation on how to use this can be found in the manual on the read the docs website.

DusteDdk commented 3 years ago

Hello, yes, I should switch this over to ujse the TCP command interface indeed! I am adding this as a feature request

MeAndMyRhythmbox commented 3 years ago

Here's my amateur implementation, in case it helps. Whole code snippet as I haven't learnt how to use GIT or make pull requests yet. sendSequence function is unchanged but included as placeholder. I also added hotkeys for Power off and reBoot later in the code as I found them useful... Hope I haven't missed anything.

void sendSequence(char *hostName, const uint8_t *data, int len) {
    IPaddress ip;
    TCPsocket sock;
    uint8_t buf[1024];
    SDLNet_SocketSet set;
    set=SDLNet_AllocSocketSet(1);
    int result =0;

    if(SDLNet_ResolveHost(&ip, hostName, 23)) {
        printf("Error resolving '%s' : %s\n", hostName, SDLNet_GetError());
        return;
    }

    sock = SDLNet_TCP_Open(&ip);
    if(!sock) {
        printf("Error connecting to '%s' : %s\n", hostName, SDLNet_GetError());
        return;
    }

    SDLNet_TCP_AddSocket(set, sock);

    SDL_Delay(10);
    for(int i=0; i < len; i++) {
        SDL_Delay(1);
        if(SDLNet_TCP_Send(sock, &data[i], 1) <1 ) {
            printf("Error sending command data: %s\n", SDLNet_GetError());
        }
        // Empty u64 send buffer
        while( SDLNet_CheckSockets(set, 30) == 1 ) {
            result = SDLNet_TCP_Recv(sock, &buf, 1023);
            buf[result]=0;
            //puts(buf); // debug, messes up terminal.
        }
    }

    SDLNet_TCP_Close(sock);
}

void sendCMD(char *hostName, const uint8_t *data, int len) {
    IPaddress ip;
    TCPsocket sock;
    SDLNet_SocketSet set;
    set=SDLNet_AllocSocketSet(1);

    if(SDLNet_ResolveHost(&ip, hostName, 64)) {
        printf("Error resolving command port on '%s' : %s\n", hostName, SDLNet_GetError());
        return;
    }

    sock = SDLNet_TCP_Open(&ip);
    if(!sock) {
        printf("Error connecting to command port '%s' : %s\n", hostName, SDLNet_GetError());
        return;
    }

    SDLNet_TCP_AddSocket(set, sock);

    SDL_Delay(10);

        SDL_Delay(1);
        if(SDLNet_TCP_Send(sock, data, len) <1 ) 
        {
            printf("Error sending command data: %s\n", SDLNet_GetError());
        }

    SDLNet_TCP_Close(sock);
}

int isStreaming=0;

//Added available TCP Port 64 commands for start/stop streams and reset U64
//Port 23 (Telnet) commands simply send keycodes to Ultimate Telnet UI ... 
//This seems to lock up any Telnet GUI running in another terminal :(

void startStream(char *hostName) {
    const uint8_t data[] = {
        0x20, 0xFF, 0x02, 0x00, 0x00, 0x00, //START stream 0
        0x21, 0xFF, 0x02, 0x00, 0x00, 0x00  //START stream 1
    };
    printf("Sending start stream command to Ultimate64...\n");
    sendCMD(hostName, data, sizeof(data));
    isStreaming=1;
}

void stopStream(char* hostName) {
    const uint8_t data[] = {
        0x30, 0xFF, 0x00, 0x00, //STOP stream 0
        0x31, 0xFF, 0x00, 0x00  //STOP stream 1
    };
    printf("Sending stop stream command to Ultimate64...\n");
    sendCMD(hostName, data, sizeof(data));
    isStreaming=0;
}

void reset(char* hostName) {
    const uint8_t data[] = {
         0x04, 0xff, 0x00, 0x00 //SOCKET_CMD_RESET 0xFF04
    };
    printf("Sending reset command to Ultimate64...\n");
    sendCMD(hostName, data, sizeof(data));
    isStreaming=1;
}

void reBoot(char* hostName) {
    // U64 FW 1.37 / 3.9
    // Select C64 Machine / Reboot C64 using telnet key sequences
    const uint8_t data[] = {
        0x1b, 0x5b, 0x31, 0x35, 0x7e,   // ESC[15~ = F5
        0x1b, 0x5b, 0x42,               // ESC[$42 = Arrow down
        0xd, 0x00,                      // enter
        0x1b, 0x5b, 0x42,               // Arrow down
        0xd, 0x00                       // enter
    };

    printf("Sending reboot key sequence to Ultimate64 via Telnet...\n");
    sendSequence(hostName, data, sizeof(data));
    printf("  * done.\n");
    isStreaming=0;
}

void powerOff(char* hostName) {
    // U64 FW 1.37 / 3.9
    // Select C64 Machine / Power OFF using telnet key sequences
        // will be UDP command in next FW
    const uint8_t data[] = {
        0x1b, 0x5b, 0x31, 0x35, 0x7e,   // ESC[15~ = F5
        0x1b, 0x5b, 0x42,               // ESC[$42 = Arrow down
        0xd, 0x00,                      // enter
        0x1b, 0x5b, 0x42,               // Arrow down
        0x1b, 0x5b, 0x42,               // Arrow down
        0xd, 0x00                       // enter
    };

    printf("Sending power-off key sequence to Ultimate64 via Telnet...\n");
    sendSequence(hostName, data, sizeof(data));
    printf("  * done.\n");
    isStreaming=0;
}

void printColors(const uint64_t *red, const uint64_t *green, const uint64_t *blue) {
    for(int i=0; i < 16; i++) {
        printf("%02x%02x%02x%c", (int)red[i], (int)green[i],(int)blue[i], ((i==15)?' ':',') );
    }

}

void printAudioSpec(SDL_AudioSpec* spec) {
    printf("  Freq: %i\n  Format: %i\n  Channels: %i\n  Samples: %i\n"
            ,spec->freq
            ,spec->format
            ,spec->channels
            ,spec->samples);
}

//int main(int argc, char** argv) {