Improved async noise model that considers all 9 dbx signals.
[SCSI2SD-V6.git] / src / firmware / config.c
1 //      Copyright (C) 2014 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "config.h"\r
19 #include "led.h"\r
20 \r
21 #include "scsi.h"\r
22 #include "scsiPhy.h"\r
23 #include "sd.h"\r
24 #include "disk.h"\r
25 #include "bootloader.h"\r
26 #include "bsp.h"\r
27 #include "spinlock.h"\r
28 \r
29 #include "../../include/scsi2sd.h"\r
30 #include "../../include/hidpacket.h"\r
31 \r
32 #include "usb_device/usb_device.h"\r
33 #include "usb_device/usbd_hid.h"\r
34 #include "usb_device/usbd_composite.h"\r
35 #include "bsp_driver_sd.h"\r
36 \r
37 \r
38 #include <string.h>\r
39 \r
40 static const uint16_t FIRMWARE_VERSION = 0x0623;\r
41 \r
42 // 1 flash row\r
43 static const uint8_t DEFAULT_CONFIG[128] =\r
44 {\r
45         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00,\r
46         0x00, 0x02, 0x3F, 0x00, 0xFF, 0x00, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x73,\r
47         0x72, 0x63, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,\r
48         0x43, 0x53, 0x49, 0x32, 0x53, 0x44, 0x20, 0x31, 0x2E, 0x30, 0x31, 0x32,\r
49         0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,\r
50         0x37, 0x38, 0x00, 0x00\r
51 };\r
52 \r
53 \r
54 static uint8_t s2s_cfg[S2S_CFG_SIZE] S2S_DMA_ALIGN;\r
55 static uint8_t configDmaBuf[512] S2S_DMA_ALIGN; // For SD card writes.\r
56 \r
57 \r
58 enum USB_STATE\r
59 {\r
60         USB_IDLE,\r
61         USB_DATA_SENT\r
62 };\r
63 \r
64 \r
65 static int usbInEpState;\r
66 \r
67 static void s2s_debugTimer();\r
68 \r
69 // Debug timer to log via USB.\r
70 // Timer 6 & 7 is a simple counter with no external IO supported.\r
71 static s2s_lock_t usbDevLock = s2s_lock_init;\r
72 TIM_HandleTypeDef htim7;\r
73 static int debugTimerStarted = 0;\r
74 void TIM7_IRQHandler()\r
75 {\r
76         HAL_TIM_IRQHandler(&htim7);\r
77 }\r
78 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)\r
79 {\r
80         if (s2s_spin_trylock(&usbDevLock)) {\r
81                 s2s_debugTimer();\r
82                 s2s_spin_unlock(&usbDevLock);\r
83         }\r
84 }\r
85 \r
86 void s2s_configInit(S2S_BoardCfg* config)\r
87 {\r
88         usbInEpState = USB_IDLE;\r
89 \r
90         if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)\r
91         {\r
92                 int cfgSectors = (S2S_CFG_SIZE + 511) / 512;\r
93                 BSP_SD_ReadBlocks_DMA(\r
94                         (uint32_t*) &s2s_cfg[0],\r
95                         (sdDev.capacity - cfgSectors) * 512ll,\r
96                         512,\r
97                         cfgSectors);\r
98 \r
99                 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
100 \r
101                 if (memcmp(config->magic, "BCFG", 4))\r
102                 {\r
103                         // Invalid SD card config, use default.\r
104                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
105                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
106                         memcpy(config->magic, "BCFG", 4);\r
107                         config->selectionDelay = 255; // auto\r
108                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
109 \r
110                         memcpy(\r
111                                 &s2s_cfg[0] + sizeof(S2S_BoardCfg),\r
112                                 DEFAULT_CONFIG,\r
113                                 sizeof(S2S_TargetCfg));\r
114                 }\r
115         }\r
116         else\r
117         {\r
118                 // No SD card, use existing config if valid\r
119                 if (memcmp(config->magic, "BCFG", 4))\r
120                 {\r
121                         // Not valid, use empty config with no disks.\r
122                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
123                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
124                         config->selectionDelay = 255; // auto\r
125                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
126                 }\r
127         }\r
128 }\r
129 \r
130 static void debugInit(void)\r
131 {\r
132         if (debugTimerStarted == 1) return;\r
133 \r
134         debugTimerStarted = 1;\r
135         // 10ms debug timer to capture logs over USB\r
136         __TIM7_CLK_ENABLE();\r
137         htim7.Instance = TIM7;\r
138         htim7.Init.Prescaler = 10800 - 1; // 16bit. 108MHz down to 10KHz\r
139         htim7.Init.CounterMode = TIM_COUNTERMODE_UP;\r
140         htim7.Init.Period = 100 - 1; // 16bit. 10KHz down to 10ms.\r
141         htim7.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;\r
142         HAL_TIM_Base_Init(&htim7);\r
143         HAL_TIM_Base_Start_IT(&htim7);\r
144 \r
145         HAL_NVIC_SetPriority(TIM7_IRQn, 10, 0);\r
146         HAL_NVIC_EnableIRQ(TIM7_IRQn);\r
147 }\r
148 \r
149 \r
150 static void\r
151 pingCommand()\r
152 {\r
153         uint8_t response[] =\r
154         {\r
155                 S2S_CFG_STATUS_GOOD\r
156         };\r
157         hidPacket_send(response, sizeof(response));\r
158 }\r
159 \r
160 static void\r
161 sdInfoCommand()\r
162 {\r
163         uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];\r
164         memcpy(response, sdDev.csd, sizeof(sdDev.csd));\r
165         memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));\r
166 \r
167         hidPacket_send(response, sizeof(response));\r
168 }\r
169 \r
170 \r
171 static void\r
172 scsiTestCommand()\r
173 {\r
174         int resultCode = scsiSelfTest();\r
175         uint8_t response[] =\r
176         {\r
177                 resultCode == 0 ? S2S_CFG_STATUS_GOOD : S2S_CFG_STATUS_ERR,\r
178                 resultCode\r
179         };\r
180         hidPacket_send(response, sizeof(response));\r
181 }\r
182 \r
183 static void\r
184 scsiDevInfoCommand()\r
185 {\r
186         uint8_t response[] =\r
187         {\r
188                 FIRMWARE_VERSION >> 8,\r
189                 FIRMWARE_VERSION & 0xff,\r
190                 sdDev.capacity >> 24,\r
191                 sdDev.capacity >> 16,\r
192                 sdDev.capacity >> 8,\r
193                 sdDev.capacity,\r
194                 1 // useSdConfig, always true for V6.\r
195         };\r
196         hidPacket_send(response, sizeof(response));\r
197 }\r
198 \r
199 static void\r
200 debugCommand()\r
201 {\r
202         uint8_t response[32];\r
203         memcpy(&response, &scsiDev.cdb, 12);\r
204         response[12] = scsiDev.msgIn;\r
205         response[13] = scsiDev.msgOut;\r
206         response[14] = scsiDev.lastStatus;\r
207         response[15] = scsiDev.lastSense;\r
208         response[16] = scsiDev.phase;\r
209         response[17] = *SCSI_STS_SCSI;\r
210         response[18] = scsiDev.target != NULL ? scsiDev.target->syncOffset : 0;\r
211         response[19] = scsiDev.target != NULL ? scsiDev.target->syncPeriod : 0;\r
212         response[20] = scsiDev.minSyncPeriod;\r
213         response[21] = scsiDev.rstCount;\r
214         response[22] = scsiDev.selCount;\r
215         response[23] = scsiDev.msgCount;\r
216         response[24] = scsiDev.cmdCount;\r
217         response[25] = scsiDev.watchdogTick;\r
218         response[26] = blockDev.state;\r
219         response[27] = scsiDev.lastSenseASC >> 8;\r
220         response[28] = scsiDev.lastSenseASC;\r
221         response[29] = *SCSI_STS_DBX & 0xff; // What we've read\r
222         response[30] = *SCSI_STS_SELECTED;\r
223         response[31] = *SCSI_STS_DBX >> 8; // What we're writing\r
224         hidPacket_send(response, sizeof(response));\r
225 }\r
226 \r
227 static void\r
228 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)\r
229 {\r
230         if (cmdSize < 517)\r
231         {\r
232                 return; // ignore.\r
233         }\r
234         uint32_t lba =\r
235                 (((uint32_t)cmd[1]) << 24) |\r
236                 (((uint32_t)cmd[2]) << 16) |\r
237                 (((uint32_t)cmd[3]) << 8) |\r
238                 ((uint32_t)cmd[4]);\r
239 \r
240         memcpy(configDmaBuf, &cmd[5], 512);\r
241         BSP_SD_WriteBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
242 \r
243         uint8_t response[] =\r
244         {\r
245                 S2S_CFG_STATUS_GOOD\r
246         };\r
247         hidPacket_send(response, sizeof(response));\r
248 }\r
249 \r
250 static void\r
251 sdReadCommand(const uint8_t* cmd, size_t cmdSize)\r
252 {\r
253         if (cmdSize < 5)\r
254         {\r
255                 return; // ignore.\r
256         }\r
257         uint32_t lba =\r
258                 (((uint32_t)cmd[1]) << 24) |\r
259                 (((uint32_t)cmd[2]) << 16) |\r
260                 (((uint32_t)cmd[3]) << 8) |\r
261                 ((uint32_t)cmd[4]);\r
262 \r
263         BSP_SD_ReadBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
264         hidPacket_send(configDmaBuf, 512);\r
265 }\r
266 \r
267 static void\r
268 processCommand(const uint8_t* cmd, size_t cmdSize)\r
269 {\r
270         switch (cmd[0])\r
271         {\r
272         case S2S_CMD_PING:\r
273                 pingCommand();\r
274                 break;\r
275 \r
276         case S2S_CMD_REBOOT:\r
277                 s2s_enterBootloader();\r
278                 break;\r
279 \r
280         case S2S_CMD_SDINFO:\r
281                 sdInfoCommand();\r
282                 break;\r
283 \r
284         case S2S_CMD_SCSITEST:\r
285                 scsiTestCommand();\r
286                 break;\r
287 \r
288         case S2S_CMD_DEVINFO:\r
289                 scsiDevInfoCommand();\r
290                 break;\r
291 \r
292         case S2S_CMD_SD_WRITE:\r
293                 sdWriteCommand(cmd, cmdSize);\r
294                 break;\r
295 \r
296         case S2S_CMD_SD_READ:\r
297                 sdReadCommand(cmd, cmdSize);\r
298                 break;\r
299 \r
300         case S2S_CMD_DEBUG:\r
301                 if (debugTimerStarted == 0) {\r
302                         debugInit();\r
303                 }\r
304                 debugCommand();\r
305                 break;\r
306 \r
307         case S2S_CMD_NONE: // invalid\r
308         default:\r
309                 break;\r
310         }\r
311 }\r
312 \r
313 void s2s_configPoll()\r
314 {\r
315         s2s_spin_lock(&usbDevLock);\r
316 \r
317         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
318         {\r
319                 usbInEpState = USB_IDLE;\r
320                 goto out;\r
321         }\r
322 \r
323         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
324         {\r
325                 s2s_ledOn();\r
326 \r
327                 // The host sent us some data!\r
328                 uint8_t hidBuffer[USBHID_LEN];\r
329                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
330                 hidPacket_recv(hidBuffer, byteCount);\r
331 \r
332                 size_t cmdSize;\r
333                 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
334                 if (cmd && (cmdSize > 0))\r
335                 {\r
336                         processCommand(cmd, cmdSize);\r
337                 }\r
338 \r
339                 s2s_ledOff();\r
340         }\r
341 \r
342         switch (usbInEpState)\r
343         {\r
344         case USB_IDLE:\r
345                 {\r
346                         uint8_t hidBuffer[USBHID_LEN];\r
347                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
348 \r
349                         if (nextChunk)\r
350                         {\r
351                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
352                                 usbInEpState = USB_DATA_SENT;\r
353                         }\r
354                 }\r
355                 break;\r
356 \r
357         case USB_DATA_SENT:\r
358                 if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
359                 {\r
360                         // Data accepted.\r
361                         usbInEpState = USB_IDLE;\r
362                 }\r
363                 break;\r
364         }\r
365 \r
366 out:\r
367         s2s_spin_unlock(&usbDevLock);\r
368 }\r
369 \r
370 void s2s_debugTimer()\r
371 {\r
372         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
373         {\r
374                 usbInEpState = USB_IDLE;\r
375                 return;\r
376         }\r
377 \r
378         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
379         {\r
380                 uint8_t hidBuffer[USBHID_LEN];\r
381                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
382                 hidPacket_recv(hidBuffer, byteCount);\r
383 \r
384                 size_t cmdSize;\r
385                 const uint8_t* cmd = hidPacket_peekPacket(&cmdSize);\r
386                 // This is called from an ISR, only process simple commands.\r
387                 if (cmd && (cmdSize > 0))\r
388                 {\r
389                         if (cmd[0] == S2S_CMD_DEBUG)\r
390                         {\r
391                                 hidPacket_getPacket(&cmdSize);\r
392                                 debugCommand();\r
393                         }\r
394                         else if (cmd[0] == S2S_CMD_PING)\r
395                         {\r
396                                 hidPacket_getPacket(&cmdSize);\r
397                                 pingCommand();\r
398                         }\r
399                 }\r
400         }\r
401 \r
402         switch (usbInEpState)\r
403         {\r
404                 case USB_IDLE:\r
405                 {\r
406                         uint8_t hidBuffer[USBHID_LEN];\r
407                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
408 \r
409                         if (nextChunk)\r
410                         {\r
411                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
412                                 usbInEpState = USB_DATA_SENT;\r
413                         }\r
414                 }\r
415                 break;\r
416 \r
417                 case USB_DATA_SENT:\r
418                         if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
419                         {\r
420                                 // Data accepted.\r
421                                 usbInEpState = USB_IDLE;\r
422                         }\r
423                         break;\r
424         }\r
425 }\r
426 \r
427 \r
428 \r
429 // Public method for storing MODE SELECT results.\r
430 void s2s_configSave(int scsiId, uint16_t bytesPerSector)\r
431 {\r
432         S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);\r
433         cfg->bytesPerSector = bytesPerSector;\r
434 \r
435         BSP_SD_WriteBlocks_DMA(\r
436                 (uint32_t*) &s2s_cfg[0],\r
437                 (sdDev.capacity - S2S_CFG_SIZE) * 512ll,\r
438                 512,\r
439                 (S2S_CFG_SIZE + 511) / 512);\r
440 }\r
441 \r
442 \r
443 const S2S_TargetCfg* s2s_getConfigByIndex(int i)\r
444 {\r
445         return (const S2S_TargetCfg*)\r
446                 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));\r
447 }\r
448 \r
449 const S2S_TargetCfg* s2s_getConfigById(int scsiId)\r
450 {\r
451         int i;\r
452         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
453         {\r
454                 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);\r
455                 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)\r
456                 {\r
457                         return tgt;\r
458                 }\r
459         }\r
460         return NULL;\r
461 \r
462 }\r
463 \r