1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.chromium.latency.walt.programmer;
18
19import android.content.Context;
20import android.os.Handler;
21import android.util.Log;
22
23import org.chromium.latency.walt.R;
24import org.chromium.latency.walt.SimpleLogger;
25import org.chromium.latency.walt.WaltConnection;
26
27import java.io.InputStream;
28import java.text.ParseException;
29import java.util.Arrays;
30
31public class Programmer {
32    private static final String TAG = "Programmer";
33    private SimpleLogger logger;
34
35    private FirmwareImage image;
36    private BootloaderConnection conn;
37
38    private Context context;
39    private Handler handler = new Handler();
40
41    public Programmer(Context context) {
42        this.context = context;
43    }
44
45    public void program() {
46        logger = SimpleLogger.getInstance(context);
47        InputStream in = context.getResources().openRawResource(R.raw.walt);
48        image = new FirmwareImage();
49        try {
50            image.parseHex(in);
51        } catch (ParseException e) {
52            Log.e(TAG, "Parsing input file: ", e);
53        }
54
55        conn = BootloaderConnection.getInstance(context);
56        // TODO: automatically reboot into the bootloader
57        logger.log("\nRemember to press the button on the Teensy first\n");
58        conn.setConnectionStateListener(new WaltConnection.ConnectionStateListener() {
59            @Override
60            public void onConnect() {
61                handler.post(programRunnable);
62            }
63
64            @Override
65            public void onDisconnect() {}
66        });
67        if (!conn.isConnected()) {
68            conn.connect();
69        }
70    }
71
72    private Runnable programRunnable = new Runnable() {
73        @Override
74        public void run() {
75            logger.log("Programming...");
76
77            // The logic for this is ported from
78            // https://github.com/PaulStoffregen/teensy_loader_cli
79            byte[] buf = new byte[DeviceConstants.BLOCK_SIZE + 64];
80            for (int addr = 0; addr < DeviceConstants.FIRMWARE_SIZE;
81                 addr += DeviceConstants.BLOCK_SIZE) {
82                if (!image.shouldWrite(addr, DeviceConstants.BLOCK_SIZE) && addr != 0)
83                    continue; // don't need to flash this block
84
85                buf[0] = (byte) (addr & 255);
86                buf[1] = (byte) ((addr >>> 8) & 255);
87                buf[2] = (byte) ((addr >>> 16) & 255);
88                Arrays.fill(buf, 3, 64, (byte) 0);
89                image.getData(buf, 64, addr, DeviceConstants.BLOCK_SIZE);
90
91                conn.write(buf, (addr == 0) ? 3000 : 250);
92            }
93
94            logger.log("Programming complete. Rebooting.");
95
96            // reboot the device
97            buf[0] = (byte) 0xFF;
98            buf[1] = (byte) 0xFF;
99            buf[2] = (byte) 0xFF;
100            Arrays.fill(buf, 3, DeviceConstants.BLOCK_SIZE + 64, (byte) 0);
101            conn.write(buf, 250);
102        }
103    };
104}
105