wangzhibo
4 天以前 ae6f40460dcd56af6c5f60ba52c883854c3bac55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*  Copyright (C) 2018-2024 José Rebelo
 
    This file is part of Gadgetbridge.
 
    Gadgetbridge is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    Gadgetbridge 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 Affero General Public License for more details.
 
    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFmFrequency;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventLEDColor;
import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.RoidmiConst;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
 
public class Roidmi1Protocol extends RoidmiProtocol {
    private static final Logger LOG = LoggerFactory.getLogger(Roidmi1Protocol.class);
 
    public Roidmi1Protocol(GBDevice device) {
        super(device);
    }
 
    private static final byte[] PACKET_HEADER = new byte[]{(byte) 0xaa, 0x55};
    private static final byte[] PACKET_TRAILER = new byte[]{(byte) 0xc3, 0x3c};
    private static final byte COMMAND_SET_FREQUENCY = 0x10;
    private static final byte COMMAND_GET_FREQUENCY = (byte) 0x80;
    private static final byte COMMAND_SET_COLOR = 0x11;
    private static final byte COMMAND_GET_COLOR = (byte) 0x81;
 
    private static final int PACKET_MIN_LENGTH = 6;
 
    private static final int LED_COLOR_RED = 1;
    private static final int LED_COLOR_GREEN = 2;
    private static final int LED_COLOR_BLUE = 3;
    private static final int LED_COLOR_YELLOW = 4; // not official
    private static final int LED_COLOR_SKY_BLUE = 5;
    private static final int LED_COLOR_PINK = 6; // not official
    private static final int LED_COLOR_WHITE = 7; // not official
    private static final int LED_COLOR_OFF = 8;
 
    // Other commands:
    // App periodically sends aa5502018588c33c and receives aa5506018515111804cec33c
    private static final byte[] COMMAND_PERIODIC = new byte[]{(byte) 0xaa, 0x55, 0x02, 0x01, (byte) 0x85, (byte) 0x88, (byte) 0xc3, 0x3c};
 
    @Override
    public GBDeviceEvent[] decodeResponse(final byte[] responseData) {
        if (responseData.length <= PACKET_MIN_LENGTH) {
            LOG.info("Response too small");
            return null;
        }
 
        for (int i = 0; i < packetHeader().length; i++) {
            if (responseData[i] != packetHeader()[i]) {
                LOG.info("Invalid response header");
                return null;
            }
        }
 
        for (int i = 0; i < packetTrailer().length; i++) {
            if (responseData[responseData.length - packetTrailer().length + i] != packetTrailer()[i]) {
                LOG.info("Invalid response trailer");
                return null;
            }
        }
 
        if (calcChecksum(responseData) != responseData[responseData.length - packetTrailer().length - 1]) {
            LOG.info("Invalid response checksum");
            return null;
        }
 
        switch (responseData[3]) {
            case COMMAND_GET_COLOR:
                final int color = responseData[5];
                LOG.debug("Got color: " + color);
                final GBDeviceEventLEDColor evColor = new GBDeviceEventLEDColor(RoidmiConst.COLOR_PRESETS[color - 1]);
                return new GBDeviceEvent[]{evColor};
            case COMMAND_GET_FREQUENCY:
                final String frequencyHex = GB.hexdump(responseData, 4, 2);
                final float frequency = Float.parseFloat(frequencyHex) / 10.0f;
                LOG.debug("Got frequency: " + frequency);
                final GBDeviceEventFmFrequency evFrequency = new GBDeviceEventFmFrequency(frequency);
                return new GBDeviceEvent[]{evFrequency};
            default:
                LOG.error("Unrecognized response type 0x" + GB.hexdump(responseData, packetHeader().length, 1));
                return null;
        }
    }
 
    @Override
    public byte[] encodeLedColor(final int color) {
        final int[] presets = RoidmiConst.COLOR_PRESETS;
        int color_id = -1;
        for (int i = 0; i < presets.length; i++) {
            if (presets[i] == color) {
                color_id = (i + 1) & 255;
                break;
            }
        }
 
        if (color_id < 0 || color_id > 8)
            throw new IllegalArgumentException("color must belong to RoidmiConst.COLOR_PRESETS");
 
        return encodeCommand(COMMAND_SET_COLOR, (byte) 0, (byte) color_id);
    }
 
    @Override
    public byte[] encodeFmFrequency(final float frequency) {
        if (frequency < 87.5 || frequency > 108.0)
            throw new IllegalArgumentException("Frequency must be >= 87.5 and <= 180.0");
 
        final byte[] freq = frequencyToBytes(frequency);
 
        return encodeCommand(COMMAND_SET_FREQUENCY, freq[0], freq[1]);
    }
 
    public byte[] encodeGetLedColor() {
        return encodeCommand(COMMAND_GET_COLOR, (byte) 0, (byte) 0);
    }
 
    public byte[] encodeGetFmFrequency() {
        return encodeCommand(COMMAND_GET_FREQUENCY, (byte) 0, (byte) 0);
    }
 
    public byte[] encodeGetVoltage() {
        return null;
    }
 
    public byte[] packetHeader() {
        return PACKET_HEADER;
    }
 
    public byte[] packetTrailer() {
        return PACKET_TRAILER;
    }
}