u64view icon indicating copy to clipboard operation
u64view copied to clipboard

Use TCP command interface instead of telnet for controlling U64

Open Grrrolf opened this issue 4 years ago • 2 comments

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.

Grrrolf avatar Jan 03 '21 22:01 Grrrolf

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

DusteDdk avatar Jul 10 '21 11:07 DusteDdk

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) {

MeAndMyRhythmbox avatar Jul 15 '21 13:07 MeAndMyRhythmbox