2
0

fpgasvc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #include "common.h"
  2. #include "config.h"
  3. #include "pins.h"
  4. #include "fpga.h"
  5. #include "esplink.h"
  6. #include "xmalloc.h"
  7. #include <driver/gpio.h>
  8. #include <driver/spi_common.h>
  9. #include <driver/spi_master.h>
  10. #define FPGA_SPI_HOST FSPI /* SPI2 */
  11. #define FPGA_PRIORITY 10
  12. #define FPGA_SVC_STACK 4096
  13. #define RTC_TIMESYNC_PERIOD (511*configTICK_RATE_HZ)
  14. static spi_bus_config_t spi_bus_config = {
  15. .data0_io_num = PIN_FPGA_IO0,
  16. .data1_io_num = PIN_FPGA_IO1,
  17. .sclk_io_num = PIN_FPGA_CLK,
  18. .data2_io_num = -1,
  19. .data3_io_num = -1,
  20. .data4_io_num = -1,
  21. .data5_io_num = -1,
  22. .data6_io_num = -1,
  23. .data7_io_num = -1,
  24. .max_transfer_sz = 4096,
  25. .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_DUAL
  26. };
  27. #define FPGA_IOV_MAX 4
  28. static void ARDUINO_ISR_ATTR spi_callback(spi_transaction_t *);
  29. static const spi_device_interface_config_t spi_device_interface_config = {
  30. .command_bits = 8,
  31. .address_bits = 32,
  32. .dummy_bits = 0,
  33. .mode = 0,
  34. .cs_ena_pretrans = 0,
  35. .cs_ena_posttrans = 0,
  36. .clock_speed_hz = SPI_MASTER_FREQ_40M,
  37. .spics_io_num = PIN_FPGA_CS,
  38. .flags = SPI_DEVICE_HALFDUPLEX,
  39. .queue_size = FPGA_IOV_MAX,
  40. .post_cb = spi_callback
  41. };
  42. static spi_device_handle_t spi_handle;
  43. static TaskHandle_t fpga_task;
  44. static TimerHandle_t fpga_timesync_timer;
  45. static SemaphoreHandle_t spi_mutex;
  46. static EventGroupHandle_t spi_done_evgroup;
  47. static volatile bool spi_abort_all;
  48. static struct esplink_head head;
  49. #define NOTIFY_INDEX 0
  50. #define NOTIFY_FPGA (1 << 0)
  51. #define NOTIFY_ENABLE (1 << 1)
  52. #define NOTIFY_DISABLE (1 << 2)
  53. #define NOTIFY_TIMESYNC (1 << 3)
  54. #if 0
  55. #define NOTIFY_SPI (1 << 3)
  56. #define NOTIFY_RINGBUF (1 << 4)
  57. #endif
  58. static uint32_t notify_poll_for(uint32_t flags)
  59. {
  60. return ulTaskNotifyValueClearIndexed(NULL, NOTIFY_INDEX, flags);
  61. }
  62. /* This supports multiple flags set */
  63. static uint32_t notify_wait_for(uint32_t flags)
  64. {
  65. uint32_t notify_value;
  66. /* Already received? Might already have been waited for... */
  67. notify_value = notify_poll_for(flags);
  68. while (!(notify_value & flags)) {
  69. xTaskNotifyWaitIndexed(NOTIFY_INDEX, 0, flags,
  70. &notify_value, portMAX_DELAY);
  71. }
  72. return notify_value;
  73. }
  74. static void ARDUINO_ISR_ATTR fpga_notify_from_isr(uint32_t flags)
  75. {
  76. BaseType_t wakeup = pdFALSE;
  77. if (xTaskNotifyIndexedFromISR(fpga_task, NOTIFY_INDEX, flags, eSetBits,
  78. &wakeup) != pdFAIL)
  79. portYIELD_FROM_ISR(wakeup);
  80. }
  81. static void fpga_notify_from_task(uint32_t flags)
  82. {
  83. xTaskNotifyIndexed(fpga_task, NOTIFY_INDEX, flags, eSetBits);
  84. }
  85. static void ARDUINO_ISR_ATTR fpga_interrupt(void)
  86. {
  87. fpga_notify_from_isr(NOTIFY_FPGA);
  88. }
  89. void fpga_timesync_trigger(void)
  90. {
  91. fpga_notify_from_task(NOTIFY_TIMESYNC);
  92. }
  93. static void ARDUINO_ISR_ATTR spi_callback(spi_transaction_t *t)
  94. {
  95. size_t flags = (size_t)t->user;
  96. if (!flags)
  97. return;
  98. BaseType_t wakeup = pdFALSE;
  99. if (xEventGroupSetBitsFromISR(spi_done_evgroup, (size_t)t->user,
  100. &wakeup) != pdFAIL)
  101. portYIELD_FROM_ISR(wakeup);
  102. }
  103. static void fpga_service_task(void *);
  104. static EventGroupHandle_t fpga_service_evgroup;
  105. void fpga_service_enable(bool on)
  106. {
  107. uint32_t flag = on ? NOTIFY_ENABLE : NOTIFY_DISABLE;
  108. fpga_notify_from_task(flag);
  109. xEventGroupWaitBits(fpga_service_evgroup, flag, 0, pdTRUE, portMAX_DELAY);
  110. }
  111. esp_err_t fpga_service_init(void)
  112. {
  113. pinMode(PIN_FPGA_INT, INPUT);
  114. setvar_bool(status_max80_fpga, false);
  115. fpga_service_evgroup = null_check(xEventGroupCreate());
  116. spi_mutex = null_check(xSemaphoreCreateRecursiveMutex());
  117. spi_done_evgroup = null_check(xEventGroupCreate());
  118. /* The ordering here attempts to avoid race conditions... */
  119. if (xTaskCreate(fpga_service_task, "fpga_svc", FPGA_SVC_STACK, NULL,
  120. FPGA_PRIORITY, &fpga_task) != pdPASS)
  121. return ESP_FAIL;
  122. fpga_timesync_timer =
  123. null_check(xTimerCreate("rtc_sync", RTC_TIMESYNC_PERIOD, pdTRUE, NULL,
  124. (TimerCallbackFunction_t)fpga_timesync_trigger));
  125. esplink_init();
  126. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_DISABLE);
  127. return ESP_OK;
  128. }
  129. static bool fpga_link_enable(void)
  130. {
  131. esp_err_t err;
  132. if (spi_handle)
  133. return true; /* Already started */
  134. xEventGroupClearBits(fpga_service_evgroup, NOTIFY_DISABLE);
  135. err = spi_bus_initialize(FPGA_SPI_HOST, &spi_bus_config, SPI_DMA_CH_AUTO);
  136. if (err)
  137. goto init_fail;
  138. err = spi_bus_add_device(FPGA_SPI_HOST, &spi_device_interface_config,
  139. &spi_handle);
  140. if (err)
  141. goto free_bus_fail;
  142. /* Only device on this bus, so acquire it permanently */
  143. err = spi_device_acquire_bus(spi_handle, portMAX_DELAY);
  144. if (err)
  145. goto release_bus_fail;
  146. xEventGroupClearBits(spi_done_evgroup, EVENT_ALL_BITS);
  147. pinMode(PIN_FPGA_INT, INPUT);
  148. attachInterrupt(PIN_FPGA_INT, fpga_interrupt, FALLING);
  149. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_ENABLE);
  150. xSemaphoreGiveRecursive(spi_mutex);
  151. fpga_notify_from_task(NOTIFY_FPGA); /* In case FPGA_INT was already low */
  152. goto done;
  153. release_bus_fail:
  154. spi_bus_remove_device(spi_handle);
  155. spi_handle = NULL;
  156. free_bus_fail:
  157. spi_bus_free(FPGA_SPI_HOST);
  158. init_fail:
  159. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_DISABLE);
  160. done:
  161. return !err;
  162. }
  163. static void fpga_link_disable(void)
  164. {
  165. if (!spi_handle)
  166. return; /* Already stopped */
  167. xEventGroupClearBits(fpga_service_evgroup, NOTIFY_ENABLE);
  168. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  169. detachInterrupt(PIN_FPGA_INT);
  170. spi_device_release_bus(spi_handle);
  171. spi_bus_remove_device(spi_handle);
  172. spi_bus_free(FPGA_SPI_HOST);
  173. spi_handle = NULL;
  174. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_DISABLE);
  175. }
  176. static void fpga_poll_set_time(void);
  177. esp_err_t fpga_send_config(void)
  178. {
  179. char *buf = NULL;
  180. size_t bufsize = head.cfg.buflen;
  181. esp_err_t err = ESP_ERR_NO_MEM;
  182. buf = xmalloc_dma(bufsize);
  183. if (!buf)
  184. goto fail;
  185. if (sysvar_marshall(sysvar_null, sysvar_count, buf, &bufsize,
  186. (uintptr_t)head.cfg.buf) != sysvar_count)
  187. goto fail;
  188. bufsize = (bufsize + 3) & ~3; /* Round to dword */
  189. err = fpga_io_write(FPGA_CMD_IRQ(EL_DIRQ_CONFIG), head.cfg.buf,
  190. buf, bufsize);
  191. fail:
  192. if (buf)
  193. free(buf);
  194. printf("[FPGA] Configuration sent, %zu bytes, status = %u\n", bufsize, err);
  195. return err;
  196. }
  197. static bool fpga_online(void)
  198. {
  199. fpga_io_read(FPGA_CMD_ACK(EL_UIRQ_READY), ESPLINK_HDR_ADDR,
  200. &head, sizeof head);
  201. if (head.magic != ESPLINK_HEAD_MAGIC || head.hlen <= 8) {
  202. printf("[FPGA] Bad header received, magic = 0x%08x len = %u\n",
  203. head.magic, head.hlen);
  204. return false;
  205. }
  206. if (unlikely(head.hlen < sizeof head)) {
  207. /* Clear any fields not provided */
  208. memset((char *)&head + head.hlen, 0, sizeof head - head.hlen);
  209. }
  210. printf("[FPGA] Ready, board = %u.%u fixes %02x fpga %u\n",
  211. head.board.major, head.board.minor,
  212. head.board.fixes, head.board.fpga);
  213. printf("[FPGA] online, signature \"%.*s\"\n",
  214. (int)(sizeof head.signature - 1), head.signature);
  215. esplink_start(&head);
  216. setvar_bool(status_max80_fpga, true);
  217. xSemaphoreGiveRecursive(spi_mutex);
  218. fpga_send_config();
  219. xTimerStart(fpga_timesync_timer, portMAX_DELAY);
  220. fpga_poll_set_time();
  221. return true;
  222. }
  223. static void fpga_offline(void)
  224. {
  225. memset(&head, 0, sizeof head);
  226. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  227. xTimerStop(fpga_timesync_timer, portMAX_DELAY);
  228. setvar_bool(status_max80_fpga, false);
  229. esplink_start(NULL); /* Stop esplink */
  230. }
  231. esp_err_t fpga_iov(const struct fpga_iov *iov, size_t niov)
  232. {
  233. spi_transaction_ext_t trans[FPGA_IOV_MAX];
  234. size_t ntrans = 0;
  235. if (niov > FPGA_IOV_MAX)
  236. return ESP_ERR_INVALID_ARG;
  237. for (size_t i = 0; i < niov; i++) {
  238. const struct fpga_iov *iv = &iov[i];
  239. if (!iv->len && !(iv->cmd & FPGA_CMD_NULL))
  240. continue;
  241. spi_transaction_ext_t *t = &trans[ntrans];
  242. memset(t, 0, sizeof *t);
  243. t->base.flags =
  244. SPI_TRANS_MODE_DIO |
  245. SPI_TRANS_VARIABLE_DUMMY |
  246. SPI_TRANS_MULTILINE_CMD |
  247. SPI_TRANS_MULTILINE_ADDR;
  248. t->base.cmd = iv->cmd;
  249. t->base.addr = iv->iaddr;
  250. if (iv->cmd & FPGA_CMD_RD) {
  251. t->base.rxlength = iv->len << 3;
  252. t->base.rx_buffer = iv->rdata;
  253. /* Emulate partial word read by adding dummy bits for offset */
  254. t->dummy_bits = 16 + ((iv->iaddr & 3) << 2);
  255. if (iv->cmd & FPGA_CMD_STATUS) {
  256. /*
  257. * Include the status "dummy" bits
  258. * THIS REQUIRES THE REMOTE ADDRESS TO BE 32-BIT ALIGNED
  259. */
  260. t->base.rxlength += 32;
  261. t->dummy_bits -= 16;
  262. }
  263. } else {
  264. t->base.length = iv->len << 3;
  265. t->base.tx_buffer = iv->wdata;
  266. }
  267. ntrans++;
  268. }
  269. if (!ntrans)
  270. return ESP_OK;
  271. esp_err_t err = ESP_OK;
  272. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  273. if (!spi_handle) {
  274. err = ESP_FAIL;
  275. goto fail;
  276. }
  277. xEventGroupClearBits(spi_done_evgroup, EVENT_ALL_BITS);
  278. size_t tbit = 1;
  279. for (size_t i = 0; i < ntrans; i++) {
  280. spi_transaction_ext_t *t = &trans[i];
  281. t->base.user = (void *)tbit;
  282. err = spi_device_queue_trans(spi_handle, &t->base, portMAX_DELAY);
  283. if (err) {
  284. ntrans = i;
  285. break;
  286. }
  287. tbit <<= 1;
  288. }
  289. if (likely(ntrans)) {
  290. xEventGroupWaitBits(spi_done_evgroup, tbit-1, pdTRUE, pdTRUE,
  291. portMAX_DELAY);
  292. while (ntrans--) {
  293. /* This is insanely stupid to have to do when not needed */
  294. spi_transaction_t *tp;
  295. spi_device_get_trans_result(spi_handle, &tp, 0);
  296. }
  297. }
  298. fail:
  299. xSemaphoreGiveRecursive(spi_mutex);
  300. return err;
  301. }
  302. esp_err_t fpga_io_write(unsigned int cmd, const volatile void *addr,
  303. const void *data, size_t len)
  304. {
  305. struct fpga_iov iov;
  306. iov.cmd = cmd & ~FPGA_CMD_RD;
  307. iov.addr = addr;
  308. iov.wdata = data;
  309. iov.len = len;
  310. return fpga_iov(&iov, 1);
  311. }
  312. esp_err_t fpga_io_read(unsigned int cmd, const volatile void *addr,
  313. void *data, size_t len)
  314. {
  315. struct fpga_iov iov;
  316. iov.cmd = cmd | FPGA_CMD_RD;
  317. iov.addr = addr;
  318. iov.rdata = data;
  319. iov.len = len;
  320. return fpga_iov(&iov, 1);
  321. }
  322. /*
  323. * This should be executed after getting an EL_UIRQ_TIME notification;
  324. * do this in polling mode for best latency.
  325. */
  326. static void fpga_get_time(void)
  327. {
  328. esp_err_t err;
  329. struct tm tm;
  330. struct timeval tv;
  331. struct tsbuf {
  332. /* These two words are the status word normally considered "dummy" */
  333. uint16_t status;
  334. uint16_t tick;
  335. struct esplink_timesync_buf get;
  336. } tsbuf;
  337. if (!head.tsync) {
  338. fpga_io_status(FPGA_CMD_ACK(EL_UIRQ_TIME));
  339. return;
  340. }
  341. spi_transaction_ext_t trans;
  342. memset(&trans, 0, sizeof trans);
  343. trans.base.flags =
  344. SPI_TRANS_MODE_DIO |
  345. SPI_TRANS_VARIABLE_DUMMY |
  346. SPI_TRANS_MULTILINE_CMD |
  347. SPI_TRANS_MULTILINE_ADDR;
  348. trans.base.rxlength = sizeof tsbuf << 3;
  349. trans.base.rx_buffer = &tsbuf;
  350. trans.base.addr = (size_t)&head.tsync->get;
  351. trans.base.cmd = FPGA_CMD_RD | FPGA_CMD_ACK(EL_UIRQ_TIME);
  352. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  353. err = spi_device_polling_transmit(spi_handle, &trans.base);
  354. xSemaphoreGiveRecursive(spi_mutex);
  355. if (err)
  356. return;
  357. if (time_net_sync_status)
  358. return; /* Ignore time from RTC if SNTP active now */
  359. tm.tm_sec = tsbuf.get.tm.sec2 << 1;
  360. tm.tm_min = tsbuf.get.tm.min;
  361. tm.tm_hour = tsbuf.get.tm.hour;
  362. tm.tm_mday = tsbuf.get.tm.mday;
  363. tm.tm_mon = tsbuf.get.tm.mon - 1;
  364. tm.tm_year = tsbuf.get.tm.year + 80;
  365. tm.tm_isdst = -1; /* Unknown */
  366. /* The third term handles wraparounds due to delay in transit */
  367. tv.tv_sec = mktime(&tm) + (tsbuf.tick >> 15) +
  368. ((tsbuf.get.tick >= tsbuf.tick) << 1);
  369. tv.tv_usec = (((uint32_t)tsbuf.tick << 17) * UINT64_C(1000000)) >> 32;
  370. settimeofday(&tv, NULL);
  371. print_time("[FPGA] Time set from RTC: ", &tv);
  372. }
  373. static void fpga_poll_set_time(void)
  374. {
  375. if (!head.tsync)
  376. return;
  377. if (!time_net_sync_status) {
  378. /* Poll for current time; will call fpga_get_time() later */
  379. fpga_io_status(FPGA_CMD_IRQ(EL_DIRQ_TIME));
  380. return;
  381. }
  382. /* Otherwise transmit time to set the RTC */
  383. esp_err_t err;
  384. struct timeval tv;
  385. struct esplink_timesync_buf tset;
  386. spi_transaction_t trans;
  387. memset(&trans, 0, sizeof trans);
  388. tset.update = 1;
  389. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  390. gettimeofday(&tv, NULL);
  391. const struct tm *tm = localtime(&tv.tv_sec);
  392. tset.tick = ((tv.tv_usec * ((1ULL << (32+15))/1000000+1)) >> 32)
  393. + ((tv.tv_sec & 1) << 15);
  394. tset.tm.sec2 = tm->tm_sec >> 1;
  395. tset.tm.min = tm->tm_min;
  396. tset.tm.hour = tm->tm_hour;
  397. tset.tm.mday = tm->tm_mday;
  398. tset.tm.mon = tm->tm_mon + 1;
  399. tset.tm.year = tm->tm_year - 80;
  400. trans.flags =
  401. SPI_TRANS_MODE_DIO |
  402. SPI_TRANS_MULTILINE_CMD |
  403. SPI_TRANS_MULTILINE_ADDR;
  404. trans.length = sizeof tset << 3;
  405. trans.tx_buffer = &tset;
  406. trans.addr = (size_t)&head.tsync->set;
  407. trans.cmd = FPGA_CMD_WR | FPGA_CMD_IRQ(EL_DIRQ_TIME) |
  408. FPGA_CMD_ACK(EL_UIRQ_TIME);
  409. err = spi_device_polling_transmit(spi_handle, &trans);
  410. xSemaphoreGiveRecursive(spi_mutex);
  411. if (err)
  412. return;
  413. print_time("[FPGA] RTC update: ", &tv);
  414. }
  415. /*
  416. * Get status in polling mode (small transaction, < 256 CPU cycles).
  417. * cmd typically would be IRQ/ACK bits.
  418. */
  419. uint32_t fpga_io_status(unsigned int cmd)
  420. {
  421. spi_transaction_t trans;
  422. memset(&trans, 0, sizeof trans);
  423. trans.flags =
  424. SPI_TRANS_MODE_DIO |
  425. SPI_TRANS_MULTILINE_CMD |
  426. SPI_TRANS_MULTILINE_ADDR |
  427. SPI_TRANS_USE_RXDATA;
  428. trans.cmd = cmd | FPGA_CMD_RD;
  429. trans.addr = 0;
  430. trans.rxlength = 32;
  431. esp_err_t err = ESP_OK;
  432. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  433. err = spi_device_polling_transmit(spi_handle, &trans);
  434. xSemaphoreGiveRecursive(spi_mutex);
  435. return err ? 0 : *(const uint32_t *)trans.rx_data;
  436. }
  437. static int fpga_read_func(token_t token, void *buf, size_t len)
  438. {
  439. const void **pp = token;
  440. const char *p = *pp;
  441. esp_err_t err;
  442. err = fpga_io_read(0, p, buf, len);
  443. if (err)
  444. return -1;
  445. p += len;
  446. *pp = p;
  447. return len;
  448. }
  449. static void fpga_ota_update(void)
  450. {
  451. struct esplink_ota ota;
  452. fpga_io_read(0, head.ota, &ota, sizeof ota);
  453. if (!ota.data)
  454. return;
  455. esp_update(fpga_read_func, &ota.data, ota.len);
  456. fpga_io_status(FPGA_CMD_ACK(EL_UIRQ_OTA)|FPGA_CMD_IRQ(EL_DIRQ_DONE));
  457. reboot_delayed();
  458. }
  459. static void fpga_service_task(void *dummy)
  460. {
  461. (void)dummy;
  462. enum fpga_state {
  463. FPGA_DISABLED, /* FPGA services disabled */
  464. FPGA_OFFLINE, /* FPGA services enabled, waiting for FPGA */
  465. FPGA_ONLINE /* FPGA services active */
  466. } fpga_state = FPGA_DISABLED;
  467. fputs("[FPGA] Starting FPGA services task\n", stdout);
  468. while (1) {
  469. uint32_t notifiers = 0;
  470. uint32_t status;
  471. switch (fpga_state) {
  472. case FPGA_DISABLED:
  473. notifiers = notify_wait_for(NOTIFY_ENABLE);
  474. if ((notifiers & NOTIFY_ENABLE) && fpga_link_enable()) {
  475. fputs("[FPGA] Enabling FPGA services\n", stdout);
  476. fpga_state = FPGA_OFFLINE;
  477. }
  478. break;
  479. case FPGA_OFFLINE:
  480. status = fpga_io_status(FPGA_CMD_IRQ(EL_DIRQ_HELLO));
  481. printf("[FPGA] FPGA status flags = 0x%08x\n", status);
  482. if (!digitalRead(PIN_FPGA_INT)) {
  483. for (unsigned int i = 1; i < 8; i++) {
  484. if (status & (0x100 << i))
  485. status = fpga_io_status(FPGA_CMD_ACK(i));
  486. }
  487. if ((status & 0x301) == 0x300) {
  488. if (fpga_online()) {
  489. fpga_state = FPGA_ONLINE;
  490. break;
  491. }
  492. }
  493. }
  494. notifiers = notify_wait_for(NOTIFY_FPGA|NOTIFY_DISABLE);
  495. break;
  496. case FPGA_ONLINE:
  497. notifiers = notify_wait_for(NOTIFY_FPGA|NOTIFY_DISABLE|
  498. NOTIFY_TIMESYNC);
  499. if (notifiers & NOTIFY_DISABLE) {
  500. fpga_offline();
  501. break;
  502. }
  503. while (!digitalRead(PIN_FPGA_INT)) {
  504. status = fpga_io_status(0);
  505. if ((status & 0x301) != 0x100) {
  506. fpga_offline();
  507. printf("[FPGA] FPGA offline, status = 0x%08x\n", status);
  508. fpga_state = FPGA_OFFLINE;
  509. notifiers = 0;
  510. break;
  511. }
  512. if (status & (0x100 << EL_UIRQ_TIME))
  513. fpga_get_time();
  514. if (status & (0x100 << EL_UIRQ_RINGBUF))
  515. esplink_poll();
  516. if (status & (0x100 << EL_UIRQ_OTA))
  517. fpga_ota_update();
  518. for (unsigned int i = 5; i < 8; i++) {
  519. if (status & (0x100 << i)) {
  520. printf("[FPGA] Invalid interrupt %u received\n", i);
  521. status = fpga_io_status(FPGA_CMD_ACK(i));
  522. }
  523. }
  524. }
  525. if (notifiers & NOTIFY_TIMESYNC)
  526. fpga_poll_set_time();
  527. break;
  528. }
  529. if (notifiers & NOTIFY_DISABLE) {
  530. fputs("[FPGA] Disabling FPGA services\n", stdout);
  531. fpga_link_disable();
  532. fpga_state = FPGA_DISABLED;
  533. }
  534. }
  535. }