Skip to content

Commit 35a22b1

Browse files
committed
started work on java bootloader
1 parent f293cba commit 35a22b1

29 files changed

+1291
-2
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44
*.lst
55
*.map
66
*~
7+
.project
8+
.classpath
9+
.settings/
10+
target/

Makefile

+5-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# See the License for the specific language governing permissions and
1616
# limitations under the License.
1717

18-
all: checkVIDPID 18f13k50 18f2550
18+
all: checkVIDPID 18f13k50 18f2550 java
1919

2020
checkVIDPID:
2121
@test "$(VID)" || ( echo "ERROR: missing VID"; exit 1 )
@@ -28,7 +28,10 @@ checkVIDPID:
2828
18f2550:
2929
$(MAKE) -C 18f2550 clean all
3030

31+
java:
32+
( cd java; mvn clean install )
33+
3134
clean:
3235
$(MAKE) -C 18f13k50 clean
3336

34-
.PHONY: all clean checkVIDPID 18f13k50 18f2550
37+
.PHONY: all clean checkVIDPID 18f13k50 18f2550 java

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ There is a CI build of the firmware at travis-ci: http://travis-ci.org/holgero/P
5454
18f13k50 Bootloader for the PIC 18f13k50 (works only on 18f13k50,
5555
the 18f14k50 has a different block write size).
5656

57+
18f2550 Bootloader for the PIC 18f2550 (might work on other
58+
PICs of the 18fx[45]5x family, but I did not try that).
59+
60+
java The start of an implementation of a java bootloader for the
61+
host part. Does not work yet. (Only compiles and runs tests.)
62+
5763
## License
5864

5965
Licensed under the Apache License, Version 2.0 (the "License");

