Compare commits

...
224 Commits
Author SHA1 Message Date
Sergio R. Caprile 32559f15ea fix Github editor line ending creativity 2023-10-12 10:56:38 -03:00
Sergio R. Caprile b10eef1e32 Update version in mongoose.h 2023-10-12 10:44:58 -03:00
Sergio R. Caprile 7c4911598c Update version.h 2023-10-12 10:27:55 -03:00
Sergio R. Caprile efacb20bdc Merge pull request #2423 from cesanta/same
rename same54
2023-10-11 17:36:09 -03:00
Sergio R. Caprile 2e6188205f rename same54 2023-10-11 16:58:21 -03:00
Sergio R. Caprile 83fec2cf45 cleanup 2023-10-11 16:39:24 -03:00
Sergio R. Caprile 9be36eb9cb Merge pull request #2422 from cesanta/tcp
Fix tcp example for 2-way TLS
2023-10-11 16:34:12 -03:00
Sergio R. Caprile a51802ecaf Fix tcp example for 2-way TLS 2023-10-11 16:25:24 -03:00
Sergio R. Caprile b1c220e610 Remove mg_mkpipe() leftovers 2023-10-10 18:16:02 -03:00
Sergey Lyubka 36f6b805e3 Merge pull request #2421 from cesanta/h723
Add h723 example
2023-10-10 19:19:51 +01:00
Sergey Lyubka 64efad9e46 Merge pull request #2419 from cesanta/rt1020
Add FreeRTOS example for RT1020
2023-10-10 07:57:05 +01:00
Sergio R. Caprile 8a8d5ce151 Add FreeRTOS example for RT1020 2023-10-09 17:03:58 -03:00
Sergey Lyubka 907417f9ec Merge pull request #2418 from cesanta/rt1020
Add TRNG
2023-10-09 17:24:39 +01:00
Sergio R. Caprile 0965177e72 Add TRNG 2023-10-09 13:03:52 -03:00
cpq 7d07ca8427 Add drivers 2023-10-09 09:36:43 +01:00
Sergey Lyubka d18b2b390a Merge pull request #2415 from cesanta/json
Add mg_json_next() for iterating objects/arrays
2023-10-09 07:55:44 +01:00
Sergey Lyubka fefe8b1c15 Merge pull request #2416 from cesanta/log
Add MG_ENABLE_CUSTOM_LOG
2023-10-09 07:55:31 +01:00
cpq ea2ff010a9 Add MG_ENABLE_CUSTOM_LOG 2023-10-08 17:09:14 +01:00
cpq e357cb3185 Bump up max DNS responses 10->15 2023-10-08 15:30:18 +01:00
cpq 293ee2162c Add mg_json_next() for iterating objects/arrays 2023-10-07 22:40:51 +01:00
cpq c29ee769bc Fix comment 2023-10-07 17:58:20 +01:00
Sergey Lyubka 82399f1561 Merge pull request #2414 from cesanta/rt1020
Rework  RT1020 driver
2023-10-07 11:21:29 +01:00
Sergio R. Caprile 9255ceaf8a Rework RT1020 driver
Add web server in example
Add to tests
2023-10-06 16:56:00 -03:00
cpq bb9c7c0eb3 Handle ECOS case in accept_conn() 2023-10-06 15:58:26 +01:00
Sergey Lyubka 8ec327f9c7 Merge pull request #2407 from cesanta/rt1020
Add RT1020-EVK baremetal example
2023-10-05 14:19:00 +01:00
Sergio R. Caprile c9b982eaff add update script to Makefile 2023-10-04 16:31:50 -03:00
Sergio R. Caprile 248e7b6e29 Add RT1020-EVK baremetal example 2023-10-04 15:18:57 -03:00
Sergey Lyubka cb1ae312a1 Merge pull request #2404 from cesanta/g031
Add nucleo-g031 baremetal example
2023-10-04 15:39:19 +01:00
cpq aec25cf547 Add h723 example 2023-10-04 11:11:56 +01:00
cpq 4db3fc2515 dd nucleo-g031 baremetal example 2023-10-03 13:55:47 +01:00
Sergey Lyubka 79d6017c56 Merge pull request #2402 from cesanta/bcast
send broadcasts in MIP
2023-10-03 13:53:58 +01:00
Sergio R. Caprile d4c122b17a send broadcasts in MIP 2023-10-02 13:37:27 -03:00
cpq 57fd93eeda Fix ring color 2023-10-01 23:20:42 +01:00
cpq 19cac05747 Enhance components 2023-10-01 23:08:10 +01:00
Sergey Lyubka 5ebede5096 Merge pull request #2395 from cesanta/scopeid
Fix #2192 - honor addr%scopeid ipv6 notation
2023-09-29 15:52:40 +01:00
cpq 46ecb07fc8 Fix #2192 - honor addr%scopeid ipv6 notation 2023-09-29 15:49:47 +01:00
cpq a628a05efb Restore pub. domain notice 2023-09-29 13:09:29 +01:00
cpq fc626bb57f Update pakced fs 2023-09-28 16:27:58 +01:00
cpq 1291839182 Update packed fs 2023-09-28 15:09:34 +01:00
Sergey Lyubka 736e7a2cf9 Merge pull request #2394 from cesanta/chunks
Get rid of MG_EV_HTTP_CHUNK
2023-09-26 20:45:40 +01:00
cpq 7884a2f3c7 Get rid of MG_EV_HTTP_CHUNK 2023-09-26 20:45:24 +01:00
Sergey Lyubka dde699ffda Merge pull request #2393 from cesanta/ota-api-refactoring
OTA API refactoring: renamed files and defines
2023-09-26 14:15:49 +01:00
robert fa54a22aed OTA API refactoring: renamed files and defines 2023-09-26 08:33:39 -04:00
cpq 822b0c011a Add sys_flash.c for common mg_flash_{load,save} 2023-09-25 07:55:35 +01:00
cpq a0f8a197c9 Split sys.h API over MG_SYS_* 2023-09-25 07:33:38 +01:00
Sergey Lyubka 7e75e51332 Merge pull request #2392 from cesanta/flash2
Commonise flash-based OTA. Add h7 support.
2023-09-25 05:21:52 +01:00
cpq b37efbe891 Commonise flash-based OTA. Add h7 support. 2023-09-24 21:55:49 +01:00
cpq 6e648c90b0 Added OTA to the feature list 2023-09-24 21:18:02 +01:00
cpq 377d6acc74 Fix leak in unit test 2023-09-22 08:12:09 +01:00
Sergey Lyubka f552d15fe4 Merge pull request #2390 from cesanta/tickets
Restore tickets support
2023-09-21 19:08:08 +01:00
cpq d1204e8a66 Better chunk length calculation 2023-09-21 19:04:32 +01:00
cpq 9ec48e41f7 Restore tickets support 2023-09-21 18:43:33 +01:00
Sergey Lyubka 9055a83b4f Merge pull request #2388 from cesanta/dns
dns.c slight refactor, no functional changes
2023-09-21 13:38:23 +01:00
cpq dd047b2613 dns.c slight refactor, no functional changes 2023-09-21 13:38:06 +01:00
Sergey Lyubka b7a32069b1 Merge pull request #2389 from cesanta/ipv6
Address discussions/2305 - bind to v6 only / v6 and v4
2023-09-21 13:37:29 +01:00
cpq 00d475bc7e Address https://github.com/cesanta/mongoose/discussions/2305 - bind to v6 only / v6 and v4 2023-09-21 12:35:47 +01:00
Sergio R. Caprile 33ab44430c Merge pull request #2386 from cesanta/timer
Revert to the old TLS API, but keep certs as mg_str for DER
2023-09-19 12:17:56 -03:00
Sergio R. Caprile b355da32b9 Add GA OpenSSL tests back 2023-09-19 12:08:02 -03:00
cpq 3f0366a514 Revert to the old TLS API, but keep certs as mg_str for DER 2023-09-19 11:15:23 +01:00
cpq 7ecbbc517d Using mg_bzero to cleanup memory in mg_close_conn() 2023-09-17 22:25:36 +01:00
cpq a04c94444e Add rt1020 baremetal sketch 2023-09-17 10:41:04 +01:00
Sergio R. Caprile 42b9ac1145 update 2023-09-12 18:30:23 -03:00
Sergio R. Caprile 7be4925c70 Merge pull request #2384 from cesanta/p_open
Do not use CLOEXEC on Windows
2023-09-12 18:28:39 -03:00
Sergio R. Caprile 7b19568683 Do not use CLOEXEC on Windows 2023-09-12 17:11:55 -03:00
Sergio R. Caprile 8f56779855 Merge pull request #2383 from cesanta/poll
Optimize test coverage
2023-09-12 16:41:17 -03:00
Sergio R. Caprile fdfad8462c Optimize test coverage 2023-09-12 16:28:10 -03:00
Sergio R. Caprile 3773ef45e7 Optimize test coverage 2023-09-12 16:22:54 -03:00
Sergio R. Caprile c0ca3cacb4 Fixing test.yml 2023-09-12 15:05:29 -03:00
Sergio R. Caprile bed0630698 Fixing test.yml 2023-09-12 09:13:38 -03:00
Sergey Lyubka 53baa18836 Merge pull request #2380 from cesanta/ip-fragmentation-2
IP fragmentation send path: added TCP/UDP packet splitting to fit within MTU
2023-09-12 12:51:04 +01:00
Sergey Lyubka 32a2144426 Merge pull request #2382 from cesanta/poll
increase test coverage
2023-09-12 12:50:50 +01:00
robert 264026acde added TCP/UDP packet splitting to fit within MTU 2023-09-12 07:05:13 -04:00
Sergio R. Caprile 43503ef73a increase test coverage 2023-09-11 17:46:25 -03:00
Sergio R. Caprile 7f52717e9d increase test coverage 2023-09-11 17:41:36 -03:00
Sergio R. Caprile bd59185ef1 Merge pull request #2381 from cesanta/tls
add host only validation
2023-09-11 16:38:18 -03:00
Sergio R. Caprile 310ffcd4eb add host only validation 2023-09-11 16:34:24 -03:00
cpq d23664a457 Move network code to net.* 2023-09-08 09:39:57 +01:00
Sergio R. Caprile a1e316ddcf make TCP example work with new TLS API 2023-09-06 18:50:33 -03:00
Sergio R. Caprile e328758fc7 Merge pull request #2379 from cesanta/tls
unifomize TLS examples, stage 1
2023-09-06 16:55:46 -03:00
Sergio R. Caprile dbf49255a3 fix 2023-09-06 16:19:21 -03:00
Sergio R. Caprile 1391bdcf8b remove certs.h 2023-09-06 15:49:02 -03:00
Sergio R. Caprile d8106a8ffe use packed ca.pem 2023-09-06 15:21:16 -03:00
Sergio R. Caprile ae55789c4b erase ca.pem 2023-09-06 15:21:16 -03:00
Sergio R. Caprile ec02ccf5b2 Merge pull request #2377 from cesanta/h5
uniformize examples
2023-09-05 13:43:39 -03:00
Sergio R. Caprile f970cd78d7 uniformize examples 2023-09-05 13:36:46 -03:00
Sergio R. Caprile 8140ea16a7 Merge pull request #2371 from cesanta/cloexec
Fix #2369 - set CLOEXEC on epoll and regular file fds
2023-09-05 10:15:58 -03:00
Sergey Lyubka 2883709756 Merge pull request #2370 from cesanta/ota
Add OTA to the device dashboard. Implement for H5
2023-09-05 13:28:22 +01:00
cpq ca4c2c6c41 Set CLOEXEC on epoll and regular file fds 2023-09-05 06:56:41 +01:00
Sergey Lyubka fbc56f4adf Merge pull request #2367 from cesanta/ip-fragmentation
closing connection if a fragmented packet is received
2023-09-05 06:34:29 +01:00
cpq 2f014237b2 Add OTA to the device dashboard. Implement for H5 2023-09-04 22:07:32 +01:00
robert f33e3a7752 closing connection if a fragmented packet is received 2023-08-30 10:30:51 -04:00
cpq d5b5cec797 Make fuzzer faster on large input/output 2023-08-26 00:52:24 +01:00
Sergey Lyubka f8e1f17651 Merge pull request #2366 from cesanta/h5
Add FreeRTOS example on H5
2023-08-25 21:21:41 +01:00
Sergio R. Caprile be58bfe22b Add FreeRTOS example on H5 2023-08-25 17:15:26 -03:00
Sergey Lyubka 995a63dc39 Merge pull request #2364 from cesanta/braces
Style: always braces around if + else
2023-08-25 15:00:52 +01:00
cpq e8d57ac4e1 Style: always braces around if + else 2023-08-25 14:46:38 +01:00
Sergio R. Caprile eab3a83548 Merge pull request #2362 from cesanta/h5
Update H5 HAL, enable RNG, work at 250MHz, add to tests
2023-08-24 13:35:37 -03:00
Sergio R. Caprile 3fb9e5fd56 Update H5 HAL, enable RNG, work at 250MHz, add to tests 2023-08-24 13:32:37 -03:00
Sergio R. Caprile 41448278cf Merge pull request #2360 from cesanta/h7
Fix sysinit in H7
2023-08-23 14:37:21 -03:00
cpq 48516b43c5 Use device 11 2023-08-23 00:38:57 +01:00
Sergio R. Caprile 80b7be0568 Fix sysinit in H7 2023-08-22 19:58:19 -03:00
Sergey Lyubka 4183552aee Merge pull request #2358 from cesanta/b64
Change base64 API
2023-08-22 14:43:33 +01:00
cpq 527e89754e Change base64 API 2023-08-22 12:11:13 +01:00
robertc2000 30e0f42c97 Merge pull request #2357 from cesanta/tcpip-conn-init
improved tcp connection initiation
2023-08-22 09:30:24 +03:00
Sergio R. Caprile 39b40daf5d cleanup 2023-08-21 19:34:04 -03:00
Sergio R. Caprile 94636f4d30 Merge pull request #2355 from cesanta/mqtt54
Add MQTT example and test for SAME54
2023-08-21 19:27:17 -03:00
Sergio R. Caprile fd53548c5e Add MQTT example and test for SAME54 2023-08-21 19:24:33 -03:00
Sergio R. Caprile 354ea30797 Add MQTT example and test for SAME54 2023-08-21 19:11:50 -03:00
Sergio R. Caprile 11303e0dc1 Merge pull request #2354 from cesanta/tst
Add MQTT test for MIP
2023-08-21 17:26:24 -03:00
Sergio R. Caprile b4c645f703 Add MQTT test for MIP 2023-08-21 17:22:42 -03:00
cpq 3256218fd2 Do uri len check after it is finalised 2023-08-21 17:16:48 +01:00
robert a4f14b0ddf improved tcp connection initiation 2023-08-21 10:22:53 -04:00
Sergio R. Caprile e7459d91f9 Merge pull request #2353 from cesanta/certs
Store certs in certs/. Add mg_unpacked()
2023-08-21 09:52:10 -03:00
cpq b32d1c15f0 Store certs in certs/. Add mg_unpacked() 2023-08-20 23:43:04 +01:00
Sergio R. Caprile 1e0d57a832 Merge pull request #2352 from cesanta/mip
Unify naming: all network stacks are in src/net_...
2023-08-18 16:40:57 -03:00
cpq f3617a1cf3 Add integer overflow protection 2023-08-18 20:33:57 +01:00
cpq 89a9a50b96 Unify naming: all network stacks are in src/net_... 2023-08-18 19:59:15 +01:00
cpq 69d2ba7316 Add example for nucleo-h563zi 2023-08-18 16:06:17 +01:00
robertc2000 3ea5f8dbde Merge pull request #2344 from cesanta/tcp-closure
improved tcp closure
2023-08-18 14:06:41 +03:00
Sergio R. Caprile d56152875d Merge pull request #2350 from cesanta/deprecate
deprecate mg_mkpipe()
2023-08-17 18:32:39 -03:00
Sergio R. Caprile 7459d30a28 deprecate mg_mkpipe() 2023-08-17 18:05:03 -03:00
Sergio R. Caprile 16bf9101aa Merge pull request #2349 from cesanta/isclosing
is_closing -> is_draining
2023-08-17 16:52:51 -03:00
Sergio R. Caprile 2b20af36a7 is_closing -> is_draining 2023-08-17 16:45:10 -03:00
robert f5e87cceec improved tcp closure 2023-08-17 10:34:31 -04:00
Sergey Lyubka 36fcb7ed21 Merge pull request #2347 from cesanta/cl
Fix #2322 - stricter Content-Length check, allow 1*DIGIT only
2023-08-17 14:58:01 +01:00
cpq 9fe7807b02 Fix #2322 - stricter Content-Length check, allow 1*DIGIT only 2023-08-17 12:55:08 +01:00
Sergey Lyubka 88e3017ee5 Merge pull request #2348 from cesanta/dns
Fix #2263 - allow multiple errors in DNS handler
2023-08-17 10:12:16 +01:00
cpq 17f3738192 Fix #2263 - allow multiple errors in DNS handler 2023-08-17 10:11:21 +01:00
Sergey Lyubka 6cfdc39005 Merge pull request #2346 from cesanta/regex
Fix #2345 - json parsing of arrays of objects
2023-08-16 22:10:13 +01:00
cpq 58886a9693 Fix #2345 - json parsing of arrays of objects 2023-08-16 22:09:45 +01:00
Sergey Lyubka 66e022c454 Merge pull request #2343 from cesanta/fuz
Add http serve to fuzzer
2023-08-16 20:46:27 +01:00
cpq ea3968601e Add http serve to fuzzer 2023-08-16 20:18:52 +01:00
Sergio R. Caprile 54be13d1d8 Merge pull request #2342 from cesanta/pio
Fix PIO assembly error
2023-08-14 16:17:37 -03:00
Sergio R. Caprile 22ea825d46 Fix PIO assembly error 2023-08-14 16:15:27 -03:00
Sergio R. Caprile 8c03aa2801 nit 2023-08-10 19:37:47 -03:00
Sergio R. Caprile 5bb952260a Merge pull request #2340 from cesanta/same54
SAME54 Ethernet driver
2023-08-10 19:26:50 -03:00
Sergio R. Caprile face6c44c6 SAME54 Ethernet driver
Add tls_builtin.c
2023-08-10 18:59:23 -03:00
Sergio R. Caprile 66c2bfe822 Merge pull request #2339 from cesanta/revert-2336-foo
Revert "Foo"
2023-08-10 18:16:38 -03:00
Sergio R. Caprile 3721bcc790 Revert "Foo" 2023-08-10 17:48:55 -03:00
Sergio R. Caprile cacab6fe4c Merge pull request #2338 from cesanta/keil
Keil
2023-08-09 17:17:57 -03:00
scaprile 6ad8674cd4 Add F4 Keil examples 2023-08-09 14:23:10 -03:00
novlean 847990ce49 Update README.md
Added URL to https://mongoose.ws/integration/
2023-08-09 17:50:57 +01:00
scaprile 1bfdc1f138 Add hw testing 2023-08-08 17:16:15 -03:00
Sergio R. Caprile 58367fe23e Merge pull request #2337 from cesanta/h7f
add H7 FreeRTOS example
2023-08-08 15:32:29 -03:00
Sergio R. Caprile a8712e2307 add H7 FreeRTOS example 2023-08-08 14:38:41 -03:00
robertc2000 8acfae1111 Merge pull request #2336 from cesanta/foo
Foo
2023-08-08 09:26:48 +03:00
cpq 70fc71c6f7 Changes 2023-08-07 06:18:49 -04:00
Sergio R. Caprile dd5118cab0 Merge pull request #2332 from cesanta/cube
update Cube test Makefile to support testing packaged examples
2023-08-04 17:11:22 -03:00
Sergio R. Caprile 2d75a6ccd4 update 2023-08-04 15:37:57 -03:00
Sergio R. Caprile e004ab1693 Merge pull request #2331 from cesanta/makefile
update Makefile
2023-08-04 14:45:56 -03:00
Sergio R. Caprile acddfc3bf4 update Makefile 2023-08-04 14:32:28 -03:00
cpq 519d4b0286 Changes 2023-08-04 13:53:01 +01:00
cpq 8005a5e687 Changes 2023-08-04 13:53:01 +01:00
cpq f5943fe591 Add tls_builtin.c 2023-08-04 13:53:01 +01:00
cpq cea7fcdb37 AVR build fixes 2023-08-04 13:52:59 +01:00
robert b5213c13dd SAME54 Ethernet driver 2023-08-04 13:48:55 +01:00
Sergio R. Caprile 3a06b4833c Merge pull request #2330 from cesanta/timeout
Timeout
2023-08-03 14:52:54 -03:00
Sergio R. Caprile 5cdf6c1d05 Add SYN timeout 2023-08-03 14:23:14 -03:00
Sergio R. Caprile 5754e5dd59 fix ARP timeout 2023-08-03 13:42:56 -03:00
Sergio R. Caprile e5ab1c454b Merge pull request #2329 from cesanta/arp
Implement ARP resolution for local LANs
2023-08-03 11:02:43 -03:00
cpq 697576b63c Implement ARP resolution for local LANs 2023-08-03 13:48:23 +01:00
Sergio R. Caprile 2db41aef09 Merge pull request #2328 from cesanta/ft
standardize example names
2023-08-02 16:20:05 -03:00
Sergio R. Caprile 7f4ad3cade standardize example names 2023-08-02 16:07:54 -03:00
Sergio R. Caprile 74c4c32082 Merge pull request #2327 from cesanta/rndis
standardize example names
2023-08-02 14:24:07 -03:00
Sergio R. Caprile 30d545443c standardize example names 2023-08-02 14:03:11 -03:00
Sergio R. Caprile dedba52315 Merge pull request #2325 from cesanta/fpu
FP unit in H743 is dp
2023-08-01 17:06:54 -03:00
Sergio R. Caprile 481f7b5cff FP unit in H743 is dp 2023-08-01 17:02:05 -03:00
Sergio R. Caprile 6ce4f4930c Merge pull request #2324 from cesanta/fb
standardize example names
2023-08-01 15:46:58 -03:00
Sergio R. Caprile e33a10db75 standardize example names 2023-08-01 15:24:28 -03:00
Sergio R. Caprile ef17055145 Merge pull request #2323 from cesanta/cube
standardize example names
2023-07-31 18:27:34 -03:00
Sergio R. Caprile 6a2fa10a4e standardize example names 2023-07-31 17:47:56 -03:00
Sergio R. Caprile 6b81a5846d Merge pull request #2320 from cesanta/2308collaterals
fix autogenerated
2023-07-28 17:47:49 -03:00
Sergio R. Caprile b54d086fde fix autogenerated 2023-07-28 17:06:58 -03:00
Sergio R. Caprile 5ee9d22263 momentarily disable MacOS OpenSSL tests 2023-07-26 15:53:59 -03:00
Sergio R. Caprile 7dcb097a5d momentarily disable OpenSSL tests 2023-07-26 15:49:03 -03:00
Sergio R. Caprile 29a30239ab momentarily disable OpenSSL tests 2023-07-26 15:33:30 -03:00
Sergio R. Caprile ed54b60ea3 update to new API 2023-07-25 18:41:41 -03:00
Sergio R. Caprile 199af33b30 update to new TLS API 2023-07-25 14:26:14 -03:00
Sergio R. Caprile adfa1d0e20 fix mongoose.h 2023-07-25 13:22:41 -03:00
Sergio R. Caprile ef25c42e86 fix unit tests for older compilers 2023-07-25 11:55:01 -03:00
Sergio R. Caprile 91a638156c Merge branch 'master' of https://github.com/cesanta/mongoose 2023-07-25 11:37:01 -03:00
Sergio R. Caprile 26ce666938 Merge branch 'master' of https://github.com/cesanta/mongoose 2023-07-25 11:35:29 -03:00
cpq 7548af895b H7 mbedtls build fixed 2023-07-25 15:34:22 +01:00
Sergio R. Caprile 9548437a9e update unit tests for new API 2023-07-25 11:27:01 -03:00
cpq 5e50b7104c Unit test fixed 2023-07-25 15:26:47 +01:00
cpq d824cf7dbd Add mbedtls to H7 baremetal 2023-07-25 15:03:01 +01:00
cpq 0613cc62f4 TLS API refactor 2023-07-25 13:07:28 +01:00
Sergey Lyubka d9cbcb5fa8 Merge pull request #2312 from cesanta/arduino
no Docker, in-place build for tests
2023-07-22 01:09:35 +01:00
Sergio R. Caprile a4f5355161 no Docker, in-place build for tests 2023-07-21 16:45:14 -03:00
Sergey Lyubka a24b6c1909 Merge pull request #2309 from cesanta/arduino
move Arduino tests to its dir
2023-07-21 14:33:00 +01:00
Sergio R. Caprile fd7dc72410 Merge pull request #2310 from cesanta/am
Add arduino/w5500-mqtt example
2023-07-21 10:27:20 -03:00
cpq e4f4dfab3b Add arduino/w5500-mqtt example 2023-07-21 13:54:41 +01:00
Sergio R. Caprile 66010be5a6 move Arduino tests to its dir 2023-07-20 20:22:06 -03:00
Sergio R. Caprile 852c42a8f3 static clue 2023-07-20 16:34:13 -03:00
Sergio R. Caprile 132725de7b Merge pull request #2308 from cesanta/nano
AVR build fixes
2023-07-20 14:12:49 -03:00
cpq 0a761c09e3 AVR build fixes 2023-07-20 16:07:53 +01:00
Sergey Lyubka 09ce6ae1c5 Merge pull request #2307 from cesanta/codeql
add CodeQL analysis
2023-07-20 14:37:18 +01:00
Sergio R. Caprile 85e60ed858 force run 2023-07-19 16:21:14 -03:00
Sergio R. Caprile 86fd18324b codeql 2023-07-19 16:14:44 -03:00
Sergio R. Caprile fdf82e5d6c codeql 2023-07-19 15:10:28 -03:00
Sergio R. Caprile eb0b1580d1 nits 2023-07-19 14:53:29 -03:00
Sergio R. Caprile 2d33c545b8 codeql 2023-07-19 14:53:29 -03:00
Sergio R. Caprile cdaf523aa8 codeql 2023-07-19 14:53:29 -03:00
Sergio R. Caprile 3195f2cec2 codeql 2023-07-19 14:53:29 -03:00
cpq ea89a4afab Revert "Integration page"
This reverts commit 3415b62d2d.
2023-07-19 18:50:27 +01:00
cpq 3415b62d2d Integration page 2023-07-19 16:25:14 +01:00
Sergey Lyubka ee80822564 Merge pull request #2306 from cesanta/nits
Nits
2023-07-19 06:00:32 +01:00
cpq 3c9e218d07 Nits 2023-07-19 05:08:28 +01:00
Sergio R. Caprile 387a602885 Merge pull request #2304 from cesanta/addressing
Addressing
2023-07-18 17:30:35 -03:00
Sergio R. Caprile ef0ff43975 static clue 2023-07-18 17:23:50 -03:00
Sergio R. Caprile ae37407369 static clue 2023-07-18 17:10:05 -03:00
cpq e1c91b5763 Merge branch 'master' of github.com:cesanta/mongoose 2023-07-18 17:47:02 +01:00
cpq c49b472f92 Ignore DHCP for static IP config 2023-07-18 17:46:52 +01:00
Sergey Lyubka 0a6b1b9418 Merge pull request #2297 from cesanta/2251-implement-tcp-retransmit-in-mip
implemented tcp retransmission
2023-07-16 04:53:06 +01:00
Sergio R. Caprile ac40673a9e test for retransmitted segment 2023-07-12 11:22:35 -04:00
cpq 818f99b286 Update examples to adopt to the new iface state 2023-07-12 14:09:30 +01:00
robert 320da5e84c implemented tcp retransmission 2023-07-11 06:20:47 -04:00
Sergey Lyubka 6957c379d5 Merge pull request #2294 from cesanta/hdr
Fix #2292 - fail on stray \r character in headers
2023-07-09 23:08:22 +01:00
cpq 88e880f107 Fix #2292 - fail on stray \r character in headers 2023-07-09 18:18:18 +01:00
cpq bf8c4dfc83 Merge branch 'master' of github.com:cesanta/mongoose 2023-07-07 08:44:33 +01:00
cpq 5dff282132 Fix #2293 - stricter header validity check 2023-07-07 08:44:25 +01:00
Sergio R. Caprile 1148ac0ae4 Merge pull request #2289 from cesanta/acl
update `mg_check_ip_acl`
2023-07-05 18:06:28 -03:00
Sergio R. Caprile 59c46fc594 update 2023-07-05 17:49:18 -03:00
cpq 03a94e3a6a Use \r\n for log messages, for terminal apps 2023-07-05 10:26:27 +01:00
1275 changed files with 43363 additions and 12386 deletions

No files matched your search

