/* * Copyright (c) 2013, Will Szumski * Copyright (c) 2013, Doug Szumski * * This file is part of Cyclismo. * * Cyclismo 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 3 of the License, or * (at your option) any later version. * * Cyclismo 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 Cyclismo. If not, see <http://www.gnu.org/licenses/>. */ import org.cowboycoders.ant.AntError; import org.cowboycoders.ant.Channel; import org.cowboycoders.ant.NetworkKeys; import org.cowboycoders.ant.Node; import org.cowboycoders.ant.Receipt; import org.cowboycoders.ant.TransferException; import org.cowboycoders.ant.events.BroadcastListener; import org.cowboycoders.ant.events.MessageCondition; import org.cowboycoders.ant.events.MessageConditionFactory; import org.cowboycoders.ant.interfaces.AntTransceiver; import org.cowboycoders.ant.messages.ChannelMessage; import org.cowboycoders.ant.messages.MasterChannelType; import org.cowboycoders.ant.messages.SlaveChannelType; import org.cowboycoders.ant.messages.StandardMessage; import org.cowboycoders.ant.messages.commands.ChannelRequestMessage; import org.cowboycoders.ant.messages.commands.ResetMessage; import org.cowboycoders.ant.messages.data.BroadcastDataMessage; import org.cowboycoders.ant.messages.responses.CapabilityResponse; import org.cowboycoders.ant.utils.ByteUtils; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; public class AntTransceiverTest { private static AntTransceiver antchip = new AntTransceiver(0); @BeforeClass public static void beforeClass() { AntTransceiver.LOGGER.setLevel(Level.ALL); ConsoleHandler handler = new ConsoleHandler(); handler.setLevel(Level.ALL); AntTransceiver.LOGGER.addHandler(handler); } @AfterClass public static void afterClass() { antchip.stop(); } @Before public void before() throws InterruptedException { //Thread.sleep(1000); } //@Test public void functionality_runthrough() throws InterruptedException { AntTransceiver ant = new AntTransceiver(0); ant.start(); StandardMessage msg = new ResetMessage(); //StandardMessage msg = new BroadcastDataMessage(); ant.send(msg.encode()); msg = new ChannelRequestMessage( 0, ChannelRequestMessage.Request.CAPABILITIES); ant.send(msg.encode()); int i = 0; //while (++i < 10) { // msg = new ChannelRequestMessage( // 0,ChannelRequestMessage.Request.CAPABILITIES ); // ant.send(msg.encode()); // } Thread.sleep(10000); ant.stop(); } //@Test public void basic_node() throws InterruptedException, TimeoutException { AntTransceiver ant = antchip; ant.start(); StandardMessage msg = new ResetMessage(); //ant.send(msg.encode()); //ant.send(msg.encode()); //ant.send(msg.encode()); //Thread.sleep(1000); Node n = new Node(ant); n.start(); //n.reset(); MessageCondition condition = new MessageCondition() { @Override public boolean test(StandardMessage msg) { return true; } }; Receipt receipt = new Receipt(); n.sendAndWaitForMessage(msg, condition, null, null, null, receipt); System.out.println(receipt.getLastSent().getTimestamp()); System.out.println(receipt.getLastReceived().getTimestamp()); Thread.sleep(1000); n.stop(); } //@Test public void test_init() throws InterruptedException, TimeoutException { //Object mBound = bindService(new Intent(MainActivity.getAppContext(), DummyService.class)); //antchip.start(); Node n = new Node(antchip); //antchip.stop(); //Thread.sleep(1000); //EventMachine em = new EventMachine(antchip); //em.start(); try { n.start(); //Thread.sleep(1000); } finally { try { //n.stop(); } catch (AntError e) { } } //Thread.sleep(3000); // try expose a race condition or dead lock int i = 0; while (++i < 1000 ) { StandardMessage capabilitiesMessage = new ChannelRequestMessage( 0, ChannelRequestMessage.Request.CAPABILITIES); StandardMessage capabilitiesResponse; MessageCondition condition = MessageConditionFactory.newInstanceOfCondition (CapabilityResponse.class); try { capabilitiesResponse = n.sendAndWaitForMessage( capabilitiesMessage, condition, 10L, TimeUnit.SECONDS, null, null ); System.out.println(((CapabilityResponse) capabilitiesResponse).getMaxNetworks()); } catch (InterruptedException e) { throw new AntError(e); } catch (TimeoutException e) { throw new AntError(e); } //Thread.sleep(100); } //Thread.sleep(10000); n.stop(); } public static boolean arrayStartsWith(Byte[] pattern, Byte[] data) { for (int i = 0; i < pattern.length; i++) { if (data[i] != pattern[i]) { return false; } } return true; } public static Byte[] iA2bA(int[] intArray) { Byte[] byteArray = new Byte[intArray.length]; for (int i = 0; i < intArray.length; i++) { byteArray[i] = (byte) intArray[i]; } return byteArray; } class BushidoData { //TODO cleanup this bodge boolean initState = true; ArrayList<Double> speedArray = new ArrayList<Double>(); ArrayList<Double> powerArray = new ArrayList<Double>(); ArrayList<Double> cadenceArray = new ArrayList<Double>(); ArrayList<Double> distanceArray = new ArrayList<Double>(); ArrayList<Double> heartRateArray = new ArrayList<Double>(); ArrayList<Double> slopeArray = new ArrayList<Double>(); public void logSpeed(double speed) { speedArray.add(speed); } public void logPower(double power) { powerArray.add(power); } public void logCadence(double cadence) { cadenceArray.add(cadence); } public void logDistance(double distance) { distanceArray.add(distance); } public void logHeartRate(double heartRate) { heartRateArray.add(heartRate); } private void logSlope(double slope) { slopeArray.add(slope); } public double getSlope() { return slopeArray.get(slopeArray.size() - 1); } public double getDistance() { return distanceArray.get(distanceArray.size() - 1); } public Byte[] setSlope(double slope) { logSlope(slope); //DC01 Packet prototype Byte[] dc01Packet = {(byte) 0xdc, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00}; if (slope < 0) { dc01Packet[3] = (byte) 0xFF; dc01Packet[4] = (byte) (256 + slope * 10); } else { dc01Packet[4] = (byte) (slope * 10); } return dc01Packet; } public Byte[] keepAlive() { Byte[] dc02Packet = {(byte) 0xdc, 0x02, 0x00, (byte) 0x99, 0x00, 0x00, 0x00, 0x00}; return dc02Packet; } public Byte[] getByte() { if (initState) { initState = false; return setSlope(getSlope()); } else { initState = true; return keepAlive(); } } } //@Test public void testCompare() { int[] packet = {0xad, 0x01, 0x03, 0x0a, 0x00, 0x00, 0x0a, 0x02}; int[] pattern = {0xad, 0x01, 0x03}; assertTrue(arrayStartsWith(iA2bA(pattern), iA2bA(packet))); } class Listener implements BroadcastListener<BroadcastDataMessage> { Byte[] data; double speed; double power; double cadence; double distance; double heartRate; Byte[] payload = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // Packet identifiers Byte[] bushidoPaused = {(byte) 0xAD, 0x01, 0x03, 0x0a, 0x00, 0x00, 0x0a, 0x02}; Byte[] bushidoLogging = {(byte) 0xAD, 0x01, 0x02}; Byte[] bushidoDataIdentifier = {(byte) 0xDD}; Byte[] bushidoSPCidentifier = {(byte) 0x01}; Byte[] bushidoDHidentifier = {(byte) 0x02}; Byte[] bushidoStatusIdentifier = {(byte) 0xAD}; Byte[] bushidoResume = {(byte) 0xAC, 0x03, 0x02}; @Override public void receiveMessage(BroadcastDataMessage message) { data = message.getData(); if (arrayStartsWith(bushidoDataIdentifier, data)) { data = message.getData(); if (arrayStartsWith(bushidoSPCidentifier, data)) { speed = ((data[2] << 8) + data[3]) / 16.1; power = (data[4] << 8) + data[5]; cadence = data[6]; System.out.println("Speed: " + speed); System.out.println("Power: " + power); System.out.println("Cadence: " + cadence); } if (arrayStartsWith(bushidoDHidentifier, data)) { distance = (data[2] << 24) + (data[3] << 16) + (data[4] << 8) + data[5]; heartRate = data[6]; System.out.println("Distance: " + distance); System.out.println("Heart rate: " + heartRate); } } else if (arrayStartsWith(bushidoStatusIdentifier, data)) { if (arrayStartsWith(bushidoPaused, data)) { //Send un-pause command payload = bushidoResume; System.out.println("Bushido Paused"); } else if (arrayStartsWith(bushidoLogging, data)) { //Send keepalive //payload = bushidoData.getByte() } } } } @Test public void test_hrm() throws InterruptedException, TimeoutException { int repeats = 10; Node n = new Node(antchip); n.start(); n.reset(); Channel c; assertNotNull(c = n.getFreeChannel()); c.setName("C:BUSHIDO"); SlaveChannelType channelType = new SlaveChannelType(); c.assign(NetworkKeys.ANT_SPORT, channelType); c.registerRxListener(new Listener(), BroadcastDataMessage.class); c.setId(0x52, 0, 0, false); c.setFrequency(60); c.setPeriod(4096); c.setSearchTimeout(255); c.open(); Thread.sleep(10000); c.close(); c.unassign(); n.freeChannel(c); n.stop(); } ExecutorService ex = Executors.newSingleThreadExecutor(); class Sender extends Thread { Channel c; Sender(Channel c) { this.c = c; } @Override public void run() { ex.execute(new Runnable() { @Override public void run() { BroadcastDataMessage msg = new BroadcastDataMessage(); msg.setData(new byte[]{(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, 0x00, 0x00, 0x00, 0x00}); MessageCondition condition = MessageConditionFactory.newResponseCondition(null, null); try { c.sendAndWaitForMessage(msg, condition, 10L, TimeUnit.SECONDS, null); } catch (InterruptedException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } }); } public void send(ChannelMessage msg) { MessageCondition condition = MessageConditionFactory.newResponseCondition(null, null); try { c.sendAndWaitForMessage(msg, condition, 10L, TimeUnit.SECONDS, null); } catch (InterruptedException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } } int count = 0; Object lock = new Object(); //@Test public void test_master() throws InterruptedException, TimeoutException { int repeats = 10; Node n = new Node(antchip); //NetworkKey key = new NetworkKey(0xB9,0xA5,0x21,0xFB,0xBD,0x72,0xC3,0x45); //key.setName("N:ANT+"); n.start(); n.reset(); // n.setNetworkKey(0, key); Channel c; assertNotNull(c = n.getFreeChannel()); c.setName("C:HRM"); MasterChannelType channelType = new MasterChannelType(); c.assign(NetworkKeys.ANT_SPORT, channelType); c.setId(33, 1, 1, false); c.setFrequency(66); c.setPeriod(8192); c.setSearchTimeout(255); c.open(); Sender s = new Sender(c); for (int i = 0; i < repeats; i++) { BroadcastDataMessage msg = new BroadcastDataMessage(); List<Byte> bytes = ByteUtils.lsbSplit(i, 4); msg.setData(new byte[]{(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, bytes.get(0), bytes.get(1), bytes.get(2), bytes.get(3)}); MessageCondition condition = MessageConditionFactory.newResponseCondition(null, null); //c.enqueue(msg, condition, null, null); } //ex.awaitTermination(10, TimeUnit.SECONDS); Thread.sleep(5000); int length = 255; byte[] test = new byte[length]; for (int i = 0; i < length; i++) { test[i] = (byte) i; } try { c.sendBurst(test, 10L, TimeUnit.SECONDS); System.out.println("transfer completed"); } catch (TransferException e) { System.out.println(e); } Thread.sleep(10000); c.close(); c.unassign(); n.freeChannel(c); n.stop(); } }