Wednesday, June 26, 2013

Part 1 Software: Automatic Camera Cable Release with an ATTINY 4313


Prev: Part 0
Next: Part 2
P A R T 1,   S O F T W A R E   D E T A I L S

I know reading can be boring, so here's the end result of the user interface I was trying to achieve, read more about how the menu user interface works below. 

video

The necessary logic components this project requires are:
  • Timer tick for the countdown - this will be interrupt driven in the background by the 8 bit timer on the 4313. 
  • Servo control - will be driven by fast pwm on the 16 bit timer for extra precision
  • User interface
    • Buttons UP, DOWN, SELECT all of which will use interrupts
    • Menu logic
I wanted the menu to be as extendible as possible, the code should be slick and work in blocks. I'd like to approach this problem like I would in Java but in C. 

I settled on having a main menu:

typedef struct {
   uint8_t len;
   MenuItem menuItems[];
}Menu;

A Menu has items in it, that makes sense, and it has a length, which is necessary of iterating through each of the individual menuItems..
Then you've got a Menu Item:

typedef struct {
   char name[17];
   void (*action)(void);
}MenuItem;

The key to this I thought was to only allow menuItems to be flexible in the struct. And make each MenuItem a strict static size. 

Digression about structs:

The interesting thing about a struct that has an array in it with an unknown size like:
typedef struct {
   uint8_t len;
   MenuItem menuItems[];
}Menu;
Is that the compiler will actually leave this as a variable size.. That is until you instantiate it, then it has to be a fixed array. 

An also interesting aspect about the structs is that:
typedef struct {
   uint8_t len;
   MenuItem * menuItems;
}Menu;
Isn't the same thing as above. The compiler will actually (it seemed) only reserve space in the struct for the size of a pointer, not continuous block of menuItems. You'll just have to find out for yourself when you do it!

end Digression

So, we've got this flexible Menu with a bunch of menu items. 
I thought it was a cool idea to say that each MenuItem has a name, 17 chars long (16 character lcd + '\0') and that each has an action method

So in my main loop, all the code does is iterrate through a the list of menuItems. Each menuItem has a name so the code will print that to LCD. And when the user hits select, the code calls the 

menuItem[cursor]->action();  

R E A L I S T I C   S U D O   C O D E

void setTimer() { stuff }
void setHoldtime(){ stuff }
void start(){ stuff }

//Instantiation 
Menu menu = 
{5, 
   { 
   {">SET TIMER      ", &setTimer},
   {">SET HOLD TIME  ", &setHoldTime},
   {">START          ", &start},
   {">TEST           ", &test},
   {">RESET          ", &reset}
   }
};

You just call the action like this:

   (*menu.menuItems[cursor].action)();

cursor is being adjusted in the background by the user and appropriate logic to prevent cursor from going out of bounds because of menu.len 

When it comes to displaying things not selected by the cursor, I just advance the pointer of the menuItem name string by 1, this way only the index of cursor will skip over the '>'

//puts takes a char *
puts( menu.menuItems[anything but cursor index].name + 1 );

D E M O

video

No comments:

Post a Comment