/* This file is part of Wattzap Community Edition. * * Wattzap Community Edtion 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. * * Wattzap Community Edition 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 Wattzap. If not, see <http://www.gnu.org/licenses/>. */ package com.wattzap.model.ant; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.cowboycoders.ant.messages.data.BroadcastDataMessage; import com.wattzap.controller.MessageBus; import com.wattzap.controller.Messages; import com.wattzap.model.UserPreferences; import com.wattzap.model.dto.Telemetry; /** * (c) 2013-2015 David George / Wattzap.com * * Speed and Cadence ANT+ processor. * * @author David George * @date 11 June 2013 */ public class AdvancedSpeedCadenceListener extends AntListener { public static final String name = "C:SC"; private static final int ANT_SPORT_SandC_TYPE = 121; // 0x79 private static final int ANT_SPORT_SPEED_PERIOD = 8086; private final static Logger logger = LogManager.getLogger("ASCL"); private final SpeedListener speedListener; private final CadenceListener cadenceListener; public AdvancedSpeedCadenceListener() { if (UserPreferences.INSTANCE.getPowerId() == 0) { // if power is selected don't register a speed listener, use power meter instead speedListener = new SpeedListener(); } else { speedListener = null; } cadenceListener = new CadenceListener(); } /** * Speed and cadence data is contained in the 8 byte data payload in the * message. Speed and Cadence have the same format. A short integer giving * time since the last reading and a short integer giving the number of * revolutions since the last reading. * <p> * The format is:<br/> * [0][1] - Cadence timing<br/> * [2][3] - Cadence revolutions<br/> * [4][5] - Speed timing<br/> * [6][7] - Speed revolutions<br/> * <p> * Values are little Endian (MSB byte is on the right) * <p> * So for timing: [0] + ([1] << 8) / 1024 gives the time in milliseconds * since the last rollover. Note that you have to account for rollovers of * both time and rotations which happen every 16 seconds/16384 revolutions. * <p> * There is another wrinkle. Messages are sent at at 4Hz rate. Below a * certain rate (240rpm) we will see messages with the same number of * rotations. This doesn't mean the wheel is stopped, just there was no new * data since the last reading. To distinguish this from a stopped wheel a * certain number of same value readings are ignored for speed or cadence * updates. * * FIX: convert distance to meters */ @Override public void receiveMessage(BroadcastDataMessage message) { int[] data = message.getUnsignedData(); // Bytes 0 and 1: TTTT / 1024 = milliSeconds since the last // rollover for cadence int tC = data[0] + (data[1] << 8); // Bytes 2 and 3: Cadence rotation Count int cR = data[2] + (data[3] << 8); // Bytes 4 and 5: TTTT / 1024 = milliSeconds since the last // rollover for speed int tS = data[4] | (data[5] << 8); // Bytes 6 and 7: speed rotation count. int sR = data[6] | (data[7] << 8); logger.debug("tC " + tC + " cR " + cR + " tS " + tS + " sR " + sR); if (speedListener != null) { Telemetry t = speedListener.getTelemetry(tS, sR); if (t != null) { MessageBus.INSTANCE.send(Messages.SPEED, t); } } int cadence = cadenceListener.getCadence(tC, cR); if (cadence < 0 || cadence > 250) { return; // bogus value } MessageBus.INSTANCE.send(Messages.CADENCE, cadence); } @Override public int getChannelId() { return UserPreferences.INSTANCE.getSCId(); } @Override public int getChannelPeriod() { return ANT_SPORT_SPEED_PERIOD; } @Override public int getDeviceType() { return ANT_SPORT_SandC_TYPE; } @Override public String getName() { return name; } }