Compare commits

..
578 Commits
Author SHA1 Message Date
Sergio R. Caprile b1c2ffe1a0 Merge pull request #3488 from cesanta/fut
fix unit tests
2026-04-01 11:05:28 -03:00
Sergio R. Caprile 9210a762de fix unit tests 2026-04-01 10:30:59 -03:00
Sergio R. Caprile 1620110f50 update version 2026-04-01 08:59:46 -03:00
Sergio R. Caprile 0d882f1b43 patch 2026-03-31 17:38:04 -03:00
Sergio R. Caprile 1bb85799ce fix Makefile 2026-03-25 16:20:01 -03:00
Sergio R. Caprile 12207edd55 Merge pull request #3476 from cesanta/revert-3474-mem
Revert "Make packed fs always available, and manually settable"
2026-03-24 16:24:03 -03:00
Sergio R. Caprile bb37f72a63 Revert "Make packed fs always available, and manually settable" 2026-03-24 16:23:11 -03:00
Sergio R. Caprile b852e0f8c3 Merge pull request #3474 from cesanta/mem
Make packed fs always available, and manually settable
2026-03-24 16:22:33 -03:00
cpq 25dc078af7 Make packed fs always available, and manually settable 2026-03-24 15:03:22 -03:00
Sergio R. Caprile 06f525713f Merge pull request #3473 from cesanta/tests
update tests
2026-03-23 11:45:14 -03:00
Sergio R. Caprile 05ade0ba3c update tests 2026-03-23 11:44:24 -03:00
Sergio R. Caprile ec91eaf0f3 Merge pull request #3472 from cesanta/wifi
update WiFi security definitions
2026-03-20 17:19:25 -03:00
Sergio R. Caprile 8392b9407a update WiFi security definitions 2026-03-20 17:14:38 -03:00
Sergio R. Caprile 60fe567845 Merge pull request #3470 from cesanta/zephyr
fix zephyr tests
2026-03-16 16:30:11 -03:00
Sergio R. Caprile 02e83c77a4 fix zephyr tests 2026-03-16 16:08:34 -03:00
novlean 538a1a9bfa Merge pull request #3469 from cesanta/novlean-patch-1
Add lwIP vs Mongoose benchmark article link
2026-03-16 14:11:02 +00:00
novlean 862fbd0abc Add lwIP vs Mongoose benchmark article link
article
2026-03-16 14:10:46 +00:00
Sergio R. Caprile 2121be1abe Merge pull request #3449 from cesanta/mdns
Obtain IP adress for MDNS automatically
2026-03-13 13:57:14 -03:00
cpq 0c794f19d2 Obtain IP adress for MDNS automatically 2026-03-13 13:47:25 -03:00
Sergio R. Caprile 44ef3b43d2 Merge pull request #3465 from cesanta/volatile
Add volatile to make MIP work on Diab 4.3 for PowerPC
2026-03-12 14:16:40 -03:00
cpq d27e7b3e7e Add volatile to make MIP work with Diab 4.3 on PPC 2026-03-12 13:45:15 -03:00
robertc2000 f0d1800c6b Merge pull request #3462 from cesanta/http-zero-content-len
Content-length not required if request body is empty
2026-03-12 15:40:30 +02:00
robert 81b61d335f Content-length not required if request body is empty 2026-03-12 05:54:21 -04:00
Sergey Lyubka 70f14336f1 Merge pull request #3458 from cesanta/mdnsc
Introduce new mDNS API, add mDNS client example
2026-03-10 19:38:34 +00:00
Sergio R. Caprile 19ea5aba43 Merge pull request #3459 from cesanta/st67w6
Introduce ST67W6 driver
2026-03-09 09:50:19 -03:00
Sergio R. Caprile 2a7fa4cb68 Introduce new mDNS API, add mDNS client example 2026-03-06 11:27:22 -03:00
Sergio R. Caprile 3d094ec921 Introduce ST67W6 driver 2026-03-06 09:05:37 -03:00
Sergio R. Caprile abe19d2367 Merge pull request #3457 from cesanta/cleanup
cleanup source and add some more IPV6 tests
2026-03-03 11:00:56 -03:00
Sergio R. Caprile 2b408e85e9 cleanup source and add some more IPV6 tests 2026-03-03 10:19:52 -03:00
Sergey Lyubka 27897d5514 Merge pull request #3451 from cesanta/dns
add entropy to DNS txnid
2026-03-02 09:38:51 +00:00
cpq dfcfdfd0f7 fix email 2026-02-26 14:49:48 +00:00
Sergio R. Caprile ec032181c6 add entropy to DNS txnid 2026-02-25 11:35:30 -03:00
Sergey Lyubka 1cc6a48eea Merge pull request #3441 from cesanta/certs
Update http-server to load certs from files
2026-02-23 13:50:33 +00:00
cpq 17b4054ea5 Update http-server to load certs from files 2026-02-16 15:45:20 +00:00
Sergio R. Caprile 0ec11128f7 enable Mac WolfSSL tests 2026-02-16 09:38:24 -03:00
Sergio R. Caprile ed0423f79d Merge pull request #3440 from leopoldch/fix/wolfssl-ca-loading
tls: fix WolfSSL CA certificate buffer loading
2026-02-16 09:21:45 -03:00
Léopold Chappuis ba69eb248c tls: fix WolfSSL CA certificate buffer loading 2026-02-13 22:34:13 -05:00
Sergio R. Caprile eefec28b50 Merge pull request #3429 from cesanta/w55rp20
add W55RP20 example
2026-02-13 08:34:48 -03:00
novlean 564c352d0c Merge pull request #3437 from cesanta/novlean-patch-1
Add NXP RW612 OTA Firmware Update link to README
2026-02-11 14:38:37 +00:00
novlean d20eb8b280 Add NXP RW612 OTA Firmware Update link to README
NXP OTA article
2026-02-11 14:38:23 +00:00
Sergio R. Caprile cc617d537d Merge pull request #3436 from cesanta/redirect
provide local info, fix redirect example
2026-02-09 14:51:03 -03:00
Sergio R. Caprile 205d4c6832 provide local info, fix redirect example 2026-02-09 14:42:31 -03:00
robertc2000 18cea946f1 Merge pull request #3435 from cesanta/mqttprop-fix
Improve mqtt props bound checks
2026-02-09 13:11:11 +02:00
robert 0884338b2a Improve mqtt props bound checks 2026-02-09 04:54:58 -05:00
Sergey Lyubka ba768693ed Merge pull request #3432 from cesanta/fuzzbound
validate props, fuzz them
2026-02-06 15:39:14 +00:00
Sergey Lyubka 3170261876 Merge pull request #3431 from cesanta/renesas
fix RA6M4
2026-02-06 15:36:47 +00:00
Sergio R. Caprile 2d7e8aa712 validate props, fuzz them 2026-02-06 10:53:25 -03:00
Sergio R. Caprile c083f204fc fix RA6M4 2026-02-05 15:14:18 -03:00
Sergio R. Caprile e83e13d8c6 add W55RP20 example 2026-02-05 10:45:27 -03:00
Sergio R. Caprile 70d268d95f Merge pull request #3428 from cesanta/teeleese
Fix long standing certverify failure TLS bug
2026-02-03 15:55:28 -03:00
Sergio R. Caprile 71f5556de7 standardize Makefile 2026-02-03 15:41:47 -03:00
Sergio R. Caprile 8c64266f95 Fix long standing certverify failure TLS bug 2026-02-03 15:26:38 -03:00
cpq 124b4e93c7 Switch off buffering 2026-02-02 09:56:07 +00:00
cpq e01eeed303 update 2026-02-02 08:04:39 +00:00
cpq 4b3cfb4bc0 update 2026-02-02 08:03:55 +00:00
cpq e5dfbec36d update 2026-02-02 08:03:28 +00:00
cpq be1587a933 update 2026-02-02 08:03:09 +00:00
cpq 3e87f18a29 update 2026-02-02 08:02:36 +00:00
cpq 2214cf66a4 update 2026-02-02 08:02:09 +00:00
cpq 7b886ccbde update 2026-02-02 08:01:22 +00:00
cpq b69b288d6c better clean 2026-02-01 13:21:00 +00:00
cpq 37fe251d31 Update readme 2026-01-31 13:22:37 +00:00
Sergio R. Caprile 5ec7ec141a Merge pull request #3427 from cesanta/tests
split nightly tests, fix some
2026-01-30 14:00:07 -03:00
Sergio R. Caprile e31079e107 split nightly tests, fix some 2026-01-30 13:58:04 -03:00
Sergio R. Caprile 1701fb0d03 Merge pull request #3425 from cesanta/vc98
Make built-in TLS c89-friendly
2026-01-30 12:46:59 -03:00
cpq f2ce01641e Make built-in TLS vc98-friendly 2026-01-30 11:40:26 -03:00
Sergio R. Caprile b5e4eef966 Merge pull request #3424 from cesanta/tls
Read out all pending TLS data
2026-01-30 11:25:17 -03:00
cpq b93822fc50 Read out all pending TLS data 2026-01-30 10:54:06 -03:00
Sergio R. Caprile 715f98c546 Merge pull request #3426 from cesanta/checksum
Add checksum validation
2026-01-28 13:26:00 -03:00
Sergio R. Caprile b1878dc9d0 Add checksum validation 2026-01-28 13:14:48 -03:00
Sergey Lyubka fe8cf7d9d6 Merge pull request #3423 from cesanta/singleton
Add http singleton client example
2026-01-28 14:50:27 +00:00
cpq 5fa6b0a6ef Add http singleton client example 2026-01-28 14:33:34 +00:00
Sergey Lyubka d3ab638e5d Merge pull request #3422 from cesanta/redir
Add http redirect example
2026-01-28 14:29:24 +00:00
cpq 44e773af54 Add http redirect example 2026-01-28 10:29:46 +00:00
Sergio R. Caprile ece3f43f34 Merge pull request #3421 from cesanta/becksum
Becksum
2026-01-27 10:40:30 -03:00
Sergio R. Caprile edd1350864 make tests big-endian- and Docker-friendly 2026-01-27 10:32:50 -03:00
Sergio R. Caprile 8e0ef3ca5c rewrite L4 checksum calculation 2026-01-27 10:32:50 -03:00
Sergio R. Caprile b74913ded5 Merge pull request #3418 from cesanta/down
Fast fail mg_connect() if network is down
2026-01-27 09:50:54 -03:00
Sergio R. Caprile 42abbb7e55 Merge pull request #3417 from cesanta/ota
Add OTA over mqtt example
2026-01-27 09:01:56 -03:00
cpq a4869febf6 Add OTA over mqtt example 2026-01-27 10:51:37 +00:00
cpq b10355a536 Fast fail mg_connect() if network is down 2026-01-27 10:46:42 +00:00
cpq e86d4da129 Export mg_pfn_iobuf_noresize 2026-01-24 11:32:32 +00:00
cpq 46ad050cea Less noisy tls_builtin 2026-01-23 06:47:39 +00:00
robertc2000 2a7cf8d5a7 Merge pull request #3416 from cesanta/tests-xq
install xq
2026-01-22 16:39:33 +02:00
robert 07fd086230 install xq 2026-01-22 09:15:33 -05:00
Sergio R. Caprile f040d094ea Merge pull request #3414 from cesanta/addnochacha
add test for no chacha20
2026-01-21 15:08:05 -03:00
Sergio R. Caprile f101d1422a add test for no chacha20 2026-01-21 15:06:24 -03:00
Sergio R. Caprile 6631c5db87 Merge pull request #3413 from cesanta/fixbe
fix one too many checks in chacha20
2026-01-21 14:51:03 -03:00
Sergio R. Caprile c429a0dc56 fix one too many checks in chacha20 2026-01-21 14:42:55 -03:00
Sergio R. Caprile 3f59974639 Merge pull request #3412 from cesanta/unbreak
unbreak stuff after last commit
2026-01-20 18:58:12 -03:00
Sergio R. Caprile c10a88b64b unbreak stuff after last commit 2026-01-20 18:40:36 -03:00
cpq d5e5b3397d Add RSA & chain support 2026-01-20 18:23:58 +00:00
Sergio R. Caprile ab83acf2d1 Merge pull request #3411 from cesanta/rndvc98
Fix rnd stuff in vc98 image
2026-01-16 10:47:26 -03:00
Sergio R. Caprile 1db25117b0 Fix rnd stuff in vc98 image 2026-01-16 10:27:13 -03:00
novlean bd1271dd41 Merge pull request #3410 from cesanta/novlean-patch-1
Add STM32 Ethernet and caches article link
2026-01-15 13:42:12 +00:00
novlean 5dddbb3fce Add STM32 Ethernet and caches article link
new article
2026-01-15 13:42:00 +00:00
Sergio R. Caprile a28decbef4 Merge pull request #3409 from cesanta/eseenetepe
Allow more than 1 address in received DHCP options
2026-01-14 17:40:25 -03:00
Sergio R. Caprile 73d9c125c0 Allow more than 1 address in received DHCP options 2026-01-14 17:30:48 -03:00
Sergio R. Caprile 667abfb5e1 disable failing tests (issues created) 2026-01-14 16:59:24 -03:00
Sergey Lyubka 8c65c2f9af Merge pull request #3407 from cesanta/unsub
Add mg_mqtt_unsub()
2026-01-14 11:17:50 +00:00
cpq f36205e65f Add mg_mqtt_unsub() 2026-01-14 04:36:50 -05:00
Sergio R. Caprile e2c0b2b477 Merge pull request #3406 from cesanta/reserved
allow creative usage of TCP reserved space in 'flags'
2026-01-12 13:56:18 -03:00
Sergio R. Caprile 29254ce84b allow creative usage of TCP reserved space in 'flags' 2026-01-12 12:27:36 -03:00
Sergio R. Caprile 1a0716ae4d Merge pull request #3404 from cesanta/der
Allow comments in PEM
2026-01-12 11:58:41 -03:00
Sergio R. Caprile e46ee68a95 nit 2026-01-12 10:55:40 -03:00
Sergio R. Caprile db496fd7dd remove respective old comment 2026-01-12 10:54:15 -03:00
cpq 0a3e129527 Allow comments in PEM 2026-01-12 10:54:15 -03:00
Sergio R. Caprile 12491777bb Merge pull request #3405 from cesanta/cache7
Synopsys driver handles STM32H7 and N6 DCACHE
2026-01-12 10:52:49 -03:00
Sergio R. Caprile ad4b87e24a Synopsys driver handles STM32H7 and N6 DCACHE
(proper memory placement required)
2026-01-12 10:25:26 -03:00
Sergio R. Caprile 7ffc51d38e Merge pull request #3398 from cesanta/zeph
Disable dirent in zephyr
2026-01-08 09:22:36 -03:00
cpq c9243c3f47 Disable dirent in zephyr 2026-01-08 08:50:05 +00:00
Sergey Lyubka 0d6c424e62 Merge pull request #3397 from cesanta/cube
Add support for N6 in ARCH_CUBE
2026-01-07 18:16:27 +00:00
Sergio R. Caprile dc9395c904 Add support for N6 in ARCH_CUBE 2026-01-07 14:03:37 -03:00
Sergio R. Caprile 2bb750070a Merge pull request #3395 from cesanta/tests
unbreak net_builtin tests
2026-01-07 10:59:38 -03:00
Sergio R. Caprile 17b0b65cab unbreak net_builtin tests 2026-01-07 10:48:22 -03:00
Sergio R. Caprile b5b63e731c Merge pull request #3394 from cesanta/match
avoid unlikely and harmless but possible read out of bounds
2026-01-07 10:38:42 -03:00
Sergio R. Caprile 7e376bb860 avoid unlikely and harmless but possible read out of bounds 2026-01-07 10:33:34 -03:00
cpq b313d697ff Limit queue fetches 2026-01-07 06:36:44 +00:00
cpq 1cadd2b2aa Fetch multiple frames from the queue 2026-01-07 05:53:55 +00:00
cpq f40b377fff Make MG_TCPIP_WIN tunable 2026-01-07 05:46:39 +00:00
cpq 43509c1781 Enable zephyr dirent 2026-01-06 18:16:54 +00:00
novlean 209d1dd426 Merge pull request #3392 from cesanta/novlean-patch-1
Update copyright year in LICENSE file
2026-01-05 13:00:15 +00:00
novlean 1f9e1a38b5 Update copyright year in LICENSE file
2026
2026-01-05 13:00:04 +00:00
Sergio R. Caprile 69936ac9f6 Merge pull request #3391 from cesanta/lwipdoze
fix lwIP redefinition of nfds_t
2026-01-05 08:48:06 -03:00
Sergio R. Caprile 6de419d14c fix lwIP redefinition of nfds_t 2026-01-02 14:22:55 -03:00
Sergio R. Caprile 1200f50e2e Merge pull request #3382 from cesanta/mcast
Make mcast/bcast consistent across stacks
2025-12-29 14:24:51 -03:00
Sergio R. Caprile 73bec74380 Make mcast/bcast consistent across stacks
Fix net_builtin inconsistency
2025-12-29 14:22:59 -03:00
Sergio R. Caprile f70647e28e Merge pull request #3386 from cesanta/mbed
Mbedtls nits
2025-12-29 13:30:10 -03:00
cpq effa61f9b2 Mbedtls nits 2025-12-29 13:29:27 -03:00
novlean b8bde63554 Merge pull request #3385 from cesanta/novlean-patch-1
Remove RP2350 OTA Firmware Update link from README
2025-12-24 10:08:49 +01:00
novlean 409d3d388a Remove RP2350 OTA Firmware Update link from README 2025-12-24 10:08:37 +01:00
Sergio R. Caprile 2c4bf4cea4 optimize for size, as everyone else 2025-12-23 14:06:06 -03:00
Sergio R. Caprile 1b9c3a0fb0 Merge pull request #3383 from cesanta/zeph
Zephyr nits
2025-12-23 13:45:42 -03:00
cpq 71cc0cfd80 Zephyr nits 2025-12-23 13:12:56 -03:00
Sergio R. Caprile 63da5aa403 Merge pull request #3381 from cesanta/tests
add on-demand test workflow
2025-12-19 14:32:21 -03:00
Sergio R. Caprile cb13900c32 add on-demand test workflow 2025-12-19 14:31:23 -03:00
Sergio R. Caprile 926a0e2cf2 Merge pull request #3380 from cesanta/l2
fix wrong length returned from l2_eth_rx
2025-12-19 14:18:42 -03:00
Sergio R. Caprile 2bfcfeb359 fix wrong length returned from l2_eth_rx 2025-12-19 14:11:13 -03:00
Sergio R. Caprile 16d8e3b4f9 restrict fuzz run time below GH allowed time 2025-12-18 11:03:17 -03:00
Sergio R. Caprile 682fe2c9a0 try extending fuzz running time 2025-12-17 19:12:02 -03:00
Sergio R. Caprile bdd309b10b Merge pull request #3379 from cesanta/moretests
add more tests, fix NDP
2025-12-17 17:45:17 -03:00
Sergio R. Caprile 21fbf9cdc5 add more tests, fix NDP 2025-12-17 17:39:09 -03:00
Sergio R. Caprile 9ed98cecff Merge pull request #3378 from cesanta/fuzz
fix fuzz, add ICMP tests
2025-12-17 17:36:08 -03:00
Sergio R. Caprile ab4e229f57 fix fuzz, add ICMP tests 2025-12-17 13:22:24 -03:00
novlean 7feab86700 Merge pull request #3377 from cesanta/novlean-patch-1
Add STM32 OTA Firmware Update link to README
2025-12-17 15:39:23 +00:00
novlean 6bc0af5dd0 Add STM32 OTA Firmware Update link to README 2025-12-17 15:39:06 +00:00
Sergio R. Caprile 6cb685b700 fix fuzzer 2025-12-16 16:46:03 -03:00
cpq 5c582c35d8 ota_frdm -> ota_rw612 2025-12-16 05:10:34 +00:00
Sergey Lyubka 10ab9ae1ea Merge pull request #3370 from cesanta/l2
Decouple from Ethernet, introduce "l2"
2025-12-15 14:49:56 +00:00
cpq 756d127cab C89 nitpick 2025-12-15 10:03:12 +00:00
Sergio R. Caprile a49eb47a91 Merge pull request #3373 from cesanta/mbedtls4
Add support for MbedTLS 4
2025-12-12 20:23:43 -03:00
Sergio R. Caprile e15056a9e4 Add support for MbedTLS 4 2025-12-12 20:19:36 -03:00
Sergio R. Caprile 66d4069644 Decouple from Ethernet, introduce "l2" 2025-12-12 13:46:20 -03:00
novlean 9aae863956 Merge pull request #3369 from cesanta/novlean-patch-1
Remove MQTT article link from README
2025-12-11 16:39:09 +00:00
novlean 878ec8a86c Remove MQTT article link from README 2025-12-11 16:38:44 +00:00
Sergio R. Caprile 8fccfca17b Merge pull request #3368 from cesanta/1000m
Add support for GbE
2025-12-10 13:43:01 -03:00
Sergio R. Caprile 69925c774d Add support for GbE 2025-12-10 10:23:47 -03:00
Sergio R. Caprile c1298973e1 Merge pull request #3367 from cesanta/rtl8211
Add support for RTL8211
2025-12-10 09:55:40 -03:00
Sergio R. Caprile bedda34515 Add support for RTL8211 2025-12-10 09:53:55 -03:00
Sergio R. Caprile 767b0ab90b Merge pull request #3366 from cesanta/ip6
Add support for prefix, link local and global in same net
2025-12-08 16:09:35 -03:00
Sergio R. Caprile b0109c3319 Add support for prefix, link local and global in same net 2025-12-08 16:05:32 -03:00
Sergio R. Caprile a42271a088 Merge pull request #3360 from cesanta/tests
fix tests not uploading on failure
2025-12-08 10:56:33 -03:00
Sergio R. Caprile 154e471256 Merge pull request #3361 from cesanta/neats
fix IPv6
2025-12-08 10:32:28 -03:00
cpq bfc411acaf Squash warning 2025-12-07 14:31:28 +00:00
cpq 2acbb0ad62 Using mg_str 2025-12-06 18:59:45 +00:00
Sergio R. Caprile 60ce504489 fix IPv6 2025-12-05 16:22:16 -03:00
Sergio R. Caprile 22b8eda0df fix tests not uploading on failure 2025-12-05 14:19:24 -03:00
Sergio R. Caprile 80ed81583e Merge pull request #3359 from cesanta/tests
fix Wizard-depent tests (track changes)
2025-12-05 13:26:48 -03:00
Sergio R. Caprile ce0c3a0fe7 fix Wizard-depent tests (track changes) 2025-12-05 13:23:43 -03:00
Sergey Lyubka 492c6385da Merge pull request #3358 from cesanta/diab
Add support for Windriver's Diab v4 (stricter C89 w/ extensions)
2025-12-05 10:32:51 +00:00
Sergio R. Caprile 5b023cb85b Add support for Windriver's Diab v4 (stricter C89) 2025-12-04 13:58:49 -03:00
Sergio R. Caprile 4717a15c17 Merge pull request #3357 from cesanta/atonscope
fix mg_aton not setting is_ip6 with scope_ids
2025-12-04 12:22:06 -03:00
Sergio R. Caprile d6e7f8ee83 fix mg_aton not setting is_ip6 with scope_ids 2025-12-04 12:18:45 -03:00
Sergio R. Caprile 17ff656a7d Merge pull request #3354 from cesanta/closefree
do not serve files when closing
2025-12-03 15:39:21 -03:00
Sergio R. Caprile 4e8965cce5 do not serve files when closing 2025-12-03 14:25:55 -03:00
Sergey Lyubka b3d27a3c43 Merge pull request #3353 from cesanta/safety-net
Add safety nets for lousy networks
2025-12-03 15:49:41 +00:00
Sergio R. Caprile 66dcca9392 Add safety nets for lousy networks 2025-12-03 11:31:47 -03:00
Sergio R. Caprile 0f1a3cf84b Merge pull request #3348 from cesanta/dhcp
allow no options in DHCP msgs
2025-12-01 10:46:40 -03:00
Sergio R. Caprile a4b7025396 allow no options in DHCP msgs 2025-12-01 10:46:03 -03:00
Sergey Lyubka 9c148fd47e Merge pull request #3351 from cesanta/dnssd
Introduce DNS-SD using mDNS
2025-12-01 10:10:17 +00:00
Sergio R. Caprile 293d8c22e1 Introduce DNS-SD using mDNS 2025-11-28 16:12:08 -03:00
Sergio R. Caprile 5f2ff680d5 Merge pull request #3350 from cesanta/portenta
fix Portenta Cube after cyw.h updates
2025-11-27 17:09:43 -03:00
Sergio R. Caprile 8eaca9437e fix Portenta Cube after cyw.h updates 2025-11-27 17:08:00 -03:00
cpq 6e72bf4b5f less verbose cyw driver 2025-11-26 16:27:51 +00:00
cpq 710e7b2004 less verbose cyw driver 2025-11-26 16:24:16 +00:00
Sergio R. Caprile 666a3b68e9 update mip test 2025-11-24 16:11:00 -03:00
Sergio R. Caprile 02e97adbef no router => no route 2025-11-24 15:09:35 -03:00
Sergio R. Caprile 236724ea29 fix mg_send() failing on 0 length 2025-11-19 17:02:28 -03:00
Sergio R. Caprile b503915ca5 update version 2025-11-19 10:04:04 -03:00
Sergio R. Caprile 156db0bc5e enable CYW driver autoinit 2025-11-19 09:57:37 -03:00
Sergey Lyubka 11b6bd7d9c Merge pull request #3338 from cesanta/tls
Fix 2-way auth max msg size, + some neats
2025-11-18 00:46:38 +00:00
Sergio R. Caprile 7ca952faa6 Merge pull request #3342 from cesanta/lsnb4ip
Allow listeners to start before stack is ready
2025-11-17 15:38:38 -03:00
Sergio R. Caprile 4fc40f0ffb Allow listeners to start before stack is ready 2025-11-17 15:23:37 -03:00
cpq cac4b3e254 Fix TM4C warnings on TI compiler (C89) 2025-11-14 06:49:53 +00:00
robert 0d5cb5cbcc undef ENET 2025-11-13 08:02:55 -05:00
Sergio R. Caprile a35901121b Fix 2-way auth max msg size, + some neats 2025-11-12 20:13:06 -03:00
novlean e0740fc2ca Merge pull request #3337 from cesanta/novlean-patch-1
Update README.md
2025-11-10 16:30:57 +00:00
novlean 7d22b5fe18 Update README.md
article 9 added
2025-11-10 16:30:44 +00:00
Sergey Lyubka d2e66ac58d Merge pull request #3325 from cesanta/oom
Handle OOM situations
2025-11-06 14:53:46 +00:00
Sergio R. Caprile 34cc8da87e Merge pull request #3335 from cesanta/mip6
enable IPv6 fuzzing
2025-11-05 19:01:06 -03:00
Sergio R. Caprile 1957ba8ffe Merge pull request #3334 from cesanta/tls
increase TLS fuzz depth
2025-11-05 17:42:29 -03:00
Sergio R. Caprile 72758812f5 increase TLS fuzz depth 2025-11-05 17:41:39 -03:00
Sergio R. Caprile ab5a0c43de enable IPv6 fuzzing 2025-11-05 16:43:51 -03:00
Sergio R. Caprile c8291e4ae9 add OOM handling to apps 2025-11-05 14:01:49 -03:00
Sergio R. Caprile 84e9ea76db wip 2025-11-05 13:55:14 -03:00
Sergio R. Caprile b8994f8bc3 Handle OOM situations in iobuf expansion 2025-11-05 13:53:18 -03:00
Sergio R. Caprile b53d8439e5 Merge pull request #3282 from cesanta/mip6
Introduce IPv6, unit tests pass
2025-11-05 11:58:26 -03:00
Sergio R. Caprile 337e8abf2f Introduce IPv6, unit tests pass 2025-11-05 11:04:23 -03:00
Sergio R. Caprile f0bc1c031f Merge pull request #3331 from cesanta/tls2
TLS: fix resuming handshake, fix improper cert req length
2025-11-04 17:08:34 -03:00
Sergio R. Caprile 19d2b93ec7 add IPaddress type SAN elements 2025-11-04 16:55:03 -03:00
Sergio R. Caprile e0304f2b8f TLS: fix resuming handshake, cert req length, 2-way auth app key generation and handling 2025-11-04 15:35:28 -03:00
Sergey Lyubka f7a86f8cf1 Merge pull request #3328 from cesanta/memory
Add memory management example, o1heap flavor
2025-11-01 17:08:42 +00:00
Sergio R. Caprile 340f0dbf89 Merge pull request #3329 from cesanta/updtst
update cesanta.com CA cert
2025-10-30 14:50:17 -03:00
Sergio R. Caprile d90b62d911 update cesanta.com CA cert 2025-10-30 14:45:20 -03:00
Sergio R. Caprile d84aff6420 Add memory management example, o1heap flavor 2025-10-29 15:51:42 -03:00
Sergio R. Caprile b3b73f4751 Merge pull request #3327 from cesanta/printoom
close connection on OOM when printing
2025-10-29 15:48:57 -03:00
Sergio R. Caprile 3c7b2dcd6d close connection on OOM when printing 2025-10-29 15:41:00 -03:00
Sergio R. Caprile 49470f9bd2 Merge pull request #3326 from cesanta/ethram
Be less intrusive with non-ld-savvy users
2025-10-28 11:06:55 -03:00
Sergio R. Caprile f7cf4f60ef Be less intrusive with non-ld-savvy users 2025-10-28 11:03:58 -03:00
novlean 7e0d06689e Merge pull request #3323 from cesanta/novlean-patch-1
Added new article
2025-10-27 17:53:28 +00:00
novlean b843957bd2 Add link for limiting TCP/IP RAM usage on STM32 2025-10-27 17:53:07 +00:00
Sergio R. Caprile 1a0167eb6d Merge pull request #3322 from cesanta/tests
fix error logs not uploading on test failure
2025-10-27 13:53:17 -03:00
Sergio R. Caprile 6ea3b98941 fix error logs not uploading on test failure 2025-10-27 13:49:35 -03:00
Sergio R. Caprile 4b0b93d4f3 Merge pull request #3307 from cesanta/openssl
improve resiliency
2025-10-13 10:55:42 -03:00
Sergio R. Caprile 64abf061bf improve resiliency 2025-10-13 10:43:45 -03:00
Sergio R. Caprile 05d5c68982 Merge pull request #3304 from cesanta/uniram
uniformize memory attributes
2025-10-13 09:41:52 -03:00
Sergio R. Caprile 235dafe646 Merge pull request #3305 from cesanta/chacha
improve error handling with ChaCha
2025-10-10 14:00:02 -03:00
Sergio R. Caprile 0cc40b0c70 improve error handling with ChaCha 2025-10-10 13:58:53 -03:00
Sergio R. Caprile 07a0d1265b uniformize memory attributes 2025-10-10 11:07:31 -03:00
Sergio R. Caprile 967d746574 fix Espressif deprecating ESP_IF_WIFI_STA and replacing it with WIFI_IF_STA 2025-10-09 11:43:01 -03:00
Sergey Lyubka bd12cb1b87 Merge pull request #3302 from cesanta/stm32h
Allow STM32H driver DMA bufs be placed elsewhere
2025-10-09 14:15:45 +01:00
cpq a21ca5d40b Allow STM32H driver DMA bufs be placed elsewhere 2025-10-09 13:16:50 +01:00
Sergio R. Caprile 2d399107fb Merge pull request #3299 from cesanta/tests
fix Espressif deprecating ESP_IF_WIFI_STA and replacing it with WIFI_…
2025-10-08 10:44:06 -03:00
Sergio R. Caprile 03bfa3806b fix Espressif deprecating ESP_IF_WIFI_STA and replacing it with WIFI_IF_STA (ugly) 2025-10-08 10:32:32 -03:00
Sergio R. Caprile 6536ae9bcc remove corpus 2025-10-08 09:38:27 -03:00
robertc2000 e8fc817a0c Merge pull request #3295 from cesanta/mcxe247
Add NXP MCXE driver support
2025-10-06 11:16:02 +03:00
robert e621ade392 Add NXP MCXE driver support 2025-10-06 04:07:51 -04:00
Sergio R. Caprile 3273c20ca9 Merge pull request #3293 from cesanta/tests
fix for non-64-bit test platforms
2025-10-01 17:25:01 -03:00
Sergio R. Caprile a6b2124fd5 fix for non-64-bit test platforms 2025-10-01 17:06:39 -03:00
Sergio R. Caprile 5a1ff125d7 Merge pull request #3292 from cesanta/tests
fixes for C89 (remove mg_queue_vprintf())
2025-10-01 14:04:54 -03:00
Sergio R. Caprile ad58a48144 fixes for C89 2025-10-01 13:51:37 -03:00
Sergio R. Caprile a205fd7877 Merge pull request #3291 from cesanta/tests
fix fuzzers for IPv6
2025-10-01 11:55:44 -03:00
Sergio R. Caprile 776360ca93 fix fuzzers for IPv6 2025-10-01 11:39:21 -03:00
cpq af7602497d Squash warning 2025-09-30 16:43:41 +01:00
Sergio R. Caprile 0f83c2a6e5 Merge pull request #3290 from cesanta/stm32n6
Add STM32N driver support
2025-09-30 08:20:15 -03:00
robert 0d58748e63 Add STM32N driver support 2025-09-30 03:48:42 -04:00
Sergio R. Caprile 01902bb8b9 Merge pull request #3289 from hgarrereyn/master
fix wrong call and undefined use of va_args in mg_queue_vprintf
2025-09-29 14:08:57 -03:00
Sergey Lyubka e28e9aa1d7 Merge pull request #3287 from cesanta/2way
Fix 2-way auth, fix skip hostname validation
2025-09-29 11:49:18 +01:00
hgarrereyn 587e79dc05 fix use of va_args in mg_queue_vprintf, fixes #3285 2025-09-26 14:28:10 -04:00
Sergio R. Caprile acd65f2340 Merge pull request #3288 from cesanta/iobuf
fix iobuf shrink to less than current len
2025-09-26 14:37:34 -03:00
Sergio R. Caprile d55fb80746 fix iobuf shrink to less than current len 2025-09-26 14:34:17 -03:00
Sergio R. Caprile 4536694f20 Fix 2-way auth, fix skip hostname validation 2025-09-26 13:40:15 -03:00
Sergio R. Caprile 2c5a6d4df6 update tests 2025-09-23 13:32:06 -03:00
Sergio R. Caprile 4c8e219643 Merge pull request #3281 from cesanta/tls36retro
add call to mbedtls_psa_free()for MbedTLS >= 3, defaulting to TLS 1.3…
2025-09-23 13:25:34 -03:00
Sergio R. Caprile daeca8128b add call to mbedtls_psa_free()for MbedTLS >= 3, defaulting to TLS 1.3, retroactively documented in 3.6.1 2025-09-23 11:31:10 -03:00
Sergey Lyubka fe6d357858 Merge pull request #3273 from cesanta/dhcpname
Make DHCP name size configurable
2025-09-20 16:43:36 +01:00
Sergio R. Caprile a99cc3dbaf fix statechange test 2025-09-17 10:45:28 -03:00
Sergio R. Caprile 3c4c04199a fix statechange test 2025-09-17 10:29:06 -03:00
Sergio R. Caprile 8ca692100f tests 2025-09-17 10:18:01 -03:00
Sergio R. Caprile 0b9f28b8e3 Make DHCP name size configurable 2025-09-15 09:40:43 -03:00
Sergio R. Caprile 1dff394b63 unbreak ARP 2025-09-12 11:11:00 -03:00
Sergio R. Caprile f4c35d1036 Merge pull request #3269 from cesanta/wifi612
add support for NXP Wifi in RW612, in an example
2025-09-11 17:51:54 -03:00
Sergio R. Caprile 81c166ad74 add support for NXP Wifi in RW612, in an example 2025-09-11 09:36:04 -03:00
Sergio R. Caprile 1f56776050 compiler nits 2025-09-10 19:27:17 -03:00
Sergio R. Caprile b3a0e7b884 fix extension header traversal 2025-09-10 18:57:15 -03:00
Sergio R. Caprile 8594507b5b Merge pull request #3267 from cesanta/wifi
move debugging logs
2025-09-09 16:24:16 -03:00
Sergio R. Caprile fa811ce12b move debugging logs 2025-09-09 16:20:54 -03:00
Sergio R. Caprile c1ef477ff3 Merge pull request #3266 from cesanta/wifi
Move interface stuff out of user handlers
2025-09-09 14:29:29 -03:00
Sergio R. Caprile 4be3a96987 Merge pull request #3265 from cesanta/alip
align mg_addr to 32- and 64-bits
2025-09-09 10:19:58 -03:00
Sergio R. Caprile 387f875aa1 Move interface stuff out of user handlers 2025-09-08 16:00:44 -03:00
Sergio R. Caprile cc069e7e5d align mg_addr to 32- and 64-bits 2025-09-08 11:43:28 -03:00
Sergey Lyubka df994df611 Merge pull request #3264 from cesanta/opts
Fix IP opts
2025-09-07 15:53:34 +01:00
Sergio R. Caprile 8f77fd3940 fixes for Keil 2025-09-04 19:45:18 -03:00
Sergio R. Caprile 7530062e4b fixes for Keil 2025-09-04 19:43:17 -03:00
Sergio R. Caprile 0e63510708 Fix IP opts
Refactor payload handling
Refactor UDP port unreachable
Add UDP unit tests
Introduce basic IPv6 handling
2025-09-02 15:58:02 -03:00
Sergio R. Caprile 26260a1d88 Merge pull request #3263 from cesanta/tests
building health dashboard
2025-09-02 10:36:31 -03:00
Sergio R. Caprile 9e82844f10 building health dashboard 2025-09-02 10:35:44 -03:00
Sergio R. Caprile 0568b5a75b Merge pull request #3262 from cesanta/tests
Push test results for health dashboard
2025-09-01 15:17:15 -03:00
Sergio R. Caprile 3baabebb34 Push test results for health dashboard 2025-09-01 14:52:37 -03:00
Sergio R. Caprile bf4dd15317 Merge pull request #3261 from cesanta/tests
Start pushing test results for health dashboard
2025-08-29 14:29:50 -03:00
Sergio R. Caprile b0f2f9621a Start pushing test results for health dashboard 2025-08-29 14:28:44 -03:00
Sergey Lyubka 04d6d05e9e Merge pull request #3258 from cesanta/tcput
Fix TCP error handling
2025-08-29 15:18:52 +01:00
Sergio R. Caprile 7339c7dfe7 Fix TCP error handling
Add unit tests for TCP error handling
Account for options in TCP header for payload start address calculation
Take UDP payload length from UDP header
2025-08-29 10:34:17 -03:00
Sergio R. Caprile c1152f5eeb Merge pull request #3255 from cesanta/tests
add support for health dashboard
2025-08-28 14:54:28 -03:00
Sergio R. Caprile 024922d566 add support for health dashboard 2025-08-27 13:35:38 -03:00
Sergio R. Caprile 6f64c8c0de Merge pull request #3254 from cesanta/upwiz
update to new wizard backend API
2025-08-27 08:59:55 -03:00
Sergio R. Caprile 2a5ac3c2e5 update to new wizard backend API 2025-08-26 19:04:10 -03:00
Sergey Lyubka 7b0120f0c2 Merge pull request #3251 from cesanta/backlog
add TCP backlog to handle client MSS
2025-08-23 21:06:12 +01:00
Sergio R. Caprile 7ee1f14a6d add TCP backlog to handle client MSS 2025-08-22 11:42:41 -03:00
Sergio R. Caprile 3aaf7d0da7 Merge pull request #3252 from cesanta/idfbrokeit
handle IDF breaking UART API
2025-08-21 18:21:30 -03:00
Sergio R. Caprile 434f3f8415 handle IDF breaking UART API 2025-08-21 18:15:21 -03:00
Sergio R. Caprile 739d78a45a update version 2025-08-21 13:13:25 -03:00
Sergio R. Caprile 8a62633b2f keep, linked by other examples 2025-08-14 11:38:48 -03:00
Sergio R. Caprile aae1a687a9 Merge pull request #3235 from cesanta/client
Refactor HTTP client
2025-08-14 11:00:23 -03:00
Sergio R. Caprile 61285ec418 cleanup 2025-08-14 10:59:07 -03:00
Sergio R. Caprile a00b3f1c6c Merge pull request #3241 from cesanta/mingw
Fixed mingw build error
2025-08-13 10:48:53 -03:00
robert 2c813f3e72 Fixed mingw build error 2025-08-13 05:17:34 -04:00
Sergio R. Caprile ea68d7a705 Merge pull request #3240 from cesanta/ppp
fix ppp driver
2025-08-12 17:51:40 -03:00
Sergio R. Caprile 654f401038 fix ppp driver 2025-08-12 17:21:36 -03:00
Sergio R. Caprile ad89122a06 Merge pull request #3237 from cesanta/tests
Fix built-in TLS CA bundle, cleanup
2025-08-12 16:34:51 -03:00
Sergio R. Caprile 73ed158e76 Fix built-in TLS CA bundle, cleanup 2025-08-12 16:10:12 -03:00
Sergio R. Caprile 548c3dc77f fix #9f76ea8 breaking bigendian 2025-08-12 15:57:26 -03:00
Sergio R. Caprile c1fa067a1f Merge pull request #3236 from cesanta/tls
Verify host against CN, too
2025-08-12 12:09:23 -03:00
Sergey Lyubka 9fd87060f9 Verify host against CN, too 2025-08-12 15:49:08 +01:00
Sergey Lyubka de0a3b035a Refactor HTTP client 2025-08-12 09:21:38 +01:00
Sergey Lyubka 9f76ea8030 CHACHA20 -> MG_ENABLE_CHACHA20 2025-08-12 08:42:20 +01:00
Sergio R. Caprile 76b7356873 Zephyr wants _DEBUG to provide mbedtls_strerror() 2025-08-11 13:23:51 -03:00
novlean c24d5aabd8 Merge pull request #3231 from cesanta/novlean-patch-2
Update README.md
2025-08-06 14:38:25 +01:00
novlean 0df6645b90 Update README.md 2025-08-06 14:38:11 +01:00
Sergey Lyubka b19cf8654f Merge pull request #3203 from cesanta/dns
Built-in TCP/IP (re-)starts DNS connection on DHCP link up
2025-08-01 12:13:39 +01:00
Sergey Lyubka 19933a4673 Merge pull request #3222 from cesanta/mbedrbose
Add verbose MbedTLS errors
2025-08-01 12:10:20 +01:00
Sergio R. Caprile 76963f7d01 Merge pull request #3229 from cesanta/tests
fix possible overflow, improve tests
2025-07-31 13:50:42 -03:00
Sergio R. Caprile e670ea3d61 fix possible overflow, improve tests 2025-07-31 13:43:18 -03:00
Sergio R. Caprile fa33b57e4f Merge pull request #3228 from cesanta/tests
mask built-in TCP/IP with WolfSSL test
2025-07-30 17:10:16 -03:00
Sergio R. Caprile 77e369bc79 mask built-in TCP/IP with WolfSSL test 2025-07-30 17:09:42 -03:00
Sergio R. Caprile 94ad9767d3 Merge pull request #3225 from cesanta/tests
ChaCha20 not working in S390 (bigendian)
2025-07-30 16:15:40 -03:00
Sergio R. Caprile aa76f5673b ChaCha20 not working in S390 (bigendian) 2025-07-30 16:13:34 -03:00
Sergio R. Caprile 81a699c801 Merge pull request #3224 from cesanta/tests
Fix tests
2025-07-29 17:26:07 -03:00
Sergio R. Caprile bd15c456b2 Fix tests
Fix Ubuntu starting Mosquitto right after install
Skip TLS on localhost on MacOS with MbedTLS
fix MQTT_LOCALHOST for built-in TCP/IP tests
2025-07-29 17:17:03 -03:00
Sergio R. Caprile 10d9e1e9ae Merge pull request #3223 from cesanta/zephyr
Improve 4.2 test time
2025-07-29 11:22:56 -03:00
Sergio R. Caprile 6a3813f633 Improve 4.2 test time
fix for intermediate releases
2025-07-29 11:19:16 -03:00
Sergio R. Caprile 51fe22a95f Add verbose MbedTLS errors 2025-07-28 16:18:53 -03:00
Sergio R. Caprile 105762416f Merge pull request #3221 from cesanta/tests
add tests for Zephyr 4.2.0
2025-07-28 15:07:50 -03:00
Sergio R. Caprile db7087f455 add tests for Zephyr 4.2.0 2025-07-28 14:43:09 -03:00
Sergio R. Caprile c5693503cb Merge pull request #3220 from cesanta/zephyr
update to Zephyr 4.2.0
2025-07-28 11:26:03 -03:00
Sergio R. Caprile b74590a4a5 update to Zephyr 4.2.0 2025-07-28 11:25:02 -03:00
Sergio R. Caprile d5eeed48eb Merge pull request #3219 from cesanta/tests
workaround GH storage
2025-07-28 10:44:53 -03:00
Sergio R. Caprile fc5c0d0964 workaround GH storage 2025-07-28 10:28:18 -03:00
robert aa2647c0bc clang format 2025-07-28 04:11:22 -04:00
robertc2000 cef0acdb40 Merge pull request #3218 from cesanta/same54-driver-update
Update same54 driver
2025-07-28 11:07:47 +03:00
robert 2140656acc Update same54 driver 2025-07-28 03:55:00 -04:00
Sergio R. Caprile fd0c969f16 Merge pull request #3217 from cesanta/tests
move Zephyr tests to their own script
2025-07-25 17:08:19 -03:00
Sergio R. Caprile dfeb929e0e move Zephyr tests to their own script 2025-07-25 17:07:06 -03:00
Sergio R. Caprile d3e67733a6 Merge pull request #3216 from cesanta/tests
Tests
2025-07-25 11:44:36 -03:00
Sergio R. Caprile eff74fdc9d Zephyr: only clean if there's a build 2025-07-25 11:38:30 -03:00
Sergio R. Caprile 5e4c40ad09 remove tailwindcss dependency 2025-07-25 11:33:49 -03:00
Sergio R. Caprile 087e6d3142 Merge pull request #3215 from cesanta/tests
fix mingw[++] tests, add local MQTTS
2025-07-24 18:43:57 -03:00
Sergio R. Caprile 587b074822 fix mingw[++] tests, add local MQTTS 2025-07-24 18:42:14 -03:00
Sergio R. Caprile 6aa8c01ac7 fix TLS text 2025-07-24 17:11:19 -03:00
Sergio R. Caprile 3bbcd5df3e Merge pull request #3214 from cesanta/tests
introduce local MQTT server, fix container calling, fill prerequisites
2025-07-24 16:10:08 -03:00
Sergio R. Caprile af512c57ef introduce local MQTT server, fix container calling, fill prerequisites 2025-07-24 15:54:58 -03:00
Sergio R. Caprile 58297a7871 remove obsolete example 2025-07-24 11:25:11 -03:00
Sergio R. Caprile 18a530048c Increase MQTT connect expected time 2025-07-24 10:15:09 -03:00
Sergio R. Caprile f9ed75d6b3 attempt to get reasons 2025-07-23 10:53:00 -03:00
Sergio R. Caprile 3c1f41e575 disable scheduled run 2025-07-23 10:33:51 -03:00
Sergio R. Caprile c772936dd1 enable manual run 2025-07-23 10:31:07 -03:00
Sergio R. Caprile 253696be45 Merge pull request #3213 from cesanta/tests
disable hw tests on quick test
2025-07-23 10:27:12 -03:00
Sergio R. Caprile 79b7accc55 disable hw tests on quick test 2025-07-23 10:26:34 -03:00
Sergio R. Caprile 7a1e846c73 Merge pull request #3211 from cesanta/ooofin
Fix ignoring SEQ on FIN
2025-07-23 08:34:05 -03:00
Sergio R. Caprile ce59ff89c3 Merge pull request #3212 from cesanta/tests
fix sh not being bash
2025-07-22 18:03:00 -03:00
Sergio R. Caprile d31d064d5e fix sh not being bash 2025-07-22 17:01:01 -03:00
Sergio R. Caprile 467fbf4bb4 Fix ignoring SEQ on FIN 2025-07-22 14:16:35 -03:00
Sergey Lyubka 6769223ce1 Nitpick: rename fn -> mqtt_ev_handler 2025-07-22 10:11:20 +01:00
Sergey Lyubka 294e483885 Nitpick: rename s_conn -> s_mqtt_conn 2025-07-22 10:10:14 +01:00
Sergey Lyubka 43513e2d56 Update MQTT client: enable keep alive, use rx/tx topics 2025-07-22 09:44:43 +01:00
Sergey Lyubka d1b7687e98 Fix comments 2025-07-21 23:01:43 +01:00
Sergey Lyubka 9ac09da1d2 Remove mg_http_run_simple_server - move to docs 2025-07-21 14:03:12 +01:00
Sergey Lyubka 24a330c750 Nits 2025-07-20 12:49:58 +01:00
Sergey Lyubka 13a9c773f2 mg_hello -> mg_http_run_simple_server() 2025-07-20 09:36:34 +01:00
Sergey Lyubka 3cd166d065 MG_ARCH_CUBE nitpicks 2025-07-19 08:33:48 +01:00
Sergio R. Caprile 490066fd17 Merge pull request #3209 from cesanta/tests
Fix misc warnings and nits
2025-07-18 17:40:53 -03:00
Sergio R. Caprile 94fce72ade Fix misc warnings and nits 2025-07-18 17:08:32 -03:00
Sergio R. Caprile eacc64bdd1 fix missing def 2025-07-18 16:44:38 -03:00
Sergio R. Caprile 7b037f4957 Merge pull request #3208 from cesanta/cube
Introduce MG_ARCH_CUBE, autodetect everything
2025-07-18 11:22:17 -03:00
Sergio R. Caprile fa841916c1 assorted nit picks 2025-07-18 11:19:58 -03:00
Sergey Lyubka 75c11436ff Introduce MG_ARCH_CUBE, autodetect everything 2025-07-17 17:29:48 +01:00
Sergio R. Caprile e07a8283ec Merge pull request #3207 from cesanta/hal
Autodetect STM32 in mg_millis()
2025-07-16 10:27:37 -03:00
Sergey Lyubka 2a174b0d3b Autodetect STM32 in mg_millis() 2025-07-16 07:38:29 +01:00
Sergey Lyubka 013993abae example configs 2025-07-16 07:37:25 +01:00
Sergey Lyubka dccc153c68 example configs 2025-07-16 07:37:07 +01:00
Sergio R. Caprile db0867f435 Merge pull request #3206 from cesanta/restrict
Avoid trashing VC++'s own proprietary restrict-like keyword
2025-07-15 16:55:52 -03:00
Sergio R. Caprile 7234121835 Avoid trashing VC++'s own propropietary restrict-like keyword 2025-07-15 16:47:06 -03:00
Sergio R. Caprile 3aafc073d8 unbreak after #8a9b1d9 2025-07-15 13:42:48 -03:00
Sergio R. Caprile b527ed313c Merge pull request #3204 from cesanta/tests
Moving tests from GH yaml to bash scripts and Makefiles
2025-07-15 11:27:24 -03:00
Sergio R. Caprile cd86559685 Move tests to bash scripts and Makefiles 2025-07-15 11:24:09 -03:00
Sergio R. Caprile f67e843be6 fix tests 2025-07-15 11:24:09 -03:00
Sergio R. Caprile 4f9ebd8092 Merge pull request #3202 from cesanta/gcc
Rename MG_ARCH_NEWLIB -> MG_ARCH_ARMGCC
2025-07-15 09:08:13 -03:00
Sergey Lyubka 6c044d6aeb Rename MG_ARCH_NEWLIB -> MG_ARCH_ARM_GCC 2025-07-15 11:22:17 +01:00
Sergio R. Caprile c6ee909aa4 uint16_t always >= 0 2025-07-14 15:12:50 -03:00
Sergio R. Caprile 393063428e Built-in TCP/IP (re-)starts DNS connection on link up 2025-07-14 15:06:31 -03:00
Sergio R. Caprile 1494f5e831 Merge pull request #3201 from cesanta/sntp
fix SNTP through proper protocol handler setup
2025-07-14 10:09:47 -03:00
Sergey Lyubka 8bfd0c2ca3 add config template 2025-07-13 07:34:48 +01:00
Sergey Lyubka e9de2f3eb1 Remove gurubase link - useless 2025-07-12 06:50:27 +01:00
Sergio R. Caprile 8bf9d09d96 fix SNTP through proper protocol handler setup 2025-07-11 16:56:12 -03:00
Sergio R. Caprile 67255ce8f5 fix broken links 2025-07-10 09:48:53 -03:00
Sergey Lyubka 5db89aa264 Update help message 2025-07-09 12:58:15 +01:00
Sergey Lyubka 8a9b1d9873 Simplify dashboard 2025-07-09 00:21:31 +01:00
Sergio R. Caprile c08c1afb1e Merge pull request #3198 from cesanta/c89
make it C89-friendly
2025-07-08 14:10:58 -03:00
Sergio R. Caprile 2c7f58aed2 test checksum primitives, enforce rx frag test 2025-07-08 13:57:03 -03:00
Sergio R. Caprile b3ee71acbe make TCP/IP C89-friendly 2025-07-08 11:15:32 -03:00
Sergio R. Caprile 52ab6bc499 make it C89-friendly 2025-07-07 15:15:31 -03:00
Sergio R. Caprile bf059ad42f Merge pull request #3197 from cesanta/select
select() minimum wait is now 1ms
2025-07-07 14:43:52 -03:00
Sergio R. Caprile 85df6a6131 select() minimum wait is now 1ms 2025-07-07 14:40:18 -03:00
Sergio R. Caprile d840b4a4ee Merge pull request #3196 from cesanta/tests
fix tests
2025-07-07 11:33:25 -03:00
Sergio R. Caprile a8c2ce544e fix tests 2025-07-07 11:32:31 -03:00
Sergio R. Caprile b95022a3b3 Merge pull request #3195 from cesanta/sanasan
remove false positive
2025-07-03 11:49:01 -03:00
Sergio R. Caprile 8c45a9d2c9 remove false positive 2025-07-03 10:53:59 -03:00
Sergio R. Caprile 0fe64fbff9 Merge pull request #3194 from cesanta/udpret
mg_send and mg_io_send now honor UDP failures
2025-07-02 17:00:50 -03:00
Sergio R. Caprile 64e806628b Merge pull request #3188 from cesanta/wintls
Fix incorrect reference to a Windows compiler
Fix memory leaks in RSA signature verificator
2025-07-02 16:49:32 -03:00
Sergio R. Caprile ccd2b2699f fix memory leaks in RSA verification function 2025-07-02 16:40:36 -03:00
Sergio R. Caprile 0b5c0c9889 mg_send now honors UDP failures 2025-07-02 10:04:24 -03:00
robertc2000 6293e7dbec Merge pull request #3193 from cesanta/driver-macro
Removed MG_DRIVER_* macros
2025-07-02 13:08:39 +03:00
robert 87325ece82 Removed MG_DRIVER_* macros 2025-07-02 05:03:32 -04:00
Sergio R. Caprile 6cbd9b3067 Merge pull request #3192 from cesanta/freeunix
fix unix detection in wrong place
2025-07-01 16:32:20 -03:00
Sergio R. Caprile aa27fde9d0 fix unix detection in wrong place 2025-07-01 16:28:13 -03:00
Sergio R. Caprile e854585802 Improve Zephyr support 2025-06-30 10:35:53 -03:00
Sergio R. Caprile 2c5aba24cc Merge pull request #3189 from cesanta/zephyrotahack
Improve Zephyr support
2025-06-27 14:13:17 -03:00
Sergio R. Caprile 806ee0f2cb Improve Zephyr support 2025-06-27 14:11:04 -03:00
Sergey Lyubka e72b95fb1c Fix tutorials/http/http-server build with windows gcc 2025-06-27 14:33:44 +01:00
Sergey Lyubka 471e7ff61a Left-align tables 2025-06-26 10:42:47 +01:00
Sergey Lyubka 3d2de154d1 Add support matrix 2025-06-26 10:40:15 +01:00
Sergio R. Caprile fc551ec2e9 Merge pull request #3182 from cesanta/calloc
Introduce mg_calloc and MG_ENABLE_CUSTOM_CALLOC
2025-06-24 16:32:28 -03:00
Sergio R. Caprile f5e2c68c8b update examples 2025-06-24 16:26:31 -03:00
Sergey Lyubka 074ef5197b Introduce mg_calloc 2025-06-24 10:52:44 +01:00
Sergey Lyubka 5f1f4a0df8 malloc -> calloc 2025-06-24 09:12:38 +01:00
Sergey Lyubka 86334e9040 Keep only one listener 2025-06-24 08:57:49 +01:00
Sergey Lyubka f71cc3ebc3 Merge pull request #3173 from cesanta/chachaleak
Avoid chacha20 header leaking its redefinitions
2025-06-18 10:47:19 +01:00
Sergio R. Caprile 00910462e7 Merge pull request #3174 from cesanta/wka
Allow KA from erroneous implementations
2025-06-17 15:17:29 -03:00
Sergio R. Caprile 2fc56dd1d0 Allow KA from erroneous implementations 2025-06-17 15:14:30 -03:00
Sergio R. Caprile a5ebe71394 Avoid chacha20 header leaking its redefinitions 2025-06-17 12:12:48 -03:00
Sergio R. Caprile 0eb8bf6b51 Merge pull request #3167 from cesanta/threadx
Add MG_ARCH_TREADX
2025-06-16 10:51:16 -03:00
Sergey Lyubka 3a0fe5288c Add MG_ARCH_TREADX 2025-06-16 11:09:41 +01:00
Sergey Lyubka bfca233160 Merge pull request #3170 from cesanta/keepack
Add Keep-Alive ACK
2025-06-12 08:37:00 +01:00
Sergio R. Caprile acf217601b Add Keep-Alive ACK 2025-06-11 14:25:05 -03:00
Sergio R. Caprile b0d0fbfd9f clarify bridging for Wi-Fi 2025-06-11 09:31:24 -03:00
Sergio R. Caprile 9411f1c7b6 Merge pull request #3165 from cesanta/wifi612
Add Wi-Fi example for RW-612
2025-06-06 18:39:35 -03:00
Sergio R. Caprile d7d7ebf99a Add Wi-Fi example for RW-612 2025-06-06 18:26:27 -03:00
novlean 8072ae2057 Update README.md 2025-06-06 16:34:19 +01:00
Sergio R. Caprile e529e644ab Merge pull request #3164 from cesanta/asan
avoid ASAN reporting read overflows
2025-06-06 09:03:02 -03:00
Sergio R. Caprile d6fdfe5b1b avoid ASAN reporting read overflows 2025-06-05 17:26:56 -03:00
Sergio R. Caprile 50e15e574f Merge pull request #3163 from cesanta/test
expand test coverage
2025-06-05 14:24:47 -03:00
Sergio R. Caprile 58f1533779 expand test coverage 2025-06-05 14:24:03 -03:00
Sergio R. Caprile f4a49829ea unbreak FreeRTOS (#3158) 2025-06-05 14:03:26 -03:00
Sergio R. Caprile 3efe6641eb Merge pull request #3161 from cesanta/fix
Unbreak MbedTLS (#3148), rollback debugging leftovers
2025-06-04 09:08:32 -03:00
Sergio R. Caprile 0459d9e106 Unbreak MbedTLS (#3148), rollback debugging leftovers 2025-06-04 09:05:27 -03:00
Sergio R. Caprile 305d69ee36 Merge pull request #3159 from cesanta/isacheese
fix error introduced in #3149
2025-06-03 15:41:13 -03:00
Sergio R. Caprile 98e744a9ad fix error introduced in #3149 2025-06-03 15:29:28 -03:00
Sergey Lyubka 1d97f2e2b5 Enable POSIX_FS on ESP32 2025-06-03 08:23:05 +01:00
Sergio R. Caprile c92bc4b4ac Merge pull request #3158 from cesanta/posiz
Redefine mkdir only if MG_ENABLE_POSIX_FS==0
2025-06-02 11:06:09 -03:00
Sergey Lyubka 6a3e1e41c4 Redefine mkdir only if MG_ENABLE_POSIX_FS==0 2025-06-02 11:04:16 -03:00
Sergio R. Caprile 650caface3 fix duplicates 2025-05-30 10:03:01 -03:00
novlean 8b6e02e985 Merge pull request #3154 from cesanta/novlean-patch-2
Update README.md - stm32 websocket article
2025-05-29 17:01:52 +01:00
novlean 3ee6fe45f9 Update README.md 2025-05-29 17:01:05 +01:00
Sergio R. Caprile e811afd397 Merge pull request #3152 from cesanta/fuzzer
fix memory leak in fuzz test itself
2025-05-28 14:36:07 -03:00
Sergio R. Caprile b197a674e1 fix memory leak in fuzz test itself 2025-05-28 13:56:04 -03:00
Sergio R. Caprile 08f6b99b13 remove conditionals from CIfuzz 2025-05-28 11:57:27 -03:00
Sergio R. Caprile b18d0301f3 Update README.md 2025-05-28 11:46:49 -03:00
Sergio R. Caprile 5596621420 Update README.md 2025-05-28 11:05:37 -03:00
Sergio R. Caprile bd8a66eee7 Update README.md
GH changes in icon stuff
2025-05-28 11:02:07 -03:00
Sergio R. Caprile b62ebb3c10 Update README.md
GH changes in build icon
2025-05-28 10:59:57 -03:00
Sergio R. Caprile 45d796fe5b Merge pull request #3151 from cesanta/wonder
Add Portenta H7 STM32CubeIDE example
2025-05-27 17:27:43 -03:00
Sergio R. Caprile d8a3b90cad Add Portenta H7 STM32CubeIDE example 2025-05-27 17:26:26 -03:00
Sergio R. Caprile 5be9e55425 Merge pull request #3142 from cesanta/wonder
Add support for SDIO
2025-05-26 10:07:41 -03:00
Sergio R. Caprile 6b6acd3967 Merge pull request #3149 from cesanta/is_tls
set is_tls at mg_listen and mg_connect level
2025-05-26 10:06:38 -03:00
Sergio R. Caprile 1b06403a19 Add support for SDIO
Add support for SDIO in CYW driver
Add Portenta H7 example
2025-05-26 10:04:44 -03:00
Sergio R. Caprile b740c80855 set is_tls at mg_listen and mg_connect level 2025-05-26 09:42:48 -03:00
Sergey Lyubka 29594283c1 Merge pull request #3148 from cesanta/iowaitormsscapped
flush TLS buffer
2025-05-26 11:38:41 +01:00
Sergio R. Caprile 51f54f9b7e Merge pull request #3147 from cesanta/ra8-eth
RA8 eth and phy support
2025-05-23 14:23:52 -03:00
Sergio R. Caprile 1f48b1ca65 flush TLS buffer 2025-05-23 14:04:59 -03:00
robert fd2d7cccf3 RA8 eth and phy support 2025-05-23 10:15:49 -04:00
Sergio R. Caprile 5726e680ec Merge pull request #3143 from cesanta/fairplay
Make built-in TLS play fair to TCP
2025-05-23 10:22:56 -03:00
Sergio R. Caprile fadf28adb4 Make built-in TLS play fair to TCP
Handshake functions in Mongoose TLS assumed data was being fully sent
after calling mg_io_send(). This was in fact the case with the usual 1460-bytes MSS, but not with the default 536-bytes MSS.
This PR removes all those calls from individual handshake functions, actual send is done at the main handshake function, keeping track of the amount of data sent, and so handling small MTUs/MSSs and possible MG_IO_WAITs when running over a socket layer.
2025-05-22 14:45:46 -03:00
novlean a321c2d096 Merge pull request #3146 from cesanta/novlean-patch-2
Update README.md
2025-05-22 17:59:06 +01:00
novlean bbb07bf6f7 Update README.md 2025-05-22 17:58:42 +01:00
Sergio R. Caprile a801160bc0 collaterals #3140
We prepend current path to the URI, so a tilde could not be the first
char in a path. However, the same would happen for double dots, and
since we're already checking for that, it doesn't hurt to be on the safe
side for future's sake.
2025-05-21 10:43:14 -03:00
Sergio R. Caprile 662cc27f4f Merge pull request #3140 from dag10/master
Fix URIs or header values containing tildes being unparsable.
2025-05-21 09:58:30 -03:00
Sergio R. Caprile ccfe7e0724 update version 2025-05-21 09:46:14 -03:00
Sergio R. Caprile 8061a41b38 workaround 2025-05-19 09:22:59 -03:00
Drew Gottlieb d01aa01a51 Fix URIs or header values containing tildes being unparsable. 2025-05-15 17:13:15 -07:00
Sergio R. Caprile 39392b3690 Merge pull request #3139 from cesanta/freewill
free ifp on mgr_free
2025-05-15 18:04:42 -03:00
Sergio R. Caprile 54d4611eb6 call mg_tcpip_free from mg_mgr_free() 2025-05-15 17:37:40 -03:00
Sergio R. Caprile 34cdce750d Merge pull request #3138 from cesanta/pedantic
make clang happy
2025-05-15 17:11:22 -03:00
Sergio R. Caprile f3fafb6759 make clang happy 2025-05-15 17:09:29 -03:00
Sergio R. Caprile 0372c97ff5 add fuzz 2025-05-15 16:48:16 -03:00
Sergio R. Caprile b46136a0af Merge pull request #3137 from cesanta/testtls
add fuzz tests
2025-05-15 16:33:17 -03:00
Sergio R. Caprile ac3d41fb79 add fuzz tests 2025-05-15 16:32:42 -03:00
Sergio R. Caprile 14be42c868 INFO -> VERBOSE 2025-05-15 15:50:36 -03:00
robertc2000 f0ec14543a Merge pull request #3136 from cesanta/ra6-driver-init
RA6 driver init macro
2025-05-15 10:20:31 +03:00
robert f46c5b7214 RA6 driver init macro 2025-05-15 03:13:49 -04:00
Sergey Lyubka ccd6bcd95f Merge pull request #3132 from cesanta/tls
stronger bounds checking
2025-05-13 22:26:35 +01:00
Sergey Lyubka a3b63f3b0d Merge pull request #3130 from cesanta/longpost
fix broken TCP closure
2025-05-13 22:26:15 +01:00
Sergey Lyubka f2905a5e10 Merge pull request #3135 from cesanta/mss
Handle (specific) TCP options
2025-05-13 22:25:52 +01:00
Sergio R. Caprile 1ef6c6aeb5 Handle TCP options 2025-05-13 16:27:50 -03:00
robertc2000 bd53529b45 Merge pull request #3134 from cesanta/ota-rw612
OTA for FRDM-RW612
2025-05-13 10:33:41 +03:00
Sergio R. Caprile cc8ecc5a42 stronger bounds checking 2025-05-12 18:13:41 -03:00
robert 5a816a1d41 OTA for FRDM-RW612 2025-05-12 07:59:15 -04:00
robertc2000 9922286c67 Merge pull request #3131 from cesanta/ws-offset
Websocket offset validation enhancement
2025-05-09 13:05:20 +03:00
robert cdc439bc38 Websocket offset validation enhancement 2025-05-09 06:04:34 -04:00
Sergio R. Caprile ae8422e304 fix broken TCP closure 2025-05-08 13:40:02 -03:00
robert 539d080346 check null pointer 2025-05-07 08:40:07 -04:00
Sergey Lyubka 041ec6e1f8 Close if drained 2025-05-03 10:28:40 +01:00
Sergio R. Caprile f618fe125c Fix lwIP builds
fixes #3119

lwIP does not export ip_mreq by default, it requires enabling support for IGMP by setting LWIP_IGMP, with the associated extra stuff. Mongoose will print an error if mg_multicast_add() is called with no multicast support in lwIP.
2025-04-29 19:24:17 -03:00
Sergio R. Caprile 8ab514fabc make hexdump send CRLF 2025-04-28 12:33:31 -03:00
novlean 08ad2c3145 Merge pull request #3113 from cesanta/novlean-patch-2
Update README.md
2025-04-24 17:40:00 +01:00
novlean c64fd404d4 Update README.md
article
2025-04-24 17:39:51 +01:00
Sergio R. Caprile 143b0ac126 fix 2025-04-24 11:04:43 -03:00
Sergio R. Caprile c2e2432010 Merge pull request #3093 from cesanta/mdns-multicast
Added MDNS and driver support for multicast
2025-04-22 14:01:34 -03:00
Sergio R. Caprile 1d2a768184 refactor the rest of the drivers 2025-04-22 13:59:03 -03:00
novlean fb099641bc Merge pull request #3111 from cesanta/novlean-patch-2
Update README.md
2025-04-22 17:48:28 +01:00
novlean 6da9afbf29 Update README.md 2025-04-22 17:48:12 +01:00
Sergio R. Caprile dceb4beb09 Refactor MIP strategy and first driver (CMSIS) 2025-04-22 12:55:21 -03:00
robert 6f697db49d Added MDNS and driver support for multicast 2025-04-22 12:55:15 -03:00
Sergio R. Caprile b44193780e Merge pull request #3110 from cesanta/tlsfindata
Fix not reading last TLS small record with fast closure
2025-04-22 10:03:40 -03:00
Sergio R. Caprile 8e0212c3db Fix not reading last TLS small record with fast closure
Fixes #3104
MbedTLS API fairplay
2025-04-22 09:56:49 -03:00
Sergio R. Caprile 3861e2e1e7 Merge pull request #3097 from cesanta/builtdoze
fix missing weird types
2025-04-14 13:13:06 -03:00
Sergio R. Caprile 21eefa4b55 Merge pull request #3102 from cesanta/mipfin
Fix handling of FIN segments carrying data
2025-04-14 11:27:09 -03:00
Sergey Lyubka fb6c6aafeb Merge pull request #3100 from cesanta/timers
Fix #2768 - remove completed timers
2025-04-14 15:15:36 +01:00
Sergio R. Caprile df07426e78 Fix handling of FIN segments carrying data 2025-04-14 11:11:48 -03:00
Sergio R. Caprile 5cf1523a13 Merge pull request #3101 from cesanta/tlszero
workaround causing TLS libs to return zero
2025-04-14 10:40:36 -03:00
Sergio R. Caprile f2fe47e9f7 workaround causing TLS libs to return zero 2025-04-11 14:42:15 -03:00
Sergio R. Caprile 2557ab2e60 Merge pull request #3086 from cesanta/cywst
Add support for RM2 with STM32F (429, 746)
2025-04-11 09:28:25 -03:00
Sergio R. Caprile fbc1708000 Add support for RM2 with STM32F (429, 746) 2025-04-11 09:20:40 -03:00
Sergey Lyubka 0539cf1023 Fix #2768 - remove completed timers 2025-04-11 11:24:10 +01:00
Sergio R. Caprile 07b410447b fix missing weird types 2025-04-10 10:02:20 -03:00
Sergey Lyubka fb69016196 Merge pull request #3096 from cesanta/polldoze
allow other stack than WinSock in Windows
2025-04-10 07:21:29 +01:00
Sergio R. Caprile 169cbc044f Merge pull request #3095 from cesanta/noVLA
no VLA
2025-04-09 13:28:21 -03:00
Sergio R. Caprile 08091d02e5 allow other stack than WinSock in Windows 2025-04-09 12:05:01 -03:00
Sergio R. Caprile 6f2dcf92a7 no VLA 2025-04-09 10:55:54 -03:00
Sergio R. Caprile 578e52618d Merge pull request #3092 from cesanta/picofix
unbreak pico[2]W auto init
2025-04-07 16:00:33 -03:00
Sergio R. Caprile ec0fe66a17 unbreak pico[2]W auto init 2025-04-07 15:56:11 -03:00
novlean 8fee24291a Merge pull request #3091 from cesanta/novlean-patch-2
Update README.md
2025-04-07 17:53:34 +01:00
novlean 05bba2958d Update README.md
Articles
2025-04-07 17:53:22 +01:00
robert e656b1c792 Removed alloca call for ARM-CGT compatibility 2025-04-07 09:08:22 -04:00
Sergey Lyubka e0ccbadd25 Merge pull request #3083 from cesanta/cyw
Introducing CYW driver and Wi-Fi AP support
2025-03-30 11:27:56 +01:00
Sergey Lyubka 40a2a8822f Squash warning 2025-03-29 18:59:01 +00:00
Sergio R. Caprile e2ee356a87 Merge pull request #3084 from cesanta/2ap
Add support for AP in Pico 2 W (valid for Pico W)
2025-03-28 09:51:15 -03:00
Sergio R. Caprile 189bef61d3 Add support for AP in Pico 2 W (valid for Pico W) 2025-03-24 17:49:40 -03:00
Sergio R. Caprile 7d94f9f61b Add Pico + RM2 Wi-Fi example 2025-03-24 17:41:12 -03:00
Sergio R. Caprile e37a0b9056 Add CYW driver 2025-03-24 17:03:05 -03:00
Sergio R. Caprile 0b57b23951 Add support for Wi-Fi chip drivers 2025-03-24 17:02:50 -03:00
Sergey Lyubka c84826e84e Merge pull request #3081 from cesanta/dhcp
Allow user to set custom DHCP name
2025-03-24 08:01:43 +00:00
Sergey Lyubka 064fc6ff7b Allow user to set custom DHCP name 2025-03-22 16:30:02 +00:00
Sergio R. Caprile 042ea53478 Merge pull request #3076 from cesanta/mondirw
keep up with Wizard dir structure
2025-03-12 17:14:30 -03:00
Sergio R. Caprile 900b0acf7a keep up with Wizard dir structure 2025-03-12 17:08:36 -03:00
Sergio R. Caprile dc5f2e295a Merge pull request #3074 from cesanta/wait
fix IO_WAIT on send for builtin TLS and MbedTLS
2025-03-11 16:21:32 -03:00
Sergio R. Caprile c1849c2b19 fix IO_WAIT on send for builtin TLS and MbedTLS 2025-03-11 16:14:12 -03:00
Sergio R. Caprile 4eadf3699f unbreak C89 2025-03-11 16:00:42 -03:00
Sergio R. Caprile b30cf6587c Merge pull request #3072 from cesanta/rw612-wifi-xpresso
RW612 MCUXpresso WiFi example with FreeRTOS and LWIP
2025-03-08 14:56:29 -03:00
Sergio R. Caprile fbc231f33e Merge pull request #3070 from cesanta/hton
remove memcpy from htons/l and test load/save bigendian macros
2025-03-08 14:46:46 -03:00
Sergio R. Caprile bc8c839342 Merge pull request #3033 from cesanta/wifi
Change driver API: up(ifp) -> poll(ifp, 1second)
2025-03-08 11:40:39 -03:00
Sergio R. Caprile 90a23fe230 Add support for Wi-Fi chip drivers 2025-03-07 16:41:33 -03:00
Sergio R. Caprile 065027843e Change driver API: up(ifp) -> poll(ifp, 1second)
Add misc extras required by Wi-Fi drivers (in progress)
2025-03-07 14:14:16 -03:00
Sergio R. Caprile 8906b1ac0f Merge pull request #3025 from cesanta/ub
fix UB and possible exception trigger
2025-03-07 13:49:37 -03:00
robert 05f9e61a41 RW612 MCUXpresso WiFi example with FreeRTOS and LWIP 2025-03-07 11:12:30 -05:00
Sergio R. Caprile 782896b5d3 remove memcpy from htons/l 2025-03-05 17:20:35 -03:00
Sergio R. Caprile 4258f62560 Merge pull request #3069 from cesanta/beduino
add test for ESP32
2025-03-05 14:23:05 -03:00
Sergio R. Caprile 537ba64a54 add test for ESP32 2025-03-05 12:34:22 -03:00
Sergey Lyubka 25d20b7354 Add mg_tcpip_driver_w5100 to the header 2025-03-05 06:54:20 +00:00
Sergio R. Caprile 04d8362905 Merge pull request #3068 from cesanta/arduino
fix Arduino tests
2025-03-04 16:31:57 -03:00
Sergio R. Caprile 21266e9a45 fix Arduino tests 2025-03-04 16:20:18 -03:00
Sergio R. Caprile 7304e2171d Merge pull request #3065 from cesanta/reduino
Rename conflictive macros, add and refactor crypto tests
2025-03-04 12:11:45 -03:00
Sergio R. Caprile 61fc480850 Rename conflictive macros, refactor crypto tests 2025-03-04 11:55:57 -03:00
robertc2000 562e82f5ac Merge pull request #3059 from cesanta/ota-rt1050
OTA on RT1050
2025-03-03 10:09:27 +02:00
robert d7ff85bb48 OTA on RT1050 2025-03-03 03:03:28 -05:00
Sergio R. Caprile 55bc6105e1 Merge pull request #3058 from cesanta/move
move examples -> tutorials
2025-02-28 14:00:06 -03:00
Sergio R. Caprile 306c0b6096 move examples -> tutorials 2025-02-28 13:55:57 -03:00
Sergio R. Caprile 024078ae33 Merge pull request #3057 from cesanta/move
move vendors -> tutorials
2025-02-28 10:10:07 -03:00
Sergio R. Caprile b5a9ba8390 move vendors -> tutorials 2025-02-28 10:01:51 -03:00
Sergey Lyubka 93f36927ca Add .mjs mime type 2025-02-27 16:50:04 +00:00
Sergio R. Caprile 1db90cafd1 Merge pull request #3056 from cesanta/move
move Zephyr -> tutorials
2025-02-27 12:02:48 -03:00
Sergio R. Caprile bf23a0def7 move Zephyr -> tutorials 2025-02-27 10:57:08 -03:00
Sergio R. Caprile ea1cbeea9d Merge pull request #3054 from cesanta/move
move UART bridge -> tutorials
2025-02-26 15:11:27 -03:00
Sergio R. Caprile aeda7e5520 move UART bridge -> tutorials 2025-02-26 15:08:06 -03:00
Sergio R. Caprile a7899af8b8 Merge pull request #3053 from cesanta/move
move ESP32 device dashboard -> tutorials
2025-02-26 14:17:06 -03:00
Sergio R. Caprile b0385f47af move ESP32 device dashboard -> tutorials 2025-02-26 14:14:08 -03:00
Sergio R. Caprile 86c384657c Merge pull request #3052 from cesanta/move
integrate reference-projects into existing tutorials
2025-02-26 12:05:14 -03:00
Sergio R. Caprile 6e569110d2 integrate reference-projects intto existing tutorials 2025-02-26 12:00:46 -03:00
Sergio R. Caprile 3b1024b13c Merge pull request #3051 from cesanta/move
move MicroPython and dashboards -> tutorials
2025-02-26 11:43:14 -03:00
Sergio R. Caprile b3f5d11275 move MicroPython and dashboards -> tutorials 2025-02-26 11:31:01 -03:00
Sergio R. Caprile 1078ba0a92 Merge pull request #3050 from cesanta/move
move file-transfer -> tutorials
2025-02-25 16:54:25 -03:00
Sergio R. Caprile 005c8170d4 move file-transfer -> tutorials 2025-02-25 16:52:16 -03:00
Sergio R. Caprile b8d1d7a10b Merge pull request #3049 from cesanta/move
move ESP8266 -> tutorials
2025-02-25 16:11:30 -03:00
Sergio R. Caprile 76769fb4d5 move ESP8266 -> tutorials 2025-02-25 16:10:28 -03:00
Sergio R. Caprile 6ff6f0a4c6 Merge pull request #3048 from cesanta/move
move Arduino examples -> tutorials
2025-02-25 15:52:12 -03:00
Sergio R. Caprile 72a45d2f6a move Arduino examples -> tutorials 2025-02-25 15:48:09 -03:00
Sergio R. Caprile 2fe7c8a410 Merge pull request #3044 from cesanta/eth-drivers-rx
ETH driver: use the same scheme for RX
2025-02-19 14:12:49 -03:00
robert 5269eb9c39 ETH driver: use the same scheme for RX 2025-02-19 10:01:54 -05:00
Sergio R. Caprile a0d9b6a7e0 fix UB and possible HF trigger 2025-01-28 10:24:59 -03:00
4048 changed files with 1469072 additions and 17163 deletions

No files matched your search

+1 -4
View File
@@ -11,17 +11,14 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^src/' ; then echo GO=1 >> $GITHUB_ENV ; fi
- name: Build Fuzzers - name: Build Fuzzers
id: build id: build
if: ${{ env.GO == 1 }}
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with: with:
oss-fuzz-project-name: 'mongoose' oss-fuzz-project-name: 'mongoose'
dry-run: false dry-run: false
language: c++ language: c++
- name: Run Fuzzers - name: Run Fuzzers
if: ${{ env.GO == 1 }}
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with: with:
oss-fuzz-project-name: 'mongoose' oss-fuzz-project-name: 'mongoose'
@@ -30,7 +27,7 @@ jobs:
language: c++ language: c++
- name: Upload Crash - name: Upload Crash
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
if: env.GO == 1 && failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts
path: ./out/artifacts path: ./out/artifacts
+2 -2
View File
@@ -2,8 +2,8 @@ name: "CodeQL Scanning"
# https://github.com/github/codeql-action # https://github.com/github/codeql-action
on: on:
schedule: #schedule:
- cron: '30 23 * * *' # run at 11:30 PM UTC # - cron: '30 23 * * *' # run at 11:30 PM UTC
# Allow manual runs # Allow manual runs
workflow_dispatch: workflow_dispatch:
+24
View File
@@ -0,0 +1,24 @@
name: Fuzz
on:
schedule:
- cron: '0 21 * * *' # run at 9 PM UTC
# Allow manual runs
workflow_dispatch:
env:
CC: clang
jobs:
fuzz:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [fuzz, fuzz_tls]
name: ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} ARGS="-max_total_time=14400"
# as we're not getting access to test units causing a problem, convert from the log:
# base64 -d > dataofdeath
# then paste the base64 data, enter, Ctrl-D; maybe check with hexdump -C dataofdeath
+123 -279
View File
@@ -1,4 +1,4 @@
name: Full build and test name: Full build
on: on:
schedule: schedule:
- cron: '0 22 * * *' # run at 10 PM UTC - cron: '0 22 * * *' # run at 10 PM UTC
@@ -29,15 +29,28 @@ jobs:
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0" select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
- ssl: WOLFSSL - ssl: WOLFSSL
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0" select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0"
include:
- ssl: BUILTIN
cc: gcc
target: test
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1 -DMG_ENABLE_CHACHA20=0"
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} - uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/linux_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
mip: mip:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -46,14 +59,40 @@ jobs:
cc: [gcc, clang, g++, clang++] cc: [gcc, clang, g++, clang++]
target: [mip_test, mip_tap_test] target: [mip_test, mip_tap_test]
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL] ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
# #3226: built-in TCP is currently not working with WolfSSL (builds fine)
exclude:
- ssl: WOLFSSL
target: mip_tap_test
name: ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} name: ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: -DMQTT_LOCALHOST -DNO_ABORT
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} IPV6=0 - uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; export IPV6=0; else export IPV6=1 ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
mip89:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 1 # no parallel runs, to minimize MQTT errors
matrix:
target: [mip_vc98]
name: mip89 ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} IPV6=1
s390: s390:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -61,10 +100,12 @@ jobs:
matrix: matrix:
ssl: ["", BUILTIN] ssl: ["", BUILTIN]
name: S390 SSL=${{ matrix.ssl }} name: S390 SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }} - run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }} MULTIREC=NO
armhf: armhf:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -72,10 +113,12 @@ jobs:
matrix: matrix:
ssl: ["", BUILTIN] ssl: ["", BUILTIN]
name: ArmHF SSL=${{ matrix.ssl }} name: ArmHF SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }} - run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }} MULTIREC=NO
unamalgamated-mg_prefix: unamalgamated-mg_prefix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -87,7 +130,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev - run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev
- run: make -C test unamalgamated && make -C test mg_prefix - run: make -C test unamalgamated SSL=${{ matrix.ssl }} && make -C test mg_prefix
valgrind: valgrind:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -95,11 +138,13 @@ jobs:
matrix: matrix:
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL] ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
name: Valgrind SSL=${{ matrix.ssl }} name: Valgrind SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev valgrind - run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev valgrind
- run: make -C test valgrind SSL=${{ matrix.ssl }} - run: ./test/setup_mqtt_server.sh && make -C test valgrind SSL=${{ matrix.ssl }}
macos: macos:
runs-on: macos-latest runs-on: macos-latest
strategy: strategy:
@@ -110,6 +155,8 @@ jobs:
exclude: exclude:
- ssl: MBEDTLS - ssl: MBEDTLS
select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
- ssl: MBEDTLS # see issue#2694
select: -DMG_ENABLE_POLL=1
- ssl: OPENSSL - ssl: OPENSSL
select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
- ssl: WOLFSSL - ssl: WOLFSSL
@@ -117,13 +164,23 @@ jobs:
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -Wno-sign-conversion # Workaround for MbedTLS 3.5.0 TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -DNO_ABORT -Wno-sign-conversion -Wno-undef # Workarounds for MbedTLS
HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_AUTO_UPDATE: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: brew install mbedtls wolfssl # jq openssl already pre-installed - uses: webfactory/ssh-agent@v0.9.1
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: brew install mbedtls wolfssl mosquitto gawk # jq openssl already pre-installed
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
windows: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -138,12 +195,21 @@ jobs:
select: -DMG_ENABLE_POLL=1 select: -DMG_ENABLE_POLL=1
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
SSL: SSL=${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} - uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/windows_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
arm: arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -165,109 +231,33 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: make -C test riscv SSL=${{ matrix.ssl }} - run: make -C test riscv SSL=${{ matrix.ssl }}
examples:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
name: examples ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
- run: sudo apt -y install libpcap-dev
- run: make -C test examples CFLAGS_EXTRA="${{ matrix.ssl }}"
- run: make -C test clean_examples
examples_win:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
name: examples_win ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
# - uses: egor-tensin/setup-mingw@v2
# with:
# platform: x64
- name: test they build
run: make -C test examples_win CFLAGS_EXTRA="${{ matrix.ssl }}"
shell: cmd
- name: test they clean
run: make -C test clean_examples_win
shell: cmd
examples_mac:
runs-on: macos-latest
env: { HOMEBREW_NO_AUTO_UPDATE: 1 }
strategy:
fail-fast: false
matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
name: examples_mac ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
- run: make -C test examples_mac CFLAGS_EXTRA="${{ matrix.ssl }}"
- run: make -C test clean_examples_mac
refprojs:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
name: reference-projects ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
- run: make -C test refprojs CFLAGS_EXTRA="${{ matrix.ssl }}"
- run: make -C test clean_refprojs
refprojs_win:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
name: reference-projects_win ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
# - uses: egor-tensin/setup-mingw@v2
# with:
# platform: x64
- name: test they build
run: make -C test refprojs_win CFLAGS_EXTRA="${{ matrix.ssl }}"
shell: cmd
- name: test they clean
run: make -C test clean_refprojs_win
shell: cmd
refprojs_mac:
runs-on: macos-latest
env: { HOMEBREW_NO_AUTO_UPDATE: 1 }
strategy:
fail-fast: false
matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
name: reference-projects_mac ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
- run: make -C test refprojs CFLAGS_EXTRA="${{ matrix.ssl }}"
- run: make -C test clean_refprojs
tutorials: tutorials:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN] ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
name: tutorials ${{ matrix.ssl }} name: tutorials ${{ matrix.ssl }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: sudo apt -y install libpcap-dev - run: sudo apt -y install libpcap-dev
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}" - run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}" > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/tutorials_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
- run: make -C test clean_tutorials - run: make -C test clean_tutorials
tutorials_win: tutorials_win:
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN] ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
name: tutorials_win ${{ matrix.ssl }} name: tutorials_win ${{ matrix.ssl }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -286,7 +276,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN] ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
name: tutorials_mac ${{ matrix.ssl }} name: tutorials_mac ${{ matrix.ssl }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -300,11 +290,8 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: echo # nothing specific to install or do - run: echo # nothing specific to install or do
- run: make -C examples/arduino arduino-xiao - run: make -C test/arduino
# TODO(): - run: make -C examples/arduino arduino-esp32 - run: make -C test/arduino cleanall
# TODO(): - run: make -C examples/arduino arduino-teensy41
# - run: make -C examples/arduino arduino-nano
- run: make -C examples/arduino clean
# wizard_examples: # wizard_examples:
@@ -322,7 +309,7 @@ jobs:
# with: { fetch-depth: 2 } # with: { fetch-depth: 2 }
# - run: echo # nothing specific to install or do # - run: echo # nothing specific to install or do
# fi # fi
# - run: make -C examples/${{ matrix.example.path }} build # - run: make -C tutorials/${{ matrix.example.path }} build
wizard_examples_arm: wizard_examples_arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -330,7 +317,9 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
example: example:
- path: infineon/infineon-xmc7200 - path: infineon/xmc47_relax-make-baremetal-builtin
- path: infineon/xmc_plt2go_4400-make-baremetal-builtin
- path: infineon/xmc72_evk-make-baremetal-builtin
- path: nxp/frdm-mcxn947-make-baremetal-builtin - path: nxp/frdm-mcxn947-make-baremetal-builtin
- path: nxp/frdm-mcxn947-make-freertos-builtin - path: nxp/frdm-mcxn947-make-freertos-builtin
- path: nxp/rt1020-evk-make-baremetal-builtin - path: nxp/rt1020-evk-make-baremetal-builtin
@@ -340,6 +329,7 @@ jobs:
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin - path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin - path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin - path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
- path: pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin
- path: stm32/nucleo-f429zi-make-baremetal-builtin - path: stm32/nucleo-f429zi-make-baremetal-builtin
- path: stm32/nucleo-f429zi-make-freertos-builtin - path: stm32/nucleo-f429zi-make-freertos-builtin
- path: stm32/nucleo-f746zg-make-baremetal-builtin - path: stm32/nucleo-f746zg-make-baremetal-builtin
@@ -361,7 +351,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi - run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/${{ matrix.example.path }} build - run: make -C tutorials/${{ matrix.example.path }} build
generic_examples: generic_examples:
@@ -370,9 +360,9 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
example: example:
- path: esp32/uart-bridge - path: micropython/esp32
- path: esp32/micropython - path: http/uart-bridge/esp32
- path: esp8266/http-client-server - path: http/http-client/esp8266/http-client-server
name: ${{ matrix.example.path }} name: ${{ matrix.example.path }}
env: env:
GO: 0 GO: 0
@@ -380,7 +370,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: echo # nothing specific to install or do - run: echo # nothing specific to install or do
- run: make -C examples/${{ matrix.example.path }} build - run: make -C tutorials/${{ matrix.example.path }} build
generic_examples_arm: generic_examples_arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -388,9 +378,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
example: example:
- path: microchip/same54-xpro/mqtt-client - path: mqtt/mqtt-client/microchip/same54-xpro
- path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
- path: nxp/nxp-mimxrt1020-azurertos
- path: nxp/nxp-frdmk66f-freertos - path: nxp/nxp-frdmk66f-freertos
- path: nxp/nxp-lpcxpresso54s018m-freertos - path: nxp/nxp-lpcxpresso54s018m-freertos
- path: nxp/nxp-mimxrt1020-freertos - path: nxp/nxp-mimxrt1020-freertos
@@ -420,7 +408,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi - run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/${{ matrix.example.path }} build - run: make -C tutorials/${{ matrix.example.path }} build
device_dashboard_examples: device_dashboard_examples:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -428,13 +416,14 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
example: example:
- path: esp32/device-dashboard - path: esp32
name: ${{ matrix.example.path }} name: ${{ matrix.example.path }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: echo # nothing specific to install or do - run: echo # nothing specific to install or do
- run: make -C examples/${{ matrix.example.path }} build - run: make -C tutorials/http/device-dashboard/${{ matrix.example.path }} build
device_dashboard_examples_arm: device_dashboard_examples_arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -443,7 +432,7 @@ jobs:
matrix: matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN] ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
example: example:
- path: microchip/same54-xpro/device-dashboard - path: http/device-dashboard/microchip/same54-xpro
- path: nxp/rt1020-evk-make-freertos-builtin - path: nxp/rt1020-evk-make-freertos-builtin
- path: nxp/rt1060-evk-make-freertos-builtin - path: nxp/rt1060-evk-make-freertos-builtin
- path: nxp/rt1170-evk-make-freertos-builtin - path: nxp/rt1170-evk-make-freertos-builtin
@@ -458,7 +447,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi - run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/${{ matrix.example.path }} build CFLAGS_EXTRA="${{ matrix.ssl }}" - run: make -C tutorials/${{ matrix.example.path }} build CFLAGS_EXTRA="${{ matrix.ssl }}"
# mqtt_dashboard_examples: # mqtt_dashboard_examples:
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
@@ -472,7 +461,7 @@ jobs:
# - uses: actions/checkout@v4 # - uses: actions/checkout@v4
# with: { fetch-depth: 2 } # with: { fetch-depth: 2 }
# - run: echo # nothing specific to install or do # - run: echo # nothing specific to install or do
# - run: make -C examples/${{ matrix.example.path }} build # - run: make -C tutorials/${{ matrix.example.path }} build
mqtt_dashboard_examples_arm: mqtt_dashboard_examples_arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -486,7 +475,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi - run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/${{ matrix.example.path }} build - run: make -C tutorials/${{ matrix.example.path }} build
# dual_examples: # dual_examples:
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
@@ -500,8 +489,8 @@ jobs:
# - uses: actions/checkout@v4 # - uses: actions/checkout@v4
# with: { fetch-depth: 2 } # with: { fetch-depth: 2 }
# - run: echo # nothing specific to install or do # - run: echo # nothing specific to install or do
# - run: make -C examples/${{ matrix.example.path }} device_dashboard # - run: make -C tutorials/${{ matrix.example.path }} device_dashboard
# - run: make -C examples/${{ matrix.example.path }} mqtt_dashboard # - run: make -C tutorials/${{ matrix.example.path }} mqtt_dashboard
cube_examples: cube_examples:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -511,155 +500,10 @@ jobs:
- run: sudo pip install yq - run: sudo pip install yq
- run: cd test/cube && make - run: cd test/cube && make
zephyr_examples: # xpresso_examples:
runs-on: ubuntu-latest # runs-on: ubuntu-latest
steps: # steps:
- uses: actions/checkout@v4 # - uses: actions/checkout@v4
with: { fetch-depth: 2 } # with: { fetch-depth: 2 }
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi # - run: sudo pip install yq
- run: make -C examples/zephyr init REPO=zephyrprojectrtos/ci:v0.26.14 # "no space left on device" with newers # - run: cd test/xpresso && make
- name: minify manifest
uses: mikefarah/yq@master
with:
cmd: yq -i eval '(.manifest.defaults, .manifest.remotes, .manifest.projects[] | select(.name == "cmsis" or .name == "hal_stm32" or .name == "mbedtls" or .name == "mcuboot" or .name == "picolibc" | del(.null) ), .manifest.self) as $i ireduce({};setpath($i | path; $i)) | del(.manifest.projects.[].null) | del(..|select(length==0))' examples/zephyr/zephyrproject/zephyr/west.yml
- run: make -C examples/zephyr update
- run: make -C examples/zephyr/device-dashboard build
- run: make -C examples/zephyr/http-client build
- run: make -C examples/zephyr/http-server build
- run: make -C examples/zephyr/mqtt-aws-client build
- run: make -C examples/zephyr/websocket-server build
test_f7:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: echo # nothing specific to install or do
# - run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
# - run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
test_f4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: echo # nothing specific to install or do
# - run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# - run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
test_h743:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - name: Cube
# run: echo # nothing specific to install or do
# - run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
# - run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
test_h723:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_h5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1020:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1060:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1170:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_ra6m4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - run: make -C examples/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_tm4c:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_same54:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/microchip/same54-xpro/device-dashboard test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C examples/microchip/same54-xpro/mqtt-client test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_pico_w5500:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: SDK
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C examples/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
+143
View File
@@ -0,0 +1,143 @@
name: Full test
on:
schedule:
- cron: '0 23 * * *' # run at 11 PM UTC
# Allow manual runs
workflow_dispatch:
env:
IPV6: 0
jobs:
test_f7:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: sudo pip install yq
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
test_f4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: sudo pip install yq
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
test_h743:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - name: Cube
# run: echo # nothing specific to install or do
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
test_h723:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_h5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1020:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1060:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1170:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_ra6m4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - run: make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_tm4c:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_same54:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_pico_w5500:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: SDK
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
+32
View File
@@ -0,0 +1,32 @@
name: On demand ad hoc test
on:
workflow_dispatch:
env:
IPV6: 0
jobs:
macos:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
ssl: [MBEDTLS, WOLFSSL]
select: [-DMG_ENABLE_POLL=1]
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env:
SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT -Wno-sign-conversion -Wno-undef # Workarounds for MbedTLS
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: brew install mbedtls wolfssl mosquitto gawk # jq openssl already pre-installed
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
File diff suppressed because it is too large. Load diff
+27
View File
@@ -0,0 +1,27 @@
name: Zephyr
on:
schedule:
- cron: '0 0 * * *' # run at 12 AM UTC
# Allow manual runs
workflow_dispatch:
jobs:
zephyr_examples:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
revno: ["--mr v3.7-branch", "--mr v4.2.0", "--mr v4.3.0"] # LTS, latest stable
name: Zephyr ${{ matrix.revno }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: test/setup_ga_docker_filesystem.sh
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci:v0.28.8 REVNO="${{ matrix.revno }}"
- run: make -C tutorials/zephyr minify REVNO="${{ matrix.revno }}"
- run: make -C tutorials/zephyr update
- run: make -C tutorials/zephyr/device-dashboard build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/http-client build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/http-server build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/mqtt-aws-client build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/websocket-server build REPO=zephyrprojectrtos/ci:v0.28.8
# Latest CI image does not work with pre 4.4, they changed some SDK paths
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2004-2013 Sergey Lyubka Copyright (c) 2004-2013 Sergey Lyubka
Copyright (c) 2013-2025 Cesanta Software Limited Copyright (c) 2013-2026 Cesanta Software Limited
All rights reserved All rights reserved
This software is dual-licensed: you can redistribute it and/or modify This software is dual-licensed: you can redistribute it and/or modify
+56 -4
View File
@@ -1,12 +1,11 @@
# Mongoose - Embedded Web Server / Embedded Network Library # Mongoose - Embedded Web Server / Embedded Network Library
[![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php) [![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php)
[![Build Status]( https://github.com/cesanta/mongoose/workflows/build/badge.svg)](https://github.com/cesanta/mongoose/actions) [![Build Status]( https://github.com/cesanta/mongoose/actions/workflows/quicktest.yml/badge.svg)](https://github.com/cesanta/mongoose/actions)
[![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose) [![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose)
[![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20Mongoose%20Guru-006BFF)](https://gurubase.io/g/mongoose)
Mongoose is a network library for C/C++. It provides event-driven non-blocking <img src="https://mongoose.ws/images/logo.svg" width="48" height="48" align="left" style="float:left;" /> Mongoose is a network library for C/C++. It provides event-driven non-blocking
APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed
for connecting devices and bringing them online. On the market since 2004, used for connecting devices and bringing them online. On the market since 2004, used
by vast number of open source and commercial products - it even runs on the by vast number of open source and commercial products - it even runs on the
@@ -35,6 +34,35 @@ robust, and easy. Features include:
See https://mongoose.ws/ for complete documentation, videos, case studies, etc. See https://mongoose.ws/ for complete documentation, videos, case studies, etc.
## Supported platforms
Mongoose can work on top of any TCP/IP stack that supports BSD sockets API.
Platforms supported by the 3rd party TCP/IP stacks:
| TCP/IP stack | Notes |
| :-------------- | :------- |
| **lwIP** | All devices running lwIP, for example ESP32, ESP32S3, ESP32C3, ESP32C6, etc |
| **Zephyr** | All devices supported by Zephyr |
| **Other** | Any other TCP/IP stack that supports BSD socket API, for example Amazon FreeRTOS-TCP |
| **Linux, Mac, Windows** | Workstations, server, single board computers, embedded Linux devices running on MPUs or FPGAs |
Optionally, Mongoose provides its own built-in TCP/IP stack, eliminating the
need for additional software to implement networking functionality. The
built-in stack supports operation in both bare-metal and RTOS environments.
Platforms supported by the Mongoose built-in TCP/IP stack:
| Hardware | Notes |
| :------------- | :------- |
| **STM32** | All STM32 MCUs with built-in Ethernet: STM32Fxx, STM32H5xx, STM32H7xx |
| **NXP** | All NXP MCUs with built-in Ethernet: IMXRT102x, IMXRT104x, IMXRT105x, IMXRT106x, IMXRT117x, RW612, MCXN94x |
| **Microchip** | ATSAME54 MCUs with built-int Ethernet |
| **Renesas** | RA5M, RA6M, RA8M MCUs with built-in Ethernet |
| **Infineon** | XMC4, XMC7 MCUs with built-in Ethernet |
| **Texas Instruments** | TM4C, TMS570 MCUs with built-in Ethernet |
| **Cypress WiFi** | Any MCU with CY43xx WiFi chips, like RP2040 Pico-W, RP2350 Pico2-W, Arduino Portenta |
| **Wiznet Ethernet** | Any MCU that use Wiznet W5500 or Wiznet 5100 MAC+PHY chips |
| **Cellular** | NRF9160, SIM800 |
## Usage Examples ## Usage Examples
Below are quick snippets that should give an idea how simple the API is and Below are quick snippets that should give an idea how simple the API is and
@@ -170,6 +198,30 @@ We take security seriously:
have specific security requirements and run independent security audits, have specific security requirements and run independent security audits,
of which we get notified and in case of any issue, act similar to (3). of which we get notified and in case of any issue, act similar to (3).
## How to report security vulnerabilities
Please send an email to support@cesanta.com, with the full information.
Do NOT create a github issue.
## Articles
Technical guides and deep dives into embedded web servers, WebUI integration and embedded networking technologies:
- [Embedded Web Server: A Comprehensive Guide for Modern Connected Devices](https://mongoose.ws/articles/embedded-web-server-a-comprehensive-guide-for-modern-connected-devices/)
- [Building Embedded Web Device Dashboards](https://mongoose.ws/articles/building-embedded-web-device-dashboard/)
- [ESP32 Device Dashboard: A Step-by-Step Guide for Developers](https://mongoose.ws/articles/esp32-device-dashboard/)
- [How to build an STM32 Web Dashboard](https://mongoose.ws/articles/stm32-device-dashboard/)
- [STM32 WebSocket Guide](https://mongoose.ws/articles/stm32-websocket-guide/)
- [Web File Manager on STM32, ESP32 and Embedded Linux](https://mongoose.ws/articles/building-a-web-file-manager-on-stm32-esp32-embedded-linux/)
- [Web dashboard on Zephyr RTOS](https://mongoose.ws/articles/web-dashboard-on-zephyr-rtos/)
- [Limiting TCP/IP RAM usage on STM32](https://mongoose.ws/articles/limiting-tcpip-ram-usage-on-stm32/)
- [STM32 Ethernet explained](https://mongoose.ws/articles/stm32-ethernet-explained/)
- [MQTT on a Microcontroller](https://mongoose.ws/articles/mqtt-on-a-microcontroller/)
- [STM32 OTA Firmware Update](https://mongoose.ws/articles/stm32-ota-firmware-update/)
- [RP2350 OTA Firmware Update](https://mongoose.ws/articles/rp2350-ota-firmware-update/)
- [STM32 Ethernet and caches](https://mongoose.ws/articles/stm32-ethernet-and-cache/)
- [NXP RW612 OTA Firmware Update](https://mongoose.ws/articles/rw612-ota-firmware-update/)
- [lwIP vs Mongoose - TCP/IP Stack Integration Benchmark](https://mongoose.ws/articles/lwip-vs-mongoose-tcpip-stack-integration/)
## Contributions ## Contributions
-24
View File
@@ -1,24 +0,0 @@
# Mongoose Network Library Examples
In order to build and run any of the existing examples, please follow:
https://mongoose.ws/documentation/#how-to-build-and-run-examples
## Contributing
Rules for creating a new example:
- Makefile golden reference for desktop/server example: [http-server](http-server)
- Makefile golden reference for the embedded example:
[stm32/nucleo-f746zg-baremetal](stm32/nucleo-f746zg-baremetal)
- An example must build on Windows, Mac and Ubuntu Linux systems
- Assume that user installed tools according to https://mongoose.ws/tutorials/tools/
- Makefile must not include any other make files
- Use `CFLAGS` for system-specific compilation options
- Use `CFLAGS_MONGOOSE` for mongoose-specific compilation options
- Use `$(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA)` to compile
- If external repository is required, download it on demand using git
shallow clone. See embedded example golden reference
- Keep Makefile as short as possible, but verbose to understand it easily
- Symlink files when required, like `mongoose.c`, `ca.pem`, etc. Make no copies
- Example's README.md should contain only the title and the link to mongoose.ws
tutorial page
-41
View File
@@ -1,41 +0,0 @@
all:
example:
true
arduino: ENV = -v $(CWD):/root
arduino:
curl -sL http://downloads.arduino.cc/arduino-1.8.19-linux64.tar.xz | unxz | tar -xf -
mv arduino-* $@
arduino-xiao-board:
./arduino/arduino --pref "boardsmanager.additional.urls=https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json" --save-prefs
./arduino/arduino --pref "compiler.warning_level=all" --save-prefs
./arduino/arduino --install-boards Seeeduino:samd
arduino-xiao: arduino arduino-xiao-board
cd sim800-mqtt && ../arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 sim800-mqtt.ino
cd w5500-http && ../arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 w5500-http.ino
cd w5500-mqtt && ../arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 w5500-mqtt.ino
arduino-nano: arduino
cd w5500-http && ../arduino/arduino --pref compiler.cpp.extra_flags=-DMG_ENABLE_LOG=0 --verbose --verify --board arduino:avr:nano w5500-http.ino
cd w5500-mqtt && ../arduino/arduino --pref compiler.cpp.extra_flags=-DMG_ENABLE_LOG=0 --verbose --verify --board arduino:avr:nano w5500-mqtt.ino
arduino-esp32: arduino
# cd esp32-http && ../arduino/arduino --verbose --verify --board esp32-http.ino
# esp32-mqtt
arduino-teensy41: arduino
# cd teensy41-http && ../arduino/arduino --verbose --verify --board teensy41-http.ino
clean:
rm -rf arduino
cleanall: clean #otherwise some parts of xiao-board installation will fail as already installed
rm -rf ~/.arduino15 ~/.oracle_jre_usage
-1
View File
@@ -1 +0,0 @@
../../mongoose.c
-1
View File
@@ -1 +0,0 @@
../../mongoose.h
File diff suppressed because it is too large. Load diff
@@ -1 +0,0 @@
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.col-span-2{grid-column:span 2/span 2}.m-4{margin:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-5{margin-top:1.25rem;margin-bottom:1.25rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-96{width:24rem}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.border-separate{border-collapse:initial}.border-spacing-0Line truncated
@@ -1 +0,0 @@
../../../micropython/mongoose/micropython.cmake
@@ -1 +0,0 @@
../../../micropython/mongoose/micropython.mk
@@ -1 +0,0 @@
../../../micropython/mongoose/module.c
-1
View File
@@ -1 +0,0 @@
../../../uart-bridge/net.c
@@ -1 +0,0 @@
../../../uart-bridge/packed_fs.c
-1
View File
@@ -1 +0,0 @@
../../mongoose.c
-1
View File
@@ -1 +0,0 @@
../../mongoose.h
@@ -1,9 +0,0 @@
NAME ?= $(notdir $(CURDIR))
build:
git clone --depth 1 https://github.com/mongoose-examples/$(NAME)
cp ./../../../mongoose.[ch] $(NAME)
make -C $(NAME) build
clean:
rm -rf $(NAME)
-1
View File
@@ -1 +0,0 @@
../device-dashboard/certs
-1
View File
@@ -1 +0,0 @@
../../mongoose.c
-1
View File
@@ -1 +0,0 @@
../../mongoose.h
File diff suppressed because it is too large. Load diff
@@ -1 +0,0 @@
/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.m-4{margin:1rem}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.max-h-64{max-height:16rem}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-full{width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.translate-x-5{--tw-translate-x:1.25rem}.translate-x-5,.translate-y-0{transform:tranLine truncated
@@ -1,14 +0,0 @@
all:
make -C ../../../tutorials/http/http-server ARGS="-d $(CURDIR)"
# Bundle JS libraries (preact, preact-router, ...) into a single file
bundle.js:
curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@
# Create optimised CSS. Prerequisite: npm -g i tailwindcss tailwindcss-font-inter
NPX ?= npx
main.css: index.html $(wildcard *.js)
$(NPX) tailwindcss -o $@ --minify
clean:
true
@@ -1 +0,0 @@
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.right-4{right:1rem}.top-0{top:0}.top-4{top:1rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-auto{margin-top:auto;margin-bottom:auto}.mb-4{margin-bottom:1rem}.mt-3{margin-top:.75rem}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-11{width:2.75rem}.w-24{width:6rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-60{width:15rem}.w-64{width:16rem}.w-96{width:24rem}.w-full{width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-5{--tw-translate-x:1.25rem}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-widtLine truncated
-618
View File
@@ -1,618 +0,0 @@
'use strict';
import {h, html, render, useEffect, useRef, useState} from './bundle.js';
const Logo = props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.87 12.85"><defs><style>.ll-cls-1{fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:0.5px;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="ll-cls-1" d="M12.62,1.82V8.91A1.58,1.58,0,0,1,11,10.48H4a1.44,1.44,0,0,1-1-.37A.69.69,0,0,1,2.84,10l-.1-.12a.81.81,0,0,1-.15-.48V5.57a.87.87,0,0,1,.86-.86H4.73V7.28a.86.86,0,0,0,.86.85H9.42a.85.85,0,0,0,.85-.85V3.45A.86.86,0,0,0,10.13,3,.76.76,0,0,0,10,2.84a.29.29,0,0,0-.12-.1,1.49,1.49,0,0,0-1-.37H2.39V1.82A1.57,1.57,0,0,1,4,.25H11A1.57,1.57,0,0,1,12.62,1.82Z"/><path class="ll-cls-1" d="M10.48,10.48V11A1.58,1.58,0,0,1,8.9,12.6H1.82A1.57,1.57,0,0,1,.25,11V3.94A1.57,1.57,0,0,1,1.82,2.37H8.9a1.49,1.49,0,0,1,1,.37l.12.1a.76.76,0,0,1,.11.14.86.86,0,0,1,.14.47V7.28a.85.85,0,0,1-.85.85H8.13V5.57a.86.86,0,0,0-.85-.86H3.45a.87.87,0,0,0-.86.86V9.4a.81.81,0,0,0,.15.48l.1.12a.69.69,0,0,0,.13.11,1.44,1.44,0,0,0,1,.37Z"/></g></g></svg>`;
const DefaultTopic = 'mg_mqtt_dashboard';
const DefaultUrl = location.protocol == 'https:'
? 'wss://broker.hivemq.com:8884/mqtt'
: 'ws://broker.hivemq.com:8000/mqtt';
const DefaultDeviceConfig = {pin_map: [], pin_state: [], log_level: 0, pin_count: 0};
const Delay = (ms, val) => new Promise(resolve => setTimeout(resolve, ms, val));
const handleFetchError = r => r.ok || alert(`Error: ${r.statusText}`);
const LabelClass = 'text-sm truncate text-gray-500 font-medium my-auto whitespace-nowrap';
const BadgeClass = 'flex-inline text-sm rounded-md rounded px-2 py-0.5 ring-1 ring-inset';
const InputClass = 'font-normal text-sm rounded w-full flex-1 py-0.5 px-2 text-gray-700 placeholder:text-gray-400 focus:outline-none disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-500 rounded border';
const TitleClass = 'font-semibold xuppercase xtext-gray-600';
const Colors = {
green: 'bg-green-100 text-green-900 ring-green-300',
yellow: 'bg-yellow-100 text-yellow-900 ring-yellow-300',
info: 'bg-zinc-100 text-zinc-900 ring-zinc-300',
red: 'bg-red-100 text-red-900 ring-red-300',
};
let MqttClient;
const Icons = {
logo: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="59.1" height="75.7" viewBox="0 0 1514 1182"> <path style="fill: #2f409a;" d="m52.8 572h345.1v346.5h-345.1zm-10.9-434.2c-12.6 6.4-32.2 20.9-35.5 37.9 0 0-6.1 35.9-6.1 36.8-2.1 13.1 10.5 10 15.8 6.7 53.9-31.8 113.9-60.7 168.7-77.5 258.2-78.2 585.9-80.2 643.1 88.8 40.3 117.1-123.6 214.8-216.1 258.4-35.7 16.8-47.6 32.8-50 49.8-2 15.3 3.2 37.8 23.8 68.3 129.7 194.8 515 474 893.1 571.7 15.7 4.2 23.5 2.8 29.9-1.1 3.5-2 7.9-4.8 1.1-8.2-251.1-132.2-490.9-353.9-610.9-525.1-27.4-39.5-34.5-65.9-32.7-87.2 1.7-18.4 18.7-34.5 54.8-51.4 134.1-62.3 270.9-157.1 230-314.9-59.5-226.9-700.5-260.1-1109-53z"/></svg>`,
activity: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg>`,
refresh: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>`,
info: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>`,
login: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>`,
logout: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>`,
menu: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>`,
upload: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>`,
monitor: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>`,
settings: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`,
download: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`,
file: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>`,
check: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`,
rollback: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline></svg>`,
save: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>`,
bolt: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>`,
delete: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`,
};
export function Button({title, onclick, disabled, extraClass, icon, ref, colors, hovercolor, disabledcolor}) {
const [spin, setSpin] = useState(false);
const cb = function(ev) {
const res = onclick ? onclick() : null;
if (res && typeof (res.catch) === 'function') {
setSpin(true);
res.catch(() => false).then(() => setSpin(false));
}
};
if (!colors) colors = 'bg-blue-600 hover:bg-blue-500 disabled:bg-blue-400';
return html`
<button type="button" class="inline-flex justify-center items-center gap-2 rounded px-2.5 py-0.5 text-sm font-semibold text-white shadow-sm ${colors} ${extraClass}"
ref=${ref} onclick=${cb} disabled=${disabled || spin} >
${title}
<${spin ? Icons.refresh : icon} class="w-4 ${spin ? 'animate-spin' : ''}" />
<//>`
};
function UploadFileButton({oncomplete, onprogress, onfileselect, url, title, colors, accept, extraClass}) {
const btn = useRef(null);
const input = useRef(null);
// Send a large file chunk by chunk
const sendFileData = function(url, fileName, fileData, chunkSize) {
return new Promise(function(resolve, reject) {
const finish = ok => {
input.fn = null;
const res = oncomplete ? oncomplete(ok, fileName, fileData.length) : null;
if (res && typeof (res.catch) === 'function') {
res.catch(() => false).then(() => ok ? resolve() : reject());
} else {
ok ? resolve() : reject();
}
};
const sendChunk = function(offset) {
var chunk = fileData.subarray(offset, offset + chunkSize) || '';
var opts = {method: 'POST', body: chunk};
var fullUrl = url + '?offset=' + offset +
'&total=' + fileData.length +
'&file=' + encodeURIComponent(fileName);
onprogress && onprogress(offset, fileData.length, fileName);
fetch(fullUrl, opts)
.then(function(res) {
if (!res.ok) {
finish(false);
} else if (offset >= fileData.length) {
finish(true);
} else {
sendChunk(offset + chunk.length);
}
});
};
sendChunk(0);
});
};
const onchange = function(ev) {
if (!ev.target.files[0]) return;
let r = new FileReader(), f = ev.target.files[0];
if (onfileselect && !onfileselect(f.name)) {
ev.target.value = '';
return;
}
r.readAsArrayBuffer(f);
r.onload = function() {
input.fn = sendFileData(url, f.name, new Uint8Array(r.result), 2048);
ev.target.value = '';
ev.preventDefault();
btn.current && btn.current.base.click();
};
};
const onclick = function(ev) {
//if (!input.fn) input.current.click(); // No upload in progress, show file dialog
};
return html`
<div class="inline-flex flex-col ${extraClass}">
<input class="hidden" type="file" ref=${input} onchange=${onchange} accept=${accept} />
<${Button} title=${title} icon=${Icons.download} onclick=${onclick} ref=${btn} colors=${colors} />
<//>`;
};
function Toggle({value, onclick, disabled}) {
const bg = !!value ? 'bg-blue-600' : 'bg-gray-200';
const tr = !!value ? 'translate-x-5' : 'translate-x-0';
return html`
<button type="button" onclick=${onclick} disabled=${disabled}
class="${bg} inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-0 ring-0"
role="switch" aria-checked=${!!value}>
<span aria-hidden="true" class="${tr} pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 focus:ring-0 transition duration-200 ease-in-out"></span>
</button>`;
};
function Header({topic, setTopic, url, setUrl, connected}) {
const forbiddenChars = ['$', '*', '+', '#', '/'];
const onClick = () => {
const isValidTopic = val => !forbiddenChars.some(char => val.includes(char));
if (isValidTopic(topic)) {
localStorage.setItem('topic', topic)
setTopic(topic);
window.location.reload();
} else {
setSaveResult('Error: The topic cannot contain these characters: ' + forbiddenChars);
}
};
return html`
<div class="top-0 py-2 border-b-2 bg-stone-100">
<div class="flex px-4">
<div class="flex grow gap-4">
<h1 class="text-2xl font-semibold">IoT Fleet Management Dashboard</h1>
<//>
<div class="flex gap-2 items-center">
<div class="flex w-96 align-center justify-between gap-2">
<span class=${LabelClass}>MQTT Server<//>
<input disabled=${!connected} value=${url}
onchange=${ev => setUrl(ev.target.value)} class=${InputClass} />
<//>
<div class="flex w-64 align-center justify-between gap-2">
<span class=${LabelClass}>Root Topic<//>
<input disabled=${!connected} value=${topic}
onchange=${ev => setTopic(ev.target.value)} class=${InputClass} />
<//>
<${Button} icon=${Icons.bolt} onclick=${onClick} title=${connected ? 'Disconnect' : 'Connect'} />
<//>
<//>
<//>`;
};
function Sidebar({devices, onclick}) {
const Td = props => html`
<td class="whitespace-nowrap border-b border-slate-200 py-2 px-4 pr-3 text-sm text-slate-900">${
props.text}</td>`;
const Device = ({d}) => html`
<div class="hover:bg-stone-100 cursor-pointer flex gap-3 px-4 py-2 justify-between"
onclick=${ev => onclick(d.id)}>
<span>${d.id}</span>
<span class="${BadgeClass} ${d.online ? Colors.green : Colors.red}"> ${d.online ? 'online' : 'offline'} <//>
<//>`;
return html`
<div class="overflow-auto divide-y">
<div class="${TitleClass} flex items-center px-4 py-2 bg-stone-100">
Device List
<//>
${(devices ? devices : []).map(d => h(Device, {d}))}
<//>`;
};
function FirmwareStatus({title, info, children}) {
const state =
['UNAVAILABLE', 'FIRST_BOOT', 'NOT_COMMITTED',
'COMMITTED'][(info.status || 0) % 4];
const valid = info.status > 0;
return html`
<div class="bg-white divide-y border rounded">
<div class="${TitleClass} bg-white flex items-center px-4 py-2">
${title}
<//>
<div class="px-4 py-2 relative">
<div class="my-1">Status: ${state}<//>
<div class="my-1">CRC32: ${valid ? info.crc32.toString(16) : 'n/a'}<//>
<div class="my-1">Size: ${valid ? info.size : 'n/a'}<//>
<div class="my-1">Flashed at: ${
valid ? new Date(info.timestamp * 1000).toLocaleString() : 'n/a'}<//>
${children}
<//>
<//>`;
};
function FirmwareUpdatePanel({no, name, current, previous, updated_at, refresh}) {
const [color, setColor] = useState(Colors.green);
const [otaStatus, setOtaStatus] = useState('up-to-date');
const Descr = ({label, value}) => html`
<div class="flex items-center justify-between">
<span class=${LabelClass}>${label}<//>
<span class="text-sm">${value}<//>
<//>`;
const onprogress = (len, total) => {
setColor(Colors.info);
setOtaStatus(`uploading, ${parseInt(len * 100 /total)}% done...`);
}
const setparam = (key, val) => fetch('api/settings/set', {
method: 'POST',
body: JSON.stringify({key, val}),
}).then(handleFetchError);
const onupload = function(ok, fileName, fileLength) {
if (ok) {
return setparam(`ecu.${no}.new`, fileName).then(refresh);
} else {
setColor(Colors.red), setOtaStatus('upload failed');
}
};
const onfileselect = function(fileName, fileLength) {
const ok = fileName.startsWith(name);
if (!ok) alert(`Firmware file name must be ${name}.VERSION.BIN_OR_HEX`);
return ok;
}
const update = rollback => new Promise(function(resolve, reject) {
const opts = {method: 'POST', body: JSON.stringify({no, rollback})};
const fail = () => (reject(), setOtaStatus('update error'), setColor(Colors.red));
const finish = () => fetch('api/ecu/update/end', opts)
.then(r => r.ok ? resolve() : reject())
.then(refresh);
const write = () => fetch('api/ecu/update/write', opts).then(r => {
if (!r.ok) fail();
//if (r.ok) r.json().then(r => console.log('Goo', r));
if (r.ok) r.json().then(r => r == 1 ? write() : finish());
});
fetch('api/ecu/update/begin', opts).then(r => r.ok ? write() : fail());
});
const onflash = ev => update(false);
const onrollback = ev => update(true);
useEffect(function() {
//setOtaStatus(anew ? 'update pending' : 'up-to-date');
//setColor(anew ? Colors.yellow : Colors.green);
}, []);
return html`
<div class="divide-y border rounded bg-white">
<div class="px-4 py-2 flex justify-between items-center rounded">
<span class="${TitleClass}">Firmware Update<//>
<div class="flex gap-2"><span class=${LabelClass}>Status:</span><span class="${BadgeClass} ${color}">${otaStatus}<//><//>
<//>
<div class="p-4 flex flex-col gap-1">
<${Descr} label="Current firmware:" value=${current || 'n/a'} />
<${Descr} label="Updated at:" value=${updated_at || 'n/a'} />
<div class="flex items-center justify-between whitespace-nowrap">
<span class=${LabelClass}>Previous firmware:<//>
<span class="flex gap-1 items-center">
<span class="text-sm">${previous}<//>
<${Button} title="rollback" icon=${Icons.bolt} onclick=${onrollback}
extraClass="w-24" disabled=${!previous} />
<//>
<//>
<div class="flex items-center justify-between">
<span class=${LabelClass}>New firmware:<//>
<span class="flex gap-1 align-center justify-between">
<${UploadFileButton} title="upload" url="api/fw/upload"
onfileselect=${onfileselect}
onprogress=${onprogress} oncomplete=${onupload} />
<${Button} title="flash" icon=${Icons.bolt} onclick=${onflash}
extraClass="w-24" disabled=${!previous} />
<//>
<//>
<//>
<//>`;
};
function DeviceSettingsPanel({device, publishFn, connected}) {
const [config, setConfig] = useState({});
const logOptions = [[0, 'Disable'], [1, 'Error'], [2, 'Info'], [3, 'Debug']];
const onSave = ev => publishFn('config.set', config).then(r => {
//setDeviceConfig(device.id, config);
}).catch(e => alert('Failure!'));
// To delete device, set an empty retained message
const onforget = function(ev) {
MqttClient.publish(device.topic, '', {retain: true});
location.reload();
};
const onloglevelchange = ev => setConfig(x => Object.assign({}, x, {log_level: parseInt(ev.target.value)}));
const onpinschange = ev => {
const pin_map = ev.target.value.split(/\s*,\s*/).map(x => parseInt(x));
setConfig(x => Object.assign({}, x, {
pin_map, // Send an updated pin map
pin_count: pin_map.length, // And pin count
pin_state:[] // Remove pin_state from the request, as pin_map change can invalidate it
}));
}
//console.log('sp', device, config);
useEffect(() => setConfig(device.config) , [device]);
return html`
<div class="divide-y border rounded bg-white">
<div class="px-4 py-2 flex justify-between items-center rounded ${TitleClass}">
<div class="flex gap-2 items-center"> Settings <//>
<//>
<div class="p-4 gap-3">
<div class="flex justify-between my-1">
<span class=${LabelClass}>Status<//>
<span class="${BadgeClass} ${device.online ? Colors.green : Colors.red}"> ${connected ? 'online' : 'offline'} <//>
<//>
<div class="flex justify-between my-1">
<span class=${LabelClass}>Device ID<//>
<span class="${LabelClass}">${device.id}<//>
<//>
<div class="grid grid-cols-2 my-1">
<span class="${LabelClass}">Log Level<//>
<select onchange=${onloglevelchange} class="w-full rounded font-normal border py-0.5 px-1 text-gray-600 focus:outline-none text-sm disabled:cursor-not-allowed" disabled=${!connected}>
${logOptions.map(v => html`<option value=${v[0]} selected=${v[0] == config.log_level}>${v[1]}<//>`) }
<//>
<//>
<div class="grid grid-cols-2 my-1">
<span class="${LabelClass}">Show Pins<//>
<div class="flex w-full items-center">
<input disabled=${!connected} value=${config.pin_map}
onchange=${onpinschange} class=${InputClass}
placeholder="comma-separated pin numbers" />
<//>
<//>
<div class="mt-3 flex justify-between gap-2">
<${Button} title="Forget this device"
disabled=${device.online || !connected} icon=${Icons.delete}
onclick=${onforget}/>
<${Button} icon=${Icons.save} onclick=${onSave} title="Save Settings" disabled=${!device.online} />
<//>
<//>
<//> `;
};
function DeviceControlPanel({device, config, setConfig, publishFn, connected}) {
const onclick = function(i) { // Send request to toggle pin i
let configCopy = Object.assign({}, config);
configCopy.pin_state[i] = !!configCopy.pin_state[i] ? 0 : 1;
return publishFn('config.set', configCopy).catch(e => alert('Failure!'));
};
const Pin = i => html`
<div class="inline-block my-1 bg-gray-100 rounded px-1 py-1">
<div class="flex align-center justify-between">
<span class="${LabelClass}">Pin ${config.pin_map[i]}<//>
<${Toggle} onclick=${ev => onclick(i)}
disabled=${!device.online || !connected}
value=${config.pin_state[i]} />
<//>
<//>`;
return html`
<div class="divide-y border rounded bg-white xbg-slate-100 my-y">
<div class="px-4 py-2 flex justify-between items-center rounded ${TitleClass}">
<div class="flex gap-2 items-center">Pin Control Panel<//>
<//>
<div class="p-4 grid grid-cols-2 lg:grid-cols-3 gap-2">
${(config.pin_map || []).map((_, i) => Pin(i))}
<div><//>
<//>
<//> `;
};
function DeviceDashboard({device, setDeviceConfig, publishFn, connected}) {
const cfg = device && device.config ? device.config : DefaultDeviceConfig;
const [localConfig, setLocalConfig] = useState(cfg);
useEffect(() => setLocalConfig(cfg), [device]);
if (!device || !localConfig) {
return html`
<div class="flex grow text-gray-400 justify-center items-center text-xl">
No device selected. Click on a device on a sidebar
<//>`;
}
return html`
<div class="p-3 grid grid-cols-3 gap-2">
<${DeviceSettingsPanel} device=${device} config=${localConfig} setConfig=${setLocalConfig} publishFn=${publishFn} connected=${connected} />
<${DeviceControlPanel} device=${device} config=${localConfig} setConfig=${setLocalConfig} publishFn=${publishFn} connected=${connected} />
<${FirmwareUpdatePanel} deviceID=${device.id} publishFn=${publishFn}
disabled=${!device.online}
info=${[localConfig.crnt_fw, localConfig.prev_fw]} />
</div>`;
}
const App = function() {
const [devices, setDevices] = useState([]);
const [currentDevID, setCurrentDevID] = useState(localStorage.getItem('currentDevID') || '');
const [loading, setLoading] = useState(true);
const [url, setUrl] = useState(localStorage.getItem('url') || DefaultUrl);
const [topic, setTopic] = useState(localStorage.getItem('topic') || DefaultTopic);
const [error, setError] = useState(null);
const [connected, setConnected] = useState(false);
const responseHandlers = useRef({});
function addResponseHandler(correlationId, handler) {
responseHandlers[correlationId] = handler;
}
function removeResponseHandler(correlationId) {
delete responseHandlers[correlationId];
}
const onRefresh = ev => window.location.reload();
const initConn = () => {
MqttClient = mqtt.connect(url, {connectTimeout: 5000, reconnectPeriod: 0});
MqttClient.on('connect', () => {
//console.log('Connected to the broker');
setLoading(false);
setError(null); // Reset error state upon successful connection
setConnected(true);
const statusTopic = topic + '/+/status'
const txTopic = topic + '/+/tx'
const subscribe = (topic) => {
MqttClient.subscribe(topic, (err) => {
if (err) {
console.error('Error subscribing to topic:', err);
setError('Error subscribing to topic');
} else {
//console.log('Successfully subscribed to ', topic);
}
});
};
subscribe(statusTopic);
subscribe(txTopic);
});
MqttClient.on('message', (topic, message) => {
// console.log(`Received message from ${topic}: ${message.toString()}`);
if (message.length == 0) return;
let response;
try {
response = JSON.parse(message.toString());
} catch (err) {
console.error(err);
return;
}
if (topic.endsWith('/status')) {
let device = {topic: topic, id: topic.split('/')[1], config: DefaultDeviceConfig};
const params = response.params;
if (!params) {
console.error('Invalid response');
return;
}
device.online = params.status === 'online';
//setConnected(device.online);
if (device.online) {
device.config = params;
if (!device.config.pins) device.config.pins = [];
}
setDevice(device)
} else if (topic.endsWith('/tx')) {
if (!response.id) {
console.error('Invalid response');
return;
}
const handler = responseHandlers[response.id];
if (handler) {
handler(response);
removeResponseHandler(response.id);
}
}
});
MqttClient.on('error', (err) => {
console.error('Connection error:', err);
setError('Connection cannot be established.');
});
MqttClient.on('close', () => {
if (!connected) {
console.error('Failed to connect to the broker.');
setError('Connection cannot be established.');
setLoading(false);
}
});
};
useEffect(() => initConn(), []);
const handlePublish = (methodName, parameters, timeout = 5000) => {
return new Promise((resolve, reject) => {
const randomIdGenerator = function(length) {
return Math.random().toString(36).substring(2, length + 2);
};
const randomID = randomIdGenerator(40);
const timeoutID = setTimeout(() => {
removeResponseHandler(randomID);
reject(new Error('Request timed out'));
}, timeout);
addResponseHandler(randomID, (messageData) => {
clearTimeout(timeoutID);
resolve(messageData);
});
if (currentDevID) {
const rxTopic = topic + `/${currentDevID}/rx`;
const rpcPayload = {method: methodName, id: randomID};
if (parameters) {
rpcPayload.params = parameters;
}
MqttClient.publish(rxTopic, JSON.stringify(rpcPayload));
}
});
};
const getDeviceByID = (deviceID) => devices.find(d => d.id === deviceID);
const setDevice = (devData) => {
setDevices(prevDevices => {
const devIndex =
prevDevices.findIndex(device => device.id === devData.id);
if (devIndex !== -1) {
if (!devData.online && !devData.config) {
const updatedDevices = [...prevDevices];
updatedDevices[devIndex].online = false;
return updatedDevices;
} else {
return prevDevices.map(device => device.id === devData.id ? devData : device);
}
} else {
return [...prevDevices, devData];
}
});
};
const setDeviceConfig = (deviceID, config) => {
setDevices(prevDevices => {
return prevDevices.map(device => {
if (device.id === deviceID) {
return {...device, config: config};
}
return device;
});
});
};
const onDeviceClick = (deviceID) => {
const device = getDeviceByID(deviceID);
if (device) {
setCurrentDevID(device.id);
localStorage.setItem('currentDevID', device.id);
}
};
if (error) {
return html`
<div class="min-h-screen bg-slate-100 flex flex-col">
<${Header}/>
<div class="flex-grow flex items-center justify-center">
<div class="bg-slate-300 p-8 rounded-lg shadow-md w-full max-w-md">
<h1 class="text-2xl font-bold text-gray-700 mb-4 text-center">Connection Error</h1>
<p class="text-gray-600 text-center mb-4">
Unable to connect to the MQTT broker.
</p>
<div class="text-center relative">
<${Button} title="Retry" onclick=${onRefresh}
icon=${Icons.refresh} class="absolute top-4 right-4" />
</div>
</div>
</div>
</div>`;
}
return html`
<div class="h-full flex flex-col">
<${Header}
topic=${topic} setTopic=${setTopic} url=${url}
setUrl=${setUrl} connected=${connected}
/>
<div class="flex grow overflow-auto">
<div class="w-60 overflow-auto">
<${Sidebar} devices=${devices} onclick=${onDeviceClick} />
<//>
<div class="grow bg-gray-200">
<${DeviceDashboard}
device=${getDeviceByID(currentDevID)} connected=${connected}
setDeviceConfig=${setDeviceConfig} publishFn=${handlePublish} />
<//>
<//>
<//>`;
};
window.onload = () => render(h(App), document.body);
@@ -1,9 +0,0 @@
NAME ?= $(notdir $(CURDIR))
build:
git clone --depth 1 https://github.com/mongoose-examples/$(NAME)
cp ./../../../mongoose.[ch] $(NAME)/source/
make -C $(NAME) build
clean:
rm -rf $(NAME)
@@ -1 +0,0 @@
../../mqtt-dashboard/device/net.c
@@ -1 +0,0 @@
../../mqtt-dashboard/device/net.h
-1
View File
@@ -1 +0,0 @@
pico-sdk
@@ -1 +0,0 @@
../../device-dashboard/net.c
@@ -1 +0,0 @@
../../device-dashboard/net.h
@@ -1 +0,0 @@
../../device-dashboard/packed_fs.c
-1
View File
@@ -1 +0,0 @@
../../mongoose.c
-1
View File
@@ -1 +0,0 @@
../../mongoose.h
@@ -1 +0,0 @@
../../modbus-dashboard/net.c
@@ -1 +0,0 @@
../../modbus-dashboard/net.h
@@ -1 +0,0 @@
../../modbus-dashboard/packed_fs.c
@@ -1 +0,0 @@
../../mongoose.c
@@ -1 +0,0 @@
../../mongoose.h
@@ -1,17 +0,0 @@
module.exports = {
content: ['./web_root/*.{html,js}'],
xplugins: [ 'tailwindcss', 'xautoprefixer' ],
corePlugins: {outline: false},
theme: {
extend: {},
fontFamily: {
sans:
[
"Inter var, Helvetica, sans-serif", {
fontFeatureSettings: '"cv11", "ss01"',
fontVariationSettings: '"opsz" 32',
}
]
}
}
}
@@ -1 +0,0 @@
../../device-dashboard/web_root/bundle.js
@@ -1 +0,0 @@
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.m-4{margin:1rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-5{margin-top:1.25rem;margin-bottom:1.25rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-96{width:24rem}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-\[85rem\]{max-width:85rem}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.border-separate{border-collapse:initial}.border-spacing-0{--tw-border-spacing-x:0px;--tw-border-spacing-y:0px;border-spacing:var(--tw-border-spacing-x) var(--tw-borLine truncated
+8126 -1788
View File
File diff suppressed because it is too large. Load diff
+1230 -487
View File
File diff suppressed because it is too large. Load diff
-1
View File
@@ -1 +0,0 @@
See detailed tutorials at https://mongoose.ws/documentation/#reference-projects
@@ -1,31 +0,0 @@
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_f7/Include
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 $(CFLAGS_EXTRA)
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
SOURCES += cmsis_f7/Source/Templates/gcc/startup_stm32f746xx.s
SOURCES += main.c hal.c mongoose.c packed_fs.c net.c
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
all build example: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
arm-none-eabi-size --format=berkeley $<
firmware.elf: cmsis_core cmsis_f7 $(SOURCES) hal.h link.ld Makefile
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
flash: firmware.bin
st-flash --reset write $< 0x8000000
cmsis_core:
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
cmsis_f7:
git clone --depth 1 -b v1.2.8 https://github.com/STMicroelectronics/cmsis_device_f7 $@
clean:
rm -rf firmware.* cmsis_core cmsis_f7
@@ -1 +0,0 @@
../../../windows-macos-linux/web-ui-dashboard/main.c
@@ -1 +0,0 @@
../../../windows-macos-linux/web-ui-dashboard/net.c
@@ -1 +0,0 @@
../../../windows-macos-linux/web-ui-dashboard/net.h
@@ -1 +0,0 @@
../../../windows-macos-linux/web-ui-dashboard/packed_fs.c
@@ -1,49 +0,0 @@
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
PROG ?= ./example # Program we are building
DELETE = rm -rf # Command to remove files
NPX ?= npx # For generating optimised tailwind CSS
OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c net.c packed_fs.c
CFLAGS += -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion -Wconversion -Wno-sign-conversion
CFLAGS += -fno-common -ffunction-sections -fdata-sections
CFLAGS += -g3 -Os -I.
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_ENABLE_PACKED_FS=1
ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe
PROG = example.exe # Use .exe suffix for the binary
CC = gcc # Use MinGW gcc compiler
CFLAGS += -lws2_32 # Link against Winsock library
DELETE = cmd /C del /Q /F /S # Command prompt command to delete files
endif
# Default target. Build and run program
all: $(PROG)
$(RUN) $(PROG) $(ARGS)
# Build program from sources
$(PROG): $(SOURCES)
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) $(OUT)
# Build using Microsoft Visual C compiler
vc: $(SOURCES) Makefile
cl $(SOURCES) /DMG_ENABLE_PACKED_FS=1 /MD /W3 /nologo /Fedemo.exe
# Bundle JS libraries (preact, preact-router, ...) into a single file
web_root/bundle.js:
curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@
# Create optimised CSS. Prerequisite: npm -g i tailwindcss tailwindcss-font-inter
css: web_root/index.html $(wildcard web_root/*.js)
$(NPX) tailwindcss -o web_root/main.css --minify
# Generate packed filesystem for serving Web UI
packed_fs.c: $(wildcard web_root/*) $(wildcard certs/*) Makefile
node pack.js $(addsuffix ::gzip, $(wildcard web_root/*)) certs/* > $@
# Cleanup. Delete built program and all build artifacts
clean:
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM mbedtls
@@ -1,13 +0,0 @@
# A complete device dashboard
This example is a demonstration of how Mongoose Library could be integrated
into an embedded device and provide a complete device dashboard with the
following features:
- Authentication: login-protected dashboard
- Multiple logins (with possibly different permissions)
- The Web UI can be fully embedded into the firmware binary, then not
needing a filesystem to serve it; so being resilient to FS problems
- All changes are propagated to all connected clients
See a detailed tutorial at https://mongoose.ws/tutorials/device-dashboard/
@@ -1,8 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIBCTCBsAIJAK9wbIDkHnAoMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAklFMB4X
DTIzMDEyOTIxMjEzOFoXDTMzMDEyNjIxMjEzOFowDTELMAkGA1UEBhMCSUUwWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAARzSQS5OHd17lUeNI+6kp9WYu0cxuEIi/JT
jphbCmdJD1cUvhmzM9/phvJT9ka10Z9toZhgnBq0o0xfTQ4jC1vwMAoGCCqGSM49
BAMCA0gAMEUCIQCe0T2E0GOiVe9KwvIEPeX1J1J0T7TNacgR0Ya33HV9VgIgNvdn
aEWiBp1xshs4iz6WbpxrS1IHucrqkZuJLfNZGZI=
-----END CERTIFICATE-----
@@ -1,5 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICBz3HOkQLPBDtdknqC7k1PNsWj6HfhyNB5MenfjmqiooAoGCCqGSM49
AwEHoUQDQgAEc0kEuTh3de5VHjSPupKfVmLtHMbhCIvyU46YWwpnSQ9XFL4ZszPf
6YbyU/ZGtdGfbaGYYJwatKNMX00OIwtb8A==
-----END EC PRIVATE KEY-----
@@ -1,21 +0,0 @@
// Copyright (c) 2024 Cesanta Software Limited
// All rights reserved
#pragma once
#define LED1 0
#define LED2 1
#define UART_DEBUG NULL
// No-op HAL API implementation for a device with GPIO and UART
#define hal_init()
#define hal_ram_free() 0
#define hal_ram_used() 0
#define gpio_output(pin)
#define gpio_toggle(pin)
#define gpio_read(pin) 0
#define gpio_write(pin, val)
#define uart_init(uart, baud)
#define uart_read_ready(uart) 0
#define uart_write_byte(uart, ch)
#define uart_write_buf(uart, buf, len)
@@ -1,32 +0,0 @@
// Copyright (c) 2024 Cesanta Software Limited
// All rights reserved
#include "hal.h"
#include "mongoose.h"
#include "net.h"
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis
static void timer_fn(void *arg) {
gpio_toggle(LED1); // Blink LED
(void) arg; // Unused
}
// In RTOS environment, you can run this function in a separate task
static void run_mongoose(void) {
struct mg_mgr mgr; // Mongoose event manager
mg_mgr_init(&mgr); // Initialise event manager
mg_log_set(MG_LL_DEBUG); // Set log level to debug
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, NULL);
net_init(&mgr); // Initialise application defined in net.c
for (;;) { // Infinite event loop
mg_mgr_poll(&mgr, 0); // Process network events
}
}
int main(void) {
hal_init(); // Cross-platform hardware init
run_mongoose(); // Initialise and run network application
return 0;
}
@@ -1,256 +0,0 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
#include "hal.h"
#include "net.h"
// Authenticated user.
// A user can be authenticated by:
// - a name:pass pair, passed in a header Authorization: Basic .....
// - an access_token, passed in a header Cookie: access_token=....
// When a user is shown a login screen, she enters a user:pass. If successful,
// a server responds with a http-only access_token cookie set.
struct user {
const char *name, *pass, *access_token;
};
// Settings
struct settings {
bool log_enabled;
int log_level;
long brightness;
char *device_name;
};
static struct settings s_settings = {true, 1, 57, NULL};
static const char *s_json_header =
"Content-Type: application/json\r\n"
"Cache-Control: no-cache\r\n";
int ui_event_next(int no, struct ui_event *e) {
if (no < 0 || no >= MAX_EVENTS_NO) return 0;
srand((unsigned) no);
e->type = (uint8_t) rand() % 4;
e->prio = (uint8_t) rand() % 3;
e->timestamp =
(unsigned long) ((int64_t) mg_now() - 86400 * 1000 /* one day back */ +
no * 300 * 1000 /* 5 mins between alerts */ +
1000 * (rand() % 300) /* randomize event time */) /
1000UL;
mg_snprintf(e->text, MAX_EVENT_TEXT_SIZE, "event#%d", no);
return no + 1;
}
static void timer_sntp_fn(void *param) { // SNTP timer function. Sync up time
mg_sntp_connect(param, "udp://time.google.com:123", NULL, NULL);
}
// Parse HTTP requests, return authenticated user or NULL
static struct user *authenticate(struct mg_http_message *hm) {
// In production, make passwords strong and tokens randomly generated
// In this example, user list is kept in RAM. In production, it can
// be backed by file, database, or some other method.
static struct user users[] = {
{"admin", "admin", "admin_token"},
{"user1", "user1", "user1_token"},
{"user2", "user2", "user2_token"},
{NULL, NULL, NULL},
};
char user[64], pass[64];
struct user *u, *result = NULL;
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
MG_VERBOSE(("user [%s] pass [%s]", user, pass));
if (user[0] != '\0' && pass[0] != '\0') {
// Both user and password is set, search by user/password
for (u = users; result == NULL && u->name != NULL; u++)
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) result = u;
} else if (user[0] == '\0') {
// Only password is set, search by token
for (u = users; result == NULL && u->name != NULL; u++)
if (strcmp(pass, u->access_token) == 0) result = u;
}
return result;
}
static void handle_login(struct mg_connection *c, struct user *u) {
char cookie[256];
const char *cookie_name = c->is_tls ? "secure_access_token" : "access_token";
mg_snprintf(cookie, sizeof(cookie),
"Set-Cookie: %s=%s; Path=/; "
"%sHttpOnly; SameSite=Lax; Max-Age=%d\r\n",
cookie_name, u->access_token,
c->is_tls ? "Secure; " : "", 3600 * 24);
mg_http_reply(c, 200, cookie, "{%m:%m}", MG_ESC("user"), MG_ESC(u->name));
}
static void handle_logout(struct mg_connection *c) {
char cookie[256];
const char *cookie_name = c->is_tls ? "secure_access_token" : "access_token";
mg_snprintf(cookie, sizeof(cookie),
"Set-Cookie: %s=; Path=/; "
"Expires=Thu, 01 Jan 1970 00:00:00 UTC; "
"%sHttpOnly; Max-Age=0; \r\n", cookie_name,
c->is_tls ? "Secure; " : "");
mg_http_reply(c, 200, cookie, "true\n");
}
static void handle_debug(struct mg_connection *c, struct mg_http_message *hm) {
int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
mg_log_set(level);
mg_http_reply(c, 200, "", "Debug level set to %d\n", level);
}
static size_t print_int_arr(void (*out)(char, void *), void *ptr, va_list *ap) {
size_t i, len = 0, num = va_arg(*ap, size_t); // Number of items in the array
int *arr = va_arg(*ap, int *); // Array ptr
for (i = 0; i < num; i++) {
len += mg_xprintf(out, ptr, "%s%d", i == 0 ? "" : ",", arr[i]);
}
return len;
}
static void handle_stats_get(struct mg_connection *c) {
int points[] = {21, 22, 22, 19, 18, 20, 23, 23, 22, 22, 22, 23, 22};
mg_http_reply(c, 200, s_json_header, "{%m:%d,%m:%d,%m:[%M]}\n",
MG_ESC("temperature"), 21, //
MG_ESC("humidity"), 67, //
MG_ESC("points"), print_int_arr,
sizeof(points) / sizeof(points[0]), points);
}
static size_t print_events(void (*out)(char, void *), void *ptr, va_list *ap) {
size_t len = 0;
struct ui_event ev;
int pageno = va_arg(*ap, int);
int no = (pageno - 1) * EVENTS_PER_PAGE;
int end = no + EVENTS_PER_PAGE;
while ((no = ui_event_next(no, &ev)) != 0 && no <= end) {
len += mg_xprintf(out, ptr, "%s{%m:%lu,%m:%d,%m:%d,%m:%m}\n", //
len == 0 ? "" : ",", //
MG_ESC("time"), ev.timestamp, //
MG_ESC("type"), ev.type, //
MG_ESC("prio"), ev.prio, //
MG_ESC("text"), MG_ESC(ev.text));
}
return len;
}
static void handle_events_get(struct mg_connection *c,
struct mg_http_message *hm) {
int pageno = (int) mg_json_get_long(hm->body, "$.page", 1);
mg_http_reply(c, 200, s_json_header, "{%m:[%M], %m:%d}\n", MG_ESC("arr"),
print_events, pageno, MG_ESC("totalCount"), MAX_EVENTS_NO);
}
static void handle_settings_set(struct mg_connection *c, struct mg_str body) {
struct settings settings;
char *s = mg_json_get_str(body, "$.device_name");
bool ok = true;
memset(&settings, 0, sizeof(settings));
mg_json_get_bool(body, "$.log_enabled", &settings.log_enabled);
settings.log_level = (int) mg_json_get_long(body, "$.log_level", 0);
settings.brightness = mg_json_get_long(body, "$.brightness", 0);
if (s && strlen(s) < MAX_DEVICE_NAME) {
free(settings.device_name);
settings.device_name = s;
} else {
free(s);
}
s_settings = settings; // Save to the device flash
mg_http_reply(c, 200, s_json_header,
"{%m:%s,%m:%m}", //
MG_ESC("status"), ok ? "true" : "false", //
MG_ESC("message"), MG_ESC(ok ? "Success" : "Failed"));
}
static void handle_settings_get(struct mg_connection *c) {
mg_http_reply(c, 200, s_json_header, "{%m:%s,%m:%hhu,%m:%hhu,%m:%m}\n", //
MG_ESC("log_enabled"),
s_settings.log_enabled ? "true" : "false", //
MG_ESC("log_level"), s_settings.log_level, //
MG_ESC("brightness"), s_settings.brightness, //
MG_ESC("device_name"), MG_ESC(s_settings.device_name));
}
static void handle_firmware_upload(struct mg_connection *c,
struct mg_http_message *hm) {
char name[64], offset[20], total[20];
struct mg_str data = hm->body;
long ofs = -1, tot = -1;
name[0] = offset[0] = '\0';
mg_http_get_var(&hm->query, "name", name, sizeof(name));
mg_http_get_var(&hm->query, "offset", offset, sizeof(offset));
mg_http_get_var(&hm->query, "total", total, sizeof(total));
MG_INFO(("File %s, offset %s, len %lu", name, offset, data.len));
if ((ofs = mg_json_get_long(mg_str(offset), "$", -1)) < 0 ||
(tot = mg_json_get_long(mg_str(total), "$", -1)) < 0) {
mg_http_reply(c, 500, "", "offset and total not set\n");
} else if (ofs == 0 && mg_ota_begin((size_t) tot) == false) {
mg_http_reply(c, 500, "", "mg_ota_begin(%ld) failed\n", tot);
} else if (data.len > 0 && mg_ota_write(data.buf, data.len) == false) {
mg_http_reply(c, 500, "", "mg_ota_write(%lu) @%ld failed\n", data.len, ofs);
mg_ota_end();
} else if (data.len == 0 && mg_ota_end() == false) {
mg_http_reply(c, 500, "", "mg_ota_end() failed\n", tot);
} else {
mg_http_reply(c, 200, s_json_header, "true\n");
}
}
// HTTP request handler function
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_ACCEPT) {
if (c->fn_data != NULL) { // TLS listener!
struct mg_tls_opts opts = {0};
opts.cert = mg_unpacked("/certs/server_cert.pem");
opts.key = mg_unpacked("/certs/server_key.pem");
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct user *u = authenticate(hm);
if (mg_match(hm->uri, mg_str("/api/#"), NULL) && u == NULL) {
mg_http_reply(c, 403, "", "Not Authorised\n");
} else if (mg_match(hm->uri, mg_str("/api/login"), NULL)) {
handle_login(c, u);
} else if (mg_match(hm->uri, mg_str("/api/logout"), NULL)) {
handle_logout(c);
} else if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) {
handle_debug(c, hm);
} else if (mg_match(hm->uri, mg_str("/api/stats/get"), NULL)) {
handle_stats_get(c);
} else if (mg_match(hm->uri, mg_str("/api/events/get"), NULL)) {
handle_events_get(c, hm);
} else if (mg_match(hm->uri, mg_str("/api/settings/get"), NULL)) {
handle_settings_get(c);
} else if (mg_match(hm->uri, mg_str("/api/settings/set"), NULL)) {
handle_settings_set(c, hm->body);
} else if (mg_match(hm->uri, mg_str("/api/firmware/upload"), NULL)) {
handle_firmware_upload(c, hm);
} else {
struct mg_http_serve_opts opts;
memset(&opts, 0, sizeof(opts));
opts.fs = HAL_FS;
opts.root_dir = HAL_WEB_ROOT_DIR;
mg_http_serve_dir(c, ev_data, &opts);
}
MG_DEBUG(("%lu %.*s %.*s -> %.*s", c->id, (int) hm->method.len,
hm->method.buf, (int) hm->uri.len, hm->uri.buf, (int) 3,
&c->send.buf[9]));
}
}
void net_init(struct mg_mgr *mgr) {
s_settings.device_name = strdup("My Device");
mg_http_listen(mgr, HTTP_URL, ev_handler, NULL);
mg_http_listen(mgr, HTTPS_URL, ev_handler, (void *) 1);
mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT,
timer_sntp_fn, mgr);
}
@@ -1,50 +0,0 @@
// Copyright (c) 2023-2024 Cesanta Software Limited
// All rights reserved
#pragma once
#include "mongoose.h"
#ifdef __cplusplus
extern "C" {
#endif
#if MG_ENABLE_FATFS
#define HAL_FS (&mg_fs_fat)
#define HAL_ROOT_DIR "/"
#elif MG_ENABLE_PACKED_FS
#define HAL_FS (&mg_fs_packed)
#define HAL_ROOT_DIR "/"
#else
#define HAL_FS (&mg_fs_posix)
#define HAL_ROOT_DIR "./"
#endif
#define HAL_WEB_ROOT_DIR HAL_ROOT_DIR "web_root"
#if defined(HTTP_URL) && defined(HTTPS_URL)
// Allow to override via the build flags
#elif MG_ENABLE_TCPIP
#define HTTP_URL "http://0.0.0.0:80" // Embedded build:
#define HTTPS_URL "https://0.0.0.0:443" // Use standard privileged ports
#else
#define HTTP_URL "http://0.0.0.0:8000" // Workstation build:
#define HTTPS_URL "https://0.0.0.0:8443" // Use non-privileged ports
#endif
#define MAX_DEVICE_NAME 40
#define MAX_EVENTS_NO 400
#define MAX_EVENT_TEXT_SIZE 10
#define EVENTS_PER_PAGE 20
// Event log entry
struct ui_event {
uint8_t type, prio;
unsigned long timestamp;
char text[10];
};
void net_init(struct mg_mgr *mgr);
#ifdef __cplusplus
}
#endif
@@ -1,70 +0,0 @@
// DO NOT EDIT. This file is generated using this command:
// /usr/local/bin/node /Users/cpq/src/mongoose/reference-projects/windows-macos-linux/web-ui-dashboard/pack.js web_root/bundle.js::gzip web_root/components.js::gzip web_root/history.min.js::gzip web_root/index.html::gzip web_root/main.css::gzip web_root/main.js::gzip certs/server_cert.pem certs/server_key.pem
#include <stddef.h>
#include <string.h>
#include <time.h>
#if defined(__cplusplus)
extern "C" {
#endif
const char *mg_unlist(size_t no);
const char *mg_unpack(const char *, size_t *, time_t *);
#if defined(__cplusplus)
}
#endif
static const unsigned char v0[] = {31,139,8,0,0,0,0,0,0,19,173,60,253,119,219,54,146,255,138,197,203,227,2,213,132,150,210,118,239,142,10,170,151,186,105,157,54,73,179,249,234,238,170,42,31,69,65,22,107,10,148,65,80,137,107,234,254,246,123,51,0,72,74,150,123,119,251,238,23,11,223,24,12,6,243,77,239,82,125,166,192,128,132,4,52,148,144,67,13,5,100,226,110,15,169,152,205,161,18,231,105,150,155,70,126,102,211,184,106,174,26,213,108,155,71,188,209,219,117,115,165,243,101,83,126,170,154,141,202,26,101,62,53,185,146,179,108,61,111,254,40,203,230,183,82,47,155,220,72,157,158,231,147,85,173,50,147,151,234,108,197,20,24,126,183,42,53,219,165,250,76,158,229,234,204,112,53,147,115,97,102,114,62,209,210,212,90,157,169,125,59,99,203,20,191,195,177,70,168,104,155,106,169,204,235,114,41,39,38,12,77,164,229,166,220,201,139,117,94,44,153,226,221,164,53,163,19,217,137,238,88,226,110,63,193,125,115,220,83,242,224,90,222,6,66,228,83,45,228,44,159,199,129,150,43,170,151,182,94,207,242,57,149,38,249,138,165,250,170,222,72,101,170,168,144,234,202,172,191,121,18,134,172,142,50,220,88,75,37,238,245,127,57,85,81,150,22,69,55,19,158,240,56,225,16,120,24,3,33,204,237,86,150,171,51,19,134,170,46,138,129,48,209,82,174,210,186,48,111,116,185,173,120,11,236,81,251,174,204,151,103,35,33,4,130,136,112,32,164,135,99,102,249,156,123,92,46,153,129,154,238,22,119,233,33,105,201,148,191,116,139,168,90,220,33,72,177,130,45,46,18,39,112,45,111,99,13,90,174,226,18,146,228,58,198,21,32,73,252,239,34,30,65,146,72,95,93,198,22,52,72,146,204,183,173,109,33,43,85,101,116,157,153,82,119,131,118,212,135,56,31,14,101,156,239,219,219,183,173,29,90,118,170,92,74,188,111,42,176,154,67,221,29,99,199,248,157,157,120,151,213,26,233,131,150,221,119,35,54,72,66,126,237,246,210,186,254,91,75,148,102,157,87,17,157,92,40,160,74,86,42,35,63,27,97,186,177,87,118,108,190,98,22,74,195,219,133,147,100,122,197,240,7,240,79,148,36,215,81,174,150,242,243,207,43,166,248,112,204,9,172,73,75,250,19,243,84,209,32,75,50,19,51,28,114,183,236,64,48,41,168,115,102,230,220,227,65,70,73,34,253,118,84,113,8,59,65,83,42,194,2,194,99,183,237,14,176,104,223,19,200,73,183,159,162,253,218,189,176,146,217,119,138,69,11,77,22,45,210,74,10,186,80,35,70,255,226,1,238,238,45,104,207,178,208,50,189,222,187,227,33,148,189,27,188,70,160,217,0,231,44,195,144,64,90,138,193,136,135,161,142,182,117,181,102,138,135,225,224,34,74,18,61,28,54,77,57,16,244,32,22,101,173,50,249,86,170,165,212,185,186,226,97,200,88,121,178,167,105,114,206,46,122,143,227,130,89,44,121,222,136,44,164,128,140,174,79,71,85,169,13,171,249,68,9,29,85,235,124,101,24,159,112,15,157,17,218,161,4,18,225,136,189,244,133,66,176,156,144,195,163,36,217,225,31,9,44,35,20,188,65,248,18,100,186,172,20,43,118,183,135,156,211,40,145,227,223,225,24,222,179,12,114,40,1,71,43,176,43,14,132,200,162,242,147,146,250,221,199,31,158,23,18,153,13,88,124,227,180,245,116,86,204,221,99,4,75,178,197,244,138,229,60,46,128,250,57,188,101,9,228,156,106,114,32,138,48,92,176,156,115,240,135,248,198,32,150,221,137,249,132,144,44,70,29,166,62,179,251,242,163,178,200,91,193,22,214,176,131,91,88,192,53,92,136,36,12,233,93,52,77,10,159,197,133,39,28,196,41,30,233,26,207,190,18,163,201,234,169,105,251,14,136,106,71,136,186,158,173,230,194,158,133,237,132,153,173,230,188,105,130,69,89,22,50,237,189,129,93,211,156,120,25,187,41,206,140,131,202,224,197,31,142,86,245,102,33,245,97,219,34,191,202,149,233,207,95,18,52,176,35,116,218,63,59,30,63,211,58,189,141,242,138,126,217,142,79,151,108,3,119,158,217,196,187,125,111,56,49,226,120,23,37,201,226,155,209,116,201,118,244,90,97,103,185,15,236,162,107,121,11,187,72,203,213,148,254,218,251,219,17,197,196,59,78,236,7,107,66,82,227,130,176,178,24,142,221,5,11,182,22,23,22,43,235,48,164,213,132,88,227,15,214,112,43,129,117,44,112,28,231,104,115,34,139,74,158,225,101,108,197,104,178,125,250,121,178,29,14,105,47,90,111,139,15,249,207,23,187,195,81,126,53,251,158,215,116,81,251,247,76,193,14,214,98,221,52,217,1,157,192,173,216,217,71,176,21,116,86,30,134,107,252,29,136,109,24,178,235,166,97,72,22,28,168,49,12,175,237,123,167,154,199,61,184,198,45,97,35,107,154,91,216,113,238,30,193,237,212,113,234,69,24,178,133,184,61,41,130,237,65,240,64,72,133,120,158,36,185,158,238,136,205,20,226,57,219,65,1,138,199,133,248,96,207,1,23,112,11,197,201,165,164,91,138,40,122,41,10,206,227,2,143,132,60,15,31,87,209,83,98,6,66,133,33,43,196,21,91,115,190,247,207,64,138,5,172,196,231,201,234,241,227,9,183,135,192,91,10,67,246,39,219,117,227,112,133,48,244,37,65,180,177,108,225,121,198,18,30,41,249,217,188,203,23,5,114,62,248,133,225,88,32,130,225,40,17,174,73,243,176,239,240,186,255,14,95,49,124,121,112,61,27,14,219,159,30,203,124,110,25,65,167,221,37,160,173,16,128,82,140,38,58,12,203,167,158,169,76,202,225,144,179,68,232,89,57,39,182,135,212,172,192,136,19,71,76,172,44,123,206,18,90,62,254,192,144,217,32,187,73,136,114,12,111,117,157,158,160,190,180,130,218,119,8,211,52,179,185,123,32,234,20,187,80,77,195,14,31,177,226,83,21,85,229,70,50,230,151,69,5Line truncated
static const unsigned char v1[] = {31,139,8,0,0,0,0,0,0,19,237,125,107,115,219,70,182,224,119,255,138,19,150,54,36,199,236,22,186,241,150,68,165,28,207,77,57,85,214,220,84,156,232,75,110,118,13,129,32,137,17,30,92,0,164,36,107,248,223,183,206,233,198,147,148,236,100,124,167,118,181,83,149,64,64,163,159,231,253,2,61,222,150,17,148,85,17,135,213,248,252,85,156,110,242,162,130,71,88,207,160,136,178,69,84,204,96,91,70,31,170,160,138,232,238,63,150,203,40,172,232,246,231,104,57,131,117,149,38,51,248,57,223,86,81,1,123,88,22,121,10,48,230,167,55,219,108,145,68,252,239,229,248,252,213,171,211,83,120,23,37,155,168,128,229,54,11,171,56,207,160,90,7,21,20,81,181,45,178,18,2,216,20,121,26,151,81,221,92,230,201,46,42,33,88,226,172,139,40,9,30,94,133,121,86,86,240,87,188,135,57,76,210,114,6,187,32,153,194,252,18,178,232,14,126,82,19,76,244,88,108,46,163,234,151,56,141,242,109,85,183,206,160,30,54,61,127,245,42,186,167,179,170,137,127,196,63,48,135,199,87,0,235,40,40,170,51,220,211,166,196,137,240,140,31,47,202,221,10,194,36,40,203,249,201,35,189,226,244,180,135,251,52,201,202,249,104,93,85,155,179,211,211,187,187,59,126,103,242,188,88,157,74,195,48,78,203,221,106,4,203,56,73,230,163,44,207,162,17,236,226,232,238,251,252,126,62,50,192,0,105,129,180,70,151,23,155,160,90,35,22,242,219,136,37,113,22,133,193,102,62,42,242,109,182,24,117,155,255,158,199,217,176,253,46,94,84,235,249,72,142,96,49,31,93,89,220,20,30,56,120,13,44,110,3,254,111,128,97,24,216,230,88,239,133,4,105,224,93,226,114,199,147,140,174,189,158,140,58,178,166,187,203,29,211,73,152,192,41,213,245,72,119,48,62,141,46,47,78,241,24,151,23,120,230,203,143,179,87,0,139,252,46,123,83,20,57,30,248,95,9,208,1,108,4,183,235,166,249,40,220,22,69,148,85,111,243,36,47,70,151,240,167,64,143,144,246,193,227,210,126,231,114,59,144,92,218,64,23,130,72,243,184,243,7,175,154,167,245,177,55,52,112,199,134,175,88,243,238,157,176,175,124,16,50,49,193,76,13,48,18,147,153,41,51,193,188,198,183,35,56,189,132,14,240,183,155,127,131,254,107,130,62,53,152,153,48,4,57,130,30,193,158,154,204,188,22,7,128,15,243,213,139,131,56,183,125,11,76,238,91,33,55,124,198,109,75,114,219,97,220,183,64,112,33,240,102,45,185,237,155,33,183,17,116,130,27,146,155,190,71,111,185,111,37,92,10,19,4,151,158,8,185,225,152,220,116,81,82,153,220,241,28,238,88,54,247,92,110,184,22,55,44,46,44,151,27,158,201,165,228,66,186,220,148,22,23,190,195,93,196,130,139,19,187,54,23,210,74,4,151,194,101,220,178,157,64,112,33,109,80,87,3,12,33,184,233,114,203,199,46,190,131,216,180,220,131,62,140,75,7,4,183,76,129,178,205,48,76,238,73,55,100,92,250,38,151,22,227,150,233,113,71,152,120,35,184,239,203,192,225,174,237,131,186,226,4,6,112,105,219,33,227,134,225,114,211,245,184,48,61,238,218,220,50,185,143,75,27,134,205,61,233,133,220,146,22,55,109,110,155,22,247,109,171,94,22,87,149,190,247,212,238,4,55,29,159,91,62,237,174,62,104,200,184,105,219,140,11,211,100,220,181,25,55,92,137,155,119,29,132,72,224,112,219,5,186,232,3,34,4,61,28,100,10,46,60,147,113,219,19,220,242,109,198,29,203,226,158,227,39,172,193,11,30,196,231,182,133,189,28,238,91,184,5,66,157,88,51,196,172,21,50,66,45,174,39,25,226,150,213,152,87,179,48,133,93,198,13,7,223,187,22,227,166,144,12,49,76,235,49,238,185,184,69,9,116,169,183,200,16,203,184,71,137,7,243,29,198,93,201,16,213,234,96,140,112,173,96,112,20,215,10,82,12,209,77,16,117,217,113,136,114,233,48,133,110,68,13,238,70,186,33,151,62,46,102,113,203,116,25,162,155,227,249,21,182,125,19,119,138,87,194,54,35,108,35,178,241,112,30,34,193,83,72,80,67,20,21,209,188,222,81,98,163,213,147,231,182,136,100,203,8,231,120,92,135,48,206,77,219,65,124,115,215,70,120,72,104,161,66,216,231,134,133,44,227,48,110,120,174,6,167,199,77,19,111,60,147,219,158,196,25,109,141,0,199,71,70,180,20,170,62,41,185,245,103,69,130,176,65,200,192,4,19,217,93,48,7,12,80,15,134,112,208,28,24,8,197,50,170,170,56,91,149,239,94,154,104,20,6,183,193,89,251,220,181,245,125,32,56,162,213,86,128,49,193,72,77,48,186,141,6,54,94,33,78,193,65,45,150,154,32,36,205,144,50,188,246,122,27,199,166,48,104,138,148,209,28,6,205,225,51,103,109,210,20,230,31,154,66,45,72,171,63,133,179,235,151,134,51,7,132,201,237,107,2,151,1,120,244,30,180,12,52,175,152,217,3,22,181,1,142,184,22,14,183,83,33,153,249,79,77,192,28,230,215,19,152,95,62,129,79,19,24,252,16,89,97,144,189,52,60,185,220,38,216,188,115,222,244,13,51,197,59,59,193,237,43,4,166,234,36,188,126,47,33,13,188,163,110,8,185,235,131,14,194,3,234,179,102,216,133,249,96,12,87,18,180,146,240,118,140,214,250,98,153,7,202,255,137,202,219,42,223,188,52,180,248,32,92,180,151,81,227,185,65,13,1,84,240,62,160,205,33,223,35,226,164,88,163,129,225,72,65,151,55,117,63,4,34,218,239,238,53,205,146,58,76,200,107,49,48,229,69,107,202,191,179,185,180,135,88,1,97,95,99,123,42,60,48,6,196,33,208,14,3,243,200,56,195,132,102,208,181,144,127,116,73,73,75,14,25,47,72,162,127,109,184,224,95,162,213,44,238,161,185,141,182,184,12,164,201,61,203,3,253,7,1,105,115,203,182,40,28,240,198,227,190,227,130,186,106,166,66,33,181,99,220,189Line truncated
static const unsigned char v2[] = {31,139,8,0,0,0,0,0,0,19,237,91,109,111,219,184,150,254,43,182,6,43,144,48,163,218,157,185,179,187,114,57,70,218,166,47,64,130,4,77,218,249,96,24,3,69,166,108,78,100,210,165,40,39,134,173,255,190,56,164,168,23,91,73,211,189,157,189,131,221,253,18,75,124,61,60,58,60,231,121,14,153,126,146,139,88,115,41,144,38,2,239,60,121,251,39,139,181,71,169,222,174,153,76,122,236,97,45,149,206,124,255,168,102,37,231,121,202,38,246,39,40,219,81,129,112,232,185,49,235,198,115,150,112,193,124,223,254,6,209,106,62,177,143,104,58,35,2,135,143,205,59,41,127,131,15,60,211,82,109,205,248,186,249,86,32,189,228,25,169,150,129,119,138,233,92,137,94,189,48,188,115,207,61,129,36,222,241,4,177,169,156,225,178,33,60,59,249,199,155,72,245,20,133,34,186,43,203,194,93,65,248,60,148,36,149,209,156,205,195,254,168,24,151,93,53,116,141,163,52,69,202,141,64,20,169,159,5,38,42,176,221,104,127,88,87,20,48,13,163,187,106,32,17,172,168,38,34,136,41,35,34,88,83,207,35,2,13,113,129,166,205,239,67,24,222,121,121,198,122,153,86,60,214,222,184,90,151,132,85,58,161,124,95,7,127,252,193,178,11,251,133,116,184,155,179,36,202,83,29,234,162,16,141,42,144,73,4,177,98,145,102,87,145,94,82,17,172,35,149,185,231,84,198,17,140,158,157,42,118,246,53,143,82,234,26,159,151,53,85,193,5,91,73,181,173,62,75,89,250,33,202,150,135,101,175,149,188,207,152,114,197,27,201,231,189,161,83,59,122,137,199,151,198,18,2,107,30,87,74,174,153,210,91,36,136,215,158,218,35,59,38,242,21,83,209,109,202,194,254,144,44,152,14,143,173,64,29,72,92,20,152,60,58,195,209,130,159,61,201,81,207,162,192,102,81,156,50,52,122,98,81,149,190,159,57,21,175,191,208,147,75,169,63,234,179,7,174,187,56,225,35,202,208,191,99,18,83,137,34,76,114,202,208,127,96,146,81,137,114,76,18,202,208,127,98,146,82,137,18,60,126,228,235,198,65,105,121,164,203,36,178,163,218,182,25,165,174,190,32,7,94,170,185,7,14,12,122,44,130,104,62,63,103,209,156,139,197,117,26,101,75,218,244,4,118,181,222,11,143,82,170,131,120,25,169,83,141,134,120,162,67,239,133,55,208,5,17,1,12,188,254,254,1,130,44,191,205,180,66,35,28,214,195,92,41,150,240,7,218,22,191,212,248,208,140,192,197,156,61,92,38,72,52,134,16,65,202,196,66,47,155,35,221,168,136,167,207,151,72,151,67,156,140,204,184,41,143,25,26,146,19,39,92,189,205,155,35,193,55,23,84,239,247,222,11,143,48,112,66,18,254,40,42,42,49,189,159,60,60,86,125,74,79,70,190,143,36,21,78,102,133,137,168,223,134,68,97,183,1,26,157,39,208,185,180,55,55,6,171,123,241,131,49,56,134,130,57,139,229,156,125,254,244,17,9,76,118,235,72,47,69,180,98,161,32,25,139,84,188,12,189,9,172,156,77,60,47,100,100,25,101,203,208,251,9,74,36,148,200,162,104,187,184,142,245,6,110,76,194,168,14,236,168,68,82,29,192,96,68,81,38,42,1,140,106,170,53,48,223,247,38,94,159,82,230,251,72,13,104,41,73,195,42,24,72,55,96,152,72,223,247,126,130,166,178,108,106,69,108,52,149,32,246,64,98,162,138,182,189,255,53,94,255,25,206,189,229,155,75,79,19,101,25,95,136,253,190,21,93,165,66,86,149,163,177,120,21,169,69,190,98,66,103,165,5,142,197,96,96,85,205,104,85,55,21,179,177,235,38,123,92,244,24,46,39,88,43,169,37,128,0,208,254,229,189,112,78,205,134,89,70,36,246,125,4,113,215,4,105,92,184,229,23,196,184,218,33,38,17,149,96,73,49,188,142,192,109,73,20,131,219,50,142,248,104,145,109,77,19,105,69,229,110,241,229,230,2,213,139,69,13,79,244,4,113,138,134,36,171,119,18,70,26,19,30,100,58,210,140,10,28,34,78,21,218,21,68,99,98,199,162,148,242,202,212,124,31,213,47,212,243,76,87,99,121,19,107,82,238,181,182,16,211,197,22,130,165,13,220,11,14,235,98,143,112,99,181,19,107,108,246,229,96,8,40,2,251,27,216,71,232,110,139,188,82,208,62,165,194,247,27,66,155,53,217,233,203,213,129,184,119,108,75,25,24,118,99,37,19,239,133,157,215,21,28,204,93,173,24,13,73,228,220,59,110,84,16,89,61,98,144,172,234,208,40,39,188,232,52,224,78,47,91,239,110,74,13,190,113,250,119,59,221,20,219,71,40,52,170,128,34,120,128,2,88,38,188,223,177,173,239,163,33,201,107,177,181,213,135,113,209,145,102,248,91,27,215,88,59,109,196,222,98,172,43,228,44,255,242,93,95,161,172,159,49,225,20,73,240,217,13,97,160,86,83,145,167,41,105,108,139,134,38,169,104,54,215,212,152,9,178,93,96,237,172,209,11,182,18,81,6,107,67,117,159,106,183,177,58,216,129,158,104,232,129,67,61,62,218,105,124,210,209,65,78,36,226,68,225,80,161,254,16,254,66,52,233,143,112,193,210,140,245,76,97,65,36,157,206,136,234,112,248,253,97,83,84,188,19,160,196,104,189,78,183,200,26,61,169,252,20,174,16,186,12,214,121,182,68,172,165,50,65,251,35,34,169,12,18,158,106,166,208,113,88,238,105,8,15,5,168,135,55,231,116,206,79,211,67,127,73,4,61,85,42,218,130,59,97,116,56,102,175,244,152,13,6,88,76,217,172,225,64,217,108,44,131,68,170,179,40,94,118,206,219,94,145,192,69,181,150,93,198,244,149,146,171,181,14,5,137,165,72,184,90,221,168,72,100,28,198,184,145,33,35,209,122,205,196,252,156,103,154,9,166,66,69,132,212,60,217,186,130,44,228,128,17,133,219,10,148,127,39,68,139,35,241,57,99,111,47,47,104,31,121,185,176,248,117,94,127,224,123,46,230,242,126,191,239,219,135,96,46,99,179,238,227,146,210,1Line truncated
static const unsigned char v3[] = {31,139,8,0,0,0,0,0,0,19,93,147,77,115,219,32,16,134,239,249,21,91,46,58,52,66,232,91,206,8,205,164,105,14,61,116,218,67,219,105,143,68,90,75,36,8,84,192,114,252,239,59,178,108,215,201,133,133,125,159,133,133,93,234,15,159,191,61,252,248,243,253,17,6,63,170,230,166,94,12,40,161,123,78,80,19,104,149,112,142,147,33,220,238,148,130,167,62,220,15,210,35,105,110,0,234,1,69,183,76,0,106,47,189,194,166,142,86,187,250,70,244,2,218,65,88,135,158,147,157,223,134,21,129,232,90,28,188,159,66,252,187,147,51,39,191,195,159,247,225,131,25,39,225,229,147,66,2,173,209,30,181,231,228,203,35,199,174,199,119,177,90,140,200,201,44,113,63,25,235,175,240,189,236,252,192,59,156,101,139,225,113,113,11,82,75,47,133,10,93,43,20,242,152,178,255,155,41,169,95,192,162,226,68,182,70,19,240,135,9,57,145,163,232,49,114,115,255,241,117,84,4,6,139,91,78,58,225,197,221,27,229,182,118,115,15,175,163,210,142,7,203,109,238,162,104,191,223,211,125,74,141,237,163,132,49,182,160,1,108,165,82,60,208,70,99,0,75,206,159,204,43,15,24,48,72,50,72,178,0,156,183,230,229,148,46,15,98,154,159,93,60,104,119,214,162,246,15,70,25,27,52,80,79,194,15,103,94,73,141,173,152,120,96,205,78,119,193,181,251,217,72,125,241,119,60,248,26,103,180,202,75,136,75,202,170,68,36,41,173,178,10,78,134,1,99,57,205,242,44,140,105,26,223,87,116,83,148,176,142,12,88,28,87,176,161,101,62,135,180,252,181,185,47,160,56,6,20,176,153,105,153,139,247,116,152,208,52,78,160,160,44,73,218,152,150,105,74,139,12,82,154,23,16,83,86,229,176,156,148,195,114,210,152,211,50,206,128,137,36,163,73,158,195,201,28,119,57,73,23,36,133,20,24,196,23,33,128,168,129,122,121,222,230,93,53,215,106,141,66,106,218,58,71,214,234,58,127,80,232,6,68,127,162,235,232,220,191,245,147,233,14,231,78,31,165,14,135,208,181,22,81,147,166,142,22,237,8,185,214,202,201,131,179,45,39,131,116,222,216,3,29,165,166,207,110,193,86,245,26,92,27,105,52,221,110,233,230,99,216,49,165,183,124,29,173,255,238,31,169,238,250,235,136,3,0,0,0};
static const unsigned char v4[] = {31,139,8,0,0,0,0,0,0,19,237,60,217,142,228,56,114,191,34,247,96,128,202,177,168,214,153,89,169,130,141,53,22,48,188,192,142,31,108,63,120,209,213,15,76,137,153,201,45,93,38,169,170,204,214,202,223,110,4,41,74,212,145,215,28,246,236,194,24,84,87,49,46,6,131,100,40,24,12,206,231,31,254,206,18,152,102,31,180,72,19,206,173,247,192,9,28,223,250,139,245,227,31,254,195,250,35,77,72,193,137,245,23,235,40,68,197,227,207,159,13,82,39,41,243,31,62,255,96,199,120,47,8,179,227,29,217,151,140,52,187,242,132,56,253,70,139,67,188,43,89,74,24,218,149,167,23,245,103,236,90,188,204,104,106,125,71,34,178,33,187,118,194,139,144,248,64,73,89,8,82,136,248,211,167,246,40,242,172,201,104,65,208,145,208,195,81,196,158,19,189,160,15,178,123,163,2,9,114,18,208,19,65,56,253,115,205,69,236,185,238,247,47,40,47,191,33,129,119,18,19,135,47,168,52,91,198,159,251,178,16,104,143,115,154,157,227,63,20,130,48,235,29,51,251,159,24,197,153,253,47,36,123,39,130,38,216,230,184,224,136,19,70,247,29,3,193,162,102,4,113,34,4,45,14,60,254,148,188,123,222,39,251,19,231,174,247,73,209,188,99,70,177,160,101,97,80,149,21,255,246,201,10,252,118,87,166,231,38,199,236,64,139,216,125,49,199,70,139,35,97,84,180,71,214,116,16,247,37,41,179,146,105,76,103,68,36,202,10,125,208,84,28,99,175,58,181,120,183,99,241,199,145,48,242,244,69,80,145,145,175,171,102,100,162,148,36,37,147,250,196,117,145,18,6,125,90,105,41,4,73,95,110,17,180,71,207,62,250,246,49,176,143,161,125,140,236,227,186,145,67,148,54,212,106,73,200,199,120,16,184,25,171,62,237,72,211,237,108,46,88,89,28,26,83,200,174,204,82,194,218,164,76,137,253,182,75,237,138,17,155,227,188,106,204,57,171,41,202,203,162,228,21,78,136,253,239,255,252,99,89,148,232,223,200,161,206,48,179,127,36,69,86,218,63,150,5,78,74,251,247,101,193,203,12,115,251,143,116,71,84,247,22,80,219,191,47,107,70,9,179,254,149,124,216,189,168,151,97,124,30,201,91,158,227,44,51,198,252,236,126,223,242,122,103,243,186,50,160,155,232,251,209,84,186,47,85,201,169,28,40,35,25,22,244,157,188,188,19,6,43,42,67,56,163,7,48,0,21,20,103,32,172,217,149,66,148,121,140,28,63,130,46,235,170,17,101,21,35,7,90,2,239,50,210,72,243,209,34,133,125,225,234,117,176,184,56,146,50,203,112,197,73,172,255,104,119,181,16,101,97,211,162,170,133,93,86,226,192,202,186,178,57,201,72,34,108,16,140,25,193,35,211,142,38,86,153,2,182,214,194,60,47,45,224,201,162,237,215,122,133,211,20,188,130,171,53,82,42,168,177,9,134,11,190,47,89,30,23,101,65,218,47,226,92,145,127,80,116,95,109,213,98,132,19,161,27,188,222,229,84,124,181,21,73,191,224,113,85,17,204,112,145,144,88,97,94,118,56,121,131,17,23,105,111,47,105,120,19,65,115,124,32,170,227,88,250,143,125,153,212,156,209,226,208,148,181,128,33,198,184,22,101,135,172,41,162,197,59,206,104,170,124,221,17,167,229,135,226,174,88,121,96,132,243,230,194,100,199,177,86,148,22,5,97,136,87,180,64,157,53,6,92,89,139,49,78,251,3,169,68,55,126,130,89,114,252,186,52,112,176,231,158,146,44,125,233,148,71,229,126,207,137,136,145,95,157,12,21,148,8,99,83,46,9,83,70,233,121,246,52,35,168,174,178,18,167,232,166,233,97,189,244,27,157,215,121,142,217,185,73,41,175,50,124,142,51,202,5,162,130,228,237,46,43,147,183,255,170,75,65,236,52,181,211,204,222,211,67,205,136,61,115,61,246,145,217,21,56,131,222,127,182,114,156,156,136,57,196,206,200,129,20,105,51,172,186,156,20,181,93,102,118,13,159,20,46,16,23,231,76,13,112,105,141,246,27,131,17,185,3,244,140,182,114,31,197,106,41,84,25,78,200,81,122,171,126,39,205,81,77,89,225,132,138,115,236,117,91,227,187,109,130,3,188,215,162,150,165,220,35,224,11,43,179,97,155,116,19,146,212,140,151,44,174,74,10,95,181,54,78,41,7,31,146,106,68,74,246,184,206,68,139,235,148,150,118,130,139,119,204,109,146,239,72,106,211,61,195,57,177,105,126,176,203,221,159,193,63,240,247,131,253,78,83,82,246,19,39,167,107,234,205,114,154,166,25,105,129,81,81,231,248,164,191,81,224,58,70,11,248,72,211,148,20,95,123,137,114,141,253,96,199,49,108,201,148,149,213,52,164,144,97,65,231,223,192,73,211,226,128,78,177,251,178,4,63,107,184,244,40,25,22,100,32,29,64,61,21,43,5,22,68,183,248,27,249,24,200,101,171,167,228,9,206,64,150,103,54,207,186,89,225,2,157,98,107,104,156,251,6,45,146,35,250,86,150,185,134,240,132,149,89,134,120,129,43,196,5,163,137,40,8,231,113,197,202,19,205,169,56,43,170,3,195,41,37,224,148,89,153,163,254,123,98,77,176,239,20,95,70,138,114,134,43,89,74,11,156,245,186,100,152,31,73,138,190,17,86,106,88,81,231,132,209,4,169,125,56,133,118,134,158,17,51,156,152,253,128,247,68,180,0,191,99,66,148,43,234,150,134,91,157,230,168,110,133,239,247,123,3,215,1,131,221,179,191,95,63,187,115,174,206,11,187,150,107,125,231,186,174,73,177,140,186,6,85,221,145,116,138,221,101,53,211,163,217,49,88,209,114,226,58,8,196,173,12,115,97,204,194,89,174,18,13,56,214,68,175,183,14,66,11,216,71,253,92,64,104,105,96,57,169,40,214,13,216,23,90,105,173,66,183,93,198,122,245,192,153,130,61,106,170,105,143,152,169,220,99,230,186,247,168,241,32,122,176,246,89,83,248,116,148,3,66,13,183,117,56,67,101,145,157,155,126,233,226Line truncated
static const unsigned char v5[] = {31,139,8,0,0,0,0,0,0,19,189,59,107,115,219,56,146,223,253,43,122,180,222,145,228,33,41,82,150,223,150,167,146,76,102,146,173,76,146,138,157,212,237,186,92,9,68,66,36,198,36,193,2,160,215,104,248,159,238,55,220,47,187,106,128,79,73,86,50,179,123,151,170,200,36,1,116,55,26,141,126,161,49,24,0,188,125,119,247,242,18,158,189,127,13,62,137,99,9,201,76,42,144,138,8,5,11,166,34,232,146,140,13,186,192,82,224,34,160,2,20,7,73,197,156,130,138,40,144,44,3,162,128,164,43,248,248,225,245,193,65,119,38,41,72,37,152,175,186,87,7,44,201,184,80,176,134,200,2,65,211,128,10,11,102,146,222,42,162,168,126,122,57,157,82,95,233,199,15,116,106,65,164,146,216,130,15,124,166,168,128,28,166,130,39,0,93,103,48,153,165,65,76,157,223,100,19,232,107,159,167,210,130,55,60,100,169,5,183,84,41,150,134,22,60,159,41,197,241,131,34,202,2,197,178,23,60,230,66,90,160,255,210,192,130,183,92,177,41,243,137,98,216,239,61,9,89,90,60,127,204,98,78,130,159,89,76,13,148,146,134,174,51,240,121,146,241,148,166,74,26,50,14,16,187,66,236,28,198,144,9,158,73,24,223,232,25,124,185,150,243,16,252,152,72,57,62,92,235,38,71,191,229,176,76,226,84,142,59,145,82,217,229,96,176,88,44,156,197,177,195,69,56,24,186,174,59,144,243,176,3,115,70,23,207,249,114,220,113,193,5,111,232,156,159,233,223,147,206,205,117,64,167,242,230,90,170,85,76,111,156,56,182,253,88,218,222,122,202,226,248,50,229,41,189,146,74,240,71,122,249,55,215,117,139,103,59,97,138,138,152,37,76,93,122,213,199,5,11,84,116,233,58,39,217,242,42,191,30,24,128,215,3,3,62,4,22,140,59,111,200,138,138,207,195,14,4,68,17,59,37,9,45,190,193,176,211,238,227,217,187,122,121,157,155,235,140,168,168,96,67,167,164,182,3,193,184,243,171,55,116,78,135,150,231,156,15,63,157,59,23,222,51,207,57,57,183,244,143,107,185,150,103,121,158,229,185,206,232,252,213,136,120,206,104,100,233,31,221,100,123,182,115,124,246,204,57,189,112,78,47,138,222,67,231,124,100,121,110,108,59,158,237,120,67,226,156,123,206,185,87,244,119,188,19,219,25,157,127,58,113,78,206,136,115,126,230,156,159,21,195,156,243,83,219,57,63,125,53,114,206,142,63,157,57,195,115,226,156,159,58,231,167,186,217,181,244,203,201,171,11,103,132,16,79,156,243,147,170,225,196,118,206,79,62,29,59,163,147,103,173,33,158,235,120,199,214,177,229,156,157,58,103,245,71,77,32,113,134,23,206,208,144,236,34,153,182,227,225,188,46,204,143,249,172,39,247,106,232,28,95,124,66,230,32,95,206,44,253,99,72,30,89,206,240,228,149,231,109,53,212,12,253,87,103,176,151,243,200,86,195,220,79,222,54,227,207,157,11,13,235,213,78,244,206,240,196,242,188,79,199,206,197,104,155,2,231,124,104,13,145,252,115,231,130,180,39,230,225,216,227,179,216,241,134,142,71,26,220,241,44,199,243,28,111,212,224,34,126,26,57,163,179,114,69,42,198,123,182,121,121,117,238,120,199,229,114,214,204,183,205,178,156,190,194,101,105,46,52,182,96,183,79,23,206,168,41,26,174,229,120,39,206,232,60,118,60,45,52,181,68,97,203,177,227,121,86,91,246,92,51,11,205,224,65,88,252,151,243,240,230,203,213,193,193,116,150,250,168,67,224,21,37,1,21,189,117,204,67,62,51,170,77,88,32,169,186,141,248,226,150,5,116,66,240,189,126,201,251,176,62,0,16,84,205,68,106,244,199,193,117,192,230,229,250,77,66,123,17,49,133,106,149,249,143,43,80,60,179,93,248,221,190,31,157,63,192,114,97,79,103,113,12,19,173,155,237,9,100,43,123,8,135,235,6,124,248,254,123,232,102,177,125,54,236,230,160,4,73,37,67,66,109,18,199,16,204,132,214,124,246,177,235,154,182,41,23,73,231,230,0,160,73,66,182,180,135,80,96,202,86,182,11,9,254,76,99,186,4,166,104,34,109,159,166,138,10,61,14,224,122,98,116,167,90,101,116,220,49,47,29,224,169,31,51,255,113,124,184,166,115,84,148,109,142,244,244,183,239,230,253,188,196,169,232,82,217,50,38,138,218,35,215,45,64,3,92,31,174,181,222,119,38,68,200,227,170,119,100,159,118,96,80,224,31,148,15,141,41,104,98,241,199,246,32,36,153,189,180,71,32,105,60,181,165,18,84,249,17,196,225,165,249,126,90,227,106,140,23,52,38,138,205,41,52,0,117,110,42,84,59,144,53,57,83,161,220,129,5,224,90,102,36,109,207,59,129,205,249,199,60,12,105,128,102,152,200,75,56,92,163,92,229,13,252,109,10,34,22,4,52,69,116,147,152,251,143,248,16,25,244,11,59,91,234,239,161,29,10,178,178,135,174,219,1,34,24,177,205,152,113,71,137,25,109,77,77,115,221,24,196,28,20,83,49,106,121,45,222,29,96,62,79,199,229,154,24,153,207,27,107,93,126,169,217,52,104,175,146,254,131,63,95,174,14,242,230,62,42,5,99,61,19,177,217,47,197,70,49,118,247,45,153,191,97,233,35,140,161,183,214,36,89,154,20,11,34,129,142,196,76,196,121,191,178,199,133,56,23,136,137,238,51,238,252,237,112,141,15,121,167,100,154,121,135,241,24,135,195,143,208,157,132,197,10,156,184,102,61,38,241,140,218,167,174,11,161,224,179,172,11,151,208,213,223,53,39,207,92,23,34,62,167,226,178,221,215,124,43,249,125,82,14,206,141,40,25,113,56,6,193,103,105,64,3,59,9,32,179,135,80,138,65,76,73,192,210,208,62,133,41,79,149,45,105,194,38,60,14,154,251,1,231,93,109,132,133,125,10,184,25,42,134,31,26,246,228,37,211,43,174,127,185,250,138,214,153,51,30,83,101,123,56,5,105,227,36,98,178,106,60,218,60,163,2Line truncated
static const unsigned char v6[] = {45,45,45,45,45,66,69,71,73,78,32,67,69,82,84,73,70,73,67,65,84,69,45,45,45,45,45,10,77,73,73,66,67,84,67,66,115,65,73,74,65,75,57,119,98,73,68,107,72,110,65,111,77,65,111,71,67,67,113,71,83,77,52,57,66,65,77,67,77,65,48,120,67,122,65,74,66,103,78,86,66,65,89,84,65,107,108,70,77,66,52,88,10,68,84,73,122,77,68,69,121,79,84,73,120,77,106,69,122,79,70,111,88,68,84,77,122,77,68,69,121,78,106,73,120,77,106,69,122,79,70,111,119,68,84,69,76,77,65,107,71,65,49,85,69,66,104,77,67,83,85,85,119,87,84,65,84,10,66,103,99,113,104,107,106,79,80,81,73,66,66,103,103,113,104,107,106,79,80,81,77,66,66,119,78,67,65,65,82,122,83,81,83,53,79,72,100,49,55,108,85,101,78,73,43,54,107,112,57,87,89,117,48,99,120,117,69,73,105,47,74,84,10,106,112,104,98,67,109,100,74,68,49,99,85,118,104,109,122,77,57,47,112,104,118,74,84,57,107,97,49,48,90,57,116,111,90,104,103,110,66,113,48,111,48,120,102,84,81,52,106,67,49,118,119,77,65,111,71,67,67,113,71,83,77,52,57,10,66,65,77,67,65,48,103,65,77,69,85,67,73,81,67,101,48,84,50,69,48,71,79,105,86,101,57,75,119,118,73,69,80,101,88,49,74,49,74,48,84,55,84,78,97,99,103,82,48,89,97,51,51,72,86,57,86,103,73,103,78,118,100,110,10,97,69,87,105,66,112,49,120,115,104,115,52,105,122,54,87,98,112,120,114,83,49,73,72,117,99,114,113,107,90,117,74,76,102,78,90,71,90,73,61,10,45,45,45,45,45,69,78,68,32,67,69,82,84,73,70,73,67,65,84,69,45,45,45,45,45,10,0};
static const unsigned char v7[] = {45,45,45,45,45,66,69,71,73,78,32,69,67,32,80,82,73,86,65,84,69,32,75,69,89,45,45,45,45,45,10,77,72,99,67,65,81,69,69,73,67,66,122,51,72,79,107,81,76,80,66,68,116,100,107,110,113,67,55,107,49,80,78,115,87,106,54,72,102,104,121,78,66,53,77,101,110,102,106,109,113,105,111,111,65,111,71,67,67,113,71,83,77,52,57,10,65,119,69,72,111,85,81,68,81,103,65,69,99,48,107,69,117,84,104,51,100,101,53,86,72,106,83,80,117,112,75,102,86,109,76,116,72,77,98,104,67,73,118,121,85,52,54,89,87,119,112,110,83,81,57,88,70,76,52,90,115,122,80,102,10,54,89,98,121,85,47,90,71,116,100,71,102,98,97,71,89,89,74,119,97,116,75,78,77,88,48,48,79,73,119,116,98,56,65,61,61,10,45,45,45,45,45,69,78,68,32,69,67,32,80,82,73,86,65,84,69,32,75,69,89,45,45,45,45,45,10,0};
static const struct packed_file {
const char *name;
const unsigned char *data;
size_t size;
time_t mtime;
} packed_files[] = {
{"/web_root/bundle.js.gz", v0, sizeof(v0) - 1, 1710000285},
{"/web_root/components.js.gz", v1, sizeof(v1) - 1, 1713984696},
{"/web_root/history.min.js.gz", v2, sizeof(v2) - 1, 1710000285},
{"/web_root/index.html.gz", v3, sizeof(v3) - 1, 1710000285},
{"/web_root/main.css.gz", v4, sizeof(v4) - 1, 1713984502},
{"/web_root/main.js.gz", v5, sizeof(v5) - 1, 1713984681},
{"/certs/server_cert.pem", v6, sizeof(v6) - 1, 1710000285},
{"/certs/server_key.pem", v7, sizeof(v7) - 1, 1710000285},
{NULL, NULL, 0, 0}
};
static int scmp(const char *a, const char *b) {
while (*a && (*a == *b)) a++, b++;
return *(const unsigned char *) a - *(const unsigned char *) b;
}
const char *mg_unlist(size_t no) {
return packed_files[no].name;
}
const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {
const struct packed_file *p;
for (p = packed_files; p->name != NULL; p++) {
if (scmp(p->name, name) != 0) continue;
if (size != NULL) *size = p->size;
if (mtime != NULL) *mtime = p->mtime;
return (const char *) p->data;
}
return NULL;
};
@@ -1 +0,0 @@
var n,t,e,_,r,o,i,u,l,c={},a=[],s=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function f(n,t){for(var e in t)n[e]=t[e];return n}function p(n){var t=n.parentNode;t&&t.removeChild(n)}function h(t,e,_){var r,o,i,u={};for(i in e)"key"==i?r=e[i]:"ref"==i?o=e[i]:u[i]=e[i];if(arguments.length>2&&(u.children=arguments.length>3?n.call(arguments,2):_),"function"==typeof t&&null!=t.defaultProps)for(i in t.defaultProps)void 0===u[i]&&(u[i]=t.defaultProps[i]);return d(t,u,r,o,null)}function d(n,_,r,o,i){var u={type:n,props:_,key:r,ref:o,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==i?++e:i};return null==i&&null!=t.vnode&&t.vnode(u),u}function v(){return{current:null}}function m(n){return n.children}function y(n,t){this.props=n,this.context=t}function g(n,t){if(null==t)return n.__?g(n.__,n.__.__k.indexOf(n)+1):null;for(var e;t<n.__k.length;t++)if(null!=(e=n.__k[t])&&null!=e.__e)return e.__e;return"function"==typeof n.type?g(n):null}function b(n){var t,e;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,t=0;t<n.__k.length;t++)if(null!=(e=n.__k[t])&&null!=e.__e){n.__e=n.__c.base=e.__e;break}return b(n)}}function k(n){(!n.__d&&(n.__d=!0)&&r.push(n)&&!C.__r++||o!==t.debounceRendering)&&((o=t.debounceRendering)||i)(C)}function C(){var n,t,e,_,o,i,l,c;for(r.sort(u);n=r.shift();)n.__d&&(t=r.length,_=void 0,o=void 0,l=(i=(e=n).__v).__e,(c=e.__P)&&(_=[],(o=f({},i)).__v=i.__v+1,T(c,i,o,e.__n,void 0!==c.ownerSVGElement,null!=i.__h?[l]:null,_,null==l?g(i):l,i.__h),R(_,i),i.__e!=l&&b(i)),r.length>t&&r.sort(u));C.__r=0}function x(n,t,e,_,r,o,i,u,l,s){var f,p,h,v,y,b,k,C=_&&_.__k||a,x=C.length;for(e.__k=[],f=0;f<t.length;f++)if(null!=(v=e.__k[f]=null==(v=t[f])||"boolean"==typeof v||"function"==typeof v?null:"string"==typeof v||"number"==typeof v||"bigint"==typeof v?d(null,v,null,null,v):Array.isArray(v)?d(m,{children:v},null,null,null):v.__b>0?d(v.type,v.props,v.key,v.ref?v.ref:null,v.__v):v)){if(v.__=e,v.__b=e.__b+1,null===(h=C[f])||h&&v.key==h.key&&v.type===h.type)C[f]=void 0;else for(p=0;p<x;p++){if((h=C[p])&&v.key==h.key&&v.type===h.type){C[p]=void 0;break}h=null}T(n,v,h=h||c,r,o,i,u,l,s),y=v.__e,(p=v.ref)&&h.ref!=p&&(k||(k=[]),h.ref&&k.push(h.ref,null,v),k.push(p,v.__c||y,v)),null!=y?(null==b&&(b=y),"function"==typeof v.type&&v.__k===h.__k?v.__d=l=E(v,l,n):l=U(n,v,h,C,y,l),"function"==typeof e.type&&(e.__d=l)):l&&h.__e==l&&l.parentNode!=n&&(l=g(h))}for(e.__e=b,f=x;f--;)null!=C[f]&&("function"==typeof e.type&&null!=C[f].__e&&C[f].__e==e.__d&&(e.__d=A(_).nextSibling),W(C[f],C[f]));if(k)for(f=0;f<k.length;f++)M(k[f],k[++f],k[++f])}function E(n,t,e){for(var _,r=n.__k,o=0;r&&o<r.length;o++)(_=r[o])&&(_.__=n,t="function"==typeof _.type?E(_,t,e):U(e,_,_,r,_.__e,t));return t}function H(n,t){return t=t||[],null==n||"boolean"==typeof n||(Array.isArray(n)?n.some((function(n){H(n,t)})):t.push(n)),t}function U(n,t,e,_,r,o){var i,u,l;if(void 0!==t.__d)i=t.__d,t.__d=void 0;else if(null==e||r!=o||null==r.parentNode)n:if(null==o||o.parentNode!==n)n.appendChild(r),i=null;else{for(u=o,l=0;(u=u.nextSibling)&&l<_.length;l+=1)if(u==r)break n;n.insertBefore(r,o),i=o}return void 0!==i?i:r.nextSibling}function A(n){var t,e,_;if(null==n.type||"string"==typeof n.type)return n.__e;if(n.__k)for(t=n.__k.length-1;t>=0;t--)if((e=n.__k[t])&&(_=A(e)))return _;return null}function P(n,t,e,_,r){var o;for(o in e)"children"===o||"key"===o||o in t||N(n,o,null,e[o],_);for(o in t)r&&"function"!=typeof t[o]||"children"===o||"key"===o||"value"===o||"checked"===o||e[o]===t[o]||N(n,o,t[o],e[o],_)}function S(n,t,e){"-"===t[0]?n.setProperty(t,null==e?"":e):n[t]=null==e?"":"number"!=typeof e||s.test(t)?e:e+"px"}function N(n,t,e,_,r){var o;n:if("style"===t)if("string"==typeof e)n.style.cssText=e;else{if("string"==typeof _&&(n.style.cssText=_=""),_)for(t in _)e&&t in e||S(n.style,t,"");if(e)for(t in e)_&&e[t]===_[t]||S(n.style,t,e[t])}else if("o"===t[0]&&"n"===t[1])o=t!==(t=t.replace(/Capture$/,"")),t=t.toLowerCase()in n?t.toLowerCase().slice(2):t.slice(2),n.l||(n.l={}),n.l[t+o]=e,e?_||n.addEventListener(t,o?D:w,o):n.removeEventListener(t,o?D:w,o);else if("dangerouslySetInnerHTML"!==t){if(r)t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!==t&&"height"!==t&&"href"!==t&&"list"!==t&&"form"!==t&&"tabIndex"!==t&&"download"!==t&&t in n)try{n[t]=null==e?"":e;break n}catch(n){}"function"==typeof e||(null==e||!1===e&&"-"!==t[4]?n.removeAttribute(t):n.setAttribute(t,e))}}function w(n){return this.l[n.type+!1](t.event?t.event(n):n)}function D(n){return this.l[n.type+!0](t.event?t.event(n):n)}function T(n,e,_,r,o,i,u,l,c){var a,s,p,h,d,v,g,b,k,C,E,H,U,A,P,S=e.type;if(void 0!==e.constructor)return null;null!=_.__h&&(c=_.__h,l=e.__e=_.__e,e.__h=null,i=[l]),(a=t.__b)&&a(e);try{n:if("function"==typeof S){if(b=e.props,k=(a=S.contextType)&&r[a.__c],C=a?k?k.props.value:a.__:r,_.__c?g=(s=e.__c=_.__c).__=s.__E:("prototype"in S&&S.prototype.render?e.__c=s=new S(b,C):(e.__c=s=new y(b,C),s.constructor=S,s.rLine truncated
@@ -1,356 +0,0 @@
'use strict';
import { h, render, useState, useEffect, useRef, html, Router } from './bundle.js';
// Helper function that returns a promise that resolves after delay
const Delay = (ms, val) => new Promise(resolve => setTimeout(resolve, ms, val));
export const Icons = {
heart: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path></svg>`,
downArrowBox: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15M9 12l3 3m0 0l3-3m-3 3V2.25" /> </svg>`,
upArrowBox: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15m0-3l-3-3m0 0l-3 3m3-3V15" /> </svg>`,
cog: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> </svg>`,
settingsH: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 11-3 0m3 0a1.5 1.5 0 10-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-9.75 0h9.75" /> </svg>`,
settingsV: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M6 13.5V3.75m0 9.75a1.5 1.5 0 010 3m0-3a1.5 1.5 0 000 3m0 3.75V16.5m12-3V3.75m0 9.75a1.5 1.5 0 010 3m0-3a1.5 1.5 0 000 3m0 3.75V16.5m-6-9V3.75m0 3.75a1.5 1.5 0 010 3m0-3a1.5 1.5 0 000 3m0 9.75V10.5" /> </svg>`,
scan: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M7.5 3.75H6A2.25 2.25 0 003.75 6v1.5M16.5 3.75H18A2.25 2.25 0 0120.25 6v1.5m0 9V18A2.25 2.25 0 0118 20.25h-1.5m-9 0H6A2.25 2.25 0 013.75 18v-1.5M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> </svg> `,
desktop: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25" /> </svg>`,
alert: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5" /> </svg>`,
bell: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5" /> </svg>`,
refresh: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" /> </svg> `,
bars4: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 5.25h16.5m-16.5 4.5h16.5m-16.5 4.5h16.5m-16.5 4.5h16.5" /> </svg>`,
bars3: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> </svg>`,
logout: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M12.75 15l3-3m0 0l-3-3m3 3h-7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg>`,
save: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" /> </svg>`,
email: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" /> </svg>`,
expand: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /> </svg>`,
shrink: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25" /> </svg>`,
ok: props => html`<svg class=${props.class} fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg>`,
fail: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg>`,
upload: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /> </svg> `,
download: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" /> </svg> `,
bolt: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg>`,
home: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" /> </svg> `,
link: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" /> </svg> `,
shield: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z" /> </svg> `,
barsdown: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M3 4.5h14.25M3 9h9.75M3 13.5h9.75m4.5-4.5v12m0 0l-3.75-3.75M17.25 21L21 17.25" /> </svg> `,
arrowdown: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75" /> </svg> `,
arrowup: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75" /> </svg>`,
warn: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /> </svg>`,
info: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /> </svg>`,
exclamationTriangle: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /> </svg>`,
thumbUp: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M6.633 10.5c.806 0 1.533-.446 2.031-1.08a9.041 9.041 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75A2.25 2.25 0 0116.5 4.5c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H13.48c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23H5.904M14.25 9h2.25M5.904 18.75c.083.205.173.405.27.602.197.4-.078.898-.523.898h-.908c-.889 0-1.713-.518-1.972-1.368a12 12 0 01-.521-3.507c0-1.553.295-3.036.831-4.398C3.387 10.203 4.167 9.75 5 9.75h1.053c.472 0 .745.556.5.96a8.958 8.958 0 00-1.302 4.665c0 1.194.232 2.333.654 3.375z" /> </svg>`,
backward: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M21 16.811c0 .864-.933 1.405-1.683.977l-7.108-4.062a1.125 1.125 0 010-1.953l7.108-4.062A1.125 1.125 0 0121 8.688v8.123zM11.25 16.811c0 .864-.933 1.405-1.683.977l-7.108-4.062a1.125 1.125 0 010-1.953L9.567 7.71a1.125 1.125 0 011.683.977v8.123z" /> </svg>`,
chip: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 3v1.5M4.5 8.25H3m18 0h-1.5M4.5 12H3m18 0h-1.5m-15 3.75H3m18 0h-1.5M8.25 19.5V21M12 3v1.5m0 15V21m3.75-18v1.5m0 15V21m-9-1.5h10.5a2.25 2.25 0 002.25-2.25V6.75a2.25 2.25 0 00-2.25-2.25H6.75A2.25 2.25 0 004.5 6.75v10.5a2.25 2.25 0 002.25 2.25zm.75-12h9v9h-9v-9z" /> </svg>`,
camera: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z" /> </svg>`,
arrows: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5" /> </svg>`,
doc: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /></svg>`,
};
export const tipColors = {
green: 'bg-green-100 text-green-900 ring-green-300',
yellow: 'bg-yellow-100 text-yellow-900 ring-yellow-300',
red: 'bg-red-100 text-red-900 ring-red-300',
};
export function Button({title, onclick, disabled, cls, icon, ref, colors, hovercolor, disabledcolor}) {
const [spin, setSpin] = useState(false);
const cb = function(ev) {
const res = onclick ? onclick() : null;
if (res && typeof (res.catch) === 'function') {
setSpin(true);
res.catch(() => false).then(() => setSpin(false));
}
};
if (!colors) colors = 'bg-blue-600 hover:bg-blue-500 disabled:bg-blue-400';
return html`
<button type="button" class="inline-flex justify-center items-center gap-2 rounded px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm ${colors} ${cls}"
ref=${ref} onclick=${cb} disabled=${disabled || spin} >
${title}
<${spin ? Icons.refresh : icon} class="w-4 ${spin ? 'animate-spin' : ''}" />
<//>`
};
export function Notification({ok, text, close}) {
const closebtn = useRef(null);
const from = 'translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2';
const to = 'translate-y-0 opacity-100 sm:translate-x-0';
const [tr, setTr] = useState(from);
useEffect(function() {
setTr(to);
setTimeout(ev => closebtn && closebtn.current.click && closebtn.current.click(), 1500);
}, []);
const onclose = ev => { setTr(from); setTimeout(close, 300); };
return html`
<div aria-live="assertive" class="z-10 pointer-events-none absolute inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6">
<div class="flex w-full flex-col items-center space-y-4 sm:items-end">
<div class="pointer-events-auto w-full max-w-sm overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5 transform ease-out duration-300 transition ${tr}">
<div class="p-4">
<div class="flex items-start">
<div class="flex-shrink-0">
<${ok ? Icons.ok : Icons.fail} class="h-6 w-6 ${ok ? 'text-green-400' : 'text-red-400'}" />
<//>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm font-medium text-gray-900">${text}</p>
<p class="hidden mt-1 text-sm text-gray-500">Anyone with a link can now view this file.</p>
<//>
<div class="ml-4 flex flex-shrink-0">
<button type="button" ref=${closebtn} onclick=${onclose} class="inline-flex rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none">
<span class="sr-only">Close</span>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
<//>
<//>
<//>
<//>
<//>
<//>
<//>
<//>`;
};
export function Login({loginFn, logoIcon, title, tipText}) {
const [user, setUser] = useState('');
const [pass, setPass] = useState('');
const onsubmit = function(ev) {
const authhdr = 'Basic ' + btoa(user + ':' + pass);
const headers = {Authorization: authhdr};
return fetch('api/login', {headers}).then(loginFn).finally(r => setPass(''));
};
return html`
<div class="h-screen flex items-center justify-center bg-slate-200">
<div class="border rounded bg-white w-96 p-5">
<div class="my-5 py-2 flex items-center justify-center gap-x-4">
<${logoIcon} class="h-12 stroke-cyan-600 stroke-1" />
<h1 class="font-bold text-xl">${title || 'Login'}<//>
<//>
<div class="my-3">
<label class="block text-sm mb-1 dark:text-white">Username</label>
<input type="text" autocomplete="current-user" required
class="font-normal bg-white rounded border border-gray-300 w-full
flex-1 py-0.5 px-2 text-gray-900 placeholder:text-gray-400
focus:outline-none sm:text-sm sm:leading-6 disabled:cursor-not-allowed
disabled:bg-gray-100 disabled:text-gray-500"
oninput=${ev => setUser(ev.target.value)} value=${user} />
<//>
<div class="my-3">
<label class="block text-sm mb-1 dark:text-white">Password</label>
<input type="password" autocomplete="current-password" required
class="font-normal bg-white rounded border border-gray-300 w-full flex-1 py-0.5 px-2 text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm sm:leading-6 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-500"
oninput=${ev => setPass(ev.target.value)}
value=${pass} onchange=${onsubmit} />
<//>
<div class="mt-7">
<${Button} title="Sign In" icon=${Icons.logout} onclick=${onsubmit} cls="flex w-full justify-center" />
<//>
<div class="mt-5 text-slate-400 text-xs">${tipText}<//>
<//>
<//>`;
};
export function Colored({icon, text, colors}) {
colors ||= 'bg-slate-100 text-slate-900';
return html`
<span class="inline-flex items-center gap-1.5 py-0.5">
${icon && html`<${icon} class="w-5 h-5" />`}
<span class="inline-block font-medium rounded-md px-2 py-1 text-xs ring-1 ring-inset ${colors}">${text}<//>
<//>`;
};
export function Stat({title, text, tipText, tipIcon, tipColors, colors}) {
return html`
<div class="flex flex-col bg-white border shadow-sm rounded-xl dark:bg-slate-900 dark:border-gray-800">
<div class="overflow-auto rounded-lg bg-white px-4 py-2 ">
<div class="flex items-center gap-x-2">
<p class="text-sm truncate text-gray-500 font-medium"> ${title} </p>
<//>
<div class="mt-1 flex items-center gap-x-2">
<h3 class="text-xl truncate font-semibold tracking-tight ${colors || 'text-gray-800 dark:text-gray-200'}">
${text}
<//>
<span class="flex items-center ${tipText || 'hidden'}">
<${Colored} text=${tipText} icon=${tipIcon} colors=${tipColors} />
<//>
<//>
<//>
<//>`;
};
export function TextValue({value, setfn, disabled, placeholder, type, addonRight, addonLeft, attr, min, max, step, mult}) {
const [bg, setBg] = useState('bg-white');
useEffect(() => { if (type == 'number') checkval(+min, +max, +value); }, []);
step ||= '1', mult ||= 1;
const checkval = function(min, max, v) {
setBg('bg-white');
if (min && v < min) setBg('bg-red-100 border-red-200');
if (max && v > max) setBg('bg-red-100 border-red-200');
};
const m = step.match(/^.+\.(.+)/);
const digits = m ? m[1].length : 0;
const onchange = ev => {
let v = ev.target.value;
if (type == 'number') {
checkval(+min, +max, +v);
v = +(parseFloat(v) / mult).toFixed(digits);
}
setfn(v);
};
if (type == 'number') value = +(value * mult).toFixed(digits);
return html`
<div class="flex w-full items-center rounded border shadow-sm ${bg}">
${addonLeft && html`<span class="inline-flex font-normal truncate py-1 border-r bg-slate-100 items-center border-gray-300 px-2 text-gray-500 text-xs">${addonLeft}<//>` }
<input type=${type || 'text'} disabled=${disabled} value=${value}
step=${step} min=${min} max=${max}
onchange=${onchange} ...${attr}
class="${bg} font-normal text-sm rounded w-full flex-1 py-0.5 px-2 text-gray-700 placeholder:text-gray-400 focus:outline-none disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-500" placeholder=${placeholder} />
${addonRight && html`<span class="inline-flex font-normal truncate py-1 border-l bg-slate-100 items-center border-gray-300 px-2 text-gray-500 text-xs overflow-scroll" style="min-width: 50%;">${addonRight}<//>` }
<//>`;
};
export function SelectValue({value, setfn, options, disabled}) {
const toInt = x => x == parseInt(x) ? parseInt(x) : x;
const onchange = ev => setfn(toInt(ev.target.value));
return html`
<select onchange=${onchange} class="w-full rounded font-normal border py-0.5 px-1 text-gray-600 focus:outline-none text-sm disabled:cursor-not-allowed" disabled=${disabled}>
${options.map(v => html`<option value=${v[0]} selected=${v[0] == value}>${v[1]}<//>`) }
<//>`;
};
export function SwitchValue({value, setfn}) {
const onclick = ev => setfn(!value);
const bg = !!value ? 'bg-blue-600' : 'bg-gray-200';
const tr = !!value ? 'translate-x-5' : 'translate-x-0';
return html`
<button type="button" onclick=${onclick} class="${bg} inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-0 ring-0" role="switch" aria-checked=${!!value}>
<span aria-hidden="true" class="${tr} pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 focus:ring-0 transition duration-200 ease-in-out"></span>
</button>`;
};
export function Setting(props) {
let input = TextValue;
if (props.type == 'switch') input = SwitchValue;
if (props.type == 'select') input = SelectValue;
return html`
<div class=${props.cls || 'grid grid-cols-2 gap-2 my-1'}>
<label class="flex items-center text-sm text-gray-700 mr-2 font-medium ${props.title || 'hidden'}">${props.title}<//>
<div class="flex items-center">${h(input, props)}<//>
<//>`;
};
export function Pagination({ totalItems, itemsPerPage, currentPage, setPageFn, colors }) {
const totalPages = Math.ceil(totalItems / itemsPerPage);
const maxPageRange = 2;
const lessThanSymbol = "<";
const greaterThanSymbol = ">";
const whiteSpace = " ";
const itemcls = 'relative inline-flex items-center px-3 py-1 text-sm focus:z-20 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-blue-600';
colors ||= 'bg-blue-600';
const PageItem = ({ page, isActive }) => (
html`<a
onClick=${() => setPageFn(page)}
class="${itemcls} ${isActive ? `${colors} text-white` : 'cursor-pointer text-gray-700 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'}"
>
${page}
</a>`
);
return html`
<div class="flex items-center justify-between bg-white px-3 py-2">
<div class="sm:flex sm:flex-1 sm:items-center sm:justify-between space-x-4 whitespace-nowrap select-none">
<p class="text-sm text-slate-500 font-medium">
showing <span class="font-bold text-slate-700">${(currentPage - 1) * itemsPerPage + 1}</span> - <span class="font-medium">${Math.min(currentPage * itemsPerPage, totalItems)}</span> of ${whiteSpace}
<span class="font-bold text-slate-700">${totalItems}</span> results
</p>
<div>
<nav class="isolate inline-flex -space-x-px rounded-md" aria-label="Pagination">
<a
onClick=${() => setPageFn(Math.max(currentPage - 1, 1))}
class="relative inline-flex px-3 items-center text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 ${currentPage != 1 ? 'cursor-pointer' : ''} focus:z-20 focus:outline-offset-0">
${lessThanSymbol}
</a>
<${PageItem} page=${1} isActive=${currentPage === 1} />
${currentPage > maxPageRange + 2 ? html`<span class="${itemcls} ring-1 ring-inset ring-gray-300 text-slate-300">...</span>` : ''}
${Array.from({length: Math.min(totalPages, maxPageRange * 2 + 1)}, (_, i) => Math.max(2, currentPage - maxPageRange) + i).map(page => page > 1 && page < totalPages && html`<${PageItem} page=${page} isActive=${currentPage === page} />`)}
${currentPage < totalPages - (maxPageRange + 1) ? html`<span class="${itemcls} ring-1 ring-inset ring-gray-300 text-slate-300">...</span>` : ''}
${totalPages > 1 ? html`<${PageItem} page=${totalPages} isActive=${currentPage === totalPages} />` : ''}
<a
onClick=${() => setPageFn(Math.min(currentPage + 1, totalPages))}
class="relative inline-flex px-3 items-center text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 ${currentPage != totalPages ? 'cursor-pointer' : ''} focus:z-20 focus:outline-offset-0">
${greaterThanSymbol}
</a>
</nav>
</div>
</div>
</div>`;
};
export function UploadFileButton(props) {
const [upload, setUpload] = useState(null); // Upload promise
const [status, setStatus] = useState(''); // Current upload status
const btn = useRef(null);
const input = useRef(null);
// Send a large file chunk by chunk
const sendFileData = function(url, fileName, fileData, chunkSize) {
return new Promise(function(resolve, reject) {
const finish = ok => {
setUpload(null);
const res = props.onupload ? props.onupload(ok, fileName, fileData.length) : null;
if (res && typeof (res.catch) === 'function') {
res.catch(() => false).then(() => ok ? resolve() : reject());
} else {
ok ? resolve() : reject();
}
};
const sendChunk = function(offset) {
var chunk = fileData.subarray(offset, offset + chunkSize) || '';
var opts = {method: 'POST', body: chunk};
var fullUrl = url + '?offset=' + offset +
'&total=' + fileData.length +
'&name=' + encodeURIComponent(fileName);
var ok;
setStatus('Uploading ' + fileName + ', bytes ' + offset + '..' +
(offset + chunk.length) + ' of ' + fileData.length);
fetch(fullUrl, opts)
.then(function(res) {
if (res.ok && chunk.length > 0) sendChunk(offset + chunk.length);
ok = res.ok;
return res.text();
})
.then(function(text) {
if (!ok) setStatus('Error: ' + text), finish(ok); // Fail
if (chunk.length > 0) return; // More chunks to send
setStatus(x => x + '. Done, resetting device...');
finish(ok); // All chunks sent
});
};
sendChunk(0);
});
};
const onchange = function(ev) {
if (!ev.target.files[0]) return;
let r = new FileReader(), f = ev.target.files[0];
r.readAsArrayBuffer(f);
r.onload = function() {
setUpload(sendFileData(props.url, f.name, new Uint8Array(r.result), 2048));
ev.target.value = '';
ev.preventDefault();
btn && btn.current.base.click();
};
};
const onclick = function(ev) {
let fn; setUpload(x => fn = x);
if (!fn) input.current.click(); // No upload in progress, show file dialog
return fn;
};
return html`
<div class="inline-flex flex-col ${props.class}">
<input class="hidden" type="file" ref=${input} onchange=${onchange} accept=${props.accept} />
<${Button} title=${props.title} icon=${Icons.download} onclick=${onclick} ref=${btn} colors=${props.colors} />
<div class="pt-2 text-sm text-slate-400 ${status || 'hidden'}">${status}<//>
<//>`;
};
@@ -1 +0,0 @@
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.History=n():t.History=n()}(this,function(){return function(t){function n(o){if(e[o])return e[o].exports;var r=e[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}var e={};return n.m=t,n.c=e,n.p="",n(0)}([function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0,n.createPath=n.parsePath=n.locationsAreEqual=n.createLocation=n.createMemoryHistory=n.createHashHistory=n.createBrowserHistory=void 0;var r=e(2);Object.defineProperty(n,"createLocation",{enumerable:!0,get:function(){return r.createLocation}}),Object.defineProperty(n,"locationsAreEqual",{enumerable:!0,get:function(){return r.locationsAreEqual}});var i=e(1);Object.defineProperty(n,"parsePath",{enumerable:!0,get:function(){return i.parsePath}}),Object.defineProperty(n,"createPath",{enumerable:!0,get:function(){return i.createPath}});var a=e(7),c=o(a),u=e(8),s=o(u),f=e(9),l=o(f);n.createBrowserHistory=c.default,n.createHashHistory=s.default,n.createMemoryHistory=l.default},function(t,n){"use strict";n.__esModule=!0;n.addLeadingSlash=function(t){return"/"===t.charAt(0)?t:"/"+t},n.stripLeadingSlash=function(t){return"/"===t.charAt(0)?t.substr(1):t},n.stripPrefix=function(t,n){return 0===t.indexOf(n)?t.substr(n.length):t},n.stripTrailingSlash=function(t){return"/"===t.charAt(t.length-1)?t.slice(0,-1):t},n.parsePath=function(t){var n=t||"/",e="",o="",r=n.indexOf("#");r!==-1&&(o=n.substr(r),n=n.substr(0,r));var i=n.indexOf("?");return i!==-1&&(e=n.substr(i),n=n.substr(0,i)),n=decodeURI(n),{pathname:n,search:"?"===e?"":e,hash:"#"===o?"":o}},n.createPath=function(t){var n=t.pathname,e=t.search,o=t.hash,r=encodeURI(n||"/");return e&&"?"!==e&&(r+="?"===e.charAt(0)?e:"?"+e),o&&"#"!==o&&(r+="#"===o.charAt(0)?o:"#"+o),r}},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0,n.locationsAreEqual=n.createLocation=void 0;var r=Object.assign||function(t){for(var n=1;n<arguments.length;n++){var e=arguments[n];for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o])}return t},i=e(10),a=o(i),c=e(11),u=o(c),s=e(1);n.createLocation=function(t,n,e,o){var i=void 0;return"string"==typeof t?(i=(0,s.parsePath)(t),i.state=n):(i=r({},t),void 0===i.pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==n&&void 0===i.state&&(i.state=n)),i.key=e,o&&(i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=(0,a.default)(i.pathname,o.pathname)):i.pathname=o.pathname),i},n.locationsAreEqual=function(t,n){return t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash&&t.key===n.key&&(0,u.default)(t.state,n.state)}},function(t,n,e){"use strict";var o=function(){};t.exports=o},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0;var r=e(3),i=(o(r),function(){var t=null,n=function(n){return t=n,function(){t===n&&(t=null)}},e=function(n,e,o,r){if(null!=t){var i="function"==typeof t?t(n,e):t;"string"==typeof i?"function"==typeof o?o(i,r):r(!0):r(i!==!1)}else r(!0)},o=[],r=function(t){var n=!0,e=function(){n&&t.apply(void 0,arguments)};return o.push(e),function(){n=!1,o=o.filter(function(t){return t!==e})}},i=function(){for(var t=arguments.length,n=Array(t),e=0;e<t;e++)n[e]=arguments[e];o.forEach(function(t){return t.apply(void 0,n)})};return{setPrompt:n,confirmTransitionTo:e,appendListener:r,notifyListeners:i}});n.default=i},function(t,n){"use strict";n.__esModule=!0;n.canUseDOM=!("undefined"==typeof window||!window.document||!window.document.createElement),n.addEventListener=function(t,n,e){return t.addEventListener?t.addEventListener(n,e,!1):t.attachEvent("on"+n,e)},n.removeEventListener=function(t,n,e){return t.removeEventListener?t.removeEventListener(n,e,!1):t.detachEvent("on"+n,e)},n.getConfirmation=function(t,n){return n(window.confirm(t))},n.supportsHistory=function(){var t=window.navigator.userAgent;return(t.indexOf("Android 2.")===-1&&t.indexOf("Android 4.0")===-1||t.indexOf("Mobile Safari")===-1||t.indexOf("Chrome")!==-1||t.indexOf("Windows Phone")!==-1)&&(window.history&&"pushState"in window.history)},n.supportsPopStateOnHashChange=function(){return window.navigator.userAgent.indexOf("Trident")===-1},n.supportsGoWithoutReloadUsingHash=function(){return window.navigator.userAgent.indexOf("Firefox")===-1},n.isExtraneousPopstateEvent=function(t){return void 0===t.state&&navigator.userAgent.indexOf("CriOS")===-1}},function(t,n,e){"use strict";var o=function(t,n,e,o,r,i,a,c){if(!t){var u;if(void 0===n)u=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[e,o,r,i,a,c],f=0;u=new Error(n.replace(/%s/g,function(){return s[f++]})),u.name="InLine truncated
@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="h-full bg-white">
<head>
<title></title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='currentColor'> <path stroke-linecap='round' stroke-linejoin='round' d='M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0' /> </svg>" />
<link href="main.css" rel="stylesheet" />
</head>
<body class="min-h-screen"></body>
<script src="history.min.js"></script>
<script type="module" src="main.js"></script>
</html>
@@ -1 +0,0 @@
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Arial,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.col-span-2{grid-column:span 2/span 2}.m-4{margin:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-5{margin-top:1.25rem;margin-bottom:1.25rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-96{width:24rem}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.border-separate{border-collaLine truncated
@@ -1,376 +0,0 @@
// NOTE: API calls must start with 'api/' in order to serve the app at any URI
'use strict';
import { h, render, useState, useEffect, useRef, html, Router } from './bundle.js';
import { Icons, Login, Setting, Button, Stat, tipColors, Colored, Notification, Pagination, UploadFileButton } from './components.js';
const Logo = props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.87 12.85"><defs><style>.ll-cls-1{fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:0.5px;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="ll-cls-1" d="M12.62,1.82V8.91A1.58,1.58,0,0,1,11,10.48H4a1.44,1.44,0,0,1-1-.37A.69.69,0,0,1,2.84,10l-.1-.12a.81.81,0,0,1-.15-.48V5.57a.87.87,0,0,1,.86-.86H4.73V7.28a.86.86,0,0,0,.86.85H9.42a.85.85,0,0,0,.85-.85V3.45A.86.86,0,0,0,10.13,3,.76.76,0,0,0,10,2.84a.29.29,0,0,0-.12-.1,1.49,1.49,0,0,0-1-.37H2.39V1.82A1.57,1.57,0,0,1,4,.25H11A1.57,1.57,0,0,1,12.62,1.82Z"/><path class="ll-cls-1" d="M10.48,10.48V11A1.58,1.58,0,0,1,8.9,12.6H1.82A1.57,1.57,0,0,1,.25,11V3.94A1.57,1.57,0,0,1,1.82,2.37H8.9a1.49,1.49,0,0,1,1,.37l.12.1a.76.76,0,0,1,.11.14.86.86,0,0,1,.14.47V7.28a.85.85,0,0,1-.85.85H8.13V5.57a.86.86,0,0,0-.85-.86H3.45a.87.87,0,0,0-.86.86V9.4a.81.81,0,0,0,.15.48l.1.12a.69.69,0,0,0,.13.11,1.44,1.44,0,0,0,1,.37Z"/></g></g></svg>`;
function Header({logout, user, setShowSidebar, showSidebar}) {
return html`
<div class="bg-white sticky top-0 z-[48] xw-full border-b py-2 ${showSidebar && 'pl-72'} transition-all duration-300 transform">
<div class="px-2 w-full py-0 my-0 flex items-center">
<button type="button" onclick=${ev => setShowSidebar(v => !v)} class="text-slate-400">
<${Icons.bars3} class="h-6" />
<//>
<div class="flex flex-1 gap-x-4 self-stretch lg:gap-x-6">
<div class="relative flex flex-1"><//>
<div class="flex items-center gap-x-4 lg:gap-x-6">
<span class="text-sm text-slate-400">logged in as: ${user}<//>
<div class="hidden lg:block lg:h-4 lg:w-px lg:bg-gray-200" aria-hidden="true"><//>
<${Button} title="Logout" icon=${Icons.logout} onclick=${logout} />
<//>
<//>
<//>
<//>`;
};
function Sidebar({url, show}) {
const NavLink = ({title, icon, href, url}) => html`
<div>
<a href="#${href}" class="${href == url ? 'bg-slate-50 text-blue-600 group' : 'text-gray-700 hover:text-blue-600 hover:bg-gray-50 group'} flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
<${icon} class="w-6 h-6"/>
${title}
<///>
<//>`;
return html`
<div class="bg-violet-100 hs-overlay hs-overlay-open:translate-x-0
-translate-x-full transition-all duration-300 transform
fixed top-0 left-0 bottom-0 z-[60] w-72 bg-white border-r
border-gray-200 overflow-y-auto scrollbar-y
${show && 'translate-x-0'} right-auto bottom-0">
<div class="flex flex-col m-4 gap-y-6">
<div class="flex h-10 shrink-0 items-center gap-x-4 font-bold text-xl text-slate-500">
<${Logo} class="h-full"/> Your Brand
<//>
<div class="flex flex-1 flex-col">
<${NavLink} title="Dashboard" icon=${Icons.home} href="/" url=${url} />
<${NavLink} title="Settings" icon=${Icons.cog} href="/settings" url=${url} />
<${NavLink} title="Firmware Update" icon=${Icons.download} href="/update" url=${url} />
<${NavLink} title="Events" icon=${Icons.alert} href="/events" url=${url} />
<//>
<//>
<//>`;
};
function Events({}) {
const [events, setEvents] = useState([]);
const [page, setPage] = useState(1);
const refresh = () =>
fetch('api/events/get', {
method: 'POST', body: JSON.stringify({page: page}),
}).then(r => r.json())
.then(r => setEvents(r));
useEffect(refresh, [page]);
useEffect(() => {
setPage(JSON.parse(localStorage.getItem('page')));
}, []);
useEffect(() => {
localStorage.setItem('page', page.toString());
}, [page]);
const Th = props => html`<th scope="col" class="sticky top-0 z-10 border-b border-slate-300 bg-white bg-opacity-75 py-1.5 px-4 text-left text-sm font-semibold text-slate-900 backdrop-blur backdrop-filter">${props.title}</th>`;
const Td = props => html`<td class="whitespace-nowrap border-b border-slate-200 py-2 px-4 pr-3 text-sm text-slate-900">${props.text}</td>`;
const Prio = ({prio}) => {
const text = ['high', 'medium', 'low'][prio];
const colors = [tipColors.red, tipColors.yellow, tipColors.green][prio];
return html`<${Colored} colors=${colors} text=${text} />`;
};
const Event = ({e}) => html`
<tr>
<${Td} text=${['power', 'hardware', 'tier3', 'tier4'][e.type]} />
<${Td} text=${html`<${Prio} prio=${e.prio}/>`} />
<${Td} text=${e.time ? (new Date(e.time * 1000)).toLocaleString() : '1970-01-01'} />
<${Td} text=${e.text} />
<//>`;
return html`
<div class="m-4 divide-y divide-gray-200 overflow-auto rounded bg-white">
<div class="font-semibold flex items-center text-gray-600 px-3 justify-between whitespace-nowrap">
<div class="font-semibold flex items-center text-gray-600">
<div class="mr-4">EVENT LOG</div>
</div>
<${Pagination} currentPage=${page} setPageFn=${setPage} totalItems=400 itemsPerPage=20 />
<//>
<div class="inline-block min-w-full align-middle" style="max-height: 82vh; overflow: auto;">
<table class="min-w-full border-separate border-spacing-0">
<thead>
<tr>
<${Th} title="Type" />
<${Th} title="Prio" />
<${Th} title="Time" />
<${Th} title="Description" />
</tr>
</thead>
<tbody>
${(events.arr ? events.arr : []).map(e => h(Event, {e}))}
</tbody>
</table>
<//>
<//>`;
};
function Chart({data}) {
const n = data.length /* entries */, w = 20 /* entry width */, ls = 15/* left space */;
const h = 100 /* graph height */, yticks = 5 /* Y axis ticks */, bs = 10 /* bottom space */;
const ymax = 25;
const yt = i => (h - bs) / yticks * (i + 1);
const bh = p => (h - bs) * p / 100; // Bar height
const by = p => (h - bs) - bh(p);
const range = (start, size, step) => Array.from({length: size}, (_, i) => i * (step || 1) + start);
// console.log(ds);
return html`
<div class="my-4 divide-y divide-gray-200 overflow-auto rounded bg-white">
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
Temperature, last 24h
<//>
<div class="relative">
<svg class="bg-yellow-x50 w-full p-4" viewBox="0 0 ${n*w+ls} ${h}">
${range(0, yticks).map(i => html`
<line x1=0 y1=${yt(i)} x2=${ls+n*w} y2=${yt(i)} stroke-width=0.3 class="stroke-slate-300" stroke-dasharray="1,1" />
<text x=0 y=${yt(i)-2} class="text-[6px] fill-slate-400">${ymax-ymax/yticks*(i+1)}<//>
`)}
${range(0, n).map(x => html`
<rect x=${ls+x*w} y=${by(data[x]*100/ymax)} width=12 height=${bh(data[x]*100/ymax)} rx=2 class="fill-cyan-500" />
<text x=${ls+x*w} y=100 class="text-[6px] fill-slate-400">${x*2}:00<//>
`)}
<//>
<//>
<//>`;
};
function DeveloperNote({text, children}) {
return html`
<div class="flex p-4 gap-2">
<div class="text-sm text-slate-500">
<div class="flex items-center">
<${Icons.info} class="self-start basis-[30px] grow-0 shrink-0 text-green-600 mr-2" />
<div class="font-semibold">Developer Note<//>
<//>
${(text || '').split('.').map(v => html` <p class="my-2 ">${v}<//>`)}
${children}
<//>
<//>`;
};
function Main({}) {
const [stats, setStats] = useState(null);
const refresh = () => fetch('api/stats/get').then(r => r.json()).then(r => setStats(r));
useEffect(refresh, []);
if (!stats) return '';
return html`
<div class="p-2">
<div class="p-4 sm:p-2 mx-auto grid grid-cols-2 lg:grid-cols-4 gap-4">
<${Stat} title="Temperature" text="${stats.temperature} °C" tipText="good" tipIcon=${Icons.ok} tipColors=${tipColors.green} />
<${Stat} title="Humidity" text="${stats.humidity} %" tipText="warn" tipIcon=${Icons.warn} tipColors=${tipColors.yellow} />
<div class="bg-white col-span-2 border rounded-md shadow-lg" role="alert">
<${DeveloperNote} text="Stats data is received from the Mongoose backend" />
<//>
<//>
<div class="p-4 sm:p-2 mx-auto grid grid-cols-1 lg:grid-cols-2 gap-4">
<${Chart} data=${stats.points} />
<div class="my-4 hx-24 bg-white border rounded-md shadow-lg" role="alert">
<${DeveloperNote}
text="This chart is an SVG image, generated on the fly from the
data returned by the api/stats/get API call" />
<//>
<//>
<//>`;
};
function FirmwareStatus({title, info, children}) {
const state = ['UNAVAILABLE', 'FIRST_BOOT', 'NOT_COMMITTED', 'COMMITTED'][(info.status || 0) % 4];
const valid = info.status > 0;
return html`
<div class="bg-white py-1 divide-y border rounded">
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
${title}
<//>
<div class="px-4 py-2 relative">
<div class="my-1">Status: ${state}<//>
<div class="my-1">CRC32: ${valid ? info.crc32.toString(16) : 'n/a'}<//>
<div class="my-1">Size: ${valid ? info.size : 'n/a'}<//>
<div class="my-1">Flashed at: ${valid ? new Date(info.timestamp * 1000).toLocaleString() : 'n/a'}<//>
${children}
<//>
<//>`;
};
function FirmwareUpdate({}) {
const [info, setInfo] = useState([{}, {}]);
const refresh = () => fetch('api/firmware/status').then(r => r.json()).then(r => setInfo(r));
useEffect(refresh, []);
const oncommit = ev => fetch('api/firmware/commit')
.then(r => r.json())
.then(refresh);
const onreboot = ev => fetch('api/device/reset')
.then(r => r.json())
.then(r => new Promise(r => setTimeout(ev => { refresh(); r(); }, 3000)));
const onrollback = ev => fetch('api/firmware/rollback')
.then(onreboot);
const onerase = ev => fetch('api/device/eraselast').then(refresh);
const onupload = function(ok, name, size) {
if (!ok) return false;
return new Promise(r => setTimeout(ev => { refresh(); r(); }, 3000));
};
return html`
<div class="m-4 gap-4 grid grid-cols-1 lg:grid-cols-3">
<${FirmwareStatus} title="Current firmware image" info=${info[0]}>
<div class="flex flex-wrap gap-2">
<${Button} title="Commit this firmware" onclick=${oncommit}
icon=${Icons.thumbUp} disabled=${info[0].status == 3} cls="w-full" />
<//>
<//>
<${FirmwareStatus} title="Previous firmware image" info=${info[1]}>
<${Button} title="Rollback to this firmware" onclick=${onrollback}
icon=${Icons.backward} disabled=${info[1].status == 0} cls="w-full" />
<//>
<div class="bg-white xm-4 divide-y border rounded flex flex-col">
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
Device control
<//>
<div class="px-4 py-3 flex flex-col gap-2 grow">
<${UploadFileButton}
title="Upload new firmware .bin file" onupload=${onupload}
url="api/firmware/upload" accept=".bin,.uf2" />
<div class="grow"><//>
<${Button} title="Reboot device" onclick=${onreboot} icon=${Icons.refresh} cls="w-full" />
<${Button} title="Erase last sector" onclick=${onerase} icon=${Icons.doc} cls="w-full hidden" />
<//>
<//>
<//>
<div class="m-4 gap-4 grid grid-cols-1 lg:grid-cols-2">
<div class="bg-white border shadow-lg">
<${DeveloperNote}>
<div class="my-2">
Firmware status and other information is stored in the last sector
of flash
<//>
<div class="my-2">
Firmware status can be FIRST_BOOT, UNCOMMITTED or COMMITTED. If no
information is available, it is UNAVAILABLE.
<//>
<div class="my-2">
This GUI loads a firmware file and sends it chunk by chunk to the
device, passing current chunk offset, total firmware size and a file name:
api/firmware/upload?offset=X&total=Y&name=Z
<//>
<//>
<//>
<div class="bg-white border shadow-lg">
<${DeveloperNote}>
<div>
Firmware update mechanism defines 3 API functions that the target
device must implement: mg_ota_begin(), mg_ota_write() and mg_ota_end()
<//>
<div class="my-2">
RESTful API handlers use ota_xxx() API to save firmware to flash.
The last 0-length chunk triggers ota_end() which performs firmware
update using saved firmware image
<//>
<div class="my-2">
<a class="link text-blue-600 underline"
href="https://mongoose.ws/webinars/">Join our free webinar</a> to
get detailed explanations about possible firmware updates strategies
and implementation demo
<//>
<//>
<//>
<//>`;
};
function Settings({}) {
const [settings, setSettings] = useState(null);
const [saveResult, setSaveResult] = useState(null);
const refresh = () => fetch('api/settings/get')
.then(r => r.json())
.then(r => setSettings(r));
useEffect(refresh, []);
const mksetfn = k => (v => setSettings(x => Object.assign({}, x, {[k]: v})));
const onsave = ev => fetch('api/settings/set', {
method: 'post', body: JSON.stringify(settings)
}).then(r => r.json())
.then(r => setSaveResult(r))
.then(refresh);
if (!settings) return '';
const logOptions = [[0, 'Disable'], [1, 'Error'], [2, 'Info'], [3, 'Debug']];
return html`
<div class="m-4 grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="py-1 divide-y border rounded bg-white flex flex-col">
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
Device Settings
<//>
<div class="py-2 px-5 flex-1 flex flex-col relative">
${saveResult && html`<${Notification} ok=${saveResult.status}
text=${saveResult.message} close=${() => setSaveResult(null)} />`}
<${Setting} title="Enable Logs" value=${settings.log_enabled} setfn=${mksetfn('log_enabled')} type="switch" />
<${Setting} title="Log Level" value=${settings.log_level} setfn=${mksetfn('log_level')} type="select" addonLeft="0-3" disabled=${!settings.log_enabled} options=${logOptions}/>
<${Setting} title="Brightness" value=${settings.brightness} setfn=${mksetfn('brightness')} type="number" addonRight="%" />
<${Setting} title="Device Name" value=${settings.device_name} setfn=${mksetfn('device_name')} type="" />
<div class="mb-1 mt-3 flex place-content-end"><${Button} icon=${Icons.save} onclick=${onsave} title="Save Settings" /><//>
<//>
<//>
<div class="bg-white border rounded-md text-ellipsis overflow-auto" role="alert">
<${DeveloperNote}
text="A variety of controls are pre-defined to ease the development:
toggle button, dropdown select, input field with left and right
addons. Device settings are received by calling
api/settings/get API call, which returns settings JSON object.
Clicking on the save button calls api/settings/set
API call" />
<//>
<//>`;
};
const App = function({}) {
const [loading, setLoading] = useState(true);
const [url, setUrl] = useState('/');
const [user, setUser] = useState('');
const [showSidebar, setShowSidebar] = useState(true);
const logout = () => fetch('api/logout').then(r => setUser(''));
const login = r => !r.ok ? setLoading(false) && setUser(null) : r.json()
.then(r => setUser(r.user))
.finally(r => setLoading(false));
useEffect(() => fetch('api/login').then(login), []);
if (loading) return ''; // Show blank page on initial load
if (!user) return html`<${Login} loginFn=${login} logoIcon=${Logo}
title="Device Dashboard Login"
tipText="To login, use: admin/admin, user1/user1, user2/user2" />`; // If not logged in, show login screen
return html`
<div class="h-screen bg-slate-100">
<${Sidebar} url=${url} show=${showSidebar} />
<${Header} logout=${logout} user=${user} showSidebar=${showSidebar} setShowSidebar=${setShowSidebar} />
<div class="${showSidebar && 'pl-72'} transition-all duration-300 transform">
<${Router} onChange=${ev => setUrl(ev.url)} history=${History.createHashHistory()} >
<${Main} default=${true} />
<${Settings} path="settings" />
<${FirmwareUpdate} path="update" />
<${Events} path="events" />
<//>
<//>
<//>`;
};
window.onload = () => render(h(App), document.body);
+9 -4
View File
@@ -6,9 +6,9 @@
#define MG_ARCH_ESP32 3 // ESP32 #define MG_ARCH_ESP32 3 // ESP32
#define MG_ARCH_ESP8266 4 // ESP8266 #define MG_ARCH_ESP8266 4 // ESP8266
#define MG_ARCH_FREERTOS 5 // FreeRTOS #define MG_ARCH_FREERTOS 5 // FreeRTOS
#define MG_ARCH_AZURERTOS 6 // MS Azure RTOS #define MG_ARCH_THREADX 6 // Eclipse ThreadX (former MS Azure RTOS)
#define MG_ARCH_ZEPHYR 7 // Zephyr RTOS #define MG_ARCH_ZEPHYR 7 // Zephyr RTOS
#define MG_ARCH_NEWLIB 8 // Bare metal ARM #define MG_ARCH_ARMGCC 8 // Plain ARM GCC
#define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX) #define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX)
#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS #define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS
#define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350) #define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350)
@@ -16,6 +16,9 @@
#define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS) #define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS)
#define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS #define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS
#define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT #define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT
#define MG_ARCH_CUBE 16 // STM32Cube environment
#define MG_ARCH_NEWLIB MG_ARCH_ARMGCC // Alias, deprecate in 2025
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
#if defined(__unix__) || defined(__APPLE__) #if defined(__unix__) || defined(__APPLE__)
@@ -30,17 +33,19 @@
#endif #endif
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
#error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in your compiler" #error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in mongoose_config.h"
#endif #endif
// http://esr.ibiblio.org/?p=5095 // http://esr.ibiblio.org/?p=5095
#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100) #define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100)
#include "arch_armgcc.h"
#include "arch_cube.h"
#include "arch_esp32.h" #include "arch_esp32.h"
#include "arch_esp8266.h" #include "arch_esp8266.h"
#include "arch_freertos.h" #include "arch_freertos.h"
#include "arch_newlib.h"
#include "arch_rtx.h" #include "arch_rtx.h"
#include "arch_threadx.h"
#include "arch_unix.h" #include "arch_unix.h"
#include "arch_win32.h" #include "arch_win32.h"
#include "arch_zephyr.h" #include "arch_zephyr.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#if MG_ARCH == MG_ARCH_NEWLIB #if MG_ARCH == MG_ARCH_ARMGCC
#define _POSIX_TIMERS #define _POSIX_TIMERS
#include <ctype.h> #include <ctype.h>
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#if MG_ARCH == MG_ARCH_AZURERTOS
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <fx_api.h>
#include <tx_api.h>
#include <nx_api.h>
#include <nx_bsd.h>
#include <nx_port.h>
#include <tx_port.h>
#define PATH_MAX FX_MAXIMUM_PATH
#define MG_DIRSEP '\\'
#define socklen_t int
#define closesocket(x) soc_close(x)
#undef FOPEN_MAX
#endif
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#if MG_ARCH == MG_ARCH_CUBE
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
// Cube-generated header, includes ST Cube HAL
// NOTE: use angle brackets to prevent amalgamator ditching it
#include <main.h>
#ifndef MG_PATH_MAX
#define MG_PATH_MAX 100
#endif
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 0
#endif
#ifndef MG_ENABLE_SOCKET
#define MG_ENABLE_SOCKET 0
#endif
#ifndef MG_ENABLE_TCPIP
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
#endif
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \
!defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N)
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
#define MG_ENABLE_DRIVER_STM32F 1
#elif defined(STM32H5) || defined(STM32H7)
#define MG_ENABLE_DRIVER_STM32H 1
#elif defined(STM32N6)
#define MG_ENABLE_DRIVER_STM32N 1
#else
#error Select a driver in mongoose_config.h
#endif
#endif
#ifndef MG_TLS
#define MG_TLS MG_TLS_BUILTIN
#endif
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || \
defined(STM32F4) || defined(STM32F7)
#define MG_OTA MG_OTA_STM32F
#elif !defined(MG_OTA) && defined(STM32H5)
#define MG_OTA MG_OTA_STM32H5
#elif !defined(MG_OTA) && defined(STM32H7)
#define MG_OTA MG_OTA_STM32H7
#endif
// use HAL-defined execute-in-ram section
#define MG_IRAM __attribute__((section(".RamFunc")))
#ifndef HAL_ICACHE_MODULE_ENABLED
#define HAL_ICACHE_IsEnabled() 0
#define HAL_ICACHE_Enable() (void) 0
#define HAL_ICACHE_Disable() (void) 0
#endif
#ifndef MG_SET_MAC_ADDRESS
// Construct MAC address from UUID
#define MGUID ((uint32_t *) UID_BASE) // Unique 96-bit chip ID
#define MG_SET_MAC_ADDRESS(mac) \
do { \
int icache_enabled_ = HAL_ICACHE_IsEnabled(); \
if (icache_enabled_) HAL_ICACHE_Disable(); \
mac[0] = 42; \
mac[1] = ((MGUID[0] >> 0) & 255) ^ ((MGUID[2] >> 19) & 255); \
mac[2] = ((MGUID[0] >> 10) & 255) ^ ((MGUID[1] >> 10) & 255); \
mac[3] = (MGUID[0] >> 19) & 255; \
mac[4] = ((MGUID[1] >> 0) & 255) ^ ((MGUID[2] >> 10) & 255); \
mac[5] = ((MGUID[2] >> 0) & 255) ^ ((MGUID[1] >> 19) & 255); \
if (icache_enabled_) HAL_ICACHE_Enable(); \
} while (0)
#endif
#endif
+8
View File
@@ -22,4 +22,12 @@
#define MG_PATH_MAX 128 #define MG_PATH_MAX 128
#ifndef MG_ENABLE_POSIX_FS
#define MG_ENABLE_POSIX_FS 1
#endif
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 1
#endif
#endif #endif
+9 -4
View File
@@ -17,6 +17,7 @@
#define mode_t size_t #define mode_t size_t
#include <alloca.h> #include <alloca.h>
#include <time.h> #include <time.h>
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
#elif defined(__CCRH__) #elif defined(__CCRH__)
#else #else
#include <sys/stat.h> #include <sys/stat.h>
@@ -25,10 +26,11 @@
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <task.h> #include <task.h>
#define calloc(a, b) mg_calloc(a, b) #define MG_ENABLE_CUSTOM_CALLOC 1
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a) static inline void mg_free(void *ptr) {
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf) vPortFree(ptr);
}
// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(size_t cnt, size_t size) { static inline void *mg_calloc(size_t cnt, size_t size) {
@@ -37,10 +39,13 @@ static inline void *mg_calloc(size_t cnt, size_t size) {
return p; return p;
} }
#if !defined(MG_ENABLE_POSIX_FS) || !MG_ENABLE_POSIX_FS
#else
#define mkdir(a, b) mg_mkdir(a, b) #define mkdir(a, b) mg_mkdir(a, b)
static inline int mg_mkdir(const char *path, mode_t mode) { static inline int mg_mkdir(const char *path, mode_t mode) {
(void) path, (void) mode; (void) path, (void) mode;
return -1; return -1;
} }
#endif
#endif // MG_ARCH == MG_ARCH_FREERTOS #endif // MG_ARCH == MG_ARCH_FREERTOS
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#if MG_ARCH == MG_ARCH_THREADX
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
// Do not include time.h and stdlib.h, since they conflict with nxd_bsd.h
// extern time_t time(time_t *);
#include <nxd_bsd.h>
#define MG_DIRSEP '\\'
#undef FOPEN_MAX
#ifndef MG_PATH_MAX
#define MG_PATH_MAX 32
#endif
#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
#define MG_SOCK_LISTEN_BACKLOG_SIZE 3
#endif
#ifndef MG_ENABLE_IPV6
#define MG_ENABLE_IPV6 0
#endif
#define socklen_t int
#define closesocket(x) soc_close(x)
// In order to enable BSD support in NetxDuo, do the following (assuming Cube):
// 1. Add nxd_bsd.h and nxd_bsd.c to the repo:
// https://github.com/eclipse-threadx/netxduo/blob/v6.1.12_rel/addons/BSD/nxd_bsd.c
// https://github.com/eclipse-threadx/netxduo/blob/v6.1.12_rel/addons/BSD/nxd_bsd.h
// 2. Add to tx_user.h
// #define TX_THREAD_USER_EXTENSION int bsd_errno;
// 3. Add to nx_user.h
// #define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT
// 4. Add __CCRX__ build preprocessor constant
// Project -> Properties -> C/C++ -> Settings -> MCU Compiler -> Preprocessor
#endif
+59 -12
View File
@@ -2,10 +2,33 @@
#if MG_ARCH == MG_ARCH_WIN32 #if MG_ARCH == MG_ARCH_WIN32
// Avoid name clashing; (macro expansion producing 'defined' has undefined
// behaviour). See config.h for user options
#ifndef MG_ENABLE_WINSOCK
#if (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP) && \
(!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \
(!defined(MG_ENABLE_FREERTOS_TCP) || !MG_ENABLE_FREERTOS_TCP)
#define MG_ENABLE_WINSOCK 1
#else
#define MG_ENABLE_WINSOCK 0
#endif
#endif
#ifndef _CRT_RAND_S #ifndef _CRT_RAND_S
#define _CRT_RAND_S #define _CRT_RAND_S
#endif #endif
#ifndef _WIN32_WINNT
#if defined(_MSC_VER) && _MSC_VER < 1700
#define _WIN32_WINNT 0x0400 // Let vc98 pick up wincrypt.h
#else
#define _WIN32_WINNT 0x0600
#endif
#endif
#ifndef WINVER
#define WINVER _WIN32_WINNT
#endif
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
@@ -33,6 +56,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <winsock2.h> // fix missing macros and types
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
#define __func__ "" #define __func__ ""
typedef __int64 int64_t; typedef __int64 int64_t;
@@ -47,22 +72,34 @@ typedef enum { false = 0, true = 1 } bool;
#else #else
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#if MG_ENABLE_WINSOCK
#include <ws2tcpip.h> #include <ws2tcpip.h>
#endif #endif
#endif
#include <process.h> #include <process.h>
#include <winerror.h> #include <winerror.h>
#include <winsock2.h>
// For mg_random() // For mg_random()
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400 // Let vc98 pick up wincrypt.h
#endif
#include <wincrypt.h> #include <wincrypt.h>
#pragma comment(lib, "advapi32.lib") #pragma comment(lib, "advapi32.lib")
#endif #endif
#if defined(_MSC_VER) && _MSC_VER <= 1200
#ifndef IPPROTO_IP
#define IPPROTO_IP 0
#endif
#ifndef IP_ADD_MEMBERSHIP
struct ip_mreq {
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
#define IP_ADD_MEMBERSHIP 12
#endif
#endif
// Protect from calls like std::snprintf in app code // Protect from calls like std::snprintf in app code
// See https://github.com/cesanta/mongoose/issues/1047 // See https://github.com/cesanta/mongoose/issues/1047
#ifndef __cplusplus #ifndef __cplusplus
@@ -73,25 +110,33 @@ typedef enum { false = 0, true = 1 } bool;
#endif #endif
#endif #endif
#define MG_INVALID_SOCKET INVALID_SOCKET #if defined(MG_ENABLE_POLL) && MG_ENABLE_POLL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP)
#define MG_SOCKET_TYPE SOCKET typedef unsigned long nfds_t; // see #3388
typedef unsigned long nfds_t; #endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if MG_ENABLE_WINSOCK
#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "ws2_32.lib")
#endif
#ifndef alloca #ifndef alloca
#define alloca(a) _alloca(a) #define alloca(a) _alloca(a)
#endif #endif
#endif #endif
#define poll(a, b, c) WSAPoll((a), (b), (c))
#define closesocket(x) closesocket(x)
typedef int socklen_t;
#define MG_DIRSEP '\\' #define MG_DIRSEP '\\'
#ifndef MG_PATH_MAX #ifndef MG_PATH_MAX
#define MG_PATH_MAX FILENAME_MAX #define MG_PATH_MAX FILENAME_MAX
#endif #endif
#if MG_ENABLE_WINSOCK
#define MG_INVALID_SOCKET INVALID_SOCKET
#define MG_SOCKET_TYPE SOCKET
#define poll(a, b, c) WSAPoll((a), (b), (c))
#define closesocket(x) closesocket(x)
typedef int socklen_t;
#ifndef SO_EXCLUSIVEADDRUSE #ifndef SO_EXCLUSIVEADDRUSE
#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR)) #define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
#endif #endif
@@ -106,13 +151,15 @@ typedef int socklen_t;
#define MG_SOCK_RESET(errcode) \ #define MG_SOCK_RESET(errcode) \
(((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET)) (((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET))
#endif // MG_ENABLE_WINSOCK
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX) #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
#define sleep(x) Sleep((x) * 1000) #define sleep(x) Sleep((x) *1000)
#define mkdir(a, b) _mkdir(a) #define mkdir(a, b) _mkdir(a)
#define timegm(x) _mkgmtime(x) #define timegm(x) _mkgmtime(x)
#ifndef S_ISDIR #ifndef S_ISDIR
#define S_ISDIR(x) (((x) & _S_IFMT) == _S_IFDIR) #define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
#endif #endif
#ifndef MG_ENABLE_DIRLIST #ifndef MG_ENABLE_DIRLIST
+6 -3
View File
@@ -3,12 +3,15 @@
#if MG_ARCH == MG_ARCH_ZEPHYR #if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/net/socket.h>
// #include <zephyr/posix/dirent.h>
#include <zephyr/posix/fcntl.h>
#include <zephyr/posix/sys/select.h>
#include <zephyr/random/random.h>
#include <zephyr/version.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <zephyr/net/socket.h>
#include <zephyr/posix/fcntl.h>
#include <zephyr/posix/sys/select.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
+36 -3
View File
@@ -4,6 +4,10 @@
#define MG_ENABLE_LOG 1 #define MG_ENABLE_LOG 1
#endif #endif
#ifndef MG_ENABLE_CUSTOM_CALLOC
#define MG_ENABLE_CUSTOM_CALLOC 0
#endif
#ifndef MG_ENABLE_CUSTOM_LOG #ifndef MG_ENABLE_CUSTOM_LOG
#define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG #define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG
#endif #endif
@@ -56,7 +60,8 @@
#define MG_ENABLE_MD5 1 #define MG_ENABLE_MD5 1
#endif #endif
// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP) // Set MG_ENABLE_WINSOCK=0 for Win32 builds with other external IP stack not
// mentioned in arch_win32.h
#ifndef MG_ENABLE_WINSOCK #ifndef MG_ENABLE_WINSOCK
#define MG_ENABLE_WINSOCK 1 #define MG_ENABLE_WINSOCK 1
#endif #endif
@@ -170,14 +175,42 @@
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) #define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
#endif #endif
#if MG_ENABLE_IPV6
#ifndef MG_TCPIP_GLOBAL
#define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_IPV6_LINKLOCAL
#define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_PREFIX_LEN
#define MG_TCPIP_PREFIX_LEN 0
#endif
#ifndef MG_TCPIP_GW6
#define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#endif
#ifndef MG_SET_MAC_ADDRESS #ifndef MG_SET_MAC_ADDRESS
#define MG_SET_MAC_ADDRESS(mac) #define MG_SET_MAC_ADDRESS(mac)
#endif #endif
#ifndef MG_SET_WIFI_CREDS #ifndef MG_TCPIP_DHCPNAME_SIZE
#define MG_SET_WIFI_CREDS(ssid, pass) #define MG_TCPIP_DHCPNAME_SIZE 18 // struct mg_tcpip_if :: dhcp_name size
#endif
#ifndef MG_SET_WIFI_CONFIG
#define MG_SET_WIFI_CONFIG(data)
#endif #endif
#ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS #ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS
#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0 #define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
#endif #endif
#ifndef MG_ENABLE_CHACHA20
#define MG_ENABLE_CHACHA20 1 // When set to 0, GCM is used. For MG_TLS_BUILTIN
#endif
+380 -19
View File
@@ -18,7 +18,7 @@ static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
static void mg_dns_free(struct dns_data **head, struct dns_data *d) { static void mg_dns_free(struct dns_data **head, struct dns_data *d) {
LIST_DELETE(struct dns_data, head, d); LIST_DELETE(struct dns_data, head, d);
free(d); mg_free(d);
} }
void mg_resolve_cancel(struct mg_connection *c) { void mg_resolve_cancel(struct mg_connection *c) {
@@ -63,7 +63,7 @@ static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
// MG_INFO(("--> [%s]", to)); // MG_INFO(("--> [%s]", to));
} }
if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term if (tolen > 0) to[tolen - 1] = '\0'; // Make sure it is nul-term
return i; return i;
} }
@@ -100,6 +100,7 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
const struct mg_dns_header *h = (struct mg_dns_header *) buf; const struct mg_dns_header *h = (struct mg_dns_header *) buf;
struct mg_dns_rr rr; struct mg_dns_rr rr;
size_t i, n, num_answers, ofs = sizeof(*h); size_t i, n, num_answers, ofs = sizeof(*h);
bool is_response;
memset(dm, 0, sizeof(*dm)); memset(dm, 0, sizeof(*dm));
if (len < sizeof(*h)) return 0; // Too small, headers dont fit if (len < sizeof(*h)) return 0; // Too small, headers dont fit
@@ -110,12 +111,22 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
num_answers = 10; // Sanity cap num_answers = 10; // Sanity cap
} }
dm->txnid = mg_ntohs(h->txnid); dm->txnid = mg_ntohs(h->txnid);
is_response = mg_ntohs(h->flags) & 0x8000;
for (i = 0; i < mg_ntohs(h->num_questions); i++) { for (i = 0; i < mg_ntohs(h->num_questions); i++) {
if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false; if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
// MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass)); // MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass));
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
ofs += n; ofs += n;
} }
if (!is_response) {
// For queries, there is no need to parse the answers. In this way,
// we also ensure the domain name (dm->name) is parsed from
// the question field.
return true;
}
for (i = 0; i < num_answers; i++) { for (i = 0; i < num_answers; i++) {
if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false; if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
// MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass, // MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass,
@@ -123,14 +134,15 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name)); mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
ofs += n; ofs += n;
if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) { if (rr.alen == 4 && rr.atype == MG_DNS_RTYPE_A && rr.aclass == 1) {
dm->addr.is_ip6 = false; dm->addr.is_ip6 = false;
memcpy(&dm->addr.ip, &buf[ofs - 4], 4); memcpy(&dm->addr.addr.ip, &buf[ofs - 4], 4);
dm->resolved = true; dm->resolved = true;
break; // Return success break; // Return success
} else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) { } else if (rr.alen == 16 && rr.atype == MG_DNS_RTYPE_AAAA &&
rr.aclass == 1) {
dm->addr.is_ip6 = true; dm->addr.is_ip6 = true;
memcpy(&dm->addr.ip, &buf[ofs - 16], 16); memcpy(&dm->addr.addr.ip, &buf[ofs - 16], 16);
dm->resolved = true; dm->resolved = true;
break; // Return success break; // Return success
} }
@@ -221,26 +233,35 @@ static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name,
return mg_send(c, &pkt, sizeof(pkt.header) + n); return mg_send(c, &pkt, sizeof(pkt.header) + n);
} }
bool mg_dnsc_init(struct mg_mgr *mgr, struct mg_dns *dnsc);
bool mg_dnsc_init(struct mg_mgr *mgr, struct mg_dns *dnsc) {
if (dnsc->url == NULL) {
mg_error(0, "DNS server URL is NULL. Call mg_mgr_init()");
return false;
}
if (dnsc->c == NULL) {
dnsc->c = mg_connect(mgr, dnsc->url, NULL, NULL);
if (dnsc->c == NULL) return false;
dnsc->c->pfn = dns_cb;
}
return true;
}
static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
struct mg_dns *dnsc, bool ipv6) { struct mg_dns *dnsc, bool ipv6) {
struct dns_data *d = NULL; struct dns_data *d = NULL;
if (dnsc->url == NULL) { if (!mg_dnsc_init(c->mgr, dnsc)) {
mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()");
} else if (dnsc->c == NULL) {
dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL);
if (dnsc->c != NULL) {
dnsc->c->pfn = dns_cb;
// dnsc->c->is_hexdumping = 1;
}
}
if (dnsc->c == NULL) {
mg_error(c, "resolver"); mg_error(c, "resolver");
} else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) { } else if ((d = (struct dns_data *) mg_calloc(1, sizeof(*d))) == NULL) {
mg_error(c, "resolve OOM"); mg_error(c, "resolve OOM");
} else { } else {
struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1; uint16_t id;
d->next = (struct dns_data *) c->mgr->active_dns_requests; mg_random(&id, sizeof(uint16_t));
// TODO(): traverse reqs and check id != reqs->txnid; repeat otherwise
if (reqs != NULL) id = (uint16_t) (reqs->txnid + 1); // no collision
d->txnid = id;
d->next = reqs;
c->mgr->active_dns_requests = d; c->mgr->active_dns_requests = d;
d->expire = mg_millis() + (uint64_t) ms; d->expire = mg_millis() + (uint64_t) ms;
d->c = c; d->c = c;
@@ -265,3 +286,343 @@ void mg_resolve(struct mg_connection *c, const char *url) {
mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6); mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6);
} }
} }
// Response header length is 10 bytes
static const uint8_t mdns_answer[] = {
0, 1, // 2 bytes - record type, A
0, 1, // 2 bytes - address class, INET
0, 0, 0, 120, // 4 bytes - TTL
0, 4 // 2 bytes - address length
};
// A name length is name->len + '.local' + 2 = name->len + 8
static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
*p++ = (uint8_t) name->len; // label 1
memcpy(p, name->buf, name->len), p += name->len;
*p++ = 5; // label 2
memcpy(p, "local", 5), p += 5;
*p++ = 0; // no more labels
return p;
}
void mg_getlocaddr(struct mg_connection *, struct mg_addr *, struct mg_addr *);
// An A record length is 10 + 4 = 14 bytes
static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
struct mg_addr *addr) {
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
if (addr != NULL && !addr->is_ip6) {
memcpy(p, &addr->addr.ip4, 4), p += 4;
} else {
#if MG_ENABLE_TCPIP
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
#else
struct mg_addr loc, to;
memset(&loc, 0, sizeof(loc));
to.is_ip6 = false;
to.port = mg_htons(5353);
to.addr.ip4 = MG_IPV4(224, 0, 0, 51);
mg_getlocaddr(c, &to, &loc);
memcpy(p, &loc.addr.ip4, 4), p += 4;
#endif
}
return p;
}
// A srv name length is r->srvcproto.len + '.local' + 2 = r->srvcproto.len + 8
static uint8_t *build_srv_name(uint8_t *p, struct mg_dnssd_record *r) {
*p++ = (uint8_t) r->srvcproto.len - 5; // label 1, up to '._tcp'
memcpy(p, r->srvcproto.buf, r->srvcproto.len), p += r->srvcproto.len;
p[-5] = 4; // label 2, '_tcp', overwrite '.'
*p++ = 5; // label 3
memcpy(p, "local", 5), p += 5;
*p++ = 0; // no more labels
return p;
}
#if 0
// TODO(): for listing
static uint8_t *build_mysrv_name(struct mg_str *name, uint8_t *p,
struct mg_dnssd_record *r) {
*p++ = name->len; // label 1
memcpy(p, name->buf, name->len), p += name->len;
return build_srv_name(p, r);
}
#endif
// A PTR record length is 10 + name->len + 3 = name->len + 13
static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
uint16_t offset = mg_htons(o);
memcpy(p, mdns_answer, sizeof(mdns_answer));
p[1] = MG_DNS_RTYPE_PTR; // overwrite record type
p += sizeof(mdns_answer);
p[-1] = (uint8_t) name->len +
3; // overwrite response length, label length + label + offset
*p++ = (uint8_t) name->len; // response: label 1
memcpy(p, name->buf, name->len), p += name->len; // copy label
memcpy(p, &offset, 2);
*p |= 0xC0, p += 2;
return p;
}
// An SRV record length is 10 + name->len + 9 = name->len + 19
static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
struct mg_dnssd_record *r, uint16_t o) {
uint16_t port = mg_htons(r->port);
uint16_t offset = mg_htons(o);
memcpy(p, mdns_answer, sizeof(mdns_answer));
p[1] = MG_DNS_RTYPE_SRV; // overwrite record type
p += sizeof(mdns_answer);
p[-1] = (uint8_t) name->len + 9; // overwrite response length (4+2+1+2)
*p++ = 0; // priority
*p++ = 0;
*p++ = 0; // weight
*p++ = 0;
memcpy(p, &port, 2), p += 2; // port
*p++ = (uint8_t) name->len; // label 1
memcpy(p, name->buf, name->len), p += name->len;
memcpy(p, &offset, 2);
*p |= 0xC0, p += 2;
return p;
}
// A TXT record length is r->txt.len (txt contents) + 10
static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
uint16_t len = mg_htons((uint16_t) r->txt.len);
memcpy(p, mdns_answer, sizeof(mdns_answer));
p[1] = MG_DNS_RTYPE_TXT; // overwrite record type
p += sizeof(mdns_answer);
memcpy(p - 2, &len, 2); // overwrite response length
memcpy(p, r->txt.buf, r->txt.len), p += r->txt.len; // copy record verbatim
return p;
}
// Each additional record has a 2-byte field pointing to the name label
// RFC-6762 16: case-insensitivity --> RFC-1034, 1035
static void handle_mdns_query(struct mg_connection *c) {
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
struct mg_dns_rr rr;
size_t n;
// Parse first question, offset 12 is header size
n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
if (n > 0) {
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
struct mg_dns_header *h = (struct mg_dns_header *) buf;
uint8_t *p = &buf[sizeof(*h)];
char name[256];
uint8_t name_len;
// uint16_t q = mg_ntohs(qh->num_questions);
struct mg_str defname = mg_str((const char *) c->fn_data);
struct mg_str *respname;
struct mg_mdns_req req;
memset(&req, 0, sizeof(req));
req.is_unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
qh->num_questions = mg_htons(1); // parser sanity
mg_dns_parse_name(c->recv.buf, c->recv.len, 12, name, sizeof(name));
name_len = (uint8_t) strlen(name); // verify it ends in .local
if (name_len <= 6 || strcmp(".local", &name[name_len - 6]) != 0 ||
(rr.aclass != 1 && rr.aclass != 0xff))
return;
name[name_len -= 6] = '\0'; // remove .local
MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype,
(unsigned int) rr.aclass, name));
if (rr.atype == MG_DNS_RTYPE_A) {
// TODO(): ensure c->fn_data ends in \0
// if we have a name to match, go; otherwise users will match and fill
// req.r.name and set req.is_resp
if (c->fn_data != NULL && mg_casecmp((char *) c->fn_data, name) != 0)
return;
req.is_resp = (c->fn_data != NULL);
req.reqname = mg_str_n(name, name_len);
} else // users have to match the request to something in their db, then
// fill req.r and set req.is_resp
if (rr.atype == MG_DNS_RTYPE_PTR) {
if (strcmp("_services._dns-sd._udp", name) == 0) req.is_listing = true;
MG_DEBUG(
("PTR request for %s", req.is_listing ? "services listing" : name));
req.reqname = mg_str_n(name, name_len);
} else if (rr.atype == MG_DNS_RTYPE_SRV || rr.atype == MG_DNS_RTYPE_TXT) {
MG_DEBUG(("%s request for %s",
rr.atype == MG_DNS_RTYPE_SRV ? "SRV" : "TXT", name));
// if possible, check it starts with our name, users will check it ends
// in a service name they handle
if (c->fn_data != NULL) {
if (mg_strcasecmp(defname, mg_str_n(name, defname.len)) != 0 ||
name[defname.len] != '.')
return;
req.reqname =
mg_str_n(name + defname.len + 1, name_len - defname.len - 1);
MG_DEBUG(
("That's us, handing %.*s", req.reqname.len, req.reqname.buf));
} else {
req.reqname = mg_str_n(name, name_len);
}
} else { // unhandled record
return;
}
req.rr = &rr;
mg_call(c, MG_EV_MDNS_REQ, &req);
if (!req.is_resp) return;
respname = req.respname.buf != NULL ? &req.respname : &defname;
memset(h, 0, sizeof(*h)); // clear header
h->txnid = req.is_unicast ? qh->txnid : 0; // RFC-6762 18.1
h->num_answers = mg_htons(1); // RFC-6762 6: 0 questions, 1 Answer
h->flags = mg_htons(0x8400); // Authoritative response
if (req.is_listing) {
// TODO(): RFC-6762 6: each responder SHOULD delay its response by a
// random amount of time selected with uniform random distribution in the
// range 20-120 ms.
// TODO():
return;
} else if (rr.atype == MG_DNS_RTYPE_PTR) { // serve PTR + SRV + TXT + A
// TODO(): RFC-6762 6: each responder SHOULD delay its response by a
// random amount of time selected with uniform random distribution in the
// range 20-120 ms. Response to PTR is local_name._myservice._tcp.local
uint8_t *o = p, *aux;
uint16_t offset;
if (respname->buf == NULL || respname->len == 0) return;
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 13 + 2 +
respname->len + 19 + 2 + req.r->txt.len + 10 + 2 + 14) >
sizeof(buf)) // srv name + PTR + 2 + SRV + 2 + TXT + 2 + A
return;
h->num_other_prs = mg_htons(3); // 3 additional records
p = build_srv_name(p, req.r);
aux = build_ptr_record(respname, p, (uint16_t) (o - buf));
o = p + sizeof(mdns_answer); // point to PTR response (full srvc name)
offset = mg_htons((uint16_t) (o - buf));
o = p - 7; // point to '.local' label (\x05local\x00)
p = aux;
memcpy(p, &offset, 2); // point to full srvc name, in record
*p |= 0xC0, p += 2;
aux = p;
p = build_srv_record(respname, p, req.r, (uint16_t) (o - buf));
o = aux + sizeof(mdns_answer) + 6; // point to target in SRV
memcpy(p, &offset, 2); // point to full srvc name, in record
*p |= 0xC0, p += 2;
p = build_txt_record(p, req.r);
offset = mg_htons((uint16_t) (o - buf));
memcpy(p, &offset, 2); // point to target name, in record
*p |= 0xC0, p += 2;
p = build_a_record(c, p, req.addr);
} else if (rr.atype == MG_DNS_RTYPE_TXT) {
if ((sizeof(*h) + req.r->srvcproto.len + 8 + req.r->txt.len + 10) >
sizeof(buf)) // srv name + TXT
return;
p = build_srv_name(p, req.r);
p = build_txt_record(p, req.r);
} else if (rr.atype == MG_DNS_RTYPE_SRV) { // serve SRV + A
uint8_t *o, *aux;
uint16_t offset;
if (respname->buf == NULL || respname->len == 0) return;
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 19 + 2 +
14) > sizeof(buf)) // srv name + SRV + 2 + A
return;
h->num_other_prs = mg_htons(1); // 1 additional record
p = build_srv_name(p, req.r);
o = p - 7; // point to '.local' label (\x05local\x00)
aux = p;
p = build_srv_record(respname, p, req.r, (uint16_t) (o - buf));
o = aux + sizeof(mdns_answer) + 6; // point to target in SRV
offset = mg_htons((uint16_t) (o - buf));
memcpy(p, &offset, 2); // point to target name, in record
*p |= 0xC0, p += 2;
p = build_a_record(c, p, req.addr);
} else { // A requested
// RFC-6762 6: 0 Auth, 0 Additional RRs
if (respname->buf == NULL || respname->len == 0) return;
if ((sizeof(*h) + respname->len + 8 + 14) > sizeof(buf)) // name + A
return;
p = build_name(respname, p);
p = build_a_record(c, p, req.addr);
}
if (!req.is_unicast) mg_multicast_restore(c, (uint8_t *) &c->loc);
mg_send(c, buf, (size_t) (p - buf)); // And send it!
MG_DEBUG(("%M > %M", mg_print_ip_port, &c->loc, mg_print_ip_port, &c->rem));
MG_DEBUG(("mDNS %s response sent", req.is_unicast ? "unicast" : "mcast"));
}
}
static void handle_mdns_response(struct mg_connection *c) {
struct mg_dns_header *rh = (struct mg_dns_header *) c->recv.buf;
struct mg_dns_rr rr;
size_t n;
// Parse first response, offset 12 is header size
n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, false, &rr);
MG_VERBOSE(("mDNS response parsed, result=%d", (int) n));
if (n > 0) {
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
char name[256];
uint8_t name_len;
struct mg_mdns_resp resp;
memset(&resp, 0, sizeof(resp));
if (rh->num_answers > mg_htons(1)) MG_DEBUG(("ignoring > 1 answers"));
mg_dns_parse_name(c->recv.buf, c->recv.len, 12, name, sizeof(name));
name_len = (uint8_t) strlen(name); // verify it ends in .local
MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype,
(unsigned int) rr.aclass, name));
if (rr.alen == 4 && rr.atype == MG_DNS_RTYPE_A &&
(rr.aclass & 0x7FFF) == 1) {
resp.addr.is_ip6 = false;
memcpy(resp.addr.addr.ip, (char *) (rh + 1) + n - 4, 4);
MG_DEBUG(("A response from %.*s = %M", name_len, name, mg_print_ip,
&resp.addr));
// } else if (rr.alen == 16 && rr.atype == MG_DNS_RTYPE_AAAA &&
// (rr.aclass & 0x7FFF) == 1) {
// resp.addr.is_ip6 = true;
// memcpy(resp.addr.addr.ip, (char *)(rh + 1) + n - 16], 16);
// MG_DEBUG(("AAAA response from %.*s = %M", name_len, name,
// mg_print_ip, &resp.addr));
} else {
return;
}
resp.name = mg_str_n(name, name_len);
resp.rr = &rr;
mg_call(c, MG_EV_MDNS_RESP, &resp);
}
}
static void handle_mdns_record(struct mg_connection *c) {
struct mg_dns_header *h = (struct mg_dns_header *) c->recv.buf;
if (c->recv.len <= 12) return;
if ((h->flags & mg_htons(0xF800)) == 0) {
// flags -> !resp, opcode=0 => query; ignore other opcodes
handle_mdns_query(c);
} else if ((h->flags & mg_htons(0xF800)) == mg_htons(0x8000)) {
// flags -> resp, opcode=0 => response; ignore other opcodes
handle_mdns_response(c);
}
}
static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_READ) {
handle_mdns_record(c);
mg_iobuf_del(&c->recv, 0, c->recv.len);
}
(void) ev_data;
}
void mg_multicast_add(struct mg_connection *c, char *ip);
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
void *fn_data) {
struct mg_connection *c =
mg_listen(mgr, "udp://224.0.0.251:5353", fn, fn_data);
if (c == NULL) return NULL;
c->pfn = mdns_cb, c->pfn_data = fn_data;
mg_multicast_add(c, (char *) "224.0.0.251");
return c;
}
bool mg_mdns_query(struct mg_connection *c, const char *name,
unsigned int rtype) {
struct mg_str name_;
name_.buf = (char *) name, name_.len = strlen(name);
mg_multicast_restore(c, (uint8_t *) &c->loc);
(void) rtype;
return mg_dns_send(c, &name_, 0, false);
}
+37
View File
@@ -3,6 +3,12 @@
#include "net.h" #include "net.h"
#include "str.h" #include "str.h"
#define MG_DNS_RTYPE_A 1
#define MG_DNS_RTYPE_PTR 12
#define MG_DNS_RTYPE_TXT 16
#define MG_DNS_RTYPE_AAAA 28
#define MG_DNS_RTYPE_SRV 33
// Mongoose sends DNS queries that contain only one question: // Mongoose sends DNS queries that contain only one question:
// either A (IPv4) or AAAA (IPv6) address lookup. // either A (IPv4) or AAAA (IPv6) address lookup.
// Therefore, we expect zero or one answer. // Therefore, we expect zero or one answer.
@@ -31,8 +37,39 @@ struct mg_dns_rr {
uint16_t alen; // Address length uint16_t alen; // Address length
}; };
// DNS-SD response record
struct mg_dnssd_record {
struct mg_str srvcproto; // service.proto, service name
struct mg_str txt; // TXT record contents
uint16_t port; // SRV record port
};
// mDNS request and response data structs passed to event handlers
struct mg_mdns_req {
struct mg_dns_rr *rr;
struct mg_dnssd_record *r;
struct mg_str reqname; // requested name in RR
struct mg_str respname; // actual name to use in response
struct mg_addr *addr; // actual address to use in response
bool is_listing;
bool is_resp;
bool is_unicast;
};
struct mg_mdns_resp {
struct mg_dns_rr *rr;
// TODO(scaprile )struct mg_str srvcproto; struct mg_str txt; uint16_t port; ?
struct mg_str name;
struct mg_addr addr;
// TODO(scaprile); bool has_A; bool has_PTR; bool has_SRV; bool has_TXT; ?
};
void mg_resolve(struct mg_connection *, const char *url); void mg_resolve(struct mg_connection *, const char *url);
void mg_resolve_cancel(struct mg_connection *); void mg_resolve_cancel(struct mg_connection *);
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *); bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *); bool is_question, struct mg_dns_rr *);
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
void *fn_data);
bool mg_mdns_query(struct mg_connection *, const char *, unsigned int);
+17 -3
View File
@@ -13,12 +13,12 @@ static struct mg_tcpip_if *s_ifp;
static void mac_cb(uint32_t); static void mac_cb(uint32_t);
static bool cmsis_init(struct mg_tcpip_if *); static bool cmsis_init(struct mg_tcpip_if *);
static bool cmsis_up(struct mg_tcpip_if *); static bool cmsis_poll(struct mg_tcpip_if *, bool);
static size_t cmsis_tx(const void *, size_t, struct mg_tcpip_if *); static size_t cmsis_tx(const void *, size_t, struct mg_tcpip_if *);
static size_t cmsis_rx(void *, size_t, struct mg_tcpip_if *); static size_t cmsis_rx(void *, size_t, struct mg_tcpip_if *);
struct mg_tcpip_driver mg_tcpip_driver_cmsis = {cmsis_init, cmsis_tx, NULL, struct mg_tcpip_driver mg_tcpip_driver_cmsis = {cmsis_init, cmsis_tx, NULL,
cmsis_up}; cmsis_poll};
static bool cmsis_init(struct mg_tcpip_if *ifp) { static bool cmsis_init(struct mg_tcpip_if *ifp) {
ARM_ETH_MAC_ADDR addr; ARM_ETH_MAC_ADDR addr;
@@ -56,7 +56,21 @@ static size_t cmsis_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
return len; return len;
} }
static bool cmsis_up(struct mg_tcpip_if *ifp) { static void cmsis_update_hash_table(struct mg_tcpip_if *ifp) {
// TODO(): read database, rebuild hash table
ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0;
ARM_ETH_MAC_ADDR addr;
memcpy(&addr, mcast_addr, sizeof(addr));
mac->SetAddressFilter(&addr, 1);
(void) ifp;
}
static bool cmsis_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
cmsis_update_hash_table(ifp);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
ARM_DRIVER_ETH_PHY *phy = &Driver_ETH_PHY0; ARM_DRIVER_ETH_PHY *phy = &Driver_ETH_PHY0;
ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0;
bool up = (phy->GetLinkState() == ARM_ETH_LINK_UP) ? 1 : 0; // link state bool up = (phy->GetLinkState() == ARM_ETH_LINK_UP) ? 1 : 0; // link state
+1415
View File
File diff suppressed because it is too large. Load diff
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#if MG_ENABLE_TCPIP && \
((defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW) || \
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO))
struct mg_tcpip_spi_ {
void *spi; // Opaque SPI bus descriptor
void (*begin)(void *); // SPI begin: slave select low
void (*end)(void *); // SPI end: slave select high
void (*txn)(void *, uint8_t *, uint8_t *,
size_t len); // SPI transaction: write-read len bytes
};
struct mg_tcpip_driver_cyw_firmware {
const uint8_t *code_addr;
size_t code_len;
const uint8_t *nvram_addr;
size_t nvram_len;
const uint8_t *clm_addr;
size_t clm_len;
};
struct mg_tcpip_driver_cyw_data {
struct mg_wifi_data wifi;
void *bus;
struct mg_tcpip_driver_cyw_firmware *fw;
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_cyw_data driver_data_; \
static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_cyw; \
mif_.driver_data = &driver_data_; \
mif_.recv_queue.size = 8192; \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
+43 -13
View File
@@ -1,6 +1,9 @@
#include "net_builtin.h" #include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct imxrt_enet { struct imxrt_enet {
volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3], volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3],
ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR, ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR,
@@ -26,12 +29,15 @@ struct imxrt_enet {
}; };
#undef ENET #undef ENET
#if defined(MG_DRIVER_IMXRT_RT11) && MG_DRIVER_IMXRT_RT11 #if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U) #define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U)
#define ETH_DESC_CNT 5 // Descriptors count #define ETH_DESC_CNT 5 // Descriptors count
#else #elif defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U) #define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U)
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
#else // MG_ENABLE_DRIVER_MCXE
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40079000U)
#define ETH_DESC_CNT 4 // Descriptor count
#endif #endif
#define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned #define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned
@@ -42,15 +48,12 @@ struct enet_desc {
uint32_t *buffer; // Data ptr uint32_t *buffer; // Data ptr
}; };
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
#define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
// Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2) // Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2)
// Buffers: 64-byte aligned (37.3.14) // Buffers: 64-byte aligned (37.3.14)
static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED; static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED; static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED; static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_64BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED; static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_64BYTE_ALIGNED;
static struct mg_tcpip_if *s_ifp; // MIP interface static struct mg_tcpip_if *s_ifp; // MIP interface
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) { static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
@@ -115,9 +118,14 @@ static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) {
ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed
ENET->TDAR = MG_BIT(24); // Transmit Descriptors have changed ENET->TDAR = MG_BIT(24); // Transmit Descriptors have changed
// ENET->OPD = 0x10014; // ENET->OPD = 0x10014;
ENET->IAUR = 0;
ENET->IALR = 0;
ENET->GAUR = 0;
ENET->GALR = 0;
return true; return true;
} }
// Transmit frame // Transmit frame
static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len, static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) { struct mg_tcpip_if *ifp) {
@@ -142,7 +150,24 @@ static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
return len; return len;
} }
static bool mg_tcpip_driver_imxrt_up(struct mg_tcpip_if *ifp) { static void mg_tcpip_driver_imxrt_update_hash_table(struct mg_tcpip_if *ifp) {
// TODO(): read database, rebuild hash table
// RM 37.3.4.3.2
uint32_t hash_table[2] = {0, 0};
// uint8_t hash64 = ((~mg_crc32(0, mcast_addr, 6)) >> 26) & 0x3f;
// hash_table[((uint8_t)hash64) >> 5] |= (1 << (hash64 & 0x1f));
hash_table[1] = MG_BIT(1); // above reduces to this for mDNS addr
ENET->GAUR = hash_table[1];
ENET->GALR = hash_table[0];
(void) ifp;
}
static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
mg_tcpip_driver_imxrt_update_hash_table(ifp);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_imxrt_data *d = struct mg_tcpip_driver_imxrt_data *d =
(struct mg_tcpip_driver_imxrt_data *) ifp->driver_data; (struct mg_tcpip_driver_imxrt_data *) ifp->driver_data;
uint8_t speed = MG_PHY_SPEED_10M; uint8_t speed = MG_PHY_SPEED_10M;
@@ -165,9 +190,14 @@ static bool mg_tcpip_driver_imxrt_up(struct mg_tcpip_if *ifp) {
return up; return up;
} }
void ENET_IRQHandler(void);
static uint32_t s_rxno; static uint32_t s_rxno;
#if !defined(MG_ENABLE_DRIVER_MCXE)
void ENET_IRQHandler(void);
void ENET_IRQHandler(void) { void ENET_IRQHandler(void) {
#else
void ENET_Receive_IRQHandler(void);
void ENET_Receive_IRQHandler(void) {
#endif
ENET->EIR = MG_BIT(25); // Ack IRQ ENET->EIR = MG_BIT(25); // Ack IRQ
// Frame received, loop // Frame received, loop
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
@@ -188,6 +218,6 @@ void ENET_IRQHandler(void) {
struct mg_tcpip_driver mg_tcpip_driver_imxrt = {mg_tcpip_driver_imxrt_init, struct mg_tcpip_driver mg_tcpip_driver_imxrt = {mg_tcpip_driver_imxrt_init,
mg_tcpip_driver_imxrt_tx, NULL, mg_tcpip_driver_imxrt_tx, NULL,
mg_tcpip_driver_imxrt_up}; mg_tcpip_driver_imxrt_poll};
#endif #endif
+4 -1
View File
@@ -1,6 +1,9 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct mg_tcpip_driver_imxrt_data { struct mg_tcpip_driver_imxrt_data {
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
+91
View File
@@ -0,0 +1,91 @@
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_NXP_WIFI) && \
MG_ENABLE_DRIVER_NXP_WIFI
#include "drivers/nxp_wifi.h"
bool __attribute__((weak)) netif_init(struct mg_tcpip_if *ifp) {
(void) ifp;
MG_ERROR(("Please link wifi/port/net contents"));
return false;
}
size_t __attribute__((weak))
netif_tx(const void *bfr, size_t len, struct mg_tcpip_if *ifp) {
(void) bfr;
(void) len;
netif_init(ifp);
return 0;
}
bool __attribute__((weak)) netif_connect(struct mg_wifi_data *wifi) {
(void) wifi;
return netif_init(NULL);
}
bool __attribute__((weak))
netif_poll(struct mg_tcpip_if *ifp, bool s1, mg_tcpip_event_handler_t evcb) {
(void) ifp;
(void) s1;
(void) evcb;
return false;
}
static struct mg_tcpip_if *s_ifp;
static uint32_t s_ip, s_mask;
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_nxp_wifi_data *) ifp->driver_data)->wifi;
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
MG_DEBUG(("Access Point started"));
s_ip = ifp->ip, ifp->ip = wifi->apip;
s_mask = ifp->mask, ifp->mask = wifi->apmask;
ifp->enable_dhcp_client = false;
ifp->enable_dhcp_server = true;
}
}
static bool nxp_wifi_init(struct mg_tcpip_if *ifp) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_nxp_wifi_data *) ifp->driver_data)->wifi;
s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
ifp->pfn = wifi_cb;
if (!netif_init(ifp)) return false;
if (wifi->apmode) {
return mg_wifi_ap_start(wifi);
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
return mg_wifi_connect(wifi);
}
return true;
}
bool nxp_wifi_poll(struct mg_tcpip_if *ifp, bool s1) {
return netif_poll(ifp, s1, mg_tcpip_call);
}
struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi = {nxp_wifi_init, netif_tx,
NULL, nxp_wifi_poll};
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
s_ifp->ip = s_ip;
s_ifp->mask = s_mask;
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
s_ifp->enable_dhcp_server = false;
return netif_connect(wifi);
}
bool __attribute__((weak)) mg_wifi_scan(void) {
return netif_init(NULL);
}
bool __attribute__((weak)) mg_wifi_disconnect(void) {
return netif_init(NULL);
}
bool __attribute__((weak)) mg_wifi_ap_start(struct mg_wifi_data *wifi) {
(void) wifi;
return netif_init(NULL);
}
bool __attribute__((weak)) mg_wifi_ap_stop(void) {
return netif_init(NULL);
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#if MG_ENABLE_TCPIP && \
defined(MG_ENABLE_DRIVER_NXP_WIFI) && MG_ENABLE_DRIVER_NXP_WIFI
struct mg_tcpip_driver_nxp_wifi_data {
struct mg_wifi_data wifi;
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_nxp_wifi_data driver_data_; \
static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_nxp_wifi; \
mif_.driver_data = &driver_data_; \
mif_.recv_queue.size = 8192; \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: nxp wifi, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
+54 -20
View File
@@ -1,13 +1,17 @@
#include "phy.h" #include "phy.h"
enum { // ID1 ID2 enum { // ID1 ID2
MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB MG_PHY_KSZ8x = 0x22, // 0022 156x - KSZ8081RNB, KSZ8091RNB
MG_PHY_DP83x = 0x2000, MG_PHY_DP83x = 0x2000,
MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I
MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I
MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720 MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720
MG_PHY_RTL8201 = 0x1C // 001c c816 - RTL8201 MG_PHY_RTL82x = 0x1c,
MG_PHY_RTL8201 = 0xc816, // 001c c816 - RTL8201F
MG_PHY_RTL8211 = 0xc916, // 001c c916 - RTL8211F
MG_PHY_ICS1894x = 0x15,
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
}; };
enum { enum {
@@ -22,8 +26,10 @@ enum {
MG_PHY_KSZ8x_REG_PC1R = 30, MG_PHY_KSZ8x_REG_PC1R = 30,
MG_PHY_KSZ8x_REG_PC2R = 31, MG_PHY_KSZ8x_REG_PC2R = 31,
MG_PHY_LAN87x_REG_SCSR = 31, MG_PHY_LAN87x_REG_SCSR = 31,
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7 MG_PHY_RTL82x_REG_PAGESEL = 31,
MG_PHY_RTL8201_REG_PAGESEL = 31 MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
MG_PHY_RTL8211_REG_PHYSR = 26, // in page a43
MG_PHY_ICS189432_REG_POLL = 17
}; };
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) { static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
@@ -43,12 +49,20 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
return "KSZ8x"; return "KSZ8x";
case MG_PHY_LAN87x: case MG_PHY_LAN87x:
return "LAN87x"; return "LAN87x";
case MG_PHY_RTL8201: case MG_PHY_RTL82x:
return "RTL8201"; switch (id2) {
case MG_PHY_RTL8201:
return "RTL8201";
case MG_PHY_RTL8211:
return "RTL8211";
default:
return "RTL82x";
}
case MG_PHY_ICS1894x:
return "ICS1894x";
default: default:
return "unknown"; return "unknown";
} }
(void) id2;
} }
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) { void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
@@ -77,20 +91,24 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
phy->write_reg(phy_addr, MG_PHY_DP83x_REG_RCSR, MG_BIT(7) | MG_BIT(0)); phy->write_reg(phy_addr, MG_PHY_DP83x_REG_RCSR, MG_BIT(7) | MG_BIT(0));
} else if (id1 == MG_PHY_KSZ8x) { } else if (id1 == MG_PHY_KSZ8x) {
// Disable isolation (override hw, it doesn't make sense at this point) // Disable isolation (override hw, it doesn't make sense at this point)
phy->write_reg( // #2848, some NXP boards set ISO, even though // - #2848, some NXP boards set ISO, even though docs say they don't
phy_addr, MG_PHY_REG_BCR, // docs say they don't phy->write_reg(phy_addr, MG_PHY_REG_BCR,
phy->read_reg(phy_addr, MG_PHY_REG_BCR) & (uint16_t) ~MG_BIT(10)); (uint16_t) (phy->read_reg(phy_addr, MG_PHY_REG_BCR) &
phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R, // now do clock stuff (uint16_t) ~MG_BIT(10)));
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); // now do clock stuff
phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R,
(uint16_t) (MG_BIT(15) | MG_BIT(8) | MG_BIT(7)));
} else if (id1 == MG_PHY_LAN87x) { } else if (id1 == MG_PHY_LAN87x) {
// nothing to do // nothing to do
} else if (id1 == MG_PHY_RTL8201) { } else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8201) {
// assume PHY has been hardware strapped properly // assume PHY has been hardware strapped properly
#if 0 #if 0
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 7); // Select page 7 phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 7); // Select page 7
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x1ffa); phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x1ffa);
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 0); // Select page 0 phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0); // Select page 0
#endif #endif
} else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8211) {
// assume PHY has been hardware strapped properly
} }
} }
@@ -130,10 +148,26 @@ bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR); uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR);
*full_duplex = scsr & MG_BIT(4); *full_duplex = scsr & MG_BIT(4);
*speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; *speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} else if (id1 == MG_PHY_RTL8201) { } else if (id1 == MG_PHY_RTL82x) {
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR); uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
*full_duplex = bcr & MG_BIT(8); if (id2 == MG_PHY_RTL8211) {
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; uint16_t physr;
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0xa43);
physr = phy->read_reg(phy_addr, MG_PHY_RTL8211_REG_PHYSR);
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0);
*full_duplex = physr & MG_BIT(3);
*speed = (physr & MG_BIT(5)) ? MG_PHY_SPEED_1000M
: (physr & MG_BIT(4)) ? MG_PHY_SPEED_100M
: MG_PHY_SPEED_10M;
} else {
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR);
*full_duplex = bcr & MG_BIT(8);
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
}
} else if (id1 == MG_PHY_ICS1894x) {
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
*full_duplex = poll_reg & MG_BIT(14);
*speed = (poll_reg & MG_BIT(15)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} }
} }
return up; return up;
+145 -20
View File
@@ -1,61 +1,186 @@
#if MG_ENABLE_TCPIP && MG_ARCH == MG_ARCH_PICOSDK && \ #if MG_ENABLE_TCPIP && MG_ARCH == MG_ARCH_PICOSDK && \
defined(MG_ENABLE_DRIVER_PICO_W) && MG_ENABLE_DRIVER_PICO_W defined(MG_ENABLE_DRIVER_PICO_W) && MG_ENABLE_DRIVER_PICO_W
#include "net_builtin.h"
#include "drivers/pico-w.h" #include "drivers/pico-w.h"
#include "net_builtin.h"
#include "pico/stdlib.h" #include "pico/stdlib.h"
static struct mg_tcpip_if *s_ifp; static struct mg_tcpip_if *s_ifp;
static uint32_t s_ip, s_mask;
static bool s_aplink = false, s_scanning = false;
static bool s_stalink = false, s_connecting = false;
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_pico_w_data *) ifp->driver_data)->wifi;
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
MG_DEBUG(("Access Point started"));
s_ip = ifp->ip, ifp->ip = wifi->apip;
s_mask = ifp->mask, ifp->mask = wifi->apmask;
ifp->enable_dhcp_client = false;
ifp->enable_dhcp_server = true;
}
}
static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) { static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_pico_w_data *d = struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
struct mg_wifi_data *wifi = &d->wifi;
s_ifp = ifp; s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
ifp->pfn = wifi_cb;
if (cyw43_arch_init() != 0) if (cyw43_arch_init() != 0)
return false; // initialize async_context and WiFi chip return false; // initialize async_context and WiFi chip
cyw43_arch_enable_sta_mode(); if (wifi->apmode && wifi->apssid != NULL) {
// start connecting to network if (!mg_wifi_ap_start(wifi)) return false;
if (cyw43_arch_wifi_connect_bssid_async(d->ssid, NULL, d->pass, cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC
CYW43_AUTH_WPA2_AES_PSK) != 0) } else {
return false; cyw43_arch_enable_sta_mode();
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
if (wifi->ssid != NULL) {
return mg_wifi_connect(wifi);
} else {
cyw43_arch_disable_sta_mode();
}
}
return true; return true;
} }
static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len, static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) { struct mg_tcpip_if *ifp) {
(void) ifp; struct mg_tcpip_driver_pico_w_data *d =
return cyw43_send_ethernet(&cyw43_state, CYW43_ITF_STA, len, buf, false) (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
? 0 return cyw43_send_ethernet(&cyw43_state,
: len; d->wifi.apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len,
buf, false) == 0
? len
: 0;
} }
static bool mg_tcpip_driver_pico_w_up(struct mg_tcpip_if *ifp) { static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
(void) ifp; cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA)
return (cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) == if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) {
CYW43_LINK_JOIN); MG_VERBOSE(("scan complete"));
s_scanning = 0;
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
}
if (ifp->update_mac_hash_table) {
// first call to _poll() is after _init(), so this is safe
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *) mcast_addr,
true);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
if (d->wifi.apmode) return s_aplink;
int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate));
if (sdkstate < 0 && s_connecting) {
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate);
s_connecting = false;
}
return s_stalink;
} }
struct mg_tcpip_driver mg_tcpip_driver_pico_w = { struct mg_tcpip_driver mg_tcpip_driver_pico_w = {
mg_tcpip_driver_pico_w_init, mg_tcpip_driver_pico_w_init,
mg_tcpip_driver_pico_w_tx, mg_tcpip_driver_pico_w_tx,
NULL, NULL,
mg_tcpip_driver_pico_w_up, mg_tcpip_driver_pico_w_poll,
}; };
// Called once per outstanding frame by async_context // Called once per outstanding frame by async_context
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len,
const uint8_t *buf) { const uint8_t *buf) {
if (itf != CYW43_ITF_STA) return;
mg_tcpip_qwrite((void *) buf, len, s_ifp); mg_tcpip_qwrite((void *) buf, len, s_ifp);
(void) cb_data; (void) cb_data;
} }
// Called by async_context // Called by async_context
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {} void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {} if (itf == CYW43_ITF_AP) {
s_aplink = true;
} else {
s_stalink = true;
s_connecting = false;
}
}
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
if (itf == CYW43_ITF_AP) {
s_aplink = false;
} else {
s_stalink = false;
// SDK calls this before we check status, don't clear s_connecting here
}
}
// there's life beyond lwIP // there's life beyond lwIP
void pbuf_copy_partial(void) {(void) 0;} void pbuf_copy_partial(void) {
(void) 0;
}
static int result_cb(void *arg, const cyw43_ev_scan_result_t *data) {
struct mg_wifi_scan_bss_data bss;
bss.SSID = mg_str_n(data->ssid, data->ssid_len);
bss.BSSID = (char *) data->bssid;
bss.RSSI = (int8_t) data->rssi;
bss.has_n = 0; // SDK ignores this
bss.channel = (uint8_t) data->channel;
bss.band = MG_WIFI_BAND_2G;
// SDK-internal dependency, 2.1.0
bss.security = data->auth_mode & MG_BIT(0) ? MG_WIFI_SECURITY_WEP
: MG_WIFI_SECURITY_OPEN;
if (data->auth_mode & MG_BIT(1)) bss.security |= MG_WIFI_SECURITY_WPA;
if (data->auth_mode & MG_BIT(2)) bss.security |= MG_WIFI_SECURITY_WPA2;
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf,
bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI,
bss.security));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
return 0;
}
bool mg_wifi_scan(void) {
cyw43_wifi_scan_options_t opts;
memset(&opts, 0, sizeof(opts));
bool res = (cyw43_wifi_scan(&cyw43_state, &opts, NULL, result_cb) == 0);
if (res) s_scanning = true;
return res;
}
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
s_ifp->ip = s_ip;
s_ifp->mask = s_mask;
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
s_ifp->enable_dhcp_server = false;
cyw43_arch_enable_sta_mode();
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
int res = cyw43_arch_wifi_connect_async(wifi->ssid, wifi->pass,
CYW43_AUTH_WPA2_AES_PSK);
MG_VERBOSE(("res: %d", res));
if (res == 0) s_connecting = true;
return (res == 0);
}
bool mg_wifi_disconnect(void) {
cyw43_arch_disable_sta_mode();
s_connecting = false;
return true;
}
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
cyw43_wifi_ap_set_channel(&cyw43_state, wifi->apchannel);
cyw43_arch_enable_ap_mode(wifi->apssid, wifi->appass,
CYW43_AUTH_WPA2_AES_PSK);
return true;
}
bool mg_wifi_ap_stop(void) {
cyw43_arch_disable_ap_mode();
return true;
}
#endif #endif
+2 -3
View File
@@ -8,15 +8,14 @@
#include "pico/unique_id.h" // keep this include #include "pico/unique_id.h" // keep this include
struct mg_tcpip_driver_pico_w_data { struct mg_tcpip_driver_pico_w_data {
char *ssid; struct mg_wifi_data wifi;
char *pass;
}; };
#define MG_TCPIP_DRIVER_INIT(mgr) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
do { \ do { \
static struct mg_tcpip_driver_pico_w_data driver_data_; \ static struct mg_tcpip_driver_pico_w_data driver_data_; \
static struct mg_tcpip_if mif_; \ static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CREDS(&driver_data_.ssid, &driver_data_.pass); \ MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \ mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \ mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \ mif_.gw = MG_TCPIP_GW; \
+3 -2
View File
@@ -96,7 +96,8 @@ static uint32_t fcs_do(uint32_t fcs, uint8_t x) {
return fcs; return fcs;
} }
static bool mg_ppp_up(struct mg_tcpip_if *ifp) { static bool mg_ppp_poll(struct mg_tcpip_if *ifp, bool s1) {
(void) s1;
return ifp->driver_data != NULL; return ifp->driver_data != NULL;
} }
@@ -322,6 +323,6 @@ static size_t mg_ppp_rx(void *ethbuf, size_t ethlen, struct mg_tcpip_if *ifp) {
} }
struct mg_tcpip_driver mg_tcpip_driver_ppp = {mg_ppp_init, mg_ppp_tx, mg_ppp_rx, struct mg_tcpip_driver mg_tcpip_driver_ppp = {mg_ppp_init, mg_ppp_tx, mg_ppp_rx,
mg_ppp_up}; mg_ppp_poll};
#endif #endif
+37 -24
View File
@@ -1,6 +1,8 @@
#include "net_builtin.h" #include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_RA6) && MG_ENABLE_DRIVER_RA6) || \
(defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8)
struct ra_etherc { struct ra_etherc {
volatile uint32_t ECMR, RESERVED, RFLR, RESERVED1, ECSR, RESERVED2, ECSIPR, volatile uint32_t ECMR, RESERVED, RFLR, RESERVED1, ECSR, RESERVED2, ECSIPR,
RESERVED3, PIR, RESERVED4, PSR, RESERVED5[5], RDMLR, RESERVED6[3], IPGR, RESERVED3, PIR, RESERVED4, PSR, RESERVED5[5], RDMLR, RESERVED6[3], IPGR,
@@ -18,27 +20,30 @@ struct ra_edmac {
}; };
#undef ETHERC #undef ETHERC
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40114100U)
#undef EDMAC #undef EDMAC
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40114000U)
#undef RASYSC #undef RASYSC
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#undef ICU_IELSR #undef ICU_IELSR
#if defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40354100U)
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40354000U)
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#define ICU_IELSR ((uint32_t *) (uintptr_t) 0x4000C300U)
#else
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40114100U)
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40114000U)
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#define ICU_IELSR ((uint32_t *) (uintptr_t) 0x40006300U) #define ICU_IELSR ((uint32_t *) (uintptr_t) 0x40006300U)
#endif
#define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32 #define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
#define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
#define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
// Descriptors: 16-byte aligned // Descriptors: 16-byte aligned
// Buffers: 32-byte aligned (27.3.1) // Buffers: 32-byte aligned (27.3.1)
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED; static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED; static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED; static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_32BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED; static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_32BYTE_ALIGNED;
static struct mg_tcpip_if *s_ifp; // MIP interface static struct mg_tcpip_if *s_ifp; // MIP interface
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent // fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
@@ -101,9 +106,9 @@ static uint16_t smi_rd(uint16_t header) {
pir = 0; // read, mdc = 0 pir = 0; // read, mdc = 0
ETHERC->PIR = pir; ETHERC->PIR = pir;
raspin(s_smispin / 2); // 1/4 clock period, 300ns max access time raspin(s_smispin / 2); // 1/4 clock period, 300ns max access time
data |= (uint16_t)(ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio data |= (uint16_t) (ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio
raspin(s_smispin / 2); // 1/4 clock period raspin(s_smispin / 2); // 1/4 clock period
pir |= MG_BIT(0); // mdc = 1 pir |= MG_BIT(0); // mdc = 1
ETHERC->PIR = pir; ETHERC->PIR = pir;
raspin(s_smispin); raspin(s_smispin);
} }
@@ -111,11 +116,14 @@ static uint16_t smi_rd(uint16_t header) {
} }
static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) { static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) {
return smi_rd((uint16_t)((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0))); return smi_rd(
(uint16_t) ((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0)));
} }
static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
smi_wr((uint16_t)((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)), val); smi_wr(
(uint16_t) ((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)),
val);
} }
// MDC clock is generated manually; as per 802.3, it must not exceed 2.5MHz // MDC clock is generated manually; as per 802.3, it must not exceed 2.5MHz
@@ -152,7 +160,7 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin)); MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
struct mg_phy phy = {raeth_read_phy, raeth_write_phy}; struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC);
// Select RMII mode, // Select RMII mode,
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
@@ -171,9 +179,9 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
EDMAC->FDR = 0x070f; // (27.2.11) EDMAC->FDR = 0x070f; // (27.2.11)
EDMAC->RMCR = MG_BIT(0); // (27.2.12) EDMAC->RMCR = MG_BIT(0); // (27.2.12)
ETHERC->ECMR |= MG_BIT(6) | MG_BIT(5); // TE RE ETHERC->ECMR |= MG_BIT(6) | MG_BIT(5); // TE RE
EDMAC->EESIPR = MG_BIT(18); // Enable Rx IRQ EDMAC->EESIPR = MG_BIT(18); // FR: Enable Rx (frame) IRQ
EDMAC->EDRRR = MG_BIT(0); // Receive Descriptors have changed EDMAC->EDRRR = MG_BIT(0); // Receive Descriptors have changed
EDMAC->EDTRR = MG_BIT(0); // Transmit Descriptors have changed EDMAC->EDTRR = MG_BIT(0); // Transmit Descriptors have changed
return true; return true;
} }
@@ -198,7 +206,12 @@ static size_t mg_tcpip_driver_ra_tx(const void *buf, size_t len,
return len; return len;
} }
static bool mg_tcpip_driver_ra_up(struct mg_tcpip_if *ifp) { static bool mg_tcpip_driver_ra_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
EDMAC->EESIPR = MG_BIT(18) | MG_BIT(7); // FR, RMAF: Frame and mcast IRQ
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_ra_data *d = struct mg_tcpip_driver_ra_data *d =
(struct mg_tcpip_driver_ra_data *) ifp->driver_data; (struct mg_tcpip_driver_ra_data *) ifp->driver_data;
uint8_t speed = MG_PHY_SPEED_10M; uint8_t speed = MG_PHY_SPEED_10M;
@@ -224,7 +237,7 @@ static uint32_t s_rxno;
void EDMAC_IRQHandler(void) { void EDMAC_IRQHandler(void) {
struct mg_tcpip_driver_ra_data *d = struct mg_tcpip_driver_ra_data *d =
(struct mg_tcpip_driver_ra_data *) s_ifp->driver_data; (struct mg_tcpip_driver_ra_data *) s_ifp->driver_data;
EDMAC->EESR = MG_BIT(18); // Ack IRQ in EDMAC 1st EDMAC->EESR = MG_BIT(18) | MG_BIT(7); // Ack IRQ in EDMAC 1st
ICU_IELSR[d->irqno] &= ~MG_BIT(16); // Ack IRQ in ICU last ICU_IELSR[d->irqno] &= ~MG_BIT(16); // Ack IRQ in ICU last
// Frame received, loop // Frame received, loop
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
@@ -245,6 +258,6 @@ void EDMAC_IRQHandler(void) {
struct mg_tcpip_driver mg_tcpip_driver_ra = {mg_tcpip_driver_ra_init, struct mg_tcpip_driver mg_tcpip_driver_ra = {mg_tcpip_driver_ra_init,
mg_tcpip_driver_ra_tx, NULL, mg_tcpip_driver_ra_tx, NULL,
mg_tcpip_driver_ra_up}; mg_tcpip_driver_ra_poll};
#endif #endif
+32 -1
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_RA6) && MG_ENABLE_DRIVER_RA6) || \
(defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8)
struct mg_tcpip_driver_ra_data { struct mg_tcpip_driver_ra_data {
// MDC clock "divider". MDC clock is software generated, // MDC clock "divider". MDC clock is software generated,
@@ -9,4 +11,33 @@ struct mg_tcpip_driver_ra_data {
uint8_t phy_addr; // PHY address uint8_t phy_addr; // PHY address
}; };
#ifndef MG_DRIVER_CLK_FREQ
#define MG_DRIVER_CLK_FREQ 100000000UL
#endif
#ifndef MG_DRIVER_IRQ_NO
#define MG_DRIVER_IRQ_NO 0
#endif
#ifndef MG_TCPIP_PHY_ADDR
#define MG_TCPIP_PHY_ADDR 0
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_ra_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.clock = MG_DRIVER_CLK_FREQ; \
driver_data_.irqno = MG_DRIVER_IRQ_NO; \
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_ra; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: ra, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif #endif
+24 -8
View File
@@ -26,17 +26,17 @@ struct ENET_Type {
CHANNEL_TCSR[4], CHANNEL_TCCR[4]; CHANNEL_TCSR[4], CHANNEL_TCCR[4];
}; };
#undef ENET
#define ENET ((struct ENET_Type *) 0x40138000) #define ENET ((struct ENET_Type *) 0x40138000)
#define ETH_PKT_SIZE 1536 // Max frame size #define ETH_PKT_SIZE 1536 // Max frame size
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 2 // Descriptor size (words) #define ETH_DS 2 // Descriptor size (words)
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U)))) static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
static uint8_t s_txno; // Current TX descriptor static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor static uint8_t s_rxno; // Current RX descriptor
@@ -89,6 +89,10 @@ static bool mg_tcpip_driver_rw612_init(struct mg_tcpip_if *ifp) {
ENET->PALR = ENET->PALR =
ifp->mac[0] << 24 | ifp->mac[1] << 16 | ifp->mac[2] << 8 | ifp->mac[3]; ifp->mac[0] << 24 | ifp->mac[1] << 16 | ifp->mac[2] << 8 | ifp->mac[3];
ENET->PAUR |= (ifp->mac[4] << 24 | ifp->mac[5] << 16); ENET->PAUR |= (ifp->mac[4] << 24 | ifp->mac[5] << 16);
ENET->IALR = 0;
ENET->IAUR = 0;
ENET->GALR = 0;
ENET->GAUR = 0;
ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8);
ENET->EIMR = MG_BIT(25); // Enable RX interrupt ENET->EIMR = MG_BIT(25); // Enable RX interrupt
ENET->ECR |= MG_BIT(8) | MG_BIT(1); // DBSWP, Enable ENET->ECR |= MG_BIT(8) | MG_BIT(1); // DBSWP, Enable
@@ -121,7 +125,19 @@ static size_t mg_tcpip_driver_rw612_tx(const void *buf, size_t len,
return len; return len;
} }
static bool mg_tcpip_driver_rw612_up(struct mg_tcpip_if *ifp) {
static void mg_tcpip_driver_rw612_update_hash_table(struct mg_tcpip_if *ifp) {
// TODO(): read database, rebuild hash table
ENET->GAUR = MG_BIT(1); // see imxrt, it reduces to this for mDNS
(void) ifp;
}
static bool mg_tcpip_driver_rw612_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
mg_tcpip_driver_rw612_update_hash_table(ifp);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_rw612_data *d = struct mg_tcpip_driver_rw612_data *d =
(struct mg_tcpip_driver_rw612_data *) ifp->driver_data; (struct mg_tcpip_driver_rw612_data *) ifp->driver_data;
uint8_t speed = MG_PHY_SPEED_10M; uint8_t speed = MG_PHY_SPEED_10M;
@@ -157,7 +173,7 @@ static bool mg_tcpip_driver_rw612_up(struct mg_tcpip_if *ifp) {
void ENET_IRQHandler(void) { void ENET_IRQHandler(void) {
if (ENET->EIR & MG_BIT(25)) { if (ENET->EIR & MG_BIT(25)) {
ENET->EIR = MG_BIT(25); // Ack RX ENET->EIR = MG_BIT(25); // Ack RX
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) != 0) break; // exit when done if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) != 0) break; // exit when done
// skip partial/errored frames // skip partial/errored frames
@@ -177,5 +193,5 @@ void ENET_IRQHandler(void) {
struct mg_tcpip_driver mg_tcpip_driver_rw612 = {mg_tcpip_driver_rw612_init, struct mg_tcpip_driver mg_tcpip_driver_rw612 = {mg_tcpip_driver_rw612_init,
mg_tcpip_driver_rw612_tx, NULL, mg_tcpip_driver_rw612_tx, NULL,
mg_tcpip_driver_rw612_up}; mg_tcpip_driver_rw612_poll};
#endif #endif
+120 -85
View File
@@ -1,8 +1,37 @@
#include "net_builtin.h" #include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
MG_ENABLE_DRIVER_SAME54
#include <sam.h> struct GMAC_REGS_ {
uint32_t GMAC_NCR, GMAC_NCFGR, GMAC_NSR, GMAC_UR, GMAC_DCFGR, GMAC_TSR,
GMAC_RBQB, GMAC_TBQB, GMAC_RSR, GMAC_ISR, GMAC_IER, GMAC_IDR, GMAC_IMR,
GMAC_MAN, GMAC_RPQ, GMAC_TPQ, GMAC_TPSF, GMAC_RPSF, GMAC_RJFML,
Reserved1[13], GMAC_HRB, GMAC_HRT, GMAC_SAB0, GMAC_SAT0, GMAC_SAB1,
GMAC_SAT1, GMAC_SAB2, GMAC_SAT2, GMAC_SAB3, GMAC_SAT3, GMAC_TIDM[4],
GMAC_WOL, GMAC_IPGS, GMAC_SVLAN, GMAC_TPFCP, GMAC_SAMB1, GMAC_SAMT1,
Reserved2[3], GMAC_NSC, GMAC_SCL, GMAC_SCH, GMAC_EFTSH, GMAC_EFRSH,
GMAC_PEFTSH, GMAC_PEFRSH, Reserved3[2], GMAC_OTLO, GMAC_OTHI, GMAC_FT,
GMAC_BCFT, GMAC_MFT, GMAC_PFT, GMAC_BFT64, GMAC_TBFT127, GMAC_TBFT255,
GMAC_TBFT511, GMAC_TBFT1023, GMAC_TBFT1518, GMAC_GTBFT1518, GMAC_TUR,
GMAC_SCF, GMAC_MCF, GMAC_EC, GMAC_LC, GMAC_DTF, GMAC_CSE, GMAC_ORLO,
GMAC_ORHI, GMAC_FR, GMAC_BCFR, GMAC_MFR, GMAC_PFR, GMAC_BFR64,
GMAC_TBFR127, GMAC_TBFR255, GMAC_TBFR511, GMAC_TBFR1023, GMAC_TBFR1518,
GMAC_TMXBFR, GMAC_UFR, GMAC_OFR, GMAC_JR, GMAC_FCSE, GMAC_LFFE, GMAC_RSE,
GMAC_AE, GMAC_RRE, GMAC_ROE, GMAC_IHCE, GMAC_TCE, GMAC_UCE, Reserved4[2],
GMAC_TISUBN, GMAC_TSH, Reserved5, GMAC_TSSSL, GMAC_TSSN, GMAC_TSL,
GMAC_TN, GMAC_TA, GMAC_TI, GMAC_EFTSL, GMAC_EFTN, GMAC_EFRSL, GMAC_EFRN,
GMAC_PEFTSL, GMAC_PEFTN, GMAC_PEFRSL, GMAC_PEFRN, Reserved6[28],
GMAC_RLPITR, GMAC_RLPITI, GMAC_TLPITR, GMAC_TLPITI;
};
struct GCLK_REGS_ {
uint32_t GCLK_CTRLA_RESERVED, GCLK_SYNCBUSY, Reserved2[6], GCLK_GENCTRL[12],
Reserved3[12], GCLK_PCHCTRL[48];
};
#define GMAC_REGS ((struct GMAC_REGS_ *) 0x42000800)
#define GCLK_REGS ((struct GCLK_REGS_ *) 0x40001c00)
#define ETH_PKT_SIZE 1536 // Max frame size #define ETH_PKT_SIZE 1536 // Max frame size
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
@@ -16,72 +45,67 @@ static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor static uint8_t s_rxno; // Current RX descriptor
static struct mg_tcpip_if *s_ifp; // MIP interface static struct mg_tcpip_if *s_ifp; // MIP interface
enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 };
#define MG_PHYREGBIT_BCR_DUPLEX_MODE MG_BIT(8)
#define MG_PHYREGBIT_BCR_SPEED MG_BIT(13)
#define MG_PHYREGBIT_BSR_LINK_STATUS MG_BIT(2)
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_REGS->GMAC_MAN = MG_BIT(30) | // Clause 22
GMAC_MAN_OP(2) | // Setting the read operation MG_BIT(29) | // Setting the read operation
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address MG_BIT(17) | ((addr & 0x1f) << 23) | // PHY address
GMAC_MAN_REGA(reg); // Setting the register ((reg & 0x1f) << 18); // Setting the register
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)) (void) 0; while (!(GMAC_REGS->GMAC_NSR & MG_BIT(2))) (void) 0;
return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value return GMAC_REGS->GMAC_MAN & 0xffff; // Getting the read value
} }
#if 0
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation GMAC_REGS->GMAC_MAN = MG_BIT(30) |
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address MG_BIT(28) | // Setting the write operation
GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register MG_BIT(17) | ((addr & 0x1f) << 23) | // PHY address
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete ((reg & 0x1f) << 18) | val; // Setting the register
while (!(GMAC_REGS->GMAC_NSR & MG_BIT(2)))
; // Waiting until the write op is complete
} }
#endif
int get_clock_rate(struct mg_tcpip_driver_same54_data *d) { uint32_t get_clock_rate(struct mg_tcpip_driver_same54_data *d) {
if (d && d->mdc_cr >= 0 && d->mdc_cr <= 5) { if (d && d->mdc_cr >= 0 && d->mdc_cr <= 5) {
return d->mdc_cr; return d->mdc_cr;
} else { } else {
// get MCLK from GCLK_GENERATOR 0 // get MCLK from GCLK_GENERATOR 0
uint32_t div = 512; uint32_t div = 512;
uint32_t mclk; uint32_t mclk;
if (!(GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_DIVSEL_Msk)) { if (!(GCLK_REGS->GCLK_GENCTRL[0] & MG_BIT(12))) {
div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16); div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16);
if (div == 0) div = 1; if (div == 0) div = 1;
} }
switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) { switch (GCLK_REGS->GCLK_GENCTRL[0] & 0xF) {
case GCLK_GENCTRL_SRC_XOSC0_Val: case 0: // GCLK_GENCTRL_SRC_XOSC0_Val
mclk = 32000000UL; /* 32MHz */ mclk = 32000000UL; // 32MHz
break; break;
case GCLK_GENCTRL_SRC_XOSC1_Val: case 1: // GCLK_GENCTRL_SRC_XOSC1_Val
mclk = 32000000UL; /* 32MHz */ mclk = 32000000UL; // 32MHz
break; break;
case GCLK_GENCTRL_SRC_OSCULP32K_Val: case 4: // GCLK_GENCTRL_SRC_OSCULP32K_Val
mclk = 32000UL; mclk = 32000UL; // 32Khz
break; break;
case GCLK_GENCTRL_SRC_XOSC32K_Val: case 5: // GCLK_GENCTRL_SRC_XOSC32K_Val
mclk = 32000UL; mclk = 32000UL; // 32Khz
break; break;
case GCLK_GENCTRL_SRC_DFLL_Val: case 6: // GCLK_GENCTRL_SRC_DFLL_Val
mclk = 48000000UL; /* 48MHz */ mclk = 48000000UL; // 48MHz
break; break;
case GCLK_GENCTRL_SRC_DPLL0_Val: case 7: // GCLK_GENCTRL_SRC_DPLL0_Val:
mclk = 200000000UL; /* 200MHz */ mclk = 200000000UL; // 200MHz
break; break;
case GCLK_GENCTRL_SRC_DPLL1_Val: case 8: // GCLK_GENCTRL_SRC_DPLL1_Val
mclk = 200000000UL; /* 200MHz */ mclk = 200000000UL; // 200MHz
break; break;
default: default:
mclk = 200000000UL; /* 200MHz */ mclk = 200000000UL; // 200MHz
} }
mclk /= div; mclk /= div;
uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values
uint8_t dividers[] = {8, 16, 32, 48, 64, 96}; // Respective CLK dividers uint8_t dividers[] = {8, 16, 32, 48, 64, 96}; // Respective CLK dividers
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (mclk / dividers[i] <= 2375000UL /* 2.5MHz - 5% */) { if (mclk / dividers[i] <= 2375000UL) { // 2.5MHz - 5%
return crs[i]; return crs[i];
} }
} }
@@ -95,11 +119,12 @@ static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
(struct mg_tcpip_driver_same54_data *) ifp->driver_data; (struct mg_tcpip_driver_same54_data *) ifp->driver_data;
s_ifp = ifp; s_ifp = ifp;
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC_Msk; GMAC_REGS->GMAC_NCFGR = get_clock_rate(d) << 18; // Set MDC divider
MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC_Msk; GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(get_clock_rate(d)); // Set MDC divider GMAC_REGS->GMAC_NCR |= MG_BIT(4); // Enable MDC & MDIO
GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; // Enable MDC & MDIO struct mg_phy phy = {eth_read_phy, eth_write_phy};
mg_phy_init(&phy, d->phy_addr, 0);
for (int i = 0; i < ETH_DESC_CNT; i++) { // Init TX descriptors for (int i = 0; i < ETH_DESC_CNT; i++) { // Init TX descriptors
s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer
@@ -107,38 +132,33 @@ static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
} }
s_txdesc[ETH_DESC_CNT - 1][1] |= MG_BIT(30); // Last tx descriptor - wrap s_txdesc[ETH_DESC_CNT - 1][1] |= MG_BIT(30); // Last tx descriptor - wrap
GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18) // DMA recv buf 1536 GMAC_REGS->GMAC_DCFGR = (0x18 << 16) | // DMA recv buf 1536
| GMAC_DCFGR_RXBMS(GMAC_DCFGR_RXBMS_FULL_Val) | (3 << 8) | // RXBMS
GMAC_DCFGR_TXPBMS(1); // See #2487 MG_BIT(10); // See #2487
for (int i = 0; i < ETH_DESC_CNT; i++) { // Init RX descriptors for (int i = 0; i < ETH_DESC_CNT; i++) { // Init RX descriptors
s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; // Address of the data buffer s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; // Address of the data buffer
s_rxdesc[i][1] = 0; // Clear status s_rxdesc[i][1] = 0; // Clear status
} }
s_rxdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(1); // Last rx descriptor - wrap s_rxdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(1); // Last rx descriptor - wrap
GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc; // about the descriptor addresses GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc; // about the descriptor addresses
GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc; // Let the controller know GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc; // Let the controller know
GMAC_REGS->SA[0].GMAC_SAB = GMAC_REGS->GMAC_SAB0 =
MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]); MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]);
GMAC_REGS->SA[0].GMAC_SAT = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]); GMAC_REGS->GMAC_SAT0 = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]);
GMAC_REGS->GMAC_UR &= ~GMAC_UR_MII_Msk; // Disable MII, use RMII GMAC_REGS->GMAC_UR &= ~MG_BIT(0); // Disable MII, use RMII
GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_MAXFS_Msk | GMAC_NCFGR_MTIHEN_Msk | GMAC_REGS->GMAC_NCFGR |= MG_BIT(8) | MG_BIT(6) | // MAXFX, MTIHEN
GMAC_NCFGR_EFRHD_Msk | GMAC_NCFGR_CAF_Msk; MG_BIT(25) | MG_BIT(4); // EFRHD, CAF
GMAC_REGS->GMAC_TSR = GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | GMAC_REGS->GMAC_TSR = 0x17f; // all transmit statuses
GMAC_TSR_TXCOMP_Msk | GMAC_TSR_TFC_Msk | GMAC_REGS->GMAC_RSR = 0xf; // all recv statuses
GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk;
GMAC_REGS->GMAC_RSR = GMAC_RSR_HNO_Msk | GMAC_RSR_RXOVR_Msk |
GMAC_RSR_REC_Msk | GMAC_RSR_BNA_Msk;
GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required
GMAC_REGS->GMAC_IER = GMAC_IER_HRESP_Msk | GMAC_IER_ROVR_Msk | GMAC_REGS->GMAC_IER = MG_BIT(11) | MG_BIT(10) | // HRESP, ROVR
GMAC_IER_TCOMP_Msk | GMAC_IER_TFC_Msk | MG_BIT(7) | MG_BIT(6) | // TCOMP, TFC
GMAC_IER_RLEX_Msk | GMAC_IER_TUR_Msk | MG_BIT(5) | MG_BIT(4) | // RLEX, TUR
GMAC_IER_RXUBR_Msk | GMAC_IER_RCOMP_Msk; MG_BIT(2) | MG_BIT(1); // RXUBR, RCOMP
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk | GMAC_NCR_RXEN_Msk; GMAC_REGS->GMAC_NCR |= MG_BIT(3) | MG_BIT(2); // TXEN, RXEN
NVIC_EnableIRQ(GMAC_IRQn);
return true; return true;
} }
@@ -159,25 +179,42 @@ static size_t mg_tcpip_driver_same54_tx(const void *buf, size_t len,
s_txdesc[s_txno][1] = status; s_txdesc[s_txno][1] = status;
if (++s_txno >= ETH_DESC_CNT) s_txno = 0; if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
} }
__DSB(); // Ensure descriptors have been written MG_DSB(); // Ensure descriptors have been written
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission GMAC_REGS->GMAC_NCR |= MG_BIT(9); // Enable transmission
return len; return len;
} }
static bool mg_tcpip_driver_same54_up(struct mg_tcpip_if *ifp) { static void mg_tcpip_driver_same54_update_hash_table(struct mg_tcpip_if *ifp) {
uint16_t bsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BSR); // TODO(): read database, rebuild hash table
bool up = bsr & MG_PHYREGBIT_BSR_LINK_STATUS ? 1 : 0; // Setting Hash Index for 01:00:5e:00:00:fb (multicast)
// 24.6.9 Hash addressing
// computed hash is 55, which means bit 23 (55 - 32) in
// HRT register must be set
GMAC_REGS->GMAC_HRT = MG_BIT(23);
GMAC_REGS->GMAC_NCFGR |= MG_BIT(6); // enable multicast hash filtering
(void) ifp;
}
// If PHY is ready, update NCFGR accordingly static bool mg_tcpip_driver_same54_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->state == MG_TCPIP_STATE_DOWN && up) { if (ifp->update_mac_hash_table) {
uint16_t bcr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BCR); mg_tcpip_driver_same54_update_hash_table(ifp);
bool fd = bcr & MG_PHYREGBIT_BCR_DUPLEX_MODE ? 1 : 0; ifp->update_mac_hash_table = false;
bool spd = bcr & MG_PHYREGBIT_BCR_SPEED ? 1 : 0;
GMAC_REGS->GMAC_NCFGR = (GMAC_REGS->GMAC_NCFGR &
~(GMAC_NCFGR_SPD_Msk | MG_PHYREGBIT_BCR_SPEED)) |
GMAC_NCFGR_SPD(spd) | GMAC_NCFGR_FD(fd);
} }
bool up = false;
if (s1) {
uint8_t speed = MG_PHY_SPEED_10M;
bool full_duplex = false;
struct mg_phy phy = {eth_read_phy, eth_write_phy};
up = mg_phy_up(&phy, 0, &full_duplex, &speed);
// If PHY is ready, update NCFGR accordingly
if (ifp->state == MG_TCPIP_STATE_DOWN && up) {
GMAC_REGS->GMAC_NCFGR =
(GMAC_REGS->GMAC_NCFGR & ~(MG_BIT(0) | MG_BIT(1))) | (speed & 1) |
(full_duplex << 1);
}
}
return up; return up;
} }
@@ -186,8 +223,8 @@ void GMAC_Handler(void) {
uint32_t isr = GMAC_REGS->GMAC_ISR; uint32_t isr = GMAC_REGS->GMAC_ISR;
uint32_t rsr = GMAC_REGS->GMAC_RSR; uint32_t rsr = GMAC_REGS->GMAC_RSR;
uint32_t tsr = GMAC_REGS->GMAC_TSR; uint32_t tsr = GMAC_REGS->GMAC_TSR;
if (isr & GMAC_ISR_RCOMP_Msk) { if (isr & MG_BIT(1)) {
if (rsr & GMAC_ISR_RCOMP_Msk) { if (rsr & MG_BIT(1)) {
for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { for (uint8_t i = 0; i < ETH_DESC_CNT; i++) {
if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break; if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break;
size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1); size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1);
@@ -198,9 +235,7 @@ void GMAC_Handler(void) {
} }
} }
if ((tsr & (GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | GMAC_TSR_TXCOMP_Msk | if (tsr != 0) {
GMAC_TSR_TFC_Msk | GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk)) != 0) {
// MG_INFO((" --> %#x %#x", s_txdesc[s_txno][1], tsr)); // MG_INFO((" --> %#x %#x", s_txdesc[s_txno][1], tsr));
if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31); if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31);
} }
@@ -211,5 +246,5 @@ void GMAC_Handler(void) {
struct mg_tcpip_driver mg_tcpip_driver_same54 = { struct mg_tcpip_driver mg_tcpip_driver_same54 = {
mg_tcpip_driver_same54_init, mg_tcpip_driver_same54_tx, NULL, mg_tcpip_driver_same54_init, mg_tcpip_driver_same54_tx, NULL,
mg_tcpip_driver_same54_up}; mg_tcpip_driver_same54_poll};
#endif #endif
+27 -5
View File
@@ -1,13 +1,35 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
MG_ENABLE_DRIVER_SAME54
struct mg_tcpip_driver_same54_data {
int mdc_cr;
};
#ifndef MG_DRIVER_MDC_CR #ifndef MG_DRIVER_MDC_CR
#define MG_DRIVER_MDC_CR 5 #define MG_DRIVER_MDC_CR 5
#endif #endif
#ifndef MG_DRIVER_PHY_ADDR
#define MG_DRIVER_PHY_ADDR 0
#endif
struct mg_tcpip_driver_same54_data {
int mdc_cr;
uint8_t phy_addr;
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_same54_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
driver_data_.phy_addr = MG_DRIVER_PHY_ADDR; \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_same54; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: same54, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif #endif
Loaded 100 of 4048 files, more files were not shown because too many files have changed in this diff. Show more