Coverage details for net.sf.tourviewer.lib.ciclo.CicloRawReader

LineHitsSource
1 package net.sf.tourviewer.lib.ciclo;
2  
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.PrintStream;
6 import java.util.Calendar;
7 import java.util.Date;
8 import net.sf.tourviewer.lib.Bike;
9 import net.sf.tourviewer.lib.Marker;
10 import net.sf.tourviewer.lib.Tour;
11 import net.sf.tourviewer.lib.TourRecord;
12 import net.sf.tourviewer.lib.TourSet;
13  
1438public class CicloRawReader {
15  
16     private static final int BITS_PER_WORD = 16;
17     private static final int BLOCK_COUNT = 2048;
18     private static final int BLOCK_SIZE = 8;
19     
20     /**
21      * Time interval for which a data block stores its values in s.
22      */
23     private static final int DATA_RECORD_INTERVAL = 20;
24     private static final int DATA_RECORDS_PER_BLOCK = 6;
25     private static final String FILE_SIGNATURE = "AFRO";
26     private static final int LAST_INDEX = BLOCK_COUNT - 1;
27  
28     private static final int WORDS_PER_BLOCK = 16;
29  
30     private Block[] blocks;
31     private int checksum;
32     private CicloDevice device;
33     private int expectedChecksum;
34     
35     public boolean accept(InputStream in) throws IOException
36     {
370        byte[] buffer = new byte[FILE_SIGNATURE.length()];
380        in.mark(buffer.length);
390        in.read(buffer);
40         
41         try {
420            return FILE_SIGNATURE.equalsIgnoreCase(new String(buffer));
43         }
44         finally {
450            in.reset();
460        }
47     }
48     
49     private TourRecord addTourRecords(Calendar cal, Tour tour, TourRecord prevRecord, DataBlock[] data, int endMarker, int cadence, int temperature)
50     {
510        int count = endMarker / DATA_RECORD_INTERVAL + 1;
520        if (endMarker % DATA_RECORD_INTERVAL == 0) {
530            count--;
54         }
55  
56         // TODO interpolate temperature
570        for (int i = 0; i < count; i++) {
580            TourRecord record = new TourRecord();
590            record.setCadence(cadence);
600            record.setTemperature(temperature);
610            record.setAltitude(prevRecord.getAltitude() + data[i].getAltitudeDelta());
620            record.setDistance(prevRecord.getDistance() + data[i].getDistanceDelta() * 10);
630            record.setPulse(Math.max(prevRecord.getPulse() + data[i].getPulseDelta(), 0));
640            if (i < count - 1 || endMarker % DATA_RECORD_INTERVAL == 0) {
650                cal.add(Calendar.SECOND, DATA_RECORD_INTERVAL);
660            }
67             else {
680                cal.add(Calendar.SECOND, endMarker % DATA_RECORD_INTERVAL);
69             }
700            record.setTime(cal.getTime());
710            tour.addRecord(record);
720            prevRecord = record;
73         }
740        return prevRecord;
75     }
76  
77     
78     private Date adjustDate(Calendar cal, Date lastDate, int year)
79     {
800        if (lastDate != null) {
810            Calendar cal2 = Calendar.getInstance();
820            cal2.setTime(lastDate);
830            int lastYear = cal2.get(Calendar.YEAR);
840            cal.set(Calendar.YEAR, lastYear);
850            if (lastDate.before(cal.getTime())) {
860                cal.set(Calendar.YEAR, lastYear - 1);
87             }
880            return cal.getTime();
89         }
90         else {
910            cal.set(Calendar.YEAR, year);
920            return cal.getTime();
93         }
94     }
95  
96     private TourSet analyze(int[] data)
97     {
9838        if (data.length != BLOCK_COUNT * WORDS_PER_BLOCK) {
990            throw new IllegalArgumentException("Expected data.length == " + BLOCK_COUNT * WORDS_PER_BLOCK);
100         }
101  
10238        blocks = new Block[BLOCK_COUNT];
10338        if (data[128] == HAC4_315.MAGIC) {
10416            device = new HAC4_315();
10516            return analyzeHAC4(data);
106         }
10722        if (data[128] == HAC4_Imp.MAGIC) {
1080            device = new HAC4_Imp();
1090            return analyzeHAC4(data);
110         }
11122        else if (data[128] == CM414M.MAGIC) {
11222            device = new CM414M();
11322            return analyzeCM414M(data);
114         }
115         else {
1160            device = new HAC4_325();
1170            return analyzeHAC4_325(data);
118         }
119     }
120     
121     private TourSet analyzeCM414M(int[] data)
122     {
12322        final int index = device.getInfoBlockIndex();
12422        if (index == CicloDevice.NO_INDEX) {
1250            throw new IllegalArgumentException("device.getInfoBlockIndex() must be valid");
126         }
127         
128         // prepare records
12922        blocks[index] = new CM414MInfo1Block(getRecordData(data, index));
13022        blocks[index + 1] = new CM414MInfo2Block(getRecordData(data, index + 1));
13122        blocks[index + 2] = new CM414MInfo3Block(getRecordData(data, index + 2));
13222        analyzeTourData(data);
133  
134         // parse records
13522        TourSet tourSet = new TourSet();
1360        tourSet.setDevice(device);
137         
1380        CM414MInfo1Block info1Record = (CM414MInfo1Block)blocks[index];
1390        tourSet.setPersonWeight(info1Record.getWeight());
140  
1410        CM414MInfo2Block info2Record = (CM414MInfo2Block)blocks[index + 1];
1420        CM414MInfo3Block info3Record = (CM414MInfo3Block)blocks[index + 2];
143         
1440        Bike bike = new Bike();
1450        bike.setDistance(info3Record.getTotalDistance1());
1460        bike.setTravelTime(info3Record.getTotalTravelTime1());
1470        bike.setWheelPerimeter(info1Record.getWheelPerimeter1());
1480        tourSet.addBike(bike);
149         
1500        bike = new Bike();
1510        bike.setDistance(info3Record.getTotalDistance2());
1520        bike.setTravelTime(info3Record.getTotalTravelTime2());
1530        bike.setWheelPerimeter(info1Record.getWheelPerimeter2());
1540        tourSet.addBike(bike);
155         
1560        parseTourRecords(tourSet, info2Record.getLastDDOffset(), info1Record.getYear());
157         
1580        return tourSet;
159     }
160  
161     private TourSet analyzeHAC4(int[] data)
162     {
16316        final int index = device.getInfoBlockIndex();
16416        if (index == CicloDevice.NO_INDEX) {
1650            throw new IllegalArgumentException("device.getInfoBlockIndex() must be valid");
166         }
167  
168         // prepare records
16916        blocks[index] = new HAC4Info1Block(getRecordData(data, index));
17016        blocks[index + 1] = new HAC4Info2Block(getRecordData(data, index + 1));
17116        blocks[index + 2] = new HAC4Info3Block(getRecordData(data, index + 2));
17216        analyzeTourData(data);
173  
174         // parse records
17516        TourSet tourSet = new TourSet();
1760        tourSet.setDevice(device);
177         
1780        HAC4Info1Block info1Record = (HAC4Info1Block)blocks[index];
1790        tourSet.setPersonWeight(info1Record.getWeight());
180         
1810        HAC4Info2Block info2Record = (HAC4Info2Block)blocks[index + 1];
1820        HAC4Info3Block info3Record = (HAC4Info3Block)blocks[index + 2];
183         
1840        Bike bike = new Bike();
1850        bike.setDistance(info2Record.getTotalDistance());
1860        bike.setTravelTime(info3Record.getTotalTravelTime());
1870        bike.setWheelPerimeter(info1Record.getWheelPerimeter());
1880        tourSet.addBike(bike);
189  
1900        parseTourRecords(tourSet, info3Record.getLastDDOffset(), info2Record.getYear());
191         
1920        return tourSet;
193     }
194     
195     private TourSet analyzeHAC4_325(int[] data)
196     {
1970        TourSet tourSet = new TourSet();
1980        tourSet.setDevice(device);
199         
200         // FIXME need to manually scan for tours
201         
2020        return tourSet;
203     }
204     
205     protected void analyzeTourData(int[] data)
206     {
20777140        for (int i = device.getTourBlockIndex(); i < BLOCK_COUNT; i++) {
20877102            int[] recordData = getRecordData(data, i);
20977102            int type = recordData[0] & 0xFF;
21077102            if (type == 0xAA) {
211566                blocks[i] = new AABlock(recordData);
212566            }
21376536            else if (type == 0xBB) {
21420276                blocks[i] = new BBBlock(recordData);
21520276            }
21656260            else if (type == 0xCC) {
217566                blocks[i] = new CCBlock(recordData);
218566            }
21955694            else if (type == 0xDD) {
220566                blocks[i] = new DDBlock(recordData);
221566            }
222             else {
22355128                blocks[i] = new UnknownBlock(recordData);
224             }
225         }
22638    }
227  
228     private int decTourIndex(int index)
229     {
2300        return (index == device.getTourBlockIndex()) ? LAST_INDEX : index - 1;
231     }
232     
233     public int getChecksum()
234     {
2350        return checksum;
236     }
237  
238     public int getExpectedChecksum()
239     {
2400        return expectedChecksum;
241     }
242     
243     private int[] getRecordData(int[] data, int index)
244     {
24577216        int[] recordData = new int[BLOCK_SIZE];
24677216        System.arraycopy(data, index * BLOCK_SIZE, recordData, 0, BLOCK_SIZE);
24777216        return recordData;
248     }
249  
250     private int incTourIndex(int index)
251     {
2520        return (index == LAST_INDEX) ? device.getTourBlockIndex() : index + 1;
253     }
254  
255     private int offsetToIndex(int offset)
256     {
2570        return offset / WORDS_PER_BLOCK;
258     }
259     
260     private Tour parseTour(AABlock startRecord, int startIndex, Date lastDate, int year)
261     {
2620        Calendar cal = Calendar.getInstance();
263         
2640        Tour tour = new Tour();
2650        tour.setAutoStatistics(true);
266         
2670        cal.set(Calendar.MONTH, startRecord.getTimeMonth() - 1);
2680        cal.set(Calendar.DAY_OF_MONTH, startRecord.getTimeDay());
2690        cal.set(Calendar.HOUR_OF_DAY, startRecord.getTimeHour());
2700        cal.set(Calendar.MINUTE, startRecord.getTimeMinute());
2710        tour.setStartTime(adjustDate(cal, lastDate, year));
272         
2730        TourRecord prevRecord = new TourRecord();
2740        prevRecord.setAltitude(startRecord.getInitialAltitude());
2750        prevRecord.setDistance(0);
2760        prevRecord.setPulse(startRecord.getInitialPulse());
2770        prevRecord.setTime(tour.getStartTime());
2780        tour.addRecord(prevRecord);
279         
2800        boolean valid = false;
2810        int index = startIndex;
282         while (true) {
2830            index = incTourIndex(index);
2840            if (blocks[index] instanceof BBBlock) {
2850                BBBlock dataRecord = (BBBlock)blocks[index];
2860                if (!valid) {
2870                    valid = true;
288                     // the first record always has the temperature of the
289                     // first data record
2900                    prevRecord.setTemperature(dataRecord.getTemperature());
291                 }
2920                if (dataRecord.getMarker() != 0) {
2930                    cal.add(Calendar.SECOND, dataRecord.getMarker());
2940                    tour.addMarker(new Marker(cal.getTime()));
2950                    cal.add(Calendar.SECOND, -dataRecord.getMarker());
296                 }
2970                prevRecord = addTourRecords(cal, tour, prevRecord,
298                         dataRecord.getDataRecords(), DATA_RECORD_INTERVAL * DATA_RECORDS_PER_BLOCK,
299                         dataRecord.getCadence(), dataRecord.getTemperature());
3000            }
3010            else if (blocks[index] instanceof CCBlock) {
3020                if (!valid) {
303                     // tour contains no data
3040                    return null;
305                 }
306                 
3070                CCBlock dataRecord = (CCBlock)blocks[index];
3080                cal.add(Calendar.SECOND, dataRecord.getEndMarker());
3090                tour.setEndTime(cal.getTime());
3100                cal.add(Calendar.SECOND, -dataRecord.getEndMarker());
3110                prevRecord = addTourRecords(cal, tour, prevRecord,
312                         dataRecord.getDataRecords(), dataRecord.getEndMarker(),
313                         dataRecord.getCadence(), dataRecord.getTemperature());
3140                tour.setDistance(prevRecord.getDistance());
315                 
3160                index = incTourIndex(index);
3170                if (blocks[index] instanceof DDBlock) {
3180                    DDBlock endBlock = (DDBlock)blocks[index];
3190                    return tour;
320                 }
321                 else {
3220                    return null;
323                 }
324             }
325             else {
3260                return null;
327             }
328         }
329     }
330     
331     private void parseTourRecords(TourSet tourSet, int lastDDOffset, int yearOfTransfer)
332     {
3330        Bike[] bikes = tourSet.getBikes();
3340        if (bikes == null) {
3350            throw new IllegalArgumentException("Bikes may not be null or empty");
336         }
337         
3380        int index = offsetToIndex(lastDDOffset);
3390        int startIndex = index;
3400        int lastIndex = index;
3410        Date lastDate = null;
342         
343         while ((index < startIndex)
3440                ? (index < lastIndex)
345                 : (unwrapIndex(index) < startIndex && unwrapIndex(index) < lastIndex)) {
3460            if (blocks[index] instanceof DDBlock) {
3470                DDBlock endRecord = (DDBlock)blocks[index];
348  
3490                index = offsetToIndex(endRecord.getAAOffset());
3500                if (blocks[index] instanceof AABlock) {
3510                    AABlock startBlock = (AABlock)blocks[index];
3520                    Tour tour = parseTour(startBlock, index, lastDate, yearOfTransfer);
3530                    if (tour != null) {
3540                        lastDate = tour.getStartTime();
3550                        setTourType(tour, startBlock, bikes);
3560                        tourSet.addTour(tour);
357                     }
3580                    lastIndex = (index < startIndex) ? index : unwrapIndex(index);
3590                    index = decTourIndex(index);
3600                }
361                 else {
3620                    return;
363                 }
3640            }
365             else {
3660                return;
367             }
368         }
3690    }
370  
371     public void print(PrintStream out)
372     {
3730        for (int i = 0; i < blocks.length; i++) {
3740            System.out.printf("%04d: ", i);
3750            if (blocks[i] != null) {
3760                out.println(blocks[i]);
3770            }
378             else {
3790                out.println();
380             }
381         }
3820    }
383  
384     public TourSet read(InputStream in) throws IOException {
38538        int lastValue = 0;
38638        byte[] buffer = new byte[5];
38738        int[] data = new int[BLOCK_COUNT * WORDS_PER_BLOCK];
38838        int offset = 0;
389         
39038        in.read(buffer);
39138        if (!FILE_SIGNATURE.equalsIgnoreCase(new String(buffer, 0, 4))) {
3920            throw new IOException("Invalid file signature, expected " + FILE_SIGNATURE);
393         }
394         
395622668        while (in.read(buffer) != -1) {
396622630            checksum = (checksum + lastValue) & 0xFFFF;
397             
398622630            String bufferText = new String(buffer, 0, 4);
399622630            lastValue = Integer.parseInt(bufferText, 16);
400             
401622630            if (offset < data.length) {
402622630                data[offset] = lastValue;
403622630            }
4040            else if (offset > data.length) {
4050                throw new IOException("File is too long, expected 81930 byte");
406             }
407622630            offset ++;
408622630        }
409         
41038        expectedChecksum = lastValue;
41138        return analyze(data);
412     }
413  
414     private void setTourType(Tour tour, AABlock startBlock, Bike[] bikes)
415     {
4160        AABlock.TourType type = startBlock.getTourType();
4170        if (type == AABlock.TourType.BIKE || type == AABlock.TourType.BIKE1) {
4180            tour.setType(Tour.Type.BIKE);
4190            if (bikes.length >= 1) {
4200                tour.setBike(bikes[0]);
4210            }
422         }
4230        else if (type == AABlock.TourType.SKI_BIKE) {
4240            tour.setType(Tour.Type.SKI_BIKE);
4250            if (bikes.length >= 1) {
4260                tour.setBike(bikes[0]);
4270            }
428         }
4290        else if (type == AABlock.TourType.BIKE2) {
4300            tour.setType(Tour.Type.BIKE);
4310            if (bikes.length >= 2) {
4320                tour.setBike(bikes[1]);
4330            }
434         }
4350        else if (type == AABlock.TourType.JOGGING) {
4360            tour.setType(Tour.Type.JOGGING);
437  
438         }
4390    }
440  
441     private int unwrapIndex(int index)
442     {
4430        return device.getTourBlockIndex() - (LAST_INDEX - index);
444     }
445     
446 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.