It sounds like you just want to create a struct (or two) in your code. If you're already successfully reading bytes, storing them in the buffer, and processing them, then you're halfway there.
But this would mean that the data is accessible to every function, and there is the fear that some functions will write to the input data or write to control variables that they should not have access to.
Not necessarily - simply avoid making the struct global. The structure can be declared in "main()" and a pointer to it passed to functions that read or manipulate it.
I also need to reduce memory copies and the like due to limited memory on each micro.
Again, you can pass a pointer to the struct to the functions of interest, so that local copies of that structure won't be created. If you're only reading from, and not modifying, the structure, then declare the struct pointer as "const" in the arguments to those functions. This should make the compiler throw warnings if you accidentally modify something you're not supposed to.
When you finish receiving a string of data, pass the buffer and a struct pointer to a function that parses the data in the buffer and updates the corresponding struct members. Now you can pass this structure around as you see fit, and perform the necessary calculations. You can either store the results in other members of the same structure, or create a second structure that contains "response" data.
When calculations are complete, pass a pointer to the structure (or the second "response" struct) and the buffer to another function that extracts data from the struct and builds the response string in the buffer. Now you can transmit the buffer, which contains the response string. And now you're done - just repeat this process every time you receive a new string of data.
If you don't expect more than one string of data at a time, then you can use the same buffer for reception and transmission (which will reduce memory usage). If you have some sort of data queue, you would be better off making separate transmit and receive buffers.
Here is a bit of sample code that illustrates the point - note the actual implementation details are not covered (for instance, the logic that is responsible for detecting received input and acting accordingly). This is just to show how such code might roughly look.
Code:
struct control_s
{
unsigned char var1;
unsigned char var2;
unsigned char var3;
};
void control_initialize(struct control_s *control);
void buffer_receive(char *buffer);
void control_set(char *buffer, struct control_s *control);
void control_calculate(struct control_s *control);
void buffer_update(char *buffer, struct control_s *control);
void buffer_transmit(const char *buffer);
void main(void)
{
// declare variables
char buffer[SIZE] = {0};
struct control_s control;
// initialize control structure
control_initialize(&control);
// main loop
while(1)
{
buffer_receive(buffer); // when data is received, call this
// function to read all data and store
// in your buffer
control_set(buffer, &control); // this function takes the received
// buffer and stores the data into the
// appropriate control struct members
control_calculate(&control); // this function uses control data received
// from the buffer to calculate other values
// in the control structure (optionally, two
// structures can be used; one for received data,
// another for results to be transmitted)
buffer_update(buffer, &control); // this function takes the results to be
// transmitted, and updates the buffer
// accordingly so that it can be sent
buffer_transmit(buffer); // this function now transmits the string of bytes
// that is the expected response
}
// end of program
}