-
Notifications
You must be signed in to change notification settings - Fork 1
/
ploader.c
255 lines (212 loc) · 7.36 KB
/
ploader.c
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#include <string.h>
#include "ploader.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/* timeouts in milliseconds */
#define ACK_TIMEOUT 25
#define CHECKSUM_TIMEOUT 10000 // big because it includes program loading
#define EEPROM_PROGRAMMING_TIMEOUT 5000
#define EEPROM_VERIFICATION_TIMEOUT 2000
#define CHECKSUM_RETRIES (CHECKSUM_TIMEOUT / ACK_TIMEOUT)
#define EEPROM_PROGRAMMING_RETRIES (EEPROM_PROGRAMMING_TIMEOUT / ACK_TIMEOUT)
#define EEPROM_VERIFICATION_RETRIES (EEPROM_VERIFICATION_TIMEOUT / ACK_TIMEOUT)
static int WaitForAck(PL_state *state, int retries);
static void SerialInit(PL_state *state);
static void TByte(PL_state *state, uint8_t x);
static void TLong(PL_state *state, uint32_t x);
static void TComm(PL_state *state);
static int RBit(PL_state *state, int timeout);
static int IterateLFSR(PL_state *state);
void PL_Init(PL_state *state)
{
memset(state, 0, sizeof(PL_state));
}
/* PL_Shutdown - shutdown the loader */
void PL_Shutdown(PL_state *state)
{
TLong(state, LOAD_TYPE_SHUTDOWN);
TComm(state);
}
/* PL_LoadSpinBinary - load a spin binary using the rom loader */
int PL_LoadSpinBinary(PL_state *state, int loadType, uint8_t *image, int size)
{
int i, sts;
/* report the start of program loading */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_PROGRAM);
TLong(state, loadType);
TLong(state, size / sizeof(uint32_t));
/* download the spin binary */
for (i = 0; i < size; i += 4) {
uint32_t data = image[i] | (image[i + 1] << 8) | (image[i + 2] << 16) | (image[i + 3] << 24);
TLong(state, data);
}
TComm(state);
/* wait for an ACK indicating a successful load */
if ((sts = WaitForAck(state, CHECKSUM_RETRIES)) < 0)
return LOAD_STS_TIMEOUT;
else if (sts == 0)
return LOAD_STS_ERROR;
/* wait for eeprom programming and verification */
if (loadType == LOAD_TYPE_EEPROM || loadType == LOAD_TYPE_EEPROM_RUN) {
/* report the start of the eeprom writing phase */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_EEPROM_WRITE);
/* wait for an ACK indicating a successful EEPROM programming */
if ((sts = WaitForAck(state, EEPROM_PROGRAMMING_RETRIES)) < 0)
return LOAD_STS_TIMEOUT;
else if (sts == 0)
return LOAD_STS_ERROR;
/* report the start of the eeprom verification phase */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_EEPROM_VERIFY);
/* wait for an ACK indicating a successful EEPROM verification */
if ((sts = WaitForAck(state, EEPROM_VERIFICATION_RETRIES)) < 0)
return LOAD_STS_TIMEOUT;
else if (sts == 0)
return LOAD_STS_ERROR;
}
/* report load completion */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_DONE);
/* load completed successfully */
return LOAD_STS_OK;
}
static int WaitForAck(PL_state *state, int retries)
{
uint8_t buf[1];
while (--retries >= 0) {
(*state->msleep)(state->serialData, 20);
TByte(state, 0xf9);
TComm(state);
if ((*state->rx_timeout)(state->serialData, buf, 1, ACK_TIMEOUT) > 0)
return buf[0] == 0xfe;
}
return -1; // timeout
}
/* this code is adapted from Chip Gracey's PNut IDE */
int PL_HardwareFound(PL_state *state, int *pVersion)
{
int version, i;
/* initialize the serial buffers */
SerialInit(state);
/* report the start of the handshake phase */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_HANDSHAKE);
/* reset the propeller (includes post-reset delay of 100ms) */
(*state->reset)(state->serialData);
/* transmit the calibration pulses */
TByte(state, 0xf9);
/* transmit the handshake pattern */
state->lfsr = 'P';
for (i = 0; i < 250; ++i)
TByte(state, IterateLFSR(state) | 0xfe);
/* transmit calibration pulses to clock out the connection response and the version byte */
for (i = 0; i < 250 + 8; ++i)
TByte(state, 0xf9);
/* flush the transmit buffer */
TComm(state);
/* report the start of the handshake response phase */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_RESPONSE);
/* receive the connection response */
for (i = 0; i < 250; ++i) {
int bit = RBit(state, 100);
if (bit < 0)
return LOAD_STS_TIMEOUT;
else if (bit != IterateLFSR(state))
return LOAD_STS_ERROR;
}
/* report the start of the version phase */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_VERSION);
/* receive the chip version */
for (version = i = 0; i < 8; ++i) {
int bit = RBit(state, 50);
if (bit < 0)
return LOAD_STS_TIMEOUT;
version = ((version >> 1) & 0x7f) | (bit << 7);
}
*pVersion = version;
/* report handshake completion */
if (state->progress)
(*state->progress)(state->progressData, LOAD_PHASE_HANDSHAKE_DONE);
/* return successfully */
return LOAD_STS_OK;
}
/* SerialInit - initialize the serial buffers */
static void SerialInit(PL_state *state)
{
state->txcnt = 0;
state->rxnext = 0;
state->rxcnt = 0;
}
/* TByte - add a byte to the transmit buffer */
static void TByte(PL_state *state, uint8_t x)
{
state->txbuf[state->txcnt++] = x;
if (state->txcnt >= sizeof(state->txbuf))
TComm(state);
}
/* TLong - add a long to the transmit buffer */
static void TLong(PL_state *state, uint32_t x)
{
int i;
for (i = 0; i < 11; ++i) {
#if 0
// p2 code
uint8_t byte = 0x92
| ((i == 10 ? -1 : 0) & 0x60)
| ((x >> 31) & 1)
| (((x >> 30) & 1) << 3)
| (((x >> 29) & 1) << 6);
TByte(state, byte);
x <<= 3;
#else
// p1 code
uint8_t byte = 0x92
| ((i == 10 ? -1 : 0) & 0x60)
| (x & 1)
| ((x & 2) << 2)
| ((x & 4) << 4);
TByte(state, byte);
x >>= 3;
#endif
}
}
/* TComm - write the transmit buffer to the port */
static void TComm(PL_state *state)
{
(*state->tx)(state->serialData, state->txbuf, state->txcnt);
state->txcnt = 0;
}
/* RBit - receive a bit with a timeout */
static int RBit(PL_state *state, int timeout)
{
int result;
for (;;) {
if (state->rxnext >= state->rxcnt) {
state->rxcnt = (*state->rx_timeout)(state->serialData, state->rxbuf, sizeof(state->rxbuf), timeout);
if (state->rxcnt <= 0) {
/* hardware lost */
return -1;
}
state->rxnext = 0;
}
result = state->rxbuf[state->rxnext++] - 0xfe;
if ((result & 0xfe) == 0)
return result;
/* checksum error */
}
}
/* IterateLFSR - get the next bit in the lfsr sequence */
static int IterateLFSR(PL_state *state)
{
uint8_t lfsr = state->lfsr;
int result = lfsr & 1;
state->lfsr = ((lfsr << 1) & 0xfe) | (((lfsr >> 7) ^ (lfsr >> 5) ^ (lfsr >> 4) ^ (lfsr >> 1)) & 1);
return result;
}
/* end of code adapted from Chip Gracey's PNut IDE */