src/telemega-v2.0/telemega-v2.0-$(VERSION).ihx \
src/telemega-v3.0/telemega-v3.0-$(VERSION).ihx \
src/telemega-v4.0/telemega-v4.0-$(VERSION).ihx \
+ src/telemega-v5.0/telemega-v5.0-$(VERSION).ihx \
src/telemetrum-v2.0/telemetrum-v2.0-$(VERSION).ihx \
src/telemetrum-v3.0/telemetrum-v3.0-$(VERSION).ihx \
src/telelco-v2.0/telelco-v2.0-$(VERSION).ihx \
src/teledongle-v3.0/{*.elf,*.ihx,*.map} \
src/telegps-v1.0/{*.elf,*.ihx,*.map} \
src/telegps-v2.0/{*.elf,*.ihx,*.map} \
- src/telemega-v[1-4].0/{*.elf,*.ihx,*.map} \
+ src/telemega-v[1-5].0/{*.elf,*.ihx,*.map} \
src/telemetrum-v2.0/{*.elf,*.ihx,*.map} \
src/telemetrum-v3.0/{*.elf,*.ihx,*.map} \
src/telemini-v3.0/{*.elf,*.ihx,*.map} \
src/teledongle-v3.0/flash-loader/*.elf \
src/telegps-v1.0/flash-loader/*.elf \
src/telegps-v2.0/flash-loader/{*.elf,*.bin,*.map} \
- src/telemega-v[1-4].0/flash-loader/*.elf \
+ src/telemega-v[1-5].0/flash-loader/*.elf \
src/telemetrum-v2.0/flash-loader/*.elf \
src/telemetrum-v3.0/flash-loader/*.elf \
src/telemini-v3.0/flash-loader/{*.elf,*.bin,*.map} \
private void enable_location_updates() {
// Listen for GPS and Network position updates
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
- location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+ if (locationManager != null)
+ {
+ try {
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+ location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+ } catch (Exception e) {
+ locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, this);
+ location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+ }
- if (location != null)
- AltosDebug.debug("Resume, location is %f,%f\n",
- location.getLatitude(),
- location.getLongitude());
+ if (location != null)
+ AltosDebug.debug("Resume, location is %f,%f\n",
+ location.getLatitude(),
+ location.getLongitude());
+ AltosDebug.debug("Failed to get GPS updates\n");
+ }
update_ui(telemetry_state, state, true);
}
// Listen for GPS and Network position updates
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+ try {
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+ } catch (Exception e) {
+ locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, this);
+ }
new AltosLaunchSites(this);
}
public class TabFlight extends AltosDroidTab {
private TextView speed_view;
private TextView height_view;
+ private TextView altitude_view;
+ private View tilt_view;
+ private TextView tilt_value;
private TextView max_speed_view;
private TextView max_height_view;
+ private TextView max_altitude_view;
private TextView elevation_view;
private TextView range_view;
private TextView bearing_view;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.tab_flight, container, false);
- speed_view = (TextView) v.findViewById(R.id.speed_value);
- height_view = (TextView) v.findViewById(R.id.height_value);
- max_speed_view = (TextView) v.findViewById(R.id.max_speed_value);
- max_height_view= (TextView) v.findViewById(R.id.max_height_value);
+ speed_view = (TextView) v.findViewById(R.id.speed_value);
+ height_view = (TextView) v.findViewById(R.id.height_value);
+ altitude_view = (TextView) v.findViewById(R.id.altitude_value);
+ tilt_view = (View) v.findViewById(R.id.tilt_view);
+ tilt_value = (TextView) v.findViewById(R.id.tilt_value);
+ max_speed_view = (TextView) v.findViewById(R.id.max_speed_value);
+ max_height_view = (TextView) v.findViewById(R.id.max_height_value);
+ max_altitude_view= (TextView) v.findViewById(R.id.max_altitude_value);
elevation_view = (TextView) v.findViewById(R.id.elevation_value);
range_view = (TextView) v.findViewById(R.id.range_value);
bearing_view = (TextView) v.findViewById(R.id.bearing_value);
if (state != null) {
set_value(speed_view, AltosConvert.speed, 1, state.speed());
set_value(height_view, AltosConvert.height, 1, state.height());
+ set_value(altitude_view, AltosConvert.height, 1, state.altitude());
+ double orient = state.orient();
+ if (orient == AltosLib.MISSING) {
+ tilt_view.setVisibility(View.GONE);
+ } else {
+ tilt_value.setText(AltosDroid.number("%1.0f°", orient));
+ tilt_view.setVisibility(View.VISIBLE);
+ }
set_value(max_speed_view, AltosConvert.speed, 1, state.max_speed());
set_value(max_height_view, AltosConvert.height, 1, state.max_height());
+ set_value(max_altitude_view, AltosConvert.height, 1, state.max_altitude());
if (from_receiver != null) {
elevation_view.setText(AltosDroid.number("%1.0f°", from_receiver.elevation));
set_value(range_view, AltosConvert.distance, 1, from_receiver.range);
private TextView[] ignite_voltage_label = new TextView[4];
private GoNoGoLights[] ignite_lights = new GoNoGoLights[4];
+ private View tilt_view;
+ private TextView tilt_value;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
(ImageView) v.findViewById(R.id.gps_ready_greenled),
getResources());
+ tilt_view = (View) v.findViewById(R.id.tilt_view);
+ tilt_value = (TextView) v.findViewById(R.id.tilt_value);
+
for (int i = 0; i < 4; i++) {
int row_id, view_id, label_id, lights_id;
int red_id, green_id;
} else
gps_locked_lights.set(false, true);
gps_ready_lights.set(state.gps_ready, state.gps == null);
+
+ double orient = state.orient();
+
+ if (orient == AltosLib.MISSING) {
+ tilt_view.setVisibility(View.GONE);
+ } else {
+ tilt_value.setText(AltosDroid.number("%1.0f°", orient));
+ tilt_view.setVisibility(View.VISIBLE);
+ }
}
+
if (telem_state != null) {
if (telem_state.receiver_battery == AltosLib.MISSING) {
receiver_row.setVisibility(View.GONE);
android:textAppearance="?android:attr/textAppearanceSmall" />
</TableRow>
+ <TableRow
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+
+ <TextView
+ android:id="@+id/altitude_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/altitude_label" />
+
+ <TextView
+ android:id="@+id/altitude_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/tilt_view"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+
+ <TextView
+ android:id="@+id/tilt_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/tilt_label" />
+
+ <TextView
+ android:id="@+id/tilt_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
<TableRow
android:layout_gravity="center"
android:layout_weight="1"
android:text="" />
</TableRow>
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+
+ <TextView
+ android:id="@+id/max_altitude_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/max_altitude_label" />
+
+ <TextView
+ android:id="@+id/max_altitude_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="" />
+ </TableRow>
+
<TableRow
android:layout_weight="1"
android:padding="2dip"
android:textAppearance="?android:attr/textAppearanceSmall" />
</TableRow>
+ <TableRow
+ android:id="@+id/tilt_view"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+
+ <TextView
+ android:id="@+id/tilt_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/tilt_label" />
+
+ <TextView
+ android:id="@+id/tilt_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
<TableRow
android:padding="2dip"
android:layout_width="wrap_content"
<!-- Tab fields -->
<string name="height_label">Height</string>
+ <string name="altitude_label">Altitude</string>
<string name="speed_label">Speed</string>
<string name="accel_label">Acceleration</string>
+ <string name="tilt_label">Tilt</string>
<string name="bearing_label">Bearing</string>
<string name="direction_label">Direction</string>
<string name="elevation_label">Elevation</string>
<string name="distance_label">Distance</string>
<string name="gnd_distance_label">Ground Distance</string>
<string name="max_height_label">Max Height</string>
+ <string name="max_altitude_label">Max Altitude</string>
<string name="max_speed_label">Max Speed</string>
<string name="max_accel_label">Max Accel</string>
<string name="battery_voltage_label">Battery</string>
return temp_gps;
}
- public int imu_type = AltosLib.MISSING;;
+ public int imu_type = AltosLib.MISSING;
+
+ public int imu_model = AltosLib.MISSING;
+
+ public int mag_model = AltosLib.MISSING;
public void set_imu_type(int imu_type) {
this.imu_type = imu_type;
}
+ public void set_imu_model(int imu_model) {
+ this.imu_model = imu_model;
+ }
+
+ public void set_mag_model(int mag_model) {
+ this.mag_model = mag_model;
+ }
+
public double accel_zero_along, accel_zero_across, accel_zero_through;
public void set_accel_zero(double zero_along, double zero_across, double zero_through) {
}
public double accel_along(double counts) {
- return AltosIMU.convert_accel(counts - accel_zero_along, imu_type);
+ return AltosIMU.convert_accel(counts - accel_zero_along, imu_type, imu_model);
}
public double accel_across(double counts) {
- return AltosIMU.convert_accel(counts - accel_zero_across, imu_type);
+ return AltosIMU.convert_accel(counts - accel_zero_across, imu_type, imu_model);
}
public double accel_through(double counts) {
- return AltosIMU.convert_accel(counts - accel_zero_through, imu_type);
+ return AltosIMU.convert_accel(counts - accel_zero_through, imu_type, imu_model);
}
public double gyro_zero_roll = AltosLib.MISSING;
if (gyro_zero_roll == AltosLib.MISSING || counts == AltosLib.MISSING)
return AltosLib.MISSING;
- return AltosIMU.gyro_degrees_per_second(counts - gyro_zero_roll, imu_type);
+ return AltosIMU.gyro_degrees_per_second(counts - gyro_zero_roll, imu_type, imu_model);
}
public double gyro_pitch(double counts) {
if (gyro_zero_pitch == AltosLib.MISSING || counts == AltosLib.MISSING)
return AltosLib.MISSING;
- return AltosIMU.gyro_degrees_per_second(counts - gyro_zero_pitch, imu_type);
+ return AltosIMU.gyro_degrees_per_second(counts - gyro_zero_pitch, imu_type, imu_model);
}
public double gyro_yaw(double counts) {
if (gyro_zero_yaw == AltosLib.MISSING || counts == AltosLib.MISSING)
return AltosLib.MISSING;
- return AltosIMU.gyro_degrees_per_second(counts - gyro_zero_yaw, imu_type);
+ return AltosIMU.gyro_degrees_per_second(counts - gyro_zero_yaw, imu_type, imu_model);
}
private double gyro_zero_overflow(double first) {
public double mag_along(double along) {
if (along == AltosLib.MISSING)
return AltosLib.MISSING;
- return AltosIMU.convert_gauss(along, imu_type, AltosIMU.mag_along_axis(imu_type));
+ return AltosMag.convert_gauss(along, imu_type, mag_model);
}
public double mag_across(double across) {
if (across == AltosLib.MISSING)
return AltosLib.MISSING;
- return AltosIMU.convert_gauss(across, imu_type, AltosIMU.mag_across_axis(imu_type));
+ return AltosMag.convert_gauss(across, imu_type, mag_model);
}
public double mag_through(double through) {
if (through == AltosLib.MISSING)
return AltosLib.MISSING;
- return AltosIMU.convert_gauss(through, imu_type, AltosIMU.mag_through_axis(imu_type));
+ return AltosMag.convert_gauss(through, imu_type, mag_model);
}
public AltosCalData() {
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
case AltosLib.AO_LOG_FORMAT_EASYMEGA_2:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_4:
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA_5:
return data32(16);
case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
return data16(14);
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
case AltosLib.AO_LOG_FORMAT_EASYMEGA_2:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_4:
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA_5:
return data32(20);
case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
return data16(16);
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
case AltosLib.AO_LOG_FORMAT_EASYMEGA_2:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_4:
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA_5:
return data32(24);
case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
return data16(18);
private int mag_z() { return data16(22); }
private int mag_y() { return data16(24); }
+ /* normalized log data */
+ private int norm_accel_along() { return data16(8); }
+ private int norm_accel_across() { return data16(10); }
+ private int norm_accel_through() { return data16(12); }
+ private int norm_gyro_roll() { return data16(14); }
+ private int norm_gyro_pitch() { return data16(16); }
+ private int norm_gyro_yaw() { return data16(18); }
+ private int norm_mag_along() { return data16(20); }
+ private int norm_mag_across() { return data16(22); }
+ private int norm_mag_through() { return data16(24); }
+
private int imu_type() {
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
}
}
+ private int imu_model() {
+ switch (log_format) {
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA_5:
+ return AltosLib.model_mpu6000;
+ }
+ return AltosLib.MISSING;
+ }
+
+ private boolean sensor_normalized() {
+ switch (log_format) {
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA_5:
+ return true;
+ }
+ return false;
+ }
+
+ private int mag_model() {
+ switch (log_format) {
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA_5:
+ return AltosLib.model_mmc5983;
+ }
+ return AltosLib.MISSING;
+ }
+
private int accel_across() {
+ if (sensor_normalized()) {
+ return norm_accel_across();
+ }
+
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
}
private int accel_along(){
+ if (sensor_normalized()) {
+ return norm_accel_along();
+ }
+
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
}
private int accel_through() {
+ if (sensor_normalized()) {
+ return norm_accel_through();
+ }
+
return accel_z();
}
private int gyro_pitch() {
+ if (sensor_normalized()) {
+ return norm_gyro_pitch();
+ }
+
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
}
private int gyro_roll() {
+ if (sensor_normalized()) {
+ return norm_gyro_roll();
+ }
+
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
}
private int gyro_yaw() {
+ if (sensor_normalized()) {
+ return norm_gyro_yaw();
+ }
+
return gyro_z();
}
private int mag_across() {
+ if (sensor_normalized()) {
+ return norm_mag_across();
+ }
+
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
}
private int mag_along() {
+ if (sensor_normalized()) {
+ return norm_mag_along();
+ }
+
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
}
private int mag_through() {
+ if (sensor_normalized()) {
+ return norm_mag_through();
+ }
+
return mag_z();
}
AltosGPS gps;
cal_data.set_imu_type(imu_type());
+ cal_data.set_imu_model(imu_model());
+ cal_data.set_mag_model(mag_model());
switch (cmd()) {
case AltosLib.AO_LOG_FLIGHT:
public int accel_y = AltosLib.MISSING;
public int accel_z = AltosLib.MISSING;
+ public int accel_along = AltosLib.MISSING;
+ public int accel_across = AltosLib.MISSING;
+ public int accel_through = AltosLib.MISSING;
+
public int gyro_x = AltosLib.MISSING;
public int gyro_y = AltosLib.MISSING;
public int gyro_z = AltosLib.MISSING;
+ public int gyro_roll = AltosLib.MISSING;
+ public int gyro_pitch = AltosLib.MISSING;
+ public int gyro_yaw = AltosLib.MISSING;
+
public int mag_x = AltosLib.MISSING;
public int mag_y = AltosLib.MISSING;
public int mag_z = AltosLib.MISSING;
+ public int mag_along = AltosLib.MISSING;
+ public int mag_across = AltosLib.MISSING;
+ public int mag_through = AltosLib.MISSING;
+
+ public int imu_model = AltosLib.MISSING;
+ public int mag_model = AltosLib.MISSING;
+
public static final double counts_per_g_mpu = 2048.0;
public static final double counts_per_g_bmx = 2048.0;
public static final double counts_per_g_adxl = 20.5;
- private static double counts_per_g(int imu_type) {
+ private static double counts_per_g(int imu_type, int imu_model) {
+ switch (imu_model) {
+ case AltosLib.model_mpu6000:
+ case AltosLib.model_mpu9250:
+ return counts_per_g_mpu;
+ case AltosLib.model_adxl375:
+ return counts_per_g_adxl;
+ case AltosLib.model_bmx160:
+ return counts_per_g_bmx;
+ }
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
return counts_per_g_bmx;
case imu_type_easymotor_v2:
return counts_per_g_adxl;
- default:
- return AltosLib.MISSING;
}
+
+ return AltosLib.MISSING;
}
- public static double convert_accel(double counts, int imu_type) {
- double cpg = counts_per_g(imu_type);
+ public static double convert_accel(double counts, int imu_type, int imu_model) {
+ double cpg = counts_per_g(imu_type, imu_model);
if (cpg == AltosLib.MISSING)
return AltosLib.MISSING;
return counts / cpg * AltosConvert.gravity;
public static final double GYRO_COUNTS_BMX = 32767.0;
public static final double counts_per_degree_bmx = GYRO_COUNTS_BMX / GYRO_FULLSCALE_DEGREES_BMX;
- private static double counts_per_degree(int imu_type) {
+ private static double counts_per_degree(int imu_type, int imu_model) {
+ switch (imu_model) {
+ case AltosLib.model_mpu6000:
+ case AltosLib.model_mpu9250:
+ return counts_per_degree_mpu;
+ case AltosLib.model_bmx160:
+ return counts_per_degree_bmx;
+ }
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
}
- public static double gyro_degrees_per_second(double counts, int imu_type) {
- double cpd = counts_per_degree(imu_type);
+ public static double gyro_degrees_per_second(double counts, int imu_type, int imu_model) {
+ double cpd = counts_per_degree(imu_type, imu_model);
+
if (cpd == AltosLib.MISSING)
return AltosLib.MISSING;
return counts / cpd;
}
- public static final int imu_axis_x = 0;
- public static final int imu_axis_y = 1;
- public static final int imu_axis_z = 2;
-
public static final double MAG_FULLSCALE_GAUSS_MPU = 48.00; /* 4800µT */
public static final double MAG_COUNTS_MPU = 32767.0;
public static final double counts_per_gauss_mpu = MAG_COUNTS_MPU / MAG_FULLSCALE_GAUSS_MPU;
public static final double counts_per_gauss_bmx = 100.0; /* BMX driver converts to µT */
- public static double counts_per_gauss(int imu_type, int axis) {
+ public static double counts_per_gauss(int imu_type, int imu_model) {
+ switch (imu_model) {
+ case AltosLib.model_mpu9250:
+ return counts_per_gauss_mpu;
+ case AltosLib.model_bmx160:
+ return counts_per_gauss_bmx;
+ }
+
switch(imu_type) {
- case imu_type_telemega_v1_v2:
- case imu_type_easymega_v1:
- return AltosMag.counts_per_gauss;
case imu_type_telemega_v3:
case imu_type_easymega_v2:
return counts_per_gauss_mpu;
case imu_type_telemega_v4:
case imu_type_easytimer_v1:
- return 100.0;
- default:
- return AltosLib.MISSING;
+ return counts_per_gauss_bmx;
}
- }
-
- public static double convert_gauss(double counts, int imu_type, int imu_axis) {
- double cpg = counts_per_gauss(imu_type, imu_axis);
- if (cpg == AltosLib.MISSING)
- return AltosLib.MISSING;
- return counts / cpg;
+ return AltosLib.MISSING;
}
public boolean parse_string(String line) {
- if (!line.startsWith("Accel:"))
- return false;
+ if (line.startsWith("Accel:")) {
- String[] items = line.split("\\s+");
+ String[] items = line.split("\\s+");
- if (items.length >= 8) {
- accel_x = Integer.parseInt(items[1]);
- accel_y = Integer.parseInt(items[2]);
- accel_z = Integer.parseInt(items[3]);
- gyro_x = Integer.parseInt(items[5]);
- gyro_y = Integer.parseInt(items[6]);
- gyro_z = Integer.parseInt(items[7]);
+ if (items.length >= 8) {
+ accel_x = Integer.parseInt(items[1]);
+ accel_y = Integer.parseInt(items[2]);
+ accel_z = Integer.parseInt(items[3]);
+ gyro_x = Integer.parseInt(items[5]);
+ 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;
}
- if (items.length >= 12) {
- mag_x = Integer.parseInt(items[9]);
- mag_y = Integer.parseInt(items[10]);
- mag_z = Integer.parseInt(items[11]);
+ if (line.startsWith("MPU6000:")) {
+ String[] items = line.split("\\s+");
+
+ imu_model = AltosLib.model_mpu6000;
+
+ if (items.length >= 7) {
+ accel_along = Integer.parseInt(items[1]);
+ accel_across = Integer.parseInt(items[2]);
+ accel_through = Integer.parseInt(items[3]);
+ gyro_roll = Integer.parseInt(items[4]);
+ gyro_pitch = Integer.parseInt(items[5]);
+ gyro_yaw = Integer.parseInt(items[6]);
+ }
+ return true;
}
- return true;
+
+ return false;
}
public AltosIMU clone() {
n.accel_y = accel_y;
n.accel_z = accel_z;
+ n.accel_along = accel_along;
+ n.accel_across = accel_across;
+ n.accel_through = accel_through;
+
n.gyro_x = gyro_x;
n.gyro_y = gyro_y;
n.gyro_z = gyro_z;
+ n.gyro_roll = gyro_roll;
+ n.gyro_pitch = gyro_pitch;
+ n.gyro_yaw = gyro_yaw;
+
n.mag_x = mag_x;
n.mag_y = mag_y;
n.mag_z = mag_z;
+ n.mag_along = mag_along;
+ n.mag_across = mag_across;
+ n.mag_through = mag_through;
+
return n;
}
public static final int imu_type_easymotor_v2 = 6; /* ADXL375 (accel only) */
private int accel_across(int imu_type) {
+
+ if (accel_across != AltosLib.MISSING)
+ return accel_across;
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
private int accel_along(int imu_type) {
+ if (accel_along != AltosLib.MISSING)
+ return accel_along;
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
private int accel_through(int imu_type) {
+ if (accel_through != AltosLib.MISSING)
+ return accel_through;
+
return accel_z;
}
private int gyro_roll(int imu_type) {
+ if (gyro_roll != AltosLib.MISSING)
+ return gyro_roll;
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
private int gyro_pitch(int imu_type) {
+ if (gyro_pitch != AltosLib.MISSING)
+ return gyro_pitch;
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
private int gyro_yaw(int imu_type) {
- return gyro_z;
- }
+ if (gyro_yaw != AltosLib.MISSING)
+ return gyro_yaw;
- public static int mag_across_axis(int imu_type) {
- switch (imu_type) {
- case imu_type_telemega_v1_v2:
- case imu_type_telemega_v3:
- case imu_type_easymega_v1:
- return imu_axis_x;
- case imu_type_easymega_v2:
- case imu_type_telemega_v4:
- case imu_type_easytimer_v1:
- return imu_axis_y;
- default:
- return AltosLib.MISSING;
- }
+ return gyro_z;
}
private int mag_across(int imu_type) {
+ if (mag_across != AltosLib.MISSING)
+ return mag_across;
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
}
- public static int mag_along_axis(int imu_type) {
- switch (imu_type) {
- case imu_type_telemega_v1_v2:
- case imu_type_telemega_v3:
- case imu_type_easymega_v1:
- return imu_axis_y;
- case imu_type_easymega_v2:
- case imu_type_telemega_v4:
- case imu_type_easytimer_v1:
- return imu_axis_x;
- default:
- return AltosLib.MISSING;
- }
- }
-
private int mag_along(int imu_type) {
+ if (mag_along != AltosLib.MISSING)
+ return mag_along;
+
switch (imu_type) {
case imu_type_telemega_v1_v2:
case imu_type_telemega_v3:
}
}
+ private int mag_through(int imu_type) {
+ if (mag_through != AltosLib.MISSING)
+ return mag_through;
+
+ return mag_z;
+ }
+
private static boolean is_primary_accel(int imu_type) {
switch (imu_type) {
case imu_type_easytimer_v1:
}
}
- public static int mag_through_axis(int imu_type) {
- return imu_axis_z;
- }
-
- private int mag_through(int imu_type) {
- return mag_z;
- }
-
static public void provide_data(AltosDataListener listener, AltosLink link, int imu_type) throws InterruptedException {
try {
AltosIMU imu = new AltosIMU(link);
AltosCalData cal_data = listener.cal_data();
- cal_data.set_imu_type(imu_type);
-
+ if (imu_type != AltosLib.MISSING)
+ cal_data.set_imu_type(imu_type);
if (imu != null) {
- if (imu.gyro_x != AltosLib.MISSING) {
+ if (imu.imu_model != AltosLib.MISSING)
+ cal_data.set_imu_model(imu.imu_model);
+ if (imu.mag_model != AltosLib.MISSING)
+ cal_data.set_mag_model(imu.mag_model);
+
+ if (imu.gyro_roll(imu_type) != AltosLib.MISSING) {
cal_data.set_gyro_zero(0, 0, 0);
listener.set_gyro(cal_data.gyro_roll(imu.gyro_roll(imu_type)),
cal_data.gyro_pitch(imu.gyro_pitch(imu_type)),
accel = -accel;
listener.set_acceleration(cal_data.acceleration(accel));
}
- if (imu.mag_x != AltosLib.MISSING) {
+ if (imu.mag_along(imu_type) != AltosLib.MISSING) {
listener.set_mag(cal_data.mag_along(imu.mag_along(imu_type)),
cal_data.mag_across(imu.mag_across(imu_type)),
cal_data.mag_through(imu.mag_through(imu_type)));
}
public AltosIMU() {
- accel_x = AltosLib.MISSING;
- accel_y = AltosLib.MISSING;
- accel_z = AltosLib.MISSING;
-
- 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 {
static final int idle_ms5607 = 9;
static final int idle_adxl375 = 10;
static final int idle_adxl375_easymotor_v2 = 11;
+ static final int idle_imu = 12;
static final int idle_sensor_tm = 100;
static final int idle_sensor_metrum = 101;
case idle_imu_et_v1:
AltosIMU.provide_data(listener, link, AltosIMU.imu_type_easytimer_v1);
break;
+ case idle_imu:
+ AltosIMU.provide_data(listener, link, AltosLib.MISSING);
+ break;
case idle_mag:
AltosMag.provide_data(listener, link);
break;
AltosIdler.idle_ms5607,
AltosIdler.idle_imu_tm_v4,
AltosIdler.idle_sensor_mega),
+ new AltosIdler("TeleMega-v5",
+ AltosIdler.idle_gps,
+ AltosIdler.idle_adxl375,
+ AltosIdler.idle_ms5607,
+ AltosIdler.idle_imu, AltosIdler.idle_mag,
+ AltosIdler.idle_sensor_mega),
new AltosIdler("EasyMega-v1",
AltosIdler.idle_mma655x,
AltosIdler.idle_ms5607,
public static final int AO_LOG_FORMAT_MICROPEAK2 = 18;
public static final int AO_LOG_FORMAT_TELEMEGA_4 = 19;
public static final int AO_LOG_FORMAT_EASYMOTOR = 20;
+ public static final int AO_LOG_FORMAT_TELEMEGA_5 = 21;
public static final int AO_LOG_FORMAT_NONE = 127;
+ public static final int model_mpu6000 = 0;
+ public static final int model_mpu9250 = 1;
+ public static final int model_adxl375 = 2;
+ public static final int model_bmx160 = 3;
+ public static final int model_hmc5883 = 4;
+ public static final int model_mmc5983 = 5;
+
public static boolean isspace(int c) {
switch (c) {
case ' ':
import java.io.*;
public class AltosMag implements Cloneable {
- public int x;
- public int z;
- public int y;
+ public int along = AltosLib.MISSING;
+ public int across = AltosLib.MISSING;
+ public int through = AltosLib.MISSING;
- public static final double counts_per_gauss = 1090;
+ public static final int model_hmc5883 = 0;
+ public static final int model_mmc5983 = 1;
- public static double convert_gauss(double counts) {
- return counts / counts_per_gauss;
+ public int mag_model = AltosLib.MISSING;
+
+ public static final double counts_per_gauss_hmc5883 = 1090;
+ public static final double counts_per_gauss_mmc5983 = 4096;
+
+ public static double counts_per_gauss(int imu_type, int mag_model) {
+ switch(mag_model) {
+ case AltosLib.model_hmc5883:
+ return counts_per_gauss_hmc5883;
+ case AltosLib.model_mmc5983:
+ return counts_per_gauss_mmc5983;
+ }
+ switch (imu_type) {
+ case AltosIMU.imu_type_telemega_v1_v2:
+ case AltosIMU.imu_type_easymega_v1:
+ return counts_per_gauss_hmc5883;
+ }
+
+ return AltosIMU.counts_per_gauss(imu_type, mag_model);
+ }
+
+ public static double convert_gauss(double counts, int imu_type, int mag_model) {
+ double cpg = counts_per_gauss(imu_type, mag_model);
+
+ if (cpg == AltosLib.MISSING)
+ return AltosLib.MISSING;
+
+ return counts / cpg;
}
public boolean parse_string(String line) {
- if (!line.startsWith("X:"))
- return false;
+ if (line.startsWith("X:")) {
- String[] items = line.split("\\s+");
+ String[] items = line.split("\\s+");
- if (items.length >= 6) {
- x = Integer.parseInt(items[1]);
- z = Integer.parseInt(items[3]);
- y = Integer.parseInt(items[5]);
+ mag_model = model_hmc5883;
+
+ if (items.length >= 6) {
+ across = Integer.parseInt(items[1]);
+ through = Integer.parseInt(items[3]);
+ along = Integer.parseInt(items[5]);
+ }
+ return true;
+ }
+ if (line.startsWith("MMC5983:")) {
+ String[] items = line.split("\\s+");
+
+ mag_model = model_mmc5983;
+
+ if (items.length >= 4) {
+ along = Integer.parseInt(items[1]);
+ across = Integer.parseInt(items[2]);
+ through = Integer.parseInt(items[3]);
+ }
+ return true;
}
- return true;
+
+ return false;
}
public AltosMag clone() {
AltosMag n = new AltosMag();
- n.x = x;
- n.z = z;
- n.y = y;
+ n.along = along;
+ n.across = across;
+ n.through = through;
return n;
}
public AltosMag() {
- x = AltosLib.MISSING;
- z = AltosLib.MISSING;
- y = AltosLib.MISSING;
}
static public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException {
AltosMag mag = new AltosMag(link);
AltosCalData cal_data = listener.cal_data();
- if (mag != null)
- listener.set_mag(cal_data.mag_along(mag.y),
- cal_data.mag_across(mag.x),
- cal_data.mag_through(mag.z));
+ if (mag != null) {
+ if (mag.mag_model != AltosLib.MISSING)
+ cal_data.set_mag_model(mag.mag_model);
+ listener.set_mag(cal_data.mag_along(mag.along),
+ cal_data.mag_across(mag.across),
+ cal_data.mag_through(mag.through));
+ }
} catch (TimeoutException te) {
}
}
final static int packet_type_mini2 = 0x10;
final static int packet_type_mini3 = 0x11;
final static int packet_type_mega_sensor_bmx160 = 0x12;
+ final static int packet_type_mega_norm_mpu6000_mmc5983 = 0x13;
static AltosTelemetry parse_hex(String hex) throws ParseException, AltosCRCException {
AltosTelemetry telem = null;
--- /dev/null
+/*
+ * Copyright © 2021 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.
+ */
+
+package org.altusmetrum.altoslib_14;
+
+public class AltosTelemetryMegaNorm extends AltosTelemetryStandard {
+ int orient() { return int8(5); }
+
+ int accel() { return int16(6); }
+ int pres() { return int32(8); }
+ int temp() { return int16(12); }
+
+ int accel_along() { return int16(14); }
+ int accel_across() { return int16(16); }
+ int accel_through() { return int16(18); }
+
+ int gyro_roll() { return int16(20); }
+ int gyro_pitch() { return int16(22); }
+ int gyro_yaw() { return int16(24); }
+
+ int mag_along() { return int16(26); }
+ int mag_across() { return int16(28); }
+ int mag_through() { return int16(30); }
+
+ int imu_model, mag_model;
+
+ public AltosTelemetryMegaNorm(int[] bytes, int imu_model, int mag_model) throws AltosCRCException {
+ super(bytes);
+ this.imu_model = imu_model;
+ this.mag_model = mag_model;
+ }
+
+ public void provide_data(AltosDataListener listener) {
+ super.provide_data(listener);
+
+ AltosCalData cal_data = listener.cal_data();
+
+ listener.set_acceleration(cal_data.acceleration(accel()));
+ listener.set_pressure(pres());
+ listener.set_temperature(temp() / 100.0);
+
+ listener.set_orient(orient());
+ cal_data.set_imu_model(imu_model);
+ cal_data.set_mag_model(mag_model);
+
+ /* XXX we have no calibration data for these values */
+
+ if (cal_data.accel_zero_along == AltosLib.MISSING)
+ cal_data.set_accel_zero(0, 0, 0);
+ if (cal_data.gyro_zero_roll == AltosLib.MISSING)
+ cal_data.set_gyro_zero(0, 0, 0);
+
+ int accel_along = accel_along();
+ int accel_across = accel_across();
+ int accel_through = accel_through();
+
+ int gyro_roll = gyro_roll();
+ int gyro_pitch = gyro_pitch();
+ int gyro_yaw = gyro_yaw();
+
+ int mag_along = mag_along();
+ int mag_across = mag_across();
+ int mag_through = mag_through();
+
+ listener.set_accel(cal_data.accel_along(accel_along),
+ cal_data.accel_across(accel_across),
+ cal_data.accel_through(accel_through));
+ listener.set_gyro(cal_data.gyro_roll(gyro_roll),
+ cal_data.gyro_pitch(gyro_pitch),
+ cal_data.gyro_yaw(gyro_yaw));
+ listener.set_mag(cal_data.mag_along(mag_along),
+ cal_data.mag_across(mag_across),
+ cal_data.mag_through(mag_through));
+ }
+}
return gyro_z();
}
- public static int mag_across_axis(int imu_type) {
- switch (imu_type) {
- case AltosIMU.imu_type_telemega_v1_v2:
- case AltosIMU.imu_type_telemega_v3:
- case AltosIMU.imu_type_easymega_v1:
- return AltosIMU.imu_axis_x;
- case AltosIMU.imu_type_telemega_v4:
- case AltosIMU.imu_type_easymega_v2:
- return AltosIMU.imu_axis_y;
- default:
- return AltosLib.MISSING;
- }
- }
-
private int mag_across(int imu_type) {
switch (imu_type) {
case AltosIMU.imu_type_telemega_v1_v2:
}
}
- public static int mag_along_axis(int imu_type) {
- switch (imu_type) {
- case AltosIMU.imu_type_telemega_v1_v2:
- case AltosIMU.imu_type_telemega_v3:
- case AltosIMU.imu_type_easymega_v1:
- return AltosIMU.imu_axis_y;
- case AltosIMU.imu_type_easymega_v2:
- case AltosIMU.imu_type_telemega_v4:
- return AltosIMU.imu_axis_x;
- default:
- return AltosLib.MISSING;
- }
- }
-
private int mag_along(int imu_type) {
switch (imu_type) {
case AltosIMU.imu_type_telemega_v1_v2:
}
}
- public static int mag_through_axis(int imu_type) {
- return AltosIMU.imu_axis_z;
- }
-
private int mag_through(int imu_type) {
return mag_z();
}
case packet_type_mini3:
telem = new AltosTelemetryMini3(bytes);
break;
+ case packet_type_mega_norm_mpu6000_mmc5983:
+ telem = new AltosTelemetryMegaNorm(bytes, AltosLib.model_mpu6000, AltosLib.model_mmc5983);
+ break;
default:
telem = new AltosTelemetryRaw(bytes);
break;
AltosTelemetryLocation.java \
AltosTelemetryMap.java \
AltosTelemetryMegaSensor.java \
+ AltosTelemetryMegaNorm.java \
AltosTelemetryMegaData.java \
AltosTelemetryMini2.java \
AltosTelemetryMini3.java \
--- /dev/null
+When adding a new product to the java code, there are a number of
+places that might need adjustment:
+
+altoslib/
+
+ 1. AltosLib.java
+
+ Declare new log format
+ Declare new USB ids
+ Declare new Product name
+ Add item to product_name function
+
+ 2. AltosIdleFetch.java
+
+ Declare any new sensors, create new sensor class
+ Create new sensor class for ADC values
+ Add new AltosIdler entry to idlers array
+
+ 3. AltosEepromRecordSet.java
+
+ Map new log format to new log record decode class
+
+ 4. AltosIMU.java
+
+ Map new imu_type (which includes orientation) correctly
+
+ 5. AltosConfigData.java
+
+ Adjust invert_accel_value for new log format or product name
+ Adjust use_flash_for_config as needed
+ Adjust various accel_inverted functions
+ Adjust adxl375_axis
+
+ 6. AltosTelemetry.java
+
+ Define new telemetry packet types
+
+
+ 7. AltosTelemetryStandard.java
+
+ Map telemetry packet type to new decoder class
+
+ 8. AltosTelemetry*.java
+
+ Adjust existing telemetry decoders for new sensors
+
+
+altosuilib/
+
+ 1. AltosUSBDevice.java
+
+ Add new product ID as appropriate to matchProduct
};
static String[] beep_values = {
+ "2000",
+ "2100",
+ "2200",
"3750",
"4000",
"4250",
altosuilib_$(ALTOSUILIB_VERSION).jar
if MULTI_ARCH
-LIBALTOS_LINUX=libaltos32.so libaltos64.so
+LIBALTOS_LINUX=libaltos_i686.so libaltos_amd64.so libaltos_aarch64.so libaltos_armel.so libaltos_armhf.so
else
LIBALTOS_LINUX=libaltos.so
endif
FIRMWARE_TMEGA_2_0=$(top_srcdir)/src/telemega-v2.0/telemega-v2.0-$(VERSION).ihx
FIRMWARE_TMEGA_3_0=$(top_srcdir)/src/telemega-v3.0/telemega-v3.0-$(VERSION).ihx
FIRMWARE_TMEGA_4_0=$(top_srcdir)/src/telemega-v4.0/telemega-v4.0-$(VERSION).ihx
-FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0) $(FIRMWARE_TMEGA_2_0) $(FIRMWARE_TMEGA_3_0) $(FIRMWARE_TMEGA_4_0)
+FIRMWARE_TMEGA_5_0=$(top_srcdir)/src/telemega-v5.0/telemega-v5.0-$(VERSION).ihx
+FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0) $(FIRMWARE_TMEGA_2_0) $(FIRMWARE_TMEGA_3_0) $(FIRMWARE_TMEGA_4_0) $(FIRMWARE_TMEGA_5_0)
FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
FIRMWARE_EMINI_2_0=$(top_srcdir)/src/easymini-v2.0/easymini-v2.0-$(VERSION).ihx
classes/altosui:
mkdir -p classes/altosui
-$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)
+$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) build-libaltos
jar cfm $@ Manifest.txt \
$(ICONJAR) \
-C classes altosui \
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-libaltos32.so: build-libaltos
+libaltos_i686.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-libaltos64.so: build-libaltos
+libaltos_amd64.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_aarch64.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_armel.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_armhf.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
-altos.dll: ../libaltos/altos.dll
+altos.dll: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
-altos64.dll: ../libaltos/altos64.dll
+altos64.dll: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
-../libaltos/.libs/libaltos64.so: ../libaltos/.libs/libaltos32.so
-
-../libaltos/.libs/libaltos32.so: build-libaltos
-
-../libaltos/.libs/libaltos.so: build-libaltos
-
-../libaltos/altos.dll: build-altos-dll
-
-../libaltos/altos64.dll: build-altos64-dll
-
build-libaltos:
- +cd ../libaltos && make libaltos.la
-build-altos-dll:
- +cd ../libaltos && make altos.dll
-
-build-altos64-dll:
- +cd ../libaltos && make altos64.dll
+ +cd ../libaltos && make
$(ALTOSLIB_CLASS):
-rm -f "$@"
File "../src/telemega-v2.0/telemega-v2.0-${VERSION}.ihx"
File "../src/telemega-v3.0/telemega-v3.0-${VERSION}.ihx"
File "../src/telemega-v4.0/telemega-v4.0-${VERSION}.ihx"
+ File "../src/telemega-v5.0/telemega-v5.0-${VERSION}.ihx"
File "../src/easymini-v1.0/easymini-v1.0-${VERSION}.ihx"
File "../src/easymini-v2.0/easymini-v2.0-${VERSION}.ihx"
File "../src/easymega-v1.0/easymega-v1.0-${VERSION}.ihx"
static public boolean loaded_library = false;
static public boolean has_bluetooth = false;
- static final String[] library_names_32 = { "altos", "altos32", "altos64" };
- static final String[] library_names_64 = { "altos", "altos64", "altos32" };
+ static final String[] library_names = {
+ "altos",
+ "altos32",
+ "altos64",
+ "altos_i686",
+ "altos_amd64",
+ "altos_aarch64",
+ "altos_armel",
+ "altos_armhf"
+ };
public static boolean load_library() {
if (!initialized) {
- String model = System.getProperty("sun.arch.data.model", "missing");
- boolean is_64 = false;
- if (model.equals("64")) {
- is_64 = true;
- } else if (model.equals("32")) {
- ;
- } else {
- String arch = System.getProperty("os.arch", "missing");
- if (arch.endsWith("64"))
- is_64 = true;
- }
- for (String name : is_64 ? library_names_64 : library_names_32) {
+ for (String name : library_names) {
try {
System.loadLibrary(name);
libaltos.altos_init();
loaded_library = true;
break;
} catch (UnsatisfiedLinkError e) {
- System.out.printf("Link error %s\n", e.getMessage());
loaded_library = false;
}
}
+ if (!loaded_library)
+ System.out.printf("Cannot find 'libaltos' device access library\n");
String OS = System.getProperty("os.name");
echo "Testing $product $serial $dev"
echo ""
- ./test-igniters $dev main drogue 3 0 1 2
+ ./test-igniters $dev --rplus=100 --rminus=27 --adcmax=4095 main drogue 3 0 1 2
echo""
echo "Testing baro sensor"
sleep 0.25
- ./test-igniters-nowait "$dev" drogue main
+ ./test-igniters-nowait "$dev" --rplus=100 --rminus=27 --adcmax=32767 drogue main
echo ""
echo "Testing baro sensor"
--- /dev/null
+#!/bin/bash
+
+VERSION=1.0
+PRODUCT=EasyMini
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+
+echo "$PRODUCT-v$VERSION Test Program"
+echo "Copyright 2014 by Keith Packard. Released under GPL v2"
+echo
+echo "Expectations:"
+echo -e "\t$PRODUCT v$VERSION powered from USB"
+echo
+
+found=0
+while [ $found -eq 0 ]; do
+ (ao-list; echo END END END END) | while read product serial dev; do
+ case "$product" in
+ "$PRODUCT-v$VERSION")
+
+ found=1
+ echo -e '\e[34m'Testing $product $serial $dev'\e[39m'
+ echo ""
+
+ sleep 2
+
+ ./test-igniters-nowait "$dev" drogue main
+ echo ""
+
+ echo "Testing baro sensor"
+ ../ao-tools/ao-test-baro/ao-test-baro --tty="$dev"
+
+ if [ $? -ne 0 ]; then
+ echo -e '\e[31m'"$PRODUCT-$VERSION serial $serial failed"'\e[39m'
+ exit 1
+ fi
+ echo""
+
+ FLASHSIZE=1048576
+
+ echo "Testing flash"
+ ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE"
+
+ if [ $? -ne 0 ]; then
+ echo -e '\e[31m'"$PRODUCT-$VERSION serial $serial failed"'\e[39m'
+ exit 1
+ fi
+ echo ""
+
+ echo -e '\e[32m'"$PRODUCT-v$VERSION" serial "$serial" is ready to ship'\e[39m'
+ exit 0
+ ;;
+ END)
+ exit 2
+ ;;
+ esac
+ done
+ result=$?
+ if [ $result -ne 2 ]; then
+ exit $result
+ fi
+ sleep 0.25
+done
dev="$1"
shift
+args=""
for igniter in "$@"; do
- pass="n"
- while [ $pass != "y" ]; do
+ case "$igniter" in
+ -*)
+ args="$args $igniter"
+ ;;
+ *)
+ pass="n"
+ while [ $pass != "y" ]; do
echo -n "Testing $igniter igniter. Press enter to continue..."
read foo < /dev/tty
- ../ao-tools/ao-test-igniter/ao-test-igniter --tty="$dev" $igniter
+ ../ao-tools/ao-test-igniter/ao-test-igniter --tty="$dev" $args $igniter
case $? in
0)
echo "Failed. Try again."
;;
esac
- done
+ done
+ ;;
+ esac
done
exit 0
dev="$1"
shift
+args=""
for igniter in "$@"; do
- pass="n"
- while [ $pass != "y" ]; do
+ case "$igniter" in
+ -*)
+ args="$args $igniter"
+ ;;
+ *)
+ pass="n"
+ while [ $pass != "y" ]; do
echo "Testing $igniter igniter."
- ../ao-tools/ao-test-igniter/ao-test-igniter --tty="$dev" $igniter
+ ../ao-tools/ao-test-igniter/ao-test-igniter --tty="$dev" $args $igniter
case $? in
0)
read foo < /dev/tty
;;
esac
- done
+ done
+ ;;
+ esac
done
exit 0
echo "Testing $product $serial $dev"
- ./test-igniters $dev main drogue 3 0 1 2
+ ./test-igniters $dev --rplus=100 --rminus=27 --adcmax=4095 main drogue 3 0 1 2
echo""
echo "Testing baro sensor"
echo "Testing $product $serial $dev"
echo ""
- ./test-igniters "$dev" drogue main
+ ./test-igniters "$dev" --rplus=100 --rminus=27 --adcmax=4095 drogue main
echo ""
echo "Testing baro sensor"
echo "Testing $product $serial $dev"
echo ""
- ./test-igniters "$dev" drogue main
+ ./test-igniters "$dev" --rplus=100 --rminus=27 --adcmax=4095 drogue main
echo ""
echo "Testing baro sensor"
#!/bin/sh
-if [ -x /usr/bin/dfu-util ]; then
- DFU_UTIL=/usr/bin/dfu-util
+if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then
+ FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc
+elif [ -x /usr/bin/ao-flash-lpc ]; then
+ FLASH_LPC=/usr/bin/ao-flash-lpc
else
- echo "Can't find dfu-util! Aborting."
- exit 1
+ echo "Can't find ao-flash-lpc! Aborting."
+ exit 1
fi
if [ -x ../ao-tools/ao-usbload/ao-usbload ]; then
exit 1
fi
-VERSION=2.0
+VERSION=1.0
PRODUCT=EasyMini
BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
echo $FILE
echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
-echo "Copyright 2010 by Bdale Garbee. Released under GPL v2+"
+echo "Copyright 2010 by Bdale Garbee. Released under GPL v2"
echo
echo "Expectations:"
-echo "\t$PRODUCT v$VERSION powered and connected to USB"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo "\t\twith ST-Link-V2 cabled to debug header"
echo
case $# in
#
# Use released versions of everything
#
-FLASH_FILE=~/altusmetrumllc/Binaries/loaders/easymini-v2.0-altos-flash-*.bin
-ALTOS_FILE=~/altusmetrumllc/Binaries/easymini-v2.0-*.elf
+FLASH_FILE=~/altusmetrumllc/Binaries/loaders/easymini-v1.0-altos-flash-*.elf
+ALTOS_FILE=~/altusmetrumllc/Binaries/easymini-v1.0-*.elf
#FLASH_FILE=../src/$BASE-v$VERSION/flash-loader/$BASE-v$VERSION-altos-flash-*.elf
#ALTOS_FILE=../src/$BASE-v$VERSION/*.ihx
-if lsusb -d 0483:df11 | grep -q STM; then
- echo $DFU_UTIL -v -v -R -a 0 -s 0x08000000:leave -D $FLASH_FILE
+echo $FLASH_LPC $FLASH_FILE
- $DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE
+$FLASH_LPC $FLASH_FILE || exit 1
- sleep 2
-fi
+sleep 1
echo $USBLOAD $ALTOS_FILE
sleep 1
-./test-easymini
+./test-easymini-v1.0
exit $?
#include <getopt.h>
#include <string.h>
#include <stdbool.h>
+#include <ctype.h>
#include "ao-elf.h"
#include "ccdbg.h"
#include "cc-usb.h"
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "raw", .has_arg = 0, .val = 'r' },
{ .name = "verbose", .has_arg = 1, .val = 'v' },
+ { .name = "rplus", .has_arg = 1, .val = 'a' },
+ { .name = "rminus", .has_arg = 1, .val = 'b' },
+ { .name = "adcmax", .has_arg = 1, .val = 'm' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
- fprintf(stderr, "usage: %s [--verbose=<verbose>] [--device=<device>] [-tty=<tty>] main|drogue\n", program);
+ fprintf(stderr, "usage: %s [--verbose=<verbose>] [--device=<device>] [--tty=<tty>] [--rplus=val] [--rminus=val] [--adcmax=val] main|drogue\n", program);
exit(1);
}
struct igniter *next;
char name[512];
char status[512];
+ int adc;
};
+static bool
+map_igniter_name(char *adc_name, char *igniter_name)
+{
+ char *colon = strchr(adc_name, ':');
+ if (!colon)
+ return false;
+ *colon = '\0';
+ if (strlen(adc_name) == 1 && isupper(adc_name[0])) {
+ igniter_name[0] = '0' + adc_name[0] - 'A';
+ igniter_name[1] = '\0';
+ } else {
+ strcpy(igniter_name, adc_name);
+ }
+ return true;
+}
+
static struct igniter *
igniters(struct cc_usb *usb)
{
struct igniter *head = NULL, **tail = &head;
- cc_usb_printf(usb, "t\nv\n");
+ cc_usb_printf(usb, "t\na\nv\n");
for (;;) {
char line[512];
char name[512];
char status[512];
+ char adc_name[512];
+ char igniter_name[512];
cc_usb_getline(usb, line, sizeof (line));
if (strstr(line, "software-version"))
break;
if (sscanf(line, "Igniter: %s Status: %s", name, status) == 2) {
- struct igniter *i = malloc (sizeof (struct igniter));
+ struct igniter *i = calloc (1, sizeof (struct igniter));
strcpy(i->name, name);
strcpy(i->status, status);
i->next = NULL;
*tail = i;
tail = &i->next;
}
+ if (strncmp(line, "tick:", 5) == 0) {
+ char *tok;
+ char *l = line;
+ bool found_igniter = false;
+
+ while ((tok = strtok(l, " ")) != NULL) {
+ l = NULL;
+ if (found_igniter) {
+ struct igniter *i;
+ for (i = head; i; i = i->next)
+ if (!strcmp(i->name, igniter_name)) {
+ i->adc = atoi(tok);
+ break;
+ }
+ found_igniter = false;
+ } else {
+ strcpy(adc_name, tok);
+ found_igniter = map_igniter_name(adc_name, igniter_name);
+ }
+ }
+ }
}
return head;
}
find_igniter(struct igniter *i, char *name)
{
for (; i; i = i->next)
- if (strcmp(i->name, name) == 0)
+ if (strcmp(i->name, name) == 0) {
+ printf("igniter %s adc %d\n", i->name, i->adc);
return i;
+ }
return NULL;
}
+static const double ref_volts = 3.3;
+
+static double
+compute_voltage(int adc, double rplus, double rminus, int adc_max)
+{
+ return (double) adc / (double) adc_max * ref_volts * (rplus + rminus) / rminus;
+}
+
static int
-do_igniter(struct cc_usb *usb, char *name)
+do_igniter(struct cc_usb *usb, char *name, double rplus, double rminus, int adc_max)
{
struct igniter *all = igniters(usb);
struct igniter *this = find_igniter(all, name);
+ double volts = -1;
if (!this) {
struct igniter *i;
printf("no igniter %s found in", name);
free_igniters(all);
return 0;
}
+ if (rplus && rminus && adc_max) {
+ volts = compute_voltage(this->adc, rplus, rminus, adc_max);
+ if (volts < 1 || volts > 4) {
+ printf("igniter %s voltage is %f, not in range of 1-4 volts\n", this->name, volts);
+ free_igniters(all);
+ return 0;
+ }
+ }
if (strcmp(this->status, "ready") != 0) {
printf("igniter %s status is %s\n", this->name, this->status);
free_igniters(all);
char *tty = NULL;
int verbose = 0;
int ret = 0;
+ double rplus = 0.0;
+ double rminus = 0.0;
+ int adcmax = 0;
- while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "rT:D:c:s:v:a:b:m:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
case 'v':
verbose++;
break;
+ case 'a':
+ rplus = strtod(optarg, NULL);
+ break;
+ case 'b':
+ rminus = strtod(optarg, NULL);
+ break;
+ case 'm':
+ adcmax = strtol(optarg, NULL, 0);
+ break;
default:
usage(argv[0]);
break;
for (i = optind; i < argc; i++) {
char *name = argv[i];
- if (!do_igniter(cc, name))
+ if (!do_igniter(cc, name, rplus, rminus, adcmax))
ret++;
}
done(cc, ret);
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.9.7)
+AC_INIT([altos], 1.9.8)
ANDROID_VERSION=29
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
-RELEASE_DATE=2021-06-08
+RELEASE_DATE=2021-09-20
AC_SUBST(RELEASE_DATE)
DOC_DATE=`LC_ALL=C date -d $RELEASE_DATE +'%d %b %Y'`
endif
RELNOTES_INC=\
+ release-notes-1.9.8.inc \
release-notes-1.9.7.inc \
release-notes-1.9.6.inc \
release-notes-1.9.5.inc \
== EasyMega Outline and Hole Pattern
This image, when printed, provides a precise template for the
mounting holes in EasyMega. EasyMega has overall dimensions of
- 1.250 x 2.250 inches, and the mounting holes are sized for use
- with 4-40 or M3 screws.
+ 1.250 x 2.250 inches, and the mounting holes are 0.125 inches from
+ each board edge. That means the mounting holes are in a rectangle
+ measuring 1.000 x 2.00 inches, sized for use with 4-40 or M3 screws.
image::easymega.svg[align="center"]
This image, when printed, provides a precise template for the
mounting holes in EasyMini, EasyMotor, and EasyTimer. Each of
these products has overall dimensions of 0.800 x 1.500 inches,
- and the mounting holes are sized for use with 4-40 or M3 screws.
+ and the mounting holes are 0.125 inches from each board edge.
+ That means the mounting holes are in a rectangle measuring
+ 0.550 x 1.250 inches apart, sized for use with 4-40 or M3 screws.
image::easymini.svg[align="center"]
+
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.8.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.7.adoc[]
since launch to zero each time a motor starts burning. Update firmware
to get the correct behavior.
+[WARNING]
+Firmware versions older than 1.9.8 cannot use times longer
+than 327.67 seconds. Update firmware if you need a longer time.
+
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.
timer expires and all of the other parameters have remained true for
the entire time, then the pyro channel is fired.
+[WARNING]
+Firmware versions older than 1.9.8 cannot use delays longer
+than 327.67 seconds. Update firmware if you need a longer delay.
+
Flight State:: The flight software tracks the flight
through a sequence of states:
--- /dev/null
+= Release Notes for Version 1.9.8
+include::release-head.adoc[]
+:doctype: article
+
+ Version 1.9.8
+
+ == AltOS
+
+ * Add support for TeleMega v5.0
+
+ * Extend extra pyro channel times to support delay > 327 seconds
+
+ == AltosUI
+
+ * Support ARM devices in Linux binary release
+
+ * Add support for TeleMega v5.0
+
+ == AltosDroid
+
+ * Show tilt angle in pad and flight tabs
+
+ * Show altitude as well as height (useful for TeleGPS)
+
+ * Support devices without GPS receivers
+
+ == MicroPeak GUI
+
+ * Show error dialog if device open fails
\ No newline at end of file
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.8.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.7.adoc[]
|40mW
|3.7V
+ |TeleMega v5.0
+ |MS5607 30km (100k')
+ |ADXL375 200g
+ |uBlox Max-8Q
+ |MPU6000 MMC5983
+ |8MB
+ |40mW
+ |3.7V
+
endif::telemega[]
ifdef::easymega[]
|EasyMega v1.0
== TeleGPS Outline and Hole Pattern
This image, when printed, provides a precise template for the
mounting holes in TeleGPS. TeleGPS has overall dimensions
- of 1.000 x 1.500 inches, and the mounting holes are sized for
- use with 4-40 or M3 screws.
+ of 1.000 x 1.500 inches, and the mounting holes are 0.125 inches
+ from each board edge. That means the mounting holes are in a
+ rectangle measuring 0.750 x 1.250 inches apart, sized for use with
+ 4-40 or M3 screws.
image::telegps.svg[align="center"]
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.8.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.7.adoc[]
== TeleMega Outline and Hole Pattern
This image, when printed, provides a precise template for the
mounting holes in TeleMega. TeleMega has overall dimensions of
- 1.250 x 3.250 inches, and the mounting holes are sized for use
- with 4-40 or M3 screws.
+ 1.250 x 3.250 inches, and the mounting holes are 0.125 inches
+ from each board edge. That means the mounting holes are in a
+ rectangle measuring 1.000 x 3.000 inches apart, sized for use with
+ 4-40 or M3 screws.
image::telemega.svg[align="center"]
== TeleMetrum Outline and Hole Pattern
This image, when printed, provides a precise template for the
mounting holes in TeleMetrum. TeleMetrum has overall dimensions of
- 1.000 x 2.750 inches, and the mounting holes are sized for use
- with 4-40 or M3 screws.
+ 1.000 x 2.750 inches, and the mounting holes are 0.125 inches from
+ three of the board edges, and 0.375 inches from the screw terminal
+ end. That means they are in a rectangle measuring 0.750 x 2.250
+ inches, sized for use with 4-40 or M3 screws.
image::telemetrum.svg[align="center"]
This image, when printed, provides a precise template for the
mounting holes in TeleMini. TeleMini v1 has overall dimensions of
- 0.500 x 1.500 inches, and the mounting holes are sized for use
- with 2-56 or M2 screws. The holes are located 0.100 inches
- from the edge of the board in both directions.
+ 0.500 x 1.500 inches, and the mounting holes are sized for use with
+ 2-56 or M2 screws. The holes are located 0.100 inches from the edge
+ of the board in both directions, meaning they are 0.300 inches apart.
image::telemini-v1.svg[align="center"]
mounting holes in TeleMini v3. TeleMini v3 has overall dimensions of
0.500 x 1.670 inches, and the mounting holes are sized for use
with 2-56 or M2 screws. The holes are located 0.085 inches
- from the edge of the board in both directions.
+ from the edge of the board in both directions, meaning they are
+ located in a rectangle of 0.330 x 1.500 inches.
image::telemini-v3.svg[align="center"]
callsign settings are, you can temporarily force it
back to the original default values (frequency
434.550MHz, callsign N0CALL) by connecting a wire
- between hole 3 and hole 7 on the debug connector. Hole
- 3 has the square pad around it, hole 7 is the one
+ between hole 3 and hole 6 on the debug connector. Hole
+ 3 has the square pad around it, hole 6 is the one
nearest the MS5607 baro sensor, which is a rectangular
component with a metal cap that has two holes in it.
JAVA_RES=16 32 48 64 128 256
MAC_RES=16 32 128 256 512
WIN_RES=16 24 32 48 64 72 96 128 180 256
-RES=$(shell echo $(JAVA_RES) $(MAC_RES) $(WIN_RES) | awk '{ for (i = 1; i <= NF; i++) printf("%s\n", $$i); }' | sort -n -u)
+AMAZON_RES=114 512
+RES=$(shell echo $(JAVA_RES) $(MAC_RES) $(WIN_RES) $(AMAZON_RES)| awk '{ for (i = 1; i <= NF; i++) printf("%s\n", $$i); }' | sort -n -u)
# Application icon base names
JAVA_FILES = $(JAVA_AM_FILES) $(JAVA_MP_FILES) $(JAVA_TG_FILES)
+# Files needed for Amazon store
+
+AMAZON_FILES = $(shell for i in $(AMAZON_RES); do echo $(AM_NAME)-$$i.png; done)
+
# PNG files needed by anyone
AM_FILES = $(shell for i in $(RES); do echo $(AM_NAME)-$$i.png; done)
fat: all $(ICO_FILES) $(ICNS_FILES) $(EXE_FILES)
-all-local: $(JAVA_FILES) $(AM_XPM) $(LED_ICONS)
+all-local: $(JAVA_FILES) $(AM_XPM) $(LED_ICONS) $(AMAZON_FILES)
clean-local:
$(RM) $(AM_NAME)-*.png $(TG_NAME)-*.png $(MP_NAME)-*.png
cjnitest
cjnitest32
cjnitest64
+cjnitest_*
btletest
libaltos.swig
swig_bindings/
+export PATH=$(shell echo "$$PWD:$$PATH")
AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE) -I$(JVM_INCLUDE)/linux
AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
btletest_LDADD=-lbluetooth
if MULTI_ARCH
-altoslib_LTLIBRARIES+=libaltos32.la libaltos64.la
-
-libaltos32_la_LDFLAGS=$(libaltos_la_LDFLAGS)
-libaltos64_la_LDFLAGS=$(libaltos_la_LDFLAGS)
-
-libaltos32_la_CFLAGS=-m32 $(AM_CFLAGS)
-libaltos64_la_CFLAGS=-m64 $(AM_CFLAGS)
-
-libaltos32_la_SOURCES=$(libaltos_la_SOURCES)
-libaltos64_la_SOURCES=$(libaltos_la_SOURCES)
-
-noinst_PROGRAMS+=cjnitest32 cjnitest64
-
-cjnitest32_CFLAGS=-m32
-cjnitest64_CFLAGS=-m64
-
-cjnitest32_SOURCES=$(cjnitest_SOURCES)
-cjnitest64_SOURCES=$(cjnitest_SOURCES)
-
-cjnitest32_LDADD=libaltos32.la
-cjnitest64_LDADD=libaltos64.la
+altoslib_LTLIBRARIES+=libaltos_i686.la libaltos_amd64.la libaltos_aarch64.la libaltos_armel.la libaltos_armhf.la
+
+I686=i686-linux-gnu
+libaltos_i686_la_LDFLAGS=-Wl,arch=$(I686) $(libaltos_la_LDFLAGS)
+libaltos_i686_la_CFLAGS=-Warch=i686-linux-gnu $(AM_CFLAGS)
+libaltos_i686_la_SOURCES=$(libaltos_la_SOURCES)
+
+AMD64=x86_64-linux-gnu
+libaltos_amd64_la_LDFLAGS=-Wl,arch=$(AMD64) $(libaltos_la_LDFLAGS)
+libaltos_amd64_la_CFLAGS=-Warch=x86_64-linux-gnu $(AM_CFLAGS)
+libaltos_amd64_la_SOURCES=$(libaltos_la_SOURCES)
+
+AARCH64=aarch64-linux-gnu
+libaltos_aarch64_la_LDFLAGS=-Wl,arch=$(AARCH64) $(libaltos_la_LDFLAGS)
+libaltos_aarch64_la_CFLAGS=-Warch=$(AARCH64) $(AM_CFLAGS)
+libaltos_aarch64_la_SOURCES=$(libaltos_la_SOURCES)
+
+ARMEL=arm-linux-gnueabi
+libaltos_armel_la_LDFLAGS=-Wl,arch=$(ARMEL) $(libaltos_la_LDFLAGS)
+libaltos_armel_la_CFLAGS=-Warch=$(ARMEL) $(AM_CFLAGS)
+libaltos_armel_la_SOURCES=$(libaltos_la_SOURCES)
+
+ARMHF=arm-linux-gnueabihf
+libaltos_armhf_la_LDFLAGS=-Wl,arch=$(ARMHF) $(libaltos_la_LDFLAGS)
+libaltos_armhf_la_CFLAGS=-Warch=$(ARMHF) $(AM_CFLAGS)
+libaltos_armhf_la_SOURCES=$(libaltos_la_SOURCES)
+
+noinst_PROGRAMS+=cjnitest_i686 cjnitest_amd64 cjnitest_aarch64 cjnitest_armel cjnitest_armhf
+
+cjnitest_i686_CFLAGS=$(libaltos_i686_la_CFLAGS)
+cjnitest_i686_LDFLAGS=-Wl,arch=$(I686)
+cjnitest_i686_SOURCES=$(cjnitest_SOURCES)
+cjnitest_i686_LDADD=libaltos_i686.la
+
+cjnitest_amd64_CFLAGS=$(libaltos_amd64_la_CFLAGS)
+cjnitest_amd64_LDFLAGS=-Wl,arch=$(AMD64)
+cjnitest_amd64_SOURCES=$(cjnitest_SOURCES)
+cjnitest_amd64_LDADD=libaltos_amd64.la
+
+cjnitest_aarch64_CFLAGS=$(libaltos_aarch64_la_CFLAGS)
+cjnitest_aarch64_LDFLAGS=-Wl,arch=$(AARCH64)
+cjnitest_aarch64_SOURCES=$(cjnitest_SOURCES)
+cjnitest_aarch64_LDADD=libaltos_aarch64.la
+
+cjnitest_armel_CFLAGS=$(libaltos_armel_la_CFLAGS)
+cjnitest_armel_LDFLAGS=-Wl,arch=$(ARMEL)
+cjnitest_armel_SOURCES=$(cjnitest_SOURCES)
+cjnitest_armel_LDADD=libaltos_armel.la
+
+cjnitest_armhf_CFLAGS=$(libaltos_armhf_la_CFLAGS)
+cjnitest_armhf_LDFLAGS=-Wl,arch=$(ARMHF)
+cjnitest_armhf_SOURCES=$(cjnitest_SOURCES)
+cjnitest_armhf_LDADD=libaltos_armhf.la
endif
all-local: classlibaltos.stamp
+test:
+ which gcc
+
libaltos_wrap.c: classlibaltos.stamp
classlibaltos.stamp: $(SWIG_FILE)
fat: all altos.dll altos64.dll
-#altos.dll: $(WINDOWS_SRC) $(WINDOWS_H)
-# $(MINGCC32) -o $@ $(MINGFLAGS) -shared $(WINDOWS_SRC) $(MINGLIBS)
+altos.dll: $(WINDOWS_SRC) $(WINDOWS_H)
+ $(MINGCC32) -o $@ $(MINGFLAGS) -shared $(WINDOWS_SRC) $(MINGLIBS)
-#altos64.dll: $(WINDOWS_SRC) $(WINDOWS_H)
-# $(MINGCC64) -o $@ $(MINGFLAGS) -shared $(WINDOWS_SRC) $(MINGLIBS)
+altos64.dll: $(WINDOWS_SRC) $(WINDOWS_H)
+ $(MINGCC64) -o $@ $(MINGFLAGS) -shared $(WINDOWS_SRC) $(MINGLIBS)
clean-local:
- -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c
-# -rm -rf altos.dll altos64.dll
+ -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c altos.dll altos64.dll
--- /dev/null
+#!/bin/bash
+NEW_PATH=`echo $PATH | sed 's/^[^:]*://'`
+PATH=$NEW_PATH
+CC=gcc
+args=()
+for i in "$@"; do
+ case "$i" in
+ -Wl,arch=*)
+ arch=`echo "$i" | sed -e 's/^-Wl,arch=//'`
+ CC="$arch"-gcc
+ ;;
+ -Warch=*)
+ arch=`echo "$i" | sed -e 's/^-Warch=//'`
+ CC="$arch"-gcc
+ ;;
+ *)
+ args+=( "$i" )
+ ;;
+ esac
+done
+echo " " "$CC" "${args[@]}"
+exec "$CC" "${args[@]}"
{ .vendor = "00:12:6f:", 1 }, /* Rayson */
{ .vendor = "8c:de:52:", 6 }, /* ISSC */
{ .vendor = "d8:80:39:", 6 }, /* Microchip */
+ { .vendor = "04:91:62:", 6 }, /* New Microchip */
};
#define NUM_BT_VENDOR_MAP (sizeof altos_bt_vendor_map / sizeof altos_bt_vendor_map[0])
-#define BT_PORT_DEFAULT 1
static inline int
ao_tolower(int c) {
break;
}
}
- return BT_PORT_DEFAULT;
+ return 0;
}
PUBLIC void
goto no_file;
}
-#if 0
- /*
- * Search for the RFCOMM service to get the right channel
- */
- session = sdp_connect(BDADDR_ANY, &addr.rc_bdaddr, SDP_RETRY_IF_BUSY);
-
- if (session) {
- static const uint8_t svc_uuid_int[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0x11, 0x01
- };
- int err;
- uuid_t svc_uuid;
- uint32_t range;
- sdp_list_t *search_list, *attrid_list;
- sdp_list_t *response_list = NULL, *r;
- sdp_uuid16_create(&svc_uuid, PUBLIC_BROWSE_GROUP);
- search_list = sdp_list_append(NULL, &svc_uuid);
-
- range = 0x0000ffff;
- attrid_list = sdp_list_append(NULL, &range);
-
- err = sdp_service_search_attr_req(session, search_list,
- SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
-
- if (err >= 0) {
- for (r = response_list; r; r = r->next) {
- sdp_record_t *rec = (sdp_record_t*) r->data;
- sdp_list_t *proto_list;
- sdp_list_t *access = NULL;
- int proto;
-
- proto = sdp_uuid_to_proto(&rec->svclass);
-
- if (proto == SERIAL_PORT_SVCLASS_ID) {
- sdp_get_access_protos(rec, &access);
- if (access) {
- int this_chan = sdp_get_proto_port(access, RFCOMM_UUID);
- if (this_chan)
- channel = this_chan;
+ /* Try the built-in vendor list */
+ channel = altos_bt_port(device);
+
+ /* Not present, try to discover an RFCOMM service */
+ if (channel == 0) {
+ /*
+ * Search for the RFCOMM service to get the right channel
+ */
+ session = sdp_connect(BDADDR_ANY, &addr.rc_bdaddr, SDP_RETRY_IF_BUSY);
+
+ if (session) {
+ static const uint8_t svc_uuid_int[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x11, 0x01
+ };
+ int err;
+ uuid_t svc_uuid;
+ uint32_t range;
+ sdp_list_t *search_list, *attrid_list;
+ sdp_list_t *response_list = NULL, *r;
+ sdp_uuid16_create(&svc_uuid, PUBLIC_BROWSE_GROUP);
+ search_list = sdp_list_append(NULL, &svc_uuid);
+
+ range = 0x0000ffff;
+ attrid_list = sdp_list_append(NULL, &range);
+
+ err = sdp_service_search_attr_req(session, search_list,
+ SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
+
+ if (err >= 0) {
+ for (r = response_list; r; r = r->next) {
+ sdp_record_t *rec = (sdp_record_t*) r->data;
+ sdp_list_t *proto_list;
+ sdp_list_t *access = NULL;
+ int proto;
+
+ proto = sdp_uuid_to_proto(&rec->svclass);
+
+ if (proto == SERIAL_PORT_SVCLASS_ID) {
+ sdp_get_access_protos(rec, &access);
+ if (access) {
+ int this_chan = sdp_get_proto_port(access, RFCOMM_UUID);
+ if (this_chan) {
+ printf("found service on channel %d\n", this_chan);
+ channel = this_chan;
+ }
+ }
}
}
}
- }
- /* Leave the session open so we don't disconnect from the device before opening
- * the RFCOMM channel
- */
+ /* Leave the session open so we don't disconnect from the device before opening
+ * the RFCOMM channel
+ */
+ }
}
-#endif
+
+ /* Still nothing, try the default */
if (channel == 0)
- channel = altos_bt_port(device);
+ channel = BT_PORT_DEFAULT;
/* Connect to the channel */
file = calloc(1, sizeof (struct altos_file_posix));
#include <string.h>
#define BLUETOOTH_PRODUCT_TELEBT "TeleBT"
+#define BT_PORT_DEFAULT 6
#define USB_BUF_SIZE 64
struct altos_file_windows *file;
SOCKADDR_BTH sockaddr_bth;
int ret;
+ int channel = 0;
file = calloc(1, sizeof (struct altos_file_windows));
if (!file) {
memset(&sockaddr_bth, '\0', sizeof (sockaddr_bth));
sockaddr_bth.addressFamily = AF_BTH;
sockaddr_bth.btAddr = str2ba(device->addr);
- sockaddr_bth.port = altos_bt_port(device);
+
+ channel = altos_bt_port(device);
+ if (channel == 0)
+ channel = BT_PORT_DEFAULT;
+
+ sockaddr_bth.port = channel;
ret = connect(file->socket, (SOCKADDR *) &sockaddr_bth, sizeof (sockaddr_bth));
FATJAR=micropeak-fat.jar
if MULTI_ARCH
-LIBALTOS_LINUX=libaltos32.so libaltos64.so
+LIBALTOS_LINUX=libaltos_i686.so libaltos_amd64.so libaltos_aarch64.so libaltos_armel.so libaltos_armhf.so
else
LIBALTOS_LINUX=libaltos.so
endif
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-libaltos32.so: build-libaltos
+libaltos_i686.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-libaltos64.so: build-libaltos
+libaltos_amd64.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_aarch64.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_armel.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_armhf.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
build-libaltos:
+cd ../libaltos && make libaltos.la
+
build-altos-dll:
+cd ../libaltos && make altos.dll
}
public void start() {
- try {
- serial = new MicroSerial(device);
- serial.set_log(this);
- } catch (FileNotFoundException fe) {
- return;
- }
+ serial.set_log(this);
serial_thread = new Thread(this);
serial_thread.start();
setVisible(false);
}
- public MicroDownload(MicroPeak owner, AltosDevice device) {
+ public MicroDownload(MicroPeak owner, AltosDevice device, MicroSerial serial) {
super (owner, "Download MicroPeak Data", false);
int y = 0;
this.owner = owner;
this.device = device;
+ this.serial = serial;
pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
private void DownloadData() {
AltosDevice device = MicroDeviceDialog.show(this);
+ MicroSerial serial = null;
+ try {
+ serial = new MicroSerial(device);
+ } catch (FileNotFoundException fe) {
+ JOptionPane.showMessageDialog(this,
+ fe.getMessage(),
+ "Cannot open device",
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
- if (device != null)
- new MicroDownload(this, device);
+ new MicroDownload(this, device, serial);
}
private void no_data() {
telemega-v2.0 telemega-v2.0/flash-loader \
telemega-v3.0 telemega-v3.0/flash-loader \
telemega-v4.0 telemega-v4.0/flash-loader \
+ telemega-v5.0 telemega-v5.0/flash-loader \
telemetrum-v2.0 telemetrum-v2.0/flash-loader \
telemetrum-v3.0 telemetrum-v3.0/flash-loader \
telegps-v0.3 telegps-v0.3/flash-loader \
#include <ao_pad.h>
#endif
+static uint8_t cc1201;
+
static uint8_t ao_radio_mutex;
static uint8_t ao_radio_wake; /* radio ready. Also used as sleep address */
#define PACKET_CHAN_BW_384 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_12 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
(16 << CC1200_CHAN_BW_BB_CIC_DECFACT))
+/*
+ * CC1201 doesn't support our low bandwidth receive setups, so we use
+ * larger values for that part, leaving the bandwidth at over 50kHz
+ */
+
/* 200 / 10 = 20 */
-#define PACKET_CHAN_BW_96 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
- (16 << CC1200_CHAN_BW_BB_CIC_DECFACT))
+#define PACKET_CHAN_BW_96_CC1200 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
+ (16 << CC1200_CHAN_BW_BB_CIC_DECFACT))
+
+#define PACKET_CHAN_BW_96_CC1201 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
+ (8 << CC1200_CHAN_BW_BB_CIC_DECFACT))
/* 200 / 25 = 8 */
-#define PACKET_CHAN_BW_24 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
- (44 << CC1200_CHAN_BW_BB_CIC_DECFACT))
+#define PACKET_CHAN_BW_24_CC1200 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
+ (44 << CC1200_CHAN_BW_BB_CIC_DECFACT))
+
+#define PACKET_CHAN_BW_24_CC1201 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \
+ (8 << CC1200_CHAN_BW_BB_CIC_DECFACT))
static const uint16_t packet_setup[] = {
CC1200_SYMBOL_RATE1, ((PACKET_SYMBOL_RATE_M >> 8) & 0xff),
(PACKET_DEV_E_96 << CC1200_MODCFG_DEV_E_DEV_E)),
CC1200_SYMBOL_RATE2, ((PACKET_SYMBOL_RATE_E_96 << CC1200_SYMBOL_RATE2_DATARATE_E) |
(((PACKET_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)),
- CC1200_CHAN_BW, PACKET_CHAN_BW_96,
CC1200_MDMCFG2, /* General Modem Parameter Configuration Reg. 2 */
((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) |
(CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) |
(PACKET_DEV_E_24 << CC1200_MODCFG_DEV_E_DEV_E)),
CC1200_SYMBOL_RATE2, ((PACKET_SYMBOL_RATE_E_24 << CC1200_SYMBOL_RATE2_DATARATE_E) |
(((PACKET_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)),
- CC1200_CHAN_BW, PACKET_CHAN_BW_24,
CC1200_MDMCFG2, /* General Modem Parameter Configuration Reg. 2 */
((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) |
(CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) |
break;
case AO_RADIO_RATE_9600:
ao_radio_set_regs(packet_setup_96);
+ if (cc1201)
+ ao_radio_reg_write(CC1200_CHAN_BW, PACKET_CHAN_BW_96_CC1201);
+ else
+ ao_radio_reg_write(CC1200_CHAN_BW, PACKET_CHAN_BW_96_CC1200);
break;
case AO_RADIO_RATE_2400:
ao_radio_set_regs(packet_setup_24);
+ if (cc1201)
+ ao_radio_reg_write(CC1200_CHAN_BW, PACKET_CHAN_BW_24_CC1201);
+ else
+ ao_radio_reg_write(CC1200_CHAN_BW, PACKET_CHAN_BW_24_CC1200);
break;
}
}
static void
ao_radio_setup(void)
{
+ uint8_t partnumber = ao_radio_reg_read(CC1200_PARTNUMBER);
+
+ if (partnumber == CC1200_PARTNUMBER_CC1201)
+ cc1201 = 1;
+
ao_radio_strobe(CC1200_SRES);
ao_radio_set_regs(radio_setup);
return (ao_radio_status() >> CC1200_STATUS_STATE) & CC1200_STATUS_STATE_MASK;
}
-#if CC1200_DEBUG
-void
+#if CC1200_DEBUG_
+static void
ao_radio_show_state(char *where)
{
printf("%s: state %d len %d rxbytes %d\n",
ao_radio_send(packet, sizeof (packet));
}
-void
+static void
ao_radio_test_recv(void)
{
static uint8_t bytes[34];
#define CC1200_FSCAL_CTRL (CC1200_EXTENDED_BIT | 0x8d)
#define CC1200_PHASE_ADJUST (CC1200_EXTENDED_BIT | 0x8e)
#define CC1200_PARTNUMBER (CC1200_EXTENDED_BIT | 0x8f)
+#define CC1200_PARTNUMBER_CC1200 0x20
+#define CC1200_PARTNUMBER_CC1201 0x21
#define CC1200_PARTVERSION (CC1200_EXTENDED_BIT | 0x90)
#define CC1200_SERIAL_STATUS (CC1200_EXTENDED_BIT | 0x91)
#define CC1200_MODEM_STATUS1 (CC1200_EXTENDED_BIT | 0x92)
--- /dev/null
+/*
+ * Copyright © 2021 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_mmc5983.h>
+#include <ao_exti.h>
+
+#if HAS_MMC5983
+
+struct ao_mmc5983_sample ao_mmc5983_current;
+
+static uint8_t ao_mmc5983_configured;
+
+#ifdef MMC5983_I2C
+#include <ao_i2c_bit.h>
+
+static void
+ao_mmc5983_reg_write(uint8_t addr, uint8_t data)
+{
+ uint8_t d[2];
+
+ d[0] = addr;
+ d[1] = data;
+
+ ao_i2c_bit_start(MMC5983_I2C_ADDR);
+ ao_i2c_bit_send(d, 2);
+ ao_i2c_bit_stop();
+}
+
+static uint8_t
+ao_mmc5983_reg_read(uint8_t addr)
+{
+ uint8_t d[1];
+
+ ao_i2c_bit_start(MMC5983_I2C_ADDR);
+ d[0] = addr;
+ ao_i2c_bit_send(d, 1);
+ ao_i2c_bit_restart(MMC5983_I2C_ADDR | 1);
+ ao_i2c_bit_recv(d, 1);
+ ao_i2c_bit_stop();
+ return d[0];
+}
+
+static void
+ao_mmc5983_sample(struct ao_mmc5983_sample *sample)
+{
+ struct ao_mmc5983_raw raw;
+
+ ao_i2c_bit_start(MMC5983_I2C_ADDR);
+ raw.addr = MMC5983_X_OUT_0;
+ ao_i2c_bit_send(&raw.addr, 1);
+ ao_i2c_bit_restart(MMC5983_I2C_ADDR | 1);
+ ao_i2c_bit_recv(&raw.x0, 7);
+ ao_i2c_bit_stop();
+
+ sample->x = raw.x0 << 10 | raw.x1 << 2 | ((raw.xyz2 >> 6) & 3);
+ sample->y = raw.y0 << 10 | raw.y1 << 2 | ((raw.xyz2 >> 4) & 3);
+ sample->z = raw.z0 << 10 | raw.z1 << 2 | ((raw.xyz2 >> 2) & 3);
+}
+
+#else
+#define AO_MMC5983_SPI_SPEED ao_spi_speed(2000000)
+
+static void
+ao_mmc5983_start(void) {
+ ao_spi_get_bit(AO_MMC5983_SPI_CS_PORT,
+ AO_MMC5983_SPI_CS_PIN,
+ AO_MMC5983_SPI_INDEX,
+ AO_MMC5983_SPI_SPEED);
+}
+
+static void
+ao_mmc5983_stop(void) {
+ ao_spi_put_bit(AO_MMC5983_SPI_CS_PORT,
+ AO_MMC5983_SPI_CS_PIN,
+ AO_MMC5983_SPI_INDEX);
+}
+
+
+static void
+ao_mmc5983_reg_write(uint8_t addr, uint8_t data)
+{
+ uint8_t d[2];
+
+ d[0] = addr;
+ d[1] = data;
+ ao_mmc5983_start();
+ ao_spi_send(d, 2, AO_MMC5983_SPI_INDEX);
+ ao_mmc5983_stop();
+}
+
+static uint8_t
+ao_mmc5983_reg_read(uint8_t addr)
+{
+ uint8_t d[2];
+
+ d[0] = addr | MMC5983_READ;
+ ao_mmc5983_start();
+ ao_spi_duplex(d, d, 2, AO_MMC5983_SPI_INDEX);
+ ao_mmc5983_stop();
+
+ return d[1];
+}
+
+static void
+ao_mmc5983_duplex(uint8_t *dst, uint8_t len)
+{
+ ao_mmc5983_start();
+ ao_spi_duplex(dst, dst, len, AO_MMC5983_SPI_INDEX);
+ ao_mmc5983_stop();
+}
+
+static void
+ao_mmc5983_sample(struct ao_mmc5983_sample *sample)
+{
+ struct ao_mmc5983_raw raw;
+
+ raw.addr = MMC5983_X_OUT_0 | MMC5983_READ;
+ ao_mmc5983_duplex((uint8_t *) &raw, sizeof (raw));
+
+ sample->x = raw.x0 << 10 | raw.x1 << 2 | ((raw.xyz2 >> 6) & 3);
+ sample->y = raw.y0 << 10 | raw.y1 << 2 | ((raw.xyz2 >> 4) & 3);
+ sample->z = raw.z0 << 10 | raw.z1 << 2 | ((raw.xyz2 >> 2) & 3);
+}
+#endif
+
+static uint8_t product_id;
+
+static uint8_t
+ao_mmc5983_setup(void)
+{
+
+ if (ao_mmc5983_configured)
+ return 1;
+
+ /* Delay for power up time (10ms) */
+ ao_delay(AO_MS_TO_TICKS(10));
+
+ ao_mmc5983_reg_write(MMC5983_CONTROL_1,
+ 1 << MMC5983_CONTROL_1_SW_RST);
+
+ /* Delay for power up time (10ms) */
+ ao_delay(AO_MS_TO_TICKS(10));
+
+ /* Check product ID */
+ product_id = ao_mmc5983_reg_read(MMC5983_PRODUCT_ID);
+ if (product_id != MMC5983_PRODUCT_ID_PRODUCT_I2C &&
+ product_id != MMC5983_PRODUCT_ID_PRODUCT_SPI)
+ {
+ AO_SENSOR_ERROR(AO_DATA_MMC5983);
+ }
+
+ /* Set bandwidth to 200Hz */
+ ao_mmc5983_reg_write(MMC5983_CONTROL_1,
+ MMC5983_CONTROL_1_BW_200 << MMC5983_CONTROL_1_BW);
+
+ /* Measure at 200Hz so we get recent samples by just reading
+ * the registers
+ */
+ ao_mmc5983_reg_write(MMC5983_CONTROL_2,
+ (1 << MMC5983_CONTROL_2_CMM_EN) |
+ (MMC5983_CONTROL_2_CM_FREQ_200HZ << MMC5983_CONTROL_2_CM_FREQ));
+
+ ao_mmc5983_configured = 1;
+ return 1;
+}
+
+struct ao_mmc5983_sample ao_mmc5983_current;
+
+static void
+ao_mmc5983(void)
+{
+ struct ao_mmc5983_sample sample;
+ ao_mmc5983_setup();
+ for (;;) {
+ ao_mmc5983_sample(&sample);
+ ao_arch_block_interrupts();
+ ao_mmc5983_current = sample;
+ AO_DATA_PRESENT(AO_DATA_MMC5983);
+ AO_DATA_WAIT();
+ ao_arch_release_interrupts();
+ }
+}
+
+static struct ao_task ao_mmc5983_task;
+
+static void
+ao_mmc5983_show(void)
+{
+ printf ("MMC5983: %d %d %d\n",
+ ao_mmc5983_along(&ao_mmc5983_current),
+ ao_mmc5983_across(&ao_mmc5983_current),
+ ao_mmc5983_through(&ao_mmc5983_current));
+}
+
+static const struct ao_cmds ao_mmc5983_cmds[] = {
+ { ao_mmc5983_show, "M\0Show MMC5983 status" },
+ { 0, NULL }
+};
+
+void
+ao_mmc5983_init(void)
+{
+ ao_mmc5983_configured = 0;
+
+#ifdef MMC5983_I2C
+ ao_enable_output(AO_MMC5983_SPI_CS_PORT, AO_MMC5983_SPI_CS_PIN, 1);
+#else
+ ao_enable_input(AO_MMC5983_SPI_MISO_PORT,
+ AO_MMC5983_SPI_MISO_PIN,
+ AO_EXTI_MODE_PULL_NONE);
+
+ ao_enable_output(AO_MMC5983_SPI_CLK_PORT,
+ AO_MMC5983_SPI_CLK_PIN,
+ 1);
+
+ ao_enable_output(AO_MMC5983_SPI_MOSI_PORT,
+ AO_MMC5983_SPI_MOSI_PIN,
+ 0);
+
+ ao_spi_init_cs(AO_MMC5983_SPI_CS_PORT, (1 << AO_MMC5983_SPI_CS_PIN));
+#endif
+
+ ao_add_task(&ao_mmc5983_task, ao_mmc5983, "mmc5983");
+ ao_cmd_register(&ao_mmc5983_cmds[0]);
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright © 2021 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_MMC5983_H_
+#define _AO_MMC5983_H_
+
+#define MMC5983_READ 0x80
+
+#define MMC5983_I2C_ADDR 0x60
+
+#define MMC5983_CONFIG_A 0
+
+#define MMC5983_CONFIG_A_MA 5
+#define MMC5983_CONFIG_A_MA_1 0
+#define MMC5983_CONFIG_A_MA_2 1
+#define MMC5983_CONFIG_A_MA_4 2
+#define MMC5983_CONFIG_A_MA_8 3
+#define MMC5983_CONFIG_A_MA_MASK 3
+
+#define MMC5983_CONFIG_A_DO 2
+#define MMC5983_CONFIG_A_DO_0_75 0
+#define MMC5983_CONFIG_A_DO_1_5 1
+#define MMC5983_CONFIG_A_DO_3 2
+#define MMC5983_CONFIG_A_DO_7_5 3
+#define MMC5983_CONFIG_A_DO_15 4
+#define MMC5983_CONFIG_A_DO_30 5
+#define MMC5983_CONFIG_A_DO_75 6
+#define MMC5983_CONFIG_A_DO_MASK 7
+
+#define MMC5983_CONFIG_A_MS 0
+#define MMC5983_CONFIG_A_MS_NORMAL 0
+#define MMC5983_CONFIG_A_MS_POSITIVE_BIAS 1
+#define MMC5983_CONFIG_A_MS_NEGATIVE_BIAS 2
+#define MMC5983_CONFIG_A_MS_MASK 3
+
+#define MMC5983_CONFIG_B 1
+
+#define MMC5983_CONFIG_B_GN 5
+#define MMC5983_CONFIG_B_GN_0_88 0
+#define MMC5983_CONFIG_B_GN_1_3 1
+#define MMC5983_CONFIG_B_GN_1_9 2
+#define MMC5983_CONFIG_B_GN_2_5 3
+#define MMC5983_CONFIG_B_GN_4_0 4
+#define MMC5983_CONFIG_B_GN_4_7 5
+#define MMC5983_CONFIG_B_GN_5_6 6
+#define MMC5983_CONFIG_B_GN_8_1 7
+#define MMC5983_CONFIG_B_GN_MASK 7
+
+#define MMC5983_MODE 2
+#define MMC5983_MODE_CONTINUOUS 0
+#define MMC5983_MODE_SINGLE 1
+#define MMC5983_MODE_IDLE 2
+
+#define MMC5983_X_OUT_0 0
+#define MMC5983_X_OUT_1 1
+#define MMC5983_Y_OUT_0 2
+#define MMC5983_Y_OUT_1 3
+#define MMC5983_Z_OUT_0 4
+#define MMC5983_Z_OUT_1 5
+#define MMC5983_XYZ_OUT_2 6
+#define MMC5983_T_OUT 7
+
+#define MMC5983_STATUS 8
+# define MMC5983_STATUS_OTP_READ_DONE 4
+# define MMC5983_STATUS_MEAS_T_DONE 1
+# define MMC5983_STATUS_MEAS_M_DONE 0
+
+#define MMC5983_CONTROL_0 9
+# define MMC5983_CONTROL_0_OTP_READ 6
+# define MMC5983_CONTROL_0_AUTO_SR_EN 5
+# define MMC5983_CONTROL_0_RESET 4
+# define MMC5983_CONTROL_0_SET 3
+# define MMC5983_CONTROL_0_INT_MEAS_DONE_EN 2
+# define MMC5983_CONTROL_0_TM_T 1
+# define MMC5983_CONTROL_0_TM_M 0
+
+#define MMC5983_CONTROL_1 0xa
+# define MMC5983_CONTROL_1_SW_RST 7
+# define MMC5983_CONTROL_1_YZ_INHIBIT 3
+# define MMC5983_CONTROL_1_X_INHIBIT 2
+# define MMC5983_CONTROL_1_BW 0
+# define MMC5983_CONTROL_1_BW_100 0
+# define MMC5983_CONTROL_1_BW_200 1
+# define MMC5983_CONTROL_1_BW_400 2
+# define MMC5983_CONTROL_1_BW_800 3
+#define MMC5983_CONTROL_2 0xb
+# define MMC5983_CONTROL_2_EN_PRD_SET 7
+# define MMC5983_CONTROL_2_PRD_SET 4
+# define MMC5983_CONTROL_2_PRD_SET_1 0
+# define MMC5983_CONTROL_2_PRD_SET_25 1
+# define MMC5983_CONTROL_2_PRD_SET_75 2
+# define MMC5983_CONTROL_2_PRD_SET_100 3
+# define MMC5983_CONTROL_2_PRD_SET_250 4
+# define MMC5983_CONTROL_2_PRD_SET_500 5
+# define MMC5983_CONTROL_2_PRD_SET_1000 6
+# define MMC5983_CONTROL_2_PRD_SET_2000 7
+# define MMC5983_CONTROL_2_CMM_EN 3
+# define MMC5983_CONTROL_2_CM_FREQ 0
+# define MMC5983_CONTROL_2_CM_FREQ_OFF 0
+# define MMC5983_CONTROL_2_CM_FREQ_1HZ 1
+# define MMC5983_CONTROL_2_CM_FREQ_10HZ 2
+# define MMC5983_CONTROL_2_CM_FREQ_20HZ 3
+# define MMC5983_CONTROL_2_CM_FREQ_50HZ 4
+# define MMC5983_CONTROL_2_CM_FREQ_100HZ 5
+# define MMC5983_CONTROL_2_CM_FREQ_200HZ 6
+# define MMC5983_CONTROL_2_CM_FREQ_1000HZ 7
+
+#define MMC5983_CONTROL_3 0xc
+#define MMC5983_CONTROL_3_SPI_3W 6
+#define MMC5983_CONTROL_3_ST_ENM 2
+#define MMC5983_CONTROL_3_ST_ENP 1
+
+#define MMC5983_PRODUCT_ID 0x2f
+#define MMC5983_PRODUCT_ID_PRODUCT_I2C 0x30
+#define MMC5983_PRODUCT_ID_PRODUCT_SPI 0x31
+
+
+struct ao_mmc5983_sample {
+ int16_t x, y, z;
+};
+
+struct ao_mmc5983_raw {
+ uint8_t addr;
+ uint8_t x0;
+ uint8_t x1;
+ uint8_t y0;
+ uint8_t y1;
+ uint8_t z0;
+ uint8_t z1;
+ uint8_t xyz2;
+};
+
+extern struct ao_mmc5983_sample ao_mmc5983_current;
+
+void
+ao_mmc5983_init(void);
+
+#endif /* _AO_MMC5983_H_ */
return 0;
}
+static uint8_t mpu_id;
+
static void
_ao_mpu6000_wait_alive(void)
{
/* Wait for the chip to wake up */
for (i = 0; i < 30; i++) {
ao_delay(AO_MS_TO_TICKS(100));
- if (_ao_mpu6000_reg_read(MPU6000_WHO_AM_I) == 0x68)
- break;
+ mpu_id = _ao_mpu6000_reg_read(MPU6000_WHO_AM_I);
+ if (mpu_id == 0x68)
+ return;
}
- if (i == 30)
- ao_panic(AO_PANIC_SELF_TEST_MPU6000);
+ AO_SENSOR_ERROR(AO_DATA_MPU6000);
}
#define ST_TRIES 10
static void
ao_mpu6000_show(void)
{
+#ifdef AO_LOG_NORMALIZED
+ printf ("MPU6000: %7d %7d %7d %7d %7d %7d\n",
+ ao_mpu6000_along(&ao_mpu6000_current),
+ ao_mpu6000_across(&ao_mpu6000_current),
+ ao_mpu6000_through(&ao_mpu6000_current),
+ ao_mpu6000_roll(&ao_mpu6000_current),
+ ao_mpu6000_pitch(&ao_mpu6000_current),
+ ao_mpu6000_yaw(&ao_mpu6000_current));
+#else
printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d\n",
ao_mpu6000_current.accel_x,
ao_mpu6000_current.accel_y,
ao_mpu6000_current.gyro_x,
ao_mpu6000_current.gyro_y,
ao_mpu6000_current.gyro_z);
+#endif
}
static const struct ao_cmds ao_mpu6000_cmds[] = {
#ifndef _AO_BEEP_H_
#define _AO_BEEP_H_
-#ifndef HAS_BEEP_CONFIG
-#if defined(USE_EEPROM_CONFIG) && USE_EEPROM_CONFIG || HAS_EEPROM
-#define HAS_BEEP_CONFIG 1
-#endif
-#endif
-
/*
* ao_beep.c
*/
* frequency = 1/2 (24e6/32) / beep
*/
+#ifndef AO_BEEP_MID_DEFAULT
#define AO_BEEP_MID_DEFAULT 94 /* 3989Hz */
-
-#if HAS_BEEP_CONFIG
-#define AO_BEEP_MID ao_config.mid_beep
-#else
-#define AO_BEEP_MID AO_BEEP_MID_DEFAULT
#endif
+#define AO_BEEP_MID ((int) ao_config.mid_beep)
+
#define AO_BEEP_MID_PANIC AO_BEEP_MID_DEFAULT
-#define AO_BEEP_LOW AO_BEEP_MID * 150 / 94 /* 2500Hz */
-#define AO_BEEP_HIGH AO_BEEP_MID * 75 / 94 /* 5000Hz */
+#ifndef AO_BEEP_MAKE_LOW
+#define AO_BEEP_MAKE_LOW(m) ((m) * 150 / 94) /* 2500Hz */
+#endif
+
+#ifndef AO_BEEP_MAKE_HIGH
+#define AO_BEEP_MAKE_HIGH(m) ((m) * 75 / 94) /* 5000Hz */
+#endif
+
+#define AO_BEEP_LOW AO_BEEP_MAKE_LOW(AO_BEEP_MID)
+#define AO_BEEP_HIGH AO_BEEP_MAKE_HIGH(AO_BEEP_MID)
-#define AO_BEEP_LOW_PANIC (AO_BEEP_MID_PANIC * 150 / 94)
-#define AO_BEEP_HIGH_PANIC (AO_BEEP_MID_PANIC * 75 / 94)
+#define AO_BEEP_LOW_PANIC AO_BEEP_MAKE_LOW(AO_BEEP_MID_PANIC)
+#define AO_BEEP_HIGH_PANIC AO_BEEP_MAKE_HIGH(AO_BEEP_MID_PANIC)
#define AO_BEEP_OFF 0 /* off */
}
minor = ao_config.minor;
if (minor != AO_CONFIG_MINOR) {
+#if AO_PYRO_NUM
+ ao_pyro_update_version();
+#endif
/* Fixups for minor version 1 */
if (minor < 1)
ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
ao_config.accel_minus_g = 0;
}
#endif
-#if HAS_BEEP_CONFIG
+#if HAS_BEEP
if (minor < 16)
ao_config.mid_beep = AO_BEEP_MID_DEFAULT;
#endif
#endif
-#if HAS_BEEP_CONFIG
+#if HAS_BEEP
static void
ao_config_beep_show(void)
{
{ "A <secs>\0APRS packet interval (0 disable)",
ao_config_aprs_set, ao_config_aprs_show },
#endif
-#if HAS_BEEP_CONFIG
+#if HAS_BEEP
{ "b <val>\0Beeper tone (freq = 1/2 (24e6/32) / beep",
ao_config_beep_set, ao_config_beep_show },
#endif
#endif
#define AO_CONFIG_MAJOR 1
-#define AO_CONFIG_MINOR 24
+#define AO_CONFIG_MINOR 25
#define AO_AES_LEN 16
#define AO_DATA_HMC5883 0
#endif
+#if HAS_MMC5983
+#include <ao_mmc5983.h>
+#define AO_DATA_MMC5983 (1 << 3)
+#else
+#define AO_DATA_MMC5983 0
+#endif
+
#if HAS_MMA655X
#include <ao_mma655x.h>
#define AO_DATA_MMA655X (1 << 4)
#ifdef AO_DATA_RING
-#define AO_DATA_ALL (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X|AO_DATA_MPU9250|AO_DATA_ADXL375|AO_DATA_BMX160)
+#define AO_DATA_ALL (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X|AO_DATA_MPU9250|AO_DATA_ADXL375|AO_DATA_BMX160|AO_DATA_MMC5983)
struct ao_data {
uint16_t tick;
#if HAS_HMC5883
struct ao_hmc5883_sample hmc5883;
#endif
+#if HAS_MMC5983
+ struct ao_mmc5983_sample mmc5983;
+#endif
#if HAS_MMA655X
uint16_t mma655x;
#endif
/* X axis is aligned in the other board axis (across) */
/* Z axis is aligned perpendicular to the board (through) */
+#ifndef ao_data_along
#define ao_data_along(packet) ((packet)->mpu6000.accel_y)
#define ao_data_across(packet) ((packet)->mpu6000.accel_x)
#define ao_data_through(packet) ((packet)->mpu6000.accel_z)
#define ao_data_roll(packet) ((packet)->mpu6000.gyro_y)
#define ao_data_pitch(packet) ((packet)->mpu6000.gyro_x)
#define ao_data_yaw(packet) ((packet)->mpu6000.gyro_z)
+#endif
static inline float ao_convert_gyro(float sensor)
{
#endif
+#if !HAS_MAG && HAS_MMC5983
+
+#define HAS_MAG 1
+
+typedef int16_t ao_mag_t; /* in raw sample units */
+
+#endif
+
#if !HAS_MAG && HAS_MPU9250
#define HAS_MAG 1
#if HAS_HMC5883
ao_data_ring[head].hmc5883 = ao_hmc5883_current;
#endif
+#if HAS_MMC5983
+ ao_data_ring[head].mmc5983 = ao_mmc5983_current;
+#endif
#if HAS_MPU6000
ao_data_ring[head].mpu6000 = ao_mpu6000_current;
#endif
#if HAS_FLIGHT_DEBUG
case ao_flight_test:
#if HAS_GYRO
- printf ("angle %4d pitch %7d yaw %7d roll %7d\n",
+ printf ("angle %4d pitch %7ld yaw %7ld roll %7ld\n",
ao_sample_orient,
((ao_sample_pitch << 9) - ao_ground_pitch) >> 9,
((ao_sample_yaw << 9) - ao_ground_yaw) >> 9,
printf ("sample:\n");
printf (" tick %d\n", ao_sample_tick);
#if HAS_BARO
- printf (" raw pres %d\n", ao_sample_pres);
+ printf (" raw pres %ld\n", ao_sample_pres);
#endif
#if HAS_ACCEL
printf (" raw accel %d\n", ao_sample_accel);
#endif
#if HAS_BARO
- printf (" ground pres %d\n", ao_ground_pres);
- printf (" ground alt %d\n", ao_ground_height);
+ printf (" ground pres %ld\n", ao_ground_pres);
+ printf (" ground alt %ld\n", ao_ground_height);
#endif
#if HAS_ACCEL
printf (" raw accel %d\n", ao_sample_accel);
#endif
#if HAS_BARO
- printf (" alt %d\n", ao_sample_alt);
- printf (" height %d\n", ao_sample_height);
+ printf (" alt %ld\n", ao_sample_alt);
+ printf (" height %ld\n", ao_sample_height);
#endif
#if HAS_ACCEL
printf ("kalman:\n");
- printf (" height %d\n", ao_height);
+ printf (" height %ld\n", ao_height);
printf (" speed %d.%02d\n", int_part(ao_speed), frac_part(ao_speed));
printf (" accel %d.%02d\n", int_part(ao_accel), frac_part(ao_accel));
- printf (" max_height %d\n", ao_max_height);
- printf (" avg_height %d\n", ao_avg_height);
- printf (" error_h %d\n", ao_error_h);
+ printf (" max_height %ld\n", ao_max_height);
+ printf (" avg_height %ld\n", ao_avg_height);
+ printf (" error_h %ld\n", ao_error_h);
#if !HAS_ACCEL
printf (" error_avg %d\n", ao_error_h_sq_avg);
#endif
ao_orient_test_select(void)
{
ao_orient_test = !ao_orient_test;
+ printf("orient test %d\n", ao_orient_test);
}
const struct ao_cmds ao_flight_cmds[] = {
--- /dev/null
+/*
+ * Copyright © 2021 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_i2c_bit.h>
+#include <ao_exti.h>
+
+#define ao_i2c_bit_set_pin(port, pin) do { \
+ ao_enable_output(port, pin, 1); \
+ ao_gpio_set_output_mode(port, pin, AO_OUTPUT_OPEN_DRAIN); \
+ ao_gpio_set_mode(port, pin, AO_EXTI_MODE_PULL_UP); \
+ stm_ospeedr_set(port, pin, STM_OSPEEDR_10MHz); \
+ } while(0)
+
+
+/* 2µS per half-cycle, for a 125kHz i2c clock */
+#define AO_I2C_TICK 10000
+
+static void
+tick(void)
+{
+ int i;
+
+ for (i = 0; i < 12; i++)
+ ao_arch_nop();
+#if 0
+ uint64_t target = ao_time_ns() + AO_I2C_TICK;
+
+ do {
+ ao_yield();
+ } while ((int64_t) (ao_time_ns() - target) < 0);
+#endif
+}
+
+static void sda(uint8_t v)
+{
+ ao_gpio_set(AO_I2C_SDA_PORT, AO_I2C_SDA_PIN, v);
+ tick();
+}
+
+static uint8_t in(void)
+{
+ uint8_t v = ao_gpio_get(AO_I2C_SDA_PORT, AO_I2C_SDA_PIN);
+ tick();
+ return v;
+}
+
+static void scl(uint8_t v)
+{
+ ao_gpio_set(AO_I2C_SCL_PORT, AO_I2C_SCL_PIN, v);
+ tick();
+}
+
+static void
+i2c_start(void)
+{
+ sda(0);
+ scl(0);
+}
+
+static bool
+ack(void)
+{
+ bool v;
+ int j;
+
+ sda(1);
+ scl(1);
+ v = false;
+ for (j = 0; j < 100; j++) {
+ if (in() == 0) {
+ v = true;
+ break;
+ }
+ }
+ scl(0);
+ sda(1);
+ ao_yield();
+ return v;
+}
+
+static bool
+send(uint8_t byte)
+{
+ uint8_t bit;
+
+ for (bit = 0; bit < 8; bit++) {
+ sda(byte>>7);
+ scl(1);
+ tick();
+ scl(0);
+ byte <<= 1;
+ }
+ return ack();
+}
+
+static uint8_t
+recv(void)
+{
+ uint8_t byte = 0;
+ uint8_t bit;
+
+ for (bit = 0; bit < 8; bit++) {
+ sda(1);
+ scl(1);
+ byte = (byte << 1) | in();
+ scl(0);
+ }
+ ack();
+ return byte;
+}
+
+static void
+stop(void)
+{
+ sda(0);
+ scl(1);
+ sda(1);
+}
+
+static void
+restart(void)
+{
+ sda(1);
+ scl(1);
+ sda(0);
+ scl(0);
+}
+
+static uint8_t
+ao_i2c_bit_mutex;
+
+void
+ao_i2c_bit_get(void)
+{
+ ao_mutex_get(&ao_i2c_bit_mutex);
+}
+
+void
+ao_i2c_bit_put(void)
+{
+ ao_mutex_put(&ao_i2c_bit_mutex);
+}
+
+bool
+ao_i2c_bit_start(uint8_t addr)
+{
+ i2c_start();
+ return send(addr);
+}
+
+bool
+ao_i2c_bit_restart(uint8_t addr)
+{
+ restart();
+ return send(addr);
+}
+
+void
+ao_i2c_bit_stop(void)
+{
+ stop();
+}
+
+void
+ao_i2c_bit_send(void *block, uint16_t len)
+{
+ uint8_t *b = block;
+ while (len--)
+ send(*b++);
+}
+
+void
+ao_i2c_bit_recv(void *block, uint16_t len)
+{
+ uint8_t *b = block;
+
+ while (len--)
+ *b++ = recv();
+}
+
+void
+ao_i2c_bit_init(void)
+{
+ ao_i2c_bit_set_pin(AO_I2C_SCL_PORT, AO_I2C_SCL_PIN);
+ ao_i2c_bit_set_pin(AO_I2C_SDA_PORT, AO_I2C_SDA_PIN);
+}
--- /dev/null
+/*
+ * Copyright © 2021 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>
+
+void
+ao_i2c_bit_get(void);
+
+void
+ao_i2c_bit_put(void);
+
+bool
+ao_i2c_bit_start(uint8_t addr);
+
+bool
+ao_i2c_bit_restart(uint8_t addr);
+
+void
+ao_i2c_bit_stop(void);
+
+void
+ao_i2c_bit_send(void *block, uint16_t len);
+
+void
+ao_i2c_bit_recv(void *block, uint16_t len);
+
+void
+ao_i2c_bit_init(void);
#define AO_LOG_FORMAT_MICROPEAK2 18 /* 2-byte baro values with header */
#define AO_LOG_FORMAT_TELEMEGA_4 19 /* 32 byte typed telemega records with 32 bit gyro cal and Bmx160 */
#define AO_LOG_FORMAT_EASYMOTOR 20 /* ? byte typed easymotor records with pressure sensor and adxl375 */
+#define AO_LOG_FORMAT_TELEMEGA_5 21 /* 32 byte typed telemega records with 32 bit gyro cal, mpu6000 and mmc5983 */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
/* Return the flight number from the given log slot, 0 if none, -slot on failure */
struct {
uint32_t pres; /* 4 */
uint32_t temp; /* 8 */
- int16_t accel_x; /* 12 */
- int16_t accel_y; /* 14 */
- int16_t accel_z; /* 16 */
- int16_t gyro_x; /* 18 */
- int16_t gyro_y; /* 20 */
- int16_t gyro_z; /* 22 */
- int16_t mag_x; /* 24 */
- int16_t mag_z; /* 26 */
- int16_t mag_y; /* 28 */
+ union {
+ struct {
+ int16_t accel_along; /* 12 */
+ int16_t accel_across; /* 14 */
+ int16_t accel_through; /* 16 */
+ int16_t gyro_roll; /* 18 */
+ int16_t gyro_pitch; /* 20 */
+ int16_t gyro_yaw; /* 22 */
+ int16_t mag_along; /* 24 */
+ int16_t mag_across; /* 26 */
+ int16_t mag_through; /* 28 */
+ };
+ struct {
+ int16_t accel_x; /* 12 */
+ int16_t accel_y; /* 14 */
+ int16_t accel_z; /* 16 */
+ int16_t gyro_x; /* 18 */
+ int16_t gyro_y; /* 20 */
+ int16_t gyro_z; /* 22 */
+ int16_t mag_x; /* 24 */
+ int16_t mag_z; /* 26 */
+ int16_t mag_y; /* 28 */
+ };
+ };
int16_t accel; /* 30 */
} sensor; /* 32 */
/* AO_LOG_TEMP_VOLT */
} u;
};
-#if AO_LOG_FORMAT == AO_LOG_FOMAT_TELEMEGA_OLD || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_3 || AO_LOG_FORMAT == AO_LOG_FORMAT_EASYMEGA_2 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_4
+#if AO_LOG_FORMAT == AO_LOG_FOMAT_TELEMEGA_OLD || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_3 || AO_LOG_FORMAT == AO_LOG_FORMAT_EASYMEGA_2 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_4 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_5
typedef struct ao_log_mega ao_log_type;
#endif
/* Write samples to EEPROM */
while (ao_log_data_pos != ao_data_head) {
ao_log_data.tick = ao_data_ring[ao_log_data_pos].tick;
+ volatile struct ao_data *d = &ao_data_ring[ao_log_data_pos];
if ((int16_t) (ao_log_data.tick - next_sensor) >= 0) {
ao_log_data.type = AO_LOG_SENSOR;
#if HAS_MS5607
- ao_log_data.u.sensor.pres = ao_data_ring[ao_log_data_pos].ms5607_raw.pres;
- ao_log_data.u.sensor.temp = ao_data_ring[ao_log_data_pos].ms5607_raw.temp;
+ ao_log_data.u.sensor.pres = d->ms5607_raw.pres;
+ ao_log_data.u.sensor.temp = d->ms5607_raw.temp;
#endif
#if HAS_MPU6000
- ao_log_data.u.sensor.accel_x = ao_data_ring[ao_log_data_pos].mpu6000.accel_x;
- ao_log_data.u.sensor.accel_y = ao_data_ring[ao_log_data_pos].mpu6000.accel_y;
- ao_log_data.u.sensor.accel_z = ao_data_ring[ao_log_data_pos].mpu6000.accel_z;
- ao_log_data.u.sensor.gyro_x = ao_data_ring[ao_log_data_pos].mpu6000.gyro_x;
- ao_log_data.u.sensor.gyro_y = ao_data_ring[ao_log_data_pos].mpu6000.gyro_y;
- ao_log_data.u.sensor.gyro_z = ao_data_ring[ao_log_data_pos].mpu6000.gyro_z;
+#ifdef AO_LOG_NORMALIZED
+ ao_log_data.u.sensor.accel_along = ao_data_along(d);
+ ao_log_data.u.sensor.accel_across = ao_data_across(d);
+ ao_log_data.u.sensor.accel_through = ao_data_through(d);
+ ao_log_data.u.sensor.gyro_roll = ao_data_roll(d);
+ ao_log_data.u.sensor.gyro_pitch = ao_data_pitch(d);
+ ao_log_data.u.sensor.gyro_yaw = ao_data_yaw(d);
+#else
+ ao_log_data.u.sensor.accel_x = d->mpu6000.accel_x;
+ ao_log_data.u.sensor.accel_y = d->mpu6000.accel_y;
+ ao_log_data.u.sensor.accel_z = d->mpu6000.accel_z;
+ ao_log_data.u.sensor.gyro_x = d->mpu6000.gyro_x;
+ ao_log_data.u.sensor.gyro_y = d->mpu6000.gyro_y;
+ ao_log_data.u.sensor.gyro_z = d->mpu6000.gyro_z;
+#endif
#endif
#if HAS_HMC5883
- ao_log_data.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].hmc5883.x;
- ao_log_data.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].hmc5883.z;
- ao_log_data.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].hmc5883.y;
+ ao_log_data.u.sensor.mag_x = d->hmc5883.x;
+ ao_log_data.u.sensor.mag_z = d->hmc5883.z;
+ ao_log_data.u.sensor.mag_y = d->hmc5883.y;
+#endif
+#ifdef HAS_MMC5983
+ ao_log_data.u.sensor.mag_along = ao_data_mag_along(d);
+ ao_log_data.u.sensor.mag_across = ao_data_mag_across(d);
+ ao_log_data.u.sensor.mag_through = ao_data_mag_through(d);
#endif
#if HAS_MPU9250
- ao_log_data.u.sensor.accel_x = ao_data_ring[ao_log_data_pos].mpu9250.accel_x;
- ao_log_data.u.sensor.accel_y = ao_data_ring[ao_log_data_pos].mpu9250.accel_y;
- ao_log_data.u.sensor.accel_z = ao_data_ring[ao_log_data_pos].mpu9250.accel_z;
- ao_log_data.u.sensor.gyro_x = ao_data_ring[ao_log_data_pos].mpu9250.gyro_x;
- ao_log_data.u.sensor.gyro_y = ao_data_ring[ao_log_data_pos].mpu9250.gyro_y;
- ao_log_data.u.sensor.gyro_z = ao_data_ring[ao_log_data_pos].mpu9250.gyro_z;
- ao_log_data.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].mpu9250.mag_x;
- ao_log_data.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].mpu9250.mag_z;
- ao_log_data.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].mpu9250.mag_y;
+ ao_log_data.u.sensor.accel_x = d->mpu9250.accel_x;
+ ao_log_data.u.sensor.accel_y = d->mpu9250.accel_y;
+ ao_log_data.u.sensor.accel_z = d->mpu9250.accel_z;
+ ao_log_data.u.sensor.gyro_x = d->mpu9250.gyro_x;
+ ao_log_data.u.sensor.gyro_y = d->mpu9250.gyro_y;
+ ao_log_data.u.sensor.gyro_z = d->mpu9250.gyro_z;
+ ao_log_data.u.sensor.mag_x = d->mpu9250.mag_x;
+ ao_log_data.u.sensor.mag_z = d->mpu9250.mag_z;
+ ao_log_data.u.sensor.mag_y = d->mpu9250.mag_y;
#endif
#if HAS_BMX160
- ao_log_data.u.sensor.accel_x = ao_data_ring[ao_log_data_pos].bmx160.acc_x;
- ao_log_data.u.sensor.accel_y = ao_data_ring[ao_log_data_pos].bmx160.acc_y;
- ao_log_data.u.sensor.accel_z = ao_data_ring[ao_log_data_pos].bmx160.acc_z;
- ao_log_data.u.sensor.gyro_x = ao_data_ring[ao_log_data_pos].bmx160.gyr_x;
- ao_log_data.u.sensor.gyro_y = ao_data_ring[ao_log_data_pos].bmx160.gyr_y;
- ao_log_data.u.sensor.gyro_z = ao_data_ring[ao_log_data_pos].bmx160.gyr_z;
- ao_log_data.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].bmx160.mag_x;
- ao_log_data.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].bmx160.mag_z;
- ao_log_data.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].bmx160.mag_y;
+ ao_log_data.u.sensor.accel_x = d->bmx160.acc_x;
+ ao_log_data.u.sensor.accel_y = d->bmx160.acc_y;
+ ao_log_data.u.sensor.accel_z = d->bmx160.acc_z;
+ ao_log_data.u.sensor.gyro_x = d->bmx160.gyr_x;
+ ao_log_data.u.sensor.gyro_y = d->bmx160.gyr_y;
+ ao_log_data.u.sensor.gyro_z = d->bmx160.gyr_z;
+ ao_log_data.u.sensor.mag_x = d->bmx160.mag_x;
+ ao_log_data.u.sensor.mag_z = d->bmx160.mag_z;
+ ao_log_data.u.sensor.mag_y = d->bmx160.mag_y;
#endif
ao_log_data.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
ao_log_write(&ao_log_data);
}
if ((int16_t) (ao_log_data.tick - next_other) >= 0) {
ao_log_data.type = AO_LOG_TEMP_VOLT;
- ao_log_data.u.volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
- ao_log_data.u.volt.v_pbatt = ao_data_ring[ao_log_data_pos].adc.v_pbatt;
+ ao_log_data.u.volt.v_batt = d->adc.v_batt;
+ ao_log_data.u.volt.v_pbatt = d->adc.v_pbatt;
ao_log_data.u.volt.n_sense = AO_ADC_NUM_SENSE;
for (i = 0; i < AO_ADC_NUM_SENSE; i++)
- ao_log_data.u.volt.sense[i] = ao_data_ring[ao_log_data_pos].adc.sense[i];
+ ao_log_data.u.volt.sense[i] = d->adc.sense[i];
ao_log_data.u.volt.pyro = ao_pyro_fired;
ao_log_write(&ao_log_data);
next_other = ao_log_data.tick + AO_OTHER_INTERVAL;
#endif
case ao_pyro_time_less:
- if ((int16_t) (ao_time() - ao_launch_tick) <= pyro->time_less)
+ if ((int32_t) (ao_time() - ao_launch_tick) <= pyro->time_less)
continue;
- DBG("time %d > %d\n", (int16_t)(ao_time() - ao_launch_tick), pyro->time_less);
+ DBG("time %d > %d\n", (int32_t)(ao_time() - ao_launch_tick), pyro->time_less);
break;
case ao_pyro_time_greater:
- if ((int16_t) (ao_time() - ao_launch_tick) >= pyro->time_greater)
+ if ((int32_t) (ao_time() - ao_launch_tick) >= pyro->time_greater)
continue;
- DBG("time %d < %d\n", (int16_t)(ao_time() - ao_launch_tick), pyro->time_greater);
+ DBG("time %d < %d\n", (int32_t)(ao_time() - ao_launch_tick), pyro->time_greater);
break;
case ao_pyro_ascending:
continue;
}
- if ((int16_t) (ao_time() - pyro->delay_done) < 0)
+ if ((int32_t) (ao_time() - pyro->delay_done) < 0)
continue;
}
}
#endif
+static int32_t
+ao_pyro_get(void *base, uint8_t offset, uint8_t size)
+{
+ int32_t value;
+ switch (size) {
+ case 8:
+ value = *((uint8_t *) ((char *) base + offset));
+ break;
+ case 16:
+ default:
+ value = *((int16_t *) (void *) ((char *) base + offset));
+ break;
+ case 32:
+ value = *((int32_t *) (void *) ((char *) base + offset));
+ break;
+ }
+ return value;
+}
+
+static bool
+ao_pyro_put(void *base, uint8_t offset, uint8_t size, int32_t value)
+{
+ switch (size) {
+ case 8:
+ if (value < 0)
+ return false;
+ *((uint8_t *) ((char *) base + offset)) = value;
+ break;
+ case 16:
+ default:
+ *((int16_t *) (void *) ((char *) base + offset)) = value;
+ break;
+ case 32:
+ *((int32_t *) (void *) ((char *) base + offset)) = value;
+ break;
+ }
+ return true;
+}
+
+static uint8_t
+ao_pyro_size(enum ao_pyro_flag flag)
+{
+ if (flag & AO_PYRO_8_BIT_VALUE)
+ return 8;
+ if (flag & AO_PYRO_32_BIT_VALUE)
+ return 32;
+ return 16;
+}
+
void
ao_pyro_show(void)
{
continue;
ao_pyro_print_name(v);
if (ao_pyro_values[v].offset != NO_VALUE) {
- int16_t value;
-
- if (ao_pyro_values[v].flag & AO_PYRO_8_BIT_VALUE)
- value = *((uint8_t *) ((char *) pyro + ao_pyro_values[v].offset));
- else
- value = *((int16_t *) (void *) ((char *) pyro + ao_pyro_values[v].offset));
- printf ("%6d ", value);
+ printf ("%6ld ",
+ (long) ao_pyro_get(pyro,
+ ao_pyro_values[v].offset,
+ ao_pyro_size(ao_pyro_values[v].flag)));
} else {
printf (" ");
}
}
pyro_tmp.flags |= ao_pyro_values[v].flag;
if (ao_pyro_values[v].offset != NO_VALUE) {
- int16_t r = 1;
+ int32_t r = 1;
ao_cmd_white();
if (ao_cmd_lex_c == '-') {
r = -1;
r *= ao_cmd_decimal();
if (ao_cmd_status != ao_cmd_success)
return;
- if (ao_pyro_values[v].flag & AO_PYRO_8_BIT_VALUE) {
- if (r < 0) {
- ao_cmd_status = ao_cmd_syntax_error;
- return;
- }
- *((uint8_t *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = r;
- } else {
- *((int16_t *) (void *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = r;
+ if (!ao_pyro_put(&pyro_tmp, ao_pyro_values[v].offset,
+ ao_pyro_size(ao_pyro_values[v].flag), r))
+ {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return;
}
}
}
ao_pyro_pins_fire(1 << p);
}
+struct ao_pyro_old_values {
+ enum ao_pyro_flag flag;
+ uint8_t offset;
+ uint8_t size;
+};
+
+static const struct ao_pyro_old_values ao_pyro_1_24_values[] = {
+ { .flag = ao_pyro_accel_less, .offset = offsetof(struct ao_pyro_1_24, accel_less), 16 },
+ { .flag = ao_pyro_accel_greater, .offset = offsetof(struct ao_pyro_1_24, accel_greater), 16 },
+ { .flag = ao_pyro_speed_less, .offset = offsetof(struct ao_pyro_1_24, speed_less), 16 },
+ { .flag = ao_pyro_speed_greater, .offset = offsetof(struct ao_pyro_1_24, speed_greater), 16 },
+ { .flag = ao_pyro_height_less, .offset = offsetof(struct ao_pyro_1_24, height_less), 16 },
+ { .flag = ao_pyro_height_greater, .offset = offsetof(struct ao_pyro_1_24, height_greater), 16 },
+ { .flag = ao_pyro_orient_less, .offset = offsetof(struct ao_pyro_1_24, orient_less), 16 },
+ { .flag = ao_pyro_orient_greater, .offset = offsetof(struct ao_pyro_1_24, orient_greater), 16 },
+ { .flag = ao_pyro_time_less, .offset = offsetof(struct ao_pyro_1_24, time_less), 16 },
+ { .flag = ao_pyro_time_greater, .offset = offsetof(struct ao_pyro_1_24, time_greater), 16 },
+ { .flag = ao_pyro_delay, .offset = offsetof(struct ao_pyro_1_24, delay), 16 },
+ { .flag = ao_pyro_state_less, .offset = offsetof(struct ao_pyro_1_24, state_less), 8 },
+ { .flag = ao_pyro_state_greater_or_equal, .offset = offsetof(struct ao_pyro_1_24, state_greater_or_equal), 8 },
+ { .flag = ao_pyro_after_motor, .offset = offsetof(struct ao_pyro_1_24, motor), 16 },
+};
+
+#define NUM_PYRO_1_24_VALUES (sizeof ao_pyro_1_24_values / sizeof ao_pyro_1_24_values[0])
+
+static int32_t
+ao_pyro_get_1_24(void *base, enum ao_pyro_flag flag)
+{
+ unsigned v;
+
+ for (v = 0; v < NUM_PYRO_1_24_VALUES; v++) {
+ if (ao_pyro_1_24_values[v].flag == flag)
+ return ao_pyro_get(base, ao_pyro_1_24_values[v].offset, ao_pyro_1_24_values[v].size);
+ }
+ return 0;
+}
+
+void
+ao_pyro_update_version(void)
+{
+ if (ao_config.minor <= 24)
+ {
+
+ /* First, move all of the config bits that follow the pyro data */
+
+ char *pyro_base = (void *) &ao_config.pyro;
+ char *after_pyro_new = pyro_base + AO_PYRO_NUM * sizeof (struct ao_pyro);
+ char *after_pyro_1_24 = pyro_base + AO_PYRO_NUM * sizeof (struct ao_pyro_1_24);
+ char *config_end = (void *) (&ao_config + 1);
+ size_t to_move = config_end - after_pyro_new;
+
+ memmove(after_pyro_new, after_pyro_1_24, to_move);
+
+ /* Now, adjust all of the pyro entries */
+
+ struct ao_pyro *pyro_new = ao_config.pyro;
+ struct ao_pyro_1_24 *pyro_old = (void *) ao_config.pyro;
+
+ int p = AO_PYRO_NUM;
+
+ /* New struct is larger than the old, so start at the
+ * last one and work towards the first
+ */
+ while (p-- > 0) {
+ unsigned v;
+ int32_t value;
+ struct ao_pyro tmp;
+
+ memset(&tmp, '\0', sizeof(tmp));
+ tmp.flags = pyro_old[p].flags;
+
+ for (v = 0; v < NUM_PYRO_VALUES; v++)
+ {
+ value = ao_pyro_get_1_24(&pyro_old[v], ao_pyro_values[v].flag);
+ ao_pyro_put(&tmp, ao_pyro_values[v].offset,
+ ao_pyro_size(ao_pyro_values[v].flag), value);
+ }
+ memcpy(&pyro_new[p], &tmp, sizeof(tmp));
+ }
+ }
+}
+
void
ao_pyro_init(void)
{
#endif
;
-struct ao_pyro {
+struct ao_pyro_1_24 {
enum ao_pyro_flag flags;
int16_t accel_less, accel_greater;
int16_t speed_less, speed_greater;
uint8_t _unused; /* was 'fired' */
};
+struct ao_pyro {
+ enum ao_pyro_flag flags;
+ int16_t accel_less, accel_greater;
+ int16_t speed_less, speed_greater;
+ int16_t height_less, height_greater;
+ int16_t orient_less, orient_greater;
+ int32_t time_less, time_greater;
+ int32_t delay;
+ uint8_t state_less, state_greater_or_equal;
+ int16_t motor;
+ int32_t delay_done;
+ uint8_t _unused; /* was 'fired' */
+};
+
#define AO_PYRO_8_BIT_VALUE (ao_pyro_state_less|ao_pyro_state_greater_or_equal)
+#define AO_PYRO_32_BIT_VALUE (ao_pyro_time_less|ao_pyro_time_greater|ao_pyro_delay)
extern uint8_t ao_pyro_wakeup;
void
ao_pyro_init(void);
+void
+ao_pyro_update_version(void);
+
void
ao_pyro_manual(uint8_t p);
*/
ao_quaternion_vectors_to_rotation(&ao_rotation, &up, &orient);
#if HAS_FLIGHT_DEBUG
- if (ao_orient_test)
+ if (ao_orient_test) {
printf("\n\treset across %d through %d along %d\n",
(ao_ground_accel_across - ao_config.accel_zero_across),
(ao_ground_accel_through - ao_config.accel_zero_through),
(ao_ground_accel_along - ao_config.accel_zero_along));
+ fflush(stdout);
+ }
#endif
ao_sample_compute_orient();
}
#if HAS_GYRO
-
#define TIME_DIV 200.0f
static void
(int) (y * 1000),
(int) (z * 1000),
ao_sample_orient);
+ fflush(stdout);
}
#endif
ao_sample_compute_orient();
static FILE __stdio = FDEV_SETUP_STREAM(ao_putc, ao_getc, ao_flushc, _FDEV_SETUP_RW);
+#ifdef PICOLIBC_STDIO_GLOBALS
+
+#ifdef __strong_reference
+#define STDIO_ALIAS(x) __strong_reference(stdin, x);
+#else
+#define STDIO_ALIAS(x) FILE *const x = &__stdio;
+#endif
+
+FILE *const stdin = &__stdio;
+STDIO_ALIAS(stdout);
+STDIO_ALIAS(stderr);
+
+#else
+
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
+
+#endif
static void
ao_send_mega_sensor(void)
{
- struct ao_data *packet = (struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
+ struct ao_data *packet = (struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
telemetry.generic.tick = packet->tick;
+#if AO_LOG_NORMALIZED
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_5
+ telemetry.generic.type = AO_TELEMETRY_MEGA_NORM_MPU6000_MMC5983;
+#else
+#error unknown normalized log type
+#endif
+
+#if HAS_GYRO
+ telemetry.mega_norm.orient = ao_sample_orient;
+#endif
+ telemetry.mega_norm.accel = ao_data_accel(packet);
+ telemetry.mega_norm.pres = ao_data_pres(packet);
+ telemetry.mega_norm.temp = ao_data_temp(packet);
+
+#if HAS_MPU6000
+ telemetry.mega_norm.accel_along = ao_data_along(packet);
+ telemetry.mega_norm.accel_across = ao_data_across(packet);
+ telemetry.mega_norm.accel_through = ao_data_through(packet);
+
+ telemetry.mega_norm.gyro_roll = ao_data_roll(packet);
+ telemetry.mega_norm.gyro_pitch = ao_data_pitch(packet);
+ telemetry.mega_norm.gyro_yaw = ao_data_yaw(packet);
+#endif
+
+#if HAS_MMC5983
+ telemetry.mega_norm.mag_along = ao_data_mag_along(packet);
+ telemetry.mega_norm.mag_across = ao_data_mag_across(packet);
+ telemetry.mega_norm.mag_through = ao_data_mag_through(packet);
+#endif
+
+#else
+
#if HAS_BMX160
telemetry.generic.type = AO_TELEMETRY_MEGA_SENSOR_BMX160;
#else
telemetry.mega_sensor.mag_z = packet->bmx160.mag_z;
telemetry.mega_sensor.mag_y = packet->bmx160.mag_y;
#endif
-
+#endif
ao_telemetry_send();
}
/* 32 */
};
+#define AO_TELEMETRY_MEGA_NORM_MPU6000_MMC5983 0x13
+
+struct ao_telemetry_mega_norm {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t orient; /* 5 angle from vertical */
+ int16_t accel; /* 6 Z axis */
+
+ int32_t pres; /* 8 Pa * 10 */
+ int16_t temp; /* 12 °C * 100 */
+
+ int16_t accel_along; /* 14 */
+ int16_t accel_across; /* 16 */
+ int16_t accel_through; /* 18 */
+
+ int16_t gyro_roll; /* 20 */
+ int16_t gyro_pitch; /* 22 */
+ int16_t gyro_yaw; /* 24 */
+
+ int16_t mag_along; /* 26 */
+ int16_t mag_across; /* 28 */
+ int16_t mag_through; /* 30 */
+ /* 32 */
+};
+
/* #define AO_SEND_ALL_BARO */
#define AO_TELEMETRY_BARO 0x80
struct ao_telemetry_metrum_data metrum_data;
struct ao_telemetry_mini mini;
struct ao_telemetry_baro baro;
+ struct ao_telemetry_mega_norm mega_norm;
};
typedef char ao_check_telemetry_size[sizeof(union ao_telemetry_all) == 32 ? 1 : -1];
vuint32_t introuting;
uint32_t r30;
vuint32_t eptoggle;
-} lpc_usb;
+};
extern struct lpc_usb lpc_usb;
#define lpc_usb (*(struct lpc_usb *) 0x40080000)
#include <ao_report_micro.h>
#include <ao_log_micro.h>
-uint32_t pa;
alt_t ground_alt, max_alt;
alt_t ao_max_height;
CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
-LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stm -Taltos-loader.ld -n
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Taltos-loader.ld -n
PROGNAME=$(HARDWARE)-altos-flash
PROG=$(PROGNAME)-$(VERSION).elf
include $(TOPDIR)/stm/Makefile-stm.defs
-LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stm -Taltos.ld -n
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Taltos.ld -n
ao_spi_put(bus); \
} while (0)
-#define ao_spi_get_bit(reg,bit,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
-#define ao_spi_put_bit(reg,bit,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+#define ao_spi_get_bit(reg,bit,bus,speed) ao_spi_get_mask(reg,1<<(bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,bus) ao_spi_put_mask(reg,1<<(bit),bus)
#define ao_enable_port(port) do { \
if ((port) == &stm_gpioa) \
#define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL
#define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN
-#define ao_gpio_set_output_mode(port,bit,mode) \
+#define ao_gpio_set_output_mode(port,pin,mode) \
stm_otyper_set(port, pin, mode)
#define ao_gpio_set_mode(port,bit,mode) do { \
extern char __stack[];
void _start(void) __attribute__((__noreturn__));
void main(void) __attribute__((__noreturn__));
+void ao_setup(void) __attribute__((constructor));
/* This must be exactly 256 bytes long so that the configuration data
* gets loaded at the right place
i(0xf0, tim7),
};
-extern char __data_source[];
-extern char __data_start[];
-extern char __data_size[];
-extern char __bss_start[];
-extern char __bss_size[];
-
-void _start(void) {
- memcpy(__data_start, __data_source, (uintptr_t) __data_size);
- memset(__bss_start, '\0', (uintptr_t) __bss_size);
-
+void __attribute__((constructor)) ao_setup(void) {
#ifdef AO_BOOT_CHAIN
if (ao_boot_check_chain()) {
#ifdef AO_BOOT_PIN
#endif
/* Set interrupt vector table offset */
stm_nvic.vto = (uint32_t) &__interrupt_vector;
- main();
}
--- /dev/null
+#
+# 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 \
+ altitude-pa.h \
+ ao_kalman.h \
+ ao_product.h \
+ ao_ms5607.h \
+ ao_mpu6000.h \
+ ao_mmc5983.h \
+ ao_adxl375.h \
+ ao_cc1200_CC1200.h \
+ ao_profile.h \
+ ao_task.h \
+ ao_whiten.h \
+ ao_sample_profile.h \
+ ao_quaternion.h \
+ ao_mpu.h \
+ stm32l.h \
+ ao_ms5607_convert.c \
+ Makefile
+
+#
+# Common AltOS sources
+#
+
+#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
+
+# Bit-bang MMC5983 chip needs this
+# ao_i2c_bit.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_stm.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_gps_report_mega.c \
+ ao_ignite.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_cc1200.c \
+ ao_data.c \
+ ao_ms5607.c \
+ ao_adxl375.c \
+ ao_adc_stm.c \
+ ao_beep_stm.c \
+ ao_eeprom_stm.c \
+ ao_storage.c \
+ ao_m25.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_report.c \
+ ao_mpu6000.c \
+ ao_mmc5983.c \
+ ao_convert_pa.c \
+ ao_convert_volt.c \
+ ao_log.c \
+ ao_log_mega.c \
+ ao_sample.c \
+ ao_kalman.c \
+ ao_flight.c \
+ ao_telemetry.c \
+ ao_packet_slave.c \
+ ao_packet.c \
+ ao_companion.c \
+ ao_pyro.c \
+ ao_aprs.c \
+ ao_pwm_stm.c \
+ $(PROFILE) \
+ $(SAMPLE_PROFILE) \
+ $(STACK_GUARD)
+
+PRODUCT=TeleMega-v5.0
+PRODUCT_DEF=-DTELEMEGA
+IDPRODUCT=0x0023
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
+
+PROGNAME=telemega-v5.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemega.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME)-*.map
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2017 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_
+
+
+/* 16MHz High speed external crystal */
+#define AO_HSE 16000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL 6
+#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_6)
+
+/* 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 0
+
+#define HAS_SERIAL_2 1
+#define USE_SERIAL_2_STDIN 0
+#define SERIAL_2_PA2_PA3 1
+#define SERIAL_2_PD5_PD6 0
+#define USE_SERIAL_2_FLOW 0
+#define USE_SERIAL_2_SW_FLOW 0
+
+#define HAS_SERIAL_3 0
+#define USE_SERIAL_3_STDIN 0
+#define SERIAL_3_PB10_PB11 0
+#define SERIAL_3_PC10_PC11 0
+#define SERIAL_3_PD8_PD9 0
+
+#define ao_gps_getchar ao_serial2_getchar
+#define ao_gps_putchar ao_serial2_putchar
+#define ao_gps_set_speed ao_serial2_set_speed
+#define ao_gps_fifo (ao_stm_usart2.rx_fifo)
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (1024 * 1024)
+#define AO_CONFIG_MAX_SIZE 1024
+#define LOG_ERASE_MARK 0x55
+#define LOG_MAX_ERASE 128
+#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMEGA_5
+#define AO_LOG_NORMALIZED 1
+
+#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 1
+#define BEEPER_TIMER 3
+#define BEEPER_CHANNEL 2
+#define BEEPER_PORT (&stm_gpioe)
+#define BEEPER_PIN 4
+#define AO_BEEP_MID_DEFAULT 179 /* 2100 Hz */
+#define AO_BEEP_MAKE_LOW(m) ((m) * 197/179) /* 1900 Hz */
+#define AO_BEEP_MAKE_HIGH(m) ((m) * 163/179) /* 2300 Hz */
+#define HAS_BATTERY_REPORT 1
+#define HAS_RADIO 1
+#define HAS_TELEMETRY 1
+#define HAS_APRS 1
+#define HAS_COMPANION 1
+
+#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 1 /* MPU6000 */
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+//#define MMC5983_I2C 1
+
+#define HAS_SPI_2 1
+#define SPI_2_PB13_PB14_PB15 1 /* Flash, Companion */
+#ifndef MMC5983_I2C
+#define SPI_2_PD1_PD3_PD4 1 /* MMC5983 */
+#endif
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#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 1
+#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 8
+#define LED_PIN_GREEN 9
+#define AO_LED_RED (1 << LED_PIN_RED)
+#define AO_LED_GREEN (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS 1
+#define HAS_FLIGHT 1
+#define HAS_ADC 1
+#define HAS_ADC_TEMP 1
+#define HAS_LOG 1
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE 1
+#define HAS_IGNITE_REPORT 1
+
+#define AO_SENSE_PYRO(p,n) ((p)->adc.sense[n])
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense[4])
+#define AO_SENSE_MAIN(p) ((p)->adc.sense[5])
+#define AO_IGNITER_CLOSED 400
+#define AO_IGNITER_OPEN 60
+
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiod)
+#define AO_PYRO_PIN_0 6
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiod)
+#define AO_PYRO_PIN_1 7
+
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpioe)
+#define AO_PYRO_PIN_2 3
+
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpioe)
+#define AO_PYRO_PIN_3 2
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioe)
+#define AO_IGNITER_DROGUE_PIN 6
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT (&stm_gpioe)
+#define AO_IGNITER_MAIN_PIN 5
+
+/* Number of general purpose pyro channels available */
+#define AO_PYRO_NUM 4
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING 32
+#define AO_ADC_NUM_SENSE 6
+
+struct ao_adc {
+ int16_t sense[AO_ADC_NUM_SENSE];
+ int16_t v_batt;
+ int16_t v_pbatt;
+ int16_t temp;
+};
+
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u A: %5d B: %5d C: %5d D: %5d drogue: %5d main: %5d batt: %5d pbatt: %5d temp: %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.v_batt, (p)->adc.v_pbatt, (p)->adc.temp)
+
+#define AO_ADC_SENSE_A 0
+#define AO_ADC_SENSE_A_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_A_PIN 0
+
+#define AO_ADC_SENSE_B 1
+#define AO_ADC_SENSE_B_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_B_PIN 1
+
+#define AO_ADC_SENSE_C 24
+#define AO_ADC_SENSE_C_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_C_PIN 9
+
+#define AO_ADC_SENSE_D 25
+#define AO_ADC_SENSE_D_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_D_PIN 10
+
+#define AO_ADC_SENSE_DROGUE 4
+#define AO_ADC_SENSE_DROGUE_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN 4
+
+#define AO_ADC_SENSE_MAIN 22
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_MAIN_PIN 7
+
+#define AO_ADC_V_BATT 8
+#define AO_ADC_V_BATT_PORT (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN 0
+
+#define AO_ADC_V_PBATT 9
+#define AO_ADC_V_PBATT_PORT (&stm_gpiob)
+#define AO_ADC_V_PBATT_PIN 1
+
+#define AO_ADC_TEMP 16
+
+#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+ (1 << STM_RCC_AHBENR_GPIOEEN) | \
+ (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 2)
+
+#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT
+#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN
+#define AO_ADC_PIN1_PORT AO_ADC_SENSE_B_PORT
+#define AO_ADC_PIN1_PIN AO_ADC_SENSE_B_PIN
+#define AO_ADC_PIN2_PORT AO_ADC_SENSE_C_PORT
+#define AO_ADC_PIN2_PIN AO_ADC_SENSE_C_PIN
+#define AO_ADC_PIN3_PORT AO_ADC_SENSE_D_PORT
+#define AO_ADC_PIN3_PIN AO_ADC_SENSE_D_PIN
+#define AO_ADC_PIN4_PORT AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN6_PORT AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN6_PIN AO_ADC_V_BATT_PIN
+#define AO_ADC_PIN7_PORT AO_ADC_V_PBATT_PORT
+#define AO_ADC_PIN7_PIN AO_ADC_V_PBATT_PIN
+
+#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 3)
+
+#define AO_ADC_SQ1 AO_ADC_SENSE_A
+#define AO_ADC_SQ2 AO_ADC_SENSE_B
+#define AO_ADC_SQ3 AO_ADC_SENSE_C
+#define AO_ADC_SQ4 AO_ADC_SENSE_D
+#define AO_ADC_SQ5 AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6 AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ7 AO_ADC_V_BATT
+#define AO_ADC_SQ8 AO_ADC_V_PBATT
+#define AO_ADC_SQ9 AO_ADC_TEMP
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS 56 /* 5.6k */
+#define AO_BATTERY_DIV_MINUS 100 /* 10k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS 100 /* 100k */
+#define AO_IGNITE_DIV_MINUS 27 /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV 33
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT (&stm_gpioc)
+#define AO_MS5607_CS_PIN 4
+#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS)
+#define AO_MS5607_MISO_PORT (&stm_gpioa)
+#define AO_MS5607_MISO_PIN 6
+#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO)
+#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT (&stm_gpiod)
+#define AO_M25_SPI_CS_MASK (1 << 10)
+#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio (cc1200)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT 5695733
+
+#define AO_FEC_DEBUG 0
+#define AO_CC1200_SPI_CS_PORT (&stm_gpioc)
+#define AO_CC1200_SPI_CS_PIN 5
+#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1200_SPI stm_spi2
+
+#define AO_CC1200_INT_PORT (&stm_gpiob)
+#define AO_CC1200_INT_PIN 11
+
+#define AO_CC1200_INT_GPIO 2
+#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2
+
+#define AO_CC1200_MARC_GPIO 3
+#define AO_CC1200_MARC_GPIO_IOCFG CC1200_IOCFG3
+
+#define HAS_BOOT_RADIO 0
+
+
+/*
+ *
+ * If the board is laying component side up with
+ * the antenna (nose) pointing north
+ *
+ * +along north +roll left up
+ * +across west +pitch nose down
+ * +through up +yaw left turn
+ */
+
+/*
+ * mpu6000
+ *
+ * pin 1 NW corner of chip
+ *
+ * +along +Y +roll +Y
+ * +across -X +pitch -X
+ * +through +Z +yaw +Z
+ *
+ */
+
+#define HAS_MPU6000 1
+#define AO_MPU6000_INT_PORT (&stm_gpioe)
+#define AO_MPU6000_INT_PIN 0
+#define AO_MPU6000_SPI_BUS AO_SPI_1_PE13_PE14_PE15
+#define AO_MPU6000_SPI_CS_PORT (&stm_gpioc)
+#define AO_MPU6000_SPI_CS_PIN 13
+#define HAS_IMU 1
+
+#define ao_mpu6000_along(m) ((m)->accel_y)
+#define ao_mpu6000_across(m) (-(m)->accel_x)
+#define ao_mpu6000_through(m) ((m)->accel_z)
+
+#define ao_mpu6000_roll(m) ((m)->gyro_y)
+#define ao_mpu6000_pitch(m) (-(m)->gyro_x)
+#define ao_mpu6000_yaw(m) ((m)->gyro_z)
+
+#define ao_data_along(packet) ao_mpu6000_along(&(packet)->mpu6000)
+#define ao_data_across(packet) ao_mpu6000_across(&(packet)->mpu6000)
+#define ao_data_through(packet) ao_mpu6000_through(&(packet)->mpu6000)
+
+#define ao_data_roll(packet) ao_mpu6000_roll(&(packet)->mpu6000)
+#define ao_data_pitch(packet) ao_mpu6000_pitch(&(packet)->mpu6000)
+#define ao_data_yaw(packet) ao_mpu6000_yaw(&(packet)->mpu6000)
+
+/* Bit-banging i2c */
+#define AO_I2C_SCL_PORT (&stm_gpiod)
+#define AO_I2C_SCL_PIN 1
+#define AO_I2C_SDA_PORT (&stm_gpiod)
+#define AO_I2C_SDA_PIN 4
+
+/*
+ * MMC5983
+ *
+ * pin 1 NE corner of chip
+ *
+ * +along -Y
+ * +across +X
+ * +through -Z
+ */
+
+#define HAS_MMC5983 1
+#define AO_MMC5983_INT_PORT (&stm_gpiod)
+#define AO_MMC5983_INT_PIN 5
+#define AO_MMC5983_SPI_CLK_PORT (&stm_gpiod)
+#define AO_MMC5983_SPI_CLK_PIN 1
+#define AO_MMC5983_SPI_MISO_PORT (&stm_gpiod)
+#define AO_MMC5983_SPI_MISO_PIN 3
+#define AO_MMC5983_SPI_MOSI_PORT (&stm_gpiod)
+#define AO_MMC5983_SPI_MOSI_PIN 4
+#define AO_MMC5983_SPI_INDEX (AO_SPI_2_PD1_PD3_PD4 | AO_SPI_MODE_3)
+#define AO_MMC5983_SPI_CS_PORT (&stm_gpioa)
+#define AO_MMC5983_SPI_CS_PIN 15
+
+#define ao_mmc5983_along(m) (-(m)->y)
+#define ao_mmc5983_across(m) ((m)->x)
+#define ao_mmc5983_through(m) (-(m)->z)
+
+#define ao_data_mag_along(packet) ao_mmc5983_along(&(packet)->mmc5983)
+#define ao_data_mag_across(packet) ao_mmc5983_across(&(packet)->mmc5983)
+#define ao_data_mag_through(packet) ao_mmc5983_through(&(packet)->mmc5983)
+
+/*
+ * ADXL375
+ *
+ * pin 1 NW corner of chip
+ *
+ * +along +X
+ * +across +Y
+ * +through +Z
+ */
+
+#define HAS_ADXL375 1
+#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
+#define AO_ADXL375_CS_PORT (&stm_gpioc)
+#define AO_ADXL375_CS_PIN 0
+
+#define AO_ADXL375_AXIS x
+#define AO_ADXL375_INVERT 1
+
+#define NUM_CMDS 16
+
+/*
+ * Companion
+ */
+
+#define AO_COMPANION_CS_PORT (&stm_gpiob)
+#define AO_COMPANION_CS_PIN_0 (6)
+#define AO_COMPANION_CS_PIN AO_COMPANION_CS_PIN_0
+#define AO_COMPANION_CS_PIN_1 (7)
+#define AO_COMPANION_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * 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
+
+/*
+ * PWM output
+ */
+
+#define NUM_PWM 4
+#define PWM_MAX 20000
+#define AO_PWM_TIMER stm_tim4
+#define AO_PWM_TIMER_ENABLE STM_RCC_APB1ENR_TIM4EN
+#define AO_PWM_TIMER_SCALE 32
+
+#define AO_PWM_0_GPIO (&stm_gpiod)
+#define AO_PWM_0_PIN 12
+
+#define AO_PWM_1_GPIO (&stm_gpiod)
+#define AO_PWM_1_PIN 13
+
+#define AO_PWM_2_GPIO (&stm_gpiod)
+#define AO_PWM_2_PIN 15
+
+#define AO_PWM_3_GPIO (&stm_gpiod)
+#define AO_PWM_3_PIN 14
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2021 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_mpu6000.h>
+#include <ao_mmc5983.h>
+#include <ao_adxl375.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_profile.h>
+#include <ao_eeprom.h>
+#include <ao_i2c_bit.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#include <ao_pyro.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+#include <ao_pwm.h>
+
+int
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+
+ ao_task_init();
+ ao_serial_init();
+ ao_led_init();
+ ao_led_on(LEDS_AVAILABLE);
+ ao_timer_init();
+
+ ao_spi_init();
+#ifdef MMC5983_I2C
+ ao_i2c_bit_init();
+#endif
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_adc_init();
+#if HAS_BEEP
+ ao_beep_init();
+#endif
+ ao_cmd_init();
+
+ ao_ms5607_init();
+ ao_mpu6000_init();
+ ao_mmc5983_init();
+ ao_adxl375_init();
+
+ ao_eeprom_init();
+ ao_storage_init();
+
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+
+ ao_usb_init();
+ ao_gps_init();
+ ao_gps_report_mega_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(false);
+ ao_igniter_init();
+ ao_companion_init();
+ ao_pyro_init();
+
+ ao_config_init();
+#if AO_PROFILE
+ ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+ ao_sample_profile_init();
+#endif
+
+ ao_pwm_init();
+
+ ao_led_off(LEDS_AVAILABLE);
+
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemega-v5.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2021 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 16MHz */
+#define AO_HSE 16000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PB6 */
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpiob
+#define AO_BOOT_APPLICATION_PIN 6
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+Beeper moved to tim11
+servo lines swapped
+ADC inputs scrambled
+pyro circuits scrambled
+mag sensor on SPI2 pd1/pd3/pd4
FATJAR=telegps-fat.jar
if MULTI_ARCH
-LIBALTOS_LINUX=libaltos32.so libaltos64.so
+LIBALTOS_LINUX=libaltos_i686.so libaltos_amd64.so libaltos_aarch64.so libaltos_armel.so libaltos_armhf.so
else
LIBALTOS_LINUX=libaltos.so
endif
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-libaltos32.so: build-libaltos
+libaltos_i686.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-libaltos64.so: build-libaltos
+libaltos_amd64.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_aarch64.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_armel.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos_armhf.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
-altos.dll: ../libaltos/altos.dll
+altos.dll: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
-altos64.dll: ../libaltos/altos64.dll
+altos64.dll: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
-../libaltos/.libs/libaltos64.so: ../libaltos/.libs/libaltos32.so
-
-../libaltos/.libs/libaltos32.so: build-libaltos
-
-../libaltos/.libs/libaltos.so: build-libaltos
-
-../libaltos/altos.dll: build-altos-dll
-
-../libaltos/altos64.dll: build-altos64-dll
-
build-libaltos:
- +cd ../libaltos && make libaltos.la
-build-altos-dll:
- +cd ../libaltos && make altos.dll
-
-build-altos64-dll:
- +cd ../libaltos && make altos64.dll
+ +cd ../libaltos && make
$(ALTOSLIB_CLASS):
-rm -f "$@"