-
Notifications
You must be signed in to change notification settings - Fork 18
/
ucp.c
245 lines (224 loc) · 6.7 KB
/
ucp.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
#include "ucp.h"
#include "usi.h"
#include "uif.h"
#include "version.h"
#include "crd.h"
#include "fls.h"
#include "hid_defines.h"
#include <stdint.h>
#include <string.h>
#include <avr/pgmspace.h>
/* public variables */
uint8_t UCP_state;
ucp_pkt_t customReport;
volatile uint8_t tempBuff[SPM_PAGESIZE];
volatile uint16_t flashWriteAddr;
volatile uint8_t buffIndex;
volatile uint8_t usbWrite = 0;
volatile uint8_t usbWriteAccepted = 0;
volatile uint8_t lockAfterSetPin=0;
/* INFO Data, the first byte is for cmd */
typedef struct
{
uint8_t versionMajor;
uint8_t versionMinor;
uint8_t versionPatch;
uint16_t credSize;
uint16_t dummy;
} info_t;
const info_t INFO_data PROGMEM ={
.versionMajor = MEMTYPE_VERSION_MAJOR,.versionMinor = MEMTYPE_VERSION_MINOR,.versionPatch = MEMTYPE_VERSION_PATCH,.credSize = MAX_CRED_FLASH_SIZE,.dummy = 0
};
//READ COMMAND variables
uint16_t readOffset=0;
uint16_t readEnd=0;
uint8_t readType = 0; // 0 - Flash, 1 - RAM
void UCP_Init(void){
UCP_state = DEVICE_LOCKED;
return; //nothing to do yet ;)
}
void UCP_Task(void){
switch(UCP_state)
{
case WRITE_EEPROM:
case IDLE:
case DEVICE_LOCKED:
break;
case READING_CMD:
UCP_state++;
break;
case READING:
if(readOffset < readEnd)
{
if(readType==0) {
memcpy_P((void*)&customReport.buf, (void*)(credentials+readOffset), 8);
}
else if (readType==1) {
memcpy((void*)&customReport.buf, (void*)(readOffset), 8);
}
else /*if(readType==2)*/ {
eeprom_read_block((void*)&customReport.buf, (void*)(readOffset), 8);
}
readOffset += 8;
if(readOffset >= readEnd)
{
UCP_state = IDLE;
}
}
else
{
UCP_state = IDLE;
customReport.buf[0] = UCP_CMD_ERROR;
customReport.buf[1] = UCP_ERR_PROTOCOL;
}
break;
case WRITTING:
if(usbWriteAccepted == 1)
{
usbWrite = 1;
usbWriteAccepted = 0;
}
break;
default: //should not arrive here,Ignore
break;
}
}
/* Decoding a received message */
void UCP_Decode(uint8_t *data, uint8_t len){
/* Always return the same command data except if error occour */
memcpy((void*)customReport.buf, (void*)data, sizeof(customReport.buf));
//Validate packet
if(len != 8) { //UCP packets are 8 byte size
customReport.buf[0]=UCP_CMD_ERROR;
customReport.buf[1]=UCP_ERR_SIZE;
}
else if (UCP_state == DEVICE_LOCKED)
{
customReport.buf[0]=UCP_CMD_ERROR;
customReport.buf[1]=UCP_ERR_LOCKED;
}
else if (UCP_state == WRITTING)
{
if( (usbWrite == 0) && (readOffset < readEnd))
{
usbWriteAccepted = 1; // flag indicating a write must be done
}
else
{
UCP_state = IDLE;
customReport.buf[0] = UCP_CMD_ERROR;
customReport.buf[1] = UCP_ERR_PROTOCOL;
usbWriteAccepted = 0;
usbWrite = 0;
}
}
else if (UCP_state == WRITE_EEPROM)
{
if(readOffset < readEnd)
{
eeprom_update_block ((void*)customReport.buf, (void*)readOffset, 8);
readOffset += 8;
/* end of WRITE */
if( readOffset >= readEnd )
{
if(lockAfterSetPin){
UIF_Init();
lockAfterSetPin=0;
} else{
UCP_state = IDLE;
}
}
}
else
{
UCP_state = IDLE;
customReport.buf[0] = UCP_CMD_ERROR;
customReport.buf[1] = UCP_ERR_PROTOCOL;
}
}
else
{
switch(data[0])
{
case UCP_CMD_RESET:
break;
case UCP_CMD_READ:
if(UCP_state==IDLE) { //TO START READING MUST BE IDLE
UCP_state = READING_CMD;
readOffset = *(uint16_t*)&data[1];
readEnd = readOffset + *(uint16_t*)&data[3];
readType = *(uint8_t*)&data[5];
}else{ //PROTOCOL ERROR
UCP_state = IDLE;
customReport.buf[0] = UCP_CMD_ERROR;
customReport.buf[1] = UCP_ERR_PROTOCOL;
}
break;
case UCP_CMD_WRITE:
if(UCP_state==IDLE) { //TO START READING MUST BE IDLE
UCP_state = WRITTING;
readOffset = *(uint16_t*)&data[1];
readEnd = readOffset + *(uint16_t*)&data[3];
buffIndex = 0;
flashWriteAddr = (readOffset+(uint16_t)credentials);
}else{ //PROTOCOL ERROR
UCP_state = IDLE;
customReport.buf[0] = UCP_CMD_ERROR;
customReport.buf[1] = UCP_ERR_PROTOCOL;
}
break;
case UCP_CMD_SET_PIN:
UCP_state = WRITE_EEPROM;
readOffset = (uint16_t)LOCK_HASH;
readEnd = (uint16_t)LOCK_HASH + 16;
lockAfterSetPin=1;
break;
case UCP_CMD_READ_PIN:
UCP_state = READING_CMD;
readOffset = (uint16_t)LOCK_HASH;
readEnd = (uint16_t)LOCK_HASH + 16;
readType = 2; /* Eeprom */
break;
case UCP_CMD_KEYBOARD:
UCP_state = WRITE_EEPROM;
readOffset = (uint16_t)keyboardLUT_ES;
readEnd = (uint16_t)keyboardLUT_ES+KEYBOARD_SIZE;
break;
case UCP_CMD_DATA:
break;
case UCP_CMD_INFO:
memcpy_P((void*)&customReport.buf[1], (void*)&INFO_data, sizeof(INFO_data));
break;
default:
customReport.buf[0] = UCP_CMD_ERROR;
customReport.buf[1] = UCP_ERR_CMD;
}
}
}
void UCP_WriteTask(void){
uint8_t i;
if(usbWrite == 1)
{
for(i=0; i < 8; i++)
{
tempBuff[buffIndex++] = customReport.buf[i]; // fill the temp buffer
readOffset++;
// if it's aligned or end, write to avoid waste of flash cycles
if( ((readOffset%SPM_PAGESIZE) == 0) || (readOffset >= readEnd) )
{
FLS_write((uint8_t*)tempBuff, flashWriteAddr, buffIndex);
flashWriteAddr += (buffIndex);
buffIndex = 0; // resetBufferIndex
/* end of WRITE */
if( readOffset >= readEnd )
{
UCP_state = IDLE;
/* Load Credentials Again */
CRD_Init();
break;
}
}
}
usbWrite = 0;
}
}