+35
View File
@@ -0,0 +1,35 @@
name: "CodeQL Scanning"
# https://github.com/github/codeql-action
on:
push:
paths:
- "Makefile"
- "mongoose.c"
- "mongoose.h"
- test/unit-test
- test/mip-test
env:
IPV6: 0
jobs:
CodeQL-Build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
permissions:
security-events: write
steps:
- uses: actions/checkout@v3
with: { fetch-depth: 2 }
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: cpp
- run: |
make test CC=gcc ASAN= ASAN_OPTIONS=
./test/setup_ga_network.sh && make mip_test CC=gcc ASAN= ASAN_OPTIONS=
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+135 -46
View File
@@ -15,11 +15,22 @@ jobs:
matrix: matrix:
cc: [gcc, clang, g++, clang++] cc: [gcc, clang, g++, clang++]
target: [test, mip_test] target: [test, mip_test]
ssl: [MBEDTLS, OPENSSL] ssl: ["", MBEDTLS, OPENSSL]
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} select: ["-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1"]
exclude:
- ssl: MBEDTLS
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
- ssl: MBEDTLS
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0"
- ssl: OPENSSL
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
- ssl: OPENSSL
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0"
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 }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
@@ -54,7 +65,21 @@ jobs:
run: make unamalgamated && make valgrind && make mg_prefix run: make unamalgamated && make valgrind && make mg_prefix
macos: macos:
runs-on: macos-latest runs-on: macos-latest
env: { HOMEBREW_NO_AUTO_UPDATE: 1 } strategy:
fail-fast: false
matrix:
ssl: ["", MBEDTLS, OPENSSL]
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
exclude:
- ssl: MBEDTLS
select: -DMG_ENABLE_POLL=0
- ssl: OPENSSL
select: -DMG_ENABLE_POLL=0
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env:
SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DNO_SNTP_CHECK
HOMEBREW_NO_AUTO_UPDATE: 1
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
@@ -62,27 +87,28 @@ jobs:
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: brew install jq mbedtls openssl run: brew install jq mbedtls openssl
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make test upload-coverage TFLAGS=-DNO_SNTP_CHECK SSL=OPENSSL ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*` run: make test ASAN_OPTIONS= MBEDTLS=`echo /usr/local/Cellar/mbedtls*/*` OPENSSL=`echo /usr/local/Cellar/openssl*/*`
- if: ${{ env.GO == 1 }}
run: make test SSL=MBEDTLS TFLAGS=-DNO_SNTP_CHECK ASAN_OPTIONS= MBEDTLS=`echo /usr/local/Cellar/mbedtls*/*`
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make mg_prefix run: make mg_prefix
windows: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [vc98, vc17, vc22, mingw, mingw++]
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
exclude:
- target: vc98
select: -DMG_ENABLE_POLL=1
name: windows ${{ matrix.target }} TFLAGS=${{ matrix.select }}
env:
TFLAGS: ${{ matrix.select }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make vc98 vc17 vc22 mingw mingw++ run: make ${{ matrix.target }}
arduino-xiao:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^examples/arduino|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }}
run: make arduino-xiao
arm: arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -99,8 +125,8 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- run: sudo apt -y install libmbedtls-dev libpcap-dev - run: sudo apt -y install libmbedtls-dev libpcap-dev
- run: make clean examples - run: make examples
- run: make clean test MG_ENABLE_POLL=1 - run: make clean
examples_win: examples_win:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
@@ -122,25 +148,26 @@ jobs:
- run: make examples_mac - run: make examples_mac
- run: make clean_examples_mac - run: make clean_examples_mac
test_f7: test_f7:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-f7" ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-f7.*-make-" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C examples/stm32/nucleo-f746zg-freertos 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}}
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C examples/stm32/nucleo-f746zg-freertos-tcp 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}}
- run: echo GO=0 >> $GITHUB_ENV ; if ./test/match_changed_files.sh '^src|examples/stm32/nucleo-f7.*-cube-'; then echo GO=1 >> $GITHUB_ENV ; fi - run: echo GO=0 >> $GITHUB_ENV ; if ./test/match_changed_files.sh '^src|examples/device-dashboard|examples/stm32/nucleo-f7.*-cube-'; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-baremetal VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5 run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-freertos 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
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-freertos-lwip 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
@@ -149,18 +176,18 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-f4" ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-f4.*-make-" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C examples/stm32/nucleo-f429zi-freertos 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}}
- run: echo GO=0 >> $GITHUB_ENV ; if ./test/match_changed_files.sh '^src|examples/stm32/nucleo-f4.*-cube-'; then echo GO=1 >> $GITHUB_ENV ; fi - run: echo GO=0 >> $GITHUB_ENV ; if ./test/match_changed_files.sh '^src|examples/device-dashboard|examples/stm32/nucleo-f4.*-cube-'; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-baremetal VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2 run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-freertos 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
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-freertos-lwip 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
@@ -169,16 +196,44 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: { fetch-depth: 3 } with: { fetch-depth: 3 }
- run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-h7" ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-h7.*-make-" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: echo GO=0 >> $GITHUB_ENV ; if ./test/match_changed_files.sh '^src|examples/stm32/nucleo-h7.*-cube-'; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-baremetal VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6 run: make -C examples/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: echo GO=0 >> $GITHUB_ENV ; if ./test/match_changed_files.sh '^src|examples/device-dashboard|examples/stm32/nucleo-h7.*-cube-'; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-freertos VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6 run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
- if: ${{ env.GO == 1 }}
run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
test_h5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with: { fetch-depth: 3 }
- run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/stm32/nucleo-h5.*-make-" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }}
run: sudo apt -y update; sudo apt -y install gcc-arm-none-eabi
- if: ${{ env.GO == 1 }}
run: make -C examples/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - if: ${{ env.GO == 1 }}
# WIP 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@v3
with: { fetch-depth: 3 }
- run: if ./test/match_changed_files.sh "^src|examples/nxp/rt1020.*-make-" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }}
run: sudo apt -y update; sudo apt -y install gcc-arm-none-eabi
- if: ${{ env.GO == 1 }}
run: make -C examples/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- if: ${{ env.GO == 1 }}
run: make -C examples/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_tm4c: test_tm4c:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -188,13 +243,24 @@ jobs:
- run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/ti/ek-tm4c" ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/ti/ek-tm4c" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
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: echo GO=0 > $GITHUB_ENV ; if ./test/match_changed_files.sh "^src|examples/ti/ek-tm4c1294xl-baremetal" ; then echo GO=1 > $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C examples/ti/ek-tm4c1294xl-baremetal test VCON_API_KEY=${{secrets.VCON_API_KEY}} run: make -C examples/ti/ek-tm4c1294xl-baremetal test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: echo GO=0 > $GITHUB_ENV ; if ./test/match_changed_files.sh "^src|examples/ti/ek-tm4c1294xl-freertos" ; then echo GO=1 > $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C examples/ti/ek-tm4c1294xl-freertos test VCON_API_KEY=${{secrets.VCON_API_KEY}} run: make -C examples/ti/ek-tm4c1294xl-freertos test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_same54:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh "^src|examples/device-dashboard|examples/microchip/same54-xpro" ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }}
run: sudo apt -y update; sudo apt -y install gcc-arm-none-eabi
- if: ${{ env.GO == 1 }}
run: make -C examples/microchip/same54-xpro/device-dashboard test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- if: ${{ env.GO == 1 }}
run: make -C examples/microchip/same54-xpro/mqtt-client test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_pico_w5500: test_pico_w5500:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -206,6 +272,21 @@ jobs:
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C examples/rp2040/pico-w5500 test VCON_API_KEY=${{secrets.VCON_API_KEY}} run: make -C examples/rp2040/pico-w5500 test VCON_API_KEY=${{secrets.VCON_API_KEY}}
arduino:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^examples/arduino|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }}
run: make -C examples/arduino arduino-xiao
# - if: ${{ env.GO == 1 }}
# run: make -C examples/arduino arduino-nano
- if: ${{ env.GO == 1 }}
run: make -C examples/arduino clean
matrix_examples: matrix_examples:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -215,14 +296,9 @@ jobs:
- path: esp32/device-dashboard - path: esp32/device-dashboard
- path: esp32/uart-bridge - path: esp32/uart-bridge
- path: esp8266/http-client-server - path: esp8266/http-client-server
- path: stm32/nucleo-f429zi-make-baremetal-builtin - path: microchip/same54-xpro/device-dashboard
- path: stm32/nucleo-f429zi-freertos - path: microchip/same54-xpro/mqtt-client
- path: stm32/nucleo-f429zi-rndis - path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
- path: stm32/nucleo-f746zg-make-baremetal-builtin
- path: stm32/nucleo-f746zg-freertos
- path: stm32/nucleo-f746zg-freertos-tcp
- path: stm32/nucleo-f746zg-rndis
- path: stm32/nucleo-h743zi-make-baremetal-builtin
- path: nxp/nxp-mimxrt1020-azurertos - 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
@@ -240,16 +316,29 @@ jobs:
- path: nxp/nxp-lpcxpresso54608-lwip-freertos - path: nxp/nxp-lpcxpresso54608-lwip-freertos
- path: nxp/nxp-lpcxpresso54618-lwip-freertos - path: nxp/nxp-lpcxpresso54618-lwip-freertos
- path: nxp/nxp-lpcxpresso54628-lwip-freertos - path: nxp/nxp-lpcxpresso54628-lwip-freertos
- path: nxp/rt1020-evk-make-baremetal-builtin
- path: nxp/rt1020-evk-make-freertos-builtin
- path: nxp/nxp-twrk65f180m-lwip-freertos - path: nxp/nxp-twrk65f180m-lwip-freertos
- path: nxp/nxp-twrkv58f220m-lwip-freertos - path: nxp/nxp-twrkv58f220m-lwip-freertos
- path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
- path: ti/ti-ek-tm4c1294xl-http-server
- path: ti/ek-tm4c1294xl-baremetal
- path: ti/ek-tm4c1294xl-freertos
- path: rp2040/pico-rmii - path: rp2040/pico-rmii
- path: rp2040/pico-rndis-dashboard - path: rp2040/pico-rndis-dashboard
- path: rp2040/pico-w - path: rp2040/pico-w
- path: rp2040/pico-w5500 - path: rp2040/pico-w5500
- path: stm32/nucleo-f429zi-make-baremetal-builtin
- path: stm32/nucleo-f429zi-make-freertos-builtin
- path: stm32/nucleo-f429zi-make-baremetal-builtin-rndis
- path: stm32/nucleo-f746zg-make-baremetal-builtin
- path: stm32/nucleo-f746zg-make-freertos-builtin
- path: stm32/nucleo-f746zg-make-freertos-tcp
- path: stm32/nucleo-f746zg-make-baremetal-builtin-rndis
- path: stm32/nucleo-g031-make-baremetal-builtin
- path: stm32/nucleo-h563zi-make-baremetal-builtin
- path: stm32/nucleo-h563zi-make-freertos-builtin
- path: stm32/nucleo-h743zi-make-baremetal-builtin
- path: stm32/nucleo-h743zi-make-freertos-builtin
- path: ti/ti-ek-tm4c1294xl-http-server
- path: ti/ek-tm4c1294xl-baremetal
- path: ti/ek-tm4c1294xl-freertos
name: ${{ matrix.example.path }} name: ${{ matrix.example.path }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
+13 -34
View File
@@ -1,13 +1,14 @@
SRCS = mongoose.c test/unit_test.c test/packed_fs.c SRCS = mongoose.c test/unit_test.c test/packed_fs.c
HDRS = $(wildcard src/*.h) $(wildcard src/tcpip/*.h) HDRS = $(wildcard src/*.h) $(wildcard src/drivers/*.h)
DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1 -DMG_ENABLE_ASSERT=1 DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1 -DMG_ENABLE_ASSERT=1
WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef
OPTS ?= -O3 -g3 OPTS ?= -O3 -g3
INCS ?= -Isrc -I. INCS ?= -Isrc -I.
SSL ?= SSL ?=
CWD ?= $(realpath $(CURDIR)) CWD ?= $(realpath $(CURDIR))
ENV ?= -e Tmp=. -e WINEDEBUG=-all ENV ?= -e Tmp=. -e WINEDEBUG=-all
DOCKER ?= docker run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD) DOCKER_BIN ?= docker
DOCKER ?= $(DOCKER_BIN) run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS) VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS)
IPV6 ?= 1 IPV6 ?= 1
ASAN ?= -fsanitize=address,undefined,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common ASAN ?= -fsanitize=address,undefined,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common
@@ -36,13 +37,13 @@ endif
ifeq "$(SSL)" "MBEDTLS" ifeq "$(SSL)" "MBEDTLS"
MBEDTLS ?= /usr/local MBEDTLS ?= /usr/local
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include CFLAGS += -DMG_TLS=MG_TLS_MBED -I$(MBEDTLS)/include -I/usr/include
LDFLAGS += -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509 LDFLAGS += -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
endif endif
ifeq "$(SSL)" "OPENSSL" ifeq "$(SSL)" "OPENSSL"
OPENSSL ?= /usr/local OPENSSL ?= /usr/local
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include CFLAGS += -DMG_TLS=MG_TLS_OPENSSL -I$(OPENSSL)/include
LDFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto LDFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto
endif endif
@@ -74,16 +75,9 @@ examples_win:
clean_examples_win: clean_examples_win:
$(foreach X, $(EXAMPLES_WIN), $(MAKE) -C $(X) clean &) $(foreach X, $(EXAMPLES_WIN), $(MAKE) -C $(X) clean &)
test/packed_fs.c: Makefile src/ssi.h test/fuzz.c test/data/a.txt test/packed_fs.c: Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/ca.pem
$(CC) $(CFLAGS) test/pack.c -o pack $(CC) $(CFLAGS) test/pack.c -o pack
$(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt > $@ $(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt test/data/ca.pem > $@
DIR ?= test/data
OUT ?= packed_fs.c
mkfs:
$(CC) $(CFLAGS) test/pack.c -o pack
$(RUN) ./pack -s $(DIR) `find $(DIR) -type f` > $(OUT)
# find $(DIR) -type f | sed -e s,^$(DIR),,g -e s,^/,,g
# Check that all external (exported) symbols have "mg_" prefix # Check that all external (exported) symbols have "mg_" prefix
mg_prefix: mongoose.c mongoose.h mg_prefix: mongoose.c mongoose.h
@@ -95,7 +89,7 @@ musl: WARN += -Wno-sign-conversion
musl: CC = $(DOCKER) mdashnet/cc1 gcc musl: CC = $(DOCKER) mdashnet/cc1 gcc
musl: RUN = $(DOCKER) mdashnet/cc1 musl: RUN = $(DOCKER) mdashnet/cc1
# Make sure we can build from an unamalgamated sources # Make sure we can build from unamalgamated sources.
unamalgamated: $(HDRS) Makefile test/packed_fs.c unamalgamated: $(HDRS) Makefile test/packed_fs.c
$(CC) src/*.c test/packed_fs.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test $(CC) src/*.c test/packed_fs.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
@@ -161,21 +155,6 @@ mingw: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe $(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
$(DOCKER) mdashnet/mingw wine64 $@.exe $(DOCKER) mdashnet/mingw wine64 $@.exe
arduino: ENV = -v $(CWD)/arduino:/root
arduino:
curl -sL http://downloads.arduino.cc/arduino-1.8.19-linux64.tar.xz | unxz | tar -xf -
mv arduino-* $@
$(DOCKER) mdashnet/cc2 ./arduino/arduino --pref "boardsmanager.additional.urls=https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json" --save-prefs
$(DOCKER) mdashnet/cc2 ./arduino/arduino --pref "compiler.warning_level=all" --save-prefs
$(DOCKER) mdashnet/cc2 ./arduino/arduino --install-boards Seeeduino:samd
arduino-xiao: ENV = -v $(CWD)/arduino:/root
arduino-xiao: arduino
rm -rf tmp; mkdir tmp
cp examples/arduino/w5500/w5500.ino tmp/tmp.ino
cp mongoose.c mongoose.h examples/arduino/w5500/mongoose_custom.h tmp/
$(DOCKER) mdashnet/cc2 ./arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 tmp/tmp.ino
mingw++: Makefile mongoose.h $(SRCS) mingw++: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe $(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
@@ -193,15 +172,15 @@ install: linux-libs
uninstall: uninstall:
rm -rf $(DESTDIR)$(LIBDIR)/libmongoose.a $(DESTDIR)$(LIBDIR)/libmongoose.so.$(VERSION) $(DESTDIR)$(INCLUDEDIR)/mongoose.h $(DESTDIR)$(LIBDIR)/libmongoose.so rm -rf $(DESTDIR)$(LIBDIR)/libmongoose.a $(DESTDIR)$(LIBDIR)/libmongoose.so.$(VERSION) $(DESTDIR)$(INCLUDEDIR)/mongoose.h $(DESTDIR)$(LIBDIR)/libmongoose.so
mongoose.c: Makefile $(wildcard src/*.c) $(wildcard src/tcpip/*.c) mongoose.c: Makefile $(wildcard src/*.c) $(wildcard src/drivers/*.c)
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/tcpip/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ (cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
mongoose.h: $(HDRS) Makefile mongoose.h: $(HDRS) Makefile
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_*.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/tcpip/tcpip.h src/tcpip/driver_*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: clean_examples clean_embedded clean: clean_examples clean_embedded
rm -rf $(PROG) *.exe *.o *.dSYM *_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack arduino tmp rm -rf $(PROG) *.exe *.o *.dSYM *_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack
#find examples -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C #find examples -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C
clean_embedded: clean_embedded:
+7 -6
View File
@@ -26,11 +26,12 @@ robust, and easy. Features include:
- Very easy to integrate: just copy `mongoose.c` and `mongoose.h` files to your source tree. See - Very easy to integrate: just copy `mongoose.c` and `mongoose.h` files to your source tree. See
[exact steps](https://mongoose.ws/documentation/#2-minute-integration-guide) [exact steps](https://mongoose.ws/documentation/#2-minute-integration-guide)
- Works with any network stack with socket API, like LwIP or FreeRTOS-Plus-TCP - Works with any network stack with socket API, like LwIP or FreeRTOS-Plus-TCP
- Provides a built-in TCP/IP stack with drivers for bare metal or RTOS systems - Built-in TCP/IP stack with drivers for bare metal or RTOS systems
- A complete Web device dashboard - Available drivers: STM32 F4, F7, H5, H7; NXP RT1020; TI TM4C; Microchip SAME54; Wiznet W5500
[bare metal example on Nucleo-F429ZI](examples/stm32/nucleo-f429zi-baremetal) - A complete Web device dashboard on bare metal
is only 6 files [Nucleo-F429ZI](examples/stm32/nucleo-f429zi-baremetal) is only 6 files
- For comparison, a CubeIDE generated HTTP example is 400+ files - For comparison, a CubeIDE generated HTTP example is 400+ files
- Built-in firmware updates for STM32H5, STM32H7, and more coming
- Detailed [user guide, API reference and tons of tutorials](https://mongoose.ws/documentation/) available - Detailed [user guide, API reference and tons of tutorials](https://mongoose.ws/documentation/) available
@@ -44,8 +45,8 @@ robust, and easy. Features include:
- See [Case Studies](https://mongoose.ws/case-studies/) from our respected - See [Case Studies](https://mongoose.ws/case-studies/) from our respected
customers like [Schneider Electric](https://mongoose.ws/case-studies/schneider-electric/) (industrial automation), [Broadcom](https://mongoose.ws/case-studies/broadcom/) (semiconductors), [Pilz](https://mongoose.ws/case-studies/pilz/) (industrial automation), and others customers like [Schneider Electric](https://mongoose.ws/case-studies/schneider-electric/) (industrial automation), [Broadcom](https://mongoose.ws/case-studies/broadcom/) (semiconductors), [Pilz](https://mongoose.ws/case-studies/pilz/) (industrial automation), and others
- See [Testimonials](https://mongoose.ws/testimonials/) from engineers that integrated Mongoose in their commercial products - See [Testimonials](https://mongoose.ws/testimonials/) from engineers that integrated Mongoose in their commercial products
- We provide [Evaluation and Commercial licensing](https://mongoose.ws/licensing/), [support](https://mongoose.ws/support/), consultancy and integration - We provide [Evaluation and Commercial licensing](https://mongoose.ws/licensing/), [support](https://mongoose.ws/support/), consultancy and [integration
assistance - don't hesitate to [contact us](https://mongoose.ws/contact/) services](https://mongoose.ws/integration/) - don't hesitate to [contact us](https://mongoose.ws/contact/)
# Security # Security
+28
View File
@@ -0,0 +1,28 @@
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 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
clean:
rm -rf arduino
cleanall: clean #otherwise some parts of xiao-board installation will fail as already installed
rm -rf ~/.arduino15 ~/.oracle_jre_usage
File renamed without changes.
File renamed without changes.
@@ -11,4 +11,5 @@
#define MG_ENABLE_SOCKET 0 #define MG_ENABLE_SOCKET 0
#define MG_ENABLE_TCPIP 1 #define MG_ENABLE_TCPIP 1
#define mkdir(a, b) (-1) #define mkdir(a, b) (-1)
#define MG_IO_SIZE 128
//#define MG_ENABLE_LOG 0 //#define MG_ENABLE_LOG 0
File renamed without changes.
@@ -0,0 +1,15 @@
#pragma once
#include "Arduino.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#define MG_ARCH MG_ARCH_CUSTOM
#define MG_ENABLE_SOCKET 0
#define MG_ENABLE_TCPIP 1
#define mkdir(a, b) (-1)
#define MG_IO_SIZE 512
//#define MG_ENABLE_LOG 0
+58
View File
@@ -0,0 +1,58 @@
#include "net.h"
#define MQTT_SERVER "mqtt://broker.hivemq.com:1883"
struct mg_connection *mqtt_connection;
const char *mqtt_subscribe_topic = "mg/rx";
const char *mqtt_publish_topic = "mg/tx";
struct mg_mgr mgr; // Mongoose event manager
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 5}}; // network interface
void mqtt_publish(const char *message) {
struct mg_mqtt_opts opts = {};
opts.topic = mg_str(mqtt_publish_topic);
opts.message = mg_str(message);
if (mqtt_connection) mg_mqtt_pub(mqtt_connection, &opts);
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_MQTT_OPEN) {
MG_INFO(("%lu CONNECTED to %s", c->id, MQTT_SERVER));
struct mg_mqtt_opts opts = {};
opts.topic = mg_str(mqtt_subscribe_topic);
mg_mqtt_sub(c, &opts);
MG_INFO(("%lu SUBSCRIBED to %s", c->id, mqtt_subscribe_topic));
} else if (ev == MG_EV_MQTT_MSG) {
// Received MQTT message
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
MG_INFO(("%lu RECEIVED %.*s <- %.*s", c->id, (int) mm->data.len,
mm->data.ptr, (int) mm->topic.len, mm->topic.ptr));
exec_command(mm->data.ptr, mm->data.len);
} else if (ev == MG_EV_CLOSE) {
MG_INFO(("%lu CLOSED", c->id));
mqtt_connection = NULL;
}
}
static void timer_fn(void *arg) {
struct mg_mgr *mgr = (struct mg_mgr *) arg;
struct mg_mqtt_opts opts;
memset(&opts, 0, sizeof(opts));
opts.clean = true;
if (mif.state == MG_TCPIP_STATE_READY && mqtt_connection == NULL) {
mqtt_connection = mg_mqtt_connect(mgr, MQTT_SERVER, &opts, fn, NULL);
}
// MG_INFO(("Eth: %d, MQTT: %p", mif.state, mqtt_connection));
}
void net_init(void) {
// Set Mongoose logging function to a serial print
mg_mgr_init(&mgr);
mif.driver = &mg_tcpip_driver_w5500;
mif.driver_data = &spi;
mg_tcpip_init(&mgr, &mif);
// Start a timer that keeps MQTT connection alive
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT, timer_fn, &mgr);
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "mongoose.h"
#ifdef __cplusplus
extern "C" {
#endif
extern struct mg_tcpip_spi spi;
extern struct mg_mgr mgr;
void mqtt_publish(const char *message);
void net_init(void);
void exec_command(const char *req, size_t req_len);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,51 @@
#include <SPI.h>
#include "net.h"
#define SS_PIN 17 // Slave select pin
struct mg_tcpip_spi spi = {
NULL, // SPI data
[](void *) { digitalWrite(SS_PIN, LOW); }, // Begin transaction
[](void *) { digitalWrite(SS_PIN, HIGH); }, // End transaction
[](void *, uint8_t c) { return SPI.transfer(c); }, // Execute transaction
};
void exec_command(const char *req, size_t req_len) {
char res[100];
if (req_len == 2 && strncmp(req, "on", req_len) == 0) {
digitalWrite(LED_BUILTIN, true);
snprintf(res, sizeof(res), "LED on");
} else if (req_len == 3 && strncmp(req, "off", req_len) == 0) {
digitalWrite(LED_BUILTIN, false);
snprintf(res, sizeof(res), "LED off");
} else {
snprintf(res, sizeof(res), "Unknown command: [%.*s]", (int) req_len, req);
}
Serial.println(res);
mqtt_publish(res);
}
static void process_input(char c) {
static char buf[100];
static size_t len = 0;
char response[100];
if (c != '\n' && c != '\0') buf[len++] = c; // Append to the buffer
if (len >= sizeof(buf)) len = 0; // On overflow, reset
if (c == '\n' && len > 0) {
exec_command(buf, len);
len = 0;
}
}
void setup() {
Serial.begin(115200);
SPI.begin();
pinMode(SS_PIN, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
mg_log_set_fn([](char ch, void *) { Serial.print(ch); }, NULL);
net_init();
}
void loop() {
if (Serial.available()) process_input(Serial.read());
mg_mgr_poll(&mgr, 1);
}
+10 -6
View File
@@ -1,12 +1,13 @@
PROG ?= ./example # Program we are building PROG ?= ./example # Program we are building
PACK ?= ./pack # Packing executable PACK ?= ./pack # Packing executable
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
GZIP ?= gzip # For compressing files in web_root/
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c net.c # Source code files SOURCES = main.c mongoose.c net.c packed_fs.c # Source code files
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += 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 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 PROG = example.exe # Use .exe suffix for the binary
@@ -14,6 +15,7 @@ ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To us
CC = gcc # Use MinGW gcc compiler CC = gcc # Use MinGW gcc compiler
CFLAGS += -lws2_32 # Link against Winsock library CFLAGS += -lws2_32 # Link against Winsock library
DELETE = cmd /C del /Q /F /S # Command prompt command to delete files DELETE = cmd /C del /Q /F /S # Command prompt command to delete files
GZIP = echo # No gzip on Windows
endif endif
# Default target. Build and run program # Default target. Build and run program
@@ -33,15 +35,17 @@ web_root/main.css: web_root/index.html $(wildcard web_root/*.js)
npx tailwindcss -o $@ --minify npx tailwindcss -o $@ --minify
# Generate packed filesystem for serving Web UI # Generate packed filesystem for serving Web UI
packed_fs.c: $(wildcard web_root/*) Makefile web_root/main.css web_root/bundle.js packed_fs.c: $(wildcard web_root/*) $(wildcard certs/*) Makefile web_root/main.css web_root/bundle.js
$(GZIP) web_root/*
$(CC) ../../test/pack.c -o $(PACK) $(CC) ../../test/pack.c -o $(PACK)
$(PACK) $(wildcard web_root/*) > $@ $(PACK) web_root/* certs/* > $@
$(GZIP) -d web_root/*
mbedtls: mbedtls:
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@ git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@
ifeq ($(TLS), mbedtls) ifeq ($(TLS), mbedtls)
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -Wno-conversion -Imbedtls/include CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
$(PROG): mbedtls $(PROG): mbedtls
endif endif
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
@@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE-----
MIIBCTCBsAIJAK9wbIDkHnAoMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAklFMB4X
DTIzMDEyOTIxMjEzOFoXDTMzMDEyNjIxMjEzOFowDTELMAkGA1UEBhMCSUUwWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAARzSQS5OHd17lUeNI+6kp9WYu0cxuEIi/JT
jphbCmdJD1cUvhmzM9/phvJT9ka10Z9toZhgnBq0o0xfTQ4jC1vwMAoGCCqGSM49
BAMCA0gAMEUCIQCe0T2E0GOiVe9KwvIEPeX1J1J0T7TNacgR0Ya33HV9VgIgNvdn
aEWiBp1xshs4iz6WbpxrS1IHucrqkZuJLfNZGZI=
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICBz3HOkQLPBDtdknqC7k1PNsWj6HfhyNB5MenfjmqiooAoGCCqGSM49
AwEHoUQDQgAEc0kEuTh3de5VHjSPupKfVmLtHMbhCIvyU46YWwpnSQ9XFL4ZszPf
6YbyU/ZGtdGfbaGYYJwatKNMX00OIwtb8A==
-----END EC PRIVATE KEY-----
-1
View File
@@ -17,7 +17,6 @@ int main(void) {
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
srand(time(NULL));
mg_log_set(MG_LL_DEBUG); // Set debug log level mg_log_set(MG_LL_DEBUG); // Set debug log level
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
+3 -2
View File
@@ -6,6 +6,7 @@
#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048 #define MBEDTLS_SSL_OUT_CONTENT_LEN 2048
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#define MBEDTLS_HAVE_TIME #define MBEDTLS_HAVE_TIME
#define MBEDTLS_SSL_SESSION_TICKETS
#define MBEDTLS_CIPHER_MODE_CBC #define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_ECP_DP_SECP192R1_ENABLED #define MBEDTLS_ECP_DP_SECP192R1_ENABLED
@@ -51,8 +52,9 @@
#define MBEDTLS_AES_FEWER_TABLES #define MBEDTLS_AES_FEWER_TABLES
#define MBEDTLS_PEM_PARSE_C #define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_BASE64_C #define MBEDTLS_BASE64_C
#define MBEDTLS_SSL_TICKET_C
// TLS 1.2 #define MBEDTLS_SSL_PROTO_TLS1_3
#define MBEDTLS_SSL_PROTO_TLS1_2 #define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_GCM_C #define MBEDTLS_GCM_C
@@ -60,4 +62,3 @@
#define MBEDTLS_ECP_C #define MBEDTLS_ECP_C
#define MBEDTLS_ECDSA_C #define MBEDTLS_ECDSA_C
#define MBEDTLS_ASN1_WRITE_C #define MBEDTLS_ASN1_WRITE_C
+95 -49
View File
@@ -28,45 +28,24 @@ static const char *s_json_header =
"Cache-Control: no-cache\r\n"; "Cache-Control: no-cache\r\n";
static uint64_t s_boot_timestamp = 0; // Updated by SNTP static uint64_t s_boot_timestamp = 0; // Updated by SNTP
// Certificate generation procedure:
// openssl ecparam -name prime256v1 -genkey -noout -out key.pem
// openssl req -new -key key.pem -x509 -nodes -days 3650 -out cert.pem
static const char *s_ssl_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBCTCBsAIJAK9wbIDkHnAoMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAklFMB4X\n"
"DTIzMDEyOTIxMjEzOFoXDTMzMDEyNjIxMjEzOFowDTELMAkGA1UEBhMCSUUwWTAT\n"
"BgcqhkjOPQIBBggqhkjOPQMBBwNCAARzSQS5OHd17lUeNI+6kp9WYu0cxuEIi/JT\n"
"jphbCmdJD1cUvhmzM9/phvJT9ka10Z9toZhgnBq0o0xfTQ4jC1vwMAoGCCqGSM49\n"
"BAMCA0gAMEUCIQCe0T2E0GOiVe9KwvIEPeX1J1J0T7TNacgR0Ya33HV9VgIgNvdn\n"
"aEWiBp1xshs4iz6WbpxrS1IHucrqkZuJLfNZGZI=\n"
"-----END CERTIFICATE-----\n";
static const char *s_ssl_key =
"-----BEGIN EC PRIVATE KEY-----\n"
"MHcCAQEEICBz3HOkQLPBDtdknqC7k1PNsWj6HfhyNB5MenfjmqiooAoGCCqGSM49\n"
"AwEHoUQDQgAEc0kEuTh3de5VHjSPupKfVmLtHMbhCIvyU46YWwpnSQ9XFL4ZszPf\n"
"6YbyU/ZGtdGfbaGYYJwatKNMX00OIwtb8A==\n"
"-----END EC PRIVATE KEY-----\n";
// This is for newlib and TLS (mbedTLS) // This is for newlib and TLS (mbedTLS)
uint64_t mg_now(void) { uint64_t mg_now(void) {
return mg_millis() + s_boot_timestamp; return mg_millis() + s_boot_timestamp;
} }
int ui_event_next(int no, struct ui_event *e) { int ui_event_next(int no, struct ui_event *e) {
if (no < 0 || no >= MAX_EVENTS_NO) if (no < 0 || no >= MAX_EVENTS_NO) return 0;
return 0;
srand(no); srand((unsigned) no);
e->type = (uint8_t) rand() % 4; e->type = (uint8_t) rand() % 4;
e->prio = (uint8_t) rand() % 3; e->prio = (uint8_t) rand() % 3;
e->timestamp = (unsigned long) (mg_now() - 86400 * 1000 /* one day back */ + e->timestamp =
no * 300 * 1000 /* 5 mins between alerts */ + (unsigned long) ((int64_t) mg_now() - 86400 * 1000 /* one day back */ +
1000 * (rand() % 300) /* randomize event time */) / no * 300 * 1000 /* 5 mins between alerts */ +
1000; 1000 * (rand() % 300) /* randomize event time */) /
1000UL;
mg_snprintf(e->text, MAX_EVENT_TEXT_SIZE,
"event#%d", no); mg_snprintf(e->text, MAX_EVENT_TEXT_SIZE, "event#%d", no);
return no + 1; return no + 1;
} }
@@ -104,7 +83,7 @@ static struct user *authenticate(struct mg_http_message *hm) {
char user[64], pass[64]; char user[64], pass[64];
struct user *u, *result = NULL; struct user *u, *result = NULL;
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass)); mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
MG_INFO(("user [%s] pass [%s]", user, pass)); MG_VERBOSE(("user [%s] pass [%s]", user, pass));
if (user[0] != '\0' && pass[0] != '\0') { if (user[0] != '\0' && pass[0] != '\0') {
// Both user and password is set, search by user/password // Both user and password is set, search by user/password
@@ -164,23 +143,24 @@ static void handle_stats_get(struct mg_connection *c) {
static size_t print_events(void (*out)(char, void *), void *ptr, va_list *ap) { static size_t print_events(void (*out)(char, void *), void *ptr, va_list *ap) {
size_t len = 0; size_t len = 0;
struct ui_event ev; struct ui_event ev;
int pageno = va_arg(*ap, unsigned); int pageno = va_arg(*ap, int);
int no = (pageno - 1) * EVENTS_PER_PAGE; int no = (pageno - 1) * EVENTS_PER_PAGE;
int end = no + EVENTS_PER_PAGE; int end = no + EVENTS_PER_PAGE;
while ((no = ui_event_next(no, &ev)) != 0 && no <= end) { while ((no = ui_event_next(no, &ev)) != 0 && no <= end) {
len += mg_xprintf(out, ptr, "%s{%m:%lu,%m:%d,%m:%d,%m:%m}", // len += mg_xprintf(out, ptr, "%s{%m:%lu,%m:%d,%m:%d,%m:%m}", //
len == 0 ? "" : ",", // len == 0 ? "" : ",", //
MG_ESC("time"), ev.timestamp, // MG_ESC("time"), ev.timestamp, //
MG_ESC("type"), ev.type, // MG_ESC("type"), ev.type, //
MG_ESC("prio"), ev.prio, // MG_ESC("prio"), ev.prio, //
MG_ESC("text"), MG_ESC(ev.text)); MG_ESC("text"), MG_ESC(ev.text));
} }
return len; return len;
} }
static void handle_events_get(struct mg_connection *c, struct mg_http_message *hm) { static void handle_events_get(struct mg_connection *c,
struct mg_http_message *hm) {
int pageno = mg_json_get_long(hm->body, "$.page", 1); int pageno = mg_json_get_long(hm->body, "$.page", 1);
mg_http_reply(c, 200, s_json_header, "{%m:[%M], %m:%d}", MG_ESC("arr"), mg_http_reply(c, 200, s_json_header, "{%m:[%M], %m:%d}", MG_ESC("arr"),
print_events, pageno, MG_ESC("totalCount"), MAX_EVENTS_NO); print_events, pageno, MG_ESC("totalCount"), MAX_EVENTS_NO);
@@ -218,11 +198,72 @@ static void handle_settings_get(struct mg_connection *c) {
MG_ESC("device_name"), MG_ESC(s_settings.device_name)); 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.ptr, 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");
if (data.len == 0) {
// Successful mg_ota_end() called, schedule device reboot
mg_timer_add(c->mgr, 500, 0, (void (*)(void *)) mg_device_reset, NULL);
}
}
}
static void handle_firmware_commit(struct mg_connection *c) {
mg_http_reply(c, 200, s_json_header, "%s\n",
mg_ota_commit() ? "true" : "false");
}
static void handle_firmware_rollback(struct mg_connection *c) {
mg_http_reply(c, 200, s_json_header, "%s\n",
mg_ota_rollback() ? "true" : "false");
}
static size_t print_status(void (*out)(char, void *), void *ptr, va_list *ap) {
int fw = va_arg(*ap, int);
return mg_xprintf(out, ptr, "{%m:%d,%m:%c%lx%c,%m:%u,%m:%u}",
MG_ESC("status"), mg_ota_status(fw), MG_ESC("crc32"), '"',
mg_ota_crc32(fw), '"', MG_ESC("size"), mg_ota_size(fw),
MG_ESC("timestamp"), mg_ota_timestamp(fw));
}
static void handle_firmware_status(struct mg_connection *c) {
mg_http_reply(c, 200, s_json_header, "[%M,%M]\n", print_status,
MG_FIRMWARE_CURRENT, print_status, MG_FIRMWARE_PREVIOUS);
}
static void handle_device_reset(struct mg_connection *c) {
mg_http_reply(c, 200, s_json_header, "true\n");
mg_timer_add(c->mgr, 500, 0, (void (*)(void *)) mg_device_reset, NULL);
}
// HTTP request handler function // HTTP request handler function
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_ACCEPT && fn_data != NULL) { if (ev == MG_EV_ACCEPT) {
struct mg_tls_opts opts = {.cert = s_ssl_cert, .certkey = s_ssl_key}; if (fn_data != NULL) { // TLS listener!
mg_tls_init(c, &opts); 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) { } else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct user *u = authenticate(hm); struct user *u = authenticate(hm);
@@ -243,14 +284,24 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
handle_settings_get(c); handle_settings_get(c);
} else if (mg_http_match_uri(hm, "/api/settings/set")) { } else if (mg_http_match_uri(hm, "/api/settings/set")) {
handle_settings_set(c, hm->body); handle_settings_set(c, hm->body);
} else if (mg_http_match_uri(hm, "/api/firmware/upload")) {
handle_firmware_upload(c, hm);
} else if (mg_http_match_uri(hm, "/api/firmware/commit")) {
handle_firmware_commit(c);
} else if (mg_http_match_uri(hm, "/api/firmware/rollback")) {
handle_firmware_rollback(c);
} else if (mg_http_match_uri(hm, "/api/firmware/status")) {
handle_firmware_status(c);
} else if (mg_http_match_uri(hm, "/api/device/reset")) {
handle_device_reset(c);
} else { } else {
struct mg_http_serve_opts opts; struct mg_http_serve_opts opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
#if MG_ENABLE_PACKED_FS #if MG_ARCH == MG_ARCH_UNIX || MG_ARCH == MG_ARCH_WIN32
opts.root_dir = "/web_root"; opts.root_dir = "web_root"; // On workstations, use filesystem
opts.fs = &mg_fs_packed;
#else #else
opts.root_dir = "web_root"; opts.root_dir = "/web_root"; // On embedded, use packed files
opts.fs = &mg_fs_packed;
#endif #endif
mg_http_serve_dir(c, ev_data, &opts); mg_http_serve_dir(c, ev_data, &opts);
} }
@@ -262,13 +313,8 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
void web_init(struct mg_mgr *mgr) { void web_init(struct mg_mgr *mgr) {
s_settings.device_name = strdup("My Device"); s_settings.device_name = strdup("My Device");
mg_http_listen(mgr, HTTP_URL, fn, NULL); mg_http_listen(mgr, HTTP_URL, fn, NULL);
#if MG_ENABLE_MBEDTLS || MG_ENABLE_OPENSSL mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
mg_http_listen(mgr, HTTPS_URL, fn, "");
#endif
// mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr);
mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT, mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT,
timer_sntp_fn, mgr); timer_sntp_fn, mgr);
} }
+1 -1
View File
@@ -9,7 +9,7 @@
#endif #endif
#if !defined(HTTPS_URL) #if !defined(HTTPS_URL)
#define HTTPS_URL "http://0.0.0.0:8443" #define HTTPS_URL "https://0.0.0.0:8443"
#endif #endif
#define MAX_DEVICE_NAME 40 #define MAX_DEVICE_NAME 40
File diff suppressed because it is too large. Load diff
+121 -27
View File
@@ -1,11 +1,16 @@
'use strict'; 'use strict';
import { h, render, useState, useEffect, useRef, html, Router } from './bundle.js'; 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 = { 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>`, 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>`, 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>`, 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>`,
settings: 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>`, 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> `, 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>`, 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>`, 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>`,
@@ -31,13 +36,18 @@ export const Icons = {
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>`, 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>`, 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>`, 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>` 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>`,
}; };
export const tipColors = { export const tipColors = {
green: 'bg-green-100 text-green-900', green: 'bg-green-100 text-green-900 ring-green-300',
yellow: 'bg-yellow-100 text-yellow-900', yellow: 'bg-yellow-100 text-yellow-900 ring-yellow-300',
red: 'bg-red-100 text-red-900', red: 'bg-red-100 text-red-900 ring-red-300',
}; };
export function Button({title, onclick, disabled, cls, icon, ref, colors, hovercolor, disabledcolor}) { export function Button({title, onclick, disabled, cls, icon, ref, colors, hovercolor, disabledcolor}) {
@@ -51,7 +61,7 @@ export function Button({title, onclick, disabled, cls, icon, ref, colors, hoverc
}; };
if (!colors) colors = 'bg-blue-600 hover:bg-blue-500 disabled:bg-blue-400'; if (!colors) colors = 'bg-blue-600 hover:bg-blue-500 disabled:bg-blue-400';
return html` return html`
<button type="button" class="inline-flex justify-center items-center gap-1 rounded px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm ${colors} ${cls}" <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} > ref=${ref} onclick=${cb} disabled=${disabled || spin} >
${title} ${title}
<${spin ? Icons.refresh : icon} class="w-4 ${spin ? 'animate-spin' : ''}" /> <${spin ? Icons.refresh : icon} class="w-4 ${spin ? 'animate-spin' : ''}" />
@@ -136,25 +146,26 @@ export function Login({loginFn, logoIcon, title, tipText}) {
}; };
export function Colored({icon, text, colors}) { export function Colored({icon, text, colors}) {
colors ||= 'bg-slate-100 text-slate-900';
return html` return html`
<span class="inline-flex items-center gap-1.5 py-0.5 px-2 rounded-full ${colors || 'bg-slate-100 text-slate-900'}"> <span class="inline-flex items-center gap-1.5 py-0.5">
${icon && html`<${icon} class="w-5 h-5" />`} ${icon && html`<${icon} class="w-5 h-5" />`}
<span class="inline-block text-xs font-medium">${text}<//> <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}) { export function Stat({title, text, tipText, tipIcon, tipColors, colors}) {
return html` return html`
<div class="flex flex-col bg-white border shadow-sm rounded-xl dark:bg-slate-900 dark:border-gray-800"> <div class="flex flex-col bg-white border shadow-sm rounded-xl dark:bg-slate-900 dark:border-gray-800">
<div class="p-4 md:p-5"> <div class="overflow-auto rounded-lg bg-white px-4 py-2 shadow">
<div class="flex items-center gap-x-2"> <div class="flex items-center gap-x-2">
<p class="text-xs uppercase tracking-wide text-gray-500"> ${title} </p> <p class="text-sm truncate text-gray-500 font-medium"> ${title} </p>
<//> <//>
<div class="mt-1 flex items-center gap-x-2"> <div class="mt-1 flex items-center gap-x-2">
<h3 class="text-xl sm:text-2xl font-medium text-gray-800 dark:text-gray-200"> <h3 class="text-xl truncate font-semibold tracking-tight ${colors || 'text-gray-800 dark:text-gray-200'}">
${text} ${text}
<//> <//>
<span class="flex items-center"> <span class="flex items-center ${tipText || 'hidden'}">
<${Colored} text=${tipText} icon=${tipIcon} colors=${tipColors} /> <${Colored} text=${tipText} icon=${tipIcon} colors=${tipColors} />
<//> <//>
<//> <//>
@@ -162,15 +173,27 @@ export function Stat({title, text, tipText, tipIcon, tipColors}) {
<//>`; <//>`;
}; };
export function TextValue({value, setfn, disabled, placeholder, type, addonRight, addonLeft, attr}) { export function TextValue({value, setfn, disabled, placeholder, type, addonRight, addonLeft, attr, min, max, step}) {
const f = type == 'number' ? x => setfn(parseInt(x)) : setfn; const [bg, setBg] = useState('bg-white');
useEffect(() => { checkval(value); }, []);
const checkval = function(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 oninput = ev => {
let v = ev.target.value;
if (type == 'number') v = parseInt(v);
setfn(v);
checkval(v);
};
return html` return html`
<div class="flex w-full items-center rounded border shadow-sm"> <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}</>` } ${ 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} <input type=${type || 'text'} disabled=${disabled}
oninput=${ev => f(ev.target.value)} ...${attr} oninput=${oninput} ...${attr}
class="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} value=${value} /> 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} value=${value} />
${ 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">${addonRight}</>` } ${ 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}<//>` }
<//>`; <//>`;
}; };
@@ -194,29 +217,29 @@ export function SwitchValue({value, setfn}) {
}; };
export function Setting(props) { export function Setting(props) {
let input = TextValue;
if (props.type == 'switch') input = SwitchValue;
if (props.type == 'select') input = SelectValue;
return html` return html`
<div class=${props.cls || 'grid grid-cols-2 gap-2 my-1'}> <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}<//> <label class="flex items-center text-sm text-gray-700 mr-2 font-medium">${props.title}<//>
<div class="flex items-center"> <div class="flex items-center">${h(input, props)}<//>
${props.type == 'switch' ? h(SwitchValue, props) :
props.type == 'select' ? h(SelectValue, props) :
h(TextValue, props) }
<//>
<//>`; <//>`;
}; };
export function Pagination({ totalItems, itemsPerPage, currentPage, setPageFn }) { export function Pagination({ totalItems, itemsPerPage, currentPage, setPageFn, colors }) {
const totalPages = Math.ceil(totalItems / itemsPerPage); const totalPages = Math.ceil(totalItems / itemsPerPage);
const maxPageRange = 2; const maxPageRange = 2;
const lessThanSymbol = "<"; const lessThanSymbol = "<";
const greaterThanSymbol = ">"; const greaterThanSymbol = ">";
const whiteSpace = " "; 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'; 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 }) => ( const PageItem = ({ page, isActive }) => (
html`<a html`<a
onClick=${() => setPageFn(page)} onClick=${() => setPageFn(page)}
class="${itemcls} ${isActive ? 'bg-blue-600 text-white' : 'cursor-pointer text-gray-700 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'}" class="${itemcls} ${isActive ? `${colors} text-white` : 'cursor-pointer text-gray-700 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'}"
> >
${page} ${page}
</a>` </a>`
@@ -253,3 +276,74 @@ export function Pagination({ totalItems, itemsPerPage, currentPage, setPageFn })
</div> </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
});
};
//setFailed(false);
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="py-2 text-sm text-slate-400 ${status || 'hidden'}">${status}<//>
<//>`;
};
+1 -1
View File
@@ -1 +1 @@
/*! 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-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.border-separate{border-collapse:initial}.border-spacing-0{--tw-border-spaciLine truncated /*! 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-4{right:1rem}.right-auto{right:auto}.top-0{top:0}.top-4{top:1rem}.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-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.border-separate{border-collapse:initialLine truncated
+105 -7
View File
@@ -2,7 +2,7 @@
'use strict'; 'use strict';
import { h, render, useState, useEffect, useRef, html, Router } from './bundle.js'; import { h, render, useState, useEffect, useRef, html, Router } from './bundle.js';
import { Icons, Login, Setting, Button, Stat, tipColors, Colored, Notification, Pagination } from './components.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>`; 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>`;
@@ -45,7 +45,8 @@ function Sidebar({url, show}) {
<//> <//>
<div class="flex flex-1 flex-col"> <div class="flex flex-1 flex-col">
<${NavLink} title="Dashboard" icon=${Icons.home} href="/" url=${url} /> <${NavLink} title="Dashboard" icon=${Icons.home} href="/" url=${url} />
<${NavLink} title="Settings" icon=${Icons.settings} href="/settings" 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} /> <${NavLink} title="Events" icon=${Icons.alert} href="/events" url=${url} />
<//> <//>
<//> <//>
@@ -143,13 +144,16 @@ function Chart({data}) {
<//>`; <//>`;
}; };
function DeveloperNote({text}) { function DeveloperNote({text, children}) {
return html` return html`
<div class="flex p-4 gap-2"> <div class="flex p-4 gap-2">
<${Icons.info} class="self-start basis-[30px] grow-0 shrink-0 text-green-600" /> <div class="text-sm text-slate-500">
<div class="text-sm"> <div class="flex items-center">
<div class="font-semibold mt-1">Developer Note<//> <${Icons.info} class="self-start basis-[30px] grow-0 shrink-0 text-green-600 mr-2" />
${text.split('.').map(v => html` <p class="my-2 text-slate-500">${v}<//>`)} <div class="font-semibold">Developer Note<//>
<//>
${(text || '').split('.').map(v => html` <p class="my-2 ">${v}<//>`)}
${children}
<//> <//>
<//>`; <//>`;
}; };
@@ -181,6 +185,99 @@ function Main({}) {
<//>`; <//>`;
}; };
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 onupload = function(ok, name, size) {
if (!ok) return false;
return new Promise(r => setTimeout(ev => { refresh(); r(); }, 3000));
};
const clean = info[0].valid && info[0].golden == 0;
return html`
<div class="m-4 gap-4 grid grid-cols-1 lg:grid-cols-2">
<${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=${clean} />
<${Button} title="Reboot device" onclick=${onreboot} icon=${Icons.refresh} clsx="absolute top-4 right-4" />
<${UploadFileButton}
title="Upload new firmware: choose .bin file:" onupload=${onupload}
url="api/firmware/upload" accept=".bin,.uf2" />
<//>
<//>
<${FirmwareStatus} title="Previous firmware image" info=${info[1]}>
<${Button} title="Rollback to this firmware" onclick=${onrollback}
icon=${Icons.backward} disabled=${info[1].valid == false} />
<//>
<div class="bg-white border shadow-lg">
<${DeveloperNote}>
<div class="my-2">
When a new firmware gets flashed, its status is marked as, "first_boot".
That is an unreliable (uncommitted) firmware. A user may choose
to revert back to the previous committed firmware on the subsequent
boots. Clicking on the "commit" button calls "mg_ota_commit()" function
which commits the firmware.
<//>
<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({}) { function Settings({}) {
const [settings, setSettings] = useState(null); const [settings, setSettings] = useState(null);
const [saveResult, setSaveResult] = useState(null); const [saveResult, setSaveResult] = useState(null);
@@ -256,6 +353,7 @@ const App = function({}) {
<${Router} onChange=${ev => setUrl(ev.url)} history=${History.createHashHistory()} > <${Router} onChange=${ev => setUrl(ev.url)} history=${History.createHashHistory()} >
<${Main} default=${true} /> <${Main} default=${true} />
<${Settings} path="settings" /> <${Settings} path="settings" />
<${FirmwareUpdate} path="update" />
<${Events} path="events" /> <${Events} path="events" />
<//> <//>
<//> <//>
+58 -696
View File
@@ -2,553 +2,61 @@
#include <string.h> #include <string.h>
#include <time.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 v1[] = { static const unsigned char v1[] = {
31, 139, 8, 8, 219, 27, 244, 98, 0, 3, 112, 114, // .......b..pr 60, 33, 68, 79, 67, 84, 89, 80, 69, 32, 104, 116, // <!DOCTYPE ht
101, 97, 99, 116, 46, 109, 105, 110, 46, 106, 115, 0, // eact.min.js. 109, 108, 62, 10, 60, 104, 116, 109, 108, 32, 108, 97, // ml>.<html la
157, 91, 123, 119, 219, 182, 146, 255, 127, 63, 69, 164, // .[{w.....?E. 110, 103, 61, 34, 101, 110, 34, 62, 10, 32, 32, 60, // ng="en">. <
211, 163, 18, 43, 68, 177, 147, 182, 187, 75, 5, 213, // ...+D....K.. 104, 101, 97, 100, 62, 10, 32, 32, 32, 32, 60, 109, // head>. <m
105, 29, 183, 238, 109, 234, 230, 38, 105, 123, 123, 85, // i...m..&i{{U 101, 116, 97, 32, 110, 97, 109, 101, 61, 34, 100, 101, // eta name="de
93, 30, 138, 132, 44, 214, 20, 169, 242, 97, 91, 53, // ]...,....a[5 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 99, // scription" c
245, 221, 247, 55, 3, 128, 164, 108, 185, 247, 236, 158, // ...7...l.... 111, 110, 116, 101, 110, 116, 61, 34, 77, 111, 110, 103, // ontent="Mong
36, 34, 30, 131, 1, 48, 47, 204, 12, 144, 155, 176, // $"...0/..... 111, 111, 115, 101, 32, 69, 109, 98, 101, 100, 100, 101, // oose Embedde
120, 166, 101, 38, 3, 89, 201, 92, 22, 178, 150, 169, // x.e&.Y...... 100, 32, 70, 105, 108, 101, 115, 121, 116, 101, 109, 32, // d Filesytem
186, 223, 203, 68, 205, 23, 50, 82, 47, 194, 40, 169, // ...D..2R/.(. 101, 120, 97, 109, 112, 108, 101, 34, 32, 47, 62, 10, // example" />.
26, 125, 231, 205, 252, 178, 185, 106, 178, 102, 219, 124, // .}.....j.f.| 32, 32, 32, 32, 60, 109, 101, 116, 97, 32, 104, 116, // <meta ht
34, 154, 98, 187, 110, 174, 138, 36, 110, 242, 219, 178, // ".b.n..$n... 116, 112, 45, 101, 113, 117, 105, 118, 61, 34, 67, 111, // tp-equiv="Co
217, 100, 81, 147, 85, 183, 77, 146, 233, 121, 180, 94, // .dQ.U.M..y.^ 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 34, 32, // ntent-Type"
52, 127, 230, 121, 243, 175, 188, 136, 155, 164, 210, 69, // 4..y.......E 99, 111, 110, 116, 101, 110, 116, 61, 34, 116, 101, 120, // content="tex
248, 34, 153, 174, 234, 44, 170, 146, 60, 123, 86, 122, // ."...,..<{Vz 116, 47, 104, 116, 109, 108, 59, 32, 99, 104, 97, 114, // t/html; char
152, 72, 220, 175, 242, 194, 187, 193, 172, 193, 179, 36, // .H.........$ 115, 101, 116, 61, 85, 84, 70, 45, 56, 34, 62, 10, // set=UTF-8">.
123, 150, 9, 61, 15, 22, 42, 195, 207, 180, 208, 85, // {..=..*....U 32, 32, 32, 32, 60, 109, 101, 116, 97, 32, 104, 116, // <meta ht
93, 100, 207, 244, 190, 29, 177, 242, 180, 184, 39, 216, // ]d........'. 116, 112, 45, 101, 113, 117, 105, 118, 61, 34, 88, 45, // tp-equiv="X-
76, 233, 201, 54, 44, 116, 86, 93, 230, 177, 158, 102, // L..6,tV]...f 85, 65, 45, 67, 111, 109, 112, 97, 116, 105, 98, 108, // UA-Compatibl
163, 81, 54, 41, 244, 38, 191, 209, 103, 235, 36, 141, // .Q6).&..g.$. 101, 34, 32, 99, 111, 110, 116, 101, 110, 116, 61, 34, // e" content="
1, 214, 13, 10, 61, 222, 141, 25, 216, 109, 105, 74, // ....=....miJ 73, 69, 61, 101, 100, 103, 101, 34, 62, 10, 32, 32, // IE=edge">.
243, 214, 52, 103, 32, 134, 215, 122, 55, 84, 170, 158, // ..4g ..z7T.. 32, 32, 60, 109, 101, 116, 97, 32, 110, 97, 109, 101, // <meta name
229, 42, 152, 215, 11, 127, 88, 232, 21, 215, 11, 83, // .*....X....S 61, 34, 118, 105, 101, 119, 112, 111, 114, 116, 34, 32, // ="viewport"
79, 241, 195, 165, 105, 178, 242, 194, 226, 170, 222, 96, // O...i......` 99, 111, 110, 116, 101, 110, 116, 61, 34, 119, 105, 100, // content="wid
230, 114, 146, 234, 236, 170, 90, 127, 249, 114, 52, 242, // .r....Z..r4. 116, 104, 61, 100, 101, 118, 105, 99, 101, 45, 119, 105, // th=device-wi
210, 73, 68, 19, 99, 69, 234, 81, 255, 171, 153, 158, // .ID.cE.Q.... 100, 116, 104, 44, 32, 105, 110, 105, 116, 105, 97, 108, // dth, initial
68, 97, 154, 118, 35, 229, 75, 225, 87, 66, 14, 221, // Da.v#.K.WB.. 45, 115, 99, 97, 108, 101, 61, 49, 34, 62, 10, 32, // -scale=1">.
26, 49, 87, 181, 219, 234, 124, 245, 140, 118, 82, 167, // .1W...|..vR. 32, 32, 32, 32, 32, 32, 32, 60, 116, 105, 116, 108, // <titl
233, 64, 101, 147, 88, 175, 194, 58, 173, 222, 21, 249, // .@e.X..:.... 101, 62, 77, 111, 110, 103, 111, 111, 115, 101, 32, 69, // e>Mongoose E
182, 20, 237, 98, 31, 180, 223, 228, 73, 252, 236, 68, // ...b....I..D 109, 98, 101, 100, 100, 101, 100, 32, 70, 105, 108, 101, // mbedded File
41, 69, 75, 164, 117, 208, 74, 15, 97, 208, 34, 28, // )EK.u.J.a.". 115, 121, 116, 101, 109, 32, 101, 120, 97, 109, 112, 108, // sytem exampl
45, 183, 160, 69, 202, 124, 165, 89, 122, 68, 218, 130, // -..E.|.YzD.. 101, 60, 47, 116, 105, 116, 108, 101, 62, 10, 32, 32, // e</title>.
23, 150, 225, 134, 80, 32, 17, 45, 201, 215, 114, 75, // ....P .-..rK 32, 32, 60, 108, 105, 110, 107, 32, 114, 101, 108, 61, // <link rel=
72, 252, 74, 130, 70, 62, 0, 244, 202, 47, 100, 16, // H.J.F>.../d. 34, 115, 116, 121, 108, 101, 115, 104, 101, 101, 116, 34, // "stylesheet"
92, 251, 132, 1, 5, 247, 93, 250, 39, 248, 213, 174, // ......].'... 32, 104, 114, 101, 102, 61, 34, 115, 116, 121, 108, 101, // href="style
26, 251, 102, 105, 40, 70, 174, 109, 109, 10, 81, 158, // ..fi(F.mm.Q. 46, 99, 115, 115, 34, 32, 47, 62, 10, 32, 32, 60, // .css" />. <
149, 85, 81, 71, 85, 94, 116, 64, 55, 220, 71, 52, // .UQGU^t@7.G4 47, 104, 101, 97, 100, 62, 10, 32, 32, 60, 98, 111, // /head>. <bo
31, 143, 3, 191, 222, 187, 21, 59, 106, 220, 100, 96, // .......;j.d` 100, 121, 62, 60, 47, 98, 111, 100, 121, 62, 10, 32, // dy></body>.
52, 177, 153, 11, 94, 42, 100, 218, 173, 126, 77, 114, // 4...^*d..~Mr 32, 60, 115, 99, 114, 105, 112, 116, 32, 116, 121, 112, // <script typ
225, 196, 165, 229, 68, 215, 31, 27, 73, 171, 214, 73, // ....D...I..I 101, 61, 34, 109, 111, 100, 117, 108, 101, 34, 32, 115, // e="module" s
57, 225, 237, 40, 236, 150, 42, 88, 74, 165, 239, 42, // 9..(..*XJ..* 114, 99, 61, 34, 109, 97, 105, 110, 46, 106, 115, 34, // rc="main.js"
213, 131, 189, 49, 176, 96, 180, 89, 80, 38, 90, 196, // ...1.`.YP&Z. 62, 60, 47, 115, 99, 114, 105, 112, 116, 62, 10, 60, // ></script>.<
65, 48, 67, 47, 62, 146, 126, 240, 247, 122, 146, 100, // A0C/>.~..z.d 47, 104, 116, 109, 108, 62, 10, 0 // /html>.
177, 190, 251, 145, 228, 114, 124, 42, 120, 11, 211, 86, // .....r|*x..V
158, 167, 217, 107, 205, 64, 70, 14, 166, 217, 120, 44, // ...k.@F...x,
44, 218, 129, 242, 2, 197, 157, 243, 108, 33, 28, 207, // ,.......l!..
9, 165, 118, 211, 113, 197, 82, 225, 136, 160, 232, 9, // ..v.q.R.....
21, 104, 61, 102, 218, 110, 3, 187, 86, 73, 100, 48, // .h=f.n..VId0
237, 230, 211, 60, 95, 59, 23, 85, 34, 163, 124, 84, // ...<_;.U".|T
52, 189, 209, 100, 25, 150, 90, 49, 151, 50, 117, 242, // 4..d..Z1.2u.
255, 220, 192, 253, 35, 132, 102, 47, 203, 66, 135, 215, // ....#.f/.B..
123, 187, 61, 90, 229, 190, 91, 244, 134, 22, 237, 13, // {.=Z..[.....
104, 76, 12, 49, 230, 175, 26, 156, 0, 115, 53, 217, // hL.1.....s5.
214, 37, 49, 120, 52, 26, 92, 161, 185, 24, 143, 155, // .%1x4.......
166, 24, 40, 150, 242, 101, 14, 4, 250, 189, 6, 23, // ..(..e......
138, 36, 187, 2, 140, 231, 21, 71, 123, 154, 38, 23, // .$.....G{.&.
222, 85, 79, 226, 175, 188, 206, 244, 232, 41, 99, 86, // .UO......)cV
149, 219, 169, 208, 40, 151, 121, 81, 121, 14, 222, 72, // ....(.yQy..H
69, 79, 20, 110, 240, 111, 249, 60, 115, 165, 189, 144, // EO.n.o.<s...
21, 217, 72, 141, 97, 27, 221, 27, 214, 242, 194, 233, // ..H.a.......
215, 212, 109, 178, 80, 94, 174, 60, 152, 50, 65, 72, // ..m.P^.<.2AH
232, 71, 75, 175, 86, 132, 242, 29, 237, 36, 32, 124, // .GK.V....$ |
94, 165, 74, 15, 6, 56, 23, 12, 165, 114, 250, 29, // ^.J..8...r..
159, 202, 119, 94, 13, 116, 149, 36, 232, 76, 26, 53, // ..w^.t.$.L.5
2, 81, 234, 73, 126, 155, 233, 226, 195, 207, 223, 158, // .Q.I~.......
167, 154, 108, 141, 52, 156, 161, 97, 235, 217, 188, 88, // ..l.4..a...X
88, 93, 148, 70, 184, 11, 8, 80, 46, 160, 208, 220, // X].F...P....
47, 228, 27, 47, 192, 76, 92, 211, 3, 85, 140, 70, // /../.L...U.F
59, 116, 11, 177, 239, 209, 237, 218, 59, 60, 30, 34, // ;t......;<."
89, 202, 149, 217, 100, 40, 99, 185, 147, 27, 121, 37, // Y...d(c...y%
175, 229, 157, 188, 80, 21, 113, 15, 34, 210, 52, 137, // ....P.q.".4.
60, 87, 23, 142, 184, 68, 117, 214, 30, 218, 95, 8, // <W...Du..._.
49, 11, 95, 103, 174, 47, 60, 16, 177, 13, 75, 206, // 1._g./<...K.
245, 60, 92, 40, 179, 94, 180, 100, 168, 129, 155, 195, // .<.(.^.d....
101, 158, 167, 58, 236, 105, 196, 102, 70, 48, 254, 16, // e..:.i.fF0..
182, 5, 12, 239, 181, 3, 56, 171, 55, 75, 93, 28, // ......8.7K].
182, 45, 147, 171, 36, 171, 250, 227, 183, 60, 47, 54, // .-..$....</6
96, 20, 128, 203, 194, 255, 170, 40, 194, 221, 36, 41, // `......(..$)
249, 235, 109, 4, 192, 214, 242, 222, 25, 25, 127, 179, // ..m.........
239, 129, 179, 85, 245, 55, 36, 16, 95, 158, 0, 112, // ...U.7$._..p
195, 90, 42, 55, 198, 234, 224, 11, 35, 106, 17, 51, // .Z*7....#j.3
207, 253, 141, 96, 83, 67, 53, 21, 112, 227, 146, 247, // ...`SC5.p...
188, 4, 139, 205, 150, 149, 183, 83, 23, 102, 207, 187, // .......S.f..
209, 136, 49, 40, 181, 163, 15, 213, 8, 189, 162, 58, // ..1(.......:
21, 4, 193, 41, 35, 11, 83, 157, 150, 250, 25, 145, // ...)#.S.....
58, 6, 133, 227, 215, 231, 211, 24, 164, 165, 185, 24, // :...........
95, 76, 74, 251, 215, 200, 238, 9, 202, 97, 51, 186, // _LJ......a3.
187, 99, 54, 236, 223, 65, 4, 54, 114, 167, 118, 77, // .c6..A.6r.vM
147, 30, 72, 129, 188, 82, 27, 35, 198, 49, 10, 56, // ..H..R.#.1.8
42, 48, 201, 142, 190, 3, 69, 2, 127, 215, 52, 222, // *0....E...4.
29, 152, 46, 36, 55, 142, 70, 119, 70, 183, 185, 230, // ...$7.FwF...
232, 45, 109, 99, 204, 212, 136, 154, 230, 10, 141, 194, // .-mc........
138, 241, 213, 204, 90, 229, 107, 160, 187, 86, 87, 71, // ....Z.k..VWG
207, 80, 179, 17, 103, 147, 8, 203, 53, 237, 142, 4, // .P..g...5...
142, 54, 135, 239, 108, 195, 246, 165, 84, 75, 111, 131, // .6..l...TKo.
133, 195, 132, 150, 234, 204, 108, 74, 94, 64, 124, 75, // ......lJ^@|K
33, 87, 144, 144, 124, 203, 136, 161, 86, 129, 177, 182, // !W..|...V...
71, 38, 11, 236, 100, 44, 209, 64, 41, 124, 61, 185, // G&..d,.@)|=.
9, 211, 90, 171, 225, 16, 104, 105, 255, 100, 12, 21, // ..Z...hi.d..
74, 101, 207, 101, 129, 1, 198, 152, 82, 221, 120, 59, // Je.e....R.x;
168, 151, 211, 8, 173, 174, 161, 16, 231, 211, 240, 249, // ............
243, 169, 48, 203, 39, 150, 2, 242, 47, 102, 238, 224, // ..0.'.../f..
8, 195, 104, 228, 74, 138, 5, 41, 110, 151, 118, 227, // ..h.J..)n.v.
85, 50, 196, 41, 37, 228, 79, 30, 193, 72, 150, 42, // U2.)%.O..H.*
65, 71, 196, 29, 251, 23, 70, 21, 239, 250, 170, 248, // AG....F.....
209, 187, 35, 200, 187, 249, 120, 220, 126, 122, 182, 96, // ..#...x.~z.`
105, 108, 129, 209, 126, 24, 4, 86, 237, 10, 104, 170, // il..~..V..h.
195, 131, 163, 2, 42, 216, 58, 115, 94, 84, 36, 122, // ....*.:s^T$z
30, 153, 24, 156, 194, 153, 58, 178, 179, 220, 80, 123, // ......:...P{
233, 229, 140, 221, 63, 35, 171, 132, 63, 60, 222, 24, // ....?#..?<..
39, 24, 227, 214, 169, 233, 29, 222, 103, 125, 227, 100, // '.......g}.d
150, 5, 111, 79, 38, 180, 201, 214, 70, 146, 201, 140, // ..oO&...F...
133, 49, 180, 49, 27, 208, 248, 64, 105, 218, 163, 63, // .1.1...@i..?
192, 161, 1, 43, 216, 52, 166, 154, 247, 248, 39, 180, // ...+.4....'.
223, 130, 1, 160, 56, 96, 45, 44, 186, 158, 132, 219, // ....8`-,....
45, 14, 31, 227, 142, 194, 164, 214, 172, 58, 60, 1, // -........:<.
31, 59, 169, 42, 224, 84, 159, 76, 81, 72, 39, 25, // .;.*.T.LQH'.
124, 144, 15, 201, 50, 53, 71, 88, 242, 186, 61, 135, // |...25GX..=.
146, 177, 122, 73, 246, 144, 102, 23, 172, 131, 56, 171, // ..zI..f...8.
52, 188, 142, 82, 23, 213, 215, 26, 136, 180, 71, 59, // 4..R......G;
5, 250, 194, 157, 172, 221, 89, 48, 171, 253, 188, 143, // ......Y0....
187, 163, 211, 157, 99, 220, 240, 57, 200, 14, 155, 122, // ....c..9...z
178, 128, 147, 90, 106, 246, 24, 129, 122, 231, 49, 225, // ...Zj...z.1.
53, 14, 119, 107, 121, 131, 217, 112, 232, 59, 59, 58, // 5.wky..p.;;:
104, 101, 176, 105, 162, 73, 165, 203, 202, 203, 196, 44, // he.i.I.....,
240, 131, 241, 112, 123, 55, 236, 166, 185, 232, 216, 97, // ...p{7.....a
152, 81, 76, 153, 110, 176, 209, 187, 84, 243, 204, 194, // .QL.n...T...
84, 15, 77, 118, 0, 250, 49, 200, 36, 42, 203, 143, // T.Mv..1.$*..
228, 160, 5, 134, 114, 199, 128, 43, 246, 23, 14, 193, // ....r..+....
43, 210, 62, 248, 252, 68, 233, 140, 220, 230, 74, 4, // +.>..D....J.
208, 20, 246, 246, 155, 230, 206, 193, 99, 113, 128, 35, // ........cq.#
225, 8, 58, 208, 64, 0, 99, 64, 59, 199, 20, 248, // ..:.@.c@;...
28, 194, 83, 135, 216, 59, 57, 25, 230, 142, 124, 163, // ..S..;9...|.
209, 48, 51, 229, 211, 133, 128, 11, 2, 250, 227, 104, // .03........h
167, 168, 100, 155, 134, 145, 246, 94, 156, 133, 91, 176, // ..d....^..[.
71, 127, 242, 130, 166, 132, 61, 67, 95, 149, 191, 205, // G.....=C_...
111, 117, 113, 6, 23, 201, 19, 152, 89, 207, 30, 180, // ouq.....Y...
77, 202, 52, 193, 88, 68, 11, 89, 91, 132, 22, 164, // M.4.XD.Y[...
176, 163, 248, 69, 16, 195, 181, 121, 54, 46, 16, 158, // ...E...y6...
200, 96, 86, 53, 13, 4, 47, 142, 207, 111, 32, 139, // .`V5../..o .
111, 147, 178, 210, 240, 5, 192, 202, 98, 246, 193, 63, // o.......b..?
135, 152, 192, 54, 153, 40, 233, 41, 128, 86, 1, 134, // ...6.(.).V..
113, 152, 93, 233, 34, 175, 203, 116, 247, 65, 87, 223, // q.]."..t.AW.
101, 128, 187, 248, 248, 195, 91, 50, 134, 198, 59, 206, // e.....[2..;.
197, 193, 246, 238, 32, 96, 215, 243, 11, 127, 189, 192, // .... `......
6, 215, 67, 209, 245, 148, 151, 225, 134, 183, 93, 14, // ..C.......].
123, 248, 215, 20, 98, 17, 50, 16, 46, 197, 66, 92, // {...b.2...B.
25, 108, 216, 184, 114, 21, 46, 191, 35, 255, 218, 213, // .l..r...#...
99, 248, 54, 105, 30, 198, 182, 206, 220, 210, 162, 42, // c.6i.......*
118, 247, 15, 5, 53, 152, 90, 101, 217, 71, 97, 21, // v...5.Ze.Ga.
113, 120, 176, 63, 102, 66, 65, 72, 235, 185, 66, 136, // qx.?fBAH..B.
6, 167, 3, 214, 249, 97, 216, 99, 106, 209, 50, 213, // .....a.cj.2.
40, 200, 87, 21, 196, 111, 89, 87, 218, 106, 136, 37, // (.W..oYW.j.%
104, 175, 89, 244, 253, 218, 115, 154, 154, 67, 141, 116, // h.Y...s..C.t
110, 92, 246, 241, 224, 116, 225, 101, 19, 77, 28, 152, // n....t.e.M..
217, 47, 57, 241, 253, 144, 245, 195, 145, 81, 39, 255, // ./9......Q'.
118, 20, 29, 203, 189, 176, 93, 38, 50, 50, 90, 183, // v.....]&22Z.
146, 161, 220, 202, 27, 235, 155, 45, 229, 25, 121, 103, // .......-..yg
240, 200, 204, 9, 114, 96, 27, 131, 73, 47, 58, 19, // ....r`..I/:.
189, 24, 108, 106, 232, 68, 254, 220, 26, 180, 138, 76, // ..lj.D.....L
9, 38, 204, 156, 91, 21, 27, 101, 42, 175, 77, 248, // .&..[..e*.M.
80, 171, 121, 130, 131, 222, 91, 177, 153, 93, 194, 172, // P.y...[..]..
145, 146, 77, 153, 89, 108, 2, 30, 115, 227, 156, 229, // ..M.Yl..s...
138, 252, 31, 227, 45, 157, 41, 140, 62, 119, 49, 218, // ....-.).>w1.
71, 242, 73, 70, 163, 124, 190, 34, 183, 0, 135, 145, // G.IF.|."....
90, 205, 206, 102, 103, 6, 214, 28, 185, 62, 117, 33, // Z..fg....>u!
70, 165, 197, 68, 179, 43, 133, 19, 141, 86, 100, 214, // F..D.+...Vd.
26, 145, 255, 172, 66, 252, 156, 251, 222, 16, 163, 170, // ....B.......
156, 230, 29, 66, 134, 206, 71, 163, 243, 73, 219, 2, // ...B..G..I..
142, 82, 208, 48, 51, 67, 67, 149, 233, 91, 176, 113, // .R.03CC..[.q
41, 239, 132, 239, 245, 219, 98, 110, 147, 97, 159, 98, // ).....bn.a.b
234, 28, 117, 51, 94, 125, 37, 228, 217, 104, 116, 54, // ..u3^}%..ht6
41, 235, 165, 23, 18, 156, 137, 60, 151, 40, 149, 85, // )......<.(.U
88, 105, 200, 158, 45, 177, 34, 135, 109, 48, 122, 39, // Xi..-.".m0z'
105, 149, 153, 202, 229, 150, 215, 75, 129, 16, 55, 173, // i......K..7.
217, 119, 50, 98, 78, 117, 248, 20, 30, 127, 149, 69, // .w2bNu.....E
228, 220, 164, 243, 201, 149, 174, 222, 32, 240, 185, 209, // ........ ...
241, 7, 234, 248, 166, 200, 55, 156, 12, 104, 71, 184, // ......7..hG.
33, 109, 3, 71, 25, 92, 132, 117, 42, 77, 163, 124, // !m.G...u*M.|
26, 145, 183, 116, 192, 66, 222, 40, 187, 57, 248, 132, // ...t.B.(.9..
22, 173, 220, 10, 179, 206, 191, 90, 138, 89, 44, 109, // .......Z.Y,m
124, 179, 205, 51, 72, 244, 47, 73, 154, 254, 128, 192, // |..3H./I....
13, 6, 248, 88, 171, 231, 246, 215, 235, 124, 147, 196, // ...X.....|..
237, 8, 80, 200, 248, 142, 71, 250, 69, 123, 128, 252, // ..P...G.E{..
251, 117, 45, 161, 8, 55, 79, 44, 239, 189, 142, 52, // .u-..7O,...4
198, 88, 200, 191, 232, 52, 210, 49, 8, 141, 83, 230, // .X...4.1..S.
112, 149, 235, 188, 78, 227, 51, 55, 232, 167, 109, 204, // p...N.37..m.
60, 24, 156, 42, 245, 84, 175, 163, 52, 208, 53, 77, // <..*.T..4.5M
192, 65, 160, 98, 137, 190, 17, 247, 143, 132, 202, 200, // .A.b........
5, 43, 226, 205, 192, 130, 89, 22, 67, 140, 78, 5, // .+....Y.C.N.
163, 186, 161, 195, 226, 129, 218, 94, 115, 249, 218, 148, // .......^s...
39, 176, 194, 231, 33, 236, 102, 63, 140, 213, 54, 46, // '...!.f?..6.
87, 129, 216, 27, 60, 107, 235, 166, 140, 70, 169, 165, // W...<k...F..
187, 104, 237, 238, 81, 226, 185, 237, 30, 109, 238, 237, // .h..Q....m..
243, 40, 155, 187, 193, 45, 159, 219, 229, 17, 37, 30, // .(...-....%.
195, 122, 108, 242, 40, 122, 61, 84, 174, 227, 52, 179, // .zl.(z=T..4.
166, 170, 176, 166, 74, 58, 154, 181, 36, 163, 239, 59, // ....J:..$..;
248, 172, 43, 229, 116, 220, 115, 114, 239, 164, 190, 157, // ..+.t.sr....
71, 60, 64, 238, 54, 4, 161, 99, 151, 240, 204, 128, // G<@.6..c....
145, 35, 12, 205, 179, 17, 190, 124, 212, 239, 145, 122, // .#.....|...z
109, 157, 3, 202, 221, 31, 178, 112, 11, 57, 177, 222, // m......p.9..
159, 217, 40, 76, 201, 230, 233, 94, 34, 3, 208, 92, // ..(L...^"...
40, 179, 8, 196, 93, 43, 23, 234, 173, 141, 100, 42, // (...]+....d*
181, 162, 24, 112, 182, 178, 214, 180, 13, 110, 87, 146, // ...p.....nW.
194, 253, 195, 8, 248, 66, 204, 46, 252, 249, 197, 226, // .....B......
209, 89, 131, 229, 119, 217, 158, 254, 89, 240, 132, 172, // .Y..w...Y...
200, 43, 43, 153, 231, 76, 36, 134, 53, 100, 215, 32, // .++..L$.5d.
187, 241, 177, 108, 82, 16, 14, 89, 95, 240, 103, 222, // ...lR..Y_.g.
67, 145, 181, 162, 44, 124, 83, 185, 245, 172, 100, 247, // C...,|S...d.
150, 24, 137, 41, 179, 56, 78, 86, 43, 29, 91, 46, // ...).8NV+.[.
119, 254, 129, 153, 128, 215, 235, 69, 134, 226, 3, 85, // w......E...U
11, 27, 62, 105, 149, 216, 29, 13, 6, 145, 172, 231, // ..>i........
117, 155, 249, 75, 196, 194, 174, 156, 164, 71, 155, 51, // u..K.....G.3
184, 239, 2, 188, 161, 38, 113, 79, 189, 17, 37, 48, // .....&qO..%0
241, 65, 60, 163, 197, 163, 84, 17, 128, 248, 120, 100, // .A<...T...xd
2, 174, 237, 116, 199, 83, 74, 54, 161, 76, 154, 216, // ...t.SJ6.L..
237, 160, 157, 159, 109, 195, 190, 159, 180, 185, 245, 250, // ....m.......
41, 155, 214, 49, 40, 217, 49, 88, 131, 118, 70, 140, // )..1(.1X.vF.
227, 246, 236, 221, 89, 231, 64, 110, 16, 163, 176, 215, // ....Y.@n....
125, 67, 46, 183, 218, 113, 222, 106, 112, 226, 84, 180, // }C...q.jp.T.
102, 191, 121, 186, 121, 93, 187, 144, 101, 99, 50, 56, // f.y.y]..ec28
136, 109, 235, 249, 134, 67, 189, 146, 60, 40, 136, 232, // .m...C..<(..
110, 6, 127, 38, 199, 194, 201, 33, 4, 42, 255, 21, // n..&...!.*..
194, 226, 9, 165, 115, 249, 108, 23, 216, 129, 42, 37, // ....s.l...*%
141, 50, 177, 146, 201, 57, 244, 18, 177, 157, 245, 86, // .2...9.....V
59, 231, 155, 196, 121, 196, 57, 245, 73, 4, 232, 74, // ;...y.9.I..J
147, 247, 79, 65, 152, 23, 139, 105, 166, 138, 217, 131, // ..OA...i....
110, 155, 20, 187, 252, 0, 7, 180, 170, 182, 254, 139, // n...........
23, 183, 183, 183, 147, 219, 87, 147, 188, 184, 122, 241, // ......W...z.
242, 228, 228, 228, 5, 237, 19, 234, 226, 31, 31, 232, // ............
237, 100, 12, 69, 24, 141, 98, 23, 209, 201, 136, 100, // .d.E..b....d
181, 191, 176, 53, 126, 99, 196, 69, 196, 107, 168, 95, // ...5~c.E.k._
104, 170, 158, 173, 196, 221, 65, 84, 147, 92, 91, 78, // h.....AT..[N
102, 70, 231, 104, 233, 37, 116, 64, 121, 45, 83, 154, // fF.h.%t@y-S.
38, 21, 147, 39, 188, 113, 56, 8, 241, 147, 125, 131, // &..'.q8...}.
168, 37, 152, 227, 211, 154, 174, 114, 136, 163, 155, 215, // .%.....r....
217, 36, 116, 46, 107, 217, 103, 221, 122, 222, 239, 1, // .$t.k.g.z...
47, 38, 25, 184, 69, 119, 10, 135, 173, 236, 112, 77, // /&..Ew....pM
61, 216, 166, 144, 120, 188, 37, 85, 30, 141, 182, 36, // =...x.%U...$
179, 213, 198, 250, 39, 84, 106, 154, 174, 13, 72, 18, // ....'Tj...H.
183, 60, 193, 36, 105, 171, 106, 219, 13, 134, 7, 142, // .<.$i.j.....
8, 137, 104, 218, 79, 190, 30, 134, 145, 180, 155, 194, // ..h.O.......
94, 222, 56, 107, 69, 242, 137, 88, 220, 94, 230, 112, // ^.8kE..X.^.p
88, 206, 55, 38, 77, 67, 113, 168, 185, 242, 64, 252, // X.7&MCq...@.
86, 44, 160, 159, 29, 130, 76, 228, 20, 118, 56, 111, // V,....L..v8o
180, 13, 109, 51, 0, 2, 217, 211, 200, 135, 76, 2, // ..m3......L.
87, 137, 214, 58, 186, 214, 177, 173, 210, 44, 28, 55, // W..:.....,.7
16, 14, 59, 59, 77, 108, 103, 223, 67, 29, 99, 185, // ..;;Mlg.C.c.
70, 43, 172, 230, 86, 184, 100, 104, 27, 29, 109, 156, // F+..V.dh..m.
30, 182, 150, 24, 118, 56, 147, 143, 50, 145, 27, 31, // ....v8..2...
172, 112, 138, 109, 130, 39, 157, 92, 101, 63, 46, 127, // .p.m.'..e?..
215, 17, 71, 84, 59, 214, 246, 122, 86, 35, 152, 241, // ..GT;..zV#..
43, 147, 9, 163, 60, 16, 244, 55, 58, 84, 225, 141, // +...<..7:T..
234, 52, 184, 203, 62, 145, 50, 146, 161, 100, 85, 158, // .4..>.2..dU.
194, 44, 122, 118, 215, 32, 92, 12, 84, 46, 108, 192, // .,zv. ..T.l.
240, 216, 136, 4, 9, 195, 134, 147, 44, 92, 5, 101, // ........,..e
176, 145, 171, 66, 151, 165, 53, 31, 131, 13, 64, 46, // ...B..5...@.
176, 27, 139, 9, 49, 201, 218, 192, 74, 242, 79, 90, // ....1...J.OZ
66, 30, 155, 193, 246, 81, 234, 146, 167, 176, 117, 139, // B....Q....u.
207, 141, 100, 140, 182, 66, 56, 197, 254, 113, 162, 232, // ..d..B8..q..
163, 181, 211, 108, 113, 143, 93, 175, 204, 180, 199, 225, // ...lq.].....
93, 84, 23, 148, 216, 81, 193, 99, 59, 123, 96, 229, // ]T...Q.c;{`.
127, 114, 8, 237, 45, 35, 223, 188, 76, 234, 108, 99, // .r..-#..L.lc
156, 211, 182, 8, 4, 146, 83, 97, 38, 59, 234, 229, // ......Sa&;..
110, 6, 132, 54, 174, 72, 25, 36, 154, 163, 105, 62, // n..6.H.$..i>
82, 10, 140, 197, 182, 77, 129, 218, 60, 90, 100, 18, // R....M..<Zd.
199, 249, 3, 79, 202, 76, 194, 49, 241, 241, 46, 239, // ...O.L.1....
216, 129, 33, 246, 185, 57, 186, 115, 118, 113, 56, 201, // ..!..9.svq8.
75, 200, 77, 198, 142, 229, 163, 128, 213, 40, 94, 231, // K.M......(^.
78, 70, 10, 152, 138, 28, 194, 60, 26, 253, 228, 229, // NF.....<....
44, 217, 242, 136, 14, 153, 216, 21, 81, 159, 243, 96, // ,.......Q..`
236, 182, 86, 230, 206, 73, 200, 238, 166, 200, 165, 224, // ..V..I......
58, 138, 126, 229, 114, 84, 150, 123, 238, 194, 206, 197, // :.~.rT.{....
90, 102, 225, 45, 248, 15, 94, 223, 64, 144, 220, 79, // Zf.-..^.@..O
105, 127, 230, 196, 165, 62, 178, 216, 216, 198, 177, 124, // i....>.....|
163, 48, 87, 7, 57, 241, 128, 239, 43, 140, 99, 193, // .0W.9...+.c.
151, 222, 239, 160, 46, 129, 242, 6, 208, 175, 28, 29, // ............
130, 117, 53, 244, 214, 134, 47, 243, 0, 17, 89, 77, // .u5.../...YM
121, 240, 180, 187, 132, 169, 30, 93, 194, 240, 232, 217, // y......]....
60, 95, 248, 181, 153, 170, 154, 172, 146, 162, 52, 190, // <_........4.
158, 187, 30, 174, 250, 103, 128, 185, 167, 73, 236, 200, // .....g...I..
28, 227, 106, 162, 213, 193, 64, 74, 252, 189, 241, 146, // ..j...@J....
3, 50, 124, 99, 46, 170, 248, 2, 82, 221, 243, 229, // .2|c....R...
171, 26, 226, 115, 54, 28, 215, 227, 49, 221, 215, 106, // ...s6...1..j
9, 231, 178, 196, 225, 86, 248, 79, 92, 110, 57, 163, // .....V.O.n9.
227, 101, 98, 47, 17, 204, 220, 36, 241, 1, 176, 69, // .eb/...$...E
47, 171, 105, 159, 53, 15, 92, 87, 216, 10, 119, 129, // /.i.5..W..w.
133, 240, 150, 242, 51, 4, 37, 143, 129, 170, 158, 31, // ....3.%.....
239, 48, 238, 13, 228, 209, 136, 72, 245, 151, 210, 93, // .0.....H...]
234, 26, 43, 194, 202, 195, 37, 114, 26, 217, 115, 66, // ..+...%r..sB
8, 96, 177, 213, 203, 131, 177, 129, 187, 91, 156, 186, // .`.......[..
71, 5, 199, 84, 102, 122, 188, 185, 191, 106, 76, 180, // G..Tfz...jL.
229, 252, 92, 208, 187, 17, 150, 48, 103, 252, 50, 129, // .......0g.2.
185, 75, 215, 157, 36, 240, 237, 237, 116, 123, 197, 29, // .K..$...t{..
76, 28, 141, 57, 186, 154, 56, 246, 244, 51, 31, 176, // L..9..8..3..
63, 112, 65, 77, 18, 80, 102, 196, 88, 253, 128, 123, // ?pAM.Pf.X..{
237, 181, 51, 105, 193, 52, 227, 88, 102, 202, 158, 88, // ..3i.4.Xf..X
192, 229, 136, 46, 80, 233, 164, 97, 227, 64, 237, 213, // ....P..a.@..
131, 108, 143, 139, 82, 171, 99, 161, 241, 121, 81, 228, // .l..R.c..yQ.
5, 59, 195, 37, 162, 12, 106, 245, 158, 134, 195, 102, // .;.%..j....f
133, 204, 205, 253, 131, 179, 91, 193, 65, 128, 118, 70, // ......[.A.vF
54, 136, 209, 61, 106, 37, 202, 181, 99, 243, 254, 117, // 6..=j%..c..u
248, 121, 107, 133, 177, 95, 173, 178, 125, 181, 46, 242, // .yk.._..}...
91, 4, 155, 123, 104, 232, 9, 60, 179, 46, 135, 227, // [..{h..<....
22, 169, 14, 137, 100, 238, 229, 3, 27, 9, 177, 76, // ....d......L
112, 26, 197, 149, 72, 121, 89, 80, 104, 236, 204, 181, // p...HyYPh...
250, 174, 96, 146, 36, 29, 196, 209, 235, 39, 142, 147, // ..`.$....'..
149, 54, 65, 29, 226, 200, 78, 64, 65, 20, 116, 150, // .6A...N@A.t.
198, 251, 183, 215, 240, 237, 220, 20, 166, 103, 109, 205, // .........gm.
6, 184, 153, 144, 27, 143, 154, 112, 136, 29, 236, 15, // .......p....
220, 142, 244, 83, 218, 96, 144, 217, 162, 166, 236, 145, // ...S.`......
126, 136, 88, 63, 133, 216, 38, 175, 214, 230, 54, 59, // ~.X?..&...6;
63, 102, 46, 33, 173, 155, 164, 212, 51, 251, 237, 13, // ?f.!....3...
174, 214, 58, 155, 44, 161, 1, 158, 235, 195, 193, 159, // ..:.,.......
167, 55, 26, 113, 172, 15, 150, 124, 76, 54, 58, 175, // .7.q...|L6:.
43, 105, 110, 219, 79, 96, 144, 79, 88, 243, 222, 202, // +in.O`.OX...
75, 249, 139, 124, 143, 150, 239, 104, 214, 31, 77, 206, // K..|...h..M.
80, 254, 108, 2, 114, 249, 71, 27, 181, 201, 175, 141, // P.l.r.G.....
44, 203, 79, 84, 123, 162, 118, 15, 138, 126, 239, 34, // ,.OT{.v..~."
173, 181, 177, 251, 107, 239, 82, 106, 249, 30, 14, 153, // ....k.Rj....
32, 244, 60, 89, 165, 46, 209, 115, 1, 251, 196, 95, // .<Y...s..._
210, 37, 31, 147, 210, 243, 148, 249, 98, 223, 222, 42, // .%......b..*
233, 47, 57, 164, 108, 195, 86, 174, 48, 237, 40, 91, // ./9.l.V.0.([
71, 181, 185, 94, 116, 118, 247, 219, 222, 19, 148, 247, // G..^tv......
234, 84, 254, 233, 37, 90, 246, 179, 179, 127, 30, 220, // .T..%Z......
149, 169, 223, 189, 183, 48, 199, 47, 219, 233, 170, 73, // .....0./...I
69, 143, 82, 38, 124, 229, 201, 209, 171, 154, 7, 179, // E.R&|.......
0, 18, 224, 39, 218, 230, 103, 33, 193, 242, 209, 195, // ...'..g!....
2, 172, 178, 98, 120, 184, 120, 146, 206, 90, 83, 52, // ...bx.x..ZS4
41, 114, 139, 40, 51, 235, 61, 93, 44, 204, 12, 157, // )r.(3.=],...
14, 99, 47, 98, 111, 91, 213, 165, 217, 87, 183, 230, // .c/bo[...W..
191, 25, 130, 246, 87, 252, 74, 76, 7, 153, 81, 154, // ....W.JL..Q.
84, 51, 250, 11, 73, 175, 74, 204, 76, 102, 7, 23, // T3..I.J.Lf..
42, 144, 76, 219, 78, 222, 42, 209, 35, 197, 247, 143, // *.L.N.*.#...
209, 126, 246, 127, 64, 123, 12, 229, 223, 15, 200, 255, // .~..@{......
185, 252, 213, 123, 116, 166, 220, 91, 239, 202, 39, 123, // ...{t..[..'{
49, 239, 95, 99, 254, 195, 177, 230, 189, 250, 66, 126, // 1._c......B~
223, 31, 249, 132, 103, 152, 145, 60, 155, 124, 152, 243, // ....g..<.|..
15, 169, 105, 47, 221, 21, 68, 224, 179, 105, 133, 177, // ..i/..D..i..
34, 83, 216, 205, 244, 107, 255, 116, 54, 59, 255, 175, // "S...k.t6;..
86, 4, 82, 205, 169, 134, 11, 64, 216, 172, 3, 172, // V.R....@....
136, 224, 112, 254, 66, 101, 54, 31, 160, 77, 67, 135, // ..p.Be6..MC.
242, 159, 7, 135, 247, 123, 245, 223, 199, 246, 14, 27, // .....{......
9, 160, 110, 144, 214, 157, 252, 92, 186, 115, 102, 206, // ..n......sf.
126, 37, 52, 193, 174, 236, 127, 68, 119, 66, 69, 116, // ~%4....DwBEt
87, 235, 46, 223, 3, 246, 171, 204, 10, 97, 92, 50, // W........a.2
78, 113, 95, 146, 135, 218, 63, 136, 201, 123, 238, 47, // Nq_...?..{./
52, 211, 78, 61, 235, 82, 191, 209, 203, 250, 234, 103, // 4.N=.R.....g
115, 74, 63, 104, 240, 72, 236, 31, 92, 109, 4, 189, // sJ?h.H...m..
245, 154, 197, 157, 34, 132, 9, 212, 183, 94, 119, 11, // ...."....^w.
108, 4, 229, 242, 241, 129, 194, 154, 254, 168, 245, 192, // l...........
108, 246, 60, 69, 34, 48, 52, 133, 206, 107, 1, 247, // l.<E"04..k..
142, 180, 170, 127, 208, 83, 151, 209, 70, 232, 77, 183, // .....S..F.M.
64, 168, 146, 184, 255, 238, 104, 222, 52, 49, 222, 238, // @.....h.41..
59, 115, 81, 213, 170, 133, 3, 45, 172, 27, 124, 216, // ;sQ....-..|.
90, 247, 91, 97, 19, 237, 185, 23, 136, 251, 126, 171, // Z.[a......~.
77, 57, 153, 247, 104, 156, 242, 97, 3, 186, 103, 243, // M9..h..a..g.
121, 176, 193, 75, 147, 172, 248, 113, 52, 250, 145, 118, // y..K...q4..v
198, 3, 139, 3, 136, 159, 71, 163, 159, 105, 243, 111, // ......G..i.o
173, 153, 204, 148, 119, 105, 35, 13, 154, 145, 222, 88, // ....wi#....X
122, 217, 163, 149, 103, 143, 86, 157, 217, 181, 241, 36, // z...g.V....$
198, 106, 31, 204, 243, 199, 104, 244, 135, 243, 184, 204, // .j....h.....
19, 178, 104, 26, 152, 252, 222, 133, 253, 28, 164, 11, // ..h.........
61, 186, 149, 251, 206, 168, 60, 89, 132, 95, 56, 143, // =.....<Y._8.
80, 232, 63, 106, 93, 86, 95, 101, 201, 38, 36, 204, // P.?j]V_e.&$.
223, 20, 225, 134, 210, 160, 222, 47, 79, 117, 10, 132, // ......./Ou..
29, 143, 31, 101, 245, 157, 184, 40, 213, 97, 97, 143, // ...e...(.aa.
40, 88, 23, 153, 67, 54, 163, 48, 139, 116, 122, 136, // (X..C6.0.tz.
137, 78, 229, 238, 48, 99, 114, 86, 170, 215, 16, 64, // .N..0crV...@
56, 79, 196, 148, 134, 123, 153, 58, 186, 24, 236, 4, // 8O...{.:....
226, 229, 85, 228, 39, 93, 186, 200, 135, 73, 23, 245, // ..U.']...I..
61, 150, 128, 61, 203, 135, 201, 63, 39, 71, 143, 101, // =..=...?'G.e
104, 173, 108, 123, 146, 86, 186, 56, 24, 100, 180, 132, // h.l{.V.8.d..
31, 216, 53, 77, 173, 89, 188, 173, 80, 85, 71, 103, // ..5M.Y..PUGg
209, 230, 20, 245, 116, 203, 79, 82, 184, 86, 230, 170, // ....t.OR.V..
158, 204, 125, 61, 26, 125, 109, 162, 49, 217, 158, 202, // ..}=.}m.1...
7, 60, 255, 100, 52, 250, 228, 33, 207, 233, 210, 221, // .<.d4..!....
242, 155, 53, 195, 113, 190, 191, 169, 167, 115, 155, 140, // ..5.q....s..
42, 215, 199, 220, 147, 163, 4, 239, 156, 132, 162, 111, // *..........o
250, 166, 71, 95, 86, 114, 162, 150, 63, 30, 177, 167, // ..G_Vr..?...
151, 54, 168, 15, 6, 51, 8, 111, 231, 33, 92, 170, // .6...3.o.!..
251, 86, 121, 160, 233, 94, 222, 8, 52, 231, 45, 76, // .Vy..^..4.-L
17, 65, 241, 3, 178, 247, 195, 93, 122, 65, 64, 111, // .A.....]zA@o
161, 251, 105, 220, 228, 0, 237, 177, 231, 195, 179, 140, // ..i.........
31, 132, 238, 105, 137, 209, 161, 247, 219, 75, 79, 76, // ...i.....KOL
233, 114, 27, 122, 238, 98, 134, 66, 157, 34, 184, 207, // .r.z.b.B."..
250, 193, 189, 121, 59, 67, 25, 172, 241, 120, 33, 83, // ...y;C...x!S
78, 101, 193, 254, 99, 92, 163, 234, 217, 169, 255, 146, // Ne..c.......
94, 66, 112, 231, 2, 243, 205, 199, 227, 98, 49, 125, // ^Bp......b1}
165, 232, 209, 73, 69, 184, 83, 255, 51, 91, 57, 93, // ...IE.S.3[9]
40, 147, 143, 154, 132, 101, 153, 92, 101, 30, 53, 53, // (....e..e.55
13, 124, 227, 84, 248, 159, 51, 16, 55, 41, 215, 142, // .|.T..3.7)..
88, 145, 209, 17, 146, 47, 90, 36, 174, 113, 172, 210, // X..../Z$.q..
241, 112, 136, 112, 152, 179, 19, 225, 118, 155, 238, 188, // .p.p....v...
84, 70, 68, 24, 122, 214, 56, 31, 14, 249, 16, 94, // TFD.z.8....^
8, 242, 101, 216, 104, 228, 66, 166, 244, 190, 197, 172, // ..e.h.B.....
253, 165, 143, 77, 20, 207, 95, 98, 251, 156, 146, 83, // ...M.._b...S
57, 142, 114, 11, 153, 182, 153, 34, 132, 159, 244, 14, // 9.r...."....
86, 223, 62, 251, 33, 220, 202, 213, 161, 143, 109, 216, // V.>.!.....m.
15, 231, 22, 225, 143, 241, 161, 219, 51, 136, 146, 154, // ........3...
237, 176, 146, 195, 16, 134, 160, 231, 74, 18, 93, 88, // ........J.]X
167, 169, 242, 88, 109, 146, 160, 4, 68, 65, 93, 127, // ...Xm...DA].
14, 199, 25, 230, 26, 220, 73, 56, 226, 67, 89, 208, // ......I8.CY.
79, 173, 232, 72, 74, 15, 160, 233, 246, 144, 159, 193, // O..HJ.......
0, 95, 174, 242, 238, 237, 197, 191, 126, 43, 255, 243, // ._......~+..
183, 12, 63, 141, 43, 124, 242, 226, 138, 31, 160, 136, // ..?.+|......
89, 109, 54, 141, 224, 0, 81, 22, 229, 226, 29, 138, // Ym6...Q.....
92, 204, 60, 219, 249, 138, 59, 177, 130, 151, 194, 127, // ..<...;.....
105, 32, 134, 147, 201, 132, 82, 121, 57, 84, 196, 225, // i ....Ry9T..
248, 12, 96, 39, 45, 4, 122, 6, 109, 215, 231, 242, // ..`'-.z.m...
68, 194, 71, 192, 12, 213, 151, 234, 115, 122, 159, 155, // D.G.....sz..
55, 205, 0, 166, 145, 88, 95, 145, 163, 99, 1, 43, // 7....X_..c.+
0, 230, 28, 47, 169, 47, 56, 78, 234, 58, 128, 220, // ..././8N.:..
117, 8, 166, 196, 158, 159, 78, 37, 175, 117, 247, 78, // u.....N%.u.N
138, 222, 54, 210, 97, 97, 150, 144, 66, 33, 83, 47, // ..6.aa..B!S/
17, 162, 21, 241, 8, 3, 162, 215, 122, 158, 44, 220, // ........z.,.
152, 8, 99, 16, 242, 163, 101, 14, 167, 135, 7, 206, // ..c...e.....
134, 175, 249, 185, 199, 204, 35, 4, 160, 116, 13, 215, // ......#..t..
88, 189, 18, 126, 62, 86, 25, 75, 52, 64, 158, 63, // X..~>V.K4@.?
183, 219, 31, 126, 105, 129, 29, 131, 0, 167, 178, 113, // ...~i......q
78, 185, 214, 98, 150, 81, 38, 120, 70, 44, 51, 163, // N..b.Q&xF,3.
63, 29, 126, 106, 238, 65, 134, 159, 154, 97, 5, 26, // ?.~j.A...a..
91, 20, 52, 31, 208, 128, 74, 244, 216, 79, 181, 136, // [.4...J..O..
63, 135, 205, 205, 45, 242, 225, 11, 110, 38, 167, 248, // ?...-...n&..
245, 231, 192, 195, 99, 205, 250, 199, 244, 62, 133, 145, // ....c....>..
56, 62, 214, 138, 114, 190, 132, 180, 150, 174, 98, 232, // 8>..r.....b.
249, 18, 212, 172, 168, 3, 28, 27, 62, 27, 218, 69, // ........>..E
253, 86, 181, 165, 172, 45, 21, 7, 171, 123, 105, 232, // .V...-...{i.
208, 206, 49, 28, 180, 164, 192, 74, 63, 147, 118, 22, // ..1....J?.v.
167, 67, 76, 194, 61, 167, 2, 48, 166, 251, 191, 15, // .CL.=..0....
56, 74, 132, 251, 175, 17, 167, 179, 204, 39, 189, 220, // 8J.......'..
155, 168, 49, 20, 83, 125, 183, 205, 139, 234, 62, 124, // ..1.S}....>|
22, 150, 207, 214, 208, 60, 254, 86, 155, 84, 254, 64, // .....<.V.T.@
37, 19, 157, 202, 152, 202, 109, 82, 72, 126, 67, 85, // %.....mRH~CU
115, 79, 99, 51, 74, 242, 91, 106, 130, 91, 201, 81, // sOc3J.[j.[.Q
142, 252, 211, 214, 222, 235, 184, 142, 48, 254, 111, 182, // ........0.o.
126, 14, 239, 36, 170, 228, 247, 182, 250, 54, 220, 225, // ~..$.....6..
252, 182, 141, 127, 111, 199, 172, 228, 63, 108, 249, 187, // ....o...?l..
205, 86, 23, 56, 84, 110, 244, 69, 152, 197, 169, 150, // .V.8Tn.E....
191, 218, 142, 31, 244, 38, 151, 255, 180, 149, 179, 48, // .....&.....0
77, 151, 97, 116, 45, 181, 118, 45, 118, 85, 153, 107, // M.at-.v-vU.k
232, 188, 93, 25, 184, 54, 206, 156, 124, 141, 179, 51, // ..]..6..|..3
14, 139, 221, 126, 250, 31, 255, 11, 22, 19, 178, 116, // ...~.......t
138, 51, 0, 0, 0 // .3..
}; };
static const unsigned char v2[] = { static const unsigned char v2[] = {
31, 139, 8, 8, 219, 27, 244, 98, 0, 3, 109, 97, // .......b..ma
105, 110, 46, 106, 115, 0, 165, 86, 237, 110, 219, 54, // in.js..V.n.6
20, 253, 239, 167, 184, 8, 6, 52, 65, 109, 41, 77, // .......4Am)M
246, 1, 52, 138, 1, 55, 93, 129, 20, 93, 61, 204, // ..4..7]..]=.
233, 218, 254, 43, 37, 210, 22, 91, 138, 84, 249, 97, // ...+%..[.T.a
205, 11, 242, 46, 125, 150, 62, 217, 14, 37, 217, 177, // ....}.>..%..
19, 103, 195, 218, 95, 166, 36, 222, 123, 15, 207, 185, // .g.._.$.{...
247, 208, 143, 130, 19, 228, 188, 149, 133, 127, 116, 54, // ..........t6
144, 85, 109, 172, 167, 107, 42, 135, 84, 250, 74, 13, // .Um..k*.T.J.
201, 10, 205, 133, 165, 27, 154, 91, 83, 209, 163, 36, // .......[S..$
173, 173, 96, 133, 79, 42, 169, 147, 143, 14, 33, 131, // ..`.O*....!.
65, 97, 180, 243, 244, 142, 206, 105, 30, 116, 225, 165, // Aa.....i.t..
209, 116, 120, 68, 215, 131, 1, 33, 218, 7, 171, 219, // .txD...!....
84, 31, 240, 152, 113, 185, 164, 66, 49, 231, 206, 15, // T...q..B1...
16, 229, 153, 212, 194, 30, 140, 241, 5, 223, 202, 147, // ............
245, 39, 39, 218, 44, 7, 227, 201, 179, 233, 155, 43, // .''.,......+
122, 51, 203, 210, 242, 164, 223, 181, 149, 193, 154, 166, // z3..........
143, 189, 155, 89, 141, 126, 217, 124, 193, 183, 122, 220, // ...Y.~.|..z.
45, 54, 111, 136, 46, 132, 99, 168, 79, 51, 51, 247, // -6o...c.O33.
13, 179, 130, 94, 121, 158, 144, 116, 84, 10, 198, 63, // ...^y..tT..?
7, 102, 189, 176, 130, 127, 253, 34, 53, 61, 15, 185, // .f....."5=..
146, 122, 72, 127, 136, 58, 174, 10, 50, 115, 186, 180, // .zH..:..2s..
66, 49, 205, 147, 219, 26, 105, 189, 83, 112, 231, 121, // B1....i.Sp.y
26, 44, 40, 54, 118, 69, 214, 24, 239, 40, 103, 197, // .,(6vE...(g.
39, 242, 134, 78, 142, 143, 127, 28, 82, 83, 10, 77, // '..N....RS.M
191, 25, 189, 48, 6, 82, 188, 21, 57, 205, 132, 93, // ...0.R..9..]
130, 243, 87, 50, 183, 204, 174, 190, 126, 225, 98, 41, // ..W2....~.b)
148, 169, 43, 161, 61, 242, 68, 108, 192, 154, 229, 118, // ..+.=.Dl...v
60, 216, 148, 152, 184, 189, 41, 22, 86, 52, 132, 51, // <.....).V4.3
212, 166, 14, 138, 89, 233, 87, 4, 216, 84, 49, 200, // ....Y.W..T1.
34, 56, 153, 184, 199, 151, 130, 230, 70, 41, 211, 72, // "8......F).H
189, 160, 149, 96, 214, 13, 99, 204, 201, 241, 147, 211, // ...`..c.....
13, 79, 13, 115, 36, 80, 27, 4, 184, 18, 145, 64, // .O.s$P.....@
31, 5, 148, 58, 8, 146, 56, 210, 54, 196, 88, 97, // ...:..8.6.Xa
3, 172, 182, 102, 41, 57, 90, 44, 212, 109, 107, 33, // ...f)9Z,.mk!
208, 128, 142, 37, 83, 1, 105, 138, 0, 94, 42, 97, // ...%S.i..^*a
221, 195, 76, 190, 21, 20, 245, 65, 158, 208, 150, 45, // ..L....A...-
217, 18, 111, 42, 28, 182, 77, 180, 201, 128, 67, 233, // ..o*..M...C.
21, 101, 114, 252, 2, 101, 130, 22, 244, 211, 241, 113, // .er..e.....q
150, 202, 49, 112, 86, 53, 211, 82, 56, 194, 25, 26, // ..1pV5.R8...
161, 84, 252, 173, 4, 151, 161, 106, 161, 186, 138, 225, // .T.....j....
157, 147, 127, 11, 202, 131, 67, 71, 58, 39, 182, 240, // ......CG:'..
16, 184, 44, 194, 134, 58, 244, 134, 138, 107, 52, 65, // ..,..:...k4A
44, 239, 140, 10, 177, 87, 93, 236, 29, 70, 53, 179, // ,....W]..F5.
128, 22, 64, 194, 220, 88, 10, 174, 13, 105, 9, 198, // ..@..X...i..
204, 96, 193, 252, 94, 153, 16, 139, 49, 228, 148, 175, // .`..^...1...
232, 245, 100, 54, 33, 150, 27, 102, 187, 192, 75, 141, // ..d6!..f..K.
78, 212, 44, 214, 96, 138, 102, 53, 43, 4, 205, 124, // N.,.`.f5+..|
251, 28, 195, 182, 96, 198, 221, 57, 52, 138, 194, 204, // ....`..94...
165, 173, 186, 61, 96, 76, 250, 100, 135, 212, 150, 214, // ...=`L.d....
153, 212, 200, 20, 53, 30, 110, 68, 46, 163, 200, 127, // ....5.nD....
129, 44, 14, 44, 81, 85, 144, 206, 3, 128, 71, 229, // .,.,QU....G.
208, 34, 210, 36, 64, 189, 214, 186, 61, 27, 151, 209, // .".$@...=...
59, 242, 224, 5, 137, 42, 23, 60, 70, 186, 245, 76, // ;....*.<F..L
197, 13, 37, 14, 210, 62, 52, 210, 151, 96, 5, 122, // ..%..>4..`.z
17, 96, 1, 163, 198, 148, 99, 119, 95, 227, 150, 170, // .`....cw_...
238, 196, 194, 71, 138, 175, 74, 244, 164, 235, 224, 175, // ...G..J.....
39, 61, 197, 168, 247, 102, 176, 94, 246, 139, 15, 103, // '=...f.^...g
131, 155, 179, 181, 31, 189, 255, 110, 63, 58, 189, 239, // .......n?:..
71, 155, 182, 187, 69, 109, 197, 83, 216, 211, 233, 55, // G...Em.S...7
219, 83, 22, 212, 150, 52, 153, 146, 219, 66, 81, 6, // .S...4...BQ.
85, 172, 152, 159, 31, 148, 222, 215, 238, 105, 154, 86, // U........i.V
125, 251, 36, 141, 75, 15, 198, 123, 154, 41, 75, 217, // }.$.K..{.)K.
78, 134, 17, 136, 189, 213, 166, 193, 62, 215, 53, 93, // N.......>.5]
228, 27, 52, 55, 198, 126, 138, 131, 175, 58, 183, 217, // ..47.~...:..
130, 146, 238, 96, 249, 79, 100, 75, 48, 152, 72, 3, // ...`.OdK0.H.
84, 127, 94, 76, 95, 99, 117, 31, 201, 196, 242, 32, // T.^L_cu....
181, 25, 181, 35, 233, 101, 174, 208, 177, 177, 211, 93, // ...#.e.....]
215, 29, 121, 144, 202, 143, 96, 61, 177, 125, 219, 166, // ..y...`=.}..
153, 94, 77, 40, 212, 156, 121, 225, 182, 51, 117, 30, // .^M(..y..3u.
166, 217, 66, 180, 134, 195, 153, 43, 219, 60, 223, 14, // ..B....+.<..
190, 138, 57, 18, 208, 1, 248, 213, 243, 126, 189, 151, // ..9......~..
74, 152, 5, 32, 142, 12, 28, 230, 210, 92, 209, 239, // J.. ........
138, 97, 52, 108, 245, 29, 165, 123, 13, 71, 198, 37, // .a4l...{.G.%
32, 102, 75, 212, 233, 108, 47, 2, 83, 11, 11, 246, // fK..l/.S...
160, 153, 91, 57, 47, 170, 214, 107, 96, 223, 163, 218, // ..[9/..k`...
52, 208, 181, 146, 133, 53, 177, 155, 45, 76, 29, 198, // 4....5..-L..
120, 23, 217, 255, 128, 182, 128, 42, 33, 143, 168, 210, // x......*!...
162, 243, 136, 180, 250, 232, 192, 208, 203, 253, 200, 54, // ...........6
109, 246, 146, 45, 217, 172, 176, 178, 246, 36, 244, 2, // m..-.....$..
83, 213, 98, 188, 72, 47, 30, 63, 126, 128, 168, 44, // S.b.H/.?~..,
189, 157, 131, 173, 17, 191, 63, 58, 63, 239, 222, 236, // ......?:?...
89, 62, 158, 238, 248, 112, 55, 144, 249, 238, 13, 188, // Y>...p7.....
59, 100, 237, 193, 37, 108, 102, 1, 30, 163, 213, 105, // ;d..%lf....i
184, 164, 47, 77, 192, 17, 209, 139, 240, 29, 156, 24, // ../M........
119, 74, 33, 97, 185, 235, 73, 191, 35, 107, 155, 131, // wJ!a..I.#k..
139, 90, 153, 85, 119, 29, 150, 65, 115, 220, 169, 109, // .Z.Uw..As..m
120, 37, 149, 106, 193, 192, 42, 37, 152, 107, 175, 224, // x%.j..*%.k..
46, 79, 116, 35, 161, 151, 210, 26, 29, 123, 247, 78, // .Ot#.....{.N
218, 7, 88, 248, 87, 163, 155, 212, 245, 142, 213, 161, // ..X.W.......
80, 237, 246, 249, 93, 86, 62, 25, 63, 99, 14, 255, // P...]V>.?c..
96, 126, 93, 235, 244, 66, 42, 209, 55, 17, 23, 21, // `~]..B*.7...
38, 22, 91, 6, 89, 95, 236, 135, 235, 242, 240, 221, // &.[.Y_......
209, 205, 160, 47, 186, 253, 250, 253, 230, 117, 15, 5, // .../.....u..
255, 29, 184, 105, 18, 163, 149, 97, 28, 112, 96, 184, // ...i...a.p`.
231, 227, 254, 207, 227, 97, 121, 8, 140, 71, 67, 226, // .....ay..GC.
112, 255, 120, 232, 36, 55, 124, 117, 116, 54, 248, 7, // p.x.$7|ut6..
71, 33, 75, 134, 124, 10, 0, 0, 0 // G!K.|...
};
static const unsigned char v3[] = {
39, 117, 115, 101, 32, 115, 116, 114, 105, 99, 116, 39, // 'use strict' 39, 117, 115, 101, 32, 115, 116, 114, 105, 99, 116, 39, // 'use strict'
59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 104, // ;.import { h 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 104, // ;.import { h
44, 32, 104, 116, 109, 108, 44, 32, 114, 101, 110, 100, // , html, rend 44, 32, 104, 116, 109, 108, 44, 32, 114, 101, 110, 100, // , html, rend
@@ -774,7 +282,7 @@ static const unsigned char v3[] = {
112, 41, 44, 32, 100, 111, 99, 117, 109, 101, 110, 116, // p), document 112, 41, 44, 32, 100, 111, 99, 117, 109, 101, 110, 116, // p), document
46, 98, 111, 100, 121, 41, 59, 10, 0 // .body);. 46, 98, 111, 100, 121, 41, 59, 10, 0 // .body);.
}; };
static const unsigned char v4[] = { static const unsigned char v3[] = {
118, 97, 114, 32, 101, 44, 110, 44, 95, 44, 116, 44, // var e,n,_,t, 118, 97, 114, 32, 101, 44, 110, 44, 95, 44, 116, 44, // var e,n,_,t,
111, 44, 114, 44, 117, 44, 108, 61, 123, 125, 44, 105, // o,r,u,l={},i 111, 44, 114, 44, 117, 44, 108, 61, 123, 125, 44, 105, // o,r,u,l={},i
61, 91, 93, 44, 99, 61, 47, 97, 99, 105, 116, 124, // =[],c=/acit| 61, 91, 93, 44, 99, 61, 47, 97, 99, 105, 116, 124, // =[],c=/acit|
@@ -1876,147 +1384,7 @@ static const unsigned char v4[] = {
115, 101, 69, 114, 114, 111, 114, 66, 111, 117, 110, 100, // seErrorBound 115, 101, 69, 114, 114, 111, 114, 66, 111, 117, 110, 100, // seErrorBound
97, 114, 121, 125, 59, 10, 0 // ary};. 97, 114, 121, 125, 59, 10, 0 // ary};.
}; };
static const unsigned char v5[] = { static const unsigned char v4[] = {
60, 33, 68, 79, 67, 84, 89, 80, 69, 32, 104, 116, // <!DOCTYPE ht
109, 108, 62, 10, 60, 104, 116, 109, 108, 32, 108, 97, // ml>.<html la
110, 103, 61, 34, 101, 110, 34, 62, 10, 32, 32, 60, // ng="en">. <
104, 101, 97, 100, 62, 10, 32, 32, 32, 32, 60, 109, // head>. <m
101, 116, 97, 32, 110, 97, 109, 101, 61, 34, 100, 101, // eta name="de
115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 99, // scription" c
111, 110, 116, 101, 110, 116, 61, 34, 77, 111, 110, 103, // ontent="Mong
111, 111, 115, 101, 32, 69, 109, 98, 101, 100, 100, 101, // oose Embedde
100, 32, 70, 105, 108, 101, 115, 121, 116, 101, 109, 32, // d Filesytem
101, 120, 97, 109, 112, 108, 101, 34, 32, 47, 62, 10, // example" />.
32, 32, 32, 32, 60, 109, 101, 116, 97, 32, 104, 116, // <meta ht
116, 112, 45, 101, 113, 117, 105, 118, 61, 34, 67, 111, // tp-equiv="Co
110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 34, 32, // ntent-Type"
99, 111, 110, 116, 101, 110, 116, 61, 34, 116, 101, 120, // content="tex
116, 47, 104, 116, 109, 108, 59, 32, 99, 104, 97, 114, // t/html; char
115, 101, 116, 61, 85, 84, 70, 45, 56, 34, 62, 10, // set=UTF-8">.
32, 32, 32, 32, 60, 109, 101, 116, 97, 32, 104, 116, // <meta ht
116, 112, 45, 101, 113, 117, 105, 118, 61, 34, 88, 45, // tp-equiv="X-
85, 65, 45, 67, 111, 109, 112, 97, 116, 105, 98, 108, // UA-Compatibl
101, 34, 32, 99, 111, 110, 116, 101, 110, 116, 61, 34, // e" content="
73, 69, 61, 101, 100, 103, 101, 34, 62, 10, 32, 32, // IE=edge">.
32, 32, 60, 109, 101, 116, 97, 32, 110, 97, 109, 101, // <meta name
61, 34, 118, 105, 101, 119, 112, 111, 114, 116, 34, 32, // ="viewport"
99, 111, 110, 116, 101, 110, 116, 61, 34, 119, 105, 100, // content="wid
116, 104, 61, 100, 101, 118, 105, 99, 101, 45, 119, 105, // th=device-wi
100, 116, 104, 44, 32, 105, 110, 105, 116, 105, 97, 108, // dth, initial
45, 115, 99, 97, 108, 101, 61, 49, 34, 62, 10, 32, // -scale=1">.
32, 32, 32, 32, 32, 32, 32, 60, 116, 105, 116, 108, // <titl
101, 62, 77, 111, 110, 103, 111, 111, 115, 101, 32, 69, // e>Mongoose E
109, 98, 101, 100, 100, 101, 100, 32, 70, 105, 108, 101, // mbedded File
115, 121, 116, 101, 109, 32, 101, 120, 97, 109, 112, 108, // sytem exampl
101, 60, 47, 116, 105, 116, 108, 101, 62, 10, 32, 32, // e</title>.
32, 32, 60, 108, 105, 110, 107, 32, 114, 101, 108, 61, // <link rel=
34, 115, 116, 121, 108, 101, 115, 104, 101, 101, 116, 34, // "stylesheet"
32, 104, 114, 101, 102, 61, 34, 115, 116, 121, 108, 101, // href="style
46, 99, 115, 115, 34, 32, 47, 62, 10, 32, 32, 60, // .css" />. <
47, 104, 101, 97, 100, 62, 10, 32, 32, 60, 98, 111, // /head>. <bo
100, 121, 62, 60, 47, 98, 111, 100, 121, 62, 10, 32, // dy></body>.
32, 60, 115, 99, 114, 105, 112, 116, 32, 116, 121, 112, // <script typ
101, 61, 34, 109, 111, 100, 117, 108, 101, 34, 32, 115, // e="module" s
114, 99, 61, 34, 109, 97, 105, 110, 46, 106, 115, 34, // rc="main.js"
62, 60, 47, 115, 99, 114, 105, 112, 116, 62, 10, 60, // ></script>.<
47, 104, 116, 109, 108, 62, 10, 0 // /html>.
};
static const unsigned char v6[] = {
31, 139, 8, 8, 219, 27, 244, 98, 0, 3, 105, 110, // .......b..in
100, 101, 120, 46, 104, 116, 109, 108, 0, 141, 145, 77, // dex.html...M
75, 3, 49, 16, 134, 239, 253, 21, 99, 206, 166, 139, // K.1.....c...
55, 193, 205, 130, 212, 22, 60, 136, 30, 90, 208, 99, // 7.....<..Z.c
154, 140, 205, 104, 62, 214, 205, 244, 99, 255, 189, 217, // ...h>...c...
110, 133, 5, 17, 60, 205, 7, 47, 15, 51, 239, 91, // n...<../.3.[
95, 61, 60, 47, 214, 111, 47, 75, 112, 28, 124, 51, // _=</.o/Kp.|3
171, 135, 2, 94, 199, 157, 18, 24, 69, 51, 3, 168, // ...^....E3..
29, 106, 59, 52, 165, 13, 200, 26, 162, 14, 168, 132, // .j;4........
197, 108, 58, 106, 153, 82, 20, 96, 82, 100, 140, 172, // .l:j.R.`Rd..
196, 83, 138, 187, 148, 50, 194, 50, 108, 209, 90, 180, // .S...2.2l.Z.
176, 34, 143, 185, 103, 12, 128, 39, 29, 90, 143, 2, // ."..g..'.Z..
170, 41, 205, 49, 183, 18, 191, 246, 116, 80, 98, 49, // .).1....tPb1
98, 228, 186, 111, 113, 2, 101, 60, 113, 53, 28, 118, // b..oq.e<q5.v
7, 198, 233, 46, 35, 171, 205, 122, 37, 111, 197, 95, // ....#..z%o._
156, 87, 185, 185, 151, 139, 20, 90, 205, 180, 245, 83, // .W.....Z...S
212, 227, 82, 161, 221, 161, 248, 253, 207, 129, 240, 216, // ..R.........
166, 142, 39, 226, 35, 89, 118, 202, 226, 129, 12, 202, // ..'.#Yv.....
243, 112, 13, 20, 137, 73, 123, 153, 141, 246, 168, 110, // .p...I{....n
46, 160, 51, 140, 137, 61, 54, 255, 112, 160, 174, 70, // ..3..=6.p..F
233, 120, 131, 167, 248, 9, 29, 122, 37, 50, 247, 69, // .x.....z%2.E
233, 16, 203, 17, 174, 195, 247, 203, 102, 110, 114, 190, // ........fnr.
152, 86, 87, 63, 97, 212, 219, 100, 251, 166, 174, 206, // .VW?a..d....
101, 152, 199, 52, 128, 139, 117, 74, 132, 100, 247, 195, // e..4..uJ.d..
223, 185, 51, 101, 208, 20, 231, 31, 89, 20, 245, 40, // ..3e....Y..(
42, 49, 87, 99, 220, 223, 14, 156, 225, 97, 255, 1, // *1Wc.....a..
0, 0, 0 // ..
};
static const unsigned char v7[] = {
31, 139, 8, 8, 219, 27, 244, 98, 0, 3, 115, 116, // .......b..st
121, 108, 101, 46, 99, 115, 115, 0, 117, 84, 203, 110, // yle.css.uT.n
219, 48, 16, 188, 251, 43, 88, 4, 5, 218, 32, 82, // .0...+X... R
44, 41, 178, 99, 249, 210, 91, 63, 162, 232, 129, 18, // ,).c..[?....
87, 54, 17, 138, 84, 73, 58, 118, 90, 248, 223, 187, // W6..TI:vZ...
164, 30, 164, 226, 228, 98, 75, 187, 163, 125, 204, 12, // .....bK..}..
121, 79, 254, 145, 90, 93, 18, 195, 255, 114, 121, 168, // yO..Z]...ry.
240, 89, 51, 208, 9, 134, 246, 228, 186, 58, 218, 78, // .Y3......:.N
60, 96, 140, 189, 33, 172, 163, 250, 192, 101, 69, 214, // <`..!....eE.
123, 210, 83, 198, 60, 28, 159, 143, 192, 15, 71, 91, // {.S.<.....G[
145, 108, 189, 254, 186, 39, 173, 146, 238, 121, 211, 95, // .l...'...y._
136, 161, 210, 36, 6, 52, 111, 93, 41, 3, 2, 26, // ...$.4o])...
251, 64, 184, 236, 79, 248, 39, 104, 13, 162, 170, 106, // .@..O.'h...j
104, 149, 134, 7, 98, 225, 98, 169, 6, 138, 109, 212, // h...b.b...m.
201, 10, 46, 161, 34, 82, 73, 216, 15, 195, 29, 41, // ...."RI....)
83, 231, 202, 5, 200, 23, 222, 245, 74, 91, 42, 237, // S.......J[*.
126, 28, 22, 219, 185, 110, 74, 112, 70, 238, 154, 166, // ~....nJpF...
89, 64, 174, 171, 70, 49, 108, 208, 107, 192, 218, 141, // Y@..F1l.k...
18, 10, 241, 119, 197, 182, 24, 70, 77, 90, 218, 113, // ...w...FMZ.q
241, 86, 145, 78, 73, 101, 122, 218, 192, 24, 63, 143, // .V.NIez...?.
91, 213, 74, 96, 139, 49, 136, 36, 225, 92, 166, 163, // [.J`.1.$....
66, 184, 88, 77, 155, 151, 131, 86, 39, 201, 176, 36, // B.XM...V'..$
99, 44, 230, 37, 205, 160, 195, 223, 2, 186, 105, 204, // c,.%......i.
68, 83, 198, 79, 198, 229, 114, 23, 189, 174, 166, 165, // DS.O..r.....
103, 82, 82, 252, 92, 73, 156, 51, 234, 150, 149, 253, // gRR..I.3....
229, 179, 77, 23, 13, 203, 161, 40, 86, 163, 213, 43, // ..M....(V..+
55, 220, 2, 115, 143, 180, 177, 252, 53, 222, 189, 44, // 7..s....5..,
189, 30, 115, 175, 197, 22, 0, 72, 0, 233, 184, 76, // ..s....H...L
206, 156, 217, 99, 69, 118, 88, 21, 193, 181, 69, 232, // ...cEvX...E.
138, 44, 193, 126, 130, 155, 229, 162, 149, 189, 63, 166, // .,.~......?.
190, 109, 139, 125, 155, 147, 54, 238, 173, 87, 92, 90, // .m.}..6..W.Z
228, 16, 75, 50, 110, 122, 65, 81, 2, 46, 157, 238, // ..K2nzAQ....
73, 45, 84, 243, 178, 216, 108, 131, 84, 122, 202, 62, // I-T...l.Tz.>
82, 102, 53, 76, 247, 11, 203, 208, 90, 0, 251, 237, // Rf5L....Z...
44, 132, 66, 114, 251, 230, 89, 9, 61, 233, 201, 42, // ,.Br..Y.=..*
183, 139, 233, 148, 178, 71, 132, 89, 141, 14, 229, 150, // .....G.Y....
43, 52, 53, 74, 74, 210, 220, 120, 102, 26, 108, 67, // +45JJ..xf.lC
113, 20, 29, 155, 158, 228, 107, 39, 196, 72, 139, 175, // q.....k'.H..
229, 176, 44, 105, 5, 92, 16, 56, 175, 225, 222, 199, // ..,i...8....
148, 55, 108, 148, 26, 28, 237, 6, 246, 244, 248, 163, // .7l.........
119, 163, 171, 55, 18, 98, 60, 203, 192, 102, 80, 68, // w..7.b<..fPD
241, 40, 117, 42, 213, 89, 211, 30, 17, 231, 35, 202, // .(u*.Y....#.
157, 120, 255, 186, 46, 46, 234, 1, 157, 57, 188, 87, // .x.......9.W
152, 65, 59, 139, 38, 160, 69, 34, 203, 208, 187, 220, // .A;.&.E"....
177, 91, 79, 69, 102, 220, 185, 35, 62, 81, 226, 29, // .[OEf..#>Q..
238, 219, 24, 60, 217, 220, 155, 41, 208, 149, 141, 51, // ...<...)...3
90, 213, 243, 6, 173, 205, 168, 69, 107, 166, 127, 148, // Z......Ek...
65, 88, 220, 35, 247, 7, 165, 252, 240, 160, 60, 185, // AX.#......<.
232, 80, 51, 209, 131, 236, 35, 212, 149, 30, 106, 45, // .P3...#...j-
253, 219, 210, 208, 245, 125, 178, 133, 33, 233, 70, 121, // .....}..!.Fy
159, 163, 224, 79, 197, 234, 241, 158, 252, 212, 72, 197, // ...O......H.
253, 163, 83, 224, 124, 43, 172, 251, 77, 28, 193, 21, // ..S.|+..M...
153, 105, 70, 139, 127, 126, 63, 170, 87, 208, 173, 192, // .iF..~?.W...
235, 43, 152, 6, 241, 73, 150, 59, 221, 6, 55, 13, // .+...I.;..7.
87, 231, 148, 200, 66, 98, 151, 165, 155, 77, 148, 90, // W...Bb...M.Z
135, 212, 115, 145, 22, 69, 72, 237, 66, 102, 91, 134, // ..s..EH.Bf[.
240, 115, 8, 111, 54, 139, 90, 219, 144, 41, 159, 23, // .s.o6.Z..)..
165, 54, 81, 38, 154, 171, 12, 225, 167, 229, 88, 79, // .6Q&......XO
33, 83, 44, 167, 42, 66, 38, 143, 166, 138, 87, 95, // !S,.*B&...W_
78, 21, 237, 62, 15, 245, 163, 3, 198, 41, 249, 22, // N..>.....)..
221, 74, 89, 145, 225, 105, 252, 142, 224, 15, 15, 235, // .JY..i......
64, 244, 132, 205, 183, 254, 228, 94, 227, 82, 244, 50, // @......^.R.2
95, 112, 249, 84, 201, 201, 61, 74, 185, 212, 5, 63, // _p.T..=J...?
252, 15, 225, 232, 67, 124, 39, 7, 0, 0, 0 // ....C|'...
};
static const unsigned char v8[] = {
42, 32, 123, 32, 98, 111, 120, 45, 115, 105, 122, 105, // * { box-sizi 42, 32, 123, 32, 98, 111, 120, 45, 115, 105, 122, 105, // * { box-sizi
110, 103, 58, 32, 98, 111, 114, 100, 101, 114, 45, 98, // ng: border-b 110, 103, 58, 32, 98, 111, 114, 100, 101, 114, 45, 98, // ng: border-b
111, 120, 59, 32, 125, 10, 104, 116, 109, 108, 44, 32, // ox; }.html, 111, 120, 59, 32, 125, 10, 104, 116, 109, 108, 44, 32, // ox; }.html,
@@ -2178,14 +1546,10 @@ static const struct packed_file {
size_t size; size_t size;
time_t mtime; time_t mtime;
} packed_files[] = { } packed_files[] = {
{"/web_root/preact.min.js.gz", v1, sizeof(v1), 1660165083}, {"/web_root/index.html", v1, sizeof(v1), 1692212839},
{"/web_root/main.js.gz", v2, sizeof(v2), 1660165083}, {"/web_root/main.js", v2, sizeof(v2), 1692212839},
{"/web_root/main.js", v3, sizeof(v3), 1660586478}, {"/web_root/preact.min.js", v3, sizeof(v3), 1692212839},
{"/web_root/preact.min.js", v4, sizeof(v4), 1660586478}, {"/web_root/style.css", v4, sizeof(v4), 1692212839},
{"/web_root/index.html", v5, sizeof(v5), 1660586478},
{"/web_root/index.html.gz", v6, sizeof(v6), 1660165083},
{"/web_root/style.css.gz", v7, sizeof(v7), 1660165083},
{"/web_root/style.css", v8, sizeof(v8), 1660586478},
{NULL, NULL, 0, 0} {NULL, NULL, 0, 0}
}; };
@@ -2193,11 +1557,9 @@ static int scmp(const char *a, const char *b) {
while (*a && (*a == *b)) a++, b++; while (*a && (*a == *b)) a++, b++;
return *(const unsigned char *) a - *(const unsigned char *) b; return *(const unsigned char *) a - *(const unsigned char *) b;
} }
const char *mg_unlist(size_t no);
const char *mg_unlist(size_t no) { const char *mg_unlist(size_t no) {
return packed_files[no].name; return packed_files[no].name;
} }
const char *mg_unpack(const char *path, size_t *size, time_t *mtime);
const char *mg_unpack(const char *name, size_t *size, time_t *mtime) { const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {
const struct packed_file *p; const struct packed_file *p;
for (p = packed_files; p->name != NULL; p++) { for (p = packed_files; p->name != NULL; p++) {
@@ -7,4 +7,4 @@ component_compile_options(-DMG_ENABLE_LINES)
component_compile_options(-DMG_ENABLE_PACKED_FS) component_compile_options(-DMG_ENABLE_PACKED_FS)
component_compile_options(-DHTTP_URL="http://0.0.0.0:80") component_compile_options(-DHTTP_URL="http://0.0.0.0:80")
component_compile_options(-DHTTPS_URL="https://0.0.0.0:443") component_compile_options(-DHTTPS_URL="https://0.0.0.0:443")
component_compile_options(-DMG_ENABLE_MBEDTLS=0) # change to '1' to enable TLS component_compile_options(-DMG_TLS=MG_TLS_NONE) # change to 'MG_TLS_MBED' to enable TLS
@@ -27,7 +27,7 @@ static void cb2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
} else if (ev == MG_EV_HTTP_MSG) { } else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = ev_data; // Print HTTP response struct mg_http_message *hm = ev_data; // Print HTTP response
MG_INFO(("Fetched:\n%.*s", (int) hm->message.len, hm->message.ptr)); MG_INFO(("Fetched:\n%.*s", (int) hm->message.len, hm->message.ptr));
c->is_closing = 1; c->is_draining = 1;
} }
} }
+27 -15
View File
@@ -1,8 +1,8 @@
// Copyright (c) 2020 Cesanta Software Limited // Copyright (c) 2020 Cesanta Software Limited
// All rights reserved // All rights reserved
// //
// Streaming upload example. Demonstrates how to use MG_EV_HTTP_CHUNK events // Streaming upload example. Demonstrates how to use MG_EV_READ events
// to send large payload in smaller chunks. To test, use curl utility: // to get large payload in smaller chunks. To test, use curl utility:
// //
// curl http://localhost:8000/upload?name=a.txt --data-binary @large_file.txt // curl http://localhost:8000/upload?name=a.txt --data-binary @large_file.txt
@@ -12,21 +12,33 @@
// /upload - Saves the next file chunk // /upload - Saves the next file chunk
// all other URI - serves web_root/ directory // all other URI - serves web_root/ directory
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (ev == MG_EV_READ) {
if (ev == MG_EV_HTTP_CHUNK && mg_http_match_uri(hm, "/upload")) { // Parse the incoming data ourselves. If we can parse the request,
MG_INFO(("Got chunk len %lu", (unsigned long) hm->chunk.len)); // store two size_t variables in the c->data: expected len and recv len.
MG_INFO(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr)); size_t *data = (size_t *) c->data;
// MG_INFO(("Chunk data:\n%.*s", (int) hm->chunk.len, hm->chunk.ptr)); if (data[0]) { // Already parsed, simply print received data
mg_http_delete_chunk(c, hm); data[1] += c->recv.len;
if (hm->chunk.len == 0) { MG_INFO(("Got chunk len %lu, %lu total", c->recv.len, data[1]));
MG_INFO(("Last chunk received, sending response")); c->recv.len = 0; // And cleanup the receive buffer. Streaming!
mg_http_reply(c, 200, "", "ok (chunked)\n"); if (data[1] >= data[0]) mg_http_reply(c, 200, "", "ok\n");
} else {
struct mg_http_message hm;
int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
if (n < 0) mg_error(c, "Bad response");
if (n > 0) {
if (mg_http_match_uri(&hm, "/upload")) {
MG_INFO(("Got chunk len %lu", c->recv.len - n));
data[0] = hm.body.len;
data[1] = c->recv.len - n;
if (data[1] >= data[0]) mg_http_reply(c, 200, "", "ok\n");
} else {
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
mg_http_serve_dir(c, &hm, &opts);
}
}
} }
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
mg_http_serve_dir(c, hm, &opts);
} }
(void) fn_data; (void) fn_data, (void) ev_data;
} }
int main(void) { int main(void) {
@@ -19,12 +19,10 @@
of RAM to buffer everything. of RAM to buffer everything.
<br><br> <br><br>
In order to upload large files to a memory-constrained system, use In order to upload large files to a memory-constrained system, use
<code>MG_EV_HTTP_CHUNK</code> on a server side. It fires when <code>MG_EV_READ</code> on a server side. It fires when
a partial HTTP message has been received (or a chunk-encoded chunk). a partial HTTP message has been received. We discourage this method,
Use <code>mg_http_delete_chunk()</code> to release chunk memory. since the client can send chunked-encoded data. Instead, please
When 0-sized chunk is received, that's the end of the message. split the upload into smaller pieces and send sequentially.
Use <code>MG_MAX_RECV_SIZE</code> build constant to limit
maximum chunk size on a server side.
<br><br> <br><br>
In this example, JavaScript code uses "fetch()" browser API. In this example, JavaScript code uses "fetch()" browser API.
Uploaded file is not saved, but rather printed by server side. Uploaded file is not saved, but rather printed by server side.
+10 -3
View File
@@ -1,14 +1,16 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
PACK ?= ./pack # Packing executable
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -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 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 PROG ?= example.exe # Use .exe suffix for the binary
PACK = pack.exe # Packing executable
CC = gcc # Use MinGW gcc compiler CC = gcc # Use MinGW gcc compiler
CFLAGS += -lws2_32 # Link against Winsock library CFLAGS += -lws2_32 # Link against Winsock library
DELETE = cmd /C del /Q /F /S # Command prompt command to delete files DELETE = cmd /C del /Q /F /S # Command prompt command to delete files
@@ -23,7 +25,12 @@ $(PROG): $(SOURCES) # Build program from sources
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) $(OUT) $(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) $(OUT)
clean: # Cleanup. Delete built program and all build artifacts clean: # Cleanup. Delete built program and all build artifacts
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM mbedtls $(DELETE) $(PROG) *.o *.obj *.exe *.dSYM mbedtls $(PACK)
# Generate packed filesystem for serving cert
packed_fs.c: $(wildcard certs/*) Makefile
$(CC) ../../test/pack.c -o $(PACK)
$(PACK) $(wildcard certs/*) > $@
# see https://mongoose.ws/tutorials/tls/#how-to-build for TLS build options # see https://mongoose.ws/tutorials/tls/#how-to-build for TLS build options
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+1
View File
@@ -0,0 +1 @@
../../../test/data/ca.pem
+3 -3
View File
@@ -28,9 +28,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
// Connected to server. Extract host name from URL // Connected to server. Extract host name from URL
struct mg_str host = mg_url_host(s_url); struct mg_str host = mg_url_host(s_url);
// If s_url is https://, tell client connection to use TLS
if (mg_url_is_ssl(s_url)) { if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host}; struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
@@ -49,7 +49,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
// Response is received. Print it // Response is received. Print it
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
printf("%.*s", (int) hm->message.len, hm->message.ptr); printf("%.*s", (int) hm->message.len, hm->message.ptr);
c->is_closing = 1; // Tell mongoose to close this connection c->is_draining = 1; // Tell mongoose to close this connection
*(bool *) fn_data = true; // Tell event loop to stop *(bool *) fn_data = true; // Tell event loop to stop
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
*(bool *) fn_data = true; // Error, tell event loop to stop *(bool *) fn_data = true; // Error, tell event loop to stop
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -1,13 +1,13 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
#CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -DMG_ENABLE_PACKED_FS=1
// see tutorial at https://mongoose.ws/tutorials/http-proxy-client/ # See tutorial at https://mongoose.ws/tutorials/http-proxy-client/
ARGS ?= 167.235.63.238:3128 http://info.cern.ch/ # default call arguments ARGS ?= 167.235.63.238:3128 http://info.cern.ch/ # default call arguments
ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+12 -9
View File
@@ -20,15 +20,17 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
} else if (ev == MG_EV_CONNECT) { } else if (ev == MG_EV_CONNECT) {
// Proxy TCP connection established. Send CONNECT request // Proxy TCP connection established. Send CONNECT request
struct mg_str host = mg_url_host(url); struct mg_str host = mg_url_host(url);
if (mg_url_is_ssl(url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = host};
mg_tls_init(c, &opts);
}
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
mg_printf(c, "CONNECT %.*s:%hu HTTP/1.1\r\nHost: %.*s:%hu\r\n\r\n", mg_printf(c, "CONNECT %.*s:%hu HTTP/1.1\r\nHost: %.*s:%hu\r\n\r\n",
(int) host.len, host.ptr, mg_url_port(url), (int) host.len, (int) host.len, host.ptr, mg_url_port(url), (int) host.len,
host.ptr, mg_url_port(url)); host.ptr, mg_url_port(url));
// If target URL is SSL/TLS, command client connection to use TLS
if (mg_url_is_ssl(url)) {
struct mg_tls_opts opts = {.ca = "ca.pem"};
mg_tls_init(c, &opts);
}
} else if (!connected && ev == MG_EV_READ) { } else if (!connected && ev == MG_EV_READ) {
struct mg_http_message hm; struct mg_http_message hm;
int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm); int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
@@ -40,10 +42,11 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
("Connected to proxy, status: %.*s", (int) hm.uri.len, hm.uri.ptr)); ("Connected to proxy, status: %.*s", (int) hm.uri.len, hm.uri.ptr));
mg_iobuf_del(&c->recv, 0, n); mg_iobuf_del(&c->recv, 0, n);
// Send request to the target server // Send request to the target server
mg_printf(c, "GET %s HTTP/1.0\r\n" mg_printf(c,
"Host: %.*s\r\n" "GET %s HTTP/1.0\r\n"
"\r\n", "Host: %.*s\r\n"
mg_url_uri(url), (int) host.len, host.ptr); "\r\n",
mg_url_uri(url), (int) host.len, host.ptr);
} }
} }
} }
+1
View File
@@ -0,0 +1 @@
../http-client/packed_fs.c
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+43 -5
View File
@@ -18,17 +18,55 @@ static const char *s_http_addr = "http://0.0.0.0:8000"; // HTTP port
static const char *s_https_addr = "https://0.0.0.0:8443"; // HTTPS port static const char *s_https_addr = "https://0.0.0.0:8443"; // HTTPS port
static const char *s_root_dir = "."; static const char *s_root_dir = ".";
// Self signed certificates
// https://mongoose.ws/documentation/tutorials/tls/#self-signed-certificates
#ifdef TLS_TWOWAY
static const char *s_tls_ca =
"-----BEGIN CERTIFICATE-----\n"
"MIIBqjCCAU+gAwIBAgIUESoOPGqMhf9uarzblVFwzrQweMcwCgYIKoZIzj0EAwIw\n"
"RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
"YTESMBAGA1UEAwwJVGVzdCBSb290MCAXDTIwMDUwOTIxNTE0NFoYDzIwNTAwNTA5\n"
"MjE1MTQ0WjBEMQswCQYDVQQGEwJJRTEPMA0GA1UEBwwGRHVibGluMRAwDgYDVQQK\n"
"DAdDZXNhbnRhMRIwEAYDVQQDDAlUZXN0IFJvb3QwWTATBgcqhkjOPQIBBggqhkjO\n"
"PQMBBwNCAAQsq9ECZiSW1xI+CVBP8VDuUehVA166sR2YsnJ5J6gbMQ1dUCH/QvLa\n"
"dBdeU7JlQcH8hN5KEbmM9BnZxMor6ussox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud\n"
"DwQEAwIBrjAKBggqhkjOPQQDAgNJADBGAiEAnHFsAIwGQQyRL81B04dH6d86Iq0l\n"
"fL8OKzndegxOaB0CIQCPwSIwEGFdURDqCC0CY2dnMrUGY5ZXu3hHCojZGS7zvg==\n"
"-----END CERTIFICATE-----\n";
#endif
static const char *s_tls_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw\n"
"RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
"YTESMBAGA1UEAwwJVGVzdCBSb290MB4XDTIwMDUwOTIxNTE0OVoXDTMwMDUwOTIx\n"
"NTE0OVowETEPMA0GA1UEAwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n"
"QgAEkuBGnInDN6l06zVVQ1VcrOvH5FDu9MC6FwJc2e201P8hEpq0Q/SJS2nkbSuW\n"
"H/wBTTBaeXN2uhlBzMUWK790KKMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gw\n"
"EwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDSQAwRgIhAPo6xx7LjCdZ\n"
"QY133XvLjAgVFrlucOZHONFVQuDXZsjwAiEAzHBNligA08c5U3SySYcnkhurGg50\n"
"BllCI0eYQ9ggp/o=\n"
"-----END CERTIFICATE-----\n";
static const char *s_tls_key =
"-----BEGIN PRIVATE KEY-----\n"
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w\n"
"kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70\n"
"wLoXAlzZ7bTU/yESmrRD9IlLaeRtK5Yf/AFNMFp5c3a6GUHMxRYrv3Qo\n"
"-----END PRIVATE KEY-----\n";
// We use the same event handler function for HTTP and HTTPS connections // We use the same event handler function for HTTP and HTTPS connections
// fn_data is NULL for plain HTTP, and non-NULL for HTTPS // fn_data is NULL for plain HTTP, and non-NULL for HTTPS
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_ACCEPT && fn_data != NULL) { if (ev == MG_EV_ACCEPT && fn_data != NULL) {
struct mg_tls_opts opts = { struct mg_tls_opts opts = {
//.ca = "ca.pem", // Uncomment to enable two-way SSL #ifdef TLS_TWOWAY
.cert = "server.pem", // Certificate PEM file .ca = mg_str(s_tls_ca),
.certkey = "server.pem", // This pem contains both cert and key #endif
}; .cert = mg_str(s_tls_cert),
.key = mg_str(s_tls_key)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_MSG) { }
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_http_match_uri(hm, "/api/stats")) { if (mg_http_match_uri(hm, "/api/stats")) {
// Print some statistics about currently established connections // Print some statistics about currently established connections
+2 -2
View File
@@ -1,11 +1,11 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_IO_SIZE=128 -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_IO_SIZE=128 -DMG_ENABLE_LINES=1 -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 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 PROG ?= example.exe # Use .exe suffix for the binary
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+5 -4
View File
@@ -10,7 +10,7 @@
#include "mongoose.h" #include "mongoose.h"
static const char *s_backend_url = static const char *s_backend_url =
#if MG_ENABLE_MBEDTLS || MG_ENABLE_OPENSSL #if MG_TLS
"https://cesanta.com"; "https://cesanta.com";
#else #else
"http://info.cern.ch"; "http://info.cern.ch";
@@ -37,7 +37,7 @@ static void forward_request(struct mg_http_message *hm,
} }
static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_connection *c2 = fn_data; struct mg_connection *c2 = (struct mg_connection *) fn_data;
if (ev == MG_EV_READ) { if (ev == MG_EV_READ) {
// All incoming data from the backend, forward to the client // All incoming data from the backend, forward to the client
if (c2 != NULL) mg_send(c2, c->recv.buf, c->recv.len); if (c2 != NULL) mg_send(c2, c->recv.buf, c->recv.len);
@@ -59,12 +59,13 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
mg_error(c, "Cannot create backend connection"); mg_error(c, "Cannot create backend connection");
} else { } else {
if (mg_url_is_ssl(s_backend_url)) { if (mg_url_is_ssl(s_backend_url)) {
struct mg_tls_opts opts = {.ca = "ca.pem"}; struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_backend_url)};
mg_tls_init(c2, &opts); mg_tls_init(c2, &opts);
} }
c->fn_data = c2; c->fn_data = c2;
forward_request(hm, c2); forward_request(hm, c2);
c->is_resp = 0; // process further msgs in keep-alive connection c->is_resp = 0; // process further msgs in keep-alive connection
c2->is_hexdumping = 1; c2->is_hexdumping = 1;
} }
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
+1
View File
@@ -0,0 +1 @@
../http-client/packed_fs.c
+2 -2
View File
@@ -1,11 +1,11 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -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 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 PROG ?= example.exe # Use .exe suffix for the binary
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+40 -29
View File
@@ -1,14 +1,12 @@
// Copyright (c) 2021 Cesanta Software Limited // Copyright (c) 2021 Cesanta Software Limited
// All rights reserved // All rights reserved
// //
// Example HTTP client. // Example streaming HTTP client.
// Instead of buffering the whole HTTP response in memory and wait for the // The default HTTP handler waits until the whole HTTP message is buffered in
// MG_EV_HTTP_MSG event, this client catches MG_EV_HTTP_CHUNK events and // c->recv IO buffer. It can be large. This example shows how to receive
// prints them. This is useful to download large content without spooling // a potentially large response in chunks by handling the MG_EV_READ events.
// everything to memory, or catch chunked content.
// //
// You can change `s_url` from the command line by executing: ./example YOUR_URL // You can change `s_url` from the command line by executing: ./example YOUR_URL
//
// To enable SSL/TLS, see https://mongoose.ws/tutorials/tls/#how-to-build // To enable SSL/TLS, see https://mongoose.ws/tutorials/tls/#how-to-build
#include "mongoose.h" #include "mongoose.h"
@@ -21,13 +19,11 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_CONNECT) { if (ev == MG_EV_CONNECT) {
// Connected to server. Extract host name from URL // Connected to server. Extract host name from URL
struct mg_str host = mg_url_host(s_url); struct mg_str host = mg_url_host(s_url);
// If s_url is https://, tell client connection to use TLS
if (mg_url_is_ssl(s_url)) { if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host}; struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = host};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
// Send request // Send request
mg_printf(c, mg_printf(c,
"GET %s HTTP/1.1\r\n" "GET %s HTTP/1.1\r\n"
@@ -36,33 +32,48 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
"Host: %.*s\r\n" "Host: %.*s\r\n"
"\r\n", "\r\n",
mg_url_uri(s_url), (int) host.len, host.ptr); mg_url_uri(s_url), (int) host.len, host.ptr);
} else if (ev == MG_EV_HTTP_CHUNK) { } else if (ev == MG_EV_READ) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; // Parse the incoming data ourselves. If we can parse the request,
fwrite(hm->chunk.ptr, 1, hm->chunk.len, stdout); // store two size_t variables in the c->data: expected len and recv len.
// fprintf(stderr, "c %u\n", (unsigned) hm->chunk.len); size_t *data = (size_t *) c->data;
mg_http_delete_chunk(c, hm); if (data[0]) { // Already parsed, simply print received data
if (hm->chunk.len == 0) *(bool *) fn_data = true; // Last chunk data[1] += c->recv.len;
} else if (ev == MG_EV_HTTP_MSG) { fwrite(c->recv.buf, 1, c->recv.len, stdout);
// Response is received. Print it c->recv.len = 0; // And cleanup the receive buffer. Streming!
struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (data[1] >= data[0]) * (bool *) fn_data = true;
fwrite(hm->body.ptr, 1, hm->body.len, stdout); } else {
c->is_closing = 1; // Tell mongoose to close this connection struct mg_http_message hm;
*(bool *) fn_data = true; // Tell event loop to stop int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
if (n < 0) mg_error(c, "Bad response");
if (n > 0) {
fwrite(c->recv.buf + n, 1, c->recv.len - n, stdout); // Print body
data[0] = n + hm.body.len;
data[1] = c->recv.len;
c->recv.len = 0; // Cleanup receive buffer
if (data[1] >= data[0]) * (bool *) fn_data = true;
}
}
} else if (ev == MG_EV_CLOSE) {
*(bool *) fn_data = true; // tell event loop to stop
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
*(bool *) fn_data = true; // Error, tell event loop to stop *(bool *) fn_data = true; // Error, tell event loop to stop
} }
(void) ev_data;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct mg_mgr mgr; // Event manager struct mg_mgr mgr; // Event manager
bool done = false; // Event handler flips it to true bool done = false; // Event handler flips it to true
const char *log_level = getenv("V"); // Log level const char *log_level = getenv("V"); // Log level
if (log_level == NULL) log_level = "3"; // If not set, set to DEBUG
mg_log_set(atoi(log_level)); // Set to 0 to disable debug log mg_mgr_init(&mgr); // Initialise event manager
if (argc > 1) s_url = argv[1]; // Use URL from command line if (log_level == NULL) log_level = "2"; // If not set, set to DEBUG
mg_mgr_init(&mgr); // Initialise event manager mg_log_set(atoi(log_level)); // Set to 0 to disable debug log
if (argc > 1) s_url = argv[1]; // Use URL from command line
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
mg_mgr_free(&mgr); // Free resources mg_mgr_free(&mgr); // Free resources
return 0; return 0;
} }
+1
View File
@@ -0,0 +1 @@
../http-client/packed_fs.c
@@ -0,0 +1,53 @@
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wconversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include
CFLAGS += -D__SAME54P20A__ -Icmsis_sam/include
CFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=softfp
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
SOURCES = main.c syscalls.c startup.c
# Mongoose-specific source code files and build options. See https://mongoose.ws/documentation/#build-options
SOURCES += mongoose.c net.c packed_fs.c
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_LINES=1
CFLAGS += -DMG_ENABLE_DRIVER_SAME54=1 -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1 $(CFLAGS_EXTRA)
# Example specific build options. See README.md
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\"
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F
else
RM = rm -rf
endif
build: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
firmware.elf: cmsis_core cmsis_sam hal.h link.ld Makefile $(SOURCES)
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
flash: firmware.bin
bossac -p /dev/cu.usb* -w -v -b $<
cmsis_core:
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
cmsis_sam:
curl -sL https://packs.download.microchip.com/Microchip.SAME54_DFP.3.8.234.pack -o $@.zip
mkdir $@ && cd $@ && unzip ../$@.zip
# Automated test via https://vcon.io/automated-firmware-tests/. Set VCON_API_KEY and update DEVICE_URL
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/9
update: firmware.bin
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
test update: CFLAGS += -DUART_DEBUG=USART1
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
clean:
$(RM) firmware.* cmsis_core cmsis_sam *.zip
@@ -0,0 +1,219 @@
// Copyright (c) 2022 Cesanta Software Limited
// SPDX-License-Identifier: MIT
//
// https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/DataSheets/SAM-D5x-E5x-Family-Data-Sheet-DS60001507.pdf
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
#ifndef LED_PIN
#define LED_PIN PIN('C', 18)
#endif
#ifndef BUTTON_PIN
#define BUTTON_PIN PIN('B', 31)
#endif
#ifndef UART_DEBUG
#define UART_DEBUG USART1
#endif
#pragma once
#include <sam.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define BIT(x) (1UL << (x))
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
static inline void spin(volatile uint32_t count) {
while (count--) (void) 0;
}
static inline uint32_t clock_sys_freq(void) {
return 48000000U;
}
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE };
enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN };
#define GPIO(N) ((port_group_registers_t *) (PORT_BASE_ADDRESS + 0x80 * (N)))
typedef port_group_registers_t GPIO_TypeDef;
static inline GPIO_TypeDef *gpio_bank(uint16_t pin) {
return GPIO(PINBANK(pin));
}
static inline void gpio_toggle(uint16_t pin) {
gpio_bank(pin)->PORT_OUTTGL = BIT(PINNO(pin));
}
static inline bool gpio_read(uint16_t pin) {
return gpio_bank(pin)->PORT_IN & BIT(PINNO(pin));
}
static inline void gpio_write(uint16_t pin, bool val) {
GPIO_TypeDef *gpio = gpio_bank(pin);
if (val) {
gpio->PORT_OUTSET = BIT(PINNO(pin));
} else {
gpio->PORT_OUTCLR = BIT(PINNO(pin));
}
}
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
uint8_t speed, uint8_t pull, uint8_t af) {
(void) type, (void) speed, (void) pull, (void) af;
GPIO_TypeDef *gpio = gpio_bank(pin);
uint32_t mask = BIT(PINNO(pin));
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk;
if (mode == GPIO_MODE_INPUT) {
gpio->PORT_DIRCLR = mask;
} else {
gpio->PORT_DIRSET = mask;
}
}
static inline void gpio_input(uint16_t pin) {
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
GPIO_PULL_NONE, 0);
}
static inline void gpio_output(uint16_t pin) {
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
GPIO_PULL_NONE, 0);
}
typedef sercom_usart_int_registers_t USART_TypeDef;
#define USART1 ((USART_TypeDef *) SERCOM0_BASE_ADDRESS)
#define USART2 ((USART_TypeDef *) SERCOM1_BASE_ADDRESS)
#define USART3 ((USART_TypeDef *) SERCOM2_BASE_ADDRESS)
static inline bool uart_init(USART_TypeDef *uart, unsigned long baud) {
uint16_t rx = 0, tx = 0; // Pins
uint8_t rx_mux = 0, tx_mux = 0;
if (uart == USART1) {
MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM0_Msk;
GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_CORE] =
GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN_Msk;
GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_SLOW] =
GCLK_PCHCTRL_GEN_GCLK3 | GCLK_PCHCTRL_CHEN_Msk;
tx = PIN('A', 4), rx = PIN('A', 5);
rx_mux = MUX_PA05D_SERCOM0_PAD1, tx_mux = MUX_PA04D_SERCOM0_PAD0;
} else if (uart == USART2) {
MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM1_Msk;
tx = PIN('C', 27), rx = PIN('C', 28);
} else if (uart == USART3) {
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_SERCOM2_Msk;
tx = PIN('A', 9), rx = PIN('A', 8);
} else {
return false;
}
gpio_bank(rx)->PORT_WRCONFIG =
PORT_WRCONFIG_PMUX(rx_mux) | PORT_WRCONFIG_WRPMUX(1) |
PORT_WRCONFIG_PMUXEN(1) | PORT_WRCONFIG_WRPINCFG(1) | BIT(PINNO(rx));
gpio_bank(tx)->PORT_WRCONFIG =
PORT_WRCONFIG_PMUX(tx_mux) | PORT_WRCONFIG_WRPMUX(1) |
PORT_WRCONFIG_PMUXEN(1) | PORT_WRCONFIG_WRPINCFG(1) | BIT(PINNO(tx));
uart->SERCOM_CTRLA = SERCOM_USART_INT_CTRLA_DORD(1) |
SERCOM_USART_INT_CTRLA_MODE(1 /* INT_CLK */) |
SERCOM_USART_INT_CTRLA_RXPO(1 /* PAD1 */) |
SERCOM_USART_INT_CTRLA_TXPO(0 /* PAD0 */) |
SERCOM_USART_INT_CTRLA_SAMPR(1);
uart->SERCOM_BAUD = (uint16_t) (clock_sys_freq() / (16 * baud));
uart->SERCOM_CTRLB = SERCOM_USART_INT_CTRLB_RXEN(1) |
SERCOM_USART_INT_CTRLB_TXEN(1) |
SERCOM_USART_INT_CTRLB_CHSIZE(0);
while (uart->SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_CTRLB_Msk) spin(1);
uart->SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_ENABLE(1);
while (uart->SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_ENABLE_Msk) spin(1);
return true;
}
static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
while (!(uart->SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_DRE_Msk)) spin(1);
uart->SERCOM_DATA = byte;
}
static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
}
static inline bool uart_read_ready(USART_TypeDef *uart) {
return (uart->SERCOM_INTFLAG & SERCOM_USART_EXT_INTFLAG_RXC_Msk);
}
static inline uint8_t uart_read_byte(USART_TypeDef *uart) {
return (uint8_t) (uart->SERCOM_DATA & 255U);
}
static inline void rng_init(void) {
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_TRNG_Msk;
TRNG_REGS->TRNG_CTRLA = TRNG_CTRLA_ENABLE_Msk;
}
static inline uint32_t rng_read(void) {
while ((TRNG_REGS->TRNG_INTFLAG & TRNG_INTFLAG_DATARDY_Msk) == 0) spin(1);
return TRNG_REGS->TRNG_DATA;
}
#define UID_BASE_W0 0x008061FC // Word 0 location of the 128-bit chip ID
#define UID_BASE_W1_3 0x00806010 // Words 1-3 location of the 128-bit chip ID
#define UUID(n) ((n >= 0 && n <= 3) ? \
(((uint8_t *) UID_BASE_W0)[n]) : \
(((uint8_t *) UID_BASE_W1_3)[n - 4]))
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
{ \
2, UUID(0) ^ UUID(1) ^ UUID(2), UUID(3) ^ UUID(4) ^ UUID(5), \
UUID(6) ^ UUID(7) ^ UUID(8), UUID(9) ^ UUID(10) ^ UUID(11), \
UUID(12) ^ UUID(13) ^ UUID(14) ^ UUID(15) \
}
static inline bool timer_expired(volatile uint64_t *t, uint64_t prd,
uint64_t now) {
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
if (*t > now) return false; // Not expired yet, return
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
return true; // Expired, return true
}
static inline void clock_init(void) {
SCB->CPACR |= (15U << 20); // Enable FPU
SysTick_Config(clock_sys_freq() / 1000); // Sys tick every 1ms
}
static inline void gpio_set_irq_handler(uint16_t pin, void (*fn)(void *),
void *arg) {
(void) pin, (void) fn, (void) arg;
}
static inline void ethernet_init(void) {
uint16_t pins[] = {PIN('A', 12), PIN('A', 13), PIN('A', 14), PIN('A', 15),
PIN('A', 17), PIN('A', 18), PIN('A', 19), PIN('C', 11),
PIN('C', 12), PIN('C', 20)};
uint32_t af[] = {MUX_PA12L_GMAC_GRX1, MUX_PA13L_GMAC_GRX0,
MUX_PA14L_GMAC_GTXCK, MUX_PA15L_GMAC_GRXER,
MUX_PA17L_GMAC_GTXEN, MUX_PA18L_GMAC_GTX0,
MUX_PA19L_GMAC_GTX1, MUX_PC11L_GMAC_GMDC,
MUX_PC12L_GMAC_GMDIO, MUX_PC20L_GMAC_GRXDV};
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk;
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
int bank = PINBANK(pins[i]), no = PINNO(pins[i]);
PORT_REGS->GROUP[bank].PORT_PINCFG[no] |= PORT_PINCFG_PMUXEN_Msk;
volatile uint8_t *m = &PORT_REGS->GROUP[bank].PORT_PMUX[no / 2], v = m[0];
if (no & 1) {
m[0] = (uint8_t) ((v & ~0xf0) | PORT_PMUX_PMUXO(af[i]));
} else {
m[0] = (uint8_t) ((v & ~0x0f) | PORT_PMUX_PMUXE(af[i]));
}
}
PORT_REGS->GROUP[0].PORT_PINCFG[17] |= PORT_PINCFG_DRVSTR_Msk;
PORT_REGS->GROUP[0].PORT_PINCFG[18] |= PORT_PINCFG_DRVSTR_Msk;
PORT_REGS->GROUP[0].PORT_PINCFG[19] |= PORT_PINCFG_DRVSTR_Msk;
// Reset PHY
uint16_t phy_pin = PIN('C', 21);
gpio_output(phy_pin);
gpio_write(phy_pin, false);
spin(999);
gpio_write(phy_pin, true);
spin(999);
}
@@ -0,0 +1,25 @@
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x00000000, LENGTH = 1024k
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
}
_estack = ORIGIN(sram) + LENGTH(sram);
SECTIONS {
.vectors : { FILL(256) KEEP(*(.vectors)) } > flash
.text : { *(.text*) } > flash
.rodata : { *(.rodata*) } > flash
.data : {
_sdata = .;
*(.first_data)
*(.data SORT(.data.*))
_edata = .;
} > sram AT > flash
_sidata = LOADADDR(.data);
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram
. = ALIGN(8);
_end = .;
}
@@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: 2022-2023 Cesanta Software Limited
// SPDX-License-Identifier: MIT
#include "hal.h"
#include "mongoose.h"
#include "net.h"
#define BLINK_PERIOD_MS 500 // LED blinking period in millis
#define LOG_PERIOD_MS 1000 // Info log period in millis
void SystemInit(void) { // Called automatically by startup code
clock_init();
rng_init();
}
static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++;
}
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
return s_ticks; // Return number of milliseconds since boot
}
void mg_random(void *buf, size_t len) { // Use on-board RNG
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
uint32_t r = rng_read();
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
}
static void timer_fn(void *arg) {
struct mg_tcpip_if *ifp = arg; // show network stats
const char *names[] = {"down", "up", "req", "ready"};
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
ifp->ndrop, ifp->nerr));
}
int main(void) {
gpio_input(BUTTON_PIN);
gpio_output(LED_PIN);
uart_init(UART_DEBUG, 115200);
ethernet_init();
MG_INFO(("Starting, CPU freq %g MHz", (double) clock_sys_freq() / 1000000));
struct mg_mgr mgr; // Initialise
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level
// Initialise Mongoose network stack
struct mg_tcpip_driver_same54_data driver_data = {.mdc_cr = 5};
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC()/*{2, 3, 4, 5, 6, 7}*/,
// Uncomment below for static configuration:
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
.driver = &mg_tcpip_driver_same54,
.driver_data = &driver_data};
mg_tcpip_init(&mgr, &mif);
mg_timer_add(&mgr, LOG_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
while (mif.state != MG_TCPIP_STATE_READY) {
mg_mgr_poll(&mgr, 0);
}
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
}
return 0;
}
@@ -0,0 +1 @@
../../../../mongoose.c
@@ -0,0 +1 @@
../../../../mongoose.h
@@ -0,0 +1 @@
../../../device-dashboard/net.c
@@ -0,0 +1 @@
../../../device-dashboard/net.h
@@ -0,0 +1 @@
../../../device-dashboard/packed_fs.c
@@ -0,0 +1,332 @@
// SPDX-FileCopyrightText: 2022-2023 Cesanta Software Limited
// SPDX-License-Identifier: MIT
#include "hal.h"
void Reset_Handler(void); // Defined below
void Dummy_Handler(void); // Defined below
void SysTick_Handler(void); // Defined in main.c
void SystemInit(void); // Defined in main.c, called by reset handler
void _estack(void); // Defined in link.ld
#define WEAK_ALIAS __attribute__((weak, alias("Default_Handler")))
WEAK_ALIAS void NMI_Handler(void);
WEAK_ALIAS void HardFault_Handler(void);
WEAK_ALIAS void MemoryManagement_Handler(void);
WEAK_ALIAS void BusFault_Handler(void);
WEAK_ALIAS void UsageFault_Handler(void);
WEAK_ALIAS void SVCall_Handler(void);
WEAK_ALIAS void DebugMonitor_Handler(void);
WEAK_ALIAS void PendSV_Handler(void);
WEAK_ALIAS void SysTick_Handler(void);
WEAK_ALIAS void PM_Handler(void);
WEAK_ALIAS void MCLK_Handler(void);
WEAK_ALIAS void OSCCTRL_XOSC0_Handler(void);
WEAK_ALIAS void OSCCTRL_XOSC1_Handler(void);
WEAK_ALIAS void OSCCTRL_DFLL_Handler(void);
WEAK_ALIAS void OSCCTRL_DPLL0_Handler(void);
WEAK_ALIAS void OSCCTRL_DPLL1_Handler(void);
WEAK_ALIAS void OSC32KCTRL_Handler(void);
WEAK_ALIAS void SUPC_OTHER_Handler(void);
WEAK_ALIAS void SUPC_BODDET_Handler(void);
WEAK_ALIAS void WDT_Handler(void);
WEAK_ALIAS void RTC_Handler(void);
WEAK_ALIAS void EIC_EXTINT_0_Handler(void);
WEAK_ALIAS void EIC_EXTINT_1_Handler(void);
WEAK_ALIAS void EIC_EXTINT_2_Handler(void);
WEAK_ALIAS void EIC_EXTINT_3_Handler(void);
WEAK_ALIAS void EIC_EXTINT_4_Handler(void);
WEAK_ALIAS void EIC_EXTINT_5_Handler(void);
WEAK_ALIAS void EIC_EXTINT_6_Handler(void);
WEAK_ALIAS void EIC_EXTINT_7_Handler(void);
WEAK_ALIAS void EIC_EXTINT_8_Handler(void);
WEAK_ALIAS void EIC_EXTINT_9_Handler(void);
WEAK_ALIAS void EIC_EXTINT_10_Handler(void);
WEAK_ALIAS void EIC_EXTINT_11_Handler(void);
WEAK_ALIAS void EIC_EXTINT_12_Handler(void);
WEAK_ALIAS void EIC_EXTINT_13_Handler(void);
WEAK_ALIAS void EIC_EXTINT_14_Handler(void);
WEAK_ALIAS void EIC_EXTINT_15_Handler(void);
WEAK_ALIAS void FREQM_Handler(void);
WEAK_ALIAS void NVMCTRL_0_Handler(void);
WEAK_ALIAS void NVMCTRL_1_Handler(void);
WEAK_ALIAS void DMAC_0_Handler(void);
WEAK_ALIAS void DMAC_1_Handler(void);
WEAK_ALIAS void DMAC_2_Handler(void);
WEAK_ALIAS void DMAC_3_Handler(void);
WEAK_ALIAS void DMAC_OTHER_Handler(void);
WEAK_ALIAS void EVSYS_0_Handler(void);
WEAK_ALIAS void EVSYS_1_Handler(void);
WEAK_ALIAS void EVSYS_2_Handler(void);
WEAK_ALIAS void EVSYS_3_Handler(void);
WEAK_ALIAS void EVSYS_OTHER_Handler(void);
WEAK_ALIAS void PAC_Handler(void);
WEAK_ALIAS void RAMECC_Handler(void);
WEAK_ALIAS void SERCOM0_0_Handler(void);
WEAK_ALIAS void SERCOM0_1_Handler(void);
WEAK_ALIAS void SERCOM0_2_Handler(void);
WEAK_ALIAS void SERCOM0_OTHER_Handler(void);
WEAK_ALIAS void SERCOM1_0_Handler(void);
WEAK_ALIAS void SERCOM1_1_Handler(void);
WEAK_ALIAS void SERCOM1_2_Handler(void);
WEAK_ALIAS void SERCOM1_OTHER_Handler(void);
WEAK_ALIAS void SERCOM2_0_Handler(void);
WEAK_ALIAS void SERCOM2_1_Handler(void);
WEAK_ALIAS void SERCOM2_2_Handler(void);
WEAK_ALIAS void SERCOM2_OTHER_Handler(void);
WEAK_ALIAS void SERCOM3_0_Handler(void);
WEAK_ALIAS void SERCOM3_1_Handler(void);
WEAK_ALIAS void SERCOM3_2_Handler(void);
WEAK_ALIAS void SERCOM3_OTHER_Handler(void);
WEAK_ALIAS void SERCOM4_0_Handler(void);
WEAK_ALIAS void SERCOM4_1_Handler(void);
WEAK_ALIAS void SERCOM4_2_Handler(void);
WEAK_ALIAS void SERCOM4_OTHER_Handler(void);
WEAK_ALIAS void SERCOM5_0_Handler(void);
WEAK_ALIAS void SERCOM5_1_Handler(void);
WEAK_ALIAS void SERCOM5_2_Handler(void);
WEAK_ALIAS void SERCOM5_OTHER_Handler(void);
WEAK_ALIAS void SERCOM6_0_Handler(void);
WEAK_ALIAS void SERCOM6_1_Handler(void);
WEAK_ALIAS void SERCOM6_2_Handler(void);
WEAK_ALIAS void SERCOM6_OTHER_Handler(void);
WEAK_ALIAS void SERCOM7_0_Handler(void);
WEAK_ALIAS void SERCOM7_1_Handler(void);
WEAK_ALIAS void SERCOM7_2_Handler(void);
WEAK_ALIAS void SERCOM7_OTHER_Handler(void);
WEAK_ALIAS void CAN0_Handler(void);
WEAK_ALIAS void CAN1_Handler(void);
WEAK_ALIAS void USB_OTHER_Handler(void);
WEAK_ALIAS void USB_SOF_HSOF_Handler(void);
WEAK_ALIAS void USB_TRCPT0_Handler(void);
WEAK_ALIAS void USB_TRCPT1_Handler(void);
WEAK_ALIAS void GMAC_Handler(void);
WEAK_ALIAS void TCC0_OTHER_Handler(void);
WEAK_ALIAS void TCC0_MC0_Handler(void);
WEAK_ALIAS void TCC0_MC1_Handler(void);
WEAK_ALIAS void TCC0_MC2_Handler(void);
WEAK_ALIAS void TCC0_MC3_Handler(void);
WEAK_ALIAS void TCC0_MC4_Handler(void);
WEAK_ALIAS void TCC0_MC5_Handler(void);
WEAK_ALIAS void TCC1_OTHER_Handler(void);
WEAK_ALIAS void TCC1_MC0_Handler(void);
WEAK_ALIAS void TCC1_MC1_Handler(void);
WEAK_ALIAS void TCC1_MC2_Handler(void);
WEAK_ALIAS void TCC1_MC3_Handler(void);
WEAK_ALIAS void TCC2_OTHER_Handler(void);
WEAK_ALIAS void TCC2_MC0_Handler(void);
WEAK_ALIAS void TCC2_MC1_Handler(void);
WEAK_ALIAS void TCC2_MC2_Handler(void);
WEAK_ALIAS void TCC3_OTHER_Handler(void);
WEAK_ALIAS void TCC3_MC0_Handler(void);
WEAK_ALIAS void TCC3_MC1_Handler(void);
WEAK_ALIAS void TCC4_OTHER_Handler(void);
WEAK_ALIAS void TCC4_MC0_Handler(void);
WEAK_ALIAS void TCC4_MC1_Handler(void);
WEAK_ALIAS void TC0_Handler(void);
WEAK_ALIAS void TC1_Handler(void);
WEAK_ALIAS void TC2_Handler(void);
WEAK_ALIAS void TC3_Handler(void);
WEAK_ALIAS void TC4_Handler(void);
WEAK_ALIAS void TC5_Handler(void);
WEAK_ALIAS void TC6_Handler(void);
WEAK_ALIAS void TC7_Handler(void);
WEAK_ALIAS void PDEC_OTHER_Handler(void);
WEAK_ALIAS void PDEC_MC0_Handler(void);
WEAK_ALIAS void PDEC_MC1_Handler(void);
WEAK_ALIAS void ADC0_OTHER_Handler(void);
WEAK_ALIAS void ADC0_RESRDY_Handler(void);
WEAK_ALIAS void ADC1_OTHER_Handler(void);
WEAK_ALIAS void ADC1_RESRDY_Handler(void);
WEAK_ALIAS void AC_Handler(void);
WEAK_ALIAS void DAC_OTHER_Handler(void);
WEAK_ALIAS void DAC_EMPTY_0_Handler(void);
WEAK_ALIAS void DAC_EMPTY_1_Handler(void);
WEAK_ALIAS void DAC_RESRDY_0_Handler(void);
WEAK_ALIAS void DAC_RESRDY_1_Handler(void);
WEAK_ALIAS void I2S_Handler(void);
WEAK_ALIAS void PCC_Handler(void);
WEAK_ALIAS void AES_Handler(void);
WEAK_ALIAS void TRNG_Handler(void);
WEAK_ALIAS void ICM_Handler(void);
WEAK_ALIAS void PUKCC_Handler(void);
WEAK_ALIAS void QSPI_Handler(void);
WEAK_ALIAS void SDHC0_Handler(void);
WEAK_ALIAS void SDHC1_Handler(void);
__attribute__((section(".vectors"))) void (*const tab[16 + 138])(void) = {
_estack,
Reset_Handler,
NMI_Handler,
HardFault_Handler,
MemoryManagement_Handler,
BusFault_Handler,
UsageFault_Handler,
NULL,
NULL,
NULL,
NULL,
SVCall_Handler,
DebugMonitor_Handler,
NULL,
PendSV_Handler,
SysTick_Handler,
PM_Handler, // 0 Power
MCLK_Handler, // 1 Main
OSCCTRL_XOSC0_Handler, // 2 Oscillators
OSCCTRL_XOSC1_Handler, // 3 Oscillators
OSCCTRL_DFLL_Handler, // 4 Oscillators
OSCCTRL_DPLL0_Handler, // 5 Oscillators
OSCCTRL_DPLL1_Handler, // 6 Oscillators
OSC32KCTRL_Handler, // 7 32kHz
SUPC_OTHER_Handler, // 8 Supply
SUPC_BODDET_Handler, // 9 Supply
WDT_Handler, // 10 Watchdog
RTC_Handler, // 11 Real-Time
EIC_EXTINT_0_Handler, // 12 External
EIC_EXTINT_1_Handler, // 13 External
EIC_EXTINT_2_Handler, // 14 External
EIC_EXTINT_3_Handler, // 15 External
EIC_EXTINT_4_Handler, // 16 External
EIC_EXTINT_5_Handler, // 17 External
EIC_EXTINT_6_Handler, // 18 External
EIC_EXTINT_7_Handler, // 19 External
EIC_EXTINT_8_Handler, // 20 External
EIC_EXTINT_9_Handler, // 21 External
EIC_EXTINT_10_Handler, // 22 External
EIC_EXTINT_11_Handler, // 23 External
EIC_EXTINT_12_Handler, // 24 External
EIC_EXTINT_13_Handler, // 25 External
EIC_EXTINT_14_Handler, // 26 External
EIC_EXTINT_15_Handler, // 27 External
FREQM_Handler, // 28 Frequency
NVMCTRL_0_Handler, // 29 Non-Volatile
NVMCTRL_1_Handler, // 30 Non-Volatile
DMAC_0_Handler, // 31 Direct
DMAC_1_Handler, // 32 Direct
DMAC_2_Handler, // 33 Direct
DMAC_3_Handler, // 34 Direct
DMAC_OTHER_Handler, // 35 Direct
EVSYS_0_Handler, // 36 Event
EVSYS_1_Handler, // 37 Event
EVSYS_2_Handler, // 38 Event
EVSYS_3_Handler, // 39 Event
EVSYS_OTHER_Handler, // 40 Event
PAC_Handler, // 41 Peripheral
0, // 42 Reserved
0, // 43 Reserved
0, // 44 Reserved
RAMECC_Handler, // 45 RAM
SERCOM0_0_Handler, // 46 Serial
SERCOM0_1_Handler, // 47 Serial
SERCOM0_2_Handler, // 48 Serial
SERCOM0_OTHER_Handler, // 49 Serial
SERCOM1_0_Handler, // 50 Serial
SERCOM1_1_Handler, // 51 Serial
SERCOM1_2_Handler, // 52 Serial
SERCOM1_OTHER_Handler, // 53 Serial
SERCOM2_0_Handler, // 54 Serial
SERCOM2_1_Handler, // 55 Serial
SERCOM2_2_Handler, // 56 Serial
SERCOM2_OTHER_Handler, // 57 Serial
SERCOM3_0_Handler, // 58 Serial
SERCOM3_1_Handler, // 59 Serial
SERCOM3_2_Handler, // 60 Serial
SERCOM3_OTHER_Handler, // 61 Serial
SERCOM4_0_Handler, // 62 Serial
SERCOM4_1_Handler, // 63 Serial
SERCOM4_2_Handler, // 64 Serial
SERCOM4_OTHER_Handler, // 65 Serial
SERCOM5_0_Handler, // 66 Serial
SERCOM5_1_Handler, // 67 Serial
SERCOM5_2_Handler, // 68 Serial
SERCOM5_OTHER_Handler, // 69 Serial
SERCOM6_0_Handler, // 70 Serial
SERCOM6_1_Handler, // 71 Serial
SERCOM6_2_Handler, // 72 Serial
SERCOM6_OTHER_Handler, // 73 Serial
SERCOM7_0_Handler, // 74 Serial
SERCOM7_1_Handler, // 75 Serial
SERCOM7_2_Handler, // 76 Serial
SERCOM7_OTHER_Handler, // 77 Serial
CAN0_Handler, // 78 Control
CAN1_Handler, // 79 Control
USB_OTHER_Handler, // 80 Universal
USB_SOF_HSOF_Handler, // 81 Universal
USB_TRCPT0_Handler, // 82 Universal
USB_TRCPT1_Handler, // 83 Universal
GMAC_Handler, // 84 Ethernet
TCC0_OTHER_Handler, // 85 Timer
TCC0_MC0_Handler, // 86 Timer
TCC0_MC1_Handler, // 87 Timer
TCC0_MC2_Handler, // 88 Timer
TCC0_MC3_Handler, // 89 Timer
TCC0_MC4_Handler, // 90 Timer
TCC0_MC5_Handler, // 91 Timer
TCC1_OTHER_Handler, // 92 Timer
TCC1_MC0_Handler, // 93 Timer
TCC1_MC1_Handler, // 94 Timer
TCC1_MC2_Handler, // 95 Timer
TCC1_MC3_Handler, // 96 Timer
TCC2_OTHER_Handler, // 97 Timer
TCC2_MC0_Handler, // 98 Timer
TCC2_MC1_Handler, // 99 Timer
TCC2_MC2_Handler, // 100 Timer
TCC3_OTHER_Handler, // 101 Timer
TCC3_MC0_Handler, // 102 Timer
TCC3_MC1_Handler, // 103 Timer
TCC4_OTHER_Handler, // 104 Timer
TCC4_MC0_Handler, // 105 Timer
TCC4_MC1_Handler, // 106 Timer
TC0_Handler, // 107 Basic
TC1_Handler, // 108 Basic
TC2_Handler, // 109 Basic
TC3_Handler, // 110 Basic
TC4_Handler, // 111 Basic
TC5_Handler, // 112 Basic
TC6_Handler, // 113 Basic
TC7_Handler, // 114 Basic
PDEC_OTHER_Handler, // 115 Quadrature
PDEC_MC0_Handler, // 116 Quadrature
PDEC_MC1_Handler, // 117 Quadrature
ADC0_OTHER_Handler, // 118 Analog
ADC0_RESRDY_Handler, // 119 Analog
ADC1_OTHER_Handler, // 120 Analog
ADC1_RESRDY_Handler, // 121 Analog
AC_Handler, // 122 Analog
DAC_OTHER_Handler, // 123 Digital-to-Analog
DAC_EMPTY_0_Handler, // 124 Digital-to-Analog
DAC_EMPTY_1_Handler, // 125 Digital-to-Analog
DAC_RESRDY_0_Handler, // 126 Digital-to-Analog
DAC_RESRDY_1_Handler, // 127 Digital-to-Analog
I2S_Handler, // 128 Inter-IC
PCC_Handler, // 129 Parallel
AES_Handler, // 130 Advanced
TRNG_Handler, // 131 True
ICM_Handler, // 132 Integrity
PUKCC_Handler, // 133 PUblic-Key
QSPI_Handler, // 134 Quad
SDHC0_Handler, // 135 SD/MMC
SDHC1_Handler // 136 SD/MMC
};
__attribute__((naked, noreturn)) void Reset_Handler(void) {
// Clear BSS section, and copy data section from flash to RAM
extern long _sbss, _ebss, _sdata, _edata, _sidata;
for (long *src = &_sbss; src < &_ebss; src++) *src = 0;
for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++;
SCB->VTOR = (uint32_t) &tab;
SystemInit();
// Call main()
extern void main(void);
main();
for (;;) (void) 0; // Infinite loop
}
void Default_Handler(void) {
for (;;) (void) 0;
}
@@ -0,0 +1,89 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include <sys/stat.h>
#include "hal.h"
int _fstat(int fd, struct stat *st) {
if (fd < 0) return -1;
st->st_mode = S_IFCHR;
return 0;
}
void *_sbrk(int incr) {
extern char _end;
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) heap = (unsigned char *) &_end;
prev_heap = heap;
heap += incr;
return prev_heap;
}
int _open(const char *path) {
(void) path;
return -1;
}
int _close(int fd) {
(void) fd;
return -1;
}
int _isatty(int fd) {
(void) fd;
return 1;
}
int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
int _getpid(void) {
return -1;
}
int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
return -1;
}
int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
int _unlink(const char *a) {
(void) a;
return -1;
}
int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}
void _init(void) {
}
@@ -0,0 +1,54 @@
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wconversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include
CFLAGS += -D__SAME54P20A__ -Icmsis_sam/include
CFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=softfp
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
SOURCES = main.c syscalls.c startup.c
# Mongoose-specific source code files and build options. See https://mongoose.ws/documentation/#build-options
SOURCES += mongoose.c
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_LINES=1
CFLAGS += -DMG_ENABLE_DRIVER_SAME54=1 -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1 $(CFLAGS_EXTRA)
# Example specific build options. See README.md
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\"
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F
else
RM = rm -rf
endif
build: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
firmware.elf: cmsis_core cmsis_sam hal.h link.ld Makefile $(SOURCES)
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
flash: firmware.bin
bossac -p /dev/cu.usb* -w -v -b $<
cmsis_core:
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
cmsis_sam:
curl -sL https://packs.download.microchip.com/Microchip.SAME54_DFP.3.8.234.pack -o $@.zip
mkdir $@ && cd $@ && unzip ../$@.zip
# Automated test via https://vcon.io/automated-firmware-tests/. Set VCON_API_KEY and update DEVICE_URL
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/9
update: firmware.bin
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
test update: CFLAGS += -DUART_DEBUG=USART1
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
grep 'RECEIVED hello' /tmp/output.txt # Check for MQTT success
clean:
$(RM) firmware.* cmsis_core cmsis_sam *.zip
@@ -0,0 +1,219 @@
// Copyright (c) 2022 Cesanta Software Limited
// SPDX-License-Identifier: MIT
//
// https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/DataSheets/SAM-D5x-E5x-Family-Data-Sheet-DS60001507.pdf
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
#ifndef LED_PIN
#define LED_PIN PIN('C', 18)
#endif
#ifndef BUTTON_PIN
#define BUTTON_PIN PIN('B', 31)
#endif
#ifndef UART_DEBUG
#define UART_DEBUG USART1
#endif
#pragma once
#include <sam.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define BIT(x) (1UL << (x))
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
static inline void spin(volatile uint32_t count) {
while (count--) (void) 0;
}
static inline uint32_t clock_sys_freq(void) {
return 48000000U;
}
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE };
enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN };
#define GPIO(N) ((port_group_registers_t *) (PORT_BASE_ADDRESS + 0x80 * (N)))
typedef port_group_registers_t GPIO_TypeDef;
static inline GPIO_TypeDef *gpio_bank(uint16_t pin) {
return GPIO(PINBANK(pin));
}
static inline void gpio_toggle(uint16_t pin) {
gpio_bank(pin)->PORT_OUTTGL = BIT(PINNO(pin));
}
static inline bool gpio_read(uint16_t pin) {
return gpio_bank(pin)->PORT_IN & BIT(PINNO(pin));
}
static inline void gpio_write(uint16_t pin, bool val) {
GPIO_TypeDef *gpio = gpio_bank(pin);
if (val) {
gpio->PORT_OUTSET = BIT(PINNO(pin));
} else {
gpio->PORT_OUTCLR = BIT(PINNO(pin));
}
}
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
uint8_t speed, uint8_t pull, uint8_t af) {
(void) type, (void) speed, (void) pull, (void) af;
GPIO_TypeDef *gpio = gpio_bank(pin);
uint32_t mask = BIT(PINNO(pin));
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk;
if (mode == GPIO_MODE_INPUT) {
gpio->PORT_DIRCLR = mask;
} else {
gpio->PORT_DIRSET = mask;
}
}
static inline void gpio_input(uint16_t pin) {
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
GPIO_PULL_NONE, 0);
}
static inline void gpio_output(uint16_t pin) {
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
GPIO_PULL_NONE, 0);
}
typedef sercom_usart_int_registers_t USART_TypeDef;
#define USART1 ((USART_TypeDef *) SERCOM0_BASE_ADDRESS)
#define USART2 ((USART_TypeDef *) SERCOM1_BASE_ADDRESS)
#define USART3 ((USART_TypeDef *) SERCOM2_BASE_ADDRESS)
static inline bool uart_init(USART_TypeDef *uart, unsigned long baud) {
uint16_t rx = 0, tx = 0; // Pins
uint8_t rx_mux = 0, tx_mux = 0;
if (uart == USART1) {
MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM0_Msk;
GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_CORE] =
GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN_Msk;
GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_SLOW] =
GCLK_PCHCTRL_GEN_GCLK3 | GCLK_PCHCTRL_CHEN_Msk;
tx = PIN('A', 4), rx = PIN('A', 5);
rx_mux = MUX_PA05D_SERCOM0_PAD1, tx_mux = MUX_PA04D_SERCOM0_PAD0;
} else if (uart == USART2) {
MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM1_Msk;
tx = PIN('C', 27), rx = PIN('C', 28);
} else if (uart == USART3) {
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_SERCOM2_Msk;
tx = PIN('A', 9), rx = PIN('A', 8);
} else {
return false;
}
gpio_bank(rx)->PORT_WRCONFIG =
PORT_WRCONFIG_PMUX(rx_mux) | PORT_WRCONFIG_WRPMUX(1) |
PORT_WRCONFIG_PMUXEN(1) | PORT_WRCONFIG_WRPINCFG(1) | BIT(PINNO(rx));
gpio_bank(tx)->PORT_WRCONFIG =
PORT_WRCONFIG_PMUX(tx_mux) | PORT_WRCONFIG_WRPMUX(1) |
PORT_WRCONFIG_PMUXEN(1) | PORT_WRCONFIG_WRPINCFG(1) | BIT(PINNO(tx));
uart->SERCOM_CTRLA = SERCOM_USART_INT_CTRLA_DORD(1) |
SERCOM_USART_INT_CTRLA_MODE(1 /* INT_CLK */) |
SERCOM_USART_INT_CTRLA_RXPO(1 /* PAD1 */) |
SERCOM_USART_INT_CTRLA_TXPO(0 /* PAD0 */) |
SERCOM_USART_INT_CTRLA_SAMPR(1);
uart->SERCOM_BAUD = (uint16_t) (clock_sys_freq() / (16 * baud));
uart->SERCOM_CTRLB = SERCOM_USART_INT_CTRLB_RXEN(1) |
SERCOM_USART_INT_CTRLB_TXEN(1) |
SERCOM_USART_INT_CTRLB_CHSIZE(0);
while (uart->SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_CTRLB_Msk) spin(1);
uart->SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_ENABLE(1);
while (uart->SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_ENABLE_Msk) spin(1);
return true;
}
static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
while (!(uart->SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_DRE_Msk)) spin(1);
uart->SERCOM_DATA = byte;
}
static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
}
static inline bool uart_read_ready(USART_TypeDef *uart) {
return (uart->SERCOM_INTFLAG & SERCOM_USART_EXT_INTFLAG_RXC_Msk);
}
static inline uint8_t uart_read_byte(USART_TypeDef *uart) {
return (uint8_t) (uart->SERCOM_DATA & 255U);
}
static inline void rng_init(void) {
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_TRNG_Msk;
TRNG_REGS->TRNG_CTRLA = TRNG_CTRLA_ENABLE_Msk;
}
static inline uint32_t rng_read(void) {
while ((TRNG_REGS->TRNG_INTFLAG & TRNG_INTFLAG_DATARDY_Msk) == 0) spin(1);
return TRNG_REGS->TRNG_DATA;
}
#define UID_BASE_W0 0x008061FC // Word 0 location of the 128-bit chip ID
#define UID_BASE_W1_3 0x00806010 // Words 1-3 location of the 128-bit chip ID
#define UUID(n) ((n >= 0 && n <= 3) ? \
(((uint8_t *) UID_BASE_W0)[n]) : \
(((uint8_t *) UID_BASE_W1_3)[n - 4]))
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
{ \
2, UUID(0) ^ UUID(1) ^ UUID(2), UUID(3) ^ UUID(4) ^ UUID(5), \
UUID(6) ^ UUID(7) ^ UUID(8), UUID(9) ^ UUID(10) ^ UUID(11), \
UUID(12) ^ UUID(13) ^ UUID(14) ^ UUID(15) \
}
static inline bool timer_expired(volatile uint64_t *t, uint64_t prd,
uint64_t now) {
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
if (*t > now) return false; // Not expired yet, return
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
return true; // Expired, return true
}
static inline void clock_init(void) {
SCB->CPACR |= (15U << 20); // Enable FPU
SysTick_Config(clock_sys_freq() / 1000); // Sys tick every 1ms
}
static inline void gpio_set_irq_handler(uint16_t pin, void (*fn)(void *),
void *arg) {
(void) pin, (void) fn, (void) arg;
}
static inline void ethernet_init(void) {
uint16_t pins[] = {PIN('A', 12), PIN('A', 13), PIN('A', 14), PIN('A', 15),
PIN('A', 17), PIN('A', 18), PIN('A', 19), PIN('C', 11),
PIN('C', 12), PIN('C', 20)};
uint32_t af[] = {MUX_PA12L_GMAC_GRX1, MUX_PA13L_GMAC_GRX0,
MUX_PA14L_GMAC_GTXCK, MUX_PA15L_GMAC_GRXER,
MUX_PA17L_GMAC_GTXEN, MUX_PA18L_GMAC_GTX0,
MUX_PA19L_GMAC_GTX1, MUX_PC11L_GMAC_GMDC,
MUX_PC12L_GMAC_GMDIO, MUX_PC20L_GMAC_GRXDV};
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk;
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
int bank = PINBANK(pins[i]), no = PINNO(pins[i]);
PORT_REGS->GROUP[bank].PORT_PINCFG[no] |= PORT_PINCFG_PMUXEN_Msk;
volatile uint8_t *m = &PORT_REGS->GROUP[bank].PORT_PMUX[no / 2], v = m[0];
if (no & 1) {
m[0] = (uint8_t) ((v & ~0xf0) | PORT_PMUX_PMUXO(af[i]));
} else {
m[0] = (uint8_t) ((v & ~0x0f) | PORT_PMUX_PMUXE(af[i]));
}
}
PORT_REGS->GROUP[0].PORT_PINCFG[17] |= PORT_PINCFG_DRVSTR_Msk;
PORT_REGS->GROUP[0].PORT_PINCFG[18] |= PORT_PINCFG_DRVSTR_Msk;
PORT_REGS->GROUP[0].PORT_PINCFG[19] |= PORT_PINCFG_DRVSTR_Msk;
// Reset PHY
uint16_t phy_pin = PIN('C', 21);
gpio_output(phy_pin);
gpio_write(phy_pin, false);
spin(999);
gpio_write(phy_pin, true);
spin(999);
}
@@ -0,0 +1,25 @@
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x00000000, LENGTH = 1024k
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
}
_estack = ORIGIN(sram) + LENGTH(sram);
SECTIONS {
.vectors : { FILL(256) KEEP(*(.vectors)) } > flash
.text : { *(.text*) } > flash
.rodata : { *(.rodata*) } > flash
.data : {
_sdata = .;
*(.first_data)
*(.data SORT(.data.*))
_edata = .;
} > sram AT > flash
_sidata = LOADADDR(.data);
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram
. = ALIGN(8);
_end = .;
}
@@ -0,0 +1,120 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
#include "hal.h"
#include "mongoose.h"
static const char *s_url = "mqtt://broker.hivemq.com:1883";
static const char *s_sub_topic = "mg/+/test"; // Publish topic
static const char *s_pub_topic = "mg/clnt/test"; // Subscribe topic
static const uint8_t s_qos = 1; // MQTT QoS
static struct mg_connection *s_conn; // Client connection
void SystemInit(void) { // Called automatically by startup code
clock_init();
rng_init();
}
static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++;
}
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
return s_ticks; // Return number of milliseconds since boot
}
void mg_random(void *buf, size_t len) { // Use on-board RNG
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
uint32_t r = rng_read();
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_OPEN) {
MG_INFO(("%lu CREATED", c->id));
// c->is_hexdumping = 1;
} else if (ev == MG_EV_ERROR) {
// On error, log error message
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
} else if (ev == MG_EV_MQTT_OPEN) {
// MQTT connect is successful
struct mg_str subt = mg_str(s_sub_topic);
struct mg_str pubt = mg_str(s_pub_topic), data = mg_str("hello");
MG_INFO(("%lu CONNECTED to %s", c->id, s_url));
struct mg_mqtt_opts sub_opts;
memset(&sub_opts, 0, sizeof(sub_opts));
sub_opts.topic = subt;
sub_opts.qos = s_qos;
mg_mqtt_sub(c, &sub_opts);
MG_INFO(("%lu SUBSCRIBED to %.*s", c->id, (int) subt.len, subt.ptr));
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = pubt;
pub_opts.message = data;
pub_opts.qos = s_qos, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
MG_INFO(("%lu PUBLISHED %.*s -> %.*s", c->id, (int) data.len, data.ptr,
(int) pubt.len, pubt.ptr));
} else if (ev == MG_EV_MQTT_MSG) {
// When we get echo response, print it
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
MG_INFO(("%lu RECEIVED %.*s <- %.*s", c->id, (int) mm->data.len,
mm->data.ptr, (int) mm->topic.len, mm->topic.ptr));
} else if (ev == MG_EV_CLOSE) {
MG_INFO(("%lu CLOSED", c->id));
s_conn = NULL; // Mark that we're closed
}
(void) fn_data;
}
// Timer function - recreate client connection if it is closed
static void timer_fn(void *arg) {
struct mg_mgr *mgr = (struct mg_mgr *) arg;
struct mg_mqtt_opts opts = {.clean = true,
.qos = s_qos,
.topic = mg_str(s_pub_topic),
.version = 4,
.message = mg_str("bye")};
if (s_conn == NULL) s_conn = mg_mqtt_connect(mgr, s_url, &opts, fn, NULL);
}
int main(void) {
gpio_input(BUTTON_PIN);
gpio_output(LED_PIN);
uart_init(UART_DEBUG, 115200);
ethernet_init();
MG_INFO(("Starting, CPU freq %g MHz", (double) clock_sys_freq() / 1000000));
struct mg_mgr mgr; // Initialise
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level
// Initialise Mongoose network stack
struct mg_tcpip_driver_same54_data driver_data = {.mdc_cr = 5};
struct mg_tcpip_if mif = {
.mac = GENERATE_LOCALLY_ADMINISTERED_MAC() /*{2, 3, 4, 5, 6, 7}*/,
// Uncomment below for static configuration:
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
.driver = &mg_tcpip_driver_same54,
.driver_data = &driver_data};
mg_tcpip_init(&mgr, &mif);
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
while (mif.state != MG_TCPIP_STATE_READY) {
mg_mgr_poll(&mgr, 0);
}
MG_INFO(("Initialising application..."));
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
}
return 0;
}
@@ -0,0 +1 @@
../../../../mongoose.c
@@ -0,0 +1 @@
../../../../mongoose.h
@@ -0,0 +1,332 @@
// SPDX-FileCopyrightText: 2022-2023 Cesanta Software Limited
// SPDX-License-Identifier: MIT
#include "hal.h"
void Reset_Handler(void); // Defined below
void Dummy_Handler(void); // Defined below
void SysTick_Handler(void); // Defined in main.c
void SystemInit(void); // Defined in main.c, called by reset handler
void _estack(void); // Defined in link.ld
#define WEAK_ALIAS __attribute__((weak, alias("Default_Handler")))
WEAK_ALIAS void NMI_Handler(void);
WEAK_ALIAS void HardFault_Handler(void);
WEAK_ALIAS void MemoryManagement_Handler(void);
WEAK_ALIAS void BusFault_Handler(void);
WEAK_ALIAS void UsageFault_Handler(void);
WEAK_ALIAS void SVCall_Handler(void);
WEAK_ALIAS void DebugMonitor_Handler(void);
WEAK_ALIAS void PendSV_Handler(void);
WEAK_ALIAS void SysTick_Handler(void);
WEAK_ALIAS void PM_Handler(void);
WEAK_ALIAS void MCLK_Handler(void);
WEAK_ALIAS void OSCCTRL_XOSC0_Handler(void);
WEAK_ALIAS void OSCCTRL_XOSC1_Handler(void);
WEAK_ALIAS void OSCCTRL_DFLL_Handler(void);
WEAK_ALIAS void OSCCTRL_DPLL0_Handler(void);
WEAK_ALIAS void OSCCTRL_DPLL1_Handler(void);
WEAK_ALIAS void OSC32KCTRL_Handler(void);
WEAK_ALIAS void SUPC_OTHER_Handler(void);
WEAK_ALIAS void SUPC_BODDET_Handler(void);
WEAK_ALIAS void WDT_Handler(void);
WEAK_ALIAS void RTC_Handler(void);
WEAK_ALIAS void EIC_EXTINT_0_Handler(void);
WEAK_ALIAS void EIC_EXTINT_1_Handler(void);
WEAK_ALIAS void EIC_EXTINT_2_Handler(void);
WEAK_ALIAS void EIC_EXTINT_3_Handler(void);
WEAK_ALIAS void EIC_EXTINT_4_Handler(void);
WEAK_ALIAS void EIC_EXTINT_5_Handler(void);
WEAK_ALIAS void EIC_EXTINT_6_Handler(void);
WEAK_ALIAS void EIC_EXTINT_7_Handler(void);
WEAK_ALIAS void EIC_EXTINT_8_Handler(void);
WEAK_ALIAS void EIC_EXTINT_9_Handler(void);
WEAK_ALIAS void EIC_EXTINT_10_Handler(void);
WEAK_ALIAS void EIC_EXTINT_11_Handler(void);
WEAK_ALIAS void EIC_EXTINT_12_Handler(void);
WEAK_ALIAS void EIC_EXTINT_13_Handler(void);
WEAK_ALIAS void EIC_EXTINT_14_Handler(void);
WEAK_ALIAS void EIC_EXTINT_15_Handler(void);
WEAK_ALIAS void FREQM_Handler(void);
WEAK_ALIAS void NVMCTRL_0_Handler(void);
WEAK_ALIAS void NVMCTRL_1_Handler(void);
WEAK_ALIAS void DMAC_0_Handler(void);
WEAK_ALIAS void DMAC_1_Handler(void);
WEAK_ALIAS void DMAC_2_Handler(void);
WEAK_ALIAS void DMAC_3_Handler(void);
WEAK_ALIAS void DMAC_OTHER_Handler(void);
WEAK_ALIAS void EVSYS_0_Handler(void);
WEAK_ALIAS void EVSYS_1_Handler(void);
WEAK_ALIAS void EVSYS_2_Handler(void);
WEAK_ALIAS void EVSYS_3_Handler(void);
WEAK_ALIAS void EVSYS_OTHER_Handler(void);
WEAK_ALIAS void PAC_Handler(void);
WEAK_ALIAS void RAMECC_Handler(void);
WEAK_ALIAS void SERCOM0_0_Handler(void);
WEAK_ALIAS void SERCOM0_1_Handler(void);
WEAK_ALIAS void SERCOM0_2_Handler(void);
WEAK_ALIAS void SERCOM0_OTHER_Handler(void);
WEAK_ALIAS void SERCOM1_0_Handler(void);
WEAK_ALIAS void SERCOM1_1_Handler(void);
WEAK_ALIAS void SERCOM1_2_Handler(void);
WEAK_ALIAS void SERCOM1_OTHER_Handler(void);
WEAK_ALIAS void SERCOM2_0_Handler(void);
WEAK_ALIAS void SERCOM2_1_Handler(void);
WEAK_ALIAS void SERCOM2_2_Handler(void);
WEAK_ALIAS void SERCOM2_OTHER_Handler(void);
WEAK_ALIAS void SERCOM3_0_Handler(void);
WEAK_ALIAS void SERCOM3_1_Handler(void);
WEAK_ALIAS void SERCOM3_2_Handler(void);
WEAK_ALIAS void SERCOM3_OTHER_Handler(void);
WEAK_ALIAS void SERCOM4_0_Handler(void);
WEAK_ALIAS void SERCOM4_1_Handler(void);
WEAK_ALIAS void SERCOM4_2_Handler(void);
WEAK_ALIAS void SERCOM4_OTHER_Handler(void);
WEAK_ALIAS void SERCOM5_0_Handler(void);
WEAK_ALIAS void SERCOM5_1_Handler(void);
WEAK_ALIAS void SERCOM5_2_Handler(void);
WEAK_ALIAS void SERCOM5_OTHER_Handler(void);
WEAK_ALIAS void SERCOM6_0_Handler(void);
WEAK_ALIAS void SERCOM6_1_Handler(void);
WEAK_ALIAS void SERCOM6_2_Handler(void);
WEAK_ALIAS void SERCOM6_OTHER_Handler(void);
WEAK_ALIAS void SERCOM7_0_Handler(void);
WEAK_ALIAS void SERCOM7_1_Handler(void);
WEAK_ALIAS void SERCOM7_2_Handler(void);
WEAK_ALIAS void SERCOM7_OTHER_Handler(void);
WEAK_ALIAS void CAN0_Handler(void);
WEAK_ALIAS void CAN1_Handler(void);
WEAK_ALIAS void USB_OTHER_Handler(void);
WEAK_ALIAS void USB_SOF_HSOF_Handler(void);
WEAK_ALIAS void USB_TRCPT0_Handler(void);
WEAK_ALIAS void USB_TRCPT1_Handler(void);
WEAK_ALIAS void GMAC_Handler(void);
WEAK_ALIAS void TCC0_OTHER_Handler(void);
WEAK_ALIAS void TCC0_MC0_Handler(void);
WEAK_ALIAS void TCC0_MC1_Handler(void);
WEAK_ALIAS void TCC0_MC2_Handler(void);
WEAK_ALIAS void TCC0_MC3_Handler(void);
WEAK_ALIAS void TCC0_MC4_Handler(void);
WEAK_ALIAS void TCC0_MC5_Handler(void);
WEAK_ALIAS void TCC1_OTHER_Handler(void);
WEAK_ALIAS void TCC1_MC0_Handler(void);
WEAK_ALIAS void TCC1_MC1_Handler(void);
WEAK_ALIAS void TCC1_MC2_Handler(void);
WEAK_ALIAS void TCC1_MC3_Handler(void);
WEAK_ALIAS void TCC2_OTHER_Handler(void);
WEAK_ALIAS void TCC2_MC0_Handler(void);
WEAK_ALIAS void TCC2_MC1_Handler(void);
WEAK_ALIAS void TCC2_MC2_Handler(void);
WEAK_ALIAS void TCC3_OTHER_Handler(void);
WEAK_ALIAS void TCC3_MC0_Handler(void);
WEAK_ALIAS void TCC3_MC1_Handler(void);
WEAK_ALIAS void TCC4_OTHER_Handler(void);
WEAK_ALIAS void TCC4_MC0_Handler(void);
WEAK_ALIAS void TCC4_MC1_Handler(void);
WEAK_ALIAS void TC0_Handler(void);
WEAK_ALIAS void TC1_Handler(void);
WEAK_ALIAS void TC2_Handler(void);
WEAK_ALIAS void TC3_Handler(void);
WEAK_ALIAS void TC4_Handler(void);
WEAK_ALIAS void TC5_Handler(void);
WEAK_ALIAS void TC6_Handler(void);
WEAK_ALIAS void TC7_Handler(void);
WEAK_ALIAS void PDEC_OTHER_Handler(void);
WEAK_ALIAS void PDEC_MC0_Handler(void);
WEAK_ALIAS void PDEC_MC1_Handler(void);
WEAK_ALIAS void ADC0_OTHER_Handler(void);
WEAK_ALIAS void ADC0_RESRDY_Handler(void);
WEAK_ALIAS void ADC1_OTHER_Handler(void);
WEAK_ALIAS void ADC1_RESRDY_Handler(void);
WEAK_ALIAS void AC_Handler(void);
WEAK_ALIAS void DAC_OTHER_Handler(void);
WEAK_ALIAS void DAC_EMPTY_0_Handler(void);
WEAK_ALIAS void DAC_EMPTY_1_Handler(void);
WEAK_ALIAS void DAC_RESRDY_0_Handler(void);
WEAK_ALIAS void DAC_RESRDY_1_Handler(void);
WEAK_ALIAS void I2S_Handler(void);
WEAK_ALIAS void PCC_Handler(void);
WEAK_ALIAS void AES_Handler(void);
WEAK_ALIAS void TRNG_Handler(void);
WEAK_ALIAS void ICM_Handler(void);
WEAK_ALIAS void PUKCC_Handler(void);
WEAK_ALIAS void QSPI_Handler(void);
WEAK_ALIAS void SDHC0_Handler(void);
WEAK_ALIAS void SDHC1_Handler(void);
__attribute__((section(".vectors"))) void (*const tab[16 + 138])(void) = {
_estack,
Reset_Handler,
NMI_Handler,
HardFault_Handler,
MemoryManagement_Handler,
BusFault_Handler,
UsageFault_Handler,
NULL,
NULL,
NULL,
NULL,
SVCall_Handler,
DebugMonitor_Handler,
NULL,
PendSV_Handler,
SysTick_Handler,
PM_Handler, // 0 Power
MCLK_Handler, // 1 Main
OSCCTRL_XOSC0_Handler, // 2 Oscillators
OSCCTRL_XOSC1_Handler, // 3 Oscillators
OSCCTRL_DFLL_Handler, // 4 Oscillators
OSCCTRL_DPLL0_Handler, // 5 Oscillators
OSCCTRL_DPLL1_Handler, // 6 Oscillators
OSC32KCTRL_Handler, // 7 32kHz
SUPC_OTHER_Handler, // 8 Supply
SUPC_BODDET_Handler, // 9 Supply
WDT_Handler, // 10 Watchdog
RTC_Handler, // 11 Real-Time
EIC_EXTINT_0_Handler, // 12 External
EIC_EXTINT_1_Handler, // 13 External
EIC_EXTINT_2_Handler, // 14 External
EIC_EXTINT_3_Handler, // 15 External
EIC_EXTINT_4_Handler, // 16 External
EIC_EXTINT_5_Handler, // 17 External
EIC_EXTINT_6_Handler, // 18 External
EIC_EXTINT_7_Handler, // 19 External
EIC_EXTINT_8_Handler, // 20 External
EIC_EXTINT_9_Handler, // 21 External
EIC_EXTINT_10_Handler, // 22 External
EIC_EXTINT_11_Handler, // 23 External
EIC_EXTINT_12_Handler, // 24 External
EIC_EXTINT_13_Handler, // 25 External
EIC_EXTINT_14_Handler, // 26 External
EIC_EXTINT_15_Handler, // 27 External
FREQM_Handler, // 28 Frequency
NVMCTRL_0_Handler, // 29 Non-Volatile
NVMCTRL_1_Handler, // 30 Non-Volatile
DMAC_0_Handler, // 31 Direct
DMAC_1_Handler, // 32 Direct
DMAC_2_Handler, // 33 Direct
DMAC_3_Handler, // 34 Direct
DMAC_OTHER_Handler, // 35 Direct
EVSYS_0_Handler, // 36 Event
EVSYS_1_Handler, // 37 Event
EVSYS_2_Handler, // 38 Event
EVSYS_3_Handler, // 39 Event
EVSYS_OTHER_Handler, // 40 Event
PAC_Handler, // 41 Peripheral
0, // 42 Reserved
0, // 43 Reserved
0, // 44 Reserved
RAMECC_Handler, // 45 RAM
SERCOM0_0_Handler, // 46 Serial
SERCOM0_1_Handler, // 47 Serial
SERCOM0_2_Handler, // 48 Serial
SERCOM0_OTHER_Handler, // 49 Serial
SERCOM1_0_Handler, // 50 Serial
SERCOM1_1_Handler, // 51 Serial
SERCOM1_2_Handler, // 52 Serial
SERCOM1_OTHER_Handler, // 53 Serial
SERCOM2_0_Handler, // 54 Serial
SERCOM2_1_Handler, // 55 Serial
SERCOM2_2_Handler, // 56 Serial
SERCOM2_OTHER_Handler, // 57 Serial
SERCOM3_0_Handler, // 58 Serial
SERCOM3_1_Handler, // 59 Serial
SERCOM3_2_Handler, // 60 Serial
SERCOM3_OTHER_Handler, // 61 Serial
SERCOM4_0_Handler, // 62 Serial
SERCOM4_1_Handler, // 63 Serial
SERCOM4_2_Handler, // 64 Serial
SERCOM4_OTHER_Handler, // 65 Serial
SERCOM5_0_Handler, // 66 Serial
SERCOM5_1_Handler, // 67 Serial
SERCOM5_2_Handler, // 68 Serial
SERCOM5_OTHER_Handler, // 69 Serial
SERCOM6_0_Handler, // 70 Serial
SERCOM6_1_Handler, // 71 Serial
SERCOM6_2_Handler, // 72 Serial
SERCOM6_OTHER_Handler, // 73 Serial
SERCOM7_0_Handler, // 74 Serial
SERCOM7_1_Handler, // 75 Serial
SERCOM7_2_Handler, // 76 Serial
SERCOM7_OTHER_Handler, // 77 Serial
CAN0_Handler, // 78 Control
CAN1_Handler, // 79 Control
USB_OTHER_Handler, // 80 Universal
USB_SOF_HSOF_Handler, // 81 Universal
USB_TRCPT0_Handler, // 82 Universal
USB_TRCPT1_Handler, // 83 Universal
GMAC_Handler, // 84 Ethernet
TCC0_OTHER_Handler, // 85 Timer
TCC0_MC0_Handler, // 86 Timer
TCC0_MC1_Handler, // 87 Timer
TCC0_MC2_Handler, // 88 Timer
TCC0_MC3_Handler, // 89 Timer
TCC0_MC4_Handler, // 90 Timer
TCC0_MC5_Handler, // 91 Timer
TCC1_OTHER_Handler, // 92 Timer
TCC1_MC0_Handler, // 93 Timer
TCC1_MC1_Handler, // 94 Timer
TCC1_MC2_Handler, // 95 Timer
TCC1_MC3_Handler, // 96 Timer
TCC2_OTHER_Handler, // 97 Timer
TCC2_MC0_Handler, // 98 Timer
TCC2_MC1_Handler, // 99 Timer
TCC2_MC2_Handler, // 100 Timer
TCC3_OTHER_Handler, // 101 Timer
TCC3_MC0_Handler, // 102 Timer
TCC3_MC1_Handler, // 103 Timer
TCC4_OTHER_Handler, // 104 Timer
TCC4_MC0_Handler, // 105 Timer
TCC4_MC1_Handler, // 106 Timer
TC0_Handler, // 107 Basic
TC1_Handler, // 108 Basic
TC2_Handler, // 109 Basic
TC3_Handler, // 110 Basic
TC4_Handler, // 111 Basic
TC5_Handler, // 112 Basic
TC6_Handler, // 113 Basic
TC7_Handler, // 114 Basic
PDEC_OTHER_Handler, // 115 Quadrature
PDEC_MC0_Handler, // 116 Quadrature
PDEC_MC1_Handler, // 117 Quadrature
ADC0_OTHER_Handler, // 118 Analog
ADC0_RESRDY_Handler, // 119 Analog
ADC1_OTHER_Handler, // 120 Analog
ADC1_RESRDY_Handler, // 121 Analog
AC_Handler, // 122 Analog
DAC_OTHER_Handler, // 123 Digital-to-Analog
DAC_EMPTY_0_Handler, // 124 Digital-to-Analog
DAC_EMPTY_1_Handler, // 125 Digital-to-Analog
DAC_RESRDY_0_Handler, // 126 Digital-to-Analog
DAC_RESRDY_1_Handler, // 127 Digital-to-Analog
I2S_Handler, // 128 Inter-IC
PCC_Handler, // 129 Parallel
AES_Handler, // 130 Advanced
TRNG_Handler, // 131 True
ICM_Handler, // 132 Integrity
PUKCC_Handler, // 133 PUblic-Key
QSPI_Handler, // 134 Quad
SDHC0_Handler, // 135 SD/MMC
SDHC1_Handler // 136 SD/MMC
};
__attribute__((naked, noreturn)) void Reset_Handler(void) {
// Clear BSS section, and copy data section from flash to RAM
extern long _sbss, _ebss, _sdata, _edata, _sidata;
for (long *src = &_sbss; src < &_ebss; src++) *src = 0;
for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++;
SCB->VTOR = (uint32_t) &tab;
SystemInit();
// Call main()
extern void main(void);
main();
for (;;) (void) 0; // Infinite loop
}
void Default_Handler(void) {
for (;;) (void) 0;
}
@@ -0,0 +1,89 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include <sys/stat.h>
#include "hal.h"
int _fstat(int fd, struct stat *st) {
if (fd < 0) return -1;
st->st_mode = S_IFCHR;
return 0;
}
void *_sbrk(int incr) {
extern char _end;
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) heap = (unsigned char *) &_end;
prev_heap = heap;
heap += incr;
return prev_heap;
}
int _open(const char *path) {
(void) path;
return -1;
}
int _close(int fd) {
(void) fd;
return -1;
}
int _isatty(int fd) {
(void) fd;
return 1;
}
int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
int _getpid(void) {
return -1;
}
int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
return -1;
}
int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
int _unlink(const char *a) {
(void) a;
return -1;
}
int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}
void _init(void) {
}
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+1 -1
View File
@@ -47,7 +47,7 @@ static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
MG_DEBUG(("Got response (%d) %.*s...", (int) hm->message.len, 12, MG_DEBUG(("Got response (%d) %.*s...", (int) hm->message.len, 12,
hm->message.ptr)); hm->message.ptr));
c->is_closing = 1; c->is_draining = 1;
} else if (ev == MG_EV_CONNECT) { } else if (ev == MG_EV_CONNECT) {
mg_printf(c, "GET %s HTTP/1.1\r\n\r\n", mg_url_uri((char *) fn_data)); mg_printf(c, "GET %s HTTP/1.1\r\n\r\n", mg_url_uri((char *) fn_data));
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
-2
View File
@@ -102,9 +102,7 @@ int main(int argc, char *argv[]) {
// Start infinite event loop // Start infinite event loop
MG_INFO(("Mongoose version : v%s", MG_VERSION)); MG_INFO(("Mongoose version : v%s", MG_VERSION));
MG_INFO(("Listening on : %s", HTTP_URL)); MG_INFO(("Listening on : %s", HTTP_URL));
#if MG_ENABLE_MBEDTLS || MG_ENABLE_OPENSSL
MG_INFO(("Listening on : %s", HTTPS_URL)); MG_INFO(("Listening on : %s", HTTPS_URL));
#endif
web_init(&mgr); web_init(&mgr);
while (s_signo == 0) mg_mgr_poll(&mgr, 100); // Infinite event loop while (s_signo == 0) mg_mgr_poll(&mgr, 100); // Infinite event loop
+2 -2
View File
@@ -1,11 +1,11 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
#CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -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 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 PROG ?= example.exe # Use .exe suffix for the binary
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+8 -7
View File
@@ -29,8 +29,8 @@ static const char *s_url =
// 3. From the dialog box that appears, download: // 3. From the dialog box that appears, download:
// xxx-certificate.pem.crt as cert.pem to the example directory // xxx-certificate.pem.crt as cert.pem to the example directory
// xxx-private.pem.key as key.pem to the example directory // xxx-private.pem.key as key.pem to the example directory
static const char *s_cert = "cert.pem"; // static const char *s_cert = "cert.pem";
static const char *s_key = "key.pem"; // static const char *s_key = "key.pem";
static const char *s_rx_topic = "d/rx"; static const char *s_rx_topic = "d/rx";
static const char *s_tx_topic = "d/tx"; static const char *s_tx_topic = "d/tx";
@@ -41,14 +41,15 @@ static int s_qos = 1;
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_OPEN) { if (ev == MG_EV_OPEN) {
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
// On error, log error message // On error, log error message
MG_ERROR(("%p %s", c->fd, (char *) ev_data)); MG_ERROR(("%p %s", c->fd, (char *) ev_data));
} else if (ev == MG_EV_CONNECT) {
// Set up 2-way TLS that is required by AWS IoT
struct mg_tls_opts opts = {
.ca = "ca.pem", .cert = s_cert, .certkey = s_key};
mg_tls_init(c, &opts);
} else if (ev == MG_EV_MQTT_OPEN) { } else if (ev == MG_EV_MQTT_OPEN) {
// MQTT connect is successful // MQTT connect is successful
struct mg_str topic = mg_str(s_rx_topic); struct mg_str topic = mg_str(s_rx_topic);
+1
View File
@@ -0,0 +1 @@
../http-client/packed_fs.c
+2 -2
View File
@@ -1,11 +1,11 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
#CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -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 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 PROG ?= example.exe # Use .exe suffix for the binary
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+9 -7
View File
@@ -20,21 +20,23 @@ static struct mg_connection *s_conn; // Client connection
// Handle interrupts, like Ctrl-C // Handle interrupts, like Ctrl-C
static int s_signo; static int s_signo;
static void signal_handler(int signo) { s_signo = signo; } static void signal_handler(int signo) {
s_signo = signo;
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_OPEN) { if (ev == MG_EV_OPEN) {
MG_INFO(("%lu CREATED", c->id)); MG_INFO(("%lu CREATED", c->id));
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
// On error, log error message // On error, log error message
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data)); MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
} else if (ev == MG_EV_CONNECT) {
// If target URL is SSL/TLS, command client connection to use TLS
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = "ca.pem"};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_MQTT_OPEN) { } else if (ev == MG_EV_MQTT_OPEN) {
// MQTT connect is successful // MQTT connect is successful
struct mg_str subt = mg_str(s_sub_topic); struct mg_str subt = mg_str(s_sub_topic);
+1
View File
@@ -0,0 +1 @@
../http-client/packed_fs.c
+2 -2
View File
@@ -1,11 +1,11 @@
PROG ?= example # Program we are building PROG ?= example # Program we are building
DELETE = rm -rf # Command to remove files DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c # Source code files SOURCES = main.c mongoose.c packed_fs.c # Source code files, packed_fs.c contains ca.pem, which contains CA certs for TLS
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
#CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -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 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 PROG ?= example.exe # Use .exe suffix for the binary
-1
View File
@@ -1 +0,0 @@
../../test/data/ca.pem
+13 -14
View File
@@ -9,15 +9,15 @@
// //
// To enable SSL/TLS, see https://mongoose.ws/tutorials/tls/#how-to-build // To enable SSL/TLS, see https://mongoose.ws/tutorials/tls/#how-to-build
static const char *s_url =
#if defined(MG_ENABLE_MBEDTLS) || defined(MG_ENABLE_OPENSSL)
"wss://broker.hivemq.com:8884/mqtt";
#else
"ws://broker.hivemq.com:8000/mqtt";
#endif
#include "mongoose.h" #include "mongoose.h"
static const char *s_url =
#if MG_TLS
"wss://broker.hivemq.com:8884/mqtt";
#else
"ws://broker.hivemq.com:8000/mqtt";
#endif
static const char *s_topic = "mg/test"; static const char *s_topic = "mg/test";
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
@@ -25,17 +25,16 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
// On error, log error message // On error, log error message
MG_ERROR(("%p %s", c->fd, (char *) ev_data)); MG_ERROR(("%p %s", c->fd, (char *) ev_data));
} else if (ev == MG_EV_CONNECT) { } else if (ev == MG_EV_CONNECT) {
// If target URL is SSL/TLS, command client connection to use TLS
if (mg_url_is_ssl(s_url)) { if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = "ca.pem"}; struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
} else if (ev == MG_EV_WS_OPEN) { } else if (ev == MG_EV_WS_OPEN) {
// WS connection established. Perform MQTT login // WS connection established. Perform MQTT login
MG_INFO(("Connected to WS. Logging in to MQTT...")); MG_INFO(("Connected to WS. Logging in to MQTT..."));
struct mg_mqtt_opts opts = {.qos = 1, struct mg_mqtt_opts opts = {
.topic = mg_str(s_topic), .qos = 1, .topic = mg_str(s_topic), .message = mg_str("goodbye")};
.message = mg_str("goodbye")};
size_t len = c->send.len; size_t len = c->send.len;
mg_mqtt_login(c, &opts); mg_mqtt_login(c, &opts);
mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY); mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
@@ -72,7 +71,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
len = mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY); len = mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
} else { } else {
MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack)); MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack));
c->is_closing = 1; c->is_draining = 1;
} }
break; break;
case MQTT_CMD_PUBLISH: { case MQTT_CMD_PUBLISH: {
@@ -80,7 +79,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
mm.topic.ptr, (int) mm.data.len, mm.data.ptr)); mm.topic.ptr, (int) mm.data.len, mm.data.ptr));
MG_INFO(("RECEIVED %.*s <- %.*s", (int) mm.data.len, mm.data.ptr, MG_INFO(("RECEIVED %.*s <- %.*s", (int) mm.data.len, mm.data.ptr,
(int) mm.topic.len, mm.topic.ptr)); (int) mm.topic.len, mm.topic.ptr));
c->is_closing = 1; c->is_draining = 1;
break; break;
} }
} }
+1
View File
@@ -0,0 +1 @@
../http-client/packed_fs.c
@@ -0,0 +1,73 @@
CFLAGS = -W -Wall -Wextra -Werror -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_mcu/devices/MIMXRT1021 #-DCPU_MIMXRT1021DAG5A
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16
LDFLAGS ?= -Tlink_ram.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
SOURCES = main.c syscalls.c sysinit.c
SOURCES += cmsis_mcu/devices/MIMXRT1021/gcc/startup_MIMXRT1021.S # NXP startup file. Compiler-dependent!
CFLAGS += -D__ATOLLIC__ -D__STARTUP_CLEAR_BSS # Make startup code work as expected
# Mongoose-specific. See https://mongoose.ws/documentation/#build-options
SOURCES += mongoose.c
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1
CFLAGS += -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_DRIVER_IMXRT1020=1
CFLAGS += $(CFLAGS_EXTRA)
# Example specific build options. See README.md
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
else
RM = rm -rf
endif
all build example: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
firmware.elf: cmsis_core cmsis_mcu $(SOURCES) hal.h link_ram.ld Makefile
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
arm-none-eabi-size $@
flash: firmware.bin
st-flash --reset write $< 0x8000000
cmsis_core: # ARM CMSIS core headers
git clone -q --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
cmsis_mcu:
curl -sL https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.MIMXRT1021_DFP.17.0.0.pack -o $@.zip
mkdir $@ && cd $@ && unzip -q ../$@.zip
mbedtls: # mbedTLS library
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@
ifeq ($(TLS), mbedtls)
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
firmware.elf: mbedtls
endif
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/4
update: firmware.bin
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0003 wm,e000edfc,1 wm,e000ed0c,5fa0004"}'
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
PC=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,4"}' | jq -r .resp[5:]` && \
SP=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,0"}' | jq -r .resp[5:]` && \
REQ="wm,e000ed08,0 wr,d,$$SP wr,f,$$PC" && \
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"'"$$REQ"'"}'
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0001"}'
test update: CFLAGS += -DUART_DEBUG=LPUART2
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
clean:
$(RM) firmware.* *.su cmsis_core cmsis_mcu mbedtls *.zip
@@ -0,0 +1,303 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
// https://www.nxp.com/webapp/Download?colCode=IMXRT1020RM
// https://cache.nxp.com/secured/assets/documents/en/user-guide/MIMXRT1020EVKHUG.pdf
#pragma once
#include "MIMXRT1021.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define BIT(x) (1UL << (x))
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
#define PIN(bank, num) ((((bank) - '0') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
// Use LED for blinking, GPIO_AD_B0_05. GPIO1.5 (schematics)
#define LED PIN('1', 5)
#ifndef UART_DEBUG
#define UART_DEBUG LPUART1
#endif
// No settable constants, see sysinit.c
#define SYS_FREQUENCY 500000000UL
static inline void spin(volatile uint32_t count) {
while (count--) (void) 0;
}
enum { CLOCK_OFF = 0U, CLOCK_ON_RUN = 1U, CLOCK_ON_RUN_WAIT = 3U };
static inline void clock_periph(uint32_t index, uint32_t shift, uint32_t val) {
volatile uint32_t *r = &CCM->CCGR0;
SETBITS(r[index], 3UL << shift, val << shift);
}
// which peripheral feeds the pin
static inline void gpio_mux_config(uint16_t index, uint8_t af) {
IOMUXC->SW_MUX_CTL_PAD[index] = af;
}
// which pin feeds the peripheral (2nd stage)
static inline void periph_mux_config(uint16_t index, uint8_t in) {
IOMUXC->SELECT_INPUT[index] = in;
}
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT };
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_MEDIUM_, GPIO_SPEED_HIGH };
enum { GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_UP };
static inline GPIO_Type *gpio_bank(uint16_t pin) {
static const GPIO_Type *g[] = {NULL, GPIO1, GPIO2, GPIO3, NULL, GPIO5};
return (GPIO_Type *) g[PINBANK(pin)];
}
// pin driver/pull-up/down configuration (ignore "keeper")
static inline void gpio_pad_config(uint16_t index, uint8_t type, uint8_t speed,
uint8_t pull) {
bool dopull = pull > 0;
if (dopull) --pull;
IOMUXC->SW_PAD_CTL_PAD[index] =
IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_ODE(type) |
IOMUXC_SW_PAD_CTL_PAD_SRE(speed >= GPIO_SPEED_HIGH) |
IOMUXC_SW_PAD_CTL_PAD_PUE(1) | IOMUXC_SW_PAD_CTL_PAD_PKE(dopull) |
IOMUXC_SW_PAD_CTL_PAD_PUS(pull) | IOMUXC_SW_PAD_CTL_PAD_DSE(7);
}
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
uint8_t speed, uint8_t pull) {
GPIO_Type *gpio = gpio_bank(pin);
uint8_t bit = (uint8_t) PINNO(pin);
uint32_t mask = (uint32_t) BIT(PINNO(pin));
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
switch (PINBANK(pin)) {
case 1:
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_00 + bit, 5);
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_00 + bit, type, speed,
pull);
clock_periph(1, CCM_CCGR1_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
break;
case 2:
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_00 + bit, 5);
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_00 + bit, type, speed,
pull);
clock_periph(0, CCM_CCGR0_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
break;
case 3:
gpio_mux_config(bit < 13
? kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_32 + bit
: kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 + bit - 13,
5);
gpio_pad_config(bit < 13
? kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_32 + bit
: kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 + bit - 13,
type, speed, pull);
clock_periph(2, CCM_CCGR2_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
break;
case 5:
// TODO(): support sw_mux
clock_periph(1, CCM_CCGR1_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
break;
default:
break;
}
gpio->IMR &= ~mask;
if (mode == GPIO_MODE_INPUT) {
gpio->GDIR &= ~mask;
} else {
gpio->GDIR |= mask;
}
}
static inline void gpio_input(uint16_t pin) {
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
GPIO_PULL_NONE);
}
static inline void gpio_output(uint16_t pin) {
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
GPIO_PULL_NONE);
}
static inline bool gpio_read(uint16_t pin) {
GPIO_Type *gpio = gpio_bank(pin);
uint32_t mask = (uint32_t) BIT(PINNO(pin));
return gpio->DR & mask;
}
static inline void gpio_write(uint16_t pin, bool value) {
GPIO_Type *gpio = gpio_bank(pin);
uint32_t mask = (uint32_t) BIT(PINNO(pin));
if (value) {
gpio->DR |= mask;
} else {
gpio->DR &= ~mask;
}
}
static inline void gpio_toggle(uint16_t pin) {
gpio_write(pin, !gpio_read(pin));
}
// 14.5 Table 14-4: uart_clk_root
// see sysinit.c for clocks, (14.7.9: defaults to PLL3/6/1 = 80MHz)
static inline void uart_init(LPUART_Type *uart, unsigned long baud) {
uint8_t af = 2; // Alternate function
uint16_t mr = 0, pr = 0, mt = 0, pt = 0; // pins
uint32_t freq = 80000000; // uart_clk_root frequency
if (uart == LPUART1)
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_06,
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_06,
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_07,
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_07;
if (uart == LPUART2)
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_08,
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_08,
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_09,
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_09;
if (uart == LPUART1) clock_periph(5, CCM_CCGR5_CG12_SHIFT, CLOCK_ON_RUN_WAIT);
if (uart == LPUART2) clock_periph(0, CCM_CCGR0_CG14_SHIFT, CLOCK_ON_RUN_WAIT);
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
gpio_mux_config(mt, af);
gpio_pad_config(pt, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
gpio_mux_config(mr, af);
gpio_pad_config(pr, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
uart->GLOBAL |= LPUART_GLOBAL_RST_MASK; // reset, CTRL = 0, defaults
uart->GLOBAL &= ~LPUART_GLOBAL_RST_MASK;
SETBITS(uart->BAUD,
LPUART_BAUD_OSR_MASK | LPUART_BAUD_SBR_MASK | LPUART_BAUD_SBNS_MASK,
LPUART_BAUD_OSR(16 - 1) |
LPUART_BAUD_SBR(freq / (16 * baud))); // Rx sample at 16x
SETBITS(uart->CTRL,
LPUART_CTRL_PE_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
LPUART_CTRL_IDLECFG_MASK,
LPUART_CTRL_IDLECFG(1) | LPUART_CTRL_ILT(1) |
LPUART_BAUD_SBNS(0)); // no parity, idle 2 chars after 1 stop bit
uart->CTRL |= LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
}
static inline void uart_write_byte(LPUART_Type *uart, uint8_t byte) {
uart->DATA = byte;
while ((uart->STAT & LPUART_STAT_TDRE_MASK) == 0) spin(1);
}
static inline void uart_write_buf(LPUART_Type *uart, char *buf, size_t len) {
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
}
static inline int uart_read_ready(LPUART_Type *uart) {
(void) uart;
return uart->STAT & LPUART_STAT_RDRF_MASK;
}
static inline uint8_t uart_read_byte(LPUART_Type *uart) {
return (uint8_t) (uart->DATA & 255);
}
static inline void rng_init(void) {
clock_periph(6, CCM_CCGR6_CG6_SHIFT, CLOCK_ON_RUN_WAIT); // trng_clk
SETBITS(TRNG->MCTL,
TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK | TRNG_MCTL_RST_DEF_MASK,
TRNG_MCTL_PRGM(1) | TRNG_MCTL_ERR(1) |
TRNG_MCTL_RST_DEF(1)); // reset to default values
SETBITS(TRNG->MCTL, TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK,
TRNG_MCTL_PRGM(0)); // set to run mode
(void) TRNG->ENT[TRNG_ENT_COUNT - 1]; // start new entropy generation
(void) TRNG->ENT[0]; // defect workaround
}
static inline uint32_t rng_read(void) {
static uint8_t idx = 0;
while ((TRNG->MCTL & TRNG_MCTL_ENT_VAL_MASK) == 0) (void) 0;
uint32_t data = TRNG->ENT[idx++]; // read data
idx %= TRNG_ENT_COUNT; // stay within array limits
if (idx == 0) // we've just read TRNG_ENT_COUNT - 1
(void) TRNG->ENT[0]; // defect workaround
return data;
}
// - PHY has no xtal, XI driven from ENET_REF_CLK1 (labeled as ENET_TX_CLK
// (GPIO_AD_B0_08)), generated by the MCU
// - PHY RST connected to GPIO1.4 (GPIO_AD_B0_04); INTRP/NAND_TREE connected to
// GPIO1.22 (GPIO_AD_B1_06)
// - 37.4 REF_CLK1 is RMII mode reference clock for Rx, Tx, and SMI; it is I/O
// - 11.4.2 IOMUXC_GPR_GPR1 bit 17: ENET_REF_CLK_DIR --> 1 ENET_REF_CLK is
// output driven by ref_enetpll0
// - 14.6.1.3.4 Ethernet PLL (PLL6)
static inline void ethernet_init(void) {
gpio_init(PIN('1', 4), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_MEDIUM, GPIO_PULL_UP); // set GPIO1.4 as GPIO (PHY \RST)
gpio_write(PIN('1', 4), 0); // reset PHY
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_08,
4); // set for ENET_REF_CLK1
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_08] |=
IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
periph_mux_config(kIOMUXC_ENET_RMII_SELECT_INPUT,
1); // drive peripheral from B0_08, so RMII clock is taken
// from ENET_REF_CLK1
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_08, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_09, 0); // set for RXDATA1
periph_mux_config(kIOMUXC_ENET_RX_DATA1_SELECT_INPUT,
1); // drive peripheral from B0_09
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_09, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_10, 0); // set for RXDATA0
periph_mux_config(kIOMUXC_ENET_RX_DATA0_SELECT_INPUT,
1); // drive peripheral from B0_10
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_10, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_11, 0); // set for CRS
periph_mux_config(kIOMUXC_ENET_RX_EN_SELECT_INPUT,
1); // drive peripheral from B0_11
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_11, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12, 0); // set for RXERR
periph_mux_config(kIOMUXC_ENET_RX_ERR_SELECT_INPUT,
1); // drive peripheral from B0_12
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_12, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_13, 0); // set for TXEN
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_13, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_14, 0); // set for TXDATA0
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_14, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_15, 0); // set for TXDATA1
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_15, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_HIGH, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_40, 4); // set for MDIO
periph_mux_config(kIOMUXC_ENET_MDIO_SELECT_INPUT,
2); // drive peripheral from EMC_40
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_40, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_41, 4); // set for MDC
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_41, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
gpio_init(PIN('1', 22), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
GPIO_SPEED_MEDIUM,
GPIO_PULL_UP); // set GPIO1.22 as GPIO (PHY INTRP/NAND_TREE)
gpio_write(PIN('1', 22), 1); // prevent NAND_TREE
// 14.8.9 Use 500MHz reference and generate 50MHz. This is done at sysinit.c,
// as we use this source to clock the core
spin(10000); // keep PHY RST low for a while
gpio_write(PIN('1', 4), 1); // deassert RST
gpio_init(PIN('1', 22), GPIO_MODE_INPUT, 0, GPIO_SPEED_MEDIUM,
GPIO_PULL_UP); // setup IRQ (pulled-up)(not used)
IOMUXC_GPR->GPR1 |=
IOMUXC_GPR_GPR1_ENET_REF_CLK_DIR(1); // Set ENET_REF_CLK1 as output
clock_periph(1, CCM_CCGR1_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enet_ipg_clk
NVIC_EnableIRQ(ENET_IRQn); // Setup Ethernet IRQ handler
}
// Helper macro for MAC generation, byte reads not allowed
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
{ \
2, OCOTP->CFG0 & 255, (OCOTP->CFG0 >> 10) & 255, \
((OCOTP->CFG0 >> 19) ^ (OCOTP->CFG1 >> 19)) & 255, \
(OCOTP->CFG1 >> 10) & 255, OCOTP->CFG1 & 255 \
}
@@ -0,0 +1,22 @@
ENTRY(Reset_Handler);
MEMORY {
flash_cfg(rx) : ORIGIN = 0x60000000, LENGTH = 4k
flash_ivt(rx) : ORIGIN = 0x60001000, LENGTH = 4k
flash_irq(rx) : ORIGIN = 0x60002000, LENGTH = 1k
flash_code(rx) : ORIGIN = 0x60002400, LENGTH = 8183k
ram0(rx) : ORIGIN = 0x00000000, LENGTH = 64k
ram1(rw) : ORIGIN = 0x20000000, LENGTH = 64k
ram2(rw) : ORIGIN = 0x20200000, LENGTH = 128k
}
__StackTop = ORIGIN(ram2) + LENGTH(ram2);
SECTIONS {
.cfg : { __FLASH_BASE = .; KEEP(* (.cfg)) } > flash_cfg
.ivt : { KEEP(*(.ivt)) } > flash_ivt
.irq : { KEEP(*(.isr_vector)) } > flash_irq
.text : { *(.text* .text.*) *(.rodata*) __etext = .; } > flash_code
.data : { __data_start__ = .; *(.data SORT(.data.*)) __data_end__ = .; } > ram1 AT > flash_code
.bss : { __bss_start__ = .; *(.bss SORT(.bss.*) COMMON) __bss_end__ = .; } > ram1
_end = .;
}
@@ -0,0 +1 @@
cmsis_mcu/devices/MIMXRT1021/gcc/MIMXRT1021xxxxx_ram.ld
@@ -0,0 +1,16 @@
ENTRY(Reset_Handler);
MEMORY {
itcram(rx) : ORIGIN = 0x00000000, LENGTH = 64k
dtcram(rw) : ORIGIN = 0x20000000, LENGTH = 64k
ocram(rw) : ORIGIN = 0x20200000, LENGTH = 128k /* This is cached */
}
__StackTop = ORIGIN(dtcram) + LENGTH(dtcram);
SECTIONS {
.irq : { KEEP(*(.isr_vector)) } > itcram
.text : { *(.text* .text.*) *(.rodata*) ; } > itcram
.data : { __data_start__ = .; *(.data SORT(.data.*)) __data_end__ = .; } > dtcram AT > itcram
__etext = LOADADDR(.data);
.bss : { __bss_start__ = .; *(.bss SORT(.bss.*) COMMON) __bss_end__ = .; } > dtcram
_end = .;
}
@@ -0,0 +1,93 @@
// Copyright (c) 2022-2023 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 volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++;
}
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
return s_ticks; // Return number of milliseconds since boot
}
void mg_random(void *buf, size_t len) { // Use on-board RNG
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
uint32_t r = rng_read();
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
}
static void timer_fn(void *arg) {
gpio_toggle(LED); // Blink LED
struct mg_tcpip_if *ifp = arg; // And show
const char *names[] = {"down", "up", "req", "ready"}; // network stats
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
ifp->ndrop, ifp->nerr));
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) fn_data;
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_http_match_uri(hm, "/api/hello")) { // Request to /api/hello
mg_http_reply(c, 200, "", "{%m:%u,%m:%u,%m:%u,%m:%u,%m:%u}\n",
MG_ESC("eth"), ifp->state, MG_ESC("frames_received"),
ifp->nrecv, MG_ESC("frames_sent"), ifp->nsent,
MG_ESC("frames_dropped"), ifp->ndrop,
MG_ESC("interface_errors"), ifp->nerr);
} else if (mg_http_match_uri(hm, "/")) { // Index page
mg_http_reply(
c, 200, "", "%s",
"<html><head><link rel='icon' href='data:;base64,='></head><body>"
"<h1>Welcome to Mongoose</h1>"
"See <a href=/api/hello>/api/hello</a> for REST example"
"</body></html>");
} else { // All other URIs
mg_http_reply(c, 404, "", "Not Found\n");
}
}
}
int main(void) {
gpio_output(LED); // Setup blue LED
uart_init(UART_DEBUG, 115200); // Initialise debug printf
ethernet_init(); // Initialise ethernet pins
MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000));
struct mg_mgr mgr; // Initialise
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level
// Initialise Mongoose network stack
struct mg_tcpip_driver_imxrt1020_data driver_data = {.mdc_cr = 24};
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
// Uncomment below for static configuration:
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
.driver = &mg_tcpip_driver_imxrt1020,
.driver_data = &driver_data};
mg_tcpip_init(&mgr, &mif);
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
while (mif.state != MG_TCPIP_STATE_READY) {
mg_mgr_poll(&mgr, 0);
}
MG_INFO(("Initialising application..."));
mg_http_listen(&mgr, "http://0.0.0.0:80", fn, &mif);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
}
return 0;
}
@@ -0,0 +1,98 @@
#include <sys/stat.h>
#include "hal.h"
int _fstat(int fd, struct stat *st) {
if (fd < 0) return -1;
st->st_mode = S_IFCHR;
return 0;
}
void *_sbrk(int incr) {
extern char _end;
static unsigned char *heap = NULL;
unsigned char *prev_heap;
unsigned char x = 0, *heap_end = (unsigned char *)((size_t) &x - 512);
(void) x;
if (heap == NULL) heap = (unsigned char *) &_end;
prev_heap = heap;
if (heap + incr > heap_end) return (void *) -1;
heap += incr;
return prev_heap;
}
int _open(const char *path) {
(void) path;
return -1;
}
int _close(int fd) {
(void) fd;
return -1;
}
int _isatty(int fd) {
(void) fd;
return 1;
}
int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
int _getpid(void) {
return -1;
}
int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
return -1;
}
int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
int _unlink(const char *a) {
(void) a;
return -1;
}
int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}
void _init(void) {}
extern uint64_t mg_now(void);
int _gettimeofday(struct timeval *tv, void *tz) {
uint64_t now = mg_now();
(void) tz;
tv->tv_sec = (time_t) (now / 1000);
tv->tv_usec = (unsigned long) ((now % 1000) * 1000);
return 0;
}
@@ -0,0 +1,106 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
//
// This file contains essentials required by the CMSIS:
// uint32_t SystemCoreClock - holds the system core clock value
// SystemInit() - initialises the system, e.g. sets up clocks
#include "hal.h"
uint32_t SystemCoreClock = SYS_FREQUENCY;
// - 14.4, Figure 14-2: clock tree
// - 14.7.4: ARM_PODF defaults to /1
// - 14.7.5: AHB_PODF defaults to /1; PERIPH_CLK_SEL defaults to derive clock
// from pre_periph_clk_sel
// - 14.7.6: PRE_PERIPH_CLK_SEL defaults to derive clock from PLL2 PFD3.
// - (For 528MHz operation, we need to set it to derive clock from PLL2, but
// this chip max is 500 MHz).
// - 14.6.1.3.1 System PLL (PLL2); 13.3.2.2 PLLs; 14.6.1.4 Phase Fractional
// Dividers (PFD)
// - 14.8.2: PLL2 is powered off and bypassed to 24MHz
// - 14.8.11: PFD defaults to 18/16 but Figure 14-2 shows half the value
// ("divider")
// - For 500MHz operation, we need to set PRE_PERIPH_CLK_SEL to derive clock
// from divided PLL6
// - 14.8.9: configure PLL6 to generate a 500MHz clock
// - Datasheet 4.1.3: System frequency/Bus frequency max 500/125MHz respectively
// (AHB/IPG)
// - MCUXpresso: IPG_CLK_ROOT <= 125MHz; PERCLK_CLK_ROOT <= 62.5MHz
// - Datasheet 4.8.4.1.1/2: the processor clock frequency must exceed twice the
// ENET_RX_CLK/ENET_TX_CLK frequency.
// - Datasheet 4.8.4.2: no details for RMII (above is for MII), assumed 50MHz
// min processor clock
// - Datasheet 4.1.3, Table 11: "Overdrive" run mode requires 1.25V core voltage
// minimum
void SystemInit(void) { // Called automatically by startup code (ints masked)
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
asm("DSB");
asm("ISB");
// 53.4.2: Disable watchdog after reset (unlocked)
RTWDOG->CS &= ~RTWDOG_CS_EN_MASK;
RTWDOG->TOVAL = 0xFFFF;
while (RTWDOG->CS & RTWDOG_CS_ULK_MASK) spin(1); // wait for lock
while ((RTWDOG->CS & RTWDOG_CS_RCS_MASK) == 0)
spin(1); // wait for new config
// Set VDD_SOC to 1.25V
SETBITS(DCDC->REG3, DCDC_REG3_TRG_MASK, DCDC_REG3_TRG(0x12));
while ((DCDC->REG0 & DCDC_REG0_STS_DC_OK_MASK) == 0)
spin(1); // Wait for DCDC_STS_DC_OK
// 14.8.9 Init 500MHz reference, clock the M7 core with it, generate 50MHz for
// ENET and RMII.
SETBITS(CCM_ANALOG->PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK,
CCM_ANALOG_PLL_ENET_BYPASS_MASK |
CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(0)); // bypass to 24MHz osc
SETBITS(
CCM_ANALOG->PLL_ENET,
CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK,
CCM_ANALOG_PLL_ENET_DIV_SELECT(1) | CCM_ANALOG_PLL_ENET_ENABLE_MASK |
CCM_ANALOG_PLL_ENET_ENET_500M_REF_EN_MASK); // setup PLL
while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0)
spin(1); // wait until it is stable
CCM_ANALOG->PLL_ENET &=
~CCM_ANALOG_PLL_ENET_BYPASS_MASK; // Disable Bypass (switch to PLL)
SETBITS(CCM->CBCDR, CCM_CBCDR_IPG_PODF_MASK,
CCM_CBCDR_IPG_PODF(3)); // Set IPG divider /4 (125MHz)
SETBITS(CCM->CSCMR1, CCM_CSCMR1_PERCLK_PODF_MASK,
CCM_CSCMR1_PERCLK_PODF(1)); // Set PERCLK divider /2 (62.5MHz)
SETBITS(CCM->CBCMR, CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK,
CCM_CBCMR_PRE_PERIPH_CLK_SEL(3)); // run from 500MHz clock
// 14.5 Table 14-4: uart_clk_root
// 14.4: uart_clk_root = PLL3/6 or OSC; CCM_CSCDR1 (14.7.9) defaults to
// PLL3/6/1
CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_POWER_MASK; // Power PLL on
while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0)
spin(1); // wait until it is stable
CCM_ANALOG->PLL_USB1 &=
~CCM_ANALOG_PLL_USB1_BYPASS_MASK; // Disable Bypass (switch to PLL)
rng_init(); // Initialise random number generator
// NXP startup code calls SystemInit BEFORE initializing RAM...
SysTick_Config(SYS_FREQUENCY / 1000); // Sys tick every 1ms
}
#if 0
__attribute__((section(".cfg"), used)) uint32_t __cfg[] = {0x1234abcd};
extern uint32_t __isr_vector[];
extern uint32_t __ivt_boot_data[];
__attribute__((section(".ivt"), used)) uint32_t __ivt[8] = {
0x412000d1, // header: 41 - version, 2000 size, d1 tag
(uint32_t) __isr_vector, // entry
0, // reserved
0, // dcd
(uint32_t) __ivt_boot_data, // boot data
(uint32_t) __ivt, // this is us - ivt absolute address
0, // csf absolute address
0, // reserved for HAB
};
__attribute__((section(".ivt"), used)) uint32_t __ivt_boot_data[] = {
0, // boot start location
64 * 1024, // size
0, // Plugin flag
0Xffffffff // empty - extra data word
};
#endif
@@ -0,0 +1 @@
cmsis_mcu/devices/MIMXRT1021/system_MIMXRT1021.c
Loaded 100 of 1275 files, more files were not shown because too many files have changed in this diff. Show more