<item android:id="@+id/connect_scan"
android:icon="@android:drawable/ic_menu_search"
android:title="@string/connect_device" />
+ <item android:id="@+id/disconnect"
+ android:icon="@android:drawable/ic_notification_clear_all"
+ android:title="@string/disconnect_device" />
<item android:id="@+id/quit"
android:icon="@android:drawable/ic_menu_close_clear_cancel"
android:title="@string/quit" />
<!-- Options Menu -->
<string name="connect_device">Connect a device</string>
+ <string name="disconnect_device">Disconnect device</string>
<string name="quit">Quit</string>
<string name="select_freq">Select radio frequency</string>
<string name="select_rate">Select data rate</string>
}
+ private void connected() {
+ try {
+ synchronized(this) {
+ if (socket != null) {
+ input = socket.getInputStream();
+ output = socket.getOutputStream();
+
+ input_thread = new Thread(this);
+ input_thread.start();
+
+ // Configure the newly connected device for telemetry
+ print("~\nE 0\n");
+ set_monitor(false);
+ if (D) Log.d(TAG, "ConnectThread: connected");
+
+ /* Let TelemetryService know we're connected
+ */
+ handler.obtainMessage(TelemetryService.MSG_CONNECTED).sendToTarget();
+
+ /* Notify other waiting threads that we're connected now
+ */
+ notifyAll();
+ }
+ }
+ } catch (IOException io) {
+ connect_failed();
+ }
+ }
+
+ private void connect_failed() {
+ synchronized (this) {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException e2) {
+ if (D) Log.e(TAG, "ConnectThread: Failed to close() socket after failed connection");
+ }
+ socket = null;
+ }
+ input = null;
+ output = null;
+ handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED).sendToTarget();
+ if (D) Log.e(TAG, "ConnectThread: Failed to establish connection");
+ }
+ }
+
+ private Object closing_lock = new Object();
+ private boolean closing = false;
+
+ private void disconnected() {
+ synchronized(closing_lock) {
+ if (D) Log.e(TAG, String.format("Connection lost during I/O. Closing %b", closing));
+ if (!closing) {
+ if (D) Log.d(TAG, "Sending disconnected message");
+ handler.obtainMessage(TelemetryService.MSG_DISCONNECTED).sendToTarget();
+ }
+ }
+ }
+
private class ConnectThread extends Thread {
private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery();
- synchronized (AltosBluetooth.this) {
- // Make a connection to the BluetoothSocket
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- socket.connect();
+ BluetoothSocket local_socket;
- input = socket.getInputStream();
- output = socket.getOutputStream();
- } catch (IOException e) {
- // Close the socket
- try {
- socket.close();
- } catch (IOException e2) {
- if (D) Log.e(TAG, "ConnectThread: Failed to close() socket after failed connection");
- }
- input = null;
- output = null;
- AltosBluetooth.this.notifyAll();
- handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED).sendToTarget();
- if (D) Log.e(TAG, "ConnectThread: Failed to establish connection");
- return;
+ try {
+ synchronized (AltosBluetooth.this) {
+ local_socket = socket;
}
- input_thread = new Thread(AltosBluetooth.this);
- input_thread.start();
-
- // Configure the newly connected device for telemetry
- print("~\nE 0\n");
- set_monitor(false);
+ if (local_socket != null) {
+ // Make a connection to the BluetoothSocket
+ // This is a blocking call and will only return on a
+ // successful connection or an exception
+ local_socket.connect();
+ }
- // Let TelemetryService know we're connected
- handler.obtainMessage(TelemetryService.MSG_CONNECTED).sendToTarget();
+ connected();
- // Notify other waiting threads, now that we're connected
- AltosBluetooth.this.notifyAll();
+ } catch (IOException e) {
+ connect_failed();
+ }
- // Reset the ConnectThread because we're done
+ synchronized (AltosBluetooth.this) {
+ /* Reset the ConnectThread because we're done
+ */
connect_thread = null;
-
- if (D) Log.d(TAG, "ConnectThread: Connect completed");
}
+ if (D) Log.d(TAG, "ConnectThread: Connect completed");
}
public void cancel() {
try {
- if (socket != null)
- socket.close();
+ BluetoothSocket local_socket;
+ synchronized(AltosBluetooth.this) {
+ local_socket = socket;
+ socket = null;
+ }
+ if (local_socket != null)
+ local_socket.close();
+
} catch (IOException e) {
if (D) Log.e(TAG, "ConnectThread: close() of connect socket failed", e);
}
}
private synchronized void wait_connected() throws InterruptedException, IOException {
- if (input == null) {
+ if (input == null && socket != null) {
if (D) Log.d(TAG, "wait_connected...");
wait();
if (D) Log.d(TAG, "wait_connected done");
- if (input == null) throw new IOException();
}
- }
-
- private void connection_lost() {
- if (D) Log.e(TAG, "Connection lost during I/O");
- handler.obtainMessage(TelemetryService.MSG_DISCONNECTED).sendToTarget();
+ if (socket == null)
+ throw new IOException();
}
public void print(String data) {
output.write(bytes);
if (D) Log.d(TAG, "print(): Wrote bytes: '" + data.replace('\n', '\\') + "'");
} catch (IOException e) {
- connection_lost();
+ disconnected();
} catch (InterruptedException e) {
- connection_lost();
+ disconnected();
}
}
output.write(bytes);
if (D) Log.d(TAG, "print(): Wrote byte: '" + c + "'");
} catch (IOException e) {
- connection_lost();
+ disconnected();
} catch (InterruptedException e) {
- connection_lost();
+ disconnected();
}
}
buffer_len = input.read(buffer);
buffer_off = 0;
} catch (IOException e) {
- connection_lost();
+ if (D) Log.d(TAG, "getchar IOException");
+ disconnected();
return AltosLink.ERROR;
} catch (java.lang.InterruptedException e) {
- connection_lost();
+ if (D) Log.d(TAG, "getchar Interrupted");
+ disconnected();
return AltosLink.ERROR;
}
}
return buffer[buffer_off++];
}
+ public void closing() {
+ synchronized(closing_lock) {
+ if (D) Log.d(TAG, "Marked closing true");
+ closing = true;
+ }
+ }
+
+
public void close() {
if (D) Log.d(TAG, "close(): begin");
+
+ closing();
+
synchronized(this) {
if (D) Log.d(TAG, "close(): synched");
- if (connect_thread != null) {
- if (D) Log.d(TAG, "close(): stopping connect_thread");
- connect_thread.cancel();
- connect_thread = null;
- }
- if (D) Log.d(TAG, "close(): Closing socket");
- try {
- socket.close();
- } catch (IOException e) {
- if (D) Log.e(TAG, "close(): unable to close() socket");
+ if (socket != null) {
+ if (D) Log.d(TAG, "close(): Closing socket");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ if (D) Log.e(TAG, "close(): unable to close() socket");
+ }
+ socket = null;
}
+ connect_thread = null;
if (input_thread != null) {
if (D) Log.d(TAG, "close(): stopping input_thread");
try {
}
break;
case TelemetryState.CONNECT_CONNECTING:
- mTitle.setText(R.string.title_connecting);
+ if (telemetry_state.address != null)
+ mTitle.setText(String.format("Connecting to %s...", telemetry_state.address.name));
+ else
+ mTitle.setText("Connecting to something...");
break;
- case TelemetryState.CONNECT_READY:
+ case TelemetryState.CONNECT_DISCONNECTED:
case TelemetryState.CONNECT_NONE:
mTitle.setText(R.string.title_not_connected);
break;
update_ui(telemetry_state.state, telemetry_state.location);
if (telemetry_state.connect == TelemetryState.CONNECT_CONNECTED)
start_timer();
- else
- stop_timer();
}
boolean same_string(String a, String b) {
void update_ui(AltosState state, Location location) {
- Log.d(TAG, "update_ui");
-
int prev_state = AltosLib.ao_flight_invalid;
AltosGreatCircle from_receiver = null;
prev_state = saved_state.state;
if (state != null) {
- Log.d(TAG, String.format("prev state %d new state %d\n", prev_state, state.state));
if (state.state == AltosLib.ao_flight_stateless) {
boolean prev_locked = false;
boolean locked = false;
} else {
if (prev_state != state.state) {
String currentTab = mTabHost.getCurrentTabTag();
- Log.d(TAG, "switch state");
switch (state.state) {
case AltosLib.ao_flight_boost:
if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("ascent");
}
if (saved_state == null || !same_string(saved_state.callsign, state.callsign)) {
- Log.d(TAG, "update callsign");
mCallsignView.setText(state.callsign);
}
if (saved_state == null || state.serial != saved_state.serial) {
- Log.d(TAG, "update serial");
mSerialView.setText(String.format("%d", state.serial));
}
if (saved_state == null || state.flight != saved_state.flight) {
- Log.d(TAG, "update flight");
if (state.flight == AltosLib.MISSING)
mFlightView.setText("");
else
mFlightView.setText(String.format("%d", state.flight));
}
if (saved_state == null || state.state != saved_state.state) {
- Log.d(TAG, "update state");
if (state.state == AltosLib.ao_flight_stateless) {
mStateLayout.setVisibility(View.GONE);
} else {
}
}
if (saved_state == null || state.rssi != saved_state.rssi) {
- Log.d(TAG, "update rssi");
mRSSIView.setText(String.format("%d", state.rssi));
}
}
for (AltosDroidTab mTab : mTabs)
mTab.update_ui(state, from_receiver, location, mTab == mTabsAdapter.currentItem());
- if (state != null)
+ if (state != null && mAltosVoice != null)
mAltosVoice.tell(state, from_receiver);
saved_state = state;
mStateLayout = (RelativeLayout) findViewById(R.id.state_container);
mStateView = (TextView) findViewById(R.id.state_value);
mAgeView = (TextView) findViewById(R.id.age_value);
-
- mAltosVoice = new AltosVoice(this);
}
@Override
doBindService();
+ if (mAltosVoice == null)
+ mAltosVoice = new AltosVoice(this);
}
@Override
- public synchronized void onResume() {
+ public void onResume() {
super.onResume();
if(D) Log.e(TAG, "+ ON RESUME +");
}
@Override
- public synchronized void onPause() {
+ public void onPause() {
super.onPause();
if(D) Log.e(TAG, "- ON PAUSE -");
}
if(D) Log.e(TAG, "-- ON STOP --");
doUnbindService();
+ if (mAltosVoice != null) {
+ mAltosVoice.stop();
+ mAltosVoice = null;
+ }
}
@Override
}
}
- private void connectDevice(String address) {
+ private void connectDevice(Intent data) {
// Attempt to connect to the device
try {
- if (D) Log.d(TAG, "Connecting to " + address);
- mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, address));
+ String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
+ String name = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_NAME);
+
+ if (D) Log.d(TAG, "Connecting to " + address + name);
+ DeviceAddress a = new DeviceAddress(address, name);
+ mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, a));
} catch (RemoteException e) {
}
}
- private void connectDevice(Intent data) {
- // Get the device MAC address
- String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
- connectDevice(address);
+ private void disconnectDevice() {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_DISCONNECT, null));
+ } catch (RemoteException e) {
+ }
}
@Override
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
return true;
+ case R.id.disconnect:
+ /* Disconnect the bluetooth device
+ */
+ disconnectDevice();
+ return true;
case R.id.quit:
Log.d(TAG, "R.id.quit");
- stopService(new Intent(AltosDroid.this, TelemetryService.class));
+ disconnectDevice();
finish();
return true;
case R.id.select_freq:
public class AltosDroidPreferences extends AltosPreferences {
/* Active device preference name */
- final static String activeDevicePreference = "ACTIVE-DEVICE";
+ final static String activeDeviceAddressPreference = "ACTIVE-DEVICE-ADDRESS";
+ final static String activeDeviceNamePreference = "ACTIVE-DEVICE-NAME";
- static String active_device_address;
+ static DeviceAddress active_device_address;
public static void init(Context context) {
if (backend != null)
AltosPreferences.init(new AltosDroidPreferencesBackend(context));
- active_device_address = backend.getString(activeDevicePreference, null);
+ String address = backend.getString(activeDeviceAddressPreference, null);
+ String name = backend.getString(activeDeviceNamePreference, null);
+
+ if (address != null && name != null)
+ active_device_address = new DeviceAddress (address, name);
}
- public static void set_active_device(String address) {
+ public static void set_active_device(DeviceAddress address) {
synchronized(backend) {
active_device_address = address;
- backend.putString(activeDevicePreference, active_device_address);
+ backend.putString(activeDeviceAddressPreference, active_device_address.address);
+ backend.putString(activeDeviceNamePreference, active_device_address.name);
flush_preferences();
}
}
- public static String active_device() {
+ public static DeviceAddress active_device() {
synchronized(backend) {
return active_device_address;
}
ft.show(this);
} else
ft.hide(this);
- ft.commit();
+ ft.commitAllowingStateLoss();
}
public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver, boolean is_current) {
last_state = state;
last_from_receiver = from_receiver;
last_receiver = receiver;
- if (is_current) {
- if (AltosDroid.D) Log.d(AltosDroid.TAG, String.format("%s: visible, performing update", tab_name()));
-
+ if (is_current)
show(state, from_receiver, receiver);
- } else {
- if (AltosDroid.D) Log.d(AltosDroid.TAG, String.format("%s: not visible, skipping update", tab_name()));
+ else
return;
- }
}
}
--- /dev/null
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+public class DeviceAddress {
+ public String address;
+ public String name;
+
+ public DeviceAddress(String address, String name) {
+ this.address = address;
+ this.name = name;
+ }
+}
private static final boolean D = true;
// Return Intent extra
- public static String EXTRA_DEVICE_ADDRESS = "device_address";
+ public static final String EXTRA_DEVICE_ADDRESS = "device_address";
+ public static final String EXTRA_DEVICE_NAME = "device_name";
// Member fields
private BluetoothAdapter mBtAdapter;
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
+ int newline = info.indexOf('\n');
+
+ String name = null;
+ if (newline > 0)
+ name = info.substring(0, newline);
+ else
+ name = info;
+
+ if (D) Log.d(TAG, String.format("******* selected item '%s'", info));
+
// Create the result Intent and include the MAC address
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
+ intent.putExtra(EXTRA_DEVICE_NAME, name);
// Set result and finish this Activity
setResult(Activity.RESULT_OK, intent);
static final int MSG_SETFREQUENCY = 8;
static final int MSG_CRC_ERROR = 9;
static final int MSG_SETBAUD = 10;
+ static final int MSG_DISCONNECT = 11;
// Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it.
private int NOTIFICATION = R.string.telemetry_service_label;
//private NotificationManager mNM;
- // Timer - we wake up every now and then to decide if the service should stop
- private Timer timer = new Timer();
-
- ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
- final Handler mHandler = new IncomingHandler(this);
- final Messenger mMessenger = new Messenger(mHandler); // Target we publish for clients to send messages to IncomingHandler.
+ ArrayList<Messenger> clients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
+ final Handler handler = new IncomingHandler(this);
+ final Messenger messenger = new Messenger(handler); // Target we publish for clients to send messages to IncomingHandler.
// Name of the connected device
- String address;
- private AltosBluetooth mAltosBluetooth = null;
- private TelemetryReader mTelemetryReader = null;
- private TelemetryLogger mTelemetryLogger = null;
- // Local Bluetooth adapter
- private BluetoothAdapter mBluetoothAdapter = null;
+ DeviceAddress address;
+ private AltosBluetooth altos_bluetooth = null;
+ private TelemetryReader telemetry_reader = null;
+ private TelemetryLogger telemetry_logger = null;
- private TelemetryState telemetry_state;
+ // Local Bluetooth adapter
+ private BluetoothAdapter bluetooth_adapter = null;
// Last data seen; send to UI when it starts
+ private TelemetryState telemetry_state;
// Handler of incoming messages from clients.
static class IncomingHandler extends Handler {
if (s == null)
return;
switch (msg.what) {
+
+ /* Messages from application */
case MSG_REGISTER_CLIENT:
- s.mClients.add(msg.replyTo);
- try {
- // Now we try to send the freshly connected UI any relavant information about what
- // we're talking to
- msg.replyTo.send(s.message());
- } catch (RemoteException e) {
- s.mClients.remove(msg.replyTo);
- }
- if (D) Log.d(TAG, "Client bound to service");
+ s.add_client(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
- s.mClients.remove(msg.replyTo);
- if (D) Log.d(TAG, "Client unbound from service");
+ s.remove_client(msg.replyTo);
break;
case MSG_CONNECT:
if (D) Log.d(TAG, "Connect command received");
- String address = (String) msg.obj;
+ DeviceAddress address = (DeviceAddress) msg.obj;
AltosDroidPreferences.set_active_device(address);
- s.startAltosBluetooth(address);
+ s.start_altos_bluetooth(address);
+ break;
+ case MSG_DISCONNECT:
+ if (D) Log.d(TAG, "Disconnect command received");
+ s.address = null;
+ s.stop_altos_bluetooth(true);
+ break;
+ case MSG_SETFREQUENCY:
+ if (D) Log.d(TAG, "MSG_SETFREQUENCY");
+ s.telemetry_state.frequency = (Double) msg.obj;
+ if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
+ try {
+ s.altos_bluetooth.set_radio_frequency(s.telemetry_state.frequency);
+ s.altos_bluetooth.save_frequency();
+ } catch (InterruptedException e) {
+ } catch (TimeoutException e) {
+ }
+ }
+ s.send_to_clients();
break;
+ case MSG_SETBAUD:
+ if (D) Log.d(TAG, "MSG_SETBAUD");
+ s.telemetry_state.telemetry_rate = (Integer) msg.obj;
+ if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
+ s.altos_bluetooth.set_telemetry_rate(s.telemetry_state.telemetry_rate);
+ s.altos_bluetooth.save_telemetry_rate();
+ }
+ s.send_to_clients();
+ break;
+
+ /*
+ *Messages from AltosBluetooth
+ */
case MSG_CONNECTED:
if (D) Log.d(TAG, "Connected to device");
try {
}
break;
case MSG_CONNECT_FAILED:
- if (D) Log.d(TAG, "Connection failed... retrying");
- if (s.address != null)
- s.startAltosBluetooth(s.address);
+ if (s.address != null) {
+ if (D) Log.d(TAG, "Connection failed... retrying");
+ s.start_altos_bluetooth(s.address);
+ } else {
+ s.stop_altos_bluetooth(true);
+ }
break;
case MSG_DISCONNECTED:
Log.d(TAG, "MSG_DISCONNECTED");
- s.stopAltosBluetooth();
+ if (s.address != null) {
+ if (D) Log.d(TAG, "Connection lost... retrying");
+ s.start_altos_bluetooth(s.address);
+ } else {
+ s.stop_altos_bluetooth(true);
+ }
break;
+
+ /*
+ * Messages from TelemetryReader
+ */
case MSG_TELEMETRY:
- // forward telemetry messages
s.telemetry_state.state = (AltosState) msg.obj;
if (s.telemetry_state.state != null) {
if (D) Log.d(TAG, "Save state");
AltosPreferences.set_state(0, s.telemetry_state.state, null);
}
if (D) Log.d(TAG, "MSG_TELEMETRY");
- s.sendMessageToClients();
+ s.send_to_clients();
break;
case MSG_CRC_ERROR:
// forward crc error messages
s.telemetry_state.crc_errors = (Integer) msg.obj;
if (D) Log.d(TAG, "MSG_CRC_ERROR");
- s.sendMessageToClients();
- break;
- case MSG_SETFREQUENCY:
- if (D) Log.d(TAG, "MSG_SETFREQUENCY");
- s.telemetry_state.frequency = (Double) msg.obj;
- if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
- try {
- s.mAltosBluetooth.set_radio_frequency(s.telemetry_state.frequency);
- s.mAltosBluetooth.save_frequency();
- } catch (InterruptedException e) {
- } catch (TimeoutException e) {
- }
- }
- s.sendMessageToClients();
- break;
- case MSG_SETBAUD:
- if (D) Log.d(TAG, "MSG_SETBAUD");
- s.telemetry_state.telemetry_rate = (Integer) msg.obj;
- if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
- s.mAltosBluetooth.set_telemetry_rate(s.telemetry_state.telemetry_rate);
- s.mAltosBluetooth.save_telemetry_rate();
- }
- s.sendMessageToClients();
+ s.send_to_clients();
break;
default:
super.handleMessage(msg);
}
}
+ /* Construct the message to deliver to clients
+ */
private Message message() {
if (telemetry_state == null)
Log.d(TAG, "telemetry_state null!");
return Message.obtain(null, AltosDroid.MSG_STATE, telemetry_state);
}
- private void sendMessageToClients() {
- Message m = message();
- if (D) Log.d(TAG, String.format("Send message to %d clients", mClients.size()));
- for (int i=mClients.size()-1; i>=0; i--) {
- try {
- if (D) Log.d(TAG, String.format("Send message to client %d", i));
- mClients.get(i).send(m);
- } catch (RemoteException e) {
- mClients.remove(i);
- }
+ /* A new friend has connected
+ */
+ private void add_client(Messenger client) {
+
+ clients.add(client);
+ if (D) Log.d(TAG, "Client bound to service");
+
+ /* On connect, send the current state to the new client
+ */
+ send_to_client(client, message());
+
+ /* If we've got an address from a previous session, then
+ * go ahead and try to reconnect to the device
+ */
+ if (address != null && telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED) {
+ if (D) Log.d(TAG, "Reconnecting now...");
+ start_altos_bluetooth(address);
+ }
+ }
+
+ /* A client has disconnected, clean up
+ */
+ private void remove_client(Messenger client) {
+ clients.remove(client);
+ if (D) Log.d(TAG, "Client unbound from service");
+
+ /* When the list of clients is empty, stop the service if
+ * we have no current telemetry source
+ */
+
+ if (clients.isEmpty() && telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED) {
+ if (!D) Log.d(TAG, "No clients, no connection. Stopping\n");
+ stopSelf();
+ }
+ }
+
+ private void send_to_client(Messenger client, Message m) {
+ try {
+ if (D) Log.d(TAG, String.format("Send message to client %s", client.toString()));
+ client.send(m);
+ } catch (RemoteException e) {
+ if (D) Log.e(TAG, String.format("Client %s disappeared", client.toString()));
+ remove_client(client);
}
}
- private void stopAltosBluetooth() {
- if (D) Log.d(TAG, "stopAltosBluetooth(): begin");
- telemetry_state.connect = TelemetryState.CONNECT_READY;
- if (mTelemetryReader != null) {
- if (D) Log.d(TAG, "stopAltosBluetooth(): stopping TelemetryReader");
- mTelemetryReader.interrupt();
+ private void send_to_clients() {
+ Message m = message();
+ if (D) Log.d(TAG, String.format("Send message to %d clients", clients.size()));
+ for (Messenger client : clients)
+ send_to_client(client, m);
+ }
+
+ private void stop_altos_bluetooth(boolean notify) {
+ if (D) Log.d(TAG, "stop_altos_bluetooth(): begin");
+ telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;
+ telemetry_state.address = null;
+
+ if (altos_bluetooth != null)
+ altos_bluetooth.closing();
+
+ if (telemetry_reader != null) {
+ if (D) Log.d(TAG, "stop_altos_bluetooth(): stopping TelemetryReader");
+ telemetry_reader.interrupt();
try {
- mTelemetryReader.join();
+ telemetry_reader.join();
} catch (InterruptedException e) {
}
- mTelemetryReader = null;
+ telemetry_reader = null;
}
- if (mTelemetryLogger != null) {
- if (D) Log.d(TAG, "stopAltosBluetooth(): stopping TelemetryLogger");
- mTelemetryLogger.stop();
- mTelemetryLogger = null;
+ if (telemetry_logger != null) {
+ if (D) Log.d(TAG, "stop_altos_bluetooth(): stopping TelemetryLogger");
+ telemetry_logger.stop();
+ telemetry_logger = null;
}
- if (mAltosBluetooth != null) {
- if (D) Log.d(TAG, "stopAltosBluetooth(): stopping AltosBluetooth");
- mAltosBluetooth.close();
- mAltosBluetooth = null;
+ if (altos_bluetooth != null) {
+ if (D) Log.d(TAG, "stop_altos_bluetooth(): stopping AltosBluetooth");
+ altos_bluetooth.close();
+ altos_bluetooth = null;
}
telemetry_state.config = null;
- if (D) Log.d(TAG, "stopAltosBluetooth(): send message to clients");
- sendMessageToClients();
+ if (notify) {
+ if (D) Log.d(TAG, "stop_altos_bluetooth(): send message to clients");
+ send_to_clients();
+ if (clients.isEmpty()) {
+ if (D) Log.d(TAG, "stop_altos_bluetooth(): no clients, terminating");
+ stopSelf();
+ }
+ }
}
- private void startAltosBluetooth(String address) {
+ private void start_altos_bluetooth(DeviceAddress address) {
// Get the BLuetoothDevice object
- BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
+ BluetoothDevice device = bluetooth_adapter.getRemoteDevice(address.address);
+ stop_altos_bluetooth(false);
this.address = address;
- if (mAltosBluetooth == null) {
- if (D) Log.d(TAG, String.format("startAltosBluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress()));
- mAltosBluetooth = new AltosBluetooth(device, mHandler);
- telemetry_state.connect = TelemetryState.CONNECT_CONNECTING;
- sendMessageToClients();
- } else {
- // This is a bit of a hack - if it appears we're still connected, we treat this as a restart.
- // So, to give a suitable delay to teardown/bringup, we just schedule a resend of a message
- // to ourselves in a few seconds time that will ultimately call this method again.
- // ... then we tear down the existing connection.
- // We do it this way around so that we don't lose a reference to the device when this method
- // is called on reception of MSG_CONNECT_FAILED in the handler above.
- mHandler.sendMessageDelayed(Message.obtain(null, MSG_CONNECT, address), 3000);
- stopAltosBluetooth();
- }
+ if (D) Log.d(TAG, String.format("start_altos_bluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress()));
+ altos_bluetooth = new AltosBluetooth(device, handler);
+ telemetry_state.connect = TelemetryState.CONNECT_CONNECTING;
+ telemetry_state.address = address;
+ send_to_clients();
}
private void connected() throws InterruptedException {
if (D) Log.d(TAG, "connected top");
try {
- if (mAltosBluetooth == null)
+ if (altos_bluetooth == null)
throw new InterruptedException("no bluetooth");
- telemetry_state.config = mAltosBluetooth.config_data();
- mAltosBluetooth.set_radio_frequency(telemetry_state.frequency);
- mAltosBluetooth.set_telemetry_rate(telemetry_state.telemetry_rate);
+ telemetry_state.config = altos_bluetooth.config_data();
+ altos_bluetooth.set_radio_frequency(telemetry_state.frequency);
+ altos_bluetooth.set_telemetry_rate(telemetry_state.telemetry_rate);
} catch (TimeoutException e) {
// If this timed out, then we really want to retry it, but
// probably safer to just retry the connection from scratch.
- mHandler.obtainMessage(MSG_CONNECT_FAILED).sendToTarget();
+ handler.obtainMessage(MSG_CONNECT_FAILED).sendToTarget();
return;
}
if (D) Log.d(TAG, "connected bluetooth configured");
telemetry_state.connect = TelemetryState.CONNECT_CONNECTED;
+ telemetry_state.address = address;
- mTelemetryReader = new TelemetryReader(mAltosBluetooth, mHandler, telemetry_state.state);
- mTelemetryReader.start();
+ telemetry_reader = new TelemetryReader(altos_bluetooth, handler, telemetry_state.state);
+ telemetry_reader.start();
if (D) Log.d(TAG, "connected TelemetryReader started");
- mTelemetryLogger = new TelemetryLogger(this, mAltosBluetooth);
+ telemetry_logger = new TelemetryLogger(this, altos_bluetooth);
if (D) Log.d(TAG, "Notify UI of connection");
- sendMessageToClients();
- }
-
- private void onTimerTick() {
- if (D) Log.d(TAG, "Timer wakeup");
- try {
- if (mClients.size() <= 0 && telemetry_state.connect != TelemetryState.CONNECT_CONNECTED) {
- stopSelf();
- }
- } catch (Throwable t) {
- Log.e(TAG, "Timer failed: ", t);
- }
+ send_to_clients();
}
@Override
public void onCreate() {
// Get local Bluetooth adapter
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ bluetooth_adapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
- if (mBluetoothAdapter == null) {
+ if (bluetooth_adapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
}
// Create a reference to the NotificationManager so that we can update our notifcation text later
//mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- telemetry_state.connect = TelemetryState.CONNECT_READY;
+ telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;
+ telemetry_state.address = null;
AltosSavedState saved_state = AltosPreferences.state(0);
telemetry_state.state = saved_state.state;
}
- // Start our timer - first event in 10 seconds, then every 10 seconds after that.
- timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 10000L, 10000L);
-
// Listen for GPS and Network position updates
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
- String address = AltosDroidPreferences.active_device();
+ DeviceAddress address = AltosDroidPreferences.active_device();
if (address != null)
- startAltosBluetooth(address);
+ start_altos_bluetooth(address);
}
@Override
((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
// Stop the bluetooth Comms threads
- stopAltosBluetooth();
+ stop_altos_bluetooth(true);
// Demote us from the foreground, and cancel the persistent notification.
stopForeground(true);
- // Stop our timer
- if (timer != null) {timer.cancel();}
-
// Tell the user we stopped.
Toast.makeText(this, R.string.telemetry_service_stopped, Toast.LENGTH_SHORT).show();
}
@Override
public IBinder onBind(Intent intent) {
- return mMessenger.getBinder();
+ return messenger.getBinder();
}
public void onLocationChanged(Location location) {
telemetry_state.location = location;
if (D) Log.d(TAG, "location changed");
- sendMessageToClients();
+ send_to_clients();
}
public void onStatusChanged(String provider, int status, Bundle extras) {
import android.location.Location;
public class TelemetryState {
- public static final int CONNECT_NONE = 0;
- public static final int CONNECT_READY = 1;
- public static final int CONNECT_CONNECTING = 2;
- public static final int CONNECT_CONNECTED = 3;
+ public static final int CONNECT_NONE = 0;
+ public static final int CONNECT_DISCONNECTED = 1;
+ public static final int CONNECT_CONNECTING = 2;
+ public static final int CONNECT_CONNECTED = 3;
int connect;
+ DeviceAddress address;
AltosConfigData config;
AltosState state;
Location location;
LinkedBlockingQueue<String> command_queue;
- LinkedBlockingQueue<String> reply_queue;
-
class Igniter {
JRadioButton button;
JLabel status_label;
}
reply = "status";
} else if (command.equals("get_npyro")) {
- put_reply(String.format("%d", ignite.npyro()));
- continue;
+ reply = String.format("npyro %d", ignite.npyro());
} else if (command.equals("quit")) {
ignite.close();
break;
set_ignite_status();
} else if (reply.equals("fired")) {
fired();
+ } else if (reply.startsWith("npyro")) {
+ npyro = Integer.parseInt(reply.substring(6));
+ make_ui();
}
}
}
}
- void put_reply(String reply) {
- try {
- reply_queue.put(reply);
- } catch (Exception ex) {
- ignite_exception(ex);
- }
- }
-
- String get_reply() {
- String reply = "";
- try {
- reply = reply_queue.take();
- } catch (Exception ex) {
- ignite_exception(ex);
- }
- return reply;
- }
-
boolean getting_status = false;
boolean visible = false;
}
}
- int get_npyro() {
- send_command("get_npyro");
- String reply = get_reply();
- return Integer.parseInt(reply);
- }
-
boolean firing = false;
void start_fire(String which) {
void close() {
if (opened) {
send_command("quit");
- timer.stop();
}
+ if (timer != null)
+ timer.stop();
setVisible(false);
dispose();
}
private boolean open() {
command_queue = new LinkedBlockingQueue<String>();
- reply_queue = new LinkedBlockingQueue<String>();
opened = false;
device = AltosDeviceUIDialog.show(owner, Altos.product_any);
return false;
}
- public AltosIgniteUI(JFrame in_owner) {
-
- owner = in_owner;
-
- if (!open())
- return;
-
+ private void make_ui() {
group = new ButtonGroup();
Container pane = getContentPane();
timer_running = false;
timer.restart();
- owner = in_owner;
-
pane.setLayout(new GridBagLayout());
c.fill = GridBagConstraints.NONE;
y++;
- int npyro = get_npyro();
-
igniters = new Igniter[2 + npyro];
igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
addWindowListener(new ConfigListener(this));
}
-}
\ No newline at end of file
+
+ public AltosIgniteUI(JFrame in_owner) {
+
+ owner = in_owner;
+
+ if (!open())
+ return;
+
+ send_command("get_npyro");
+ }
+}
// Flash controller
AltosProgrammer programmer;
- private static String[] pair_programmed = {
+ private static final String[] pair_programmed_files = {
"teleballoon",
"telebt-v1",
"teledongle-v0",
"teleterra"
};
+ private static final String[] pair_programmed_devices = {
+ "TeleBalloon",
+ "TeleBT-v1",
+ "TeleDongle-v0",
+ "TeleFire",
+ "TeleMetrum-v0",
+ "TeleMetrum-v1",
+ "TeleMini",
+ "TeleNano",
+ "TeleShield",
+ "TeleTerra"
+ };
+
private boolean is_pair_programmed() {
if (file != null) {
String name = file.getName();
- for (int i = 0; i < pair_programmed.length; i++) {
- if (name.startsWith(pair_programmed[i]))
+ for (int i = 0; i < pair_programmed_files.length; i++) {
+ if (name.startsWith(pair_programmed_files[i]))
return true;
}
}
if (device != null) {
- if (!device.matchProduct(AltosLib.product_altusmetrum) &&
- (device.matchProduct(AltosLib.product_teledongle) ||
- device.matchProduct(AltosLib.product_telebt)))
- return true;
+ String name = device.toString();
+ for (int i = 0; i < pair_programmed_devices.length; i++) {
+ if (name.startsWith(pair_programmed_devices[i]))
+ return true;
+ }
}
return false;
}
#!/bin/sh
-# serial number of the TeleDongle being used as the flash programmer
-DONGLE=612
-
if [ -x ../ao-tools/ao-load/ao-load ]; then
AOLOAD=../ao-tools/ao-load/ao-load
elif [ -x /usr/bin/ao-load ]; then
echo $RAWLOAD
+case $USER in
+ bdale)
+ DONGLE=100
+ ;;
+ keithp)
+ DONGLE=186
+ ;;
+ *)
+ echo "Unknow user"
+ exit 1
+ ;;
+esac
+
$RAWLOAD -D $DONGLE -r ao_led_blink.ihx
echo "LEDs should be blinking"
sleep 5
CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
echo "Programming flash with cal value " $CAL_VALUE
-$AOLOAD -D $DONGLE --cal $CAL_VALUE /usr/share/altos/telebt-v1.0*.ihx $SERIAL
+$AOLOAD -D $DONGLE --cal $CAL_VALUE ~/altusmetrumllc/Binaries/telebt-v1.0*.ihx $SERIAL
echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
echo $SERIAL","$CAL_VALUE >> cal_values
exit 1
fi
-echo "TeleMini v1.0 Turn-On and Calibration Program"
+VERSION=1.0
+
+echo "TeleMini v$VERSION Turn-On and Calibration Program"
echo "Copyright 2011 by Bdale Garbee. Released under GPL v2"
echo
echo "Expectations:"
-echo "\tTeleMini v1.0 powered from LiPo"
+echo "\tTeleMini v$VERSION powered from LiPo"
echo "\t\twith TeleDongle (on /dev/ttyACM0) cabled to debug header"
echo "\t\twith frequency counter able to sample RF output"
echo
echo $RAWLOAD
-$RAWLOAD -D 100 -r ao_led_blink.ihx
+case $USER in
+ bdale)
+ programmer=100
+ ;;
+ keithp)
+ programmer=186
+ ;;
+esac
+
+$RAWLOAD -D $programmer -r ao_led_blink.ihx
echo "LEDs should be blinking"
sleep 5
-$RAWLOAD -D 100 -r ao_radio_xmit.ihx
+$RAWLOAD -D $programmer -r ao_radio_xmit.ihx
echo -n "Generating RF carrier. Please enter measured frequency: "
read FREQ
CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
echo "Programming flash with cal value " $CAL_VALUE
-$AOLOAD -D 100 --cal $CAL_VALUE /usr/share/altos/stable/telemini-v1.0*.ihx $SERIAL
+$AOLOAD -D $programmer --cal $CAL_VALUE ~/altusmetrumllc/Binaries/telemini-v$VERSION-*.ihx $SERIAL
echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
echo "Unplug and replug USB, cu to the board, confirm freq and record power"
.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
.\"
.\"
-.TH AO-LOAD 1 "ao-usbtrng" ""
+.TH AO-USBTRNG 1 "ao-usbtrng" ""
.SH NAME
ao-usbtrng \- dump random numbers from USBtrng
.SH SYNOPSIS
-.B "ao-usbtrng"
-[\-T \fItty-device\fP]
-[\--tty \fItty-device\fP]
-[\-D \fIaltos-device\fP]
-[\--device \fIaltos-device\fP]
-\fIkbytes\fP
+.B "ao-usbtrng" [OPTION...] [KBYTES]
.SH DESCRIPTION
.I ao-usbtrng
-dumps random numbers from a USBtrng device
+dumps random numbers from a USBtrng device. If provided KBYTES specifies the number of 1024 byte blocks to produce on standard output. Without KBYTES
+.I ao-usbtrng
+produces random bytes continuously until killed.
.SH OPTIONS
.TP
-\-T tty-device | --tty tty-device
+\-v, --verbose
+increase verbosity
+.TP
+\-T, -tty=TTYDEVICE
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.TP
-\-D AltOS-device | --device AltOS-device
+\-D, --device=ALTOSDEVICE
Search for a connected device. This requires an argument of one of the
following forms:
.IP
one of the available devices.
.SH USAGE
.I ao-usbtrng
-opens the target device and reads the specified number of kbytes of
+opens the target device and reads the specified number of KBYTES of
random data.
.SH AUTHOR
Keith Packard
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
- { .name = "raw", .has_arg = 0, .val = 'r' },
- { .name = "verbose", .has_arg = 1, .val = 'v' },
+ { .name = "verbose", .has_arg = 0, .val = 'v' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
- fprintf(stderr, "usage: %s [--verbose=<verbose>] [--device=<device>] [-tty=<tty>] <kbytes>\n", program);
+ fprintf(stderr, "usage: %s [--verbose] [--device=<AltOS-device>] [-tty=<tty>] [<kbytes>]\n", program);
exit(1);
}
{
char *device = NULL;
char *filename;
- Elf *e;
- unsigned int s;
int i;
int c;
- int tries;
struct cc_usb *cc = NULL;
char *tty = NULL;
- int success;
int verbose = 0;
int ret = 0;
- int expected_size;
- int kbytes;
+ int kbytes = 0; /* 0 == continuous */
+ int written;
uint8_t bits[1024];
- while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "vT:D:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
}
}
- if (!argv[optind])
- usage(argv[0]);
-
- kbytes = atoi(argv[optind]);
- if (kbytes < 1)
- kbytes = 1;
+ if (optind < argc)
+ kbytes = atoi(argv[optind]);
ao_verbose = verbose;
if (!cc)
exit(1);
- cc_usb_printf(cc, "f %d\n", kbytes);
+ if (kbytes) {
+ cc_usb_printf(cc, "f %d\n", kbytes);
- while (kbytes--) {
- int i;
- for (i = 0; i < 1024; i++)
- bits[i] = cc_usb_getchar(cc);
- write(1, bits, 1024);
+ while (kbytes--) {
+ for (i = 0; i < 1024; i++)
+ bits[i] = cc_usb_getchar(cc);
+ write(1, bits, 1024);
+ }
+ } else { /* 0 == continuous */
+ written = 0;
+ while (written >= 0) {
+ cc_usb_printf(cc, "f 1\n");
+ for (i = 0; i < 1024; i++)
+ bits[i] = cc_usb_getchar(cc);
+ written = write(1, bits, 1024);
+ }
}
done(cc, ret);
ao_button_init(void);
char
-ao_button_get(void) __critical;
+ao_button_get(uint16_t timeout) __critical;
void
ao_button_clear(void) __critical;
}
char
-ao_button_get(void) __critical
+ao_button_get(uint16_t timeout) __critical
{
char b;
while (ao_fifo_empty(ao_button_fifo))
- if (ao_sleep(&ao_button_fifo))
+ if (ao_sleep_for(&ao_button_fifo, timeout))
return 0;
ao_fifo_remove(ao_button_fifo, b);
return b;
/* Wait for DMA to be done, for the radio receive process to
* get aborted or for a receive timeout to fire
*/
- if (timeout)
- ao_alarm(timeout);
__critical while (!ao_radio_dma_done && !ao_radio_abort)
- if (ao_sleep(&ao_radio_dma_done))
+ if (ao_sleep_for(&ao_radio_dma_done, timeout))
break;
- if (timeout)
- ao_clear_alarm();
/* If recv was aborted, clean up by stopping the DMA engine
* and idling the radio
#ifndef ao_serial_btm_getchar
#define ao_serial_btm_putchar ao_serial1_putchar
#define _ao_serial_btm_pollchar _ao_serial1_pollchar
-#define _ao_serial_btm_sleep() ao_sleep((void *) &ao_serial1_rx_fifo)
+#define _ao_serial_btm_sleep_for(timeout) ao_sleep_for((void *) &ao_serial1_rx_fifo, timeout)
#define ao_serial_btm_set_speed ao_serial1_set_speed
#define ao_serial_btm_drain ao_serial1_drain
#endif
while (ao_btm_enable) {
ao_arch_block_interrupts();
while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN && ao_btm_enable)
- _ao_serial_btm_sleep();
+ _ao_serial_btm_sleep_for(0);
ao_arch_release_interrupts();
if (c != AO_READ_AGAIN) {
putchar(c);
ao_arch_block_interrupts();
while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN) {
- ao_alarm(AO_MS_TO_TICKS(10));
- c = _ao_serial_btm_sleep();
- ao_clear_alarm();
+ c = _ao_serial_btm_sleep_for(AO_MS_TO_TICKS(10));
if (c) {
c = AO_READ_AGAIN;
break;
static void
ao_radio_wait_isr(uint16_t timeout)
{
- if (timeout)
- ao_alarm(timeout);
ao_arch_block_interrupts();
while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
- if (ao_sleep(&ao_radio_wake))
+ if (ao_sleep_for(&ao_radio_wake, timeout))
ao_radio_abort = 1;
ao_arch_release_interrupts();
- if (timeout)
- ao_clear_alarm();
if (ao_radio_mcu_wake)
ao_radio_check_marc_status();
}
static uint16_t
ao_radio_rx_wait(void)
{
- ao_alarm(AO_MS_TO_TICKS(100));
ao_arch_block_interrupts();
rx_waiting = 1;
while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
!ao_radio_abort &&
!ao_radio_mcu_wake)
{
- if (ao_sleep(&ao_radio_wake))
+ if (ao_sleep_for(&ao_radio_wake, AO_MS_TO_TICKS(100)))
ao_radio_abort = 1;
}
rx_waiting = 0;
ao_arch_release_interrupts();
- ao_clear_alarm();
if (ao_radio_abort || ao_radio_mcu_wake)
return 0;
rx_data_consumed += AO_FEC_DECODE_BLOCK;
ao_radio_strobe(CC1120_SRX);
- if (timeout)
- ao_alarm(timeout);
ao_arch_block_interrupts();
while (rx_starting && !ao_radio_abort) {
- if (ao_sleep(&ao_radio_wake))
+ if (ao_sleep_for(&ao_radio_wake, timeout))
ao_radio_abort = 1;
}
uint8_t rx_task_id_save = rx_task_id;
rx_task_id = 0;
rx_starting = 0;
ao_arch_release_interrupts();
- if (timeout)
- ao_clear_alarm();
if (ao_radio_abort) {
if (rx_task_id_save == 0)
static void
ao_radio_wait_isr(uint16_t timeout)
{
- if (timeout)
- ao_alarm(timeout);
-
ao_arch_block_interrupts();
while (!ao_radio_wake && !ao_radio_abort)
- if (ao_sleep(&ao_radio_wake))
+ if (ao_sleep_for(&ao_radio_wake, timeout))
ao_radio_abort = 1;
ao_arch_release_interrupts();
-
- if (timeout)
- ao_clear_alarm();
}
static void
#define CC1200_IF_MIX_CFG (CC1200_EXTENDED_BIT | 0x00)
#define CC1200_FREQOFF_CFG (CC1200_EXTENDED_BIT | 0x01)
#define CC1200_TOC_CFG (CC1200_EXTENDED_BIT | 0x02)
+
+#define CC1200_TOC_CFG_TOC_LIMIT 6
+#define CC1200_TOC_CFG_TOC_LIMIT_0_2 0
+#define CC1200_TOC_CFG_TOC_LIMIT_2 1
+#define CC1200_TOC_CFG_TOC_LIMIT_12 3
+
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN 3
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_8 0
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_16 1
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_32 2
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_64 3
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_128 4
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_256 5
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_8_16 0
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_6_16 1
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_2_16 2
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_1_16 3
+#define CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_1_16_SYNC 4
+
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN 0
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_8 0
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_16 1
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_32 2
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_64 3
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_128 4
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_256 5
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_FREEZE 0
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_6_32 1
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_2_32 2
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_1_32 3
+#define CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_1_32_SYNC 4
+
#define CC1200_MARC_SPARE (CC1200_EXTENDED_BIT | 0x03)
#define CC1200_ECG_CFG (CC1200_EXTENDED_BIT | 0x04)
#define CC1200_MDMCFG2 (CC1200_EXTENDED_BIT | 0x05)
(CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) |
(CC1200_MDMCFG2_UPSAMPLER_P_8 << CC1200_MDMCFG2_UPSAMPLER_P) |
(0 << CC1200_MDMCFG2_CFM_DATA_EN)),
+ CC1200_MDMCFG0, /* General Modem Parameter Configuration Reg. 0 */
+ ((0 << CC1200_MDMCFG0_TRANSPARENT_MODE_EN) |
+ (0 << CC1200_MDMCFG0_TRANSPARENT_INTFACT) |
+ (0 << CC1200_MDMCFG0_DATA_FILTER_EN) |
+ (1 << CC1200_MDMCFG0_VITERBI_EN)),
+ CC1200_TOC_CFG, /* Timing Offset Correction Configuration */
+ ((CC1200_TOC_CFG_TOC_LIMIT_2 << CC1200_TOC_CFG_TOC_LIMIT) |
+ (CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN_6_16 << CC1200_TOC_CFG_TOC_PRE_SYNC_BLOCKLEN)|
+ (CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN_2_32 << CC1200_TOC_CFG_TOC_POST_SYNC_BLOCKLEN)),
CC1200_FREQ2, 0x6c, /* Frequency Configuration [23:16] */
CC1200_FREQ1, 0xa3, /* Frequency Configuration [15:8] */
CC1200_FREQ0, 0x33, /* Frequency Configuration [7:0] */
break;
}
while (ao_companion_running) {
- ao_alarm(ao_companion_setup.update_period);
- if (ao_sleep(DATA_TO_XDATA(&ao_flight_state)))
+ if (ao_sleep_for(DATA_TO_XDATA(&ao_flight_state), ao_companion_setup.update_period))
ao_companion_get_data();
else
ao_companion_notify();
ao_exti_enable(AO_HMC5883_INT_PORT, AO_HMC5883_INT_PIN);
ao_hmc5883_reg_write(HMC5883_MODE, HMC5883_MODE_SINGLE);
- ao_alarm(AO_MS_TO_TICKS(10));
ao_arch_block_interrupts();
while (!ao_hmc5883_done)
- if (ao_sleep(&ao_hmc5883_done))
+ if (ao_sleep_for(&ao_hmc5883_done, AO_MS_TO_TICKS(10)))
++ao_hmc5883_missed_irq;
ao_arch_release_interrupts();
- ao_clear_alarm();
ao_hmc5883_read(HMC5883_X_MSB, (uint8_t *) sample, sizeof (struct ao_hmc5883_sample));
#if __BYTE_ORDER == __LITTLE_ENDIAN
}
uint8_t
-ao_packet_recv(void)
+ao_packet_recv(uint16_t timeout)
{
uint8_t dma_done;
#ifdef AO_LED_GREEN
ao_led_on(AO_LED_GREEN);
#endif
- dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv), 0);
+ dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv), timeout);
#ifdef AO_LED_GREEN
ao_led_off(AO_LED_GREEN);
#endif
if (ao_tx_packet.len)
ao_packet_master_busy();
ao_packet_master_check_busy();
- ao_alarm(AO_PACKET_MASTER_RECV_DELAY);
- r = ao_packet_recv();
- ao_clear_alarm();
+ r = ao_packet_recv(AO_PACKET_MASTER_RECV_DELAY);
if (r) {
/* if we can transmit data, do so */
if (ao_packet_tx_used && ao_tx_packet.len == 0)
if (ao_rx_packet.packet.len)
ao_packet_master_busy();
ao_packet_master_sleeping = 1;
- ao_alarm(ao_packet_master_delay);
- ao_sleep(&ao_packet_master_sleeping);
- ao_clear_alarm();
+ ao_sleep_for(&ao_packet_master_sleeping, ao_packet_master_delay);
ao_packet_master_sleeping = 0;
}
}
ao_tx_packet.len = AO_PACKET_SYN;
ao_packet_restart = 1;
while (ao_packet_enable) {
- if (ao_packet_recv()) {
+ if (ao_packet_recv(0)) {
ao_xmemcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
#if HAS_FLIGHT
ao_flight_force_idle = TRUE;
ao_packet_send(void);
uint8_t
-ao_packet_recv(void);
+ao_packet_recv(uint16_t timeout);
void
ao_packet_flush(void);
ao_sleep(&ao_flight_state);
for (;;) {
- ao_alarm(AO_MS_TO_TICKS(100));
- ao_sleep(&ao_pyro_wakeup);
- ao_clear_alarm();
+ ao_sleep_for(&ao_pyro_wakeup, AO_MS_TO_TICKS(100));
if (ao_flight_state >= ao_flight_landed)
break;
any_waiting = ao_pyro_check();
_ao_serial0_pollchar(void);
uint8_t
-_ao_serial0_sleep(void);
+_ao_serial0_sleep_for(uint16_t timeout);
void
ao_serial0_putchar(char c);
_ao_serial1_pollchar(void);
uint8_t
-_ao_serial1_sleep(void);
+_ao_serial1_sleep_for(uint16_t timeout);
void
ao_serial1_putchar(char c);
_ao_serial2_pollchar(void);
uint8_t
-_ao_serial2_sleep(void);
+_ao_serial2_sleep_for(uint16_t timeout);
void
ao_serial2_putchar(char c);
_ao_serial3_pollchar(void);
uint8_t
-_ao_serial3_sleep(void);
+_ao_serial3_sleep_for(uint16_t timeout);
void
ao_serial3_putchar(char c);
ao_check_stack();
}
-void
-ao_alarm(uint16_t delay)
+uint8_t
+ao_sleep_for(__xdata void *wchan, uint16_t timeout)
{
+ uint8_t ret;
+ if (timeout) {
#if HAS_TASK_QUEUE
- uint32_t flags;
- /* Make sure we sleep *at least* delay ticks, which means adding
- * one to account for the fact that we may be close to the next tick
- */
- flags = ao_arch_irqsave();
+ uint32_t flags;
+ /* Make sure we sleep *at least* delay ticks, which means adding
+ * one to account for the fact that we may be close to the next tick
+ */
+ flags = ao_arch_irqsave();
#endif
- if (!(ao_cur_task->alarm = ao_time() + delay + 1))
- ao_cur_task->alarm = 1;
+ if (!(ao_cur_task->alarm = ao_time() + timeout + 1))
+ ao_cur_task->alarm = 1;
#if HAS_TASK_QUEUE
- ao_task_to_alarm_queue(ao_cur_task);
- ao_arch_irqrestore(flags);
+ ao_task_to_alarm_queue(ao_cur_task);
+ ao_arch_irqrestore(flags);
#endif
-}
-
-void
-ao_clear_alarm(void)
-{
+ }
+ ret = ao_sleep(wchan);
+ if (timeout) {
#if HAS_TASK_QUEUE
- uint32_t flags;
+ uint32_t flags;
- flags = ao_arch_irqsave();
+ flags = ao_arch_irqsave();
#endif
- ao_cur_task->alarm = 0;
+ ao_cur_task->alarm = 0;
#if HAS_TASK_QUEUE
- ao_task_from_alarm_queue(ao_cur_task);
- ao_arch_irqrestore(flags);
+ ao_task_from_alarm_queue(ao_cur_task);
+ ao_arch_irqrestore(flags);
#endif
+ }
+ return ret;
}
static __xdata uint8_t ao_forever;
void
ao_delay(uint16_t ticks)
{
- ao_alarm(ticks);
- ao_sleep(&ao_forever);
- ao_clear_alarm();
+ ao_sleep_for(&ao_forever, ticks);
}
void
uint8_t
ao_sleep(__xdata void *wchan);
+/* Suspend the current task until wchan is awoken or the timeout
+ * expires. returns:
+ * 0 on normal wake
+ * 1 on alarm
+ */
+uint8_t
+ao_sleep_for(__xdata void *wchan, uint16_t timeout);
+
/* Wake all tasks sleeping on wchan */
void
ao_wakeup(__xdata void *wchan) __reentrant;
+#if 0
/* set an alarm to go off in 'delay' ticks */
void
ao_alarm(uint16_t delay);
/* Clear any pending alarm */
void
ao_clear_alarm(void);
+#endif
/* Yield the processor to another task */
void
#endif /* HAS_APRS */
delay = time - ao_time();
if (delay > 0) {
- ao_alarm(delay);
- ao_sleep(&telemetry);
- ao_clear_alarm();
+ ao_sleep_for(&telemetry, delay);
}
}
}
else
ao_terraui_page[ao_current_page]();
- ao_alarm(AO_SEC_TO_TICKS(1));
- b = ao_button_get();
- ao_clear_alarm();
+ b = ao_button_get(AO_SEC_TO_TICKS(1));
if (b > 0) {
ao_beep_for(AO_BEEP_HIGH, AO_MS_TO_TICKS(10));
if (!(stm_i2c->cr1 & (1 << STM_I2C_CR1_START)))
break;
}
- ao_alarm(AO_MS_TO_TICKS(250));
ao_arch_block_interrupts();
stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN);
ao_i2c_ev_isr(index);
while (ao_i2c_state[index] == I2C_IDLE)
- if (ao_sleep(&ao_i2c_state[index]))
+ if (ao_sleep_for(&ao_i2c_state[index], AO_MS_TO_TICKS(250)))
break;
ao_arch_release_interrupts();
- ao_clear_alarm();
return ao_i2c_state[index] == I2C_RUNNING;
}
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
ao_dma_start(tx_dma_index);
- ao_alarm(1 + len);
ao_arch_block_interrupts();
while (!ao_dma_done[tx_dma_index])
- if (ao_sleep(&ao_dma_done[tx_dma_index]))
+ if (ao_sleep_for(&ao_dma_done[tx_dma_index], 1 + len))
break;
- ao_clear_alarm();
ao_dma_done_transfer(tx_dma_index);
stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN);
while ((stm_i2c->sr1 & (1 << STM_I2C_SR1_BTF)) == 0)
- if (ao_sleep(&ao_i2c_state[index]))
+ if (ao_sleep_for(&ao_i2c_state[index], 1 + len))
break;
stm_i2c->cr2 = AO_STM_I2C_CR2;
ao_arch_release_interrupts();
if (stop)
stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP);
- ao_alarm(1);
ao_arch_block_interrupts();
while (ao_i2c_recv_len[index])
- if (ao_sleep(&ao_i2c_recv_len[index]))
+ if (ao_sleep_for(&ao_i2c_recv_len[index], 1))
break;
ao_arch_release_interrupts();
ret = ao_i2c_recv_len[index] == 0;
- ao_clear_alarm();
} else {
uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index;
ao_dma_set_transfer(rx_dma_index,
ao_i2c_wait_addr(index);
ao_dma_start(rx_dma_index);
- ao_alarm(len);
ao_arch_block_interrupts();
while (!ao_dma_done[rx_dma_index])
- if (ao_sleep(&ao_dma_done[rx_dma_index]))
+ if (ao_sleep_for(&ao_dma_done[rx_dma_index], len))
break;
ao_arch_release_interrupts();
- ao_clear_alarm();
ret = ao_dma_done[rx_dma_index];
ao_dma_done_transfer(rx_dma_index);
stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP);
}
static inline uint8_t
-_ao_usart_sleep(struct ao_stm_usart *usart)
+_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout)
{
- return ao_sleep(&usart->rx_fifo);
+ return ao_sleep_for(&usart->rx_fifo, timeout);
}
void
}
uint8_t
-_ao_serial1_sleep(void)
+_ao_serial1_sleep_for(uint16_t timeout)
{
- return _ao_usart_sleep(&ao_stm_usart1);
+ return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
}
void
}
uint8_t
-_ao_serial2_sleep(void)
+_ao_serial2_sleep_for(uint16_t timeout)
{
- return _ao_usart_sleep(&ao_stm_usart2);
+ return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
}
void
}
uint8_t
-_ao_serial3_sleep(void)
+_ao_serial3_sleep_for(uint16_t timeout)
{
- return _ao_usart_sleep(&ao_stm_usart3);
+ return _ao_usart_sleep_for(&ao_stm_usart3, timeout);
}
void
--- /dev/null
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_crc.h>
+
+#ifndef AO_CRC_WIDTH
+#error "Must define AO_CRC_WIDTH"
+#endif
+
+/* Only the STM32F07x and ST32F09x series have
+ * programmable CRC units. Others can only do the ANSI CRC-32 computation
+ */
+
+#if !AO_HAVE_PROGRAMMABLE_CRC_UNIT && AO_CRC_WIDTH != 32
+#error "Target hardware does not have programmable CRC unit"
+#endif
+
+#ifndef AO_CRC_POLY
+#if AO_CRC_WIDTH == 16
+#define AO_CRC_POLY AO_CRC_16_DEFAULT
+#endif
+#if AO_CRC_WIDTH == 32
+#define AO_CRC_POLY AO_CRC_32_DEFAULT
+#endif
+#endif
+
+#if !AO_HAVE_PROGRAMMABLE_CRC_UNIT && (AO_CRC_WIDTH != 32 || AO_CRC_POLY != AO_CRC_32_ANSI)
+#error "Target hardware does not have programmable CRC unit"
+#endif
+
+#if AO_CRC_WIDTH == 32
+#define AO_CRC_CR_POLYSIZE STM_CRC_CR_POLYSIZE_32
+#endif
+
+#if AO_CRC_WIDTH == 16
+#define AO_CRC_CR_POLYSIZE STM_CRC_CR_POLYSIZE_16
+#endif
+
+#if AO_CRC_WIDTH == 8
+#define AO_CRC_CR_POLYSIZE STM_CRC_CR_POLYSIZE_8
+#endif
+
+#if AO_CRC_WIDTH == 7
+#define AO_CRC_CR_POLYSIZE STM_CRC_CR_POLYSIZE_7
+#endif
+
+#ifndef AO_CRC_INIT
+#define AO_CRC_INIT 0xffffffff;
+#endif
+
+void
+ao_crc_reset(void)
+{
+ stm_crc.cr |= (1 << STM_CRC_CR_RESET);
+ while ((stm_crc.cr & (1 << STM_CRC_CR_RESET)) != 0)
+ ;
+}
+
+void
+ao_crc_init(void)
+{
+ /* Turn on the CRC clock */
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_CRCEN);
+
+ /* Need to initialize CR even on non-programmable hardware,
+ * the write to the POLYSIZE bits will be ignored in that
+ * case
+ */
+ stm_crc.cr = (AO_CRC_CR_POLYSIZE << STM_CRC_CR_POLYSIZE);
+ stm_crc.init = AO_CRC_INIT;
+#if AO_HAVE_PROGRAMMABLE_CRC_UNIT
+ stm_crc.pol = AO_CRC_POLY;
+#endif
+ ao_crc_reset();
+}
#define ao_serial_btm_getchar ao_serial2_getchar
#define ao_serial_btm_putchar ao_serial2_putchar
#define _ao_serial_btm_pollchar _ao_serial2_pollchar
-#define _ao_serial_btm_sleep _ao_serial2_sleep
+#define _ao_serial_btm_sleep_for _ao_serial2_sleep_for
#define ao_serial_btm_set_speed ao_serial2_set_speed
#define ao_serial_btm_drain ao_serial2_drain
#define ao_serial_btm_rx_fifo (ao_stm_usart2.rx_fifo)
uint16_t delay;
for (;;) {
-// ao_alarm(delay);
ao_sleep(&ao_pad_query);
-// ao_clear_alarm();
if (!ao_lco_valid) {
ao_led_on(AO_LED_RED);
ao_led_off(AO_LED_GREEN);
delay = AO_MS_TO_TICKS(100);
else
delay = AO_SEC_TO_TICKS(1);
- ao_alarm(delay);
- ao_sleep(&ao_lco_armed);
- ao_clear_alarm();
+ ao_sleep_for(&ao_lco_armed, delay);
}
}
delay = AO_MS_TO_TICKS(100);
else
delay = AO_SEC_TO_TICKS(1);
- ao_alarm(delay);
- ao_sleep(&ao_lco_armed);
- ao_clear_alarm();
+ ao_sleep_for(&ao_lco_armed, delay);
}
}