aboutsummaryrefslogtreecommitdiffstats
path: root/Bootloaders/Incomplete/MIDI/JavaHost/BIN2BOOT.java
blob: f30998ad5116ae992c23d4f7e867739f6524898a (plain)
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import javax.sound.midi.*;
import javax.sound.midi.MidiMessage.*;
import java.io.RandomAccessFile;

class BIN2BOOT
{
	private static final int MIDI_CONTROL_CHANNEL          = 9;
	private static final int MIDI_DATA_CHANNEL             = 0;

	private static final int CONTROL_DEVICE_READY          = 0xD1;
	private static final int CONTROL_ENTER_PROG_MODE       = 0xDC;
	private static final int CONTROL_LEAVE_PROG_MODE       = 0xDF;
	private static final int CONTROL_GET_PAGE_SIZE         = 0x01;

	public static void main(String[] args)
	{
		if (args.length != 1)
		{
			System.out.println("BIN2BOOT - USB-MIDI bootloader");
			System.out.println("  Usage: java BIN2BOOT {input}.bin");
		}	
	
		RandomAccessFile inFile = null;
		
		try
		{
			inFile = new RandomAccessFile(args[0], "r");
		}
		catch (Exception e)
		{
			System.out.println("Could not open input file!");
			return;
		}

		MidiDevice  currDevice = null;
		Receiver    midiOut    = null;
		Transmitter midiIn     = null;
		MIDIMessageReceiver midiInMessages = new MIDIMessageReceiver();
		
		try
		{
			MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
			
			for (MidiDevice.Info info : infos)
			{
				currDevice = MidiSystem.getMidiDevice(info);
			
				if (!(currDevice instanceof Sequencer) && !(currDevice instanceof Synthesizer))
				{
					if (info.getName().indexOf("LUFA") == -1)
					  continue;
					  
					System.out.println(" MIDI Device: " + info.getName());
				
					currDevice.open();
				
					if (currDevice.getMaxReceivers() != 0)
					{
						midiOut = currDevice.getReceiver();
						break;
					}

					if (currDevice.getMaxTransmitters() != 0)
					{
						midiIn  = currDevice.getTransmitter();
						midiIn.setReceiver(midiInMessages);
					}
				}
			}
			
			if ((midiOut == null) || (midiIn == null))
			{
				System.out.println("Could not find suitable MIDI device!");
				return;
			}			
		}
		catch (Exception e)
		{
			System.out.println("Could not enumerate MIDI devices!");
			return;
		}
		
		System.out.println("PROGRAMMING FILE...");

		ProgramFirmware(inFile, midiOut, midiInMessages);

		System.out.println("DONE.");

		try
		{
			midiOut.close();
			midiIn.close();
			currDevice.close();
			inFile.close();
		}
		catch (Exception e)
		{
			System.out.println("ERROR: Could not close open resources.");		
		}
	}
	
	private static void ProgramFirmware(RandomAccessFile inFile, Receiver midiOut, MIDIMessageReceiver midiInMessages)
	{
		try
		{
			System.out.println("Entering Programming Mode...");
			sendByteViaMIDI(midiOut, MIDI_CONTROL_CHANNEL, CONTROL_ENTER_PROG_MODE);
			
			int[] messageData;
			do
			{
				messageData = receiveByteViaMIDI(midiInMessages);
			}
			while ((messageData[0] != MIDI_CONTROL_CHANNEL) && (messageData[1] != CONTROL_DEVICE_READY));
			
			System.out.println("Getting Page Size...");
			sendByteViaMIDI(midiOut, MIDI_CONTROL_CHANNEL, CONTROL_GET_PAGE_SIZE);

			int nextByte = inFile.read();
			while (nextByte != -1)
			{
				sendByteViaMIDI(midiOut, 9, nextByte);

				if ((inFile.getFilePointer() % (inFile.length() / 100)) == 0)
					System.out.println("  LOADING: " + (int)(inFile.getFilePointer() / (inFile.length() / 100.0)) + "%...");

				nextByte = inFile.read();
			}

			sendByteViaMIDI(midiOut, MIDI_CONTROL_CHANNEL, CONTROL_LEAVE_PROG_MODE);
		}
		catch (Exception e)
		{
			System.out.println("ERROR: Could not send data to device.");		
		}
	}

	private static void sendByteViaMIDI(Receiver midiOut, int channel, int data)
	{
		ShortMessage sendMessage = new ShortMessage();
		
		try
		{
			sendMessage.setMessage(ShortMessage.NOTE_ON, channel, (data & 0x7F), (((data & 0x80) == 0x80) ? 64 : 32));
			midiOut.send(sendMessage, -1);

//			try {Thread.sleep(1);} catch (Exception e) {}

			sendMessage.setMessage(ShortMessage.NOTE_OFF, channel, (data & 0x7F), (((data & 0x80) == 0x80) ? 64 : 32));
			midiOut.send(sendMessage, -1);
		}
		catch (Exception e)
		{
			System.out.println("ERROR: Could not send MIDI note press.");
		}
	}

	private static int[] receiveByteViaMIDI(MIDIMessageReceiver midiInReceiver)
	{
		byte[] messageData;
		
		do
		{
			while (!(midiInReceiver.hasReceived()));
			messageData = midiInReceiver.receive().getMessage();
		}
		while ((messageData[0] & 0xF0) != ShortMessage.NOTE_ON);
	
		int channel = (messageData[0] & 0x0F);
		int data    = (messageData[1] | ((messageData[2] == 64) ? 0x80 : 0x00));
		
		int[] formattedMessageData = new int[2];
		formattedMessageData[0] = channel;
		formattedMessageData[1] = data;
	
		return formattedMessageData;
	}
}