C: Cascading for Aliases?

I’m the interim programmer for our team, and I’m trying to write some dead-reckoning code for the robot. I’ve currently got all my dead-reckoning strategies written in a .h file as an array of command type structures, much like the demo gyro code, but I need to be able to switch between them.

We’re using a DIP switch to choose the strategy we want, and I was wondering if I could use an array variable of command type structures in my functions that is aliased via a cascading-if in my code. (It would look something like this:)

command struct command_list];
if(dipswitch == 0)
      command_list] = strat1_list]; //strat1_list] is defined in an included h file
else if(dipswitch == 1)
      command_list] = strat2_list];

and so on and so forth, with a method calling it like this:

int move_forward(void)
{
     end_time = command_list[current_command].parm_1;
     if(curr_time > end_time)
            rc = 1;
     else
            rc = 0;
}

(So that you can understand what’s going on, end_time would be the time at which you stop moving forward, and curr_time would count millisecs since the match began. You would grab the parameter that end_time is set to from a command type structure out of an array of those structs. command_list] is that array and current_command is a variable that increments as commands are completed.)

Our mentor wasn’t sure whether the aliasing of arrays was legal in C, though it seems like it should be, and I need to change a pretty sizeable chunk of code to find out. Anyone have any ideas?

You probably want to use either an array or arrays, an array and an index array or else pointers:

array or array method:

struct comands cmd_list][20] = {
  {
    {CMD_DRIVE,1,2,3,4},
    {CMD_DRIVE,1,2,3,4},
    {CMD_DRIVE,1,2,3,4},
    {NULL,0,0,0,0}
  },
  {
    {CMD_DRIVE,1,2,3,4},
    {CMD_DRIVE,1,2,3,4},
    {CMD_DRIVE,1,2,3,4},
    {NULL,0,0,0,0}
  }
};

This might use up a lot of memory, and probably will run out of space if you haven’t already.

Another method:

// It may be easier to understand if you know assembly and you have an array of function pointers.
struct comands cmd_list] = {
  {CMD_DRIVE,1,2,3,4}, // 0x0000 DRIVE 1,2,3,4
  {CMD_DRIVE,1,2,3,4}, // 0x0001 DRIVE 1,2,3,4
  {CMD_DRIVE,1,2,3,4}, // 0x0002 DRIVE 1,2,3,4
  {NULL,0,0,0,0}, // 0x0003 RET 0,0,0,0
  {CMD_DRIVE,1,2,3,4}, // 0x0004 DRIVE 1,2,3,4
  {CMD_DRIVE,1,2,3,4}, // 0x0005 DRIVE 1,2,3,4
  {CMD_DRIVE,1,2,3,4}, // 0x0006 DRIVE 1,2,3,4
  {CMD_DRIVE,1,2,3,4}, // 0x0007 DRIVE 1,2,3,4
  {CMD_DRIVE,1,2,3,4}, // 0x0008 DRIVE 1,2,3,4
  {NULL,0,0,0,0} // 0x0009 RET 0,0,0,0
  {CMD_TURN,1,2,3,4}, // 0x000a TURN 1,2,3,4
};
int cmd_list_index]={
  0, // CALL 0x0000
  4, // CALL 0x0004
  10 // CALL 0x0010
}

That one might take up less memory.
The advantage of this is that it’s one long list of stuff.
And it’s already compatible with kevin’s code!

just add anywhere you want in the pre-autonomous routine (disabled mode), some code that sets:


extern int current_command; // To interface with robot.c from another file.
void Default_Routine(void) {
  int switch;
  switch = rxdata.oi_swB_byte.allbits; // Will give you a 16-bit # based on the port2 digin.
  switch = p2_sw_aux1*8 + p2_sw_trig*4 + p_sw_top*2 + p2_sw_aux2; // Longer but more correct way of doing that....
  switch = rc_dig_in03*8+rc_dig_in04*4+rc_dig_in05*2+rc_dig_in07; // Will give you a 16-bit int based on the digital input on the rc.
  current_command = cmd_list_index[switch]; // basically a goto statement.
  // goto cmd_list_index[switch]
}

Basically you can view the NULL items as return statements and if you set the statement “pointer” to one past the return statement you can go instead with the next function.
Kevin’s function will just think that it somehow ended up past the NULL statement and will keep going until the next NULL.

Your idea should work. My team is doing it in basically the same way. Here’s what I’d do.
commands.h


extern struct commands *command_list;

/* externs for the actual command lists */
extern struct command_list_1];
extern struct command_list_2];


commands.c


#include "commands.h"

struct commands *command_list;

/* actual command lists */
struct commands command_list_1 = {
   /* commands */
   {NULL, 0, 0, 0}
}

struct commands command_list_2 = {
   /* different command list */
   {NULL, 0, 0, 0}
}

user_routines_fast.c (at top of file)


#include "commands.h"

user_routines_fast.c (in autonomous function, before the while loop begins)


if(dipswitch == 0)
      command_list = command_list_1; // This makes the command_list pointer look at command_list_1. Because arrays in C are pointers anyways, this _should_ work... Should. :)
else if(dipswitch == 1)
      command_list = command_list_2;

Then, add the newly created commands.c to the project.

So yeah, your idea works.

Just be aware that the multiple structs and multidimensional arrays are memory hogs. The most I was able to do with two different methods that I tried were 3 unique autonomous modes, while our strategy team has identified at least 5 that they would like to have available. As such, we are not going to use the scripting, although we are still going to use the same functions with some modifications.