#include <avr/io.h>
+#include <avr/interrupt.h>
#include <stdio.h>
+#include "config.h"
#include "chassis.h"
-#define DEBUG
+#ifdef __AVR_ATmega16__
+#define CHASSISPORT B
+#define POWER_PIN 0
+#define RESET_PIN 1
+#define ACTIVE_LOW
+#else
+#error "Please add chassis power/reset-PIN information for this chip"
+#endif
+
+#define __CPORT(port) PORT##port
+#define _CPORT(port) __CPORT(port)
+#define CPORT _CPORT(CHASSISPORT)
+
+#define __CDDR(port) DDR##port
+#define _CDDR(port) __CDDR(port)
+#define CDDR _CDDR(CHASSISPORT)
+
+static volatile int power_cnt = 0;
+static volatile int reset_cnt = 0;
+static volatile int power_cycle = 0;
+
+static void chassis_set_pins(uint8_t pins, uint8_t state);
void chassis_init()
{
- DDRB = 0xff;
- PORTB = 0xff;
+ chassis_set_pins((1<<POWER_PIN) | (1<<RESET_PIN), 0);
+
+ /* About 1ms */
+ OCR0 = ((F_CPU/64)/1000) - 1;
+
+ TCCR0 = ((1<<WGM01) | (1<<CS01) | (1<<CS00)); /* CTC, Prescaler 64 */
+ TIMSK |= (1<<OCIE0);
+
+}
+
+/* gracefully transition between tri-state and active */
+static void chassis_set_pins(uint8_t pins, uint8_t state)
+{
+ if(state) {
+ /* active */
+#ifndef ACTIVE_LOW
+ /* Pull UPs for a short moment... */
+ CPORT |= pins;
+#endif
+ CDDR |= pins;
+#ifdef ACTIVE_LOW
+ CPORT &= ~pins;
+#endif
+ } else {
+#ifdef ACTIVE_LOW
+ CPORT &= ~pins; /* NoOp... */
+#endif
+ CDDR &= ~pins;
+#ifndef ACTIVE_LOW
+ CPORT &= ~pins;
+#endif
+ }
+}
+
+static void chassis_power(int msec)
+{
+ uint8_t old_SREG = SREG;
+
+ chassis_set_pins((1<<POWER_PIN), 1);
+
+ cli();
+ if (!power_cnt)
+ power_cnt = msec;
+ SREG = old_SREG;
+}
+
+static void chassis_reset(int msec)
+{
+ uint8_t old_SREG = SREG;
+
+ chassis_set_pins((1<<RESET_PIN), 1);
+
+ cli();
+ if (!reset_cnt)
+ reset_cnt = msec;
+ SREG = old_SREG;
}
void chassis_control(unsigned char action)
{
+ uint8_t old_SREG = SREG;
+
#ifdef DEBUG
printf("Chassis control 0x%02x\n", action);
#endif
switch(action) {
case CHASSIS_ACTION_POWER_DOWN:
- PORTB=0xff;
+ chassis_power(POWERDOWN_TIME_MS);
break;
case CHASSIS_ACTION_POWER_UP:
- PORTB=0x00;
+ chassis_power(POWERUP_TIME_MS);
break;
case CHASSIS_ACTION_HARD_RESET:
- PORTB=0x55;
+ chassis_reset(RESET_TIME_MS);
break;
+ case CHASSIS_ACTION_POWER_CYCLE:
+ cli();
+ power_cycle = POWER_CYCLE_PAUSE_MS;
+ SREG = old_SREG;
+ chassis_power(POWERDOWN_TIME_MS);
+
default:
+#ifdef DEBUG
printf("Unimplemented chassis action 0x%02x\n", action);
+#endif
break;
}
}
+
+ISR(TIMER0_COMP_vect)
+{
+ if (power_cnt) {
+ power_cnt--;
+
+ if (!power_cnt)
+ chassis_set_pins((1<<POWER_PIN), 0);
+ } else if (power_cycle) {
+ power_cycle--;
+
+ if (!power_cycle) {
+ chassis_set_pins((1<<POWER_PIN), 1);
+ power_cnt = POWERUP_TIME_MS;
+ }
+ }
+ if (reset_cnt) {
+ reset_cnt--;
+
+ if (!reset_cnt)
+ chassis_set_pins((1<<RESET_PIN), 0);
+ }
+}