diff options
135 files changed, 6008 insertions, 1021 deletions
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java index 71309897..ec73f5e3 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java @@ -63,7 +63,10 @@ public abstract class AltosDroidTab extends Fragment implements AltosUnitsListen  			show(last_telem_state, last_state, last_from_receiver, last_receiver);  		} else  			ft.hide(this); -		ft.commitAllowingStateLoss(); +		try { +			ft.commitAllowingStateLoss(); +		} catch (IllegalStateException ie) { +		}  	}  	@Override diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/SetupActivity.java b/altosdroid/src/org/altusmetrum/AltosDroid/SetupActivity.java index d970fc4f..6c2d9d7a 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/SetupActivity.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/SetupActivity.java @@ -256,6 +256,12 @@ public class SetupActivity extends Activity {  	protected void onCreate(Bundle savedInstanceState) {  		super.onCreate(savedInstanceState); +		AltosDebug.init(this); +		AltosDebug.debug("+++ ON CREATE +++"); + +		// Initialise preferences +		AltosDroidPreferences.init(this); +  		// Setup the window  		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);  		setContentView(R.layout.setup); diff --git a/altoslib/AltosAccelCal.java b/altoslib/AltosAccelCal.java index 03d9fbf2..f98090ef 100644 --- a/altoslib/AltosAccelCal.java +++ b/altoslib/AltosAccelCal.java @@ -174,22 +174,23 @@ public class AltosAccelCal implements Runnable {  				if (worked)  					new_config = new AltosConfigData(link);  			} finally { +				int plus = config_data.accel_cal_plus(config_data.pad_orientation); +				int minus = config_data.accel_cal_minus(config_data.pad_orientation);  				System.out.printf("Restore orientation %d +g %d -g %d\n",  						  config_data.pad_orientation, -						  config_data.accel_cal_plus, -						  config_data.accel_cal_minus); -				if (config_data.pad_orientation != AltosLib.MISSING && config_data.pad_orientation != 0) +						  plus, minus); +				if (config_data.pad_orientation != AltosLib.MISSING)  					link.printf("c o %d\n", config_data.pad_orientation); -				if (config_data.accel_cal_plus != AltosLib.MISSING && config_data.accel_cal_minus != AltosLib.MISSING) -					link.printf("c a %d %d\n", -						    config_data.accel_cal_plus, config_data.accel_cal_minus); +				if (plus != AltosLib.MISSING && minus != AltosLib.MISSING) +					link.printf("c a %d %d\n", plus, minus); +				link.flush_output();  				stop_link();  			}  			if (new_config != null) { -				System.out.printf("*** +1g %d -1g %d\n", -						  new_config.accel_cal_plus, -						  new_config.accel_cal_minus); -				listener.cal_done(this, new_config.accel_cal_plus, new_config.accel_cal_minus); +				int plus = new_config.accel_cal_plus(AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP); +				int minus = new_config.accel_cal_minus(AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP); +				System.out.printf("*** +1g %d -1g %d\n", plus, minus); +				listener.cal_done(this, plus, minus);  				if (!wait_signal())  					throw new InterruptedException("aborted");  			} else diff --git a/altoslib/AltosCalData.java b/altoslib/AltosCalData.java index 03e2cbd7..5bc6c4fd 100644 --- a/altoslib/AltosCalData.java +++ b/altoslib/AltosCalData.java @@ -397,7 +397,7 @@ public class AltosCalData {  		set_flight_params(config_data.apogee_delay / ticks_per_sec, config_data.apogee_lockout / ticks_per_sec);  		set_pad_orientation(config_data.pad_orientation);  		set_product(config_data.product); -		set_accel_plus_minus(config_data.accel_cal_plus, config_data.accel_cal_minus); +		set_accel_plus_minus(config_data.accel_cal_plus(config_data.pad_orientation), config_data.accel_cal_minus(config_data.pad_orientation));  		set_accel_zero(config_data.accel_zero_along, config_data.accel_zero_across, config_data.accel_zero_through);  		set_ms5607(config_data.ms5607);  		try { diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index dc036867..8d0bb479 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -22,6 +22,7 @@ import java.util.*;  import java.text.*;  import java.util.concurrent.*; +/* Don't change the field names in this structure; they're part of all .eeprom files */  public class AltosConfigData {  	/* Version information */ @@ -53,6 +54,8 @@ public class AltosConfigData {  	/* HAS_ACCEL */  	public int	accel_cal_plus, accel_cal_minus; +	private int	accel_cal_plus_cooked, accel_cal_minus_cooked; +	private boolean	accel_cal_adjusted;  	public int	pad_orientation;  	/* HAS_LOG */ @@ -186,6 +189,23 @@ public class AltosConfigData {  		}  	} +	public int invert_accel_value(int value) { +		if (value == AltosLib.MISSING) +			return AltosLib.MISSING; + +		switch (log_format) { +		case AltosLib.AO_LOG_FORMAT_FULL: +			return 0x7fff - value; +		case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD: +		case AltosLib.AO_LOG_FORMAT_TELEMETRUM: +		case AltosLib.AO_LOG_FORMAT_TELEMEGA: +		case AltosLib.AO_LOG_FORMAT_TELEMEGA_3: +			return 4095 - value; +		default: +			return AltosLib.MISSING; +		} +	} +  	public boolean has_monitor_battery() {  		if (product.startsWith("TeleBT"))  			return true; @@ -252,9 +272,12 @@ public class AltosConfigData {  		radio_setting = AltosLib.MISSING;  		telemetry_rate = AltosLib.MISSING; +		accel_cal_plus_cooked = AltosLib.MISSING; +		accel_cal_minus_cooked = AltosLib.MISSING;  		accel_cal_plus = AltosLib.MISSING;  		accel_cal_minus = AltosLib.MISSING;  		pad_orientation = AltosLib.MISSING; +		accel_cal_adjusted = false;  		flight_log_max = AltosLib.MISSING;  		log_fixed = AltosLib.MISSING; @@ -285,6 +308,59 @@ public class AltosConfigData {  		accel_zero_through = AltosLib.MISSING;  	} +	/* Return + accel calibration relative to a specific pad orientation */ +	public int accel_cal_plus(int pad_orientation) { +		adjust_accel_cal(); +		switch (pad_orientation) { +		case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP: +			return accel_cal_plus_cooked; +		case AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN: +			return invert_accel_value(accel_cal_minus_cooked); +		default: +			return AltosLib.MISSING; +		} +	} + +	/* Return - accel calibration relative to a specific pad orientation */ +	public int accel_cal_minus(int pad_orientation) { +		adjust_accel_cal(); +		switch (pad_orientation) { +		case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP: +			return accel_cal_minus_cooked; +		case AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN: +			return invert_accel_value(accel_cal_plus_cooked); +		default: +			return AltosLib.MISSING; +		} +	} + +	/* Once we have all of the values from the config data, compute the +	 * accel cal values relative to Antenna Up orientation. +	 */ +	private void adjust_accel_cal() { +		if (!accel_cal_adjusted && +		    pad_orientation != AltosLib.MISSING && +		    accel_cal_plus != AltosLib.MISSING && +		    accel_cal_minus != AltosLib.MISSING && +		    log_format != AltosLib.AO_LOG_FORMAT_UNKNOWN) +		{ +			switch (pad_orientation) { +			case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP: +				accel_cal_plus_cooked = accel_cal_plus; +				accel_cal_minus_cooked = accel_cal_minus; +				accel_cal_adjusted = true; +				break; +			case AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN: +				accel_cal_plus_cooked = invert_accel_value(accel_cal_minus); +				accel_cal_minus_cooked = invert_accel_value(accel_cal_plus); +				accel_cal_adjusted = true; +				break; +			default: +				break; +			} +		} +	} +  	public void parse_line(String line) {  		/* Version replies */ @@ -351,6 +427,7 @@ public class AltosConfigData {  				if (bits.length >= 6) {  					accel_cal_plus = Integer.parseInt(bits[3]);  					accel_cal_minus = Integer.parseInt(bits[5]); +					accel_cal_adjusted = false;  				}  			}  		} catch (Exception e) {} @@ -414,6 +491,9 @@ public class AltosConfigData {  				}  			}  		} catch (Exception e) {} + +		/* Fix accel cal as soon as all of the necessary values appear */ +		adjust_accel_cal();  	}  	public AltosConfigData() { @@ -525,11 +605,11 @@ public class AltosConfigData {  		if (pad_orientation != AltosLib.MISSING)  			pad_orientation = source.pad_orientation(); -		if (accel_cal_plus != AltosLib.MISSING) -			accel_cal_plus = source.accel_cal_plus(); +		if (accel_cal_plus_cooked != AltosLib.MISSING) +			accel_cal_plus_cooked = source.accel_cal_plus(); -		if (accel_cal_minus != AltosLib.MISSING) -			accel_cal_minus = source.accel_cal_minus(); +		if (accel_cal_minus_cooked != AltosLib.MISSING) +			accel_cal_minus_cooked = source.accel_cal_minus();  		/* HAS_LOG */  		if (flight_log_max != AltosLib.MISSING) @@ -598,7 +678,8 @@ public class AltosConfigData {  		dest.set_flight_log_max(flight_log_max);  		dest.set_ignite_mode(ignite_mode);  		dest.set_pad_orientation(pad_orientation); -		dest.set_accel_cal(accel_cal_plus, accel_cal_minus); +		dest.set_accel_cal(accel_cal_plus(AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP), +				   accel_cal_minus(AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP));  		dest.set_callsign(callsign);  		if (npyro != AltosLib.MISSING)  			dest.set_pyros(pyros); @@ -676,10 +757,13 @@ public class AltosConfigData {  			link.printf("c e %d\n", radio_enable);  		/* HAS_ACCEL */ +		/* set orientation first so that we know how to set the accel cal */  		if (pad_orientation != AltosLib.MISSING)  			link.printf("c o %d\n", pad_orientation); -		if (accel_cal_plus != AltosLib.MISSING && accel_cal_minus != AltosLib.MISSING) -			link.printf("c a %d %d\n", accel_cal_plus, accel_cal_minus); +		int plus = accel_cal_plus(pad_orientation); +		int minus = accel_cal_minus(pad_orientation); +		if (plus != AltosLib.MISSING && minus != AltosLib.MISSING) +			link.printf("c a %d %d\n", plus, minus);  		/* HAS_LOG */  		if (flight_log_max != 0) diff --git a/altoslib/AltosDebug.java b/altoslib/AltosDebug.java index 24a25933..a44eb12f 100644 --- a/altoslib/AltosDebug.java +++ b/altoslib/AltosDebug.java @@ -264,8 +264,8 @@ public class AltosDebug {  	public AltosRomconfig romconfig() throws InterruptedException {  		try { -			byte[] bytes = read_memory(0xa0, 10); -			AltosHexfile hexfile = new AltosHexfile (bytes, 0xa0); +			byte[] bytes = read_memory(0x00, 0x200); +			AltosHexfile hexfile = new AltosHexfile (bytes, 0x00);  			return new AltosRomconfig(hexfile);  		} catch (IOException ie) {  		} diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index d130d3ad..182bdd19 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -257,6 +257,15 @@ public class AltosFlightSeries extends AltosDataListener {  	public AltosTimeSeries height_series; +	public double max_height = AltosLib.MISSING; + +	public	void set_min_pressure(double pa) { +		double ground_altitude = cal_data().ground_altitude; +		if (ground_altitude != AltosLib.MISSING) +			max_height = AltosConvert.pressure_to_altitude(pa) - +				ground_altitude; +	} +  	public static final String height_name = "Height";  	public  void set_pressure(double pa) { diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index 6bb83581..2760321d 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -266,8 +266,8 @@ public class AltosFlightStats {  			}  		} -		max_height = AltosLib.MISSING; -		if (series.height_series != null) +		max_height = series.max_height; +		if (max_height == AltosLib.MISSING && series.height_series != null)  			max_height = series.height_series.max().value;  		max_gps_height = AltosLib.MISSING;  		if (series.gps_height != null) { diff --git a/altoslib/AltosHexfile.java b/altoslib/AltosHexfile.java index 6aa98383..f2ab4bea 100644 --- a/altoslib/AltosHexfile.java +++ b/altoslib/AltosHexfile.java @@ -294,15 +294,19 @@ public class AltosHexfile {  		if (usb_descriptors == null)  			return -1; -		/* Walk the descriptors looking for the device */ -		a = usb_descriptors.address; -		while (get_u8(a+1) != AO_USB_DESC_DEVICE) { -			int delta = get_u8(a); -			a += delta; -			if (delta == 0 || a >= max_address) -				return -1; +		try { +			/* Walk the descriptors looking for the device */ +			a = usb_descriptors.address; +			while (get_u8(a+1) != AO_USB_DESC_DEVICE) { +				int delta = get_u8(a); +				a += delta; +				if (delta == 0 || a >= max_address) +					return -1; +			} +			return a; +		} catch (ArrayIndexOutOfBoundsException ae) { +			return -1;  		} -		return a;  	}  	public AltosUsbId find_usb_id() { diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index ba6f1a82..df81c9dd 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -22,13 +22,17 @@ import java.util.concurrent.*;  import java.io.*;  public class AltosIMU implements Cloneable { -	public int		accel_x; -	public int		accel_y; -	public int		accel_z; +	public int		accel_x = AltosLib.MISSING; +	public int		accel_y = AltosLib.MISSING; +	public int		accel_z = AltosLib.MISSING; -	public int		gyro_x; -	public int		gyro_y; -	public int		gyro_z; +	public int		gyro_x = AltosLib.MISSING; +	public int		gyro_y = AltosLib.MISSING; +	public int		gyro_z = AltosLib.MISSING; + +	public int		mag_x = AltosLib.MISSING; +	public int		mag_y = AltosLib.MISSING; +	public int		mag_z = AltosLib.MISSING;  	public static final double	counts_per_g = 2048.0; @@ -58,6 +62,11 @@ public class AltosIMU implements Cloneable {  			gyro_y = Integer.parseInt(items[6]);  			gyro_z = Integer.parseInt(items[7]);  		} +		if (items.length >= 12) { +			mag_x = Integer.parseInt(items[9]); +			mag_y = Integer.parseInt(items[10]); +			mag_z = Integer.parseInt(items[11]); +		}  		return true;  	} @@ -71,6 +80,11 @@ public class AltosIMU implements Cloneable {  		n.gyro_x = gyro_x;  		n.gyro_y = gyro_y;  		n.gyro_z = gyro_z; + +		n.mag_x = mag_x; +		n.mag_y = mag_y; +		n.mag_z = mag_z; +  		return n;  	} @@ -86,6 +100,11 @@ public class AltosIMU implements Cloneable {  				listener.set_accel_ground(imu.accel_y,  							  imu.accel_x,  							  imu.accel_z); +				if (imu.mag_x != AltosLib.MISSING) { +					listener.set_mag(cal_data.mag_along(imu.mag_y), +							 cal_data.mag_across(imu.mag_x), +							 cal_data.mag_through(imu.mag_z)); +				}  			}  		} catch (TimeoutException te) {  		} @@ -99,6 +118,10 @@ public class AltosIMU implements Cloneable {  		gyro_x = AltosLib.MISSING;  		gyro_y = AltosLib.MISSING;  		gyro_z = AltosLib.MISSING; + +		mag_x = AltosLib.MISSING; +		mag_y = AltosLib.MISSING; +		mag_z = AltosLib.MISSING;  	}  	public AltosIMU(AltosLink link) throws InterruptedException, TimeoutException { diff --git a/altoslib/AltosIdleFetch.java b/altoslib/AltosIdleFetch.java index 058df0a1..88a5dab4 100644 --- a/altoslib/AltosIdleFetch.java +++ b/altoslib/AltosIdleFetch.java @@ -133,12 +133,30 @@ public class AltosIdleFetch implements AltosDataProvider {  			       AltosIdler.idle_ms5607,  			       AltosIdler.idle_sensor_metrum), -		new AltosIdler("TeleMega", +		new AltosIdler("TeleMega-v0",  			       AltosIdler.idle_gps,  			       AltosIdler.idle_mma655x,  			       AltosIdler.idle_ms5607,  			       AltosIdler.idle_imu, AltosIdler.idle_mag,  			       AltosIdler.idle_sensor_mega), +		new AltosIdler("TeleMega-v1", +			       AltosIdler.idle_gps, +			       AltosIdler.idle_mma655x, +			       AltosIdler.idle_ms5607, +			       AltosIdler.idle_imu, AltosIdler.idle_mag, +			       AltosIdler.idle_sensor_mega), +		new AltosIdler("TeleMega-v2", +			       AltosIdler.idle_gps, +			       AltosIdler.idle_mma655x, +			       AltosIdler.idle_ms5607, +			       AltosIdler.idle_imu, AltosIdler.idle_mag, +			       AltosIdler.idle_sensor_mega), +		new AltosIdler("TeleMega-v3", +			       AltosIdler.idle_gps, +			       AltosIdler.idle_mma655x, +			       AltosIdler.idle_ms5607, +			       AltosIdler.idle_imu, +			       AltosIdler.idle_sensor_mega),  		new AltosIdler("EasyMega",  			       AltosIdler.idle_mma655x,  			       AltosIdler.idle_ms5607, diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index c25a6273..7d2b68e0 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -348,6 +348,9 @@ public class AltosLib {  	public static final int AO_GPS_NUM_SAT_SHIFT = 0;  	public static final int AO_GPS_NUM_SAT_MASK = 0xf; +	public static final int AO_PAD_ORIENTATION_ANTENNA_UP = 0; +	public static final int AO_PAD_ORIENTATION_ANTENNA_DOWN = 1; +  	public static final int AO_LOG_FORMAT_UNKNOWN = 0;  	public static final int AO_LOG_FORMAT_FULL = 1;  	public static final int AO_LOG_FORMAT_TINY = 2; diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 829a1a63..3ad34891 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -339,9 +339,22 @@ public abstract class AltosLink implements Runnable {  	public void flush_input() throws InterruptedException { -		if (remote) -			flush_input(500); -		else +		if (remote) { +			int timeout = 500; +			switch (telemetry_rate) { +			case AltosLib.ao_telemetry_rate_38400: +			default: +				timeout = 500; +				break; +			case AltosLib.ao_telemetry_rate_9600: +				timeout = 1000; +				break; +			case AltosLib.ao_telemetry_rate_2400: +				timeout = 2000; +				break; +			} +			flush_input(timeout); +		} else  			flush_input(100);  	} diff --git a/altoslib/AltosPyro.java b/altoslib/AltosPyro.java index 0ea3bfc1..fea4fd59 100644 --- a/altoslib/AltosPyro.java +++ b/altoslib/AltosPyro.java @@ -29,24 +29,24 @@ public class AltosPyro {  	public static final int pyro_accel_greater		= 0x00000002;  	public static final String pyro_accel_less_string	= "a<";  	public static final String pyro_accel_greater_string	= "a>"; -	public static final String pyro_accel_less_name		= "Acceleration less than"; -	public static final String pyro_accel_greater_name	= "Acceleration greater than"; +	public static final String pyro_accel_less_name		= "Vertical acceleration less than"; +	public static final String pyro_accel_greater_name	= "Vertical acceleration greater than";  	public static final double pyro_accel_scale		= 16.0;  	public static final int pyro_speed_less			= 0x00000004;  	public static final int pyro_speed_greater		= 0x00000008;  	public static final String pyro_speed_less_string	= "s<";  	public static final String pyro_speed_greater_string	= "s>"; -	public static final String pyro_speed_less_name		= "Speed less than"; -	public static final String pyro_speed_greater_name	= "Speed greater than"; +	public static final String pyro_speed_less_name		= "Ascent rate less than"; +	public static final String pyro_speed_greater_name	= "Ascent rate greater than";  	public static final double pyro_speed_scale		= 16.0;  	public static final int pyro_height_less		= 0x00000010;  	public static final int pyro_height_greater		= 0x00000020;  	public static final String pyro_height_less_string	= "h<";  	public static final String pyro_height_greater_string	= "h>"; -	public static final String pyro_height_less_name	= "Height less than"; -	public static final String pyro_height_greater_name	= "Height greater than"; +	public static final String pyro_height_less_name	= "Height above pad less than"; +	public static final String pyro_height_greater_name	= "Height above pad greater than";  	public static final double pyro_height_scale		= 1.0;  	public static final int pyro_orient_less		= 0x00000040; @@ -61,8 +61,8 @@ public class AltosPyro {  	public static final int pyro_time_greater		= 0x00000200;  	public static final String pyro_time_less_string	= "t<";  	public static final String pyro_time_greater_string	= "t>"; -	public static final String pyro_time_less_name		= "Time since boost less than (s)"; -	public static final String pyro_time_greater_name	= "Time since boost greater than (s)"; +	public static final String pyro_time_less_name		= "Time since launch less than (s)"; +	public static final String pyro_time_greater_name	= "Time since launch greater than (s)";  	public static final double pyro_time_scale		= 100.0;  	public static final int pyro_ascending			= 0x00000400; @@ -90,7 +90,10 @@ public class AltosPyro {  	public static final String pyro_state_greater_or_equal_name	= "Flight state after";  	public static final double pyro_state_scale		= 1.0; +	public static final int pyro_deprecate			= pyro_ascending | pyro_descending; +  	public static final int	pyro_all			= 0x0000ffff; +	public static final int pyro_all_useful			= pyro_all ^ pyro_deprecate;  	public static final int pyro_no_value			= (pyro_ascending |  								   pyro_descending); diff --git a/altoslib/AltosRomconfig.java b/altoslib/AltosRomconfig.java index 1fbb4115..44a3fa60 100644 --- a/altoslib/AltosRomconfig.java +++ b/altoslib/AltosRomconfig.java @@ -35,12 +35,12 @@ public class AltosRomconfig {  			System.out.printf("no symbol %s\n", name);  			throw new AltosNoSymbol(name);  		} -		if (hexfile.address <= symbol.address && symbol.address + len < hexfile.max_address) { +		if (hexfile.address <= symbol.address && symbol.address + len <= hexfile.max_address) {  			System.out.printf("%s: %x\n", name, symbol.address);  			return symbol.address;  		} -		System.out.printf("invalid symbol addr %x range is %x - %x\n", -				  symbol.address, hexfile.address, hexfile.max_address); +		System.out.printf("invalid symbol addr %x len %d range is %x - %x\n", +				  symbol.address, len, hexfile.address, hexfile.max_address);  		throw new AltosNoSymbol(name);  	} diff --git a/altosui/AltosConfigFCUI.java b/altosui/AltosConfigFCUI.java index 1e875dec..9bd265f0 100644 --- a/altosui/AltosConfigFCUI.java +++ b/altosui/AltosConfigFCUI.java @@ -440,7 +440,7 @@ public class AltosConfigFCUI  		apogee_lockout_value.setEditable(true);  		apogee_lockout_value.addItemListener(this);  		pane.add(apogee_lockout_value, c); -		apogee_lockout_value.setToolTipText("Time after boost while apogee detection is locked out"); +		apogee_lockout_value.setToolTipText("Time after launch while apogee detection is locked out");  		row++;  		/* Frequency */ diff --git a/altosui/AltosConfigPyroUI.java b/altosui/AltosConfigPyroUI.java index cd887c00..62c434ac 100644 --- a/altosui/AltosConfigPyroUI.java +++ b/altosui/AltosConfigPyroUI.java @@ -186,8 +186,17 @@ public class AltosConfigPyroUI  		public void set(AltosPyro pyro) {  			int row = 0; +			if ((pyro.flags & AltosPyro.pyro_deprecate) != 0) { +				JOptionPane.showMessageDialog(owner, +							      String.format("Pyro settings “Ascending” and “Descending” are deprecated.\n" + +									    "Clearing %s configuration.", AltosLib.igniter_name(pyro.channel)), +							      "Deprecated Pyro Settings", +							      JOptionPane.ERROR_MESSAGE); +				pyro.flags = 0; +				owner.set_dirty(); +			}  			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) { -				if ((AltosPyro.pyro_all & flag) != 0) { +				if ((AltosPyro.pyro_all_useful & flag) != 0) {  					items[row].set((pyro.flags & flag) != 0,  						       pyro.get_value(flag));  					row++; @@ -200,7 +209,7 @@ public class AltosConfigPyroUI  			int row = 0;  			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) { -				if ((AltosPyro.pyro_all & flag) != 0) { +				if ((AltosPyro.pyro_all_useful & flag) != 0) {  					if (items[row].enabled()) {  						try {  						p.flags |= flag; @@ -220,7 +229,7 @@ public class AltosConfigPyroUI  		public void units_changed(boolean imperial_units) {  			int row = 0;  			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) { -				if ((AltosPyro.pyro_all & flag) != 0) { +				if ((AltosPyro.pyro_all_useful & flag) != 0) {  					items[row].units_changed(imperial_units);  					row++;  				} @@ -233,7 +242,7 @@ public class AltosConfigPyroUI  			int	nrow = 0;  			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) -				if ((flag & AltosPyro.pyro_all) != 0) +				if ((flag & AltosPyro.pyro_all_useful) != 0)  					nrow++;  			items = new PyroItem[nrow]; @@ -251,7 +260,7 @@ public class AltosConfigPyroUI  			y++;  			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) -				if ((flag & AltosPyro.pyro_all) != 0) { +				if ((flag & AltosPyro.pyro_all_useful) != 0) {  					items[row] = new PyroItem(ui, flag, x, y + row);  					row++;  				} @@ -336,10 +345,12 @@ public class AltosConfigPyroUI  			columns[c].units_changed(imperial_units);  		int r = 0;  		for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) { -			String n = AltosPyro.pyro_to_name(flag); -			if (n != null) { -				labels[r].setText(n); -				r++; +			if ((flag & AltosPyro.pyro_all_useful) != 0) { +				String n = AltosPyro.pyro_to_name(flag); +				if (n != null) { +					labels[r].setText(n); +					r++; +				}  			}  		}  	} @@ -380,7 +391,7 @@ public class AltosConfigPyroUI  		int	nrow = 0;  		for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) -			if ((flag & AltosPyro.pyro_all) != 0) +			if ((flag & AltosPyro.pyro_all_useful) != 0)  				nrow++;  		labels = new JLabel[nrow]; @@ -390,18 +401,20 @@ public class AltosConfigPyroUI  		for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {  			String	n; -			n = AltosPyro.pyro_to_name(flag); -			if (n != null) { -				c = new GridBagConstraints(); -				c.gridx = 0; c.gridy = row; -				c.gridwidth = 1; -				c.fill = GridBagConstraints.NONE; -				c.anchor = GridBagConstraints.LINE_START; -				c.insets = il; -				JLabel label = new JLabel(n); -				pane.add(label, c); -				labels[row-1] = label; -				row++; +			if ((flag & AltosPyro.pyro_all_useful) != 0) { +				n = AltosPyro.pyro_to_name(flag); +				if (n != null) { +					c = new GridBagConstraints(); +					c.gridx = 0; c.gridy = row; +					c.gridwidth = 1; +					c.fill = GridBagConstraints.NONE; +					c.anchor = GridBagConstraints.LINE_START; +					c.insets = il; +					JLabel label = new JLabel(n); +					pane.add(label, c); +					labels[row-1] = label; +					row++; +				}  			}  		} diff --git a/altosuilib/AltosFlashUI.java b/altosuilib/AltosFlashUI.java index c717e47c..802e8eb3 100644 --- a/altosuilib/AltosFlashUI.java +++ b/altosuilib/AltosFlashUI.java @@ -59,10 +59,10 @@ public class AltosFlashUI  		"teleballoon",  		"telebt-v1",  		"teledongle-v0", -		"telefire", +		"telefire-v0",  		"telemetrum-v0",  		"telemetrum-v1", -		"telemini", +		"telemini-v1",  		"telenano",  		"teleshield",  		"teleterra" @@ -72,10 +72,11 @@ public class AltosFlashUI  		"TeleBalloon",  		"TeleBT-v1",  		"TeleDongle-v0", +		"TeleFire-v0",  		"TeleFire",  		"TeleMetrum-v0",  		"TeleMetrum-v1", -		"TeleMini", +		"TeleMini-v1",  		"TeleNano",  		"TeleShield",  		"TeleTerra" diff --git a/ao-bringup/turnon_chaoskey b/ao-bringup/turnon_chaoskey index d710e5ff..9ad80912 100755 --- a/ao-bringup/turnon_chaoskey +++ b/ao-bringup/turnon_chaoskey @@ -1,7 +1,7 @@  #!/bin/sh -if [ -x /usr/bin/dfu-util ]; then -    DFU_UTIL=/usr/bin/dfu-util +if [ -x `which dfu-util` ]; then +    DFU_UTIL=`which dfu-util`  else      echo "Can't find dfu-util! Aborting."      exit 1 @@ -33,7 +33,7 @@ $DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || true  #$USBLOAD --serial=1 $ALTOS_FILE || exit 1 -sleep 1 +sleep 3  ./test-chaoskey diff --git a/ao-bringup/turnon_telegps b/ao-bringup/turnon_telegps index 48af692a..5e4cd616 100755 --- a/ao-bringup/turnon_telegps +++ b/ao-bringup/turnon_telegps @@ -49,9 +49,9 @@ esac  FLASH_FILE=$REPO/loaders/telegps-v2.0-altos-flash-*.bin  ALTOS_FILE=$REPO/telegps-v2.0-*.elf -$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE  +$DFU_UTIL -v -v -R -a 0 -s 0x08000000:leave -D $FLASH_FILE  -sleep 2 +sleep 3  $USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1 diff --git a/ao-bringup/turnon_telelco b/ao-bringup/turnon_telelco new file mode 100755 index 00000000..dafa2131 --- /dev/null +++ b/ao-bringup/turnon_telelco @@ -0,0 +1,76 @@ +#!/bin/sh + +if [ -x /usr/bin/ao-flash-stm ]; then +	FLASH_STM=/usr/bin/ao-flash-stm +else +	echo "Can't find ao-flash-stm!  Aborting." +	exit 1 +fi + +if [ -x /usr/bin/ao-usbload ]; then +	USBLOAD=/usr/bin/ao-usbload +else +	echo "Can't find ao-usbload!  Aborting." +	exit 1 +fi + +VERSION=2.0 +REPO=~/altusmetrumllc/Binaries +PRODUCT=TeleLCO + +echo "$PRODUCT v$VERSION Turn-On and Calibration Program" +echo "Copyright 2018 by Bdale Garbee.  Released under GPL v3" +echo +echo "Expectations:" +echo "\t$PRODUCT v$VERSION powered from USB" +echo "\t\twith ST-Link-V2 cabled to debug header" +echo "\t\twith coax from UHF to frequency counter" +echo + +case $# in +    1) +	SERIAL="$1" +	echo "$PRODUCT-$VERSION serial number: $SERIAL"  +	;; +    0) +	echo -n "$PRODUCT-$VERSION serial number: " +	read SERIAL +	;; +    *) +	echo "Usage: $0 <serial-number>" 1>&2 +	exit 1; +	;; +esac + +echo $FLASH_STM + +$FLASH_STM $REPO/loaders/telelco-v$VERSION*.elf  + +sleep 3 + +$USBLOAD --serial=$SERIAL --force $REPO/telelco-v$VERSION*.elf || exit 1 + +sleep 5 + +dev=`ao-list | awk '/'"$PRODUCT-v$VERSION"'/ { print $3; exit(0); }'` + +case "$dev" in +/dev/tty*) +	echo "$PRODUCT"' found on $dev' +	;; +*) +	echo 'No '"$PRODUCT-v$VERSION"' found' +	exit 1 +	;; +esac + +echo 'E 0' > $dev + +SERIAL=$SERIAL ./cal-freq $dev + +echo 'E 1' > $dev + +echo "$PRODUCT-v$VERSION" serial "$serial" is ready to ship +echo "\007" + +exit $? diff --git a/ao-bringup/turnon_telemega b/ao-bringup/turnon_telemega index 49776788..1fce345a 100755 --- a/ao-bringup/turnon_telemega +++ b/ao-bringup/turnon_telemega @@ -46,7 +46,7 @@ echo $FLASH_STM  $FLASH_STM $REPO/loaders/telemega-v$VERSION*.elf  -sleep 5 +sleep 3  $USBLOAD --serial=$SERIAL --force $REPO/telemega-v$VERSION*.elf || exit 1 diff --git a/ao-bringup/turnon_telemetrum b/ao-bringup/turnon_telemetrum index d40be953..dd30378a 100755 --- a/ao-bringup/turnon_telemetrum +++ b/ao-bringup/turnon_telemetrum @@ -46,7 +46,7 @@ echo $FLASH_STM  $FLASH_STM ~/altusmetrumllc/Binaries/loaders/telemetrum-v$VERSION-*.elf || exit 1 -sleep 2 +sleep 3  $USBLOAD --serial=$SERIAL ~/altusmetrumllc/Binaries/telemetrum-v$VERSION-*.elf || exit 1 diff --git a/ao-bringup/turnon_telemini b/ao-bringup/turnon_telemini index 23031481..678251f4 100755 --- a/ao-bringup/turnon_telemini +++ b/ao-bringup/turnon_telemini @@ -45,9 +45,11 @@ ALTOS_FILE=~/altusmetrumllc/Binaries/telemini-v$VERSION-*.elf  #FLASH_FILE=../src/telemini-v3.0/flash-loader/telemini-v$VERSION-altos-flash-*.bin  #ALTOS_FILE=../src/telemini-v3.0/telemini-v$VERSION-*.elf -$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1 +if lsusb -d 0483:df11 | grep -q STM; then +    $DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1 -sleep 2 +    sleep 2 +fi  $USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1 diff --git a/ao-tools/ao-chaosread/ao-chaosread.1 b/ao-tools/ao-chaosread/ao-chaosread.1 index e6ed2fac..94ca5ce9 100644 --- a/ao-tools/ao-chaosread/ao-chaosread.1 +++ b/ao-tools/ao-chaosread/ao-chaosread.1 @@ -47,6 +47,12 @@ from the noise source.  .TP  \-r | --raw  Read raw data from the noise source. This is the default. +.TP +\-f | --flash +Read the contents of flash memory on the device. This loops through +flash memory, so you can read the contents more than once, but there's +no way to reset the pointer back to the start other than making sure +you read the whole contents.  .SH USAGE  .I ao-chaosread  reads noise data. diff --git a/ao-tools/ao-chaosread/ao-chaosread.c b/ao-tools/ao-chaosread/ao-chaosread.c index 8a814a00..5c0de125 100644 --- a/ao-tools/ao-chaosread/ao-chaosread.c +++ b/ao-tools/ao-chaosread/ao-chaosread.c @@ -174,6 +174,7 @@ chaoskey_close(struct chaoskey *ck)  #define COOKED_ENDPOINT	0x85  #define RAW_ENDPOINT	0x86 +#define FLASH_ENDPOINT	0x87  int  chaoskey_read(struct chaoskey *ck, int endpoint, void *buffer, int len) @@ -208,12 +209,13 @@ static const struct option options[] = {  	{ .name = "bytes", .has_arg = 0, .val = 'b' },  	{ .name = "cooked", .has_arg = 0, .val = 'c' },  	{ .name = "raw", .has_arg = 0, .val = 'r' }, +	{ .name = "flash", .has_arg = 0, .val = 'f' },  	{ 0, 0, 0, 0},  };  static void usage(char *program)  { -	fprintf(stderr, "usage: %s [--serial=<serial>] [--length=<length>[kMG]] [--infinite] [--bytes] [--cooked] [--raw]\n", program); +	fprintf(stderr, "usage: %s [--serial=<serial>] [--length=<length>[kMG]] [--infinite] [--bytes] [--cooked] [--raw] [--flash]\n", program);  	exit(1);  } @@ -233,7 +235,7 @@ main (int argc, char **argv)  	int	bytes = 0;  	int	endpoint = RAW_ENDPOINT; -	while ((c = getopt_long(argc, argv, "s:l:ibcr", options, NULL)) != -1) { +	while ((c = getopt_long(argc, argv, "s:l:ibcrf", options, NULL)) != -1) {  		switch (c) {  		case 's':  			serial = optarg; @@ -262,6 +264,9 @@ main (int argc, char **argv)  		case 'r':  			endpoint = RAW_ENDPOINT;  			break; +		case 'f': +			endpoint = FLASH_ENDPOINT; +			break;  		default:  			usage(argv[0]);  			break; diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c index 6d4fa5bf..41d0ac10 100644 --- a/ao-tools/ao-dumplog/ao-dumplog.c +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -90,6 +90,8 @@ main (int argc, char **argv)  	int		any_valid;  	int		invalid;  	char		serial_line[8192]; +	unsigned	storage_size; +	int		blocks;  	while ((c = getopt_long(argc, argv, "T:D:C:R", options, NULL)) != -1) {  		switch (c) { @@ -140,10 +142,21 @@ main (int argc, char **argv)  		cc_usb_close(cc);  		exit(1);  	} -	printf ("Serial number: %d\n", serial_number); +	cc_usb_printf(cc, "f\n"); +	storage_size = 0; +	for (;;) { +		cc_usb_getline(cc, line, sizeof(line)); +		if (sscanf(line, "Storage size: %u", &storage_size) == 1) +			break; +	} +	printf ("Serial number: %d Storage size: %u\n", serial_number, storage_size); +	if (storage_size) +		blocks = storage_size / 256; +	else +		blocks = 511;  	done = 0;  	column = 0; -	for (block = 0; !done && block < 511; block++) { +	for (block = 0; !done && block < blocks; block++) {  		cc_usb_printf(cc, "e %x\n", block);  		if (column == 64) {  			putchar('\n'); diff --git a/configure.ac b/configure.ac index 82e0f3d0..c5de6a5d 100644 --- a/configure.ac +++ b/configure.ac @@ -18,13 +18,13 @@ dnl  dnl Process this file with autoconf to create configure.  AC_PREREQ(2.57) -AC_INIT([altos], 1.8.5) +AC_INIT([altos], 1.8.6)  ANDROID_VERSION=17  AC_CONFIG_SRCDIR([src/kernel/ao.h])  AM_INIT_AUTOMAKE([foreign dist-bzip2])  AM_MAINTAINER_MODE -RELEASE_DATE=2018-03-17 +RELEASE_DATE=2018-06-17  AC_SUBST(RELEASE_DATE)  VERSION_DASH=`echo $VERSION | sed 's/\./-/g'` diff --git a/doc/Makefile b/doc/Makefile index efa7f9d3..3661a6d6 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,6 +3,7 @@  #  RELNOTES_INC=\ +	release-notes-1.8.6.inc \  	release-notes-1.8.5.inc \  	release-notes-1.8.4.inc \  	release-notes-1.8.3.inc \ diff --git a/doc/RELNOTES b/doc/RELNOTES index c3980882..748d2b5b 100644 --- a/doc/RELNOTES +++ b/doc/RELNOTES @@ -1,5 +1,9 @@  Creating documentation for a new release of AltOS +* Make sure that doc/altusmetrum-docinfo.xml has the right copyright  +  year, and add release to the revision history at the front (release  +  notes will be pulled in by release-notes.inc) +  * Write release notes in release-notes-${version}.inc. Add to    Makefile diff --git a/doc/altusmetrum-docinfo.xml b/doc/altusmetrum-docinfo.xml index 3ea79f8b..7b696b97 100644 --- a/doc/altusmetrum-docinfo.xml +++ b/doc/altusmetrum-docinfo.xml @@ -47,6 +47,20 @@  <revhistory>    <?dbhtml filename="altusmetrum-revhistory.html"?>    <revision> +    <revnumber>1.8.6</revnumber> +    <date>6 Aug 2018</date> +    <revremark> +      Various pyro channel configuration updates. +    </revremark> +  </revision> +  <revision> +    <revnumber>1.8.5</revnumber> +    <date>18 Mar 2018</date> +    <revremark> +      Minor ground station software updates. +    </revremark> +  </revision> +  <revision>      <revnumber>1.8.4</revnumber>      <date>20 Dec 2017</date>      <revremark> diff --git a/doc/config-device.inc b/doc/config-device.inc index 99d5c008..0ca6afff 100644 --- a/doc/config-device.inc +++ b/doc/config-device.inc @@ -23,7 +23,7 @@ ifdef::altusmetrum[]  	==== Apogee Lockout -		Apogee lockout is the number of seconds after boost +		Apogee lockout is the number of seconds after launch  		where the flight computer will not fire the apogee  		charge, even if the rocket appears to be at  		apogee. This is often called 'Mach Delay', as it is @@ -35,6 +35,12 @@ ifdef::altusmetrum[]  		pressure increase, and so this setting should be left  		at the default value of zero to disable it. +		[WARNING] +		Firmware versions older than 1.8.6 have a +		bug which resets the time since launch to zero each +		time a motor starts burning. Update firmware to get +		the correct behavior. +  endif::altusmetrum[]  ifdef::radio[] diff --git a/doc/easymini-release-notes.inc b/doc/easymini-release-notes.inc index 2d289b12..425236ef 100644 --- a/doc/easymini-release-notes.inc +++ b/doc/easymini-release-notes.inc @@ -1,6 +1,10 @@  [appendix]  == Release Notes  	:leveloffset: 2 +	include::release-notes-1.8.6.raw[] + +	<<<< +	:leveloffset: 2  	include::release-notes-1.8.5.raw[]  	<<<< diff --git a/doc/intro.inc b/doc/intro.inc index 6b0cd318..bff009c0 100644 --- a/doc/intro.inc +++ b/doc/intro.inc @@ -7,6 +7,16 @@  	we also hope to empower you to take as active a role in our collective  	future as you wish! +	Our goal is to include in this document all of the information required +	to successfully configure and use Altus Metrum products.  But  +	documentation is a lot like software in that it can contain "bugs", +	and can probably always be improved!  If you have questions that  +	aren't answered in this manual, or just need a little help figuring +	things out, we strongly suggest joining the Altus Metrum user email +	list, which you can do by visiting  +	https://lists.gag.com/mailman/listinfo/altusmetrum.  There's a lot +	of useful information in the mailing list archives! +  	The first device created for our community was TeleMetrum, a dual  	deploy altimeter with fully integrated GPS and radio telemetry  	as standard features, and a “companion interface” that will diff --git a/doc/load-maps.inc b/doc/load-maps.inc index e7717d89..ccab4795 100644 --- a/doc/load-maps.inc +++ b/doc/load-maps.inc @@ -5,7 +5,11 @@  	Before heading out to a new launch site, you can use  	this to load satellite images in case you don't have -	internet connectivity at the site. +	internet connectivity at the site.  Try not to wait +	until the last minute, though, particularly if you're +	heading to a major launch.  If too many people are  +	all trying to download map data at once, Google may +	limit access until the next day.  	There's a drop-down menu of launch sites we know  	about; if your favorites aren't there, please let us diff --git a/doc/pyro-channels.inc b/doc/pyro-channels.inc index 3b918544..ab5baef0 100644 --- a/doc/pyro-channels.inc +++ b/doc/pyro-channels.inc @@ -1,33 +1,28 @@ -Acceleration:: Select a value, and then choose -whether acceleration should be above or below -that value. Acceleration is positive upwards, -so accelerating towards the ground would -produce negative numbers. Acceleration during -descent is noisy and inaccurate, so be careful -when using it during these phases of the -flight. - -Vertical speed:: Select a value, and then -choose whether vertical speed should be above -or below that value. Speed is positive -upwards, so moving towards the ground would -produce negative numbers. Speed during descent -is a bit noisy and so be careful when using it +Vertical Acceleration:: Select a value, and then choose whether +acceleration away from the ground should be above or below that +value. Acceleration is positive upwards, so accelerating towards the +ground would produce negative numbers. Acceleration during descent is +noisy and inaccurate, so be careful when using it during these phases +of the flight. + +Ascent rate:: Select a value, and then choose whether ascent rate +should be above or below that value. Ascent rate is positive upwards, +so moving towards the ground would produce negative numbers. Ascent +rate during descent is a bit noisy and so be careful when using it  during these phases of the flight. -Height:: Select a value, and then choose -whether the height above the launch pad should -be above or below that value. +Height above pad:: Select a value, and then choose whether the height +above the launch pad should be above or below that value. -Orientation:: TeleMega and EasyMega contain a -3-axis gyroscope and accelerometer which is -used to measure the current angle. Note that -this angle is not the change in angle from the -launch pad, but rather absolute relative to -gravity; the 3-axis accelerometer is used to -compute the angle of the rocket on the launch -pad and initialize the system. +Orientation:: TeleMega and EasyMega contain a 3-axis gyroscope and +accelerometer which is used to compute the orientation of the +rocket. A record of orientations over the last 0.64 seconds is kept +and the largest value within this period is compared with the +specified value. Note that the tilt angle is not the change in angle +from the launch pad, but rather absolute relative to gravity—the +3-axis accelerometer is used to compute the angle of the rocket on the +launch pad and initialize the system.    [NOTE]    ==== @@ -47,45 +42,70 @@ pad and initialize the system.    of less than that value.    ==== -Flight Time:: Time since boost was detected. Select a value and choose -whether to activate the pyro channel before or after that amount of -time. +Flight Time:: Time since launch. Select a value and choose whether to +activate the pyro channel before or after that amount of time. -Ascending:: A simple test saying whether the rocket is going up or -not. This is exactly equivalent to testing whether the speed is > 0. +[WARNING] +Firmware versions older than 1.8.6 have a bug which resets the time +since launch to zero each time a motor starts burning. Update firmware +to get the correct behavior. -Descending:: A simple test saying whether the rocket is going down or -not. This is exactly equivalent to testing whether the speed is < 0. +Ascending:: A deprecated configuration value which was the same as +setting Ascent rate > 0. Existing configurations using this will be +cleared and must be reconfigured by the user. + +Descending:: A deprecated configuration value which was the same as +setting Ascent rate < 0. Existing configurations using this will be +cleared and must be reconfigured by the user.  After Motor:: The flight software counts each time the rocket starts  accelerating and then decelerating (presumably due to a motor or  motors burning). Use this value for multi-staged or multi-airstart -launches. +launches. As of version 1.8.6 firmware, this checks to make sure at +least this many motors have burned. Before version 1.8.6, this checked +to make sure that exactly this many motors had burned. -Delay:: This value doesn't perform any checks, instead it inserts a -delay between the time when the other parameters become true and when -the pyro channel is activated. +Delay:: Once the other parameters all become true, a timer is +started for the specified amount of time. While the timer is running, +the other parameters are checked repeatedly and if any of them become +false, then the pyro channel is disabled and will not fire. If the +timer expires and all of the other parameters have remained true for +the entire time, then the pyro channel is fired.  Flight State:: The flight software tracks the flight  through a sequence of states:   * Boost. The motor has lit and the rocket is -   accelerating upwards. +   accelerating upwards. Ascent rate will be greater than zero. +   Vertical acceleration will be greater than zero.   * Fast. The motor has burned out and the     rocket is decelerating, but it is going -   faster than 200m/s. +   faster than 200m/s. Ascent rate will be greater than zero. Vertical +   acceleration will be less than zero.   * Coast. The rocket is still moving upwards -   and decelerating, but the speed is less -   than 200m/s. +   and decelerating, but the Ascent rate is less +   than 200m/s. Ascent rate will greater than zero. Vertical +   acceleration will be less than zero.   * Drogue. The rocket has reached apogee and     is heading back down, but is above the -   configured Main altitude. +   configured Main altitude. Ascent rate will be less than zero during +   this state. Vertical acceleration will be negative until the rocket +   reaches a terminal descent rate, at which point Vertical +   acceleration will be zero. Both Ascent rate and Vertical +   acceleration are very noisy in this state, so be careful when +   trying to use them to control pyro channels.   * Main. The rocket is still descending, and -   is below the Main altitude +   is below the Main altitude. Ascent rate will be less than zero +   during this state. Vertical acceleration may be briefly less than +   zero as the rocket slows from drogue descent to main descent, but +   it will settle down to a zero value once the rocket has reached the +   terminal velocity under the main chute. Ascent rate and Vertical +   acceleration should be much less noisy once the main chute has +   deployed.   * Landed. The rocket is no longer moving. diff --git a/doc/release-notes-1.8.6.inc b/doc/release-notes-1.8.6.inc new file mode 100644 index 00000000..1467977c --- /dev/null +++ b/doc/release-notes-1.8.6.inc @@ -0,0 +1,33 @@ += Release Notes for Version 1.8.6 +:toc!: +:doctype: article + +	Version 1.8.6 + +	== AltOS + +	* Use maximum of 64 previous tilt values in pyro tilt tests +	 +	* Eliminate 100m height requirement for coast detection + +	* Change After Motor pyro check to be >= instead of == + +	* Change Time since Boost to be Time since launch. + +	== AltosUI, TeleGPS + +	* Clarify pyro test phrasing + +	* Remove ascending/descending from pyro config UI + +	* Fix accel calibration in Antenna Down mode + +	* Add mag sensor reporting for TeleMega v3 idle monitoring. + +	* Fix radio parameter saving at 2400 bps telmetry rate. + +	== MicroPeak + +	* Report altimeter-recorded maximum height value + +	 diff --git a/doc/release-notes.inc b/doc/release-notes.inc index b7c7f5a7..693699df 100644 --- a/doc/release-notes.inc +++ b/doc/release-notes.inc @@ -1,6 +1,10 @@  [appendix]  == Release Notes  	:leveloffset: 2 +	include::release-notes-1.8.6.raw[] + +	<<<< +	:leveloffset: 2  	include::release-notes-1.8.5.raw[]  	<<<< diff --git a/doc/telegps-release-notes.inc b/doc/telegps-release-notes.inc index f451c2c8..9c1353f8 100644 --- a/doc/telegps-release-notes.inc +++ b/doc/telegps-release-notes.inc @@ -2,6 +2,10 @@  == Release Notes  	:leveloffset: 2 +	include::release-notes-1.8.6.raw[] + +	<<<< +	:leveloffset: 2  	include::release-notes-1.8.5.raw[]  	<<<< diff --git a/micropeak/MicroData.java b/micropeak/MicroData.java index 70492a07..6a9adf3f 100644 --- a/micropeak/MicroData.java +++ b/micropeak/MicroData.java @@ -345,6 +345,8 @@ public class MicroData {  			flight_series.set_time(cal_data.time());  			flight_series.set_state(AltosLib.ao_flight_landed); +			flight_series.set_min_pressure(min_pressure); +  			flight_series.finish();  			flight_stats = new AltosFlightStats(flight_series); diff --git a/src/Makefile b/src/Makefile index 8420b376..0dafb5ec 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,6 +25,7 @@ SDCCDIRS=\  	telerepeat-v1.0  ARMM3DIRS=\ +	fox1ihu fox1ihu/flash-loader \  	easymega-v1.0 easymega-v1.0/flash-loader \  	telemega-v0.1 telemega-v0.1/flash-loader \  	telemega-v1.0 telemega-v1.0/flash-loader \ @@ -36,13 +37,16 @@ ARMM3DIRS=\  	telegps-v1.0 telegps-v1.0/flash-loader \  	telegps-v2.0 telegps-v2.0/flash-loader \  	telelco-v0.2 telelco-v0.2/flash-loader \ +	telelco-v0.2-cc1200 telelco-v0.2-cc1200/flash-loader \  	telelco-v0.3 telelco-v0.3/flash-loader \ +	telelco-v2.0 telelco-v2.0/flash-loader \  	teledongle-v3.0 teledongle-v3.0/flash-loader \  	teleballoon-v2.0 \  	telebt-v3.0 telebt-v3.0/flash-loader \  	telebt-v4.0 telebt-v4.0/flash-loader \  	telelcotwo-v0.1 telelcotwo-v0.1/flash-loader \  	telefiretwo-v0.1 telefiretwo-v0.1/flash-loader \ +	telefireeight-v1.0 telefireeight-v1.0/flash-loader   ARMM0DIRS=\  	easymini-v1.0 easymini-v1.0/flash-loader \ diff --git a/src/chaoskey-v1.0/Makefile b/src/chaoskey-v1.0/Makefile index dea5b483..c6cf45bd 100644 --- a/src/chaoskey-v1.0/Makefile +++ b/src/chaoskey-v1.0/Makefile @@ -14,6 +14,7 @@ INC = \  	ao_task.h \  	ao_adc_fast.h \  	ao_power.h \ +	ao_flash_readout.h \  	ao_crc.h \  	stm32f0.h @@ -34,6 +35,7 @@ ALTOS_SRC = \  	ao_boot_chain.c \  	ao_usb_stm.c \  	ao_trng_send.c \ +	ao_flash_readout.c \  	ao_task.c \  	ao_power.c \  	ao_gpio.c \ @@ -84,7 +86,7 @@ check: $(METAINFO)  distclean:	clean  clean: -	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx *.bin  	rm -f ao_product.h  	rm -f *.cab diff --git a/src/chaoskey-v1.0/ao_chaoskey.c b/src/chaoskey-v1.0/ao_chaoskey.c index c3acd441..1165e454 100644 --- a/src/chaoskey-v1.0/ao_chaoskey.c +++ b/src/chaoskey-v1.0/ao_chaoskey.c @@ -20,6 +20,7 @@  #include <ao_adc_fast.h>  #include <ao_crc.h>  #include <ao_trng_send.h> +#include <ao_flash_readout.h>  void main(void)  { @@ -30,6 +31,7 @@ void main(void)  	ao_dma_init();  	ao_adc_init();  	ao_crc_init(); +	ao_flash_readout_init();  	ao_usb_init(); diff --git a/src/chaoskey-v1.0/ao_pins.h b/src/chaoskey-v1.0/ao_pins.h index f2c46d8b..22861d9d 100644 --- a/src/chaoskey-v1.0/ao_pins.h +++ b/src/chaoskey-v1.0/ao_pins.h @@ -50,6 +50,7 @@  #define AO_USB_HAS_OUT			0  #define AO_USB_HAS_IN			1  #define AO_USB_HAS_IN2			1 +#define AO_USB_HAS_IN3			1  #define AO_USB_HAS_INT			0  #define AO_USB_SELF_POWER		0  #define AO_USB_DEVICE_ID_SERIAL		1 @@ -58,6 +59,9 @@  #define IS_FLASH_LOADER	0 +#define AO_FLASH_READOUT		1 +#define ao_flash_readout_putchar(c)	ao_usb_putchar3(c) +  /* ADC */  #define AO_ADC_PIN0_PORT	(&stm_gpioa) diff --git a/src/drivers/ao_button.c b/src/drivers/ao_button.c index 07e92c67..f6a9676b 100644 --- a/src/drivers/ao_button.c +++ b/src/drivers/ao_button.c @@ -69,6 +69,39 @@ _ao_button_get(uint8_t b)  #if AO_BUTTON_COUNT > 4  	case 4: return ao_button_value(4);  #endif +#if AO_BUTTON_COUNT > 5 +	case 5: return ao_button_value(5); +#endif +#if AO_BUTTON_COUNT > 6 +	case 6: return ao_button_value(6); +#endif +#if AO_BUTTON_COUNT > 7 +	case 7: return ao_button_value(7); +#endif +#if AO_BUTTON_COUNT > 8 +	case 8: return ao_button_value(8); +#endif +#if AO_BUTTON_COUNT > 9 +	case 9: return ao_button_value(9); +#endif +#if AO_BUTTON_COUNT > 10 +	case 10: return ao_button_value(10); +#endif +#if AO_BUTTON_COUNT > 11 +	case 11: return ao_button_value(11); +#endif +#if AO_BUTTON_COUNT > 12 +	case 12: return ao_button_value(12); +#endif +#if AO_BUTTON_COUNT > 13 +	case 13: return ao_button_value(13); +#endif +#if AO_BUTTON_COUNT > 14 +	case 14: return ao_button_value(14); +#endif +#if AO_BUTTON_COUNT > 15 +	case 15: return ao_button_value(15); +#endif  	}  	return 0;  } @@ -144,4 +177,40 @@ ao_button_init(void)  #if AO_BUTTON_COUNT > 4  	init(4);  #endif +#if AO_BUTTON_COUNT > 5 +	init(5); +#endif +#if AO_BUTTON_COUNT > 6 +	init(6); +#endif +#if AO_BUTTON_COUNT > 7 +	init(7); +#endif +#if AO_BUTTON_COUNT > 8 +	init(8); +#endif +#if AO_BUTTON_COUNT > 9 +	init(9); +#endif +#if AO_BUTTON_COUNT > 10 +	init(10); +#endif +#if AO_BUTTON_COUNT > 11 +	init(11); +#endif +#if AO_BUTTON_COUNT > 12 +	init(12); +#endif +#if AO_BUTTON_COUNT > 13 +	init(13); +#endif +#if AO_BUTTON_COUNT > 14 +	init(14); +#endif +#if AO_BUTTON_COUNT > 15 +	init(15); +#endif +#if AO_BUTTON_COUNT > 16 +	#error too many buttons +#endif  } diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index efe5f996..2f091485 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -1447,7 +1447,9 @@ ao_radio_test_recv(void)  static void  ao_radio_aprs(void)  { +#if PACKET_HAS_SLAVE  	ao_packet_slave_stop(); +#endif  	ao_aprs_send();  }  #endif diff --git a/src/drivers/ao_lco.c b/src/drivers/ao_lco.c index e1806ca3..e892c8c0 100644 --- a/src/drivers/ao_lco.c +++ b/src/drivers/ao_lco.c @@ -23,14 +23,8 @@  #include <ao_quadrature.h>  #include <ao_lco_func.h>  #include <ao_radio_cmac.h> - -#define DEBUG	1 - -#if DEBUG -static uint8_t	ao_lco_debug; -#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) -#else -#define PRINTD(...)  +#if HAS_ADC_SINGLE +#include <ao_adc_single.h>  #endif  #define AO_LCO_PAD_DIGIT	0 @@ -40,32 +34,16 @@ static uint8_t	ao_lco_debug;  #define AO_LCO_DRAG_RACE_START_TIME	AO_SEC_TO_TICKS(5)  #define AO_LCO_DRAG_RACE_STOP_TIME	AO_SEC_TO_TICKS(2) -#define AO_LCO_VALID_LAST	1 -#define AO_LCO_VALID_EVER	2 - -static uint8_t	ao_lco_min_box, ao_lco_max_box; -static uint8_t	ao_lco_selected[AO_PAD_MAX_BOXES]; -static uint8_t	ao_lco_valid[AO_PAD_MAX_BOXES]; -static uint8_t	ao_lco_channels[AO_PAD_MAX_BOXES]; -static uint16_t	ao_lco_tick_offset[AO_PAD_MAX_BOXES]; +#define AO_LCO_BOX_DRAG		0x1000  /* UI values */ -static uint8_t	ao_lco_armed; -static uint8_t	ao_lco_firing;  static uint16_t	ao_lco_fire_tick;  static uint8_t	ao_lco_fire_down; -static uint8_t	ao_lco_drag_race; -static uint8_t	ao_lco_pad; -static int16_t	ao_lco_box; - -#define AO_LCO_BOX_DRAG		0x1000 - -static struct ao_pad_query	ao_pad_query;  static uint8_t	ao_lco_display_mutex; -static void -ao_lco_set_pad(uint8_t pad) +void +ao_lco_show_pad(uint8_t pad)  {  	ao_mutex_get(&ao_lco_display_mutex);  	ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad | (ao_lco_drag_race << 4)); @@ -89,8 +67,8 @@ ao_lco_set_pad(uint8_t pad)  				 (0 << 5) |	\  				 (0 << 6)) -static void -ao_lco_set_box(uint16_t box) +void +ao_lco_show_box(uint16_t box)  {  	ao_mutex_get(&ao_lco_display_mutex);  	if (box == AO_LCO_BOX_DRAG) { @@ -104,7 +82,7 @@ ao_lco_set_box(uint16_t box)  }  static void -ao_lco_set_voltage(uint16_t decivolts) +ao_lco_show_voltage(uint16_t decivolts)  {  	uint8_t	tens, ones, tenths; @@ -118,27 +96,21 @@ ao_lco_set_voltage(uint16_t decivolts)  	ao_mutex_put(&ao_lco_display_mutex);  } -static void -ao_lco_set_display(void) +void +ao_lco_show(void)  { -	if (ao_lco_pad == 0 && ao_lco_box != AO_LCO_BOX_DRAG) { -		ao_lco_set_voltage(ao_pad_query.battery); +	if (ao_lco_pad == AO_LCO_PAD_VOLTAGE && ao_lco_box != AO_LCO_BOX_DRAG) { +		ao_lco_show_voltage(ao_pad_query.battery);  	} else {  		if (ao_lco_box == AO_LCO_BOX_DRAG) -			ao_lco_set_pad(ao_lco_drag_race); +			ao_lco_show_pad(ao_lco_drag_race);  		else -			ao_lco_set_pad(ao_lco_pad); -		ao_lco_set_box(ao_lco_box); +			ao_lco_show_pad(ao_lco_pad); +		ao_lco_show_box(ao_lco_box);  	}  } -#define MASK_SIZE(n)	(((n) + 7) >> 3) -#define MASK_ID(n)	((n) >> 3) -#define MASK_SHIFT(n)	((n) & 7) - -static uint8_t	ao_lco_box_mask[MASK_SIZE(AO_PAD_MAX_BOXES)]; - -static uint8_t +uint8_t  ao_lco_box_present(uint16_t box)  {  	if (box == AO_LCO_BOX_DRAG) @@ -146,117 +118,11 @@ ao_lco_box_present(uint16_t box)  	if (box >= AO_PAD_MAX_BOXES)  		return 0; -	return (ao_lco_box_mask[MASK_ID(box)] >> MASK_SHIFT(box)) & 1; -} - -static uint8_t -ao_lco_pad_present(uint8_t box, uint8_t pad) -{ -	/* voltage measurement is always valid */ -	if (pad == 0) -		return 1; -	if (!ao_lco_channels[box]) -		return 0; -	if (pad > AO_PAD_MAX_CHANNELS) -		return 0; -	return (ao_lco_channels[box] >> (pad - 1)) & 1; -} - -static uint8_t -ao_lco_pad_first(uint8_t box) -{ -	uint8_t	pad; - -	for (pad = 1; pad <= AO_PAD_MAX_CHANNELS; pad++) -		if (ao_lco_pad_present(box, pad)) -			return pad; -	return 0; +	return (ao_lco_box_mask[AO_LCO_MASK_ID(box)] >> AO_LCO_MASK_SHIFT(box)) & 1;  }  static struct ao_task	ao_lco_drag_task;  static uint8_t		ao_lco_drag_active; -static uint8_t		ao_lco_drag_beep_count; -static uint8_t		ao_lco_drag_beep_on; -static uint16_t		ao_lco_drag_beep_time; -static uint16_t		ao_lco_drag_warn_time; - -#define AO_LCO_DRAG_BEEP_TIME	AO_MS_TO_TICKS(50) -#define AO_LCO_DRAG_WARN_TIME	AO_SEC_TO_TICKS(5) - -static void -ao_lco_drag_beep_start(void) -{ -	ao_beep(AO_BEEP_HIGH); -	PRINTD("beep start\n"); -	ao_lco_drag_beep_on = 1; -	ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME; -} - -static void -ao_lco_drag_beep_stop(void) -{ -	ao_beep(0); -	PRINTD("beep stop\n"); -	ao_lco_drag_beep_on = 0; -	if (ao_lco_drag_beep_count) { -		--ao_lco_drag_beep_count; -		if (ao_lco_drag_beep_count) -			ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME; -	} -} - -static void -ao_lco_drag_beep(uint8_t beeps) -{ -	PRINTD("beep %d\n", beeps); -	if (!ao_lco_drag_beep_count) -		ao_lco_drag_beep_start(); -	ao_lco_drag_beep_count += beeps; -} - -static uint16_t -ao_lco_drag_beep_check(uint16_t now, uint16_t delay) -{ -	PRINTD("beep check count %d delta %d\n", -	       ao_lco_drag_beep_count, -	       (int16_t) (now - ao_lco_drag_beep_time)); -	if (ao_lco_drag_beep_count) { -		if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) { -			if (ao_lco_drag_beep_on) -				ao_lco_drag_beep_stop(); -			else -				ao_lco_drag_beep_start(); -		} -	} - -	if (ao_lco_drag_beep_count) { -		if (delay > AO_LCO_DRAG_BEEP_TIME) -			delay = AO_LCO_DRAG_BEEP_TIME; -	} -	return delay; -} - -static void -ao_lco_drag_enable(void) -{ -	PRINTD("Drag enable\n"); -	ao_lco_drag_race = 1; -	memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -	ao_lco_drag_beep(5); -	ao_lco_set_display(); -	ao_lco_fire_down = 0; -} - -static void -ao_lco_drag_disable(void) -{ -	PRINTD("Drag disable\n"); -	ao_lco_drag_race = 0; -	memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -	ao_lco_drag_beep(2); -	ao_lco_set_display(); -	ao_lco_fire_down = 0; -}  static uint16_t  ao_lco_drag_button_check(uint16_t now, uint16_t delay) @@ -269,13 +135,17 @@ ao_lco_drag_button_check(uint16_t now, uint16_t delay)  	 */  	if (ao_lco_fire_down) {  		if (ao_lco_drag_race) { -			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_STOP_TIME) +			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_STOP_TIME) {  				ao_lco_drag_disable(); +				ao_lco_fire_down = 0; +			}  			else  				button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_STOP_TIME - now;  		} else { -			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_START_TIME) +			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_START_TIME) {  				ao_lco_drag_enable(); +				ao_lco_fire_down = 0; +			}  			else  				button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_START_TIME - now;  		} @@ -285,35 +155,20 @@ ao_lco_drag_button_check(uint16_t now, uint16_t delay)  	return delay;  } -static uint16_t -ao_lco_drag_warn_check(uint16_t now, uint16_t delay) -{ -	uint16_t	warn_delay = ~0; - -	if (ao_lco_drag_race) { -		if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) { -			ao_lco_drag_beep(1); -			ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME; -		} -		warn_delay = ao_lco_drag_warn_time - now; -	} -	if (delay > warn_delay) -		delay = warn_delay; -	return delay; -} -  static void  ao_lco_drag_monitor(void)  {  	uint16_t	delay = ~0;  	uint16_t	now; +	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	for (;;) { -		PRINTD("Drag monitor active %d delay %d\n", ao_lco_drag_active, delay); +		PRINTD("Drag monitor count %d active %d delay %d\n", +		       ao_lco_drag_beep_count, ao_lco_drag_active, delay);  		if (delay == (uint16_t) ~0) -			ao_sleep(&ao_lco_drag_active); +			ao_sleep(&ao_lco_drag_beep_count);  		else -			ao_sleep_for(&ao_lco_drag_active, delay); +			ao_sleep_for(&ao_lco_drag_beep_count, delay);  		delay = ~0;  		if (!ao_lco_drag_active) @@ -333,13 +188,33 @@ ao_lco_drag_monitor(void)  }  static void +ao_lco_step_box(int8_t dir) +{ +	int16_t new_box = ao_lco_box; +	do { +		if (new_box == AO_LCO_BOX_DRAG) { +			if (dir < 0) +				new_box = ao_lco_max_box; +			else +				new_box = ao_lco_min_box; +		} else { +			new_box += dir; +			if (new_box > ao_lco_max_box) +				new_box = AO_LCO_BOX_DRAG; +			else if (new_box < ao_lco_min_box) +				new_box = AO_LCO_BOX_DRAG; +		} +		if (new_box == ao_lco_box) +			break; +	} while (!ao_lco_box_present(new_box)); +	ao_lco_set_box(new_box); +} + +static void  ao_lco_input(void)  {  	static struct ao_event	event; -	int8_t		dir, new_pad; -	int16_t		new_box; -	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	for (;;) {  		ao_event_get(&event);  		PRINTD("event type %d unit %d value %d\n", @@ -348,106 +223,38 @@ ao_lco_input(void)  		case AO_EVENT_QUADRATURE:  			switch (event.unit) {  			case AO_QUADRATURE_PAD: -				if (!ao_lco_armed) { -					dir = (int8_t) event.value; -					new_pad = ao_lco_pad; -					do { -						new_pad += dir; -						if (new_pad > AO_PAD_MAX_CHANNELS) -							new_pad = 0; -						if (new_pad < 0) -							new_pad = AO_PAD_MAX_CHANNELS; -						if (new_pad == ao_lco_pad) -							break; -					} while (!ao_lco_pad_present(ao_lco_box, new_pad)); -					if (new_pad != ao_lco_pad) { -						ao_lco_pad = new_pad; -						ao_lco_set_display(); -					} -				} +				if (!ao_lco_armed) +					ao_lco_step_pad((int8_t) event.value);  				break;  			case AO_QUADRATURE_BOX: -				if (!ao_lco_armed) { -					dir = (int8_t) event.value; -					new_box = ao_lco_box; -					do { -						if (new_box == AO_LCO_BOX_DRAG) { -							if (dir < 0) -								new_box = ao_lco_max_box; -							else -								new_box = ao_lco_min_box; -						} else { -							new_box += dir; -							if (new_box > ao_lco_max_box) -								new_box = AO_LCO_BOX_DRAG; -							else if (new_box < ao_lco_min_box) -								new_box = AO_LCO_BOX_DRAG; -						} -						if (new_box == ao_lco_box) -							break; -					} while (!ao_lco_box_present(new_box)); -					if (ao_lco_box != new_box) { -						ao_lco_box = new_box; -						ao_lco_pad = 1; -						if (ao_lco_box != AO_LCO_BOX_DRAG) -							ao_lco_channels[ao_lco_box] = 0; -						ao_lco_set_display(); -					} -				} +				if (!ao_lco_armed) +					ao_lco_step_box((int8_t) event.value);  				break;  			}  			break;  		case AO_EVENT_BUTTON:  			switch (event.unit) {  			case AO_BUTTON_ARM: -				ao_lco_armed = event.value; -				PRINTD("Armed %d\n", ao_lco_armed); -				if (ao_lco_armed) { -					if (ao_lco_drag_race) { -						uint8_t	box; - -						for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { -							if (ao_lco_selected[box]) { -								ao_wakeup(&ao_lco_armed); -								break; -							} -						} -					} else { -						memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -						if (ao_lco_pad != 0 && ao_lco_box != AO_LCO_BOX_DRAG) -							ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1)); -						else -							ao_lco_armed = 0; -					} -				} -				ao_wakeup(&ao_lco_armed); +				ao_lco_set_armed(event.value);  				break;  			case AO_BUTTON_FIRE:  				if (ao_lco_armed) {  					ao_lco_fire_down = 0; -					ao_lco_firing = event.value; -					PRINTD("Firing %d\n", ao_lco_firing); -					ao_wakeup(&ao_lco_armed); +					ao_lco_set_firing(event.value);  				} else {  					if (event.value) {  						if (ao_lco_box == AO_LCO_BOX_DRAG) {  							ao_lco_fire_down = 1;  							ao_lco_fire_tick = ao_time();  							ao_lco_drag_active = 1; +							ao_wakeup(&ao_lco_drag_beep_count); +						} else { +							ao_lco_toggle_drag();  						} -						if (ao_lco_drag_race) { -							if (ao_lco_pad != 0 && ao_lco_box != AO_LCO_BOX_DRAG) { -								ao_lco_selected[ao_lco_box] ^= (1 << (ao_lco_pad - 1)); -								PRINTD("Toggle box %d pad %d (pads now %x) to drag race\n", -								       ao_lco_pad, ao_lco_box, ao_lco_selected[ao_lco_box]); -								ao_lco_drag_beep(ao_lco_pad); -							} -						} -						ao_wakeup(&ao_lco_drag_active);  					} else {  						ao_lco_fire_down = 0;  						if (ao_lco_drag_active) -							ao_wakeup(&ao_lco_drag_active); +							ao_wakeup(&ao_lco_drag_beep_count);  					}  				}  				break; @@ -457,188 +264,36 @@ ao_lco_input(void)  	}  } -static AO_LED_TYPE	continuity_led[AO_LED_CONTINUITY_NUM] = { -#ifdef AO_LED_CONTINUITY_0 -	AO_LED_CONTINUITY_0, -#endif -#ifdef AO_LED_CONTINUITY_1 -	AO_LED_CONTINUITY_1, -#endif -#ifdef AO_LED_CONTINUITY_2 -	AO_LED_CONTINUITY_2, -#endif -#ifdef AO_LED_CONTINUITY_3 -	AO_LED_CONTINUITY_3, -#endif -#ifdef AO_LED_CONTINUITY_4 -	AO_LED_CONTINUITY_4, -#endif -#ifdef AO_LED_CONTINUITY_5 -	AO_LED_CONTINUITY_5, -#endif -#ifdef AO_LED_CONTINUITY_6 -	AO_LED_CONTINUITY_6, -#endif -#ifdef AO_LED_CONTINUITY_7 -	AO_LED_CONTINUITY_7, -#endif -}; - -static uint8_t -ao_lco_get_channels(uint8_t box, struct ao_pad_query *query) -{ -	int8_t			r; - -	r = ao_lco_query(box, query, &ao_lco_tick_offset[box]); -	if (r == AO_RADIO_CMAC_OK) { -		ao_lco_channels[box] = query->channels; -		ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; -	} else -		ao_lco_valid[box] &= ~AO_LCO_VALID_LAST; -	PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d offset %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r, ao_lco_tick_offset[box]); -	ao_wakeup(&ao_pad_query); -	return ao_lco_valid[box]; -} - -static void -ao_lco_update(void) -{ -	if (ao_lco_box != AO_LCO_BOX_DRAG) { -		uint8_t	previous_valid = ao_lco_valid[ao_lco_box]; - -		if (ao_lco_get_channels(ao_lco_box, &ao_pad_query) & AO_LCO_VALID_LAST) { -			if (!(previous_valid & AO_LCO_VALID_EVER)) { -				if (ao_lco_pad != 0) -					ao_lco_pad = ao_lco_pad_first(ao_lco_box); -				ao_lco_set_display(); -			} -			if (ao_lco_pad == 0) -				ao_lco_set_display(); -		} -	} -} - -static void -ao_lco_box_reset_present(void) -{ -	ao_lco_min_box = 0xff; -	ao_lco_max_box = 0x00; -	memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask)); -} - -static void -ao_lco_box_set_present(uint8_t box) -{ -	if (box < ao_lco_min_box) -		ao_lco_min_box = box; -	if (box > ao_lco_max_box) -		ao_lco_max_box = box; -	if (box >= AO_PAD_MAX_BOXES) -		return; -	ao_lco_box_mask[MASK_ID(box)] |= 1 << MASK_SHIFT(box); -} - +/* + * Light up everything for a second at power on to let the user + * visually inspect the system for correct operation + */  static void -ao_lco_search(void) +ao_lco_display_test()  { -	int8_t		r; -	int8_t		try; -	uint8_t		box; -	uint8_t		boxes = 0; - -	ao_lco_box_reset_present(); -	ao_lco_set_pad(0); -	for (box = 0; box < AO_PAD_MAX_BOXES; box++) { -		if ((box % 10) == 0) -			ao_lco_set_box(box); -		for (try = 0; try < 3; try++) { -			ao_lco_tick_offset[box] = 0; -			r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]); -			PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]); -			if (r == AO_RADIO_CMAC_OK) { -				++boxes; -				ao_lco_box_set_present(box); -				ao_lco_set_pad(boxes % 10); -				ao_delay(AO_MS_TO_TICKS(30)); -				break; -			} -		} -	} -	if (ao_lco_min_box <= ao_lco_max_box) -		ao_lco_box = ao_lco_min_box; -	else -		ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0; -	memset(ao_lco_valid, 0, sizeof (ao_lco_valid)); -	memset(ao_lco_channels, 0, sizeof (ao_lco_channels)); -	ao_lco_pad = 1; -	ao_lco_set_display(); +	ao_mutex_get(&ao_lco_display_mutex); +	ao_seven_segment_set(AO_LCO_PAD_DIGIT, 8 | 0x10); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, 8 | 0x10); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, 8 | 0x10); +	ao_mutex_put(&ao_lco_display_mutex); +	ao_led_on(LEDS_AVAILABLE); +	ao_delay(AO_MS_TO_TICKS(1000)); +	ao_led_off(LEDS_AVAILABLE);  } +#if HAS_ADC_SINGLE  static void -ao_lco_igniter_status(void) +ao_lco_batt_voltage(void)  { -	uint8_t		c; -	uint8_t		t = 0; - -	for (;;) { -		ao_sleep(&ao_pad_query); -		PRINTD("RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_box == AO_LCO_BOX_DRAG ? -1 : ao_lco_valid[ao_lco_box]); -		if (ao_lco_box == AO_LCO_BOX_DRAG) { -			ao_led_off(AO_LED_RED|AO_LED_GREEN|AO_LED_AMBER); -			for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) -				ao_led_off(continuity_led[c]); -		} else { -			if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) { -				ao_led_on(AO_LED_RED); -				ao_led_off(AO_LED_GREEN|AO_LED_AMBER); -				continue; -			} -			if (ao_radio_cmac_rssi < -90) { -				ao_led_on(AO_LED_AMBER); -				ao_led_off(AO_LED_RED|AO_LED_GREEN); -			} else { -				ao_led_on(AO_LED_GREEN); -				ao_led_off(AO_LED_RED|AO_LED_AMBER); -			} -			if (ao_pad_query.arm_status) -				ao_led_on(AO_LED_REMOTE_ARM); -			else -				ao_led_off(AO_LED_REMOTE_ARM); - -			for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) { -				uint8_t	status; +	struct ao_adc	packet; +	int16_t		decivolt; -				if (ao_lco_drag_race) { -					if (ao_lco_selected[ao_lco_box] & (1 << c) && t) -						ao_led_on(continuity_led[c]); -					else -						ao_led_off(continuity_led[c]); -				} else { -					if (ao_pad_query.channels & (1 << c)) -						status = ao_pad_query.igniter_status[c]; -					else -						status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; -					if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) -						ao_led_on(continuity_led[c]); -					else -						ao_led_off(continuity_led[c]); -				} -			} -			t = 1-t; -		} -	} -} - -static void -ao_lco_arm_warn(void) -{ -	for (;;) { -		while (!ao_lco_armed) -			ao_sleep(&ao_lco_armed); -		ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); -		ao_delay(AO_MS_TO_TICKS(200)); -	} +	ao_adc_single_get(&packet); +	decivolt = ao_battery_decivolt(packet.v_batt); +	ao_lco_show_voltage(decivolt); +	ao_delay(AO_MS_TO_TICKS(1000));  } +#endif  static struct ao_task ao_lco_input_task;  static struct ao_task ao_lco_monitor_task; @@ -646,43 +301,18 @@ static struct ao_task ao_lco_arm_warn_task;  static struct ao_task ao_lco_igniter_status_task;  static void -ao_lco_monitor(void) +ao_lco_main(void)  { -	uint16_t		delay; -	uint8_t			box; - +	ao_lco_display_test(); +#if HAS_ADC_SINGLE +	ao_lco_batt_voltage(); +#endif  	ao_lco_search();  	ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input");  	ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");  	ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status");  	ao_add_task(&ao_lco_drag_task, ao_lco_drag_monitor, "drag race"); -	for (;;) { -		PRINTD("monitor armed %d firing %d\n", -		       ao_lco_armed, ao_lco_firing); - -		if (ao_lco_armed && ao_lco_firing) { -			ao_lco_ignite(AO_PAD_FIRE); -		} else { -			ao_lco_update(); -			if (ao_lco_armed) { -				for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { -					if (ao_lco_selected[box]) { -						PRINTD("Arming box %d pads %x\n", -						       box, ao_lco_selected[box]); -						if (ao_lco_valid[box] & AO_LCO_VALID_EVER) { -							ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]); -							ao_delay(AO_MS_TO_TICKS(10)); -						} -					} -				} -			} -		} -		if (ao_lco_armed && ao_lco_firing) -			delay = AO_MS_TO_TICKS(100); -		else -			delay = AO_SEC_TO_TICKS(1); -		ao_sleep_for(&ao_lco_armed, delay); -	} +	ao_lco_monitor();  }  #if DEBUG @@ -704,7 +334,7 @@ __code struct ao_cmds ao_lco_cmds[] = {  void  ao_lco_init(void)  { -	ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor"); +	ao_add_task(&ao_lco_monitor_task, ao_lco_main, "lco monitor");  #if DEBUG  	ao_cmd_register(&ao_lco_cmds[0]);  #endif diff --git a/src/drivers/ao_lco.h b/src/drivers/ao_lco.h index 5721eed5..2958fbcc 100644 --- a/src/drivers/ao_lco.h +++ b/src/drivers/ao_lco.h @@ -19,7 +19,126 @@  #ifndef _AO_LCO_H_  #define _AO_LCO_H_ +#include <ao_lco_func.h> + +#ifndef AO_LCO_DRAG +#define AO_LCO_DRAG	1 +#endif + +#define DEBUG	1 + +#if DEBUG +extern uint8_t	ao_lco_debug; +#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) +#else +#define PRINTD(...)  +#endif + +#if AO_LCO_DRAG +extern uint8_t	ao_lco_drag_race;	/* TRUE when drag race mode enabled */ +#endif + +extern uint8_t	ao_lco_pad;		/* Currently selected pad */ +extern int16_t	ao_lco_box;		/* Currently selected box */ + +extern uint8_t	ao_lco_armed;		/* armed mode active */ +extern uint8_t	ao_lco_firing;		/* fire button pressed */ + +extern struct ao_pad_query	ao_pad_query;	/* Last received QUERY from pad */ + +#define AO_LCO_PAD_VOLTAGE	0		/* Pad number to show box voltage */ + +extern uint8_t	ao_lco_min_box, ao_lco_max_box; + +#define AO_LCO_MASK_SIZE(n)	(((n) + 7) >> 3) +#define AO_LCO_MASK_ID(n)	((n) >> 3) +#define AO_LCO_MASK_SHIFT(n)	((n) & 7) + +extern uint8_t	ao_lco_box_mask[AO_LCO_MASK_SIZE(AO_PAD_MAX_BOXES)]; + +/* + * Shared functions + */ + +void +ao_lco_igniter_status(void); + +void +ao_lco_update(void); + +uint8_t +ao_lco_pad_present(uint8_t box, uint8_t pad); + +uint8_t +ao_lco_pad_first(uint8_t box); + +void +ao_lco_set_pad(uint8_t new_pad); + +void +ao_lco_step_pad(int8_t dir); + +void +ao_lco_set_box(uint16_t new_box); + +void +ao_lco_set_armed(uint8_t armed); + +void +ao_lco_set_firing(uint8_t firing); + +void +ao_lco_toggle_drag(void); + +void +ao_lco_search(void); + +void +ao_lco_monitor(void); + +extern uint8_t			ao_lco_drag_beep_count; + +/* enable drag race mode */ +void +ao_lco_drag_enable(void); + +/* disable drag race mode */ +void +ao_lco_drag_disable(void); + +/* Handle drag beeps, return new delay */ +uint16_t +ao_lco_drag_beep_check(uint16_t now, uint16_t delay); + +/* Check if it's time to beep during drag race. Return new delay */ +uint16_t +ao_lco_drag_warn_check(uint16_t now, uint16_t delay); + +/* Request 'beeps' additional drag race beeps */ +void +ao_lco_drag_add_beeps(uint8_t beeps); + +/* task function for beeping while arm is active */ +void +ao_lco_arm_warn(void); + +/* + * Provided by the hw-specific driver code + */ + +void +ao_lco_show_pad(uint8_t pad); + +void +ao_lco_show_box(uint16_t box); + +void +ao_lco_show(void); +  void  ao_lco_init(void); +uint8_t +ao_lco_box_present(uint16_t box); +  #endif /* _AO_LCO_H_ */ diff --git a/src/drivers/ao_lco_bits.c b/src/drivers/ao_lco_bits.c new file mode 100644 index 00000000..6e50e44d --- /dev/null +++ b/src/drivers/ao_lco_bits.c @@ -0,0 +1,501 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lco.h> +#include <ao_radio_cmac.h> + +uint8_t		ao_lco_debug; + +uint8_t		ao_lco_pad; +int16_t		ao_lco_box; + +uint8_t		ao_lco_armed;					/* arm active */ +uint8_t		ao_lco_firing;					/* fire active */ + +uint8_t		ao_lco_min_box, ao_lco_max_box; + +#if AO_LCO_DRAG +uint8_t		ao_lco_drag_race; +#endif + +struct ao_pad_query	ao_pad_query;				/* latest query response */ + +static uint8_t		ao_lco_channels[AO_PAD_MAX_BOXES];	/* pad channels available on each box */ +static uint16_t		ao_lco_tick_offset[AO_PAD_MAX_BOXES];	/* offset from local to remote tick count */ +static uint8_t		ao_lco_selected[AO_PAD_MAX_BOXES];	/* pads selected to fire */ + +#define AO_LCO_VALID_LAST	1 +#define AO_LCO_VALID_EVER	2 + +static uint8_t		ao_lco_valid[AO_PAD_MAX_BOXES];		/* AO_LCO_VALID bits per box */ + +static const AO_LED_TYPE	continuity_led[AO_LED_CONTINUITY_NUM] = { +#ifdef AO_LED_CONTINUITY_0 +	AO_LED_CONTINUITY_0, +#endif +#ifdef AO_LED_CONTINUITY_1 +	AO_LED_CONTINUITY_1, +#endif +#ifdef AO_LED_CONTINUITY_2 +	AO_LED_CONTINUITY_2, +#endif +#ifdef AO_LED_CONTINUITY_3 +	AO_LED_CONTINUITY_3, +#endif +#ifdef AO_LED_CONTINUITY_4 +	AO_LED_CONTINUITY_4, +#endif +#ifdef AO_LED_CONTINUITY_5 +	AO_LED_CONTINUITY_5, +#endif +#ifdef AO_LED_CONTINUITY_6 +	AO_LED_CONTINUITY_6, +#endif +#ifdef AO_LED_CONTINUITY_7 +	AO_LED_CONTINUITY_7, +#endif +}; + +/* Set LEDs to match remote box status */ +void +ao_lco_igniter_status(void) +{ +	uint8_t		c; +	uint8_t		t = 0; + +	for (;;) { +#if AO_LCO_DRAG +		if (ao_lco_drag_race) +			ao_sleep_for(&ao_pad_query, AO_MS_TO_TICKS(50)); +		else +#endif +			ao_sleep(&ao_pad_query); +		PRINTD("RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_valid[ao_lco_box]); +		if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) { +			ao_led_on(AO_LED_RED); +			ao_led_off(AO_LED_GREEN|AO_LED_AMBER); +			continue; +		} +		if (ao_radio_cmac_rssi < -90) { +			ao_led_on(AO_LED_AMBER); +			ao_led_off(AO_LED_RED|AO_LED_GREEN); +		} else { +			ao_led_on(AO_LED_GREEN); +			ao_led_off(AO_LED_RED|AO_LED_AMBER); +		} +		if (ao_pad_query.arm_status) +			ao_led_on(AO_LED_REMOTE_ARM); +		else +			ao_led_off(AO_LED_REMOTE_ARM); + +		for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) { +			uint8_t	status; + +			if (ao_pad_query.channels & (1 << c)) +				status = ao_pad_query.igniter_status[c]; +			else +				status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; + +#if AO_LCO_DRAG +			if (ao_lco_drag_race && (ao_lco_selected[ao_lco_box] & (1 << c))) { +				uint8_t	on = 0; +				if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) { +					if (t) +						on = 1; +				} else { +					if (t == 1) +						on = 1; +				} +				if (on) +					ao_led_on(continuity_led[c]); +				else +					ao_led_off(continuity_led[c]); +			} else +#endif +			{ +				if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) +					ao_led_on(continuity_led[c]); +				else +					ao_led_off(continuity_led[c]); +			} +		} +		t = (t + 1) & 3; +	} +} + +uint8_t +ao_lco_pad_present(uint8_t box, uint8_t pad) +{ +	/* voltage measurement is always valid */ +	if (pad == AO_LCO_PAD_VOLTAGE) +		return 1; +	if (!ao_lco_channels[box]) +		return 0; +	if (pad > AO_PAD_MAX_CHANNELS) +		return 0; +	return (ao_lco_channels[box] >> (pad - 1)) & 1; +} + +uint8_t +ao_lco_pad_first(uint8_t box) +{ +	uint8_t	pad; + +	for (pad = 1; pad <= AO_PAD_MAX_CHANNELS; pad++) +		if (ao_lco_pad_present(box, pad)) +			return pad; +	return 0; +} + +static uint8_t +ao_lco_get_channels(uint8_t box, struct ao_pad_query *query) +{ +	int8_t			r; + +	r = ao_lco_query(box, query, &ao_lco_tick_offset[box]); +	if (r == AO_RADIO_CMAC_OK) { +		ao_lco_channels[box] = query->channels; +		ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; +	} else +		ao_lco_valid[box] &= ~AO_LCO_VALID_LAST; +	PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d offset %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r, ao_lco_tick_offset[box]); +	ao_wakeup(&ao_pad_query); +	return ao_lco_valid[box]; +} + +void +ao_lco_update(void) +{ +	uint8_t	previous_valid = ao_lco_valid[ao_lco_box]; + +	if (ao_lco_get_channels(ao_lco_box, &ao_pad_query) & AO_LCO_VALID_LAST) { +		if (!(previous_valid & AO_LCO_VALID_EVER)) { +			if (ao_lco_pad != AO_LCO_PAD_VOLTAGE) +				ao_lco_set_pad(ao_lco_pad_first(ao_lco_box)); +		} +		if (ao_lco_pad == AO_LCO_PAD_VOLTAGE) +			ao_lco_show(); +	} +} + +uint8_t	ao_lco_box_mask[AO_LCO_MASK_SIZE(AO_PAD_MAX_BOXES)]; + +static void +ao_lco_box_reset_present(void) +{ +	ao_lco_min_box = 0xff; +	ao_lco_max_box = 0x00; +	memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask)); +} + +static void +ao_lco_box_set_present(uint8_t box) +{ +	if (box < ao_lco_min_box) +		ao_lco_min_box = box; +	if (box > ao_lco_max_box) +		ao_lco_max_box = box; +	if (box >= AO_PAD_MAX_BOXES) +		return; +	ao_lco_box_mask[AO_LCO_MASK_ID(box)] |= 1 << AO_LCO_MASK_SHIFT(box); +} + +void +ao_lco_set_pad(uint8_t new_pad) +{ +	ao_lco_pad = new_pad; +	ao_lco_show(); +} + +void +ao_lco_set_box(uint16_t new_box) +{ +	ao_lco_box = new_box; +	if (ao_lco_box < AO_PAD_MAX_BOXES) +		ao_lco_channels[ao_lco_box] = 0; +	ao_lco_pad = 1; +	ao_lco_show(); +} + +void +ao_lco_step_pad(int8_t dir) +{ +	int8_t	new_pad; + +	new_pad = ao_lco_pad; +	do { +		new_pad += dir; +		if (new_pad > AO_PAD_MAX_CHANNELS) +			new_pad = AO_LCO_PAD_VOLTAGE; +		if (new_pad < 0) +			new_pad = AO_PAD_MAX_CHANNELS; +		if (new_pad == ao_lco_pad) +			break; +	} while (!ao_lco_pad_present(ao_lco_box, new_pad)); +	ao_lco_set_pad(new_pad); +} + +void +ao_lco_set_armed(uint8_t armed) +{ +	ao_lco_armed = armed; +	PRINTD("Armed %d\n", ao_lco_armed); +	if (ao_lco_armed) { +#if AO_LCO_DRAG +		if (ao_lco_drag_race) { +			uint8_t	box; + +			for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) +				if (ao_lco_selected[box]) +					break; +			if (box > ao_lco_max_box) +				ao_lco_armed = 0; +		} else +#endif +		{ +			memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); +			if (ao_lco_pad != 0) +				ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1)); +			else +				ao_lco_armed = 0; +		} +	} +	ao_wakeup(&ao_lco_armed); +} + +void +ao_lco_set_firing(uint8_t firing) +{ +	ao_lco_firing = firing; +	PRINTD("Firing %d\n", ao_lco_firing); +	ao_wakeup(&ao_lco_armed); +} + +void +ao_lco_search(void) +{ +	int8_t		r; +	int8_t		try; +	uint8_t		box; +	uint8_t		boxes = 0; + +	ao_lco_box_reset_present(); +	ao_lco_show_box(0); +	ao_lco_show_pad(0); +	for (box = 0; box < AO_PAD_MAX_BOXES; box++) { +		if ((box % 10) == 0) +			ao_lco_show_box(box); +		for (try = 0; try < 3; try++) { +			ao_lco_tick_offset[box] = 0; +			r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]); +			PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]); +			if (r == AO_RADIO_CMAC_OK) { +				++boxes; +				ao_lco_box_set_present(box); +				ao_lco_show_pad(boxes % 10); +				ao_delay(AO_MS_TO_TICKS(30)); +				break; +			} +		} +	} +	if (ao_lco_min_box <= ao_lco_max_box) +		ao_lco_box = ao_lco_min_box; +	else +		ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0; +	memset(ao_lco_valid, 0, sizeof (ao_lco_valid)); +	memset(ao_lco_channels, 0, sizeof (ao_lco_channels)); +	ao_lco_set_box(ao_lco_min_box); +} + +void +ao_lco_monitor(void) +{ +	uint16_t		delay; +	uint8_t			box; + +	for (;;) { +		PRINTD("monitor armed %d firing %d\n", +		       ao_lco_armed, ao_lco_firing); + +		if (ao_lco_armed && ao_lco_firing) { +			ao_lco_ignite(AO_PAD_FIRE); +		} else { +			ao_lco_update(); +			if (ao_lco_armed) { +				for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { +					if (ao_lco_selected[box]) { +						PRINTD("Arming box %d pads %x\n", +						       box, ao_lco_selected[box]); +						if (ao_lco_valid[box] & AO_LCO_VALID_EVER) { +							ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]); +							ao_delay(AO_MS_TO_TICKS(10)); +						} +					} +				} +			} +		} +		if (ao_lco_armed && ao_lco_firing) +			delay = AO_MS_TO_TICKS(100); +		else +			delay = AO_SEC_TO_TICKS(1); +		ao_sleep_for(&ao_lco_armed, delay); +	} +} + +#if AO_LCO_DRAG + +uint8_t			ao_lco_drag_beep_count; +static uint8_t		ao_lco_drag_beep_on; +static uint16_t		ao_lco_drag_beep_time; +static uint16_t		ao_lco_drag_warn_time; + +#define AO_LCO_DRAG_BEEP_TIME	AO_MS_TO_TICKS(50) +#define AO_LCO_DRAG_WARN_TIME	AO_SEC_TO_TICKS(5) + +/* Request 'beeps' additional drag race beeps */ +void +ao_lco_drag_add_beeps(uint8_t beeps) +{ +	PRINTD("beep %d\n", beeps); +	if (ao_lco_drag_beep_count == 0) +		ao_lco_drag_beep_time = ao_time(); +	ao_lco_drag_beep_count += beeps; +	ao_wakeup(&ao_lco_drag_beep_count); +} + +/* Toggle current pad in drag set */ +void +ao_lco_toggle_drag(void) +{ +	if (ao_lco_drag_race && ao_lco_pad != AO_LCO_PAD_VOLTAGE) { +		ao_lco_selected[ao_lco_box] ^= (1 << (ao_lco_pad - 1)); +		PRINTD("Toggle box %d pad %d (pads now %x) to drag race\n", +		       ao_lco_pad, ao_lco_box, ao_lco_selected[ao_lco_box]); +		ao_lco_drag_add_beeps(ao_lco_pad); +	} +} + +/* Check whether it's time to change the beeper status, then either + * turn it on or off as necessary and bump the remaining beep counts + */ + +uint16_t +ao_lco_drag_beep_check(uint16_t now, uint16_t delay) +{ +	PRINTD("beep check count %d delta %d\n", +	       ao_lco_drag_beep_count, +	       (int16_t) (now - ao_lco_drag_beep_time)); +	if (ao_lco_drag_beep_count) { +		if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) { +			if (ao_lco_drag_beep_on) { +				ao_beep(0); +				PRINTD("beep stop\n"); +				ao_lco_drag_beep_on = 0; +				if (ao_lco_drag_beep_count) { +					--ao_lco_drag_beep_count; +					if (ao_lco_drag_beep_count) +						ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME; +				} +			} else { +				ao_beep(AO_BEEP_HIGH); +				PRINTD("beep start\n"); +				ao_lco_drag_beep_on = 1; +				ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME; +			} +		} +	} + +	if (ao_lco_drag_beep_count) { +		uint16_t beep_delay = 0; + +		if (ao_lco_drag_beep_time > now) +			beep_delay = ao_lco_drag_beep_time - now; + +		if (delay > beep_delay) +			delay = beep_delay; +	} +	return delay; +} + +void +ao_lco_drag_enable(void) +{ +	if (!ao_lco_drag_race) { +		PRINTD("Drag enable\n"); +		ao_lco_drag_race = 1; +		memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); +#ifdef AO_LED_DRAG +		ao_led_on(AO_LED_DRAG); +#endif +		ao_lco_drag_add_beeps(5); +		ao_lco_show(); +	} +} + +void +ao_lco_drag_disable(void) +{ +	if (ao_lco_drag_race) { +		PRINTD("Drag disable\n"); +		ao_lco_drag_race = 0; +#ifdef AO_LED_DRAG +		ao_led_off(AO_LED_DRAG); +#endif +		memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); +		ao_lco_drag_add_beeps(2); +		ao_lco_show(); +	} +} + +/* add a beep if it's time to warn the user that drag race mode is + * active + */ + +uint16_t +ao_lco_drag_warn_check(uint16_t now, uint16_t delay) +{ +	if (ao_lco_drag_race) { +		uint16_t	warn_delay; + +		if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) { +			ao_lco_drag_add_beeps(1); +			ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME; +		} +		warn_delay = ao_lco_drag_warn_time - now; +		if (delay > warn_delay) +			delay = warn_delay; +	} +	return delay; +} +#endif /* AO_LCO_DRAG */ + +/* task function for beeping while arm is active */ +void +ao_lco_arm_warn(void) +{ +	for (;;) { +		while (!ao_lco_armed) { +#ifdef AO_LED_FIRE +			ao_led_off(AO_LED_FIRE); +#endif +			ao_sleep(&ao_lco_armed); +		} +#ifdef AO_LED_FIRE +		ao_led_on(AO_LED_FIRE); +#endif +		ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +		ao_delay(AO_MS_TO_TICKS(200)); +	} +} diff --git a/src/drivers/ao_lco_cmd.c b/src/drivers/ao_lco_cmd.c index 8de21fb6..dba9a76a 100644 --- a/src/drivers/ao_lco_cmd.c +++ b/src/drivers/ao_lco_cmd.c @@ -22,6 +22,10 @@  #include <ao_lco_func.h>  #include <ao_radio_cmac.h> +#ifndef HAS_STATIC_TEST +#define HAS_STATIC_TEST	1 +#endif +  static __pdata uint16_t	lco_box;  static __pdata uint8_t	lco_channels;  static __pdata uint16_t	tick_offset; @@ -150,6 +154,7 @@ lco_fire_cmd(void) __reentrant  	}  } +#if HAS_STATIC_TEST  static void  lco_static_cmd(void) __reentrant  { @@ -182,6 +187,7 @@ lco_static_cmd(void) __reentrant  		ao_delay(AO_MS_TO_TICKS(100));  	}  } +#endif  static void  lco_arm_cmd(void) __reentrant @@ -208,18 +214,21 @@ lco_ignite_cmd(void) __reentrant  } +#if HAS_STATIC_TEST  static void  lco_endstatic_cmd(void) __reentrant  {  	lco_ignite(AO_PAD_ENDSTATIC);  } +#endif  static __code struct ao_cmds ao_lco_cmds[] = {  	{ lco_report_cmd,	"l <box> <channel>\0Get remote status" },  	{ lco_fire_cmd,		"F <box> <channel> <secs>\0Fire remote igniters" }, -	{ lco_fire_cmd,		"F <box> <channel> <secs>\0Fire remote igniters" }, +#if HAS_STATIC_TEST  	{ lco_static_cmd,	"S <box> <channel> <secs>\0Initiate static test" },  	{ lco_endstatic_cmd,	"D\0End static test (and download someday)" }, +#endif  	{ lco_arm_cmd,		"a <box> <channel>\0Arm remote igniter" },  	{ lco_ignite_cmd,	"i <box> <channel>\0Pulse remote igniter" },  	{ 0, NULL }, diff --git a/src/drivers/ao_lco_two.c b/src/drivers/ao_lco_two.c index e2f86745..6f2d81ff 100644 --- a/src/drivers/ao_lco_two.c +++ b/src/drivers/ao_lco_two.c @@ -23,64 +23,13 @@  #include <ao_lco_func.h>  #include <ao_radio_cmac.h> -#define DEBUG	1 - -#if DEBUG -static uint8_t	ao_lco_debug; -#define DEBUG_EVENT	1 -#define DEBUG_STATUS	2 -#define PRINTD(l, ...) do { if (!(ao_lco_debug & l)) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) -#else -#define PRINTD(l,...) -#endif - -#define AO_LCO_VALID_LAST	1 -#define AO_LCO_VALID_EVER	2 -  static uint8_t	ao_lco_suspended; -static uint8_t	ao_lco_valid; -static uint8_t	ao_lco_channels; -static uint16_t	ao_lco_tick_offset; - -/* UI values */ -static uint8_t	ao_lco_armed; -static uint8_t	ao_lco_firing; -static uint8_t	ao_lco_box; - -static struct ao_pad_query	ao_pad_query; - -/* TeleFireTwo boxes have a single pad */ -#define ao_lco_pad	0 - -static void -ao_lco_set_box(int box) -{ -	ao_lco_box = ao_config.pad_box + box; -	ao_lco_valid = 0; -	ao_lco_armed = 0; -	ao_wakeup(&ao_lco_armed); -} - -static void -ao_lco_set_armed(int armed) -{ -	uint8_t	bit = (1 << ao_lco_pad); - -	if (armed) { -		ao_lco_armed = bit; -	} else { -		ao_lco_armed = 0; -	} -	PRINTD(DEBUG_EVENT, "pad %d bit 0x%x armed %d ao_lco_armed 0x%x\n", -	       ao_lco_pad, bit, armed, ao_lco_armed); -	ao_wakeup(&ao_lco_armed); -}  static void  ao_lco_suspend(void)  {  	if (!ao_lco_suspended) { -		PRINTD(DEBUG_EVENT, "suspend\n"); +		PRINTD("suspend\n");  		ao_lco_suspended = 1;  		ao_lco_armed = 0;  		ao_wakeup(&ao_pad_query); @@ -96,6 +45,23 @@ ao_lco_wakeup(void)  	}  } +void +ao_lco_show_pad(uint8_t pad) +{ +	(void) pad; +} + +void +ao_lco_show_box(uint16_t box) +{ +	(void) box; +} + +void +ao_lco_show(void) +{ +} +  static void  ao_lco_input(void)  { @@ -113,23 +79,21 @@ ao_lco_input(void)  			ao_event_get(&event);  		}  		ao_lco_wakeup(); -		PRINTD(DEBUG_EVENT, "event type %d unit %d value %d\n", +		PRINTD("event type %d unit %d value %d\n",  		       event.type, event.unit, event.value);  		switch (event.type) {  		case AO_EVENT_BUTTON:  			switch (event.unit) {  			case AO_BUTTON_BOX:  				ao_lco_set_box(event.value); +				ao_lco_set_armed(0);  				break;  			case AO_BUTTON_ARM:  				ao_lco_set_armed(event.value);  				break;  			case AO_BUTTON_FIRE: -				if (ao_lco_armed) { -					ao_lco_firing = event.value; -					PRINTD(DEBUG_EVENT, "Firing %d\n", ao_lco_firing); -					ao_wakeup(&ao_lco_armed); -				} +				if (ao_lco_armed) +					ao_lco_set_firing(event.value);  				break;  			}  			break; @@ -137,140 +101,14 @@ ao_lco_input(void)  	}  } -static AO_LED_TYPE	continuity_led[AO_LED_CONTINUITY_NUM] = { -#ifdef AO_LED_CONTINUITY_0 -	AO_LED_CONTINUITY_0, -#endif -#ifdef AO_LED_CONTINUITY_1 -	AO_LED_CONTINUITY_1, -#endif -#ifdef AO_LED_CONTINUITY_2 -	AO_LED_CONTINUITY_2, -#endif -#ifdef AO_LED_CONTINUITY_3 -	AO_LED_CONTINUITY_3, -#endif -#ifdef AO_LED_CONTINUITY_4 -	AO_LED_CONTINUITY_4, -#endif -#ifdef AO_LED_CONTINUITY_5 -	AO_LED_CONTINUITY_5, -#endif -#ifdef AO_LED_CONTINUITY_6 -	AO_LED_CONTINUITY_6, -#endif -#ifdef AO_LED_CONTINUITY_7 -	AO_LED_CONTINUITY_7, -#endif -}; - -static uint8_t -ao_lco_get_channels(void) -{ -	int8_t			r; - -	r = ao_lco_query(ao_lco_box, &ao_pad_query, &ao_lco_tick_offset); -	if (r == AO_RADIO_CMAC_OK) { -		ao_lco_channels = ao_pad_query.channels; -		ao_lco_valid = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; -	} else -		ao_lco_valid &= ~AO_LCO_VALID_LAST; -	PRINTD(DEBUG_STATUS, "ao_lco_get_channels() rssi %d valid %d ret %d offset %d\n", ao_radio_cmac_rssi, ao_lco_valid, r, ao_lco_tick_offset); -	ao_wakeup(&ao_pad_query); -	return ao_lco_valid; -} - -static void -ao_lco_igniter_status(void) -{ -	uint8_t		c; -	uint8_t		t = 0; - -	for (;;) { -		uint8_t	all_status; -		ao_sleep(&ao_pad_query); -		while (ao_lco_suspended) { -			ao_led_off(AO_LED_GREEN|AO_LED_AMBER|AO_LED_RED|AO_LED_REMOTE_ARM); -			for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) -				ao_led_off(continuity_led[c]); -			ao_sleep(&ao_lco_suspended); -		} -		PRINTD(DEBUG_STATUS, "RSSI %d VALID %d channels %d arm_status %d\n", -		       ao_radio_cmac_rssi, ao_lco_valid, -		       ao_lco_channels, ao_pad_query.arm_status); -		if (!(ao_lco_valid & AO_LCO_VALID_LAST)) { -			ao_led_on(AO_LED_RED); -			ao_led_off(AO_LED_GREEN|AO_LED_AMBER); -			memset(&ao_pad_query, '\0', sizeof (ao_pad_query)); -		} else if (ao_radio_cmac_rssi < -90) { -			ao_led_on(AO_LED_AMBER); -			ao_led_off(AO_LED_RED|AO_LED_GREEN); -		} else { -			ao_led_on(AO_LED_GREEN); -			ao_led_off(AO_LED_RED|AO_LED_AMBER); -		} -		if (ao_pad_query.arm_status) -			ao_led_on(AO_LED_REMOTE_ARM); -		else -			ao_led_off(AO_LED_REMOTE_ARM); - -		all_status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; -		for (c = 0; c < 8; c++) { -			if (ao_pad_query.channels & (1 << c)) { -				uint8_t status = ao_pad_query.igniter_status[c]; -				if (status > all_status) -					all_status = status; -				PRINTD(DEBUG_STATUS, "\tchannel %d status %d\n", c, status); -			} -		} -		for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) { -			uint8_t	on = 0; -			if (c == (ao_lco_box - ao_config.pad_box) % AO_LED_CONTINUITY_NUM) { -				switch (all_status) { -				case AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN: -					on = 1; -					break; -				case AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_CLOSED: -				case AO_PAD_IGNITER_STATUS_UNKNOWN: -					on = t & 1; -				} -			} -			if (on) -				ao_led_on(continuity_led[c]); -			else -				ao_led_off(continuity_led[c]); -		} -		t = 1-t; -	} -} - -static void -ao_lco_arm_warn(void) -{ -	int	i; -	for (;;) { -		while (ao_lco_suspended) -			ao_sleep(&ao_lco_suspended); -		while (!ao_lco_armed) -			ao_sleep(&ao_lco_armed); -		for (i = 0; i < ao_lco_armed; i++) { -			ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(100)); -			ao_delay(AO_MS_TO_TICKS(100)); -		} -		ao_delay(AO_MS_TO_TICKS(300)); -	} -} -  static struct ao_task ao_lco_input_task;  static struct ao_task ao_lco_monitor_task;  static struct ao_task ao_lco_arm_warn_task;  static struct ao_task ao_lco_igniter_status_task;  static void -ao_lco_monitor(void) +ao_lco_main(void)  { -	uint16_t		delay; -  	ao_config_get();  	ao_lco_set_box(ao_button_get(AO_BUTTON_BOX));  	ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input"); @@ -279,33 +117,7 @@ ao_lco_monitor(void)  	ao_led_on(~0);  	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	ao_led_off(~0); -	for (;;) { -		while (ao_lco_suspended) -			ao_sleep(&ao_lco_suspended); - -		PRINTD(DEBUG_STATUS, "monitor armed %d firing %d\n", -		       ao_lco_armed, ao_lco_firing); - -		if (ao_lco_armed && ao_lco_firing) { -			ao_lco_ignite(AO_PAD_FIRE); -		} else { -			ao_lco_get_channels(); -			if (ao_lco_armed) { -				PRINTD(DEBUG_STATUS, "Arming pads %x\n", -				       ao_lco_armed); -				if (ao_lco_valid & AO_LCO_VALID_EVER) { -					ao_lco_arm(ao_lco_box, ao_lco_armed, ao_lco_tick_offset); -					ao_delay(AO_MS_TO_TICKS(10)); -				} -			} -		} -		if (ao_lco_armed && ao_lco_firing) -			delay = AO_MS_TO_TICKS(100); -		else { -			delay = AO_SEC_TO_TICKS(1); -		} -		ao_sleep_for(&ao_lco_armed, delay); -	} +	ao_lco_monitor();  }  #if DEBUG @@ -326,7 +138,7 @@ __code struct ao_cmds ao_lco_cmds[] = {  void  ao_lco_init(void)  { -	ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor"); +	ao_add_task(&ao_lco_monitor_task, ao_lco_main, "lco monitor");  #if DEBUG  	ao_cmd_register(&ao_lco_cmds[0]);  #endif diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index 16b4ae60..c6efc311 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -17,6 +17,7 @@   */  #include <ao.h> +#include <ao_exti.h>  #include <ao_pad.h>  #include <ao_74hc165.h>  #include <ao_radio_cmac.h> @@ -69,10 +70,20 @@ ao_strobe(uint8_t v)  #endif  } +#ifdef AO_PAD_PORT_0 +#define pins_pad(pad)	(*((AO_PAD_ ## pad ## _PORT) == AO_PAD_PORT_0 ? (&pins0) : (&pins1))) +#else +#define pins_pad(pad)	pins0 +#define AO_PAD_PORT_0 AO_PAD_PORT +#endif +  static void  ao_pad_run(void)  { -	AO_PORT_TYPE	pins; +	AO_PORT_TYPE	pins0; +#ifdef AO_PAD_PORT_1 +	AO_PORT_TYPE	pins1; +#endif  	for (;;) {  		while (!ao_pad_ignite) @@ -80,58 +91,116 @@ ao_pad_run(void)  		/*  		 * Actually set the pad bits  		 */ -		pins = 0; +		pins0 = 0; +#ifdef AO_PAD_PORT_1 +		pins1 = 0; +#endif  #if AO_PAD_NUM > 0  		if (ao_pad_ignite & (1 << 0)) -			pins |= (1 << AO_PAD_PIN_0); +			pins_pad(0) |= (1 << AO_PAD_PIN_0);  #endif  #if AO_PAD_NUM > 1  		if (ao_pad_ignite & (1 << 1)) -			pins |= (1 << AO_PAD_PIN_1); +			pins_pad(1) |= (1 << AO_PAD_PIN_1);  #endif  #if AO_PAD_NUM > 2  		if (ao_pad_ignite & (1 << 2)) -			pins |= (1 << AO_PAD_PIN_2); +			pins_pad(2) |= (1 << AO_PAD_PIN_2);  #endif  #if AO_PAD_NUM > 3  		if (ao_pad_ignite & (1 << 3)) -			pins |= (1 << AO_PAD_PIN_3); +			pins_pad(3) |= (1 << AO_PAD_PIN_3); +#endif +#if AO_PAD_NUM > 4 +		if (ao_pad_ignite & (1 << 4)) +			pins_pad(4) |= (1 << AO_PAD_PIN_4); +#endif +#if AO_PAD_NUM > 5 +		if (ao_pad_ignite & (1 << 5)) +			pins_pad(5) |= (1 << AO_PAD_PIN_5); +#endif +#if AO_PAD_NUM > 6 +		if (ao_pad_ignite & (1 << 6)) +			pins_pad(6) |= (1 << AO_PAD_PIN_6); +#endif +#if AO_PAD_NUM > 7 +		if (ao_pad_ignite & (1 << 7)) +			pins_pad(7) |= (1 << AO_PAD_PIN_7); +#endif +#ifdef AO_PAD_PORT_1 +		PRINTD("ignite pins 0x%x 0x%x\n", pins0, pins1); +		ao_gpio_set_bits(AO_PAD_PORT_0, pins0); +		ao_gpio_set_bits(AO_PAD_PORT_1, pins1); +#else +		PRINTD("ignite pins 0x%x\n", pins0); +		ao_gpio_set_bits(AO_PAD_PORT_0, pins0);  #endif -		PRINTD("ignite pins 0x%x\n", pins); -		ao_gpio_set_bits(AO_PAD_PORT, pins);  		while (ao_pad_ignite) {  			ao_pad_ignite = 0;  			ao_delay(AO_PAD_FIRE_TIME);  		} -		ao_gpio_clr_bits(AO_PAD_PORT, pins); -		PRINTD("turn off pins 0x%x\n", pins); +#ifdef AO_PAD_PORT_1 +		ao_gpio_clr_bits(AO_PAD_PORT_0, pins0); +		ao_gpio_clr_bits(AO_PAD_PORT_1, pins1); +		PRINTD("turn off pins 0x%x 0x%x\n", pins0, pins1); +#else +		ao_gpio_set_bits(AO_PAD_PORT_0, pins0); +		PRINTD("turn off pins 0x%x\n", pins0); +#endif  	}  }  #define AO_PAD_ARM_SIREN_INTERVAL	200 -#ifndef AO_PYRO_R_PYRO_SENSE -#define AO_PYRO_R_PYRO_SENSE	100 -#define AO_PYRO_R_SENSE_GND	27 -#define AO_FIRE_R_POWER_FET	100 -#define AO_FIRE_R_FET_SENSE	100 -#define AO_FIRE_R_SENSE_GND	27 -#endif +/* Resistor values needed for various voltage test ratios: + * + *	Net names involved: + * + *	V_BATT		Battery power, after the initial power switch + *	V_PYRO		Pyro power, after the pyro power switch (and initial power switch) + *	PYRO_SENSE	ADC input to sense V_PYRO voltage + *	BATT_SENSE	ADC input to sense V_BATT voltage + *	IGNITER		FET output to pad (the other pad lead hooks to V_PYRO) + *	IGNITER_SENSE	ADC input to sense igniter voltage + * + *	AO_PAD_R_V_BATT_BATT_SENSE	Resistor from battery rail to battery sense input + *	AO_PAD_R_BATT_SENSE_GND		Resistor from battery sense input to ground + * + *	AO_PAD_R_V_BATT_V_PYRO		Resistor from battery rail to pyro rail + *	AO_PAD_R_V_PYRO_PYRO_SENSE	Resistor from pyro rail to pyro sense input + *	AO_PAD_R_PYRO_SENSE_GND		Resistor from pyro sense input to ground + * + *	AO_PAD_R_V_PYRO_IGNITER		Optional resistors from pyro rail to FET igniter output + *	AO_PAD_R_IGNITER_IGNITER_SENSE	Resistors from FET igniter output to igniter sense ADC inputs + *	AO_PAD_R_IGNITER_SENSE_GND	Resistors from igniter sense ADC inputs to ground + */ + +int16_t +ao_pad_decivolt(int16_t adc, int16_t r_plus, int16_t r_minus) +{ +	int32_t	mul = (int32_t) AO_ADC_REFERENCE_DV * (r_plus + r_minus); +	int32_t div = (int32_t) AO_ADC_MAX * r_minus; +	return ((int32_t) adc * mul + mul/2) / div; +}  static void  ao_pad_monitor(void)  {  	uint8_t			c;  	uint8_t			sample; -	__pdata uint8_t		prev = 0, cur = 0; +	__pdata AO_LED_TYPE	prev = 0, cur = 0;  	__pdata uint8_t		beeping = 0;  	__xdata volatile struct ao_data	*packet;  	__pdata uint16_t	arm_beep_time = 0;  	sample = ao_data_head; +	ao_led_set(LEDS_AVAILABLE); +	ao_delay(AO_MS_TO_TICKS(1000)); +	ao_led_set(0);  	for (;;) {  		__pdata int16_t			pyro; +  		ao_arch_critical(  			while (sample == ao_data_head)  				ao_sleep((void *) DATA_TO_XDATA(&ao_data_head)); @@ -141,28 +210,18 @@ ao_pad_monitor(void)  		packet = &ao_data_ring[sample];  		sample = ao_data_ring_next(sample); -		pyro = packet->adc.pyro; - -#define VOLTS_TO_PYRO(x) ((int16_t) ((x) * ((1.0 * AO_PYRO_R_SENSE_GND) / \ -					    (1.0 * (AO_PYRO_R_SENSE_GND + AO_PYRO_R_PYRO_SENSE)) / 3.3 * AO_ADC_MAX))) - +		/* Reply battery voltage */ +		query.battery = ao_pad_decivolt(packet->adc.batt, AO_PAD_R_V_BATT_BATT_SENSE, AO_PAD_R_BATT_SENSE_GND); -#define VOLTS_TO_FIRE(x) ((int16_t) ((x) * ((1.0 * AO_FIRE_R_SENSE_GND) / \ -					    (1.0 * (AO_FIRE_R_SENSE_GND + AO_FIRE_R_FET_SENSE)) / 3.3 * AO_ADC_MAX))) +		/* Current pyro voltage */ +		pyro = ao_pad_decivolt(packet->adc.pyro, +				       AO_PAD_R_V_PYRO_PYRO_SENSE, +				       AO_PAD_R_PYRO_SENSE_GND); -		/* convert ADC value to voltage in tenths, then add .2 for the diode drop */ -		query.battery = (packet->adc.batt + 96) / 192 + 2;  		cur = 0; -		if (pyro > VOLTS_TO_PYRO(10)) { +		if (pyro > query.battery * 7 / 8) {  			query.arm_status = AO_PAD_ARM_STATUS_ARMED;  			cur |= AO_LED_ARMED; -#if AO_FIRE_R_POWER_FET -		} else if (pyro > VOLTS_TO_PYRO(5)) { -			if ((ao_time() % 100) < 50) -				cur |= AO_LED_ARMED; -			query.arm_status = AO_PAD_ARM_STATUS_UNKNOWN; -			arm_beep_time = 0; -#endif  		} else {  			query.arm_status = AO_PAD_ARM_STATUS_DISARMED;  			arm_beep_time = 0; @@ -175,54 +234,50 @@ ao_pad_monitor(void)  			cur |= AO_LED_GREEN;  		for (c = 0; c < AO_PAD_NUM; c++) { -			int16_t		sense = packet->adc.sense[c]; +			int16_t		sense = ao_pad_decivolt(packet->adc.sense[c], +								AO_PAD_R_IGNITER_IGNITER_SENSE, +								AO_PAD_R_IGNITER_SENSE_GND);  			uint8_t	status = AO_PAD_IGNITER_STATUS_UNKNOWN;  			/* -			 *	pyro is run through a divider, so pyro = v_pyro * 27 / 127 ~= v_pyro / 20 -			 *	v_pyro = pyro * 127 / 27 +			 *	Here's the resistor stack on each +			 *	igniter channel. Note that +			 *	AO_PAD_R_V_PYRO_IGNITER is optional  			 * -			 *		v_pyro \ -			 *	100k		igniter -			 *		output / -			 *	100k           \ -			 *		sense   relay -			 *	27k            / -			 *		gnd --- +			 *					v_pyro \ +			 *	AO_PAD_R_V_PYRO_IGNITER			igniter +			 *					output / +			 *	AO_PAD_R_IGNITER_IGNITER_SENSE         \ +			 *					sense   relay +			 *	AO_PAD_R_IGNITER_SENSE_GND	       / +			 *					gnd ---  			 * -			 *		v_pyro \ -			 *	200k		igniter -			 *		output / -			 *	200k           \ -			 *		sense   relay -			 *	22k            / -			 *		gnd --- -			 * -			 *	If the relay is closed, then sense will be 0 -			 *	If no igniter is present, then sense will be v_pyro * 27k/227k = pyro * 127 / 227 ~= pyro/2 -			 *	If igniter is present, then sense will be v_pyro * 27k/127k ~= v_pyro / 20 = pyro  			 */ -#if AO_FIRE_R_POWER_FET +#ifdef AO_PAD_R_V_PYRO_IGNITER  			if (sense <= pyro / 8) { +				/* close to zero → relay is closed */  				status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_CLOSED;  				if ((ao_time() % 100) < 50)  					cur |= AO_LED_CONTINUITY(c); -			} else -			if (pyro / 8 * 3 <= sense && sense <= pyro / 8 * 5) -				status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; -			else if (pyro / 8 * 7 <= sense) { -				status = AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN; -				cur |= AO_LED_CONTINUITY(c); -			} -#else -			if (sense >= pyro / 8 * 5) { -				status = AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN; -				cur |= AO_LED_CONTINUITY(c); -			} else { -				status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;  			} +			else  #endif +			{ +				if (sense >= (pyro * 7) / 8) { + +					/* sense close to pyro voltage; igniter is good +					 */ +					status = AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN; +					cur |= AO_LED_CONTINUITY(c); +				} else { + +					/* relay not shorted (if we can tell), +					 * and igniter not obviously present +					 */ +					status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; +				} +			}  			query.igniter_status[c] = status;  		}  		if (cur != prev) { @@ -284,6 +339,23 @@ ao_pad_read_box(void)  }  #endif +#ifdef AO_PAD_SELECTOR_PORT +static int ao_pad_read_box(void) { +	AO_PORT_TYPE	value = ao_gpio_get_all(AO_PAD_SELECTOR_PORT); +	unsigned	pin; +	int		select = 1; + +	for (pin = 0; pin < sizeof (AO_PORT_TYPE) * 8; pin++) { +		if (AO_PAD_SELECTOR_PINS & (1 << pin)) { +			if ((value & (1 << pin)) == 0) +				return select; +			select++; +		} +	} +	return ao_config.pad_box; +} +#else +  #if HAS_FIXED_PAD_BOX  #define ao_pad_read_box()	ao_config.pad_box  #endif @@ -292,6 +364,8 @@ ao_pad_read_box(void)  #define ao_pad_read_box()	PAD_BOX  #endif +#endif +  static void  ao_pad(void)  { @@ -299,7 +373,6 @@ ao_pad(void)  	int8_t	ret;  	ao_pad_box = 0; -	ao_led_set(0);  	for (;;) {  		FLUSHD();  		while (ao_pad_disabled) @@ -497,20 +570,51 @@ __code struct ao_cmds ao_pad_cmds[] = {  	{ 0, NULL }  }; +#ifndef AO_PAD_PORT_1 +#define AO_PAD_0_PORT	AO_PAD_PORT +#define AO_PAD_1_PORT	AO_PAD_PORT +#define AO_PAD_2_PORT	AO_PAD_PORT +#define AO_PAD_3_PORT	AO_PAD_PORT +#define AO_PAD_4_PORT	AO_PAD_PORT +#define AO_PAD_5_PORT	AO_PAD_PORT +#define AO_PAD_6_PORT	AO_PAD_PORT +#define AO_PAD_7_PORT	AO_PAD_PORT +#endif +  void  ao_pad_init(void)  { +#ifdef AO_PAD_SELECTOR_PORT +	unsigned pin; + +	for (pin = 0; pin < sizeof (AO_PORT_TYPE) * 8; pin++) { +		if (AO_PAD_SELECTOR_PINS & (1 << pin)) +			ao_enable_input(AO_PAD_SELECTOR_PORT, pin, AO_EXTI_MODE_PULL_UP); +	} +#endif  #if AO_PAD_NUM > 0 -	ao_enable_output(AO_PAD_PORT, AO_PAD_PIN_0, AO_PAD_0, 0); +	ao_enable_output(AO_PAD_0_PORT, AO_PAD_PIN_0, AO_PAD_0, 0);  #endif  #if AO_PAD_NUM > 1 -	ao_enable_output(AO_PAD_PORT, AO_PAD_PIN_1, AO_PAD_1, 0); +	ao_enable_output(AO_PAD_1_PORT, AO_PAD_PIN_1, AO_PAD_1, 0);  #endif  #if AO_PAD_NUM > 2 -	ao_enable_output(AO_PAD_PORT, AO_PAD_PIN_2, AO_PAD_2, 0); +	ao_enable_output(AO_PAD_2_PORT, AO_PAD_PIN_2, AO_PAD_2, 0);  #endif  #if AO_PAD_NUM > 3 -	ao_enable_output(AO_PAD_PORT, AO_PAD_PIN_3, AO_PAD_3, 0); +	ao_enable_output(AO_PAD_3_PORT, AO_PAD_PIN_3, AO_PAD_3, 0); +#endif +#if AO_PAD_NUM > 4 +	ao_enable_output(AO_PAD_4_PORT, AO_PAD_PIN_4, AO_PAD_4, 0); +#endif +#if AO_PAD_NUM > 5 +	ao_enable_output(AO_PAD_5_PORT, AO_PAD_PIN_5, AO_PAD_5, 0); +#endif +#if AO_PAD_NUM > 5 +	ao_enable_output(AO_PAD_6_PORT, AO_PAD_PIN_6, AO_PAD_6, 0); +#endif +#if AO_PAD_NUM > 7 +	ao_enable_output(AO_PAD_7_PORT, AO_PAD_PIN_7, AO_PAD_7, 0);  #endif  #ifdef AO_STROBE  	ao_enable_output(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, 0); diff --git a/src/drivers/ao_quadrature.c b/src/drivers/ao_quadrature.c index deecfb79..250e035f 100644 --- a/src/drivers/ao_quadrature.c +++ b/src/drivers/ao_quadrature.c @@ -23,6 +23,10 @@  #include <ao_event.h>  __xdata int32_t ao_quadrature_count[AO_QUADRATURE_COUNT]; +#ifndef AO_QUADRATURE_SINGLE_CODE +static int8_t ao_quadrature_step[AO_QUADRATURE_COUNT]; +#endif +  static uint8_t  ao_quadrature_state[AO_QUADRATURE_COUNT];  struct ao_debounce { @@ -39,20 +43,25 @@ static struct ao_debounce ao_debounce_state[AO_QUADRATURE_COUNT][2];  #define pinb(q) AO_QUADRATURE_ ## q ## _B ## _PIN  #define isr(q)  ao_quadrature_isr_ ## q -#define DEBOUNCE	10 +#ifndef AO_QUADRATURE_DEBOUNCE +#error must define AO_QUADRATURE_DEBOUNCE +#endif  static uint8_t  ao_debounce(uint8_t cur, struct ao_debounce *debounce)  { -	if (cur == debounce->state) -		debounce->count = 0; -	else { -		if (++debounce->count == DEBOUNCE) { -			debounce->state = cur; -			debounce->count = 0; -		} +#if AO_QUADRATURE_DEBOUNCE > 0 +	if (debounce->count > 0) { +		debounce->count--; +	} else if (cur != debounce->state) { +		debounce->state = cur; +		debounce->count = AO_QUADRATURE_DEBOUNCE;  	}  	return debounce->state; +#else +	(void) debounce; +	return cur; +#endif  }  static uint16_t @@ -70,8 +79,21 @@ ao_quadrature_read(struct stm_gpio *gpio, uint8_t pin_a, uint8_t pin_b, struct a  #define _ao_quadrature_get(q)	ao_quadrature_read(port(q), bita(q), bitb(q), ao_debounce_state[q])  static void -_ao_quadrature_queue(uint8_t q, int8_t step) +_ao_quadrature_step(uint8_t q, int8_t step)  { +#ifndef AO_QUADRATURE_SINGLE_CODE +	ao_quadrature_step[q] += step; +	if (ao_quadrature_state[q] != 0) +		return; +	if (ao_quadrature_step[q] >= 4) { +		ao_quadrature_step[q] = 0; +		step = 1; +	} else if (ao_quadrature_step[q] <= -4) { +		ao_quadrature_step[q] = 0; +		step = -1; +	} else +		return; +#endif  	ao_quadrature_count[q] += step;  #if AO_EVENT  	ao_event_put_isr(AO_EVENT_QUADRATURE, q, step); @@ -79,17 +101,29 @@ _ao_quadrature_queue(uint8_t q, int8_t step)  	ao_wakeup(&ao_quadrature_count[q]);  } +static const struct { +	uint8_t prev, next; +} ao_quadrature_steps[4] = { +	[0] { .prev = 2, .next = 1 }, +	[1] { .prev = 0, .next = 3 }, +	[3] { .prev = 1, .next = 2 }, +	[2] { .prev = 3, .next = 0 }, +}; +  static void -_ao_quadrature_set(uint8_t q, uint8_t new) { -	uint8_t	old = ao_quadrature_state[q]; - -	if (old != new && new == 0) { -		if (old & 2) -			_ao_quadrature_queue(q, 1); -		else if (old & 1) -			_ao_quadrature_queue(q, -1); -	} +_ao_quadrature_set(uint8_t q, uint8_t new) +{ +	uint8_t	old; + +	ao_arch_block_interrupts(); +	old = ao_quadrature_state[q];  	ao_quadrature_state[q] = new; +	ao_arch_release_interrupts(); + +	if (new == ao_quadrature_steps[old].next) +		_ao_quadrature_step(q, 1); +	else if (new == ao_quadrature_steps[old].prev) +		_ao_quadrature_step(q, -1);  }  static void @@ -103,6 +137,14 @@ ao_quadrature_isr(void)  #endif  } +static void +_ao_quadrature_start_one(uint8_t q, uint8_t new) +{ +	ao_arch_block_interrupts(); +	ao_quadrature_state[q] = new; +	ao_arch_release_interrupts(); +} +  int32_t  ao_quadrature_poll(uint8_t q)  { @@ -124,21 +166,32 @@ ao_quadrature_test(void)  	uint8_t	q;  	int32_t	c;  	uint8_t	s; +#ifndef AO_QUADRATURE_SINGLE_CODE +	int8_t t = 0; +#endif  	ao_cmd_decimal();  	q = ao_cmd_lex_i; -	if (q >= AO_QUADRATURE_COUNT) { +	if (q >= AO_QUADRATURE_COUNT)  		ao_cmd_status = ao_cmd_syntax_error; +	if (ao_cmd_status != ao_cmd_success)  		return; -	}  	c = -10000;  	s = 0;  	while (ao_quadrature_count[q] != 10) {  		if (ao_quadrature_count[q] != c || -		    ao_quadrature_state[q] != s) { +#ifndef AO_QUADRATURE_SINGLE_CODE +		    ao_quadrature_step[q] != t || +#endif +		    ao_quadrature_state[q] != s) +		{  			c = ao_quadrature_count[q];  			s = ao_quadrature_state[q]; +#ifndef AO_QUADRATURE_SINGLE_CODE +			t = ao_quadrature_step[q]; +			printf("step %3d ", t); +#endif  			printf ("count %3d state %2x\n", c, s);  			flush();  		} @@ -160,9 +213,10 @@ static const struct ao_cmds ao_quadrature_cmds[] = {  	{ 0, NULL }  }; -#define init(q) do {					\ -		ao_enable_input(port(q), bita(q), 0);	\ -		ao_enable_input(port(q), bitb(q), 0);	\ +#define init(q) do {							\ +		ao_enable_input(port(q), bita(q), 0);			\ +		ao_enable_input(port(q), bitb(q), 0);			\ +		_ao_quadrature_start_one(q, _ao_quadrature_get(q));	\  	} while (0)  void diff --git a/src/fox1ihu/.gitignore b/src/fox1ihu/.gitignore new file mode 100644 index 00000000..538cf8b2 --- /dev/null +++ b/src/fox1ihu/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +fox1ihu-*.elf diff --git a/src/fox1ihu/Makefile b/src/fox1ihu/Makefile new file mode 100644 index 00000000..e3226a24 --- /dev/null +++ b/src/fox1ihu/Makefile @@ -0,0 +1,89 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_watchdog.h \ +	ao_storage.h \ +	ao_task.h \ +	stm32l.h \ +	ao_sdcard.h \ +	ao_bufio.h \ +	ao_fat.h \ +	Makefile + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#SAMPLE_PROFILE=ao_sample_profile.c \ +#	ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_adc_stm.c \ +	ao_data.c \ +	ao_storage.c \ +	ao_mr25.c \ +	ao_sdcard.c \ +	ao_bufio.c \ +	ao_fat.c \ +	ao_watchdog.c + +PRODUCT=Fox1IHU-v2 +PRODUCT_DEF=-DFOX +IDPRODUCT=0x0024 + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=fox1ihu-v0.1 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_fox1ihu.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/fox1ihu/ao_fox1ihu.c b/src/fox1ihu/ao_fox1ihu.c new file mode 100644 index 00000000..2e1a2fdf --- /dev/null +++ b/src/fox1ihu/ao_fox1ihu.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_exti.h> +#include <ao_watchdog.h> +#include <ao_storage.h> +#include <ao_fat.h> + +int +main(void) +{ +	ao_clock_init(); +	 +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init(); +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_RED|AO_LED_GREEN|AO_LED_RED_2|AO_LED_GREEN_2); +	ao_timer_init(); + +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); + +	ao_adc_init(); + +	ao_cmd_init(); + +	ao_usb_init(); + +	ao_storage_init(); + +	ao_watchdog_init(); + +	ao_fat_init(); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/fox1ihu/ao_pins.h b/src/fox1ihu/ao_pins.h new file mode 100644 index 00000000..b5dd7283 --- /dev/null +++ b/src/fox1ihu/ao_pins.h @@ -0,0 +1,317 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1		1 +#define USE_SERIAL_1_STDIN	0 +#define SERIAL_1_PB6_PB7	0 +#define SERIAL_1_PA9_PA10	1 + +#define HAS_SERIAL_2		0 +#define USE_SERIAL_2_STDIN	0 +#define SERIAL_2_PA2_PA3	0 +#define SERIAL_2_PD5_PD6	0 + +#define HAS_SERIAL_3		0 +#define USE_SERIAL_3_STDIN	0 +#define SERIAL_3_PB10_PB11	0 +#define SERIAL_3_PC10_PC11	1 +#define SERIAL_3_PD8_PD9	0 + +#define HAS_EEPROM		0 +#define USE_INTERNAL_FLASH	0 +#define HAS_USB			1 +#define HAS_BEEP		0 +#define HAS_RADIO		0 +#define HAS_TELEMETRY		0 + +#define HAS_SPI_1		1 +#define SPI_1_PA5_PA6_PA7	0 +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	1	/* */ +#define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_SPI_2		1 +#define SPI_2_PB13_PB14_PB15	1	/* */ +#define SPI_2_PD1_PD3_PD4	0 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz +#define HAS_STORAGE_DEBUG	1 + +#define SPI_2_PORT		(&stm_gpiob) +#define SPI_2_SCK_PIN		13 +#define SPI_2_MISO_PIN		14 +#define SPI_2_MOSI_PIN		15 + +#define HAS_I2C_1		1 +#define I2C_1_PB6_PB7		1 +#define I2C_1_PB8_PB9		0 + +#define HAS_I2C_2		1 +#define I2C_2_PB10_PB11		1 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT_0_ENABLE	STM_RCC_AHBENR_GPIOCEN +#define LED_PORT_0		(&stm_gpioc) +#define LED_PORT_0_MASK		(0xff) +#define LED_PORT_0_SHIFT	0 +#define LED_PIN_RED		6 +#define LED_PIN_GREEN		7 +#define LED_PIN_RED_2		8 +#define LED_PIN_GREEN_2		9 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) +#define AO_LED_RED_2		(1 << LED_PIN_RED_2) +#define AO_LED_GREEN_2		(1 << LED_PIN_GREEN_2) + +#define LEDS_AVAILABLE		(AO_LED_RED | AO_LED_GREEN | AO_LED_RED_2 | AO_LED_GREEN_2) + +#define HAS_GPS			0 +#define HAS_FLIGHT		0 +#define HAS_ADC			1 +#define HAS_ADC_TEMP		1 +#define HAS_LOG			0 + +/* + * ADC + */ +#define AO_DATA_RING		32 + +struct ao_adc { +	int16_t			tx_pa_current;	/* 0 ADC_IN0 */ +	int16_t			tx_temp;	/* 1 ADC_IN1 */ +	int16_t			exp4_temp;	/* 2 ADC_IN2 */ +	int16_t			rx_temp;	/* 3 ADC_IN3 */ +	int16_t			tx_analog_1;	/* 4 ADC_IN4 */ +	int16_t			sense_batt;	/* 5 ADC_IN5 */ +	int16_t			rx_analog_1;	/* 6 ADC_IN6 */ +	int16_t			rx_rssi;	/* 7 ADC_IN8 */ +	int16_t			rx_cd;		/* 8 ADC_IN9 */ +	int16_t			ant_sense_1;	/* 9 ADC_IN10 */ +	int16_t			ant_sense_2;	/* 10 ADC_IN11 */ +	int16_t			gyro_x_1;	/* 11 ADC_IN12 */ +	int16_t			gyro_z_1;	/* 12 ADC_IN13 */ +	int16_t			gyro_vref_1;	/* 13 ADC_IN24 */ +	int16_t			gyro_x_2;	/* 14 ADC_IN14 */ +	int16_t			gyro_z_2;	/* 15 ADC_IN15 */ +	int16_t			gyro_vref_2;	/* 16 ADC_IN25 */ +}; + +#define AO_ADC_TX_PA_CURRENT		0 +#define AO_ADC_TX_PA_CURRENT_PORT	(&stm_gpioa) +#define AO_ADC_TX_PA_CURRENT_PIN	0 + +#define AO_ADC_TX_TEMP			1 +#define AO_ADC_TX_TEMP_PORT		(&stm_gpioa) +#define AO_ADC_TX_TEMP_PIN		1 + +#define AO_ADC_EXP4_TEMP		2 +#define AO_ADC_EXP4_TEMP_PORT		(&stm_gpioa) +#define AO_ADC_EXP4_TEMP_PIN		2 + +#define AO_ADC_RX_TEMP			3 +#define AO_ADC_RX_TEMP_PORT		(&stm_gpioa) +#define AO_ADC_RX_TEMP_PIN		3 + +#define AO_ADC_TX_ANALOG_1		4 +#define AO_ADC_TX_ANALOG_1_PORT		(&stm_gpioa) +#define AO_ADC_TX_ANALOG_1_PIN		4 + +#define AO_ADC_SENSE_BATT		5 +#define AO_ADC_SENSE_BATT_PORT		(&stm_gpioa) +#define AO_ADC_SENSE_BATT_PIN		5 + +#define AO_ADC_RX_ANALOG_1		6 +#define AO_ADC_RX_ANALOG_1_PORT		(&stm_gpioa) +#define AO_ADC_RX_ANALOG_1_PIN		6 + +#define AO_ADC_RX_RSSI			8 +#define AO_ADC_RX_RSSI_PORT		(&stm_gpiob) +#define AO_ADC_RX_RSSI_PIN		0 + +#define AO_ADC_RX_CD			9 +#define AO_ADC_RX_CD_PORT		(&stm_gpiob) +#define AO_ADC_RX_CD_PIN		1 + +#define AO_ADC_ANT_SENSE_1		10 +#define AO_ADC_ANT_SENSE_1_PORT		(&stm_gpioc) +#define AO_ADC_ANT_SENSE_1_PIN		0 + +#define AO_ADC_ANT_SENSE_2		11 +#define AO_ADC_ANT_SENSE_2_PORT		(&stm_gpioc) +#define AO_ADC_ANT_SENSE_2_PIN		1 + +#define AO_ADC_GYRO_X_1			12 +#define AO_ADC_GYRO_X_1_PORT		(&stm_gpioc) +#define AO_ADC_GYRO_X_1_PIN		2 + +#define AO_ADC_GYRO_Z_1			13 +#define AO_ADC_GYRO_Z_1_PORT		(&stm_gpioc) +#define AO_ADC_GYRO_Z_1_PIN		3 + +#define AO_ADC_GYRO_VREF_1		24 +#define AO_ADC_GYRO_VREF_1_PORT		(&stm_gpioe) +#define AO_ADC_GYRO_VREF_1_PIN		9 + +#define AO_ADC_GYRO_X_2			14 +#define AO_ADC_GYRO_X_2_PORT		(&stm_gpioc) +#define AO_ADC_GYRO_X_2_PIN		4 + +#define AO_ADC_GYRO_Z_2			15 +#define AO_ADC_GYRO_Z_2_PORT		(&stm_gpioc) +#define AO_ADC_GYRO_Z_2_PIN		5 + +#define AO_ADC_GYRO_VREF_2		25 +#define AO_ADC_GYRO_VREF_2_PORT		(&stm_gpioe) +#define AO_ADC_GYRO_VREF_2_PIN		10 + +#define AO_ADC_TEMP			16 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_GPIOAEN) | \ +				 (1 << STM_RCC_AHBENR_GPIOBEN) | \ +				 (1 << STM_RCC_AHBENR_GPIOCEN) | \ +				 (1 << STM_RCC_AHBENR_GPIOEEN)) + +#define AO_NUM_ADC_PIN		(17) + +#define AO_ADC_PIN0_PORT	AO_ADC_TX_PA_CURRENT_PORT +#define AO_ADC_PIN0_PIN		AO_ADC_TX_PA_CURRENT_PIN +#define AO_ADC_PIN1_PORT	AO_ADC_TX_TEMP_PORT +#define AO_ADC_PIN1_PIN		AO_ADC_TX_TEMP_PIN +#define AO_ADC_PIN2_PORT	AO_ADC_EXP4_TEMP_PORT +#define AO_ADC_PIN2_PIN		AO_ADC_EXP4_TEMP_PIN +#define AO_ADC_PIN3_PORT	AO_ADC_RX_TEMP_PORT +#define AO_ADC_PIN3_PIN		AO_ADC_RX_TEMP_PIN +#define AO_ADC_PIN4_PORT	AO_ADC_TX_ANALOG_1_PORT +#define AO_ADC_PIN4_PIN		AO_ADC_TX_ANALOG_1_PIN +#define AO_ADC_PIN5_PORT	AO_ADC_SENSE_BATT_PORT +#define AO_ADC_PIN5_PIN		AO_ADC_SENSE_BATT_PIN +#define AO_ADC_PIN6_PORT	AO_ADC_RX_ANALOG_1_PORT +#define AO_ADC_PIN6_PIN		AO_ADC_RX_ANALOG_1_PIN +#define AO_ADC_PIN7_PORT	AO_ADC_RX_RSSI_PORT +#define AO_ADC_PIN7_PIN		AO_ADC_RX_RSSI_PIN +#define AO_ADC_PIN8_PORT	AO_ADC_RX_CD_PORT +#define AO_ADC_PIN8_PIN		AO_ADC_RX_CD_PIN +#define AO_ADC_PIN9_PORT	AO_ADC_ANT_SENSE_1_PORT +#define AO_ADC_PIN9_PIN		AO_ADC_ANT_SENSE_1_PIN +#define AO_ADC_PIN10_PORT	AO_ADC_ANT_SENSE_2_PORT +#define AO_ADC_PIN10_PIN	AO_ADC_ANT_SENSE_2_PIN +#define AO_ADC_PIN11_PORT	AO_ADC_GYRO_X_1_PORT +#define AO_ADC_PIN11_PIN	AO_ADC_GYRO_X_1_PIN +#define AO_ADC_PIN12_PORT	AO_ADC_GYRO_Z_1_PORT +#define AO_ADC_PIN12_PIN	AO_ADC_GYRO_Z_1_PIN +#define AO_ADC_PIN13_PORT	AO_ADC_GYRO_VREF_1_PORT +#define AO_ADC_PIN13_PIN	AO_ADC_GYRO_VREF_1_PIN +#define AO_ADC_PIN14_PORT	AO_ADC_GYRO_X_2_PORT +#define AO_ADC_PIN14_PIN	AO_ADC_GYRO_X_2_PIN +#define AO_ADC_PIN15_PORT	AO_ADC_GYRO_Z_2_PORT +#define AO_ADC_PIN15_PIN	AO_ADC_GYRO_Z_2_PIN +#define AO_ADC_PIN16_PORT	AO_ADC_GYRO_VREF_2_PORT +#define AO_ADC_PIN16_PIN	AO_ADC_GYRO_VREF_2_PIN + +#define AO_NUM_ADC	       	(AO_NUM_ADC_PIN + 1)	/* Add internal temp sensor */ + +#define AO_ADC_SQ1		AO_ADC_TX_PA_CURRENT +#define AO_ADC_SQ1_NAME		"tx_pa_current" +#define AO_ADC_SQ2		AO_ADC_TX_TEMP +#define AO_ADC_SQ2_NAME		"tx_temp" +#define AO_ADC_SQ3		AO_ADC_EXP4_TEMP +#define AO_ADC_SQ3_NAME		"expr_temp" +#define AO_ADC_SQ4		AO_ADC_RX_TEMP +#define AO_ADC_SQ4_NAME		"rx_temp" +#define AO_ADC_SQ5		AO_ADC_TX_ANALOG_1 +#define AO_ADC_SQ5_NAME		"tx_analog_1" +#define AO_ADC_SQ6		AO_ADC_SENSE_BATT +#define AO_ADC_SQ6_NAME		"sense_batt" +#define AO_ADC_SQ7		AO_ADC_RX_ANALOG_1 +#define AO_ADC_SQ7_NAME		"rx_analog_1" +#define AO_ADC_SQ8		AO_ADC_RX_RSSI +#define AO_ADC_SQ8_NAME		"rx_rssi" +#define AO_ADC_SQ9		AO_ADC_RX_CD +#define AO_ADC_SQ9_NAME		"rx_cd" +#define AO_ADC_SQ10		AO_ADC_ANT_SENSE_1 +#define AO_ADC_SQ10_NAME	"ant_sense_1" +#define AO_ADC_SQ11		AO_ADC_ANT_SENSE_2 +#define AO_ADC_SQ11_NAME	"ant_sense_2" +#define AO_ADC_SQ12		AO_ADC_GYRO_X_1 +#define AO_ADC_SQ12_NAME	"gyro_x_1" +#define AO_ADC_SQ13		AO_ADC_GYRO_Z_1 +#define AO_ADC_SQ13_NAME	"gyro_z_1" +#define AO_ADC_SQ14		AO_ADC_GYRO_VREF_1 +#define AO_ADC_SQ14_NAME	"gyro_vref_1" +#define AO_ADC_SQ15		AO_ADC_GYRO_X_2 +#define AO_ADC_SQ15_NAME	"gyro_x_2" +#define AO_ADC_SQ16		AO_ADC_GYRO_Z_2 +#define AO_ADC_SQ16_NAME	"gyro_z_2" +#define AO_ADC_SQ17		AO_ADC_GYRO_VREF_2 +#define AO_ADC_SQ17_NAME	"gyro_vref_2" +#define AO_ADC_SQ18		AO_ADC_TEMP +#define AO_ADC_SQ18_NAME	"temp" + +/* Watchdog timer */ + +#define AO_WATCHDOG_INTERVAL	AO_MS_TO_TICKS(40) +#define AO_WATCHDOG_PORT	(&stm_gpiod) +#define AO_WATCHDOG_BIT		3 + +/* MRAM device */ + +#define AO_MR25_SPI_CS_PORT	(&stm_gpiod) +#define AO_MR25_SPI_CS_PIN	0 +#define AO_MR25_SPI_BUS		AO_SPI_2_PB13_PB14_PB15 + +/* SD card */ + +#define AO_SDCARD_SPI_CS_PORT	(&stm_gpiod) +#define AO_SDCARD_SPI_CS_PIN	1 +#define AO_SDCARD_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 +#define AO_SDCARD_SPI_PORT	(&stm_gpiob) +#define AO_SDCARD_SPI_SCK_PIN	13 +#define AO_SDCARD_SPI_MISO_PIN	14 +#define AO_SDCARD_SPI_MOSI_PIN	15 + +#endif /* _AO_PINS_H_ */ diff --git a/src/fox1ihu/flash-loader/Makefile b/src/fox1ihu/flash-loader/Makefile new file mode 100644 index 00000000..454bc6fb --- /dev/null +++ b/src/fox1ihu/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=fox1ihu +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/fox1ihu/flash-loader/ao_pins.h b/src/fox1ihu/flash-loader/ao_pins.h new file mode 100644 index 00000000..19f29b08 --- /dev/null +++ b/src/fox1ihu/flash-loader/ao_pins.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#define AO_WATCHDOG_PORT	(&stm_gpiod) +#define AO_WATCHDOG_PORT_BIT	(1 << STM_RCC_AHBENR_GPIODEN) +#define AO_WATCHDOG_BIT		3 +#define AO_WATCHDOG_VALUE	0 + +#define AO_RADIO_CONTROL_PORT		(&stm_gpioe) +#define AO_RADIO_CONTROL_PORT_BIT	(1 << STM_RCC_AHBENR_GPIOEEN) +#define AO_RADIO_CONTROL_BIT		12 +#define AO_RADIO_CONTROL_VALUE		1 + +#define AO_FLASH_LOADER_INIT do {					\ +		stm_rcc.ahbenr |= AO_WATCHDOG_PORT_BIT | AO_RADIO_CONTROL_PORT_BIT; \ +									\ +		stm_gpio_set(AO_WATCHDOG_PORT, AO_WATCHDOG_BIT, AO_WATCHDOG_VALUE); \ +		stm_moder_set(AO_WATCHDOG_PORT, AO_WATCHDOG_BIT, STM_MODER_OUTPUT); \ +									\ +		stm_gpio_set(AO_RADIO_CONTROL_PORT, AO_RADIO_CONTROL_BIT, AO_RADIO_CONTROL_VALUE); \ +		stm_moder_set(AO_RADIO_CONTROL_PORT, AO_RADIO_CONTROL_BIT, STM_MODER_OUTPUT); \ +	} while (0) + +#define AO_TIMER_HOOK	do {						\ +		AO_WATCHDOG_PORT->odr ^= (1 << AO_WATCHDOG_BIT);	\ +	} while (0) + +#define HAS_TICK		1 +#include <ao_flash_stm_pins.h> + +/* Attached signal, PB8 */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiob +#define AO_BOOT_APPLICATION_PIN		8 +#define AO_BOOT_APPLICATION_VALUE	0 +#define AO_BOOT_APPLICATION_MODE	0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/kernel/ao_flash_readout.c b/src/kernel/ao_flash_readout.c new file mode 100644 index 00000000..46b5ba7a --- /dev/null +++ b/src/kernel/ao_flash_readout.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_usb.h> +#include <ao_flash_readout.h> + +#ifndef AO_FLASH_READOUT_BASE +#define AO_FLASH_READOUT_BASE	AO_BOOT_LOADER_BASE +#define AO_FLASH_READOUT_BOUND	AO_BOOT_APPLICATION_BOUND +#endif + +static void +ao_flash_readout(void) +{ +	uint8_t	*base = (uint8_t *) AO_FLASH_READOUT_BASE; +	uint8_t	*bound = (uint8_t *) AO_FLASH_READOUT_BOUND; +	uint8_t	*p = base; + +	for (;;) { +		ao_arch_block_interrupts(); +		while (!ao_usb_running) { +			p = base; +			ao_sleep(&ao_usb_running); +		} +		ao_arch_release_interrupts(); +		ao_flash_readout_putchar(*p++); +		if (p == bound) +			p = base; +	} +} + +static struct ao_task	ao_flash_readout_task; + +void +ao_flash_readout_init(void) +{ +	ao_add_task(&ao_flash_readout_task, ao_flash_readout, "flash_readout"); +} diff --git a/src/kernel/ao_flash_readout.h b/src/kernel/ao_flash_readout.h new file mode 100644 index 00000000..5eee53cc --- /dev/null +++ b/src/kernel/ao_flash_readout.h @@ -0,0 +1,20 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_FLASH_READOUT_H_ +#define _AO_FLASH_READOUT_H_ + +void	ao_flash_readout_init(void); + +#endif /* _AO_FLASH_READOUT_H_ */ diff --git a/src/kernel/ao_flight.c b/src/kernel/ao_flight.c index cb02c454..c2700d20 100644 --- a/src/kernel/ao_flight.c +++ b/src/kernel/ao_flight.c @@ -48,7 +48,8 @@  /* Main flight thread. */  __pdata enum ao_flight_state	ao_flight_state;	/* current flight state */ -__pdata uint16_t		ao_boost_tick;		/* time of launch detect */ +__pdata uint16_t		ao_boost_tick;		/* time of most recent boost detect */ +__pdata uint16_t		ao_launch_tick;		/* time of first boost detect */  __pdata uint16_t		ao_motor_number;	/* number of motors burned so far */  #if HAS_SENSOR_ERRORS @@ -199,7 +200,7 @@ ao_flight(void)  				)  			{  				ao_flight_state = ao_flight_boost; -				ao_boost_tick = ao_sample_tick; +				ao_launch_tick = ao_boost_tick = ao_sample_tick;  				/* start logging data */  				ao_log_start(); @@ -233,7 +234,7 @@ ao_flight(void)  			 * deceleration, or by waiting until the maximum burn duration  			 * (15 seconds) has past.  			 */ -			if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || +			if ((ao_accel < AO_MSS_TO_ACCEL(-2.5)) ||  			    (int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX)  			{  #if HAS_ACCEL @@ -269,7 +270,7 @@ ao_flight(void)  			 * number of seconds.  			 */  			if (ao_config.apogee_lockout) { -				if ((int16_t) (ao_sample_tick - ao_boost_tick) < +				if ((int16_t) (ao_sample_tick - ao_launch_tick) <  				    AO_SEC_TO_TICKS(ao_config.apogee_lockout))  					break;  			} @@ -310,7 +311,7 @@ ao_flight(void)  #if HAS_ACCEL  			else {  			check_re_boost: -				ao_coast_avg_accel = ao_coast_avg_accel - (ao_coast_avg_accel >> 6) + (ao_accel >> 6); +				ao_coast_avg_accel = ao_coast_avg_accel + ((ao_accel - ao_coast_avg_accel) >> 5);  				if (ao_coast_avg_accel > AO_MSS_TO_ACCEL(20)) {  					ao_boost_tick = ao_sample_tick;  					ao_flight_state = ao_flight_boost; diff --git a/src/kernel/ao_flight.h b/src/kernel/ao_flight.h index 6894fe59..005c7e84 100644 --- a/src/kernel/ao_flight.h +++ b/src/kernel/ao_flight.h @@ -40,6 +40,7 @@ enum ao_flight_state {  extern __pdata enum ao_flight_state	ao_flight_state;  extern __pdata uint16_t			ao_boost_tick; +extern __pdata uint16_t			ao_launch_tick;  extern __pdata uint16_t			ao_motor_number;  #if HAS_IMU || HAS_MMA655X diff --git a/src/kernel/ao_kalman.c b/src/kernel/ao_kalman.c index ac41085d..e4cc6d4b 100644 --- a/src/kernel/ao_kalman.c +++ b/src/kernel/ao_kalman.c @@ -45,7 +45,11 @@ static __pdata ao_k_t		ao_avg_height_scaled;  __xdata ao_v_t			ao_avg_height;  __pdata ao_v_t			ao_error_h; -#if !HAS_ACCEL +#if !HAS_ACCEL || AO_FLIGHT_TEST +#define AO_ERROR_H_SQ_AVG	1 +#endif + +#if AO_ERROR_H_SQ_AVG  __pdata ao_v_t			ao_error_h_sq_avg;  #endif @@ -85,7 +89,7 @@ ao_kalman_predict(void)  static void  ao_kalman_err_height(void)  { -#if !HAS_ACCEL +#if AO_ERROR_H_SQ_AVG  	ao_v_t	e;  #endif  	ao_v_t height_distrust; @@ -95,7 +99,7 @@ ao_kalman_err_height(void)  	ao_error_h = ao_sample_height - (ao_v_t) (ao_k_height >> 16); -#if !HAS_ACCEL +#if AO_ERROR_H_SQ_AVG  	e = ao_error_h;  	if (e < 0)  		e = -e; diff --git a/src/kernel/ao_product.c b/src/kernel/ao_product.c index c4df9f26..4c2d83ef 100644 --- a/src/kernel/ao_product.c +++ b/src/kernel/ao_product.c @@ -55,7 +55,7 @@ const char ao_product[] = AO_iProduct_STRING;  #define HEADER_LEN	       	9  #define CONTROL_CLASS_LEN	35 -#define DATA_LEN		(9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN + 7 * AO_USB_HAS_IN2) +#define DATA_LEN		(9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN + 7 * AO_USB_HAS_IN2 + 7 * AO_USB_HAS_IN3)  #define TOTAL_LENGTH		(HEADER_LEN + AO_USB_HAS_INT * CONTROL_CLASS_LEN + DATA_LEN)  #define NUM_INTERFACES		(AO_USB_HAS_INT + 1) @@ -141,7 +141,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =  	AO_USB_DESC_INTERFACE,  	AO_USB_HAS_INT,			/* bInterfaceNumber */  	0x00,				/* bAlternateSetting */ -	AO_USB_HAS_OUT + AO_USB_HAS_IN + AO_USB_HAS_IN2,	/* bNumEndPoints */ +	AO_USB_HAS_OUT + AO_USB_HAS_IN + AO_USB_HAS_IN2 + AO_USB_HAS_IN3,	/* bNumEndPoints */  	AO_USB_INTERFACE_CLASS_DATA,	/* bInterfaceClass = data */  	0x00,				/* bInterfaceSubClass */  	0x00,				/* bInterfaceProtocol */ @@ -177,6 +177,16 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =  	0x00,			/* bInterval */  #endif +#if AO_USB_HAS_IN3 +	/* Data EP in 3 */ +	0x07, +	AO_USB_DESC_ENDPOINT, +	AO_USB_IN3_EP|0x80,	/* bEndpointAddress */ +	0x02,			/* bmAttributes = bulk */ +	LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ +	0x00,			/* bInterval */ +#endif +  	/* String descriptors */  	0x04,  	AO_USB_DESC_STRING, diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index e5c30eec..527112ac 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -81,6 +81,19 @@ int pyro_dbg;  #define DBG(...)  #endif +static angle_t +ao_sample_max_orient(void) +{ +	uint8_t	i; +	angle_t	max = ao_sample_orients[0]; + +	for (i = 1; i < AO_NUM_ORIENT; i++) { +		angle_t a = ao_sample_orients[i]; +		if (a > max) +			max = a; +	} +	return max; +}  /*   * Given a pyro structure, figure out   * if the current flight state satisfies all @@ -90,6 +103,9 @@ static uint8_t  ao_pyro_ready(struct ao_pyro *pyro)  {  	enum ao_pyro_flag flag, flags; +#if HAS_GYRO +	angle_t max_orient; +#endif  	flags = pyro->flags;  	while (flags != ao_pyro_none) { @@ -130,26 +146,28 @@ ao_pyro_ready(struct ao_pyro *pyro)  #if HAS_GYRO  		case ao_pyro_orient_less: -			if (ao_sample_orient <= pyro->orient_less) +			max_orient = ao_sample_max_orient(); +			if (max_orient <= pyro->orient_less)  				continue; -			DBG("orient %d > %d\n", ao_sample_orient, pyro->orient_less); +			DBG("orient %d > %d\n", max_orient, pyro->orient_less);  			break;  		case ao_pyro_orient_greater: -			if (ao_sample_orient >= pyro->orient_greater) +			max_orient = ao_sample_max_orient(); +			if (max_orient >= pyro->orient_greater)  				continue; -			DBG("orient %d < %d\n", ao_sample_orient, pyro->orient_greater); +			DBG("orient %d < %d\n", max_orient, pyro->orient_greater);  			break;  #endif  		case ao_pyro_time_less: -			if ((int16_t) (ao_time() - ao_boost_tick) <= pyro->time_less) +			if ((int16_t) (ao_time() - ao_launch_tick) <= pyro->time_less)  				continue; -			DBG("time %d > %d\n", (int16_t)(ao_time() - ao_boost_tick), pyro->time_less); +			DBG("time %d > %d\n", (int16_t)(ao_time() - ao_launch_tick), pyro->time_less);  			break;  		case ao_pyro_time_greater: -			if ((int16_t) (ao_time() - ao_boost_tick) >= pyro->time_greater) +			if ((int16_t) (ao_time() - ao_launch_tick) >= pyro->time_greater)  				continue; -			DBG("time %d < %d\n", (int16_t)(ao_time() - ao_boost_tick), pyro->time_greater); +			DBG("time %d < %d\n", (int16_t)(ao_time() - ao_launch_tick), pyro->time_greater);  			break;  		case ao_pyro_ascending: @@ -164,7 +182,7 @@ ao_pyro_ready(struct ao_pyro *pyro)  			break;  		case ao_pyro_after_motor: -			if (ao_motor_number == pyro->motor) +			if (ao_motor_number >= pyro->motor)  				continue;  			DBG("motor %d != %d\n", ao_motor_number, pyro->motor);  			break; diff --git a/src/kernel/ao_sample.c b/src/kernel/ao_sample.c index 61519478..f8012e34 100644 --- a/src/kernel/ao_sample.c +++ b/src/kernel/ao_sample.c @@ -50,6 +50,8 @@ __pdata gyro_t		ao_sample_roll;  __pdata gyro_t		ao_sample_pitch;  __pdata gyro_t		ao_sample_yaw;  __pdata angle_t		ao_sample_orient; +__pdata angle_t		ao_sample_orients[AO_NUM_ORIENT]; +__pdata uint8_t		ao_sample_orient_pos;  #endif  __data uint8_t		ao_sample_data; @@ -115,6 +117,53 @@ ao_sample_preflight_add(void)  	++nsamples;  } +#if HAS_GYRO +static void +ao_sample_set_all_orients(void) +{ +	int i; +	for (i = 0; i < AO_NUM_ORIENT; i++) +		ao_sample_orients[i] = ao_sample_orient; +	ao_sample_orient_pos = 0; +} + +static void +ao_sample_set_one_orient(void) +{ +	ao_sample_orients[ao_sample_orient_pos] = ao_sample_orient; +	ao_sample_orient_pos = (ao_sample_orient_pos + 1) % AO_NUM_ORIENT; +} + +static void +ao_sample_compute_orient(void) +{ +	/* Compute pitch angle from vertical by taking the pad +	 * orientation vector and rotating it by the current total +	 * rotation value. That will be a unit vector pointing along +	 * the airframe axis. The Z value will be the cosine of the +	 * change in the angle from vertical since boost. +	 * +	 * rot = ao_rotation * vertical * ao_rotation° +	 * rot = ao_rotation * (0,0,0,1) * ao_rotation° +	 *     = ((a.z, a.y, -a.x, a.r) * (a.r, -a.x, -a.y, -a.z)) .z +	 * +	 *     = (-a.z * -a.z) + (a.y * -a.y) - (-a.x * -a.x) + (a.r * a.r) +	 *     = a.z² - a.y² - a.x² + a.r² +	 * +	 * rot = ao_rotation * (0, 0, 0, -1) * ao_rotation° +	 *     = ((-a.z, -a.y, a.x, -a.r) * (a.r, -a.x, -a.y, -a.z)) .z +	 * +	 *     = (a.z * -a.z) + (-a.y * -a.y) - (a.x * -a.x) + (-a.r * a.r) +	 *     = -a.z² + a.y² + a.x² - a.r² +	 */ + +	float rotz; +	rotz = ao_rotation.z * ao_rotation.z - ao_rotation.y * ao_rotation.y - ao_rotation.x * ao_rotation.x + ao_rotation.r * ao_rotation.r; + +	ao_sample_orient = acosf(rotz) * (float) (180.0/M_PI); +} +#endif /* HAS_GYRO */ +  static void  ao_sample_preflight_set(void)  { @@ -138,7 +187,7 @@ ao_sample_preflight_set(void)  	ao_sample_pitch_sum = 0;  	ao_sample_yaw_sum = 0;  	ao_sample_roll_sum = 0; -	ao_sample_orient = 0; +	ao_sample_set_all_orients();  	struct ao_quaternion	orient; @@ -168,6 +217,9 @@ ao_sample_preflight_set(void)  	if (ao_orient_test)  		printf("\n\treset\n");  #endif	 + +	ao_sample_compute_orient(); +	ao_sample_set_all_orients();  #endif  	nsamples = 0;  } @@ -195,31 +247,6 @@ ao_sample_rotate(void)  	/* And normalize to make sure it remains a unit vector */  	ao_quaternion_normalize(&ao_rotation, &ao_rotation); -	/* Compute pitch angle from vertical by taking the pad -	 * orientation vector and rotating it by the current total -	 * rotation value. That will be a unit vector pointing along -	 * the airframe axis. The Z value will be the cosine of the -	 * change in the angle from vertical since boost. -	 * -	 * rot = ao_rotation * vertical * ao_rotation° -	 * rot = ao_rotation * (0,0,0,1) * ao_rotation° -	 *     = ((a.z, a.y, -a.x, a.r) * (a.r, -a.x, -a.y, -a.z)) .z -	 * -	 *     = (-a.z * -a.z) + (a.y * -a.y) - (-a.x * -a.x) + (a.r * a.r) -	 *     = a.z² - a.y² - a.x² + a.r² -	 * -	 * rot = ao_rotation * (0, 0, 0, -1) * ao_rotation° -	 *     = ((-a.z, -a.y, a.x, -a.r) * (a.r, -a.x, -a.y, -a.z)) .z -	 * -	 *     = (a.z * -a.z) + (-a.y * -a.y) - (a.x * -a.x) + (-a.r * a.r) -	 *     = -a.z² + a.y² + a.x² - a.r² -	 */ - -	float rotz; -	rotz = ao_rotation.z * ao_rotation.z - ao_rotation.y * ao_rotation.y - ao_rotation.x * ao_rotation.x + ao_rotation.r * ao_rotation.r; - -	ao_sample_orient = acosf(rotz) * (float) (180.0/M_PI); -  #if HAS_FLIGHT_DEBUG  	if (ao_orient_test) {  		printf ("rot %d %d %d orient %d     \r", @@ -229,7 +256,8 @@ ao_sample_rotate(void)  			ao_sample_orient);  	}  #endif - +	ao_sample_compute_orient(); +	ao_sample_set_one_orient();  }  #endif @@ -367,6 +395,7 @@ ao_sample_init(void)  	ao_sample_yaw = 0;  	ao_sample_roll = 0;  	ao_sample_orient = 0; +	ao_sample_set_all_orients();  #endif  	ao_sample_data = ao_data_head;  	ao_preflight = TRUE; diff --git a/src/kernel/ao_sample.h b/src/kernel/ao_sample.h index fbef031d..5ae389be 100644 --- a/src/kernel/ao_sample.h +++ b/src/kernel/ao_sample.h @@ -146,7 +146,10 @@ extern __pdata accel_t	ao_sample_accel_through;  extern __pdata gyro_t	ao_sample_roll;  extern __pdata gyro_t	ao_sample_pitch;  extern __pdata gyro_t	ao_sample_yaw; +#define AO_NUM_ORIENT	64  extern __pdata angle_t	ao_sample_orient; +extern __pdata angle_t	ao_sample_orients[AO_NUM_ORIENT]; +extern __pdata uint8_t	ao_sample_orient_pos;  #endif  void ao_sample_init(void); diff --git a/src/kernel/ao_usb.h b/src/kernel/ao_usb.h index 936d939b..40516de1 100644 --- a/src/kernel/ao_usb.h +++ b/src/kernel/ao_usb.h @@ -41,7 +41,23 @@ ao_usb_pollchar(void);  void  ao_usb_flush(void); +#if AO_USB_HAS_IN2 +void +ao_usb_flush2(void); + +void +ao_usb_putchar2(char c); +#endif + +#if AO_USB_HAS_IN3 +void +ao_usb_flush3(void); + +void +ao_usb_putchar3(char c); +#endif  /* Enable the USB controller */ +  void  ao_usb_enable(void); @@ -107,6 +123,7 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];  #define AO_USB_OUT_EP		4  #define AO_USB_IN_EP		5  #define AO_USB_IN2_EP		6 +#define AO_USB_IN3_EP		7  #endif  #ifndef AO_USB_HAS_OUT @@ -125,6 +142,10 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];  #define AO_USB_HAS_IN2	0  #endif +#ifndef AO_USB_HAS_IN3 +#define AO_USB_HAS_IN3	0 +#endif +  /*   * USB bulk packets can only come in 8, 16, 32 and 64   * byte sizes, so we'll use 64 for everything diff --git a/src/mpusb-v3.0/.gitignore b/src/mpusb-v3.0/.gitignore new file mode 100644 index 00000000..7c1cb599 --- /dev/null +++ b/src/mpusb-v3.0/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +mpusb-v3.0-* diff --git a/src/mpusb-v3.0/Makefile b/src/mpusb-v3.0/Makefile new file mode 100644 index 00000000..96156741 --- /dev/null +++ b/src/mpusb-v3.0/Makefile @@ -0,0 +1,68 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	ao_whiten.h \ +	stm32f0.h \ +	Makefile + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_dma_stm.c \ +	ao_task.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_usb_stm.c \ +	ao_power.c \ +	ao_gpio.c \ +	ao_serial_stm.c + +PRODUCT=MicroPeakUSB-v3.0 +PRODUCT_DEF=-DMPUSB +IDPRODUCT=0x002b + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g + +PROGNAME=mpusb-v3.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_mpusb.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/mpusb-v3.0/ao_mpusb.c b/src/mpusb-v3.0/ao_mpusb.c new file mode 100644 index 00000000..dc30e197 --- /dev/null +++ b/src/mpusb-v3.0/ao_mpusb.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_serial.h> + +static struct ao_task ao_report_task; + +static void +ao_report(void) +{ +	int	c; +	ao_up_set_speed(AO_SERIAL_SPEED_9600); +	for (;;) { +		ao_arch_block_interrupts(); +		c = _ao_up_pollchar(); +		ao_arch_release_interrupts(); +		if (c == AO_READ_AGAIN) { +			flush(); +			c = ao_up_getchar(); +		} +		putchar(c); +	} +} + +int +main(void) +{ +	ao_clock_init(); + +	ao_task_init(); + +	ao_timer_init(); + +	ao_serial_init(); + +	ao_dma_init(); + +	ao_cmd_init(); + +	ao_usb_init(); + +	ao_add_task(&ao_report_task, ao_report, "report"); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/mpusb-v3.0/ao_pins.h b/src/mpusb-v3.0/ao_pins.h new file mode 100644 index 00000000..3e79aad3 --- /dev/null +++ b/src/mpusb-v3.0/ao_pins.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* Using TeleMetrum v1.9 board */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +#define IS_FLASH_LOADER	0 + +#define AO_POWER_MANAGEMENT	1 + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_EEPROM		0 +#define USE_INTERNAL_FLASH	0 +#define USE_STORAGE_CONFIG	0 +#define USE_EEPROM_CONFIG	0 + +#define HAS_BEEP		0 + +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#define HAS_SPI_0		0 + +#define LOW_LEVEL_DEBUG		0 + +#define HAS_SERIAL_2		1 +#define USE_SERIAL_2_STDIN	0 +#define SERIAL_2_PA2_PA3	1 +#define SERIAL_2_SWAP		0 +#define USE_SERIAL_2_FLOW	0 +#define USE_SERIAL_2_SW_FLOW	0 + +#define ao_up_getchar		ao_serial2_getchar +#define ao_up_putchar		ao_serial2_putchar +#define _ao_up_pollchar		_ao_serial2_pollchar +#define ao_up_set_speed		ao_serial2_set_speed + +#endif /* _AO_PINS_H_ */ diff --git a/src/mpusb-v3.0/flash-loader/.gitignore b/src/mpusb-v3.0/flash-loader/.gitignore new file mode 100644 index 00000000..1f8b3545 --- /dev/null +++ b/src/mpusb-v3.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +mpusb* diff --git a/src/mpusb-v3.0/flash-loader/Makefile b/src/mpusb-v3.0/flash-loader/Makefile new file mode 100644 index 00000000..8d0f9e42 --- /dev/null +++ b/src/mpusb-v3.0/flash-loader/Makefile @@ -0,0 +1,7 @@ +# +# AltOS flash loader build +# + +TOPDIR=../.. +HARDWARE=mpusb-v3.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/mpusb-v3.0/flash-loader/ao_pins.h b/src/mpusb-v3.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..7feb9362 --- /dev/null +++ b/src/mpusb-v3.0/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Debug port PA15 (pin 23) */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	(stm_gpioa) +#define AO_BOOT_APPLICATION_PIN		15 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/product/ao_flash_pins.h b/src/product/ao_flash_pins.h index ff8d3273..019b5425 100644 --- a/src/product/ao_flash_pins.h +++ b/src/product/ao_flash_pins.h @@ -25,6 +25,7 @@  #define HAS_USB			1  #define USE_USB_STDIO		0 +#define HAS_USB_DISABLE		0  #define HAS_BEEP		0  #define HAS_TASK		0  #define HAS_ECHO		0 diff --git a/src/stm-demo/Makefile b/src/stm-demo/Makefile index 869fb32f..d4569c1a 100644 --- a/src/stm-demo/Makefile +++ b/src/stm-demo/Makefile @@ -30,6 +30,8 @@ ALTOS_SRC = \  	ao_lcd_stm.c \  	ao_lcd_font.c \  	ao_mutex.c \ +	ao_storage.c \ +	ao_m25.c \  	ao_dma_stm.c \  	ao_spi_stm.c \  	ao_adc_stm.c \ diff --git a/src/stm-demo/ao_demo.c b/src/stm-demo/ao_demo.c index db432c2a..f6c8e3df 100644 --- a/src/stm-demo/ao_demo.c +++ b/src/stm-demo/ao_demo.c @@ -223,11 +223,12 @@ main(void)  	ao_cmd_init();  //	ao_lcd_stm_init();  //	ao_lcd_font_init(); -//	ao_spi_init(); +	ao_spi_init();  //	ao_i2c_init();  //	ao_exti_init();  //	ao_quadrature_init();  //	ao_button_init(); +	ao_storage_init();  //	ao_timer_set_adc_interval(100); diff --git a/src/stm-demo/ao_pins.h b/src/stm-demo/ao_pins.h index 233537df..2b4c5ab0 100644 --- a/src/stm-demo/ao_pins.h +++ b/src/stm-demo/ao_pins.h @@ -59,11 +59,14 @@  #define SERIAL_3_PC10_PC11	0  #define SERIAL_3_PD8_PD9	1 -#define HAS_SPI_1		1 +#define HAS_SPI_1		0  #define SPI_1_PB3_PB4_PB5	1  #define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz -#define HAS_SPI_2		0 +#define HAS_SPI_2		1 +#define SPI_2_PB13_PB14_PB15	1	/* Flash, Companion, Radio */ +#define SPI_2_PD1_PD3_PD4	0 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz  #define HAS_USB			1  #define HAS_BEEP		0 @@ -200,4 +203,11 @@ struct ao_adc {  #define AO_TICK_TYPE		uint32_t  #define AO_TICK_SIGNED		int32_t +#define M25_MAX_CHIPS		1 +#define AO_M25_SPI_CS_PORT	(&stm_gpiob) +#define AO_M25_SPI_CS_MASK	(1 << 12) +#define AO_M25_SPI_BUS		AO_SPI_2_PB13_PB14_PB15 + +#define AO_LOG_FORMAT				AO_LOG_FORMAT_TELEMEGA +  #endif /* _AO_PINS_H_ */ diff --git a/src/stm/ao_adc_single.h b/src/stm/ao_adc_single.h new file mode 100644 index 00000000..f9d953ca --- /dev/null +++ b/src/stm/ao_adc_single.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_ADC_SINGLE_H_ +#define _AO_ADC_SINGLE_H_ + +void +ao_adc_single_get(struct ao_adc *packet); + +void +ao_adc_single_init(void); + +#endif /* _AO_ADC_SINGLE_H_ */ diff --git a/src/stm/ao_adc_single_stm.c b/src/stm/ao_adc_single_stm.c new file mode 100644 index 00000000..8a7fda4a --- /dev/null +++ b/src/stm/ao_adc_single_stm.c @@ -0,0 +1,297 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_data.h> + +static uint8_t			ao_adc_ready; + +#define AO_ADC_CR2_VAL		((0 << STM_ADC_CR2_SWSTART) |		\ +				 (STM_ADC_CR2_EXTEN_DISABLE << STM_ADC_CR2_EXTEN) | \ +				 (0 << STM_ADC_CR2_EXTSEL) |		\ +				 (0 << STM_ADC_CR2_JWSTART) |		\ +				 (STM_ADC_CR2_JEXTEN_DISABLE << STM_ADC_CR2_JEXTEN) | \ +				 (0 << STM_ADC_CR2_JEXTSEL) |		\ +				 (0 << STM_ADC_CR2_ALIGN) |		\ +				 (0 << STM_ADC_CR2_EOCS) |		\ +				 (1 << STM_ADC_CR2_DDS) |		\ +				 (1 << STM_ADC_CR2_DMA) |		\ +				 (STM_ADC_CR2_DELS_UNTIL_READ << STM_ADC_CR2_DELS) | \ +				 (0 << STM_ADC_CR2_CONT) |		\ +				 (1 << STM_ADC_CR2_ADON)) + +/* + * Callback from DMA ISR + * + * Shut down DMA engine, signal anyone waiting + */ +static void ao_adc_done(int index) +{ +	(void) index; +	ao_dma_done_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1)); +	ao_adc_ready = 1; +	ao_wakeup((void *) &ao_adc_ready); +} + +/* + * Start the ADC sequence using the DMA engine + */ +static void +ao_adc_poll(struct ao_adc *packet) +{ +	ao_adc_ready = 0; +	stm_adc.sr = 0; +	ao_dma_set_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1), +			    &stm_adc.dr, +			    (void *) packet, +			    AO_NUM_ADC, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); +	ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1), ao_adc_done); +	ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1)); + +	stm_adc.cr2 = AO_ADC_CR2_VAL | (1 << STM_ADC_CR2_SWSTART); +} + +/* + * Fetch a copy of the most recent ADC data + */ +void +ao_adc_single_get(struct ao_adc *packet) +{ +	ao_adc_poll(packet); +	ao_arch_block_interrupts(); +	while (!ao_adc_ready) +		ao_sleep(&ao_adc_ready); +	ao_arch_release_interrupts(); +} + +static void +ao_adc_dump(void) +{ +	struct ao_adc	packet; +	ao_adc_single_get(&packet); +	AO_ADC_DUMP(&packet); +} + +__code struct ao_cmds ao_adc_cmds[] = { +	{ ao_adc_dump,	"a\0Display current ADC values" }, +	{ 0, NULL }, +}; + +void +ao_adc_single_init(void) +{ +#ifdef AO_ADC_PIN0_PORT +	stm_rcc.ahbenr |= AO_ADC_RCC_AHBENR; +#endif + +#ifdef AO_ADC_PIN0_PORT +	stm_moder_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN1_PORT +	stm_moder_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN2_PORT +	stm_moder_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN3_PORT +	stm_moder_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN4_PORT +	stm_moder_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN5_PORT +	stm_moder_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN6_PORT +	stm_moder_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN7_PORT +	stm_moder_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN8_PORT +	stm_moder_set(AO_ADC_PIN8_PORT, AO_ADC_PIN8_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN9_PORT +	stm_moder_set(AO_ADC_PIN9_PORT, AO_ADC_PIN9_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN10_PORT +	stm_moder_set(AO_ADC_PIN10_PORT, AO_ADC_PIN10_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN11_PORT +	stm_moder_set(AO_ADC_PIN11_PORT, AO_ADC_PIN11_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN12_PORT +	stm_moder_set(AO_ADC_PIN12_PORT, AO_ADC_PIN12_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN13_PORT +	stm_moder_set(AO_ADC_PIN13_PORT, AO_ADC_PIN13_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN14_PORT +	stm_moder_set(AO_ADC_PIN14_PORT, AO_ADC_PIN14_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN15_PORT +	stm_moder_set(AO_ADC_PIN15_PORT, AO_ADC_PIN15_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN16_PORT +	stm_moder_set(AO_ADC_PIN16_PORT, AO_ADC_PIN16_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN17_PORT +	stm_moder_set(AO_ADC_PIN17_PORT, AO_ADC_PIN17_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN18_PORT +	stm_moder_set(AO_ADC_PIN18_PORT, AO_ADC_PIN18_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN19_PORT +	stm_moder_set(AO_ADC_PIN19_PORT, AO_ADC_PIN19_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN20_PORT +	stm_moder_set(AO_ADC_PIN20_PORT, AO_ADC_PIN20_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN21_PORT +	stm_moder_set(AO_ADC_PIN21_PORT, AO_ADC_PIN21_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN22_PORT +	stm_moder_set(AO_ADC_PIN22_PORT, AO_ADC_PIN22_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN23_PORT +	stm_moder_set(AO_ADC_PIN23_PORT, AO_ADC_PIN23_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN24_PORT +	#error "Too many ADC ports" +#endif + +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADC1EN); + +	/* Turn off ADC during configuration */ +	stm_adc.cr2 = 0; + +	stm_adc.cr1 = ((0 << STM_ADC_CR1_OVRIE ) | +		       (STM_ADC_CR1_RES_12 << STM_ADC_CR1_RES ) | +		       (0 << STM_ADC_CR1_AWDEN ) | +		       (0 << STM_ADC_CR1_JAWDEN ) | +		       (0 << STM_ADC_CR1_PDI ) | +		       (0 << STM_ADC_CR1_PDD ) | +		       (0 << STM_ADC_CR1_DISCNUM ) | +		       (0 << STM_ADC_CR1_JDISCEN ) | +		       (0 << STM_ADC_CR1_DISCEN ) | +		       (0 << STM_ADC_CR1_JAUTO ) | +		       (0 << STM_ADC_CR1_AWDSGL ) | +		       (1 << STM_ADC_CR1_SCAN ) | +		       (0 << STM_ADC_CR1_JEOCIE ) | +		       (0 << STM_ADC_CR1_AWDIE ) | +		       (0 << STM_ADC_CR1_EOCIE ) | +		       (0 << STM_ADC_CR1_AWDCH )); + +	/* 384 cycle sample time for everyone */ +	stm_adc.smpr1 = 0x3ffff; +	stm_adc.smpr2 = 0x3fffffff; +	stm_adc.smpr3 = 0x3fffffff; + +	stm_adc.sqr1 = ((AO_NUM_ADC - 1) << 20); +	stm_adc.sqr2 = 0; +	stm_adc.sqr3 = 0; +	stm_adc.sqr4 = 0; +	stm_adc.sqr5 = 0; +#if AO_NUM_ADC > 0 +	stm_adc.sqr5 |= (AO_ADC_SQ1 << 0); +#endif +#if AO_NUM_ADC > 1 +	stm_adc.sqr5 |= (AO_ADC_SQ2 << 5); +#endif +#if AO_NUM_ADC > 2 +	stm_adc.sqr5 |= (AO_ADC_SQ3 << 10); +#endif +#if AO_NUM_ADC > 3 +	stm_adc.sqr5 |= (AO_ADC_SQ4 << 15); +#endif +#if AO_NUM_ADC > 4 +	stm_adc.sqr5 |= (AO_ADC_SQ5 << 20); +#endif +#if AO_NUM_ADC > 5 +	stm_adc.sqr5 |= (AO_ADC_SQ6 << 25); +#endif +#if AO_NUM_ADC > 6 +	stm_adc.sqr4 |= (AO_ADC_SQ7 << 0); +#endif +#if AO_NUM_ADC > 7 +	stm_adc.sqr4 |= (AO_ADC_SQ8 << 5); +#endif +#if AO_NUM_ADC > 8 +	stm_adc.sqr4 |= (AO_ADC_SQ9 << 10); +#endif +#if AO_NUM_ADC > 9 +	stm_adc.sqr4 |= (AO_ADC_SQ10 << 15); +#endif +#if AO_NUM_ADC > 10 +	stm_adc.sqr4 |= (AO_ADC_SQ11 << 20); +#endif +#if AO_NUM_ADC > 11 +	stm_adc.sqr4 |= (AO_ADC_SQ12 << 25); +#endif +#if AO_NUM_ADC > 12 +	stm_adc.sqr3 |= (AO_ADC_SQ13 << 0); +#endif +#if AO_NUM_ADC > 13 +	stm_adc.sqr3 |= (AO_ADC_SQ14 << 5); +#endif +#if AO_NUM_ADC > 14 +	stm_adc.sqr3 |= (AO_ADC_SQ15 << 10); +#endif +#if AO_NUM_ADC > 15 +	stm_adc.sqr3 |= (AO_ADC_SQ16 << 15); +#endif +#if AO_NUM_ADC > 16 +	stm_adc.sqr3 |= (AO_ADC_SQ17 << 20); +#endif +#if AO_NUM_ADC > 17 +	stm_adc.sqr3 |= (AO_ADC_SQ18 << 25); +#endif +#if AO_NUM_ADC > 18 +#error "need to finish stm_adc.sqr settings" +#endif + +	/* Turn ADC on */ +	stm_adc.cr2 = AO_ADC_CR2_VAL; + +	/* Wait for ADC to be ready */ +	while (!(stm_adc.sr & (1 << STM_ADC_SR_ADONS))) +		; + +#ifndef HAS_ADC_TEMP +#error Please define HAS_ADC_TEMP +#endif +#if HAS_ADC_TEMP +	stm_adc.ccr = ((1 << STM_ADC_CCR_TSVREFE)); +#else +	stm_adc.ccr = 0; +#endif +	/* Clear any stale status bits */ +	stm_adc.sr = 0; + +	ao_dma_alloc(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1)); + +	ao_cmd_register(&ao_adc_cmds[0]); +} diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 5f033b66..679dba44 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -30,8 +30,6 @@  #define AO_STACK_SIZE	512  #endif -#define AO_LED_TYPE	uint16_t -  #ifndef AO_TICK_TYPE  #define AO_TICK_TYPE	uint16_t  #define AO_TICK_SIGNED	int16_t @@ -153,6 +151,10 @@ ao_adc_init();  #define AO_BOOT_LOADER_BASE		((uint32_t *) 0x08000000)  #define HAS_BOOT_LOADER			1 +#ifndef AO_LED_TYPE +#define AO_LED_TYPE uint16_t +#endif +  #endif /* _AO_ARCH_H_ */ diff --git a/src/stm/ao_led.c b/src/stm/ao_led.c index 0f39befb..a7033dbb 100644 --- a/src/stm/ao_led.c +++ b/src/stm/ao_led.c @@ -18,11 +18,73 @@  #include "ao.h" -__pdata uint16_t ao_led_enable; +#if LED_PER_LED +static const struct { +	struct stm_gpio	*port; +	uint16_t	pin; +} ao_leds[] = { +#ifdef LED_0_PORT +    [0] { LED_0_PORT, LED_0_PIN }, +#endif +#ifdef LED_1_PORT +    [1] { LED_1_PORT, LED_1_PIN }, +#endif +#ifdef LED_2_PORT +    [2] { LED_2_PORT, LED_2_PIN }, +#endif +#ifdef LED_3_PORT +    [3] { LED_3_PORT, LED_3_PIN }, +#endif +#ifdef LED_4_PORT +    [4] { LED_4_PORT, LED_4_PIN }, +#endif +#ifdef LED_5_PORT +    [5] { LED_5_PORT, LED_5_PIN }, +#endif +#ifdef LED_6_PORT +    [6] { LED_6_PORT, LED_6_PIN }, +#endif +#ifdef LED_7_PORT +    [7] { LED_7_PORT, LED_7_PIN }, +#endif +#ifdef LED_8_PORT +    [8] { LED_8_PORT, LED_8_PIN }, +#endif +#ifdef LED_9_PORT +    [9] { LED_9_PORT, LED_9_PIN }, +#endif +#ifdef LED_10_PORT +    [10] { LED_10_PORT, LED_10_PIN }, +#endif +#ifdef LED_11_PORT +    [11] { LED_11_PORT, LED_11_PIN }, +#endif +#ifdef LED_12_PORT +    [12] { LED_12_PORT, LED_12_PIN }, +#endif +#ifdef LED_13_PORT +    [13] { LED_13_PORT, LED_13_PIN }, +#endif +#ifdef LED_14_PORT +    [14] { LED_14_PORT, LED_14_PIN }, +#endif +#ifdef LED_15_PORT +    [15] { LED_15_PORT, LED_15_PIN }, +#endif +}; +#define N_LED	(sizeof (ao_leds)/sizeof(ao_leds[0])) +#endif +static AO_LED_TYPE ao_led_enable;  void -ao_led_on(uint16_t colors) +ao_led_on(AO_LED_TYPE colors)  { +#ifdef LED_PER_LED +	AO_LED_TYPE i; +	for (i = 0; i < N_LED; i++) +		if (colors & (1 << i)) +			ao_gpio_set(ao_leds[i].port, ao_leds[i].pin, foo, 1); +#else  #ifdef LED_PORT  	LED_PORT->bsrr = (colors & ao_led_enable);  #else @@ -33,11 +95,18 @@ ao_led_on(uint16_t colors)  	LED_PORT_1->bsrr = ((colors & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT;  #endif  #endif +#endif  }  void -ao_led_off(uint16_t colors) +ao_led_off(AO_LED_TYPE colors)  { +#ifdef LED_PER_LED +	AO_LED_TYPE i; +	for (i = 0; i < N_LED; i++) +		if (colors & (1 << i)) +			ao_gpio_set(ao_leds[i].port, ao_leds[i].pin, foo, 0); +#else  #ifdef LED_PORT  	LED_PORT->bsrr = (uint32_t) (colors & ao_led_enable) << 16;  #else @@ -48,21 +117,28 @@ ao_led_off(uint16_t colors)  	LED_PORT_1->bsrr = ((uint32_t) (colors & ao_led_enable) & LED_PORT_1_MASK) << (LED_PORT_1_SHIFT + 16);  #endif  #endif +#endif  }  void -ao_led_set(uint16_t colors) +ao_led_set(AO_LED_TYPE colors)  { -	uint16_t	on = colors & ao_led_enable; -	uint16_t	off = ~colors & ao_led_enable; +	AO_LED_TYPE	on = colors & ao_led_enable; +	AO_LED_TYPE	off = ~colors & ao_led_enable;  	ao_led_off(off);  	ao_led_on(on);  }  void -ao_led_toggle(uint16_t colors) +ao_led_toggle(AO_LED_TYPE colors)  { +#ifdef LED_PER_LED +	AO_LED_TYPE i; +	for (i = 0; i < N_LED; i++) +		if (colors & (1 << i)) +			ao_gpio_set(ao_leds[i].port, ao_leds[i].pin, foo, ~ao_gpio_get(ao_leds[i].port, ao_leds[i].pin, foo)); +#else  #ifdef LED_PORT  	LED_PORT->odr ^= (colors & ao_led_enable);  #else @@ -73,10 +149,11 @@ ao_led_toggle(uint16_t colors)  	LED_PORT_1->odr ^= ((colors & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT;  #endif  #endif +#endif  }  void -ao_led_for(uint16_t colors, uint16_t ticks) __reentrant +ao_led_for(AO_LED_TYPE colors, AO_LED_TYPE ticks) __reentrant  {  	ao_led_on(colors);  	ao_delay(ticks); @@ -89,11 +166,15 @@ ao_led_for(uint16_t colors, uint16_t ticks) __reentrant  	} while (0)  void -ao_led_init(uint16_t enable) +ao_led_init(AO_LED_TYPE enable)  { -	int	bit; +	AO_LED_TYPE	bit;  	ao_led_enable = enable; +#if LED_PER_LED +	for (bit = 0; bit < N_LED; bit++) +		ao_enable_output(ao_leds[bit].port, ao_leds[bit].pin, foo, 0); +#else  #ifdef LED_PORT  	stm_rcc.ahbenr |= (1 << LED_PORT_ENABLE);  	LED_PORT->odr &= ~enable; @@ -106,6 +187,10 @@ ao_led_init(uint16_t enable)  	stm_rcc.ahbenr |= (1 << LED_PORT_1_ENABLE);  	LED_PORT_1->odr &= ~((enable & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT;  #endif +#ifdef LED_PORT_2 +	stm_rcc.ahbenr |= (1 << LED_PORT_1_ENABLE); +	LED_PORT_1->odr &= ~((enable & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT; +#endif  #endif  	for (bit = 0; bit < 16; bit++) {  		if (enable & (1 << bit)) { @@ -120,7 +205,12 @@ ao_led_init(uint16_t enable)  			if (LED_PORT_1_MASK & (1 << bit))  				init_led_pin(LED_PORT_1, bit + LED_PORT_1_SHIFT);  #endif +#ifdef LED_PORT_2 +			if (LED_PORT_2_MASK & (1 << bit)) +				init_led_pin(LED_PORT_2, bit + LED_PORT_2_SHIFT); +#endif  #endif  		}  	} +#endif  } diff --git a/src/stm/ao_romconfig.c b/src/stm/ao_romconfig.c index 9d5fd6fb..63a48bec 100644 --- a/src/stm/ao_romconfig.c +++ b/src/stm/ao_romconfig.c @@ -24,5 +24,6 @@ AO_ROMCONFIG_SYMBOL (0) uint16_t ao_serial_number = 0;  #ifndef AO_RADIO_CAL_DEFAULT  #define AO_RADIO_CAL_DEFAULT 0x01020304  #endif +#if HAS_RADIO  AO_ROMCONFIG_SYMBOL (0) uint32_t ao_radio_cal = AO_RADIO_CAL_DEFAULT; - +#endif diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 1576a6c9..7b526902 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -149,7 +149,7 @@ ao_clock_init(void)  #define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK	(0 << STM_RCC_CFGR_PLLSRC)  #endif -#if !AO_HSE || HAS_ADC +#if !AO_HSE || HAS_ADC || HAS_ADC_SINGLE  	/* Enable HSI RC clock 16MHz */  	stm_rcc.cr |= (1 << STM_RCC_CR_HSION);  	while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY))) diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 595bddac..b06814d2 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -446,15 +446,11 @@ ao_usb_write_short(uint16_t data, uint32_t *base, uint16_t offset)  }  static void -ao_usb_write(const uint8_t *src, uint32_t *base, uint16_t offset, uint16_t bytes) +ao_usb_write(const uint8_t *src, uint32_t *base, uint16_t bytes)  { +	uint16_t offset = 0;  	if (!bytes)  		return; -	if (offset & 1) { -		debug_data (" %02x", src[0]); -		ao_usb_write_byte(*src++, base, offset++); -		bytes--; -	}  	while (bytes >= 2) {  		debug_data (" %02x %02x", src[0], src[1]);  		ao_usb_write_short((src[1] << 8) | src[0], base, offset); @@ -531,7 +527,7 @@ ao_usb_ep0_flush(void)  	ao_usb_ep0_in_len -= this_len;  	debug_data ("Flush EP0 len %d:", this_len); -	ao_usb_write(ao_usb_ep0_in_data, ao_usb_ep0_tx_buffer, 0, this_len); +	ao_usb_write(ao_usb_ep0_in_data, ao_usb_ep0_tx_buffer, this_len);  	debug_data ("\n");  	ao_usb_ep0_in_data += this_len; @@ -850,7 +846,7 @@ _ao_usb_in_send(void)  	ao_usb_in_pending = 1;  	if (ao_usb_tx_count != AO_USB_IN_SIZE)  		ao_usb_in_flushed = 1; -	ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, 0, ao_usb_tx_count); +	ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, ao_usb_tx_count);  	ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = ao_usb_tx_count;  	ao_usb_tx_count = 0;  	_ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); @@ -974,6 +970,11 @@ ao_usb_getchar(void)  	return c;  } +#ifndef HAS_USB_DISABLE +#define HAS_USB_DISABLE 1 +#endif + +#if HAS_USB_DISABLE  void  ao_usb_disable(void)  { @@ -991,6 +992,7 @@ ao_usb_disable(void)  	stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USBEN);  	ao_arch_release_interrupts();  } +#endif  void  ao_usb_enable(void) diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 201f4f36..1da817e7 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -1454,6 +1454,9 @@ struct stm_adc {  extern struct stm_adc stm_adc; +#define STM_ADC_SQ_TEMP		16 +#define STM_ADC_SQ_V_REF	17 +  #define STM_ADC_SR_JCNR		9  #define STM_ADC_SR_RCNR		8  #define STM_ADC_SR_ADONS	6 diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index 56a3bc75..96c033f9 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -171,10 +171,12 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s  #define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)  #define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus) +#if AO_POWER_MANAGEMENT  extern struct ao_power	ao_power_gpioa;  extern struct ao_power	ao_power_gpiob;  extern struct ao_power	ao_power_gpioc;  extern struct ao_power	ao_power_gpiof; +#endif  static inline void ao_enable_port(struct stm_gpio *port)  { diff --git a/src/stmf0/ao_flash_loader_stm.c b/src/stmf0/ao_flash_loader_stm.c index a8d1701b..18bf272c 100644 --- a/src/stmf0/ao_flash_loader_stm.c +++ b/src/stmf0/ao_flash_loader_stm.c @@ -34,7 +34,7 @@ main(void)  #ifdef AO_FLASH_LOADER_INIT  	AO_FLASH_LOADER_INIT; -#endif	 +#endif  	ao_flash_task();  	return 0;  } diff --git a/src/stmf0/ao_interrupt.c b/src/stmf0/ao_interrupt.c index fcd330f1..a67f6f1a 100644 --- a/src/stmf0/ao_interrupt.c +++ b/src/stmf0/ao_interrupt.c @@ -69,20 +69,24 @@ stm_flash_size(void) {  void start(void)  { -#ifdef AO_BOOT_CHAIN +#if AO_BOOT_CHAIN  	if (ao_boot_check_chain()) { -#ifdef AO_BOOT_PIN +#if AO_BOOT_PIN  		ao_boot_check_pin();  #endif  	}  #endif -#if RELOCATE_INTERRUPT  	/* Turn on syscfg */  	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); +#if RELOCATE_INTERRUPT  	memcpy(&__interrupt_start__, &__interrupt_rom__, &__interrupt_end__ - &__interrupt_start__);  	stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) |  		(STM_SYSCFG_CFGR1_MEM_MODE_SRAM << STM_SYSCFG_CFGR1_MEM_MODE); +#else +	/* Switch to Main Flash mode (DFU loader leaves us in System mode) */ +	stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) | +		(STM_SYSCFG_CFGR1_MEM_MODE_MAIN_FLASH << STM_SYSCFG_CFGR1_MEM_MODE);  #endif  	memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);  	memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__); diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c index bf08abc1..c4860d8e 100644 --- a/src/stmf0/ao_usb_stm.c +++ b/src/stmf0/ao_usb_stm.c @@ -113,6 +113,12 @@ static uint8_t	ao_usb_in_tx2_which;  static uint8_t	ao_usb_tx2_count;  #endif +#if AO_USB_HAS_IN3 +static uint16_t ao_usb_in_tx3_offset; +static uint8_t	ao_usb_in_tx3_which; +static uint8_t	ao_usb_tx3_count; +#endif +  /*   * End point register indices   */ @@ -122,6 +128,7 @@ static uint8_t	ao_usb_tx2_count;  #define AO_USB_OUT_EPR		2  #define AO_USB_IN_EPR		3  #define AO_USB_IN2_EPR		4 +#define AO_USB_IN3_EPR		5  /* Marks when we don't need to send an IN packet.   * This happens only when the last IN packet is not full, @@ -146,6 +153,16 @@ static uint16_t	in2_count;  static uint8_t	ao_usb_in2_flushed;  #endif +#if AO_USB_HAS_IN3 +/* Marks when we have delivered an IN packet to the hardware + * and it has not been received yet. ao_sleep on this address + * to wait for it to be delivered. + */ +static uint8_t	ao_usb_in3_pending; +static uint16_t	in3_count; +static uint8_t	ao_usb_in3_flushed; +#endif +  /* Marks when an OUT packet has been received by the hardware   * but not pulled to the shadow buffer.   */ @@ -423,6 +440,11 @@ ao_usb_alloc_buffers(void)  	ao_usb_in_tx2_offset = sram_addr;  	sram_addr += AO_USB_IN_SIZE * 2;  #endif +#if AO_USB_HAS_IN3 +	sram_addr += (sram_addr & 1); +	ao_usb_in_tx3_offset = sram_addr; +	sram_addr += AO_USB_IN_SIZE * 2; +#endif  }  static void @@ -558,6 +580,25 @@ ao_usb_set_configuration(void)  	ao_usb_in_tx2_which = 0;  #endif +#if AO_USB_HAS_IN3 +	/* Set up the IN3 end point */ +	stm_usb_bdt[AO_USB_IN3_EPR].double_tx[0].addr = ao_usb_in_tx3_offset; +	stm_usb_bdt[AO_USB_IN3_EPR].double_tx[0].count = 0; +	stm_usb_bdt[AO_USB_IN3_EPR].double_tx[1].addr = ao_usb_in_tx3_offset + AO_USB_IN_SIZE; +	stm_usb_bdt[AO_USB_IN3_EPR].double_tx[1].count = 0; + +	ao_usb_init_ep(AO_USB_IN3_EPR, +		       AO_USB_IN3_EP, +		       STM_USB_EPR_EP_TYPE_BULK, +		       STM_USB_EPR_STAT_RX_DISABLED, +		       STM_USB_EPR_STAT_TX_NAK, +		       STM_USB_EPR_EP_KIND_DBL_BUF, +		       0, 1); + +	/* First transmit data goes to buffer 0 */ +	ao_usb_in_tx3_which = 0; +#endif +  	ao_usb_in_flushed = 0;  	ao_usb_in_pending = 0;  	ao_wakeup(&ao_usb_in_pending); @@ -567,6 +608,12 @@ ao_usb_set_configuration(void)  	ao_wakeup(&ao_usb_in2_pending);  #endif +#if AO_USB_HAS_IN3 +	ao_usb_in3_flushed = 0; +	ao_usb_in3_pending = 0; +	ao_wakeup(&ao_usb_in3_pending); +#endif +  	ao_usb_out_avail = 0;  	ao_usb_configuration = 0; @@ -996,6 +1043,16 @@ stm_usb_isr(void)  			}  			break;  #endif +#if AO_USB_HAS_IN3 +		case AO_USB_IN3_EPR: +			++in3_count; +			_tx_dbg1("TX3 ISR", epr); +			if (ao_usb_epr_ctr_tx(epr)) { +				ao_usb_in3_pending = 0; +				ao_wakeup(&ao_usb_in3_pending); +			} +			break; +#endif  		case AO_USB_INT_EPR:  #if USB_STATUS  			++int_count; @@ -1132,6 +1189,9 @@ _ao_usb_in2_send(void)  	/* Toggle our usage */  	ao_usb_in_tx2_which = 1 - ao_usb_in_tx2_which; +	/* Toggle the SW_BUF flag */ +	_ao_usb_toggle_dtog(AO_USB_IN2_EPR, 1, 0); +  	/* Mark the outgoing buffer as valid */  	_ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID); @@ -1199,6 +1259,94 @@ ao_usb_putchar2(char c)  }  #endif +#if AO_USB_HAS_IN3 +/* Queue the current IN buffer for transmission */ +static void +_ao_usb_in3_send(void) +{ +	_tx_dbg0("in3_send start"); +	debug ("send3 %d\n", ao_usb_tx3_count); +	while (ao_usb_in3_pending) +		ao_sleep(&ao_usb_in3_pending); +	ao_usb_in3_pending = 1; +	if (ao_usb_tx3_count != AO_USB_IN_SIZE) +		ao_usb_in3_flushed = 1; +	stm_usb_bdt[AO_USB_IN3_EPR].double_tx[ao_usb_in_tx3_which].count = ao_usb_tx3_count; +	ao_usb_tx3_count = 0; + +	/* Toggle our usage */ +	ao_usb_in_tx3_which = 1 - ao_usb_in_tx3_which; + +	/* Toggle the SW_BUF flag */ +	_ao_usb_toggle_dtog(AO_USB_IN3_EPR, 1, 0); + +	/* Mark the outgoing buffer as valid */ +	_ao_usb_set_stat_tx(AO_USB_IN3_EPR, STM_USB_EPR_STAT_TX_VALID); + +	_tx_dbg0("in3_send end"); +} + +/* Wait for a free IN buffer. Interrupts are blocked */ +static void +_ao_usb_in3_wait(void) +{ +	for (;;) { +		/* Check if the current buffer is writable */ +		if (ao_usb_tx3_count < AO_USB_IN_SIZE) +			break; + +		_tx_dbg0("in3_wait top"); +		/* Wait for an IN buffer to be ready */ +		while (ao_usb_in3_pending) +			ao_sleep(&ao_usb_in3_pending); +		_tx_dbg0("in_wait bottom"); +	} +} + +void +ao_usb_flush3(void) +{ +	if (!ao_usb_running) +		return; + +	/* Anytime we've sent a character since +	 * the last time we flushed, we'll need +	 * to send a packet -- the only other time +	 * we would send a packet is when that +	 * packet was full, in which case we now +	 * want to send an empty packet +	 */ +	ao_arch_block_interrupts(); +	while (!ao_usb_in3_flushed) { +		_tx_dbg0("flush3 top"); +		_ao_usb_in3_send(); +		_tx_dbg0("flush3 end"); +	} +	ao_arch_release_interrupts(); +} + +void +ao_usb_putchar3(char c) +{ +	if (!ao_usb_running) +		return; + +	ao_arch_block_interrupts(); +	_ao_usb_in3_wait(); + +	ao_usb_in3_flushed = 0; +	ao_usb_tx_byte(ao_usb_in_tx3_offset + AO_USB_IN_SIZE * ao_usb_in_tx3_which + ao_usb_tx3_count++, c); + +	/* Send the packet when full */ +	if (ao_usb_tx3_count == AO_USB_IN_SIZE) { +		_tx_dbg0("putchar3 full"); +		_ao_usb_in3_send(); +		_tx_dbg0("putchar3 flushed"); +	} +	ao_arch_release_interrupts(); +} +#endif +  #if AO_USB_HAS_OUT  static void  _ao_usb_out_recv(void) @@ -1447,7 +1595,7 @@ ao_usb_enable(void)  	ao_arch_release_interrupts(); -	for (t = 0; t < 1000; t++) +	for (t = 0; t < 50000; t++)  		ao_arch_nop();  	/* Enable USB pull-up */ @@ -1541,9 +1689,9 @@ struct ao_usb_dbg {  #endif  }; -#define NUM_USB_DBG	128 +#define NUM_USB_DBG	16 -struct ao_usb_dbg dbg[128]; +struct ao_usb_dbg dbg[NUM_USB_DBG];  int dbg_i;  static void _dbg(int line, char *msg, uint32_t value) @@ -1555,11 +1703,11 @@ static void _dbg(int line, char *msg, uint32_t value)  	asm("mrs %0,primask" : "=&r" (primask));  	dbg[dbg_i].primask = primask;  #if TX_DBG -	dbg[dbg_i].in_count = in_count; -	dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; -	dbg[dbg_i].in_pending = ao_usb_in_pending; -	dbg[dbg_i].tx_count = ao_usb_tx_count; -	dbg[dbg_i].in_flushed = ao_usb_in_flushed; +	dbg[dbg_i].in_count = in3_count; +	dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN3_EPR].r; +	dbg[dbg_i].in_pending = ao_usb_in3_pending; +	dbg[dbg_i].tx_count = ao_usb_tx3_count; +	dbg[dbg_i].in_flushed = ao_usb_in3_flushed;  #endif  #if RX_DBG  	dbg[dbg_i].rx_count = ao_usb_rx_count; diff --git a/src/telefire-v0.1/ao_pins.h b/src/telefire-v0.1/ao_pins.h index ee0ca716..8266589e 100644 --- a/src/telefire-v0.1/ao_pins.h +++ b/src/telefire-v0.1/ao_pins.h @@ -100,10 +100,17 @@  #define AO_STROBE_PIN		1  #define AO_STROBE		P1_1 -/* test these values with real igniters */ -#define AO_PAD_RELAY_CLOSED	3524 -#define AO_PAD_NO_IGNITER	16904 -#define AO_PAD_GOOD_IGNITER	22514 +#define AO_ADC_REFERENCE_DV	33 +#define AO_PAD_R_V_BATT_BATT_SENSE	100 +#define AO_PAD_R_BATT_SENSE_GND		27 + +#define AO_PAD_R_V_BATT_V_PYRO		100 +#define AO_PAD_R_V_PYRO_PYRO_SENSE	100 +#define AO_PAD_R_PYRO_SENSE_GND		27 + +#define AO_PAD_R_V_PYRO_IGNITER		100 +#define AO_PAD_R_IGNITER_IGNITER_SENSE	100 +#define AO_PAD_R_IGNITER_SENSE_GND	27  #define AO_PAD_ADC_PYRO		4  #define AO_PAD_ADC_BATT		5 diff --git a/src/telefire-v0.2/ao_pins.h b/src/telefire-v0.2/ao_pins.h index 4faeb65f..65f5bdcc 100644 --- a/src/telefire-v0.2/ao_pins.h +++ b/src/telefire-v0.2/ao_pins.h @@ -111,15 +111,24 @@  #define AO_STROBE		P2_4  /* test these values with real igniters */ -#define AO_PAD_RELAY_CLOSED	3524 -#define AO_PAD_NO_IGNITER	16904 -#define AO_PAD_GOOD_IGNITER	22514 -  #define AO_PAD_ADC_PYRO		4  #define AO_PAD_ADC_BATT		5  #define AO_ADC_FIRST_PIN	0 +#define AO_ADC_REFERENCE_DV	33 +#define AO_PAD_R_V_BATT_BATT_SENSE	100 +#define AO_PAD_R_BATT_SENSE_GND		27 + +#define AO_PAD_R_V_BATT_V_PYRO		100 +#define AO_PAD_R_V_PYRO_PYRO_SENSE	100 +#define AO_PAD_R_PYRO_SENSE_GND		27 + +#define AO_PAD_R_V_PYRO_IGNITER		100 +#define AO_PAD_R_IGNITER_IGNITER_SENSE	100 +#define AO_PAD_R_IGNITER_SENSE_GND	27 + +  struct ao_adc {  	int16_t		sense[AO_PAD_NUM];  	int16_t		pyro; diff --git a/src/telefireeight-v1.0/.gitignore b/src/telefireeight-v1.0/.gitignore new file mode 100644 index 00000000..22f7e9ef --- /dev/null +++ b/src/telefireeight-v1.0/.gitignore @@ -0,0 +1,2 @@ +telefireeight-* +ao_product.h diff --git a/src/telefireeight-v1.0/Makefile b/src/telefireeight-v1.0/Makefile new file mode 100644 index 00000000..200c3150 --- /dev/null +++ b/src/telefireeight-v1.0/Makefile @@ -0,0 +1,90 @@ +# +# TeleFire build file +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_pins.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pad.h \ +	ao_product.h \ +	ao_radio_spi.h \ +	ao_radio_cmac.h \ +	ao_cc1200_CC1200.h \ +	ao_cc1200.h \ +	stm32l.h +# +# Common AltOS sources +# + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_adc_stm.c \ +	ao_data.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_beep_stm.c \ +	ao_eeprom_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_cc1200.c \ +	ao_radio_cmac.c \ +	ao_aes.c \ +	ao_aes_tables.c \ +	ao_pad.c \ +	ao_radio_cmac_cmd.c + +PRODUCT_SRC = \ +	ao_telefireeight.c + +PRODUCT=TeleFireEight-v1.0 +PRODUCT_DEF=-DTELEFIREEIGHT_V_1_0 +IDPRODUCT=0x000f + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g + +PROGNAME = telefireeight-v1.0 +PROG = $(PROGNAME)-$(VERSION).elf +HEX = $(PROGNAME)-$(VERSION).ihx + +SRC = $(ALTOS_SRC) $(PRODUCT_SRC) +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: + diff --git a/src/telefireeight-v1.0/ao_pins.h b/src/telefireeight-v1.0/ao_pins.h new file mode 100644 index 00000000..15e1fa11 --- /dev/null +++ b/src/telefireeight-v1.0/ao_pins.h @@ -0,0 +1,341 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_RADIO		1 +#define HAS_RADIO_RATE		1 +#define HAS_TELEMETRY		0 +#define HAS_FLIGHT		0 +#define HAS_USB			1 +#define HAS_BEEP		0 +#define HAS_GPS			0 +#define HAS_SERIAL_1		0 +#define HAS_ADC			1 +#define HAS_DBG			0 +#define HAS_EEPROM		1 +#define HAS_LOG			0 +#define HAS_PAD			1 +#define USE_INTERNAL_FLASH	1 +#define IGNITE_ON_P0		0 +#define PACKET_HAS_MASTER	0 +#define PACKET_HAS_SLAVE	0 +#define AO_DATA_RING		32 +#define USE_EEPROM_CONFIG	1 +#define USE_STORAGE_CONFIG	0 +#define HAS_AES			1 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +#define AO_CC1200_FOSC		40000000 + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SPI_1		1 +#define SPI_1_PA5_PA6_PA7	0 +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	1 +#define SPI_1_GPIO		(&stm_gpioe) +#define SPI_1_SCK		13 +#define SPI_1_MISO		14 +#define SPI_1_MOSI		15 +#define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_SPI_2		0 +#define SPI_2_PB13_PB14_PB15	0 +#define SPI_2_PD1_PD3_PD4	0 + +#define HAS_I2C_1		0 + +#define HAS_I2C_2		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define FAST_TIMER_FREQ		10000	/* .1ms for debouncing */ + +/* + * Radio is a cc1200 connected via SPI + */ + +#define AO_RADIO_CAL_DEFAULT 	5695733 + +#define AO_CC1200_SPI_CS_PORT	(&stm_gpioe) +#define AO_CC1200_SPI_CS_PIN	11 +#define AO_CC1200_SPI_BUS	AO_SPI_1_PE13_PE14_PE15 +#define AO_CC1200_SPI		stm_spi1 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST + +#define AO_CC1200_INT_PORT	(&stm_gpioe) +#define AO_CC1200_INT_PIN	(12) + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +#define LED_PER_LED		1 +#define LED_TYPE		uint16_t + +/* Continuity leds 1-8 */ +#define LED_0_PORT		(&stm_gpiob) +#define LED_0_PIN		13 +#define LED_1_PORT		(&stm_gpiob) +#define LED_1_PIN		12 +#define LED_2_PORT		(&stm_gpiob) +#define LED_2_PIN		11 +#define LED_3_PORT		(&stm_gpiob) +#define LED_3_PIN		10 +#define LED_4_PORT		(&stm_gpioc) +#define LED_4_PIN		9 +#define LED_5_PORT		(&stm_gpioa) +#define LED_5_PIN		8 +#define LED_6_PORT		(&stm_gpioa) +#define LED_6_PIN		9 +#define LED_7_PORT		(&stm_gpioa) +#define LED_7_PIN		10 + +#define LED_PIN_CONTINUITY_0	0 +#define LED_PIN_CONTINUITY_1	1 +#define LED_PIN_CONTINUITY_2	2 +#define LED_PIN_CONTINUITY_3	3 +#define LED_PIN_CONTINUITY_4	4 +#define LED_PIN_CONTINUITY_5	5 +#define LED_PIN_CONTINUITY_6	6 +#define LED_PIN_CONTINUITY_7	7 + +/* ARM */ +#define LED_8_PORT		(&stm_gpioe) +#define LED_8_PIN		3 + +#define LED_PIN_ARMED		8 + +/* RF good/marginal/poor */ +#define LED_9_PORT		(&stm_gpioe) +#define LED_9_PIN		4 +#define LED_10_PORT		(&stm_gpioe) +#define LED_10_PIN		5 +#define LED_11_PORT		(&stm_gpioe) +#define LED_11_PIN		6 + +#define LED_PIN_GREEN		9 +#define LED_PIN_AMBER		10 +#define LED_PIN_RED		11 + +#define AO_LED_CONTINUITY(c)	(1 << (c)) +#define AO_LED_CONTINUITY_MASK	(0xff) + +#define AO_LED_ARMED		(1 << LED_PIN_ARMED) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) +#define AO_LED_AMBER		(1 << LED_PIN_AMBER) +#define AO_LED_RED		(1 << LED_PIN_RED) + +#define LEDS_AVAILABLE		(0xfff) + +/* Alarm A */ +#define AO_SIREN +#define AO_SIREN_PORT		(&stm_gpiod) +#define AO_SIREN_PIN		10 + +/* Alarm B */ +#define AO_STROBE +#define AO_STROBE_PORT		(&stm_gpiod) +#define AO_STROBE_PIN		11 + +/* Pad selector is on PD0-7 */ + +#define HAS_FIXED_PAD_BOX	1 +#define AO_PAD_SELECTOR_PORT	(&stm_gpiod) +#define AO_PAD_SELECTOR_PINS	(0xff) + +#define SPI_CONST	0x00 + +#define AO_PAD_NUM		8 +#define	AO_PAD_PORT_0		(&stm_gpiod) +#define	AO_PAD_PORT_1		(&stm_gpiob) + +#define AO_PAD_PIN_0		9 +#define AO_PAD_0_PORT		(&stm_gpiod) +#define AO_ADC_SENSE_PAD_0	3 +#define AO_ADC_SENSE_PAD_0_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_0_PIN	3 + +#define AO_PAD_PIN_1		8 +#define AO_PAD_1_PORT		(&stm_gpiod) +#define AO_ADC_SENSE_PAD_1	2 +#define AO_ADC_SENSE_PAD_1_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_1_PIN	2 + +#define AO_PAD_PIN_2		15 +#define AO_PAD_2_PORT		(&stm_gpiob) +#define AO_ADC_SENSE_PAD_2	1 +#define AO_ADC_SENSE_PAD_2_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_2_PIN	1 + +#define AO_PAD_PIN_3		14 +#define AO_PAD_3_PORT		(&stm_gpiob) +#define AO_ADC_SENSE_PAD_3	0 +#define AO_ADC_SENSE_PAD_3_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_3_PIN	0 + +#define AO_PAD_PIN_4		12 +#define AO_PAD_4_PORT		(&stm_gpiod) +#define AO_ADC_SENSE_PAD_4	7 +#define AO_ADC_SENSE_PAD_4_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_4_PIN	7 + +#define AO_PAD_PIN_5		13 +#define AO_PAD_5_PORT		(&stm_gpiod) +#define AO_ADC_SENSE_PAD_5	6 +#define AO_ADC_SENSE_PAD_5_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_5_PIN	6 + +#define AO_PAD_PIN_6		14 +#define AO_PAD_6_PORT		(&stm_gpiod) +#define AO_ADC_SENSE_PAD_6	5 +#define AO_ADC_SENSE_PAD_6_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_6_PIN	5 + +#define AO_PAD_PIN_7		15 +#define AO_PAD_7_PORT		(&stm_gpiod) +#define AO_ADC_SENSE_PAD_7	4 +#define AO_ADC_SENSE_PAD_7_PORT	(&stm_gpioa) +#define AO_ADC_SENSE_PAD_7_PIN	4 + +#define AO_ADC_PYRO		8 +#define AO_ADC_PYRO_PORT	(&stm_gpiob) +#define AO_ADC_PYRO_PIN		0 + +#define AO_ADC_BATT		15 +#define AO_ADC_BATT_PORT	(&stm_gpioc) +#define AO_ADC_BATT_PIN		5 + +#define AO_ADC_PIN0_PORT	AO_ADC_SENSE_PAD_0_PORT +#define AO_ADC_PIN0_PIN		AO_ADC_SENSE_PAD_0_PIN + +#define AO_ADC_PIN1_PORT	AO_ADC_SENSE_PAD_1_PORT +#define AO_ADC_PIN1_PIN		AO_ADC_SENSE_PAD_1_PIN + +#define AO_ADC_PIN2_PORT	AO_ADC_SENSE_PAD_2_PORT +#define AO_ADC_PIN2_PIN		AO_ADC_SENSE_PAD_2_PIN + +#define AO_ADC_PIN3_PORT	AO_ADC_SENSE_PAD_3_PORT +#define AO_ADC_PIN3_PIN		AO_ADC_SENSE_PAD_3_PIN + +#define AO_ADC_PIN4_PORT	AO_ADC_SENSE_PAD_4_PORT +#define AO_ADC_PIN4_PIN		AO_ADC_SENSE_PAD_4_PIN + +#define AO_ADC_PIN5_PORT	AO_ADC_SENSE_PAD_5_PORT +#define AO_ADC_PIN5_PIN		AO_ADC_SENSE_PAD_5_PIN + +#define AO_ADC_PIN6_PORT	AO_ADC_SENSE_PAD_6_PORT +#define AO_ADC_PIN6_PIN		AO_ADC_SENSE_PAD_6_PIN + +#define AO_ADC_PIN7_PORT	AO_ADC_SENSE_PAD_7_PORT +#define AO_ADC_PIN7_PIN		AO_ADC_SENSE_PAD_7_PIN + +#define AO_ADC_PIN8_PORT	AO_ADC_PYRO_PORT +#define AO_ADC_PIN8_PIN		AO_ADC_PYRO_PIN + +#define AO_ADC_PIN9_PORT	AO_ADC_BATT_PORT +#define AO_ADC_PIN9_PIN		AO_ADC_BATT_PIN + +#define AO_PAD_ALL_CHANNELS	(0xff) + +/* test these values with real igniters */ +#define AO_PAD_RELAY_CLOSED	3524 +#define AO_PAD_NO_IGNITER	16904 +#define AO_PAD_GOOD_IGNITER	22514 + +#define AO_ADC_FIRST_PIN	0 + +#define AO_NUM_ADC		10 + +#define AO_ADC_SQ1		AO_ADC_SENSE_PAD_0 +#define AO_ADC_SQ2		AO_ADC_SENSE_PAD_1 +#define AO_ADC_SQ3		AO_ADC_SENSE_PAD_2 +#define AO_ADC_SQ4		AO_ADC_SENSE_PAD_3 +#define AO_ADC_SQ5		AO_ADC_SENSE_PAD_4 +#define AO_ADC_SQ6		AO_ADC_SENSE_PAD_5 +#define AO_ADC_SQ7		AO_ADC_SENSE_PAD_6 +#define AO_ADC_SQ8		AO_ADC_SENSE_PAD_7 +#define AO_ADC_SQ9		AO_ADC_PYRO +#define AO_ADC_SQ10		AO_ADC_BATT + +#define AO_ADC_REFERENCE_DV	33 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_GPIOAEN) | \ +				 (1 << STM_RCC_AHBENR_GPIOBEN) | \ +				 (1 << STM_RCC_AHBENR_GPIOCEN)) + + +#define AO_PAD_R_V_BATT_BATT_SENSE	200 +#define AO_PAD_R_BATT_SENSE_GND		22 + +#define AO_PAD_R_V_BATT_V_PYRO		200 +#define AO_PAD_R_V_PYRO_PYRO_SENSE	200 +#define AO_PAD_R_PYRO_SENSE_GND		22 + +#undef AO_PAD_R_V_PYRO_IGNITER +#define AO_PAD_R_IGNITER_IGNITER_SENSE	200 +#define AO_PAD_R_IGNITER_SENSE_GND	22 + +#define HAS_ADC_TEMP		0 + +struct ao_adc { +	int16_t		sense[AO_PAD_NUM]; +	int16_t		pyro; +	int16_t		batt; +}; + +#define AO_ADC_DUMP(p)							\ +	printf ("tick: %5u "						\ +		"0: %5d 1: %5d 2: %5d 3: %5d "				\ +		"4: %5d 5: %5d 6: %5d 7: %5d "				\ +		"pyro: %5d batt: %5d\n",				\ +		(p)->tick,						\ +		(p)->adc.sense[0],					\ +		(p)->adc.sense[1],					\ +		(p)->adc.sense[2],					\ +		(p)->adc.sense[3],					\ +		(p)->adc.sense[4],					\ +		(p)->adc.sense[5],					\ +		(p)->adc.sense[6],					\ +		(p)->adc.sense[7],					\ +		(p)->adc.pyro,						\ +		(p)->adc.batt) + +#endif /* _AO_PINS_H_ */ diff --git a/src/telefireeight-v1.0/ao_telefireeight.c b/src/telefireeight-v1.0/ao_telefireeight.c new file mode 100644 index 00000000..bdcf3213 --- /dev/null +++ b/src/telefireeight-v1.0/ao_telefireeight.c @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_pad.h> +#include <ao_exti.h> +#include <ao_radio_cmac_cmd.h> + +void +main(void) +{ +	ao_clock_init(); + +	ao_led_init(LEDS_AVAILABLE); + +	ao_task_init(); + +	ao_timer_init(); +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); + +	ao_cmd_init(); + +	ao_adc_init(); + +	ao_eeprom_init(); + +	ao_radio_init(); + +	ao_usb_init(); + +	ao_config_init(); + +	ao_pad_init(); + +//	ao_radio_cmac_cmd_init(); + +	ao_start_scheduler(); +} diff --git a/src/telefireeight-v1.0/flash-loader/.gitignore b/src/telefireeight-v1.0/flash-loader/.gitignore new file mode 100644 index 00000000..65fe7eab --- /dev/null +++ b/src/telefireeight-v1.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +*.elf +*.ihx diff --git a/src/telefireeight-v1.0/flash-loader/Makefile b/src/telefireeight-v1.0/flash-loader/Makefile new file mode 100644 index 00000000..baf0e3f3 --- /dev/null +++ b/src/telefireeight-v1.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telefireeight-v1.0 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telefireeight-v1.0/flash-loader/ao_pins.h b/src/telefireeight-v1.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..889feef6 --- /dev/null +++ b/src/telefireeight-v1.0/flash-loader/ao_pins.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioe +#define AO_BOOT_APPLICATION_PIN		2 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telefiretwo-v0.1/ao_pins.h b/src/telefiretwo-v0.1/ao_pins.h index 1e5c0d09..dedd0fad 100644 --- a/src/telefiretwo-v0.1/ao_pins.h +++ b/src/telefiretwo-v0.1/ao_pins.h @@ -191,6 +191,19 @@  #define HAS_ADC_TEMP		0 +#define AO_ADC_REFERENCE_DV	33 + +#define AO_PAD_R_V_BATT_BATT_SENSE	200 +#define AO_PAD_R_BATT_SENSE_GND		22 + +#define AO_PAD_R_V_BATT_V_PYRO		200 +#define AO_PAD_R_V_PYRO_PYRO_SENSE	200 +#define AO_PAD_R_PYRO_SENSE_GND		22 + +#undef AO_PAD_R_V_PYRO_IGNITER +#define AO_PAD_R_IGNITER_IGNITER_SENSE	200 +#define AO_PAD_R_IGNITER_SENSE_GND	22 +  struct ao_adc {  	int16_t		sense[AO_PAD_NUM];  	int16_t		pyro; diff --git a/src/telelco-v0.2-cc1200/Makefile b/src/telelco-v0.2-cc1200/Makefile new file mode 100644 index 00000000..4ccf494c --- /dev/null +++ b/src/telelco-v0.2-cc1200/Makefile @@ -0,0 +1,109 @@ +# +# AltOS build for TeleLCO +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_companion.h \ +	ao_data.h \ +	ao_sample.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_seven_segment.h \ +	ao_lco.h \ +	ao_lco_cmd.h \ +	ao_lco_func.h \ +	ao_radio_spi.h \ +	ao_radio_cmac.h \ +	ao_cc1200_CC1200.h \ +	ao_cc1200.h \ +	stm32l.h + +# +# Common AltOS sources +# + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_beep_stm.c \ +	ao_eeprom_stm.c \ +	ao_adc_single_stm.c \ +	ao_convert_volt.c \ +	ao_fast_timer.c \ +	ao_lcd_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_cc1200.c \ +	ao_radio_cmac.c \ +	ao_aes.c \ +	ao_aes_tables.c \ +	ao_fec_tx.c \ +	ao_fec_rx.c \ +	ao_seven_segment.c \ +	ao_quadrature.c \ +	ao_button.c \ +	ao_event.c \ +	ao_lco.c \ +	ao_lco_bits.c \ +	ao_lco_cmd.c \ +	ao_lco_func.c \ +	ao_radio_cmac_cmd.c + +PRODUCT=TeleLCO-v0.2 +PRODUCT_DEF=-DTELELCO +IDPRODUCT=0x0023 + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g + +PROGNAME=telelco-v0.2 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telelco.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +../altitude.h: make-altitude +	nickle $< > $@ + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telelco-v0.2-cc1200/ao_pins.h b/src/telelco-v0.2-cc1200/ao_pins.h new file mode 100644 index 00000000..bc325e06 --- /dev/null +++ b/src/telelco-v0.2-cc1200/ao_pins.h @@ -0,0 +1,324 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +#define AO_CC1200_FOSC		32000000 + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_EEPROM		1 +#define USE_INTERNAL_FLASH	1 +#define USE_EEPROM_CONFIG	1 +#define USE_STORAGE_CONFIG	0 +#define HAS_USB			1 +#define HAS_BEEP		1 +#define HAS_RADIO		1 +#define HAS_RADIO_RATE		1 +#define HAS_TELEMETRY		0 +#define HAS_AES			1 +#define HAS_STATIC_TEST		0 + + +#define HAS_SPI_1		0 +#define SPI_1_PA5_PA6_PA7	0 +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	0 + +#define HAS_SPI_2		1	/* CC1120 */ +#define SPI_2_PB13_PB14_PB15	0 +#define SPI_2_PD1_PD3_PD4	1 +#define SPI_2_GPIO		(&stm_gpiod) +#define SPI_2_SCK		1 +#define SPI_2_MISO		3 +#define SPI_2_MOSI		4 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_I2C_1		0 + +#define HAS_I2C_2		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define FAST_TIMER_FREQ		10000	/* .1ms for debouncing */ + +/* + * Radio is a cc1200 connected via SPI + */ + +#define AO_RADIO_CAL_DEFAULT 	5695733 + +#define AO_FEC_DEBUG		0 +#define AO_CC1200_SPI_CS_PORT	(&stm_gpiod) +#define AO_CC1200_SPI_CS_PIN	0 +#define AO_CC1200_SPI_BUS	AO_SPI_2_PD1_PD3_PD4 +#define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST + +#define AO_CC1200_INT_PORT		(&stm_gpioc) +#define AO_CC1200_INT_PIN		(15) + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT_ENABLE		STM_RCC_AHBENR_GPIOCEN +#define LED_PORT		(&stm_gpioc) +#define LED_PIN_RED		7 +#define LED_PIN_AMBER		8 +#define LED_PIN_GREEN		9 +#define LED_PIN_CONTINUITY_3	10 +#define LED_PIN_CONTINUITY_2	11 +#define LED_PIN_CONTINUITY_1	12 +#define LED_PIN_CONTINUITY_0	13 +#define LED_PIN_REMOTE_ARM	14 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_AMBER		(1 << LED_PIN_AMBER) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) +#define AO_LED_CONTINUITY_3	(1 << LED_PIN_CONTINUITY_3) +#define AO_LED_CONTINUITY_2	(1 << LED_PIN_CONTINUITY_2) +#define AO_LED_CONTINUITY_1	(1 << LED_PIN_CONTINUITY_1) +#define AO_LED_CONTINUITY_0	(1 << LED_PIN_CONTINUITY_0) + +#define AO_LED_CONTINUITY_NUM	4 + +#define AO_LED_REMOTE_ARM	(1 << LED_PIN_REMOTE_ARM) + +#define LEDS_AVAILABLE		(AO_LED_RED |		\ +				 AO_LED_AMBER |		\ +				 AO_LED_GREEN |		\ +				 AO_LED_CONTINUITY_3 |	\ +				 AO_LED_CONTINUITY_2 |	\ +				 AO_LED_CONTINUITY_1 |	\ +				 AO_LED_CONTINUITY_0 |	\ +				 AO_LED_REMOTE_ARM) + +/* LCD displays */ + +#define LCD_DEBUG		0 +#define SEVEN_SEGMENT_DEBUG	0 + +#define AO_LCD_STM_SEG_ENABLED_0 (		\ +		(1 << 0) | /* PA1 */		\ +		(1 << 1) | /* PA2 */		\ +		(1 << 2) | /* PA3 */		\ +		(1 << 3) | /* PA6 */		\ +		(1 << 4) | /* PA7 */		\ +		(1 << 5) | /* PB0 */		\ +		(1 << 6) | /* PB1 */		\ +		(1 << 7) | /* PB3 */		\ +		(1 << 8) | /* PB4 */		\ +		(1 << 9) | /* PB5 */		\ +		(1 << 10) | /* PB10 */		\ +		(1 << 11) | /* PB11 */		\ +		(1 << 12) | /* PB12 */		\ +		(1 << 13) | /* PB13 */		\ +		(1 << 14) | /* PB14 */		\ +		(1 << 15) | /* PB15 */		\ +		(1 << 16) | /* PB8 */		\ +		(1 << 17) | /* PA15 */		\ +		(1 << 18) | /* PC0 */		\ +		(1 << 19) | /* PC1 */		\ +		(1 << 20) | /* PC2 */		\ +		(1 << 21) | /* PC3 */		\ +		(1 << 22) | /* PC4 */		\ +		(1 << 23) | /* PC5 */		\ +		(0 << 24) | /* PC6 */		\ +		(0 << 25) | /* PC7 */		\ +		(0 << 26) | /* PC8 */		\ +		(0 << 27) | /* PC9 */		\ +		(0 << 28) | /* PC10 or PD8 */	\ +		(0 << 29) | /* PC11 or PD9 */	\ +		(0 << 30) | /* PC12 or PD10 */	\ +		(0 << 31))  /* PD2 or PD11 */ + +#define AO_LCD_STM_SEG_ENABLED_1 (		\ +		(0 << 0) | /* PD12 */		\ +		(0 << 1) | /* PD13 */		\ +		(0 << 2) | /* PD14 */		\ +		(0 << 3) | /* PD15 */		\ +		(0 << 4) | /* PE0 */		\ +		(0 << 5) | /* PE1 */		\ +		(0 << 6) | /* PE2 */		\ +		(0 << 7))  /* PE3 */ + +#define AO_LCD_STM_COM_ENABLED (		\ +		(1 << 0) | /* PA8 */		\ +		(0 << 1) | /* PA9 */		\ +		(0 << 2) | /* PA10 */		\ +		(0 << 3) | /* PB9 */		\ +		(0 << 4) | /* PC10 */		\ +		(0 << 5) | /* PC11 */		\ +		(0 << 6)) /* PC12 */ + +#define AO_LCD_28_ON_C	0 + +#define AO_LCD_DUTY	STM_LCD_CR_DUTY_STATIC + +#define AO_LCD_PER_DIGIT	1 + +#define AO_LCD_DIGITS		3 +#define AO_LCD_SEGMENTS		8 + +#define AO_SEGMENT_MAP {			\ +		/* pad segments */		\ +		{ 0, 14 },			\ +		{ 0, 13 },			\ +		{ 0, 15 },			\ +		{ 0, 17 },			\ +		{ 0, 16 },			\ +		{ 0, 8 },			\ +		{ 0, 9 },			\ +		{ 0, 7 },			\ +		/* box1 segments */		\ +		{ 0, 10 },			\ +		{ 0, 6 },			\ +		{ 0, 11 },			\ +		{ 0, 12 },			\ +		{ 0, 21 },			\ +		{ 0, 19 },			\ +		{ 0, 20 },			\ +		{ 0, 18 },			\ +		/* box0 segments */		\ +		{ 0, 22 },			\ +		{ 0, 4 },			\ +		{ 0, 23 },			\ +		{ 0, 5 },			\ +		{ 0, 3 },			\ +		{ 0, 1 },			\ +		{ 0, 2 },			\ +		{ 0, 0 },			\ +} + +/* + * Use event queue for input devices + */ + +#define AO_EVENT		1 + +/* + * Knobs + */ + +#define AO_QUADRATURE_COUNT	2 + +#define AO_QUADRATURE_0_PORT	&stm_gpioe +#define AO_QUADRATURE_0_A	3 +#define AO_QUADRATURE_0_B	2 + +#define AO_QUADRATURE_PAD	0 + +#define AO_QUADRATURE_1_PORT	&stm_gpioe +#define AO_QUADRATURE_1_A	1 +#define AO_QUADRATURE_1_B	0 + +#define AO_QUADRATURE_BOX	1 +#define AO_QUADRATURE_DEBOUNCE	10 + +/* + * Buttons + */ + +#define AO_BUTTON_COUNT		2 +#define AO_BUTTON_MODE		AO_EXTI_MODE_PULL_UP + +#define AO_BUTTON_0_PORT	&stm_gpioe +#define AO_BUTTON_0		4 + +#define AO_BUTTON_ARM		0 + +#define AO_BUTTON_1_PORT	&stm_gpioe +#define AO_BUTTON_1		5 + +#define AO_BUTTON_FIRE		1 + +/* ADC */ + +#define HAS_ADC_SINGLE		1 +#define HAS_BATTERY_REPORT	1 + +struct ao_adc { +	int16_t		v_batt; +	int16_t		temp; +	int16_t		v_ref; +}; + +#if HAS_ADC_SINGLE +#define AO_ADC_DUMP(p) \ +	printf("batt: %5d temp: %5d v_ref: %5d\n", \ +	       (p)->v_batt, (p)->temp, (p)->v_ref) +#endif +#if HAS_ADC +#define AO_ADC_DUMP(p) \ +	printf("%5d: batt: %5d temp %5d v_ref %5d\n", \ +	       (p)->tick, (p)->adc.v_batt, (p)->adc.temp, (p)->adc.v_ref) +#endif + +#define HAS_ADC_TEMP		1 + +#define AO_ADC_V_BATT		0 +#define AO_ADC_V_BATT_PORT	(&stm_gpioa) +#define AO_ADC_V_BATT_PIN	0 + +#define AO_ADC_RCC_AHBENR	(1 << STM_RCC_AHBENR_GPIOAEN) + +#define AO_ADC_PIN0_PORT	AO_ADC_V_BATT_PORT +#define AO_ADC_PIN0_PIN		AO_ADC_V_BATT_PIN + +#define AO_ADC_SQ1		AO_ADC_V_BATT +#define AO_ADC_SQ2		STM_ADC_SQ_TEMP +#define AO_ADC_SQ3		STM_ADC_SQ_V_REF + +#define AO_NUM_ADC		3 + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS	15	/* 15k */ +#define AO_BATTERY_DIV_MINUS	27	/* 27k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV	33 + +#endif /* _AO_PINS_H_ */ diff --git a/src/telelco-v0.2-cc1200/ao_telelco.c b/src/telelco-v0.2-cc1200/ao_telelco.c new file mode 100644 index 00000000..3266da00 --- /dev/null +++ b/src/telelco-v0.2-cc1200/ao_telelco.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_exti.h> +#include <ao_packet.h> +#include <ao_companion.h> +#include <ao_profile.h> +#include <ao_pyro.h> +#include <ao_aes.h> +#include <ao_seven_segment.h> +#include <ao_quadrature.h> +#include <ao_button.h> +#include <ao_lco.h> +#include <ao_lco_cmd.h> +#include <ao_radio_cmac_cmd.h> +#include <ao_eeprom.h> +#if HAS_ADC_SINGLE +#include <ao_adc_single.h> +#endif +#if HAS_ADC +#include <ao_adc.h> +#endif + +int +main(void) +{ +	ao_clock_init(); +	ao_task_init(); +	ao_timer_init(); +	ao_dma_init(); + +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_GREEN); + + +	ao_spi_init(); +	ao_exti_init(); + +	ao_beep_init(); +	ao_cmd_init(); + +	ao_lcd_stm_init(); +	ao_seven_segment_init(); +	ao_quadrature_init(); +	ao_button_init(); + +	ao_adc_single_init(); + +	ao_eeprom_init(); + +	ao_radio_init(); + +	ao_usb_init(); + +	ao_config_init(); + +	ao_lco_init(); +	ao_lco_cmd_init(); +//	ao_radio_cmac_cmd_init(); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/telelco-v0.2-cc1200/flash-loader/.gitignore b/src/telelco-v0.2-cc1200/flash-loader/.gitignore new file mode 100644 index 00000000..a32ec26e --- /dev/null +++ b/src/telelco-v0.2-cc1200/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +telelco*.elf diff --git a/src/telelco-v0.2-cc1200/flash-loader/Makefile b/src/telelco-v0.2-cc1200/flash-loader/Makefile new file mode 100644 index 00000000..679e61ba --- /dev/null +++ b/src/telelco-v0.2-cc1200/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telelco-v0.2 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telelco-v0.2-cc1200/flash-loader/ao_pins.h b/src/telelco-v0.2-cc1200/flash-loader/ao_pins.h new file mode 100644 index 00000000..72f840c0 --- /dev/null +++ b/src/telelco-v0.2-cc1200/flash-loader/ao_pins.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Arm switch. Press at power on to get boot loader */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioe +#define AO_BOOT_APPLICATION_PIN		4 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telelco-v0.2/Makefile b/src/telelco-v0.2/Makefile index 8c1ced6c..8279cac1 100644 --- a/src/telelco-v0.2/Makefile +++ b/src/telelco-v0.2/Makefile @@ -64,6 +64,7 @@ ALTOS_SRC = \  	ao_button.c \  	ao_event.c \  	ao_lco.c \ +	ao_lco_bits.c \  	ao_lco_cmd.c \  	ao_lco_func.c \  	ao_radio_cmac_cmd.c diff --git a/src/telelco-v0.2/ao_pins.h b/src/telelco-v0.2/ao_pins.h index b90fca8b..f0da4fe4 100644 --- a/src/telelco-v0.2/ao_pins.h +++ b/src/telelco-v0.2/ao_pins.h @@ -253,6 +253,7 @@  #define AO_QUADRATURE_1_B	0  #define AO_QUADRATURE_BOX	1 +#define AO_QUADRATURE_DEBOUNCE	10  /*   * Buttons diff --git a/src/telelco-v0.3/Makefile b/src/telelco-v0.3/Makefile index 0bb0f9dc..c2592bf8 100644 --- a/src/telelco-v0.3/Makefile +++ b/src/telelco-v0.3/Makefile @@ -65,6 +65,7 @@ ALTOS_SRC = \  	ao_button.c \  	ao_event.c \  	ao_lco.c \ +	ao_lco_bits.c \  	ao_lco_cmd.c \  	ao_lco_func.c \  	ao_radio_cmac_cmd.c diff --git a/src/telelco-v0.3/ao_pins.h b/src/telelco-v0.3/ao_pins.h index dd4aaafb..6023739c 100644 --- a/src/telelco-v0.3/ao_pins.h +++ b/src/telelco-v0.3/ao_pins.h @@ -54,6 +54,8 @@  #define HAS_RADIO_RATE		1  #define HAS_TELEMETRY		0  #define HAS_AES			1 +#define HAS_STATIC_TEST		0 +  #define HAS_SPI_1		0  #define SPI_1_PA5_PA6_PA7	0 @@ -250,6 +252,7 @@  #define AO_QUADRATURE_1_B	0  #define AO_QUADRATURE_BOX	1 +#define AO_QUADRATURE_DEBOUNCE	10  /*   * Buttons diff --git a/src/telelco-v2.0/.gitignore b/src/telelco-v2.0/.gitignore new file mode 100644 index 00000000..a32ec26e --- /dev/null +++ b/src/telelco-v2.0/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +telelco*.elf diff --git a/src/telelco-v2.0/Makefile b/src/telelco-v2.0/Makefile new file mode 100644 index 00000000..43295fd3 --- /dev/null +++ b/src/telelco-v2.0/Makefile @@ -0,0 +1,106 @@ +# +# AltOS build for TeleLCO v2.0 +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_companion.h \ +	ao_data.h \ +	ao_sample.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_seven_segment.h \ +	ao_lco.h \ +	ao_lco_cmd.h \ +	ao_lco_func.h \ +	ao_radio_spi.h \ +	ao_radio_cmac.h \ +	ao_cc1200_CC1200.h \ +	ao_cc1200.h \ +	stm32l.h + +# +# Common AltOS sources +# + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_beep_stm.c \ +	ao_eeprom_stm.c \ +	ao_adc_single_stm.c \ +	ao_convert_volt.c \ +	ao_fast_timer.c \ +	ao_lcd_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_cc1200.c \ +	ao_radio_cmac.c \ +	ao_aes.c \ +	ao_aes_tables.c \ +	ao_fec_tx.c \ +	ao_fec_rx.c \ +	ao_seven_segment.c \ +	ao_quadrature.c \ +	ao_button.c \ +	ao_event.c \ +	ao_lco_bits.c \ +	ao_lco_v2.c \ +	ao_lco_cmd.c \ +	ao_lco_func.c \ +	ao_radio_cmac_cmd.c + +PRODUCT=TeleLCO-v2.0 +PRODUCT_DEF=-DTELELCO +IDPRODUCT=0x0023 + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g + +PROGNAME=telelco-v2.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telelco.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telelco-v2.0/ao_lco_v2.c b/src/telelco-v2.0/ao_lco_v2.c new file mode 100644 index 00000000..a9933d59 --- /dev/null +++ b/src/telelco-v2.0/ao_lco_v2.c @@ -0,0 +1,304 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_lco.h> +#include <ao_event.h> +#include <ao_seven_segment.h> +#include <ao_quadrature.h> +#include <ao_radio_cmac.h> +#include <ao_adc_single.h> + +#define AO_LCO_PAD_DIGIT	0 +#define AO_LCO_BOX_DIGIT_1	1 +#define AO_LCO_BOX_DIGIT_10	2 + +#define AO_LCO_DRAG_RACE_START_TIME	AO_SEC_TO_TICKS(5) +#define AO_LCO_DRAG_RACE_STOP_TIME	AO_SEC_TO_TICKS(2) + +/* UI values */ +static uint8_t	ao_lco_select_mode; +#define AO_LCO_SELECT_PAD	0 +#define AO_LCO_SELECT_BOX	1 + +static uint8_t	ao_lco_display_mutex; + +void +ao_lco_show_pad(uint8_t pad) +{ +	ao_mutex_get(&ao_lco_display_mutex); +	ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad | (ao_lco_drag_race << 4)); +	ao_mutex_put(&ao_lco_display_mutex); +} + +#define SEVEN_SEGMENT_d		((0 << 0) |	\ +				 (0 << 1) |	\ +				 (1 << 2) |	\ +				 (1 << 3) |	\ +				 (1 << 4) |	\ +				 (1 << 5) |	\ +				 (1 << 6)) + + +#define SEVEN_SEGMENT_r		((0 << 0) |	\ +				 (0 << 1) |	\ +				 (0 << 2) |	\ +				 (1 << 3) |	\ +				 (1 << 4) |	\ +				 (0 << 5) |	\ +				 (0 << 6)) + +void +ao_lco_show_box(uint16_t box) +{ +	ao_mutex_get(&ao_lco_display_mutex); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, box % 10 | (ao_lco_drag_race << 4)); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, box / 10 | (ao_lco_drag_race << 4)); +	ao_mutex_put(&ao_lco_display_mutex); +} + +static void +ao_lco_show_voltage(uint16_t decivolts) +{ +	uint8_t	tens, ones, tenths; + +	PRINTD("voltage %d\n", decivolts); +	tenths = decivolts % 10; +	ones = (decivolts / 10) % 10; +	tens = (decivolts / 100) % 10; +	ao_mutex_get(&ao_lco_display_mutex); +	ao_seven_segment_set(AO_LCO_PAD_DIGIT, tenths); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, ones | 0x10); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, tens); +	ao_mutex_put(&ao_lco_display_mutex); +} + +void +ao_lco_show(void) +{ +	if (ao_lco_pad == AO_LCO_PAD_VOLTAGE) { +		ao_lco_show_voltage(ao_pad_query.battery); +	} else { +		ao_lco_show_pad(ao_lco_pad); +		ao_lco_show_box(ao_lco_box); +	} +} + +uint8_t +ao_lco_box_present(uint16_t box) +{ +	if (box >= AO_PAD_MAX_BOXES) +		return 0; +	return (ao_lco_box_mask[AO_LCO_MASK_ID(box)] >> AO_LCO_MASK_SHIFT(box)) & 1; +} + +static void +ao_lco_set_select(void) +{ +	if (ao_lco_armed) { +		ao_led_off(AO_LED_PAD); +		ao_led_off(AO_LED_BOX); +	} else { +		switch (ao_lco_select_mode) { +		case AO_LCO_SELECT_PAD: +			ao_led_off(AO_LED_BOX); +			ao_led_on(AO_LED_PAD); +			break; +		case AO_LCO_SELECT_BOX: +			ao_led_off(AO_LED_PAD); +			ao_led_on(AO_LED_BOX); +			break; +		default: +			break; +		} +	} +} + +static void +ao_lco_step_box(int8_t dir) +{ +	int16_t new_box = ao_lco_box; + +	do { +		new_box += dir; +		if (new_box > ao_lco_max_box) +			new_box = ao_lco_min_box; +		else if (new_box < ao_lco_min_box) +			new_box = ao_lco_max_box; +		if (new_box == ao_lco_box) +			break; +	} while (!ao_lco_box_present(new_box)); +	ao_lco_set_box(new_box); +} + +static struct ao_task	ao_lco_drag_task; + +static void +ao_lco_drag_monitor(void) +{ +	uint16_t	delay = ~0; +	uint16_t	now; + +	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +	for (;;) { +		PRINTD("Drag monitor count %d delay %d\n", ao_lco_drag_beep_count, delay); +		if (delay == (uint16_t) ~0) +			ao_sleep(&ao_lco_drag_beep_count); +		else +			ao_sleep_for(&ao_lco_drag_beep_count, delay); + +		delay = ~0; +		now = ao_time(); +		delay = ao_lco_drag_warn_check(now, delay); +		delay = ao_lco_drag_beep_check(now, delay); +	} +} + +static void +ao_lco_input(void) +{ +	static struct ao_event	event; + +	for (;;) { +		ao_event_get(&event); +		PRINTD("event type %d unit %d value %d\n", +		       event.type, event.unit, event.value); +		switch (event.type) { +		case AO_EVENT_QUADRATURE: +			switch (event.unit) { +			case AO_QUADRATURE_SELECT: +				if (!ao_lco_armed) { +					switch (ao_lco_select_mode) { +					case AO_LCO_SELECT_PAD: +						ao_lco_step_pad((int8_t) event.value); +						break; +					case AO_LCO_SELECT_BOX: +						ao_lco_step_box((int8_t) event.value); +						break; +					default: +						break; +					} +				} +				break; +			} +			break; +		case AO_EVENT_BUTTON: +			switch (event.unit) { +			case AO_BUTTON_ARM: +				ao_lco_set_armed(event.value); +				ao_lco_set_select(); +				break; +			case AO_BUTTON_FIRE: +				if (ao_lco_armed) +					ao_lco_set_firing(event.value); +				break; +			case AO_BUTTON_DRAG_SELECT: +				if (event.value) +					ao_lco_toggle_drag(); +				break; +			case AO_BUTTON_DRAG_MODE: +				if (event.value) +					ao_lco_drag_enable(); +				else +					ao_lco_drag_disable(); +				break; +			case AO_BUTTON_ENCODER_SELECT: +				if (event.value) { +					if (!ao_lco_armed) { +						ao_lco_select_mode = 1 - ao_lco_select_mode; +						ao_lco_set_select(); +					} +				} +				break; +			} +			break; +		} +	} +} + +/* + * Light up everything for a second at power on to let the user + * visually inspect the system for correct operation + */ +static void +ao_lco_display_test() +{ +	ao_mutex_get(&ao_lco_display_mutex); +	ao_seven_segment_set(AO_LCO_PAD_DIGIT, 8 | 0x10); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, 8 | 0x10); +	ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, 8 | 0x10); +	ao_mutex_put(&ao_lco_display_mutex); +	ao_led_on(LEDS_AVAILABLE); +	ao_delay(AO_MS_TO_TICKS(1000)); +	ao_led_off(LEDS_AVAILABLE); +} + +static void +ao_lco_batt_voltage(void) +{ +	struct ao_adc	packet; +	int16_t		decivolt; + +	ao_adc_single_get(&packet); +	decivolt = ao_battery_decivolt(packet.v_batt); +	ao_lco_show_voltage(decivolt); +	ao_delay(AO_MS_TO_TICKS(1000)); +} + +static struct ao_task ao_lco_input_task; +static struct ao_task ao_lco_monitor_task; +static struct ao_task ao_lco_arm_warn_task; +static struct ao_task ao_lco_igniter_status_task; + +static void +ao_lco_main(void) +{ +	ao_lco_display_test(); +	ao_lco_batt_voltage(); +	ao_lco_search(); +	ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input"); +	ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn"); +	ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status"); +	ao_add_task(&ao_lco_drag_task, ao_lco_drag_monitor, "drag race"); +	ao_lco_monitor(); +} + +#if DEBUG +void +ao_lco_set_debug(void) +{ +	ao_cmd_decimal(); +	if (ao_cmd_status == ao_cmd_success) +		ao_lco_debug = ao_cmd_lex_i != 0; +} + +__code struct ao_cmds ao_lco_cmds[] = { +	{ ao_lco_set_debug,	"D <0 off, 1 on>\0Debug" }, +	{ ao_lco_search,	"s\0Search for pad boxes" }, +	{ 0, NULL } +}; +#endif + +void +ao_lco_init(void) +{ +	ao_add_task(&ao_lco_monitor_task, ao_lco_main, "lco monitor"); +#if DEBUG +	ao_cmd_register(&ao_lco_cmds[0]); +#endif +} diff --git a/src/telelco-v2.0/ao_pins.h b/src/telelco-v2.0/ao_pins.h new file mode 100644 index 00000000..95998dc7 --- /dev/null +++ b/src/telelco-v2.0/ao_pins.h @@ -0,0 +1,398 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +#define AO_CC1200_FOSC		40000000 + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_EEPROM		1 +#define USE_INTERNAL_FLASH	1 +#define USE_EEPROM_CONFIG	1 +#define USE_STORAGE_CONFIG	0 +#define HAS_USB			1 +#define HAS_BEEP		1 +#define HAS_RADIO		1 +#define HAS_RADIO_RATE		1 +#define HAS_TELEMETRY		0 +#define HAS_AES			1 +#define HAS_STATIC_TEST		0 + +#define HAS_SPI_1		0 +#define SPI_1_PA5_PA6_PA7	0 +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	0 + +#define HAS_SPI_2		1	/* CC1200 */ +#define SPI_2_PB13_PB14_PB15	0 +#define SPI_2_PD1_PD3_PD4	1 +#define SPI_2_GPIO		(&stm_gpiod) +#define SPI_2_SCK		1 +#define SPI_2_MISO		3 +#define SPI_2_MOSI		4 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_I2C_1		0 + +#define HAS_I2C_2		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define FAST_TIMER_FREQ		10000	/* .1ms for debouncing */ + +/* + * Radio is a cc1200 connected via SPI + */ + +#define AO_RADIO_CAL_DEFAULT 	5695733 + +#define AO_CC1200_SPI_CS_PORT	(&stm_gpiod) +#define AO_CC1200_SPI_CS_PIN	0 +#define AO_CC1200_SPI_BUS	AO_SPI_2_PD1_PD3_PD4 +#define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST + +#define AO_CC1200_INT_PORT		(&stm_gpiod) +#define AO_CC1200_INT_PIN		(5) + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PER_LED		1 +#define LED_TYPE		uint16_t + +#define LED_ENABLE_BITS		((1 << STM_RCC_AHBENR_GPIOAEN) |	\ +				 (1 << STM_RCC_AHBENR_GPIOCEN) |	\ +				 (1 << STM_RCC_AHBENR_GPIODEN) |	\ +				 (1 << STM_RCC_AHBENR_GPIOEEN)) + +/* PC7 - PC9, LED 0 - 2 */ +#define LED_0_PORT		(&stm_gpioc) +#define LED_0_PIN		7 +#define LED_1_PORT		(&stm_gpioc) +#define LED_1_PIN		8 +#define LED_2_PORT		(&stm_gpioc) +#define LED_2_PIN		9 + +/* PD8 - PD10, LED 3 - 5 */ +#define LED_3_PORT		(&stm_gpiod) +#define LED_3_PIN		8 +#define LED_4_PORT		(&stm_gpiod) +#define LED_4_PIN		9 +#define LED_5_PORT		(&stm_gpiod) +#define LED_5_PIN		10 + +/* PE2 - PE11 (not PE6), LED 6-14 */ +#define LED_6_PORT		(&stm_gpioe) +#define LED_6_PIN		2 +#define LED_7_PORT		(&stm_gpioe) +#define LED_7_PIN		3 +#define LED_8_PORT		(&stm_gpioe) +#define LED_8_PIN		4 +#define LED_9_PORT		(&stm_gpioe) +#define LED_9_PIN		5 +#define LED_10_PORT		(&stm_gpioe) +#define LED_10_PIN		7 +#define LED_11_PORT		(&stm_gpioe) +#define LED_11_PIN		8 +#define LED_12_PORT		(&stm_gpioe) +#define LED_12_PIN		9 +#define LED_13_PORT		(&stm_gpioe) +#define LED_13_PIN		10 +#define LED_14_PORT		(&stm_gpioe) +#define LED_14_PIN		11 + +/* PA5, LED 15 */ +#define LED_15_PORT		(&stm_gpioa) +#define LED_15_PIN		5 + +#define LED_PIN_RED		0 +#define LED_PIN_AMBER		1 +#define LED_PIN_GREEN		2 +#define LED_PIN_BOX		3 +#define LED_PIN_PAD		4 +#define LED_PIN_DRAG		5 +#define LED_PIN_CONTINUITY_7	6 +#define LED_PIN_CONTINUITY_6	7 +#define LED_PIN_CONTINUITY_5	8 +#define LED_PIN_CONTINUITY_4	9 +#define LED_PIN_CONTINUITY_3	10 +#define LED_PIN_CONTINUITY_2	11 +#define LED_PIN_CONTINUITY_1	12 +#define LED_PIN_CONTINUITY_0	13 +#define LED_PIN_REMOTE_ARM	14 +#define LED_PIN_FIRE		15 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_AMBER		(1 << LED_PIN_AMBER) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) +#define AO_LED_BOX		(1 << LED_PIN_BOX) +#define AO_LED_PAD		(1 << LED_PIN_PAD) +#define AO_LED_DRAG		(1 << LED_PIN_DRAG) +#define AO_LED_CONTINUITY_7	(1 << LED_PIN_CONTINUITY_7) +#define AO_LED_CONTINUITY_6	(1 << LED_PIN_CONTINUITY_6) +#define AO_LED_CONTINUITY_5	(1 << LED_PIN_CONTINUITY_5) +#define AO_LED_CONTINUITY_4	(1 << LED_PIN_CONTINUITY_4) +#define AO_LED_CONTINUITY_3	(1 << LED_PIN_CONTINUITY_3) +#define AO_LED_CONTINUITY_2	(1 << LED_PIN_CONTINUITY_2) +#define AO_LED_CONTINUITY_1	(1 << LED_PIN_CONTINUITY_1) +#define AO_LED_CONTINUITY_0	(1 << LED_PIN_CONTINUITY_0) +#define AO_LED_CONTINUITY_NUM	8 +#define AO_LED_REMOTE_ARM	(1 << LED_PIN_REMOTE_ARM) +#define AO_LED_FIRE		(1 << LED_PIN_FIRE) + +#define LEDS_AVAILABLE		(AO_LED_RED |		\ +				 AO_LED_AMBER |		\ +				 AO_LED_GREEN |		\ +				 AO_LED_BOX |		\ +				 AO_LED_PAD |		\ +				 AO_LED_DRAG |		\ +				 AO_LED_CONTINUITY_7 |	\ +				 AO_LED_CONTINUITY_6 |	\ +				 AO_LED_CONTINUITY_5 |	\ +				 AO_LED_CONTINUITY_4 |	\ +				 AO_LED_CONTINUITY_3 |	\ +				 AO_LED_CONTINUITY_2 |	\ +				 AO_LED_CONTINUITY_1 |	\ +				 AO_LED_CONTINUITY_0 |	\ +				 AO_LED_REMOTE_ARM |	\ +				 AO_LED_FIRE) + +/* LCD displays */ + +#define LCD_DEBUG		0 +#define SEVEN_SEGMENT_DEBUG	0 + +#define AO_LCD_STM_SEG_ENABLED_0 (		\ +		(1 << 0) | /* PA1 */		\ +		(1 << 1) | /* PA2 */		\ +		(1 << 2) | /* PA3 */		\ +		(1 << 3) | /* PA6 */		\ +		(1 << 4) | /* PA7 */		\ +		(1 << 5) | /* PB0 */		\ +		(1 << 6) | /* PB1 */		\ +		(1 << 7) | /* PB3 */		\ +		(1 << 8) | /* PB4 */		\ +		(1 << 9) | /* PB5 */		\ +		(1 << 10) | /* PB10 */		\ +		(1 << 11) | /* PB11 */		\ +		(1 << 12) | /* PB12 */		\ +		(1 << 13) | /* PB13 */		\ +		(1 << 14) | /* PB14 */		\ +		(1 << 15) | /* PB15 */		\ +		(1 << 16) | /* PB8 */		\ +		(1 << 17) | /* PA15 */		\ +		(1 << 18) | /* PC0 */		\ +		(1 << 19) | /* PC1 */		\ +		(1 << 20) | /* PC2 */		\ +		(1 << 21) | /* PC3 */		\ +		(1 << 22) | /* PC4 */		\ +		(1 << 23) | /* PC5 */		\ +		(0 << 24) | /* PC6 */		\ +		(0 << 25) | /* PC7 */		\ +		(0 << 26) | /* PC8 */		\ +		(0 << 27) | /* PC9 */		\ +		(0 << 28) | /* PC10 or PD8 */	\ +		(0 << 29) | /* PC11 or PD9 */	\ +		(0 << 30) | /* PC12 or PD10 */	\ +		(0 << 31))  /* PD2 or PD11 */ + +#define AO_LCD_STM_SEG_ENABLED_1 (		\ +		(0 << 0) | /* PD12 */		\ +		(0 << 1) | /* PD13 */		\ +		(0 << 2) | /* PD14 */		\ +		(0 << 3) | /* PD15 */		\ +		(0 << 4) | /* PE0 */		\ +		(0 << 5) | /* PE1 */		\ +		(0 << 6) | /* PE2 */		\ +		(0 << 7))  /* PE3 */ + +#define AO_LCD_STM_COM_ENABLED (		\ +		(1 << 0) | /* PA8 */		\ +		(0 << 1) | /* PA9 */		\ +		(0 << 2) | /* PA10 */		\ +		(0 << 3) | /* PB9 */		\ +		(0 << 4) | /* PC10 */		\ +		(0 << 5) | /* PC11 */		\ +		(0 << 6)) /* PC12 */ + +#define AO_LCD_28_ON_C	0 + +#define AO_LCD_DUTY	STM_LCD_CR_DUTY_STATIC + +#define AO_LCD_PER_DIGIT	1 + +#define AO_LCD_DIGITS		3 +#define AO_LCD_SEGMENTS		8 + +#define AO_SEGMENT_MAP {			\ +		/* pad segments */		\ +		{ 0, 14 },			\ +		{ 0, 13 },			\ +		{ 0, 15 },			\ +		{ 0, 17 },			\ +		{ 0, 16 },			\ +		{ 0, 8 },			\ +		{ 0, 9 },			\ +		{ 0, 7 },			\ +		/* box1 segments */		\ +		{ 0, 10 },			\ +		{ 0, 6 },			\ +		{ 0, 11 },			\ +		{ 0, 12 },			\ +		{ 0, 21 },			\ +		{ 0, 19 },			\ +		{ 0, 20 },			\ +		{ 0, 18 },			\ +		/* box0 segments */		\ +		{ 0, 22 },			\ +		{ 0, 4 },			\ +		{ 0, 23 },			\ +		{ 0, 5 },			\ +		{ 0, 3 },			\ +		{ 0, 1 },			\ +		{ 0, 2 },			\ +		{ 0, 0 },			\ +} + +/* + * Use event queue for input devices + */ + +#define AO_EVENT		1 + +/* + * Knobs + */ + +#define AO_QUADRATURE_COUNT	1 +#define AO_QUADRATURE_DEBOUNCE	0 +#define AO_QUADRATURE_SINGLE_CODE	1 + +#define AO_QUADRATURE_0_PORT	&stm_gpioe +#define AO_QUADRATURE_0_A	15 +#define AO_QUADRATURE_0_B	14 + +#define AO_QUADRATURE_SELECT	0 + +/* + * Buttons + */ + +#define AO_BUTTON_COUNT		9 +#define AO_BUTTON_MODE		AO_EXTI_MODE_PULL_UP + +#define AO_BUTTON_DRAG_MODE	0 +#define AO_BUTTON_0_PORT	&stm_gpioe +#define AO_BUTTON_0		1 + +#define AO_BUTTON_DRAG_SELECT	1 +#define AO_BUTTON_1_PORT	&stm_gpioe +#define AO_BUTTON_1		0 + +#define AO_BUTTON_SPARE1       	2 +#define AO_BUTTON_2_PORT	&stm_gpiob +#define AO_BUTTON_2		9 + +#define AO_BUTTON_SPARE2      	3 +#define AO_BUTTON_3_PORT	&stm_gpiob +#define AO_BUTTON_3		7 + +#define AO_BUTTON_SPARE3       	4 +#define AO_BUTTON_4_PORT	&stm_gpiob +#define AO_BUTTON_4		6 + +#define AO_BUTTON_ARM		5 +#define AO_BUTTON_5_PORT	&stm_gpioe +#define AO_BUTTON_5		12 + +#define AO_BUTTON_FIRE		6 +#define AO_BUTTON_6_PORT	&stm_gpioa +#define AO_BUTTON_6		4 + +#define AO_BUTTON_SPARE4	7 +#define AO_BUTTON_7_PORT	&stm_gpiod +#define AO_BUTTON_7		11 + +#define AO_BUTTON_ENCODER_SELECT	8 +#define AO_BUTTON_8_PORT	&stm_gpioe +#define AO_BUTTON_8		13 + +/* ADC */ + +struct ao_adc { +	int16_t		v_batt; +}; + +#define AO_ADC_DUMP(p) \ +	printf("batt: %5d\n", (p)->v_batt) + +#define HAS_ADC_SINGLE		1 +#define HAS_ADC_TEMP		0 +#define HAS_BATTERY_REPORT	1 + +#define AO_ADC_V_BATT		0 +#define AO_ADC_V_BATT_PORT	(&stm_gpioa) +#define AO_ADC_V_BATT_PIN	0 + +#define AO_ADC_RCC_AHBENR	(1 << STM_RCC_AHBENR_GPIOAEN) + +#define AO_ADC_PIN0_PORT	AO_ADC_V_BATT_PORT +#define AO_ADC_PIN0_PIN		AO_ADC_V_BATT_PIN + +#define AO_ADC_SQ1		AO_ADC_V_BATT + +#define AO_NUM_ADC		1 + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS	15	/* 15k */ +#define AO_BATTERY_DIV_MINUS	27	/* 27k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV	33 + +#endif /* _AO_PINS_H_ */ diff --git a/src/telelco-v2.0/ao_telelco.c b/src/telelco-v2.0/ao_telelco.c new file mode 100644 index 00000000..9693c657 --- /dev/null +++ b/src/telelco-v2.0/ao_telelco.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_exti.h> +#include <ao_packet.h> +#include <ao_companion.h> +#include <ao_profile.h> +#include <ao_pyro.h> +#include <ao_aes.h> +#include <ao_seven_segment.h> +#include <ao_quadrature.h> +#include <ao_button.h> +#include <ao_lco.h> +#include <ao_lco_cmd.h> +#include <ao_radio_cmac_cmd.h> +#include <ao_eeprom.h> +#include <ao_adc_single.h> + +int +main(void) +{ +	ao_clock_init(); +	 +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_GREEN); +	ao_task_init(); + +	ao_timer_init(); + +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); +	ao_adc_single_init(); + +	ao_beep_init(); +	ao_cmd_init(); + +	ao_lcd_stm_init(); +	ao_seven_segment_init(); +	ao_quadrature_init(); +	ao_button_init(); + +	ao_eeprom_init(); +	 +	ao_radio_init(); + +	ao_usb_init(); + +	ao_config_init(); +	 +	ao_lco_init(); +	ao_lco_cmd_init(); +//	ao_radio_cmac_cmd_init(); +	 +	ao_start_scheduler(); +	return 0; +} diff --git a/src/telelco-v2.0/flash-loader/.gitignore b/src/telelco-v2.0/flash-loader/.gitignore new file mode 100644 index 00000000..a32ec26e --- /dev/null +++ b/src/telelco-v2.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +telelco*.elf diff --git a/src/telelco-v2.0/flash-loader/Makefile b/src/telelco-v2.0/flash-loader/Makefile new file mode 100644 index 00000000..b4ec2dad --- /dev/null +++ b/src/telelco-v2.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telelco-v2.0 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telelco-v2.0/flash-loader/ao_pins.h b/src/telelco-v2.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..2292f03c --- /dev/null +++ b/src/telelco-v2.0/flash-loader/ao_pins.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Drag race select button. Press at power on to get boot loader */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioe +#define AO_BOOT_APPLICATION_PIN		0 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telelcotwo-v0.1/Makefile b/src/telelcotwo-v0.1/Makefile index 42188bb2..c68f3eb5 100644 --- a/src/telelcotwo-v0.1/Makefile +++ b/src/telelcotwo-v0.1/Makefile @@ -58,6 +58,7 @@ ALTOS_SRC = \  	ao_button.c \  	ao_event.c \  	ao_lco_two.c \ +	ao_lco_bits.c \  	ao_lco_func.c \  	ao_lco_cmd.c \  	ao_radio_cmac_cmd.c diff --git a/src/telelcotwo-v0.1/ao_pins.h b/src/telelcotwo-v0.1/ao_pins.h index 60e94c67..1941e03d 100644 --- a/src/telelcotwo-v0.1/ao_pins.h +++ b/src/telelcotwo-v0.1/ao_pins.h @@ -141,6 +141,8 @@  				 AO_LED_CONTINUITY_0 |	\  				 AO_LED_REMOTE_ARM) +#define AO_LCO_DRAG		0 +  /*   * Use event queue for input devices   */ diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 2d862f82..746a6814 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -305,7 +305,7 @@ struct ao_task {  #define AO_MS_TO_TICKS(ms)	((ms) / 10)  #define AO_SEC_TO_TICKS(s)	((s) * 100) -#define AO_FLIGHT_TEST +#define AO_FLIGHT_TEST	1  int	ao_flight_debug; @@ -438,10 +438,6 @@ static uint16_t	pyros_fired;  static struct ao_mpu6000_sample	ao_ground_mpu6000;  #endif -#if HAS_ACCEL -int ao_error_h_sq_avg; -#endif -  void  ao_test_exit(void)  { @@ -504,7 +500,7 @@ ao_insert(void)  	ao_data_ring[ao_data_head] = ao_data_static;  	if (ao_flight_state != ao_flight_startup) {  #if HAS_ACCEL -		double  accel = ((ao_flight_ground_accel - ao_data_accel_cook(&ao_data_static)) * GRAVITY * 2.0) / +		double  accel = ((ao_flight_ground_accel - ao_data_accel(&ao_data_static)) * GRAVITY * 2.0) /  			(ao_config.accel_minus_g - ao_config.accel_plus_g);  #else  		double	accel = 0.0; @@ -515,7 +511,12 @@ ao_insert(void)  			tick_offset = -ao_data_static.tick;  		if ((prev_tick - ao_data_static.tick) > 0x400)  			tick_offset += 65536; -		simple_speed += accel * (ao_data_static.tick - prev_tick) / 100.0; +		if (prev_tick) { +			int ticks = ao_data_static.tick - prev_tick; +			if (ticks < 0) +				ticks += 65536; +			simple_speed += accel * ticks / 100.0; +		}  		prev_tick = ao_data_static.tick;  		time = (double) (ao_data_static.tick + tick_offset) / 100; @@ -653,7 +654,7 @@ ao_insert(void)  #if 1  			printf("%7.2f height %8.2f accel %8.3f accel_speed %8.3f " -			       "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d" +			       "state %d k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d"  #if TELEMEGA  			       " angle %5d "  			       "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d " @@ -663,7 +664,7 @@ ao_insert(void)  			       height,  			       accel,  			       simple_speed > -100.0 ? simple_speed : -100.0, -			       ao_state_names[ao_flight_state], +			       ao_flight_state * 10,  			       ao_k_height / 65536.0,  			       ao_k_speed / 65536.0 / 16.0,  			       ao_k_accel / 65536.0 / 16.0, diff --git a/src/test/plottest b/src/test/plottest index 95337f10..5b30cfa5 100755 --- a/src/test/plottest +++ b/src/test/plottest @@ -1,17 +1,33 @@ +#!/bin/bash + +LINEWIDTH=2 +  gnuplot -persist << EOF +set title "$1"  set ylabel "altitude (m)"  set y2label "velocity (m/s), acceleration(m/s²)"  set xlabel "time (s)"  set xtics border out nomirror  set ytics border out nomirror  set y2tics border out nomirror -plot "$1" using 1:3 with lines axes x1y1 title "raw height",\ -"$1" using 1:5 with lines axes x1y2 title "raw accel",\ -"$1" using 1:7 with lines axes x1y2 title "accel speed",\ -"$1" using 1:11 with lines axes x1y1 title "height",\ -"$1" using 1:13 with lines axes x1y2 title "speed",\ -"$1" using 1:15 with lines axes x1y2 title "accel",\ -"$1" using 1:19 with lines axes x1y1 title "drogue",\ -"$1" using 1:21 with lines axes x1y1 title "main",\ -"$1" using 1:23 with lines axes x1y1 title "error" +set style line 1 linewidth $LINEWIDTH +set style line 2 linewidth $LINEWIDTH +set style line 3 linewidth $LINEWIDTH +set style line 4 linewidth $LINEWIDTH +set style line 5 linewidth $LINEWIDTH +set style line 6 linewidth $LINEWIDTH +set style line 7 linewidth $LINEWIDTH dashtype 2 +set style line 8 linewidth $LINEWIDTH dashtype 2 +set style line 9 linewidth $LINEWIDTH dashtype 2 +set style line 10 linewidth $LINEWIDTH dashtype 2 +plot "$1" using 1:3 with lines axes x1y1 title "raw height" ls 1,\ +"$1" using 1:5 with lines axes x1y2 title "raw accel" ls 2,\ +"$1" using 1:7 with lines axes x1y2 title "accel speed" ls 3,\ +"$1" using 1:11 with lines axes x1y1 title "height" ls 4,\ +"$1" using 1:13 with lines axes x1y2 title "speed" ls 5,\ +"$1" using 1:15 with lines axes x1y2 title "accel" ls 6,\ +"$1" using 1:19 with lines axes x1y1 title "drogue" ls 7,\ +"$1" using 1:21 with lines axes x1y1 title "main" ls 8,\ +"$1" using 1:23 with lines axes x1y1 title "error" ls 9,\ +"$1" using 1:9 with lines axes x1y2 title "state" ls 10  EOF diff --git a/src/tmgps-v2.0/.gitignore b/src/tmgps-v2.0/.gitignore new file mode 100644 index 00000000..611e845e --- /dev/null +++ b/src/tmgps-v2.0/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +tmgps-*.elf diff --git a/src/tmgps-v2.0/Makefile b/src/tmgps-v2.0/Makefile new file mode 100644 index 00000000..9e3965c6 --- /dev/null +++ b/src/tmgps-v2.0/Makefile @@ -0,0 +1,117 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_companion.h \ +	ao_data.h \ +	ao_sample.h \ +	ao_pins.h \ +	ao_kalman.h \ +	ao_product.h \ +	ao_cc1120_CC1120.h \ +	ao_profile.h \ +	ao_task.h \ +	ao_whiten.h \ +	ao_sample_profile.h \ +	ao_mpu.h \ +	stm32l.h \ +	Makefile + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#SAMPLE_PROFILE=ao_sample_profile.c \ +#	ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +MATH_SRC=\ +	ef_log.c + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_serial_stm.c \ +	ao_gps_ublox.c \ +	ao_gps_show.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_cc1120.c \ +	ao_fec_tx.c \ +	ao_fec_rx.c \ +	ao_data.c \ +	ao_adc_stm.c \ +	ao_storage.c \ +	ao_m25.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_eeprom_stm.c \ +	ao_convert_volt.c \ +	ao_log.c \ +	ao_log_gps.c \ +	ao_distance.c \ +	ao_sqrt.c \ +	ao_tracker.c \ +	ao_telemetry.c \ +	ao_aprs.c \ +	$(MATH_SRC) \ +	$(PROFILE) \ +	$(SAMPLE_PROFILE) \ +	$(STACK_GUARD) + +PRODUCT=TMGPS-v2.0 +PRODUCT_DEF=-DTMGPS_V_2_0 +IDPRODUCT=0x0025 + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=tmgps-v2.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_tmgps.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +../altitude-pa.h: make-altitude-pa +	nickle $< > $@ + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/tmgps-v2.0/ao_pins.h b/src/tmgps-v2.0/ao_pins.h new file mode 100644 index 00000000..b4dcc10c --- /dev/null +++ b/src/tmgps-v2.0/ao_pins.h @@ -0,0 +1,236 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1		0 +#define USE_SERIAL_1_STDIN	0 +#define SERIAL_1_PB6_PB7	0 +#define SERIAL_1_PA9_PA10	1 + +#define HAS_SERIAL_2		0 +#define USE_SERIAL_2_STDIN	0 +#define SERIAL_2_PA2_PA3	0 +#define SERIAL_2_PD5_PD6	0 + +#define HAS_SERIAL_3		1 +#define USE_SERIAL_3_STDIN	0 +#define SERIAL_3_PB10_PB11	1 +#define SERIAL_3_PC10_PC11	0 +#define SERIAL_3_PD8_PD9	0 + +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX	(512 * 1024) +#define AO_CONFIG_MAX_SIZE			1024 +#define LOG_ERASE_MARK				0x55 +#define LOG_MAX_ERASE				128 + +#define HAS_EEPROM		1 +#define USE_INTERNAL_FLASH	0 +#define USE_EEPROM_CONFIG	1 +#define USE_STORAGE_CONFIG	0 +#define HAS_USB			1 +#define HAS_BEEP		0 +#define HAS_RADIO		1 +#define HAS_TELEMETRY		1 +#define HAS_RDF			1 +#define HAS_APRS		1 +#define HAS_COMPANION		0 + +#define HAS_SPI_1		1 +#define SPI_1_PA5_PA6_PA7	1	/* Barometer */ +#define SPI_1_PB3_PB4_PB5	1	/* Accelerometer */ +#define SPI_1_PE13_PE14_PE15	0 +#define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_SPI_2		1 +#define SPI_2_PB13_PB14_PB15	1	/* Flash, Companion, Radio */ +#define SPI_2_PD1_PD3_PD4	0 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz + +#define SPI_2_PORT		(&stm_gpiob) +#define SPI_2_SCK_PIN		13 +#define SPI_2_MISO_PIN		14 +#define SPI_2_MOSI_PIN		15 + +#define HAS_I2C_1		0 +#define I2C_1_PB8_PB9		0 + +#define HAS_I2C_2		0 +#define I2C_2_PB10_PB11		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT_ENABLE		STM_RCC_AHBENR_GPIOCEN +#define LED_PORT		(&stm_gpioc) +#define LED_PIN_RED		14 +#define LED_PIN_GREEN		15 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) + +#define AO_LED_PANIC	AO_LED_RED +#define AO_LED_GPS_LOCK	AO_LED_GREEN + +#define LEDS_AVAILABLE		(AO_LED_RED | AO_LED_GREEN) + +#define HAS_GPS			1 +#define HAS_FLIGHT		0 +#define HAS_ADC			1 +#define HAS_ADC_TEMP		0 +#define HAS_LOG			1 +#define HAS_TRACKER		1 +#define LOG_ADC			0 +#define AO_LOG_FORMAT				AO_LOG_FORMAT_TELEGPS + +/* + * ADC + */ +#define AO_DATA_RING		32 +#define AO_ADC_NUM_SENSE	2 + +struct ao_adc { +	int16_t			v_batt; +}; + +#define AO_ADC_DUMP(p) \ +	printf("tick: %5u batt: %5d\n", \ +	       (p)->tick, \ +	       (p)->adc.v_batt); + +#define AO_ADC_V_BATT		8 +#define AO_ADC_V_BATT_PORT	(&stm_gpiob) +#define AO_ADC_V_BATT_PIN	0 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_GPIOBEN)) + +#define AO_NUM_ADC_PIN		1 + +#define AO_ADC_PIN0_PORT	AO_ADC_V_BATT_PORT +#define AO_ADC_PIN0_PIN		AO_ADC_V_BATT_PIN + +#define AO_NUM_ADC	       	(AO_NUM_ADC_PIN) + +#define AO_ADC_SQ1		AO_ADC_V_BATT + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS	56	/* 5.6k */ +#define AO_BATTERY_DIV_MINUS	100	/* 10k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV	33 + +/* + * GPS + */ + +#define AO_SERIAL_SPEED_UBLOX	AO_SERIAL_SPEED_9600 + +#define ao_gps_getchar		ao_serial3_getchar +#define ao_gps_putchar		ao_serial3_putchar +#define ao_gps_set_speed	ao_serial3_set_speed +#define ao_gps_fifo		(ao_stm_usart3.rx_fifo) + +/* + * SPI Flash memory + */ + +#define M25_MAX_CHIPS		1 +#define AO_M25_SPI_CS_PORT	(&stm_gpiob) +#define AO_M25_SPI_CS_MASK	(1 << 8) +#define AO_M25_SPI_BUS		AO_SPI_2_PB13_PB14_PB15 + +/* + * Radio (cc1120) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 	0x6ca333 + +#define AO_FEC_DEBUG		0 +#define AO_CC1120_SPI_CS_PORT	(&stm_gpioa) +#define AO_CC1120_SPI_CS_PIN	2 +#define AO_CC1120_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1120_SPI		stm_spi2 + +#define AO_CC1120_INT_PORT		(&stm_gpioa) +#define AO_CC1120_INT_PIN		(3) +#define AO_CC1120_MCU_WAKEUP_PORT	(&stm_gpioa) +#define AO_CC1120_MCU_WAKEUP_PIN	(4) + +#define AO_CC1120_INT_GPIO	2 +#define AO_CC1120_INT_GPIO_IOCFG	CC1120_IOCFG2 + +#define AO_CC1120_MARC_GPIO	3 +#define AO_CC1120_MARC_GPIO_IOCFG	CC1120_IOCFG3 + +#define HAS_BOOT_RADIO		0 + +#define NUM_CMDS		16 + +/* + * Monitor + */ + +#define HAS_MONITOR		0 +#define LEGACY_MONITOR		0 +#define HAS_MONITOR_PUT		1 +#define AO_MONITOR_LED		0 +#define HAS_RSSI		0 + +/* + * Profiling Viterbi decoding + */ + +#ifndef AO_PROFILE +#define AO_PROFILE	       	0 +#endif + +#endif /* _AO_PINS_H_ */ diff --git a/src/tmgps-v2.0/ao_tmgps.c b/src/tmgps-v2.0/ao_tmgps.c new file mode 100644 index 00000000..cbd58eb2 --- /dev/null +++ b/src/tmgps-v2.0/ao_tmgps.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_log.h> +#include <ao_exti.h> +#include <ao_tracker.h> +#include <ao_eeprom.h> +#include <ao_profile.h> +#if HAS_SAMPLE_PROFILE +#include <ao_sample_profile.h> +#endif +#if HAS_STACK_GUARD +#include <ao_mpu.h> +#endif + +int +main(void) +{ +	ao_clock_init(); + +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init(); +	ao_cmd_init(); +	ao_config_init(); + +	/* Turn on all of the LEDs to test them */ +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(LEDS_AVAILABLE); + +	/* Internal systems */ +	ao_timer_init(); +	ao_dma_init(); +	ao_exti_init(); + +	/* SoC hardware */ +	ao_spi_init(); +	ao_adc_init(); +	ao_serial_init(); +	ao_usb_init(); +	ao_eeprom_init(); + +	/* External hardware */ +	ao_storage_init(); +	ao_radio_init(); +	ao_gps_init(); + +	/* Services */ +	ao_log_init(); +	ao_telemetry_init(); +	ao_tracker_init(); + +#if AO_PROFILE +	ao_profile_init(); +#endif +#if HAS_SAMPLE_PROFILE +	ao_sample_profile_init(); +#endif +	ao_led_off(LEDS_AVAILABLE); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/vidtime/.gitignore b/src/vidtime/.gitignore new file mode 100644 index 00000000..471b7fd9 --- /dev/null +++ b/src/vidtime/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +vidtime-* diff --git a/src/vidtime/Makefile b/src/vidtime/Makefile new file mode 100644 index 00000000..327614bc --- /dev/null +++ b/src/vidtime/Makefile @@ -0,0 +1,65 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	stm32f0.h \ +	Makefile + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_dma_stm.c \ +	ao_exti_stm.c \ +	ao_task.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_usb_stm.c + +PRODUCT=VidTime +PRODUCT_DEF=-DVIDTIME +IDPRODUCT=0x002b + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g + +PROGNAME=vidtime-v1.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_vidtime.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/vidtime/ao_pins.h b/src/vidtime/ao_pins.h new file mode 100644 index 00000000..fe9d3879 --- /dev/null +++ b/src/vidtime/ao_pins.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +#define IS_FLASH_LOADER	0 + +#define AO_POWER_MANAGEMENT	0 + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_EEPROM		0 +#define USE_INTERNAL_FLASH	0 +#define USE_STORAGE_CONFIG	0 +#define USE_EEPROM_CONFIG	0 + +#define HAS_BEEP		0 + +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#define HAS_SPI_0		0 + +#define AO_SENSOR_PORT		(&stm_gpioa) +#define AO_SENSOR_PIN		3 + +#define LOW_LEVEL_DEBUG		0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/vidtime/ao_vidtime.c b/src/vidtime/ao_vidtime.c new file mode 100644 index 00000000..1b9b9e1c --- /dev/null +++ b/src/vidtime/ao_vidtime.c @@ -0,0 +1,97 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_exti.h> + +static uint8_t	sensor_value; +static uint8_t	vidtime_monitor; + +static void +vidtime(void) +{ +	uint8_t	old = 0, got; + +	ao_exti_enable(AO_SENSOR_PORT, AO_SENSOR_PIN); +	for (;;) { +		while (!vidtime_monitor) +			ao_sleep(&vidtime_monitor); +		while ((got = sensor_value) == old) +			ao_sleep(&sensor_value); +		printf("%d\n", got); +		flush(); +		old = got; +	} +} + +static void +sensor_interrupt(void) +{ +	sensor_value = ao_gpio_get(AO_SENSOR_PORT, AO_SENSOR_PIN, foo); +	ao_wakeup(&sensor_value); +} + +static struct ao_task	vidtime_task; + +static void +ao_init_vidtime(void) +{ +	ao_enable_port(AO_SENSOR_PORT); +	ao_exti_setup(AO_SENSOR_PORT, AO_SENSOR_PIN, +		      AO_EXTI_MODE_RISING| +		      AO_EXTI_MODE_FALLING| +		      AO_EXTI_MODE_PULL_NONE| +		      AO_EXTI_PRIORITY_MED, +		      sensor_interrupt); +	ao_add_task(&vidtime_task, vidtime, "vidtime"); +} + +static void +ao_set_vidtime(void) +{ +	ao_cmd_decimal(); +	if (ao_cmd_status == ao_cmd_success) { +		vidtime_monitor = ao_cmd_lex_i != 0; +		ao_wakeup(&vidtime_monitor); +	} +} + +const struct ao_cmds	ao_vidtime_cmds[] = { +	{ ao_set_vidtime, "V <0 off, 1 on>\0Enable/disable timing monitor" }, +	{ 0, NULL } +}; + +void main(void) +{ +	ao_clock_init(); + +	ao_task_init(); + +	ao_timer_init(); + +	ao_dma_init(); + +	ao_init_vidtime(); + +	ao_usb_init(); + +	ao_cmd_init(); + +	ao_cmd_register(&ao_vidtime_cmds[0]); + +	ao_start_scheduler(); +} diff --git a/src/vidtime/flash-loader/.gitignore b/src/vidtime/flash-loader/.gitignore new file mode 100644 index 00000000..05f1a4dc --- /dev/null +++ b/src/vidtime/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +vidtime* diff --git a/src/vidtime/flash-loader/Makefile b/src/vidtime/flash-loader/Makefile new file mode 100644 index 00000000..57c65b5e --- /dev/null +++ b/src/vidtime/flash-loader/Makefile @@ -0,0 +1,7 @@ +# +# AltOS flash loader build +# + +TOPDIR=../.. +HARDWARE=vidtime-v1.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/vidtime/flash-loader/ao_pins.h b/src/vidtime/flash-loader/ao_pins.h new file mode 100644 index 00000000..7feb9362 --- /dev/null +++ b/src/vidtime/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Debug port PA15 (pin 23) */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	(stm_gpioa) +#define AO_BOOT_APPLICATION_PIN		15 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#endif /* _AO_PINS_H_ */  | 
