Not entirely sure I see your problem. You can easily pass values to a subroutine and the subroutine can return new values for the program to act on.

For example, I can set up an array of characters to send and then call a custom built TRANSMIT subroutine. That subroutine might have error checking and require a handshake or acknowledgement from the distant receiver. The results of that acknowledgement or other parameters like time of transmission, etc are stored in variables that are accessible to the main program once the subroutines finishes.

Likewise I can call a RECEIVE subroutine that gets a group of characters and stores them in an array for the main program to use.

If you need speed, and you can handle assembler, then the subroutine can include blocks of assembly language by using the ASM/ENDASM instructions