java/bootloader/pom.xml

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<!-- USB Boot Loader Copyright (C) 2012 Holger Oehm This program is free
4+
software: you can redistribute it and/or modify it under the terms of the
5+
GNU General Public License as published by the Free Software Foundation,
6+
either version 3 of the License, or (at your option) any later version. This
7+
program is distributed in the hope that it will be useful, but WITHOUT ANY
8+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10+
You should have received a copy of the GNU General Public License along with
11+
this program. If not, see <http://www.gnu.org/licenses/>. -->
12+
13+
<modelVersion>4.0.0</modelVersion>
14+
<groupId>de.holger_oehm.pic.usb.bootloader</groupId>
15+
<artifactId>bootloader</artifactId>
16+
<packaging>jar</packaging>
17+
<version>0.1.0-SNAPSHOT</version>
18+
<url>https://github.com/holgero/PicUsbBootloader</url>
19+
<properties>
20+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21+
<jna.version>3.4.0</jna.version>
22+
</properties>
23+
<dependencies>
24+
<dependency>
25+
<groupId>net.java.dev.jna</groupId>
26+
<artifactId>jna</artifactId>
27+
<version>${jna.version}</version>
28+
</dependency>
29+
<dependency>
30+
<groupId>net.java.dev.jna</groupId>
31+
<artifactId>platform</artifactId>
32+
<version>${jna.version}</version>
33+
<!-- classifier>platform</classifier -->
34+
</dependency>
35+
<dependency>
36+
<groupId>commons-io</groupId>
37+
<artifactId>commons-io</artifactId>
38+
<version>2.4</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>junit</groupId>
42+
<artifactId>junit-dep</artifactId>
43+
<version>4.10</version>
44+
<scope>test</scope>
45+
<exclusions>
46+
<exclusion>
47+
<groupId>org.hamcrest</groupId>
48+
<artifactId>hamcrest-core</artifactId>
49+
</exclusion>
50+
</exclusions>
51+
</dependency>
52+
<dependency>
53+
<groupId>org.hamcrest</groupId>
54+
<artifactId>hamcrest-integration</artifactId>
55+
<version>1.3</version>
56+
<scope>test</scope>
57+
</dependency>
58+
</dependencies>
59+
<build>
60+
<plugins>
61+
<plugin>
62+
<groupId>org.apache.maven.plugins</groupId>
63+
<artifactId>maven-compiler-plugin</artifactId>
64+
<version>2.3.2</version>
65+
<configuration>
66+
<source>1.7</source>
67+
<target>1.7</target>
68+
</configuration>
69+
</plugin>
70+
<plugin>
71+
<groupId>org.apache.maven.plugins</groupId>
72+
<artifactId>maven-assembly-plugin</artifactId>
73+
<configuration>
74+
<descriptorRefs>
75+
<descriptorRef>jar-with-dependencies</descriptorRef>
76+
</descriptorRefs>
77+
<archive>
78+
<manifest>
79+
<mainClass>de.holger_oehm.pic.usb.TODO</mainClass>
80+
</manifest>
81+
</archive>
82+
</configuration>
83+
<executions>
84+
<execution>
85+
<id>make-assembly</id>
86+
<phase>package</phase>
87+
<goals>
88+
<goal>single</goal>
89+
</goals>
90+
</execution>
91+
</executions>
92+
</plugin>
93+
</plugins>
94+
</build>
95+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package de.holger_oehm.pic.progmem;
2+
3+
import java.io.IOException;
4+
import java.io.LineNumberReader;
5+
import java.io.Reader;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
import de.holger_oehm.pic.progmem.hexfile.DataRecord;
10+
import de.holger_oehm.pic.progmem.hexfile.HexFileRecord;
11+
import de.holger_oehm.pic.progmem.hexfile.HexRecordParser;
12+
import de.holger_oehm.pic.progmem.hexfile.LinearAddressRecord;
13+
import de.holger_oehm.pic.progmem.hexfile.SegmentRecord;
14+
15+
public class HexFileParser {
16+
private final List<String> warnings = new ArrayList<>();
17+
18+
public PicMemory parse(final Reader content) throws IOException {
19+
warnings.clear();
20+
boolean gotEof = false;
21+
int currentOffset = 0;
22+
final PicMemory result = new PicMemory();
23+
final LineNumberReader reader = new LineNumberReader(content);
24+
do {
25+
final String line = reader.readLine();
26+
if (line == null) {
27+
break;
28+
}
29+
if (gotEof) {
30+
warnings.add("content after EOF record: " + line);
31+
continue;
32+
}
33+
final HexFileRecord record = HexRecordParser.parse(line);
34+
switch (record.getType()) {
35+
case EOF:
36+
gotEof = true;
37+
break;
38+
case DATA:
39+
final DataRecord dataRecord = (DataRecord) record;
40+
final byte[] bytes = dataRecord.getBytes();
41+
final int address = currentOffset + dataRecord.getAddress();
42+
result.setBytes(address, bytes);
43+
break;
44+
case SEG_ADDR:
45+
final SegmentRecord segmentRecord = (SegmentRecord) record;
46+
currentOffset = segmentRecord.getUpperAddress();
47+
break;
48+
case LIN_ADDR:
49+
final LinearAddressRecord linearAddressRecord = (LinearAddressRecord) record;
50+
currentOffset = linearAddressRecord.getUpperAddress();
51+
break;
52+
}
53+
} while (true);
54+
if (!gotEof) {
55+
warnings.add("EOF record is missing");
56+
}
57+
return result;
58+
}
59+
60+
public List<String> getWarnings() {
61+
return warnings;
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package de.holger_oehm.pic.progmem;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
import java.util.SortedMap;
7+
import java.util.TreeMap;
8+
9+
public class PicMemory {
10+
private static final int CHUNK_SIZE = 0x40;
11+
private static final int CHUNK_MASK = ~(CHUNK_SIZE - 1);
12+
13+
private static class Chunk {
14+
private final byte[] chunkBytes = new byte[CHUNK_SIZE];
15+
16+
public Chunk() {
17+
Arrays.fill(chunkBytes, (byte) 0xff);
18+
}
19+
20+
private int setBytes(final int address, final byte[] bytes) {
21+
int result = 0;
22+
for (int i = 0; i < bytes.length; i++) {
23+
final byte b = bytes[i];
24+
final int localIdx = address + i;
25+
if (localIdx >= CHUNK_SIZE) {
26+
break;
27+
}
28+
chunkBytes[localIdx] = b;
29+
result++;
30+
}
31+
return result;
32+
}
33+
34+
private byte getByte(final int address) {
35+
return chunkBytes[address];
36+
}
37+
}
38+
39+
private final SortedMap<Integer, Chunk> chunkMemory = new TreeMap<>();
40+
41+
public int getByte(final int address) {
42+
final int chunkAddress = chunkAddress(address);
43+
final Chunk chunk = chunkMemory.get(chunkAddress);
44+
if (chunk == null) {
45+
return 0xff;
46+
}
47+
final byte byteValue = chunk.getByte(address - chunkAddress);
48+
return byteValue & 0xff;
49+
}
50+
51+
public void setBytes(final int address, final byte[] bytes) {
52+
final int chunkAddress = chunkAddress(address);
53+
final Chunk chunk;
54+
if (chunkMemory.containsKey(chunkAddress)) {
55+
chunk = chunkMemory.get(chunkAddress);
56+
} else {
57+
chunk = new Chunk();
58+
chunkMemory.put(chunkAddress, chunk);
59+
}
60+
final int wrote = chunk.setBytes(address - chunkAddress, bytes);
61+
if (wrote < bytes.length) {
62+
setBytes(address + wrote, Arrays.copyOfRange(bytes, wrote, bytes.length));
63+
}
64+
}
65+
66+
private int chunkAddress(final int address) {
67+
return address & CHUNK_MASK;
68+
}
69+
70+
public void setBytes(final int address, final int... integers) {
71+
final byte[] bytes = new byte[integers.length];
72+
for (int i = 0; i < integers.length; i++) {
73+
final int value = integers[i];
74+
if (0 > value || value > 255) {
75+
throw new IllegalArgumentException("all values must be between 0 and 255: " + Arrays.toString(integers));
76+
}
77+
bytes[i] = (byte) value;
78+
}
79+
setBytes(address, bytes);
80+
}
81+
82+
public List<Integer> getChunkAddresses() {
83+
final List<Integer> result = new ArrayList<>();
84+
result.addAll(chunkMemory.keySet());
85+
return result;
86+
}
87+
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package de.holger_oehm.pic.progmem.hexfile;
2+
3+
public class DataRecord extends HexFileRecord {
4+
private final int length;
5+
private final int address;
6+
private final byte[] bytes;
7+
8+
public DataRecord(final int length, final int address, final byte[] bytes) {
9+
this.length = length;
10+
this.address = address;
11+
this.bytes = bytes;
12+
}
13+
14+
@Override
15+
public RecordType getType() {
16+
return RecordType.DATA;
17+
}
18+
19+
public int getLength() {
20+
return length;
21+
}
22+
23+
public int getAddress() {
24+
return address;
25+
}
26+
27+
public byte[] getBytes() {
28+
return bytes;
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package de.holger_oehm.pic.progmem.hexfile;
2+
3+
public class EOFRecord extends HexFileRecord {
4+
public EOFRecord() {
5+
}
6+
7+
@Override
8+
public RecordType getType() {
9+
return RecordType.EOF;
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package de.holger_oehm.pic.progmem.hexfile;
2+
3+
public abstract class HexFileRecord {
4+
public abstract RecordType getType();
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package de.holger_oehm.pic.progmem.hexfile;
2+
3+
import java.util.regex.Matcher;
4+
import java.util.regex.Pattern;
5+
6+
public class HexRecordParser {
7+
public static final Pattern HEXRECORD_PATTERN = Pattern
8+
.compile(":([a-fA-F0-9]{2})([a-fA-F0-9]{4})([a-fA-F0-9]{2})(([a-fA-F0-9]{2})*)([a-fA-F0-9]{2})");
9+
10+
@SuppressWarnings("unchecked")
11+
public static <T extends HexFileRecord> T parse(final String line) {
12+
final Matcher recordMatcher = HexRecordParser.HEXRECORD_PATTERN.matcher(line);
13+
if (!recordMatcher.matches()) {
14+
throw new IllegalArgumentException("wrong format " + line);
15+
}
16+
HexRecordParser.validateChecksum(line);
17+
final int length = Integer.parseInt(recordMatcher.group(1), 16);
18+
final int address = Integer.parseInt(recordMatcher.group(2), 16);
19+
final RecordType recordType = RecordType.values()[Integer.parseInt(recordMatcher.group(3), 16)];
20+
final String data = recordMatcher.group(4);
21+
final byte[] bytes = new byte[length];
22+
for (int i = 0; i < bytes.length; i++) {
23+
bytes[i] = (byte) Integer.parseInt(data.substring(2 * i, 2 * i + 2), 16);
24+
}
25+
switch (recordType) {
26+
case EOF:
27+
return (T) new EOFRecord();
28+
case DATA:
29+
return (T) new DataRecord(length, address, bytes);
30+
case SEG_ADDR:
31+
return (T) new SegmentRecord(length, address, bytes);
32+
case SEG_START:
33+
return (T) new SegmentStartRecord(length, address, bytes);
34+
case LIN_ADDR:
35+
return (T) new LinearAddressRecord(length, address, bytes);
36+
case LIN_START:
37+
return (T) new LinearStartRecord(length, address, bytes);
38+
default:
39+
throw new IllegalStateException("dont know record type " + recordType);
40+
}
41+
}
42+
43+
private static void validateChecksum(final String line) {
44+
int checksum = 0;
45+
for (int i = 1; i + 1 < line.length(); i += 2) {
46+
final int byteValue = Integer.parseInt(line.substring(i, i + 2), 16);
47+
checksum += byteValue;
48+
}
49+
if ((checksum & 0x00ff) != 0) {
50+
throw new IllegalArgumentException("wrong checksum: " + (checksum & 0x0ff) + " in line " + line);
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)