mirror of
https://github.com/micropython/micropython.git
synced 2025-12-24 22:00:12 +01:00
Compare commits
1390 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b0a150bd6 | ||
|
|
f8fb4470a0 | ||
|
|
7063210014 | ||
|
|
1cc81ed449 | ||
|
|
c734de490a | ||
|
|
358e5d8bad | ||
|
|
657aef66ff | ||
|
|
6e87aeb841 | ||
|
|
b69f798c92 | ||
|
|
558fd5d228 | ||
|
|
6c3db26ab7 | ||
|
|
d6236e85c2 | ||
|
|
6837dba6b8 | ||
|
|
0c97e4c414 | ||
|
|
a45e280c58 | ||
|
|
f38e8f5217 | ||
|
|
5b1c221785 | ||
|
|
397b705647 | ||
|
|
7e9182f3aa | ||
|
|
b32b0d38fe | ||
|
|
20d9bc2d76 | ||
|
|
05ba2433f6 | ||
|
|
5e919b7ef8 | ||
|
|
9c04299da1 | ||
|
|
5e7fa7c80c | ||
|
|
8a8e775035 | ||
|
|
04d5e644fc | ||
|
|
2c915e1ae6 | ||
|
|
ce8b4e8749 | ||
|
|
2c407bcf20 | ||
|
|
d85439fd19 | ||
|
|
1a0a323ca8 | ||
|
|
4e51a3038c | ||
|
|
96eca22322 | ||
|
|
e6a4d4e23c | ||
|
|
e4cb7c6158 | ||
|
|
2c8356c482 | ||
|
|
f81ea6307c | ||
|
|
de12502d89 | ||
|
|
81fd5685fc | ||
|
|
1b811b946e | ||
|
|
069654f2be | ||
|
|
cee888255b | ||
|
|
28d4b94dce | ||
|
|
69b702276b | ||
|
|
e24674d44e | ||
|
|
69256ac0b1 | ||
|
|
debbaac1bd | ||
|
|
919b70b7ec | ||
|
|
8d2bcaf3cd | ||
|
|
9698a60591 | ||
|
|
fcd6862597 | ||
|
|
ef0c5db2ed | ||
|
|
254a5646c1 | ||
|
|
333a63efaa | ||
|
|
4f2d59e82f | ||
|
|
ec5f8db49d | ||
|
|
c07a03a36d | ||
|
|
aa3fb7b387 | ||
|
|
fd2b71f972 | ||
|
|
a5d07c3aba | ||
|
|
a5d2af7949 | ||
|
|
e5fa163a4c | ||
|
|
a0cb4eda9a | ||
|
|
cef073877b | ||
|
|
cf4b72bf13 | ||
|
|
b475327ffa | ||
|
|
6a051a8e0b | ||
|
|
fb6cc96951 | ||
|
|
fc4c43a72e | ||
|
|
785cf9a61f | ||
|
|
777232c9a5 | ||
|
|
3d4a535208 | ||
|
|
5531437941 | ||
|
|
4b597a1c1a | ||
|
|
98af891610 | ||
|
|
61fa7c8152 | ||
|
|
2e75a17bab | ||
|
|
b1dfdaf6cb | ||
|
|
f50d9477c1 | ||
|
|
d7019d0628 | ||
|
|
9475cc59e6 | ||
|
|
2599672384 | ||
|
|
e1e7657277 | ||
|
|
03b8bb7ec9 | ||
|
|
d88250c06e | ||
|
|
c4506ed869 | ||
|
|
402a743821 | ||
|
|
8fc5e56a6a | ||
|
|
c961889e34 | ||
|
|
6ca17c1922 | ||
|
|
b4070ee8a4 | ||
|
|
2f02302e22 | ||
|
|
193795398d | ||
|
|
71d40f132d | ||
|
|
9edd736ee6 | ||
|
|
e8e116e7fc | ||
|
|
8b08a0d9ed | ||
|
|
61230e007d | ||
|
|
b01a373adb | ||
|
|
cd6194aefc | ||
|
|
374654f2b8 | ||
|
|
fe9bc0c573 | ||
|
|
bbc65d4eda | ||
|
|
fd86bf5917 | ||
|
|
53302f1616 | ||
|
|
651a188299 | ||
|
|
13394a632d | ||
|
|
53ad5edc01 | ||
|
|
87c783b454 | ||
|
|
679fe0abae | ||
|
|
eda8746324 | ||
|
|
935e021250 | ||
|
|
c33a76059f | ||
|
|
3962766be0 | ||
|
|
b62beadae0 | ||
|
|
f71c0699a5 | ||
|
|
9c7e3353e5 | ||
|
|
ba640bde55 | ||
|
|
632d8efa05 | ||
|
|
82b95f625e | ||
|
|
91031a75a1 | ||
|
|
4332d72fd8 | ||
|
|
de0c84ebf1 | ||
|
|
5e75f335e6 | ||
|
|
0cb10b5220 | ||
|
|
159f1aaca8 | ||
|
|
e589cddcd4 | ||
|
|
6e6488530e | ||
|
|
4b5606bc09 | ||
|
|
ee6fcc6f91 | ||
|
|
96a644076d | ||
|
|
8f1854ad2d | ||
|
|
ac671546d1 | ||
|
|
88f60de914 | ||
|
|
2c81b9be28 | ||
|
|
063e6e7d0a | ||
|
|
5d93dfbc2c | ||
|
|
3dbd2ee926 | ||
|
|
4a02a8f74d | ||
|
|
24342dd65e | ||
|
|
d4c8e626f2 | ||
|
|
a5d48b1162 | ||
|
|
78d0dde562 | ||
|
|
0cdbd356fd | ||
|
|
5b9f361824 | ||
|
|
667d64b430 | ||
|
|
dd32f02cc3 | ||
|
|
7059c8c23c | ||
|
|
a1d072df81 | ||
|
|
df1f6783f2 | ||
|
|
494aea3e86 | ||
|
|
5bc9398d9d | ||
|
|
8000d51b68 | ||
|
|
1a0adf49df | ||
|
|
e673714cfe | ||
|
|
58e2ad42ae | ||
|
|
b894551772 | ||
|
|
da161fd9f0 | ||
|
|
12154b1774 | ||
|
|
8d4d6731f5 | ||
|
|
2b302dad51 | ||
|
|
6d5a549067 | ||
|
|
b8133c4c0f | ||
|
|
4a6cac4643 | ||
|
|
99146ea444 | ||
|
|
556a1df6fd | ||
|
|
9d7b871f58 | ||
|
|
2466cb67f8 | ||
|
|
3acaa28b52 | ||
|
|
52e062ef33 | ||
|
|
664f03f466 | ||
|
|
9a58316de2 | ||
|
|
be989be861 | ||
|
|
1ded19d4b3 | ||
|
|
157056ecdf | ||
|
|
ab69ed7dac | ||
|
|
9996adc37d | ||
|
|
cea6cf8a5e | ||
|
|
0d1f8868b6 | ||
|
|
77f85db41e | ||
|
|
06b398489e | ||
|
|
0be6359f39 | ||
|
|
2a1cca20b1 | ||
|
|
e7cd1699df | ||
|
|
dddb98db8b | ||
|
|
99fc0d120a | ||
|
|
00f921ce02 | ||
|
|
031fadd10e | ||
|
|
e5c39a3a9e | ||
|
|
0779409d0d | ||
|
|
ba8f7d5171 | ||
|
|
09ed5bcbbb | ||
|
|
21b74604f9 | ||
|
|
85d3b6165a | ||
|
|
70f32f0f73 | ||
|
|
3d0e3a3d3e | ||
|
|
932f07ccf5 | ||
|
|
4c2cb7e384 | ||
|
|
6e5c31c947 | ||
|
|
a099bfe89c | ||
|
|
e5b047369b | ||
|
|
54fc247f9b | ||
|
|
97375f4576 | ||
|
|
7261f17b9e | ||
|
|
97c2628900 | ||
|
|
9ae51257bd | ||
|
|
5239a8a82b | ||
|
|
a49c16069c | ||
|
|
d5a12a6608 | ||
|
|
1c43a0fbf8 | ||
|
|
7378c50b2f | ||
|
|
9e8396accb | ||
|
|
9b5e05a7c7 | ||
|
|
ad725a6661 | ||
|
|
853fb08d0d | ||
|
|
07554486ee | ||
|
|
6b80ebe32e | ||
|
|
42ef5a1567 | ||
|
|
5b74bba3a3 | ||
|
|
4b6077b3fe | ||
|
|
43d497592f | ||
|
|
fda874e406 | ||
|
|
7379be3673 | ||
|
|
4f64f6bfd3 | ||
|
|
6d2e9e70b3 | ||
|
|
6185dc5f3d | ||
|
|
f1919b7c98 | ||
|
|
c7fb87caff | ||
|
|
f7be80398e | ||
|
|
809fbeefb7 | ||
|
|
dcdf8f2d14 | ||
|
|
bb293e6bcf | ||
|
|
2c72ae5c29 | ||
|
|
f0e2d13fd2 | ||
|
|
ed593780bf | ||
|
|
a0cd118b14 | ||
|
|
f8d42da104 | ||
|
|
3fbbbecec9 | ||
|
|
04a9ac7f38 | ||
|
|
d684f872bd | ||
|
|
05dda0ee9e | ||
|
|
88b0490945 | ||
|
|
4f0080346b | ||
|
|
484a471f9b | ||
|
|
367c084c4b | ||
|
|
0edfb7a115 | ||
|
|
d964873e56 | ||
|
|
ce3beb1672 | ||
|
|
b86c20676e | ||
|
|
db984b73f3 | ||
|
|
1d5d4f49d9 | ||
|
|
419bb26ddc | ||
|
|
d973c1bc12 | ||
|
|
50e0a7b9d4 | ||
|
|
fbb3c190f9 | ||
|
|
14848ffa12 | ||
|
|
52d7685d9a | ||
|
|
d9d4a72679 | ||
|
|
d3a4d39687 | ||
|
|
077448328a | ||
|
|
26f0616e8f | ||
|
|
eb247eacd8 | ||
|
|
342d903a13 | ||
|
|
cdad2b6f4d | ||
|
|
8ab16b6af0 | ||
|
|
c70637bc00 | ||
|
|
98b727c931 | ||
|
|
f22a4f8e0a | ||
|
|
f39bcb304b | ||
|
|
7193086c03 | ||
|
|
4284b3811f | ||
|
|
5d7c408ba8 | ||
|
|
6abafca1aa | ||
|
|
a4c8ef9d16 | ||
|
|
57884996b9 | ||
|
|
b41a14a4b9 | ||
|
|
f70873db23 | ||
|
|
7480ee5892 | ||
|
|
70fb9ee99b | ||
|
|
2382d30318 | ||
|
|
259f1344ca | ||
|
|
ff69a1d27d | ||
|
|
65405247a0 | ||
|
|
3aa0f2eed3 | ||
|
|
453a2a3d7c | ||
|
|
701c4152c1 | ||
|
|
02ea74d8f5 | ||
|
|
1febaf3ac3 | ||
|
|
d083d7d610 | ||
|
|
6f4357c28e | ||
|
|
6d0629bddc | ||
|
|
ecd1272d16 | ||
|
|
3d1d92acfc | ||
|
|
6bb9d3ea3e | ||
|
|
dc320164d8 | ||
|
|
4f72aa86bf | ||
|
|
2740dd85f2 | ||
|
|
e0821830b0 | ||
|
|
09e363316f | ||
|
|
9fb36af9af | ||
|
|
08fed6992f | ||
|
|
6ef65e70af | ||
|
|
eaa96a7610 | ||
|
|
bbe832a0b2 | ||
|
|
6f469209e9 | ||
|
|
57425b648f | ||
|
|
19749db7bf | ||
|
|
9c081b740b | ||
|
|
cd6d189f48 | ||
|
|
8a18084571 | ||
|
|
ac23662550 | ||
|
|
476c15290d | ||
|
|
56f76b873a | ||
|
|
ea23520403 | ||
|
|
57b96a7be2 | ||
|
|
8e1fdf2eb3 | ||
|
|
28adab36c7 | ||
|
|
e9d1a94bf0 | ||
|
|
d6c558c0aa | ||
|
|
add930c4b5 | ||
|
|
12547ce737 | ||
|
|
cc7a4d7db2 | ||
|
|
5148860332 | ||
|
|
495e7cfebc | ||
|
|
f5248a087a | ||
|
|
0d210a0be8 | ||
|
|
fe9620a2bd | ||
|
|
73c9f85b4c | ||
|
|
562bcffd3a | ||
|
|
ed8db2e371 | ||
|
|
53fec1ef48 | ||
|
|
40d8430ee3 | ||
|
|
69d9e7d27d | ||
|
|
dfc35afba1 | ||
|
|
6cee869feb | ||
|
|
ec37239e53 | ||
|
|
4b2938a4b0 | ||
|
|
9598f36a84 | ||
|
|
94e4bd456f | ||
|
|
46fc7a3d75 | ||
|
|
4cd45f48b1 | ||
|
|
46a0ac02c5 | ||
|
|
6b0c88256b | ||
|
|
8cb78e0e53 | ||
|
|
72085a669b | ||
|
|
9fdac9144d | ||
|
|
9d0525182d | ||
|
|
9e0478a902 | ||
|
|
0ee1d0f407 | ||
|
|
e3c66a5a67 | ||
|
|
baf47c84c4 | ||
|
|
1bb15ca427 | ||
|
|
8a43a41b3a | ||
|
|
e9be6a378c | ||
|
|
dc3eb55e6a | ||
|
|
e5cff5b223 | ||
|
|
c38809e26b | ||
|
|
609a9c6b71 | ||
|
|
bf904b238d | ||
|
|
d4315a6caf | ||
|
|
2850e7cd97 | ||
|
|
dc587a3623 | ||
|
|
a2e39a756c | ||
|
|
32b7e93535 | ||
|
|
f791e14750 | ||
|
|
38ac23c942 | ||
|
|
7bb501ef9f | ||
|
|
e372e83b30 | ||
|
|
b33a770596 | ||
|
|
34023eb673 | ||
|
|
0e0ce47e65 | ||
|
|
3770cd2e70 | ||
|
|
f7e5e677df | ||
|
|
3a042fb921 | ||
|
|
a888d5ab91 | ||
|
|
13a4c120ce | ||
|
|
c33ad60a67 | ||
|
|
3846fd56c1 | ||
|
|
5b85a86ce3 | ||
|
|
a2e5e4c3d8 | ||
|
|
3e02b1d19a | ||
|
|
9e78ab4b86 | ||
|
|
814b1ae3a9 | ||
|
|
81407729a5 | ||
|
|
96688de601 | ||
|
|
ab0e36b3da | ||
|
|
350ab0f570 | ||
|
|
103fbaaf27 | ||
|
|
5bf6eba845 | ||
|
|
a63a4761cd | ||
|
|
71206f02c3 | ||
|
|
97a0846af9 | ||
|
|
ff1a96ce2c | ||
|
|
2e2e15cec2 | ||
|
|
5f3e005b67 | ||
|
|
086d98cbde | ||
|
|
87e07ea943 | ||
|
|
e3a29de1dc | ||
|
|
2bd758fe96 | ||
|
|
67e8108345 | ||
|
|
93bb7dffd2 | ||
|
|
9e677114e4 | ||
|
|
331a48195d | ||
|
|
ef5f2669dc | ||
|
|
db573082b5 | ||
|
|
ea040a4f9a | ||
|
|
3cfb15cf4d | ||
|
|
0f87a010e3 | ||
|
|
a8a4b01af6 | ||
|
|
ea89b80ff4 | ||
|
|
d363133917 | ||
|
|
7417ccfb0d | ||
|
|
d3b1f0b627 | ||
|
|
850212203a | ||
|
|
6a804cbaba | ||
|
|
7b05b1b225 | ||
|
|
ac37e0fd1f | ||
|
|
8f54c08691 | ||
|
|
3d42aa07dd | ||
|
|
ac11e89fa3 | ||
|
|
e713222fab | ||
|
|
0ae97f531d | ||
|
|
d22bdad6dd | ||
|
|
a53af6c875 | ||
|
|
f5c42dd9d1 | ||
|
|
ee1656e148 | ||
|
|
df4ce930e3 | ||
|
|
42a6364a31 | ||
|
|
6c8b3a7fee | ||
|
|
cb4fbc8861 | ||
|
|
f22844b4e5 | ||
|
|
a17755ee8b | ||
|
|
ac16cc9a35 | ||
|
|
ea495d6aa6 | ||
|
|
a58a91eb04 | ||
|
|
e7bee6b35e | ||
|
|
31dd312f83 | ||
|
|
55ad083061 | ||
|
|
aeadda4eac | ||
|
|
d8b08cf5fc | ||
|
|
ff133cdb07 | ||
|
|
f8ba2eca80 | ||
|
|
dea585f8ae | ||
|
|
c13b2f2d00 | ||
|
|
22d85ec5be | ||
|
|
8bb4931fec | ||
|
|
efc971e8f9 | ||
|
|
c9845a0685 | ||
|
|
11b97d7ec5 | ||
|
|
5b3f0b7f39 | ||
|
|
4b72b3a133 | ||
|
|
a0c97814df | ||
|
|
66d0c1052a | ||
|
|
8175877ad6 | ||
|
|
fe6756aa2d | ||
|
|
bae052d420 | ||
|
|
3b936a5f4c | ||
|
|
da3dffa79d | ||
|
|
2adf7ec3dd | ||
|
|
b1fa907d56 | ||
|
|
978d2e55ef | ||
|
|
c1c57eafac | ||
|
|
1fa6be5264 | ||
|
|
7dbf74c5b9 | ||
|
|
1404d620c0 | ||
|
|
adfe4ff72a | ||
|
|
54729247e1 | ||
|
|
dd0a0f79d7 | ||
|
|
daa1a455c6 | ||
|
|
2621f8a340 | ||
|
|
ea8be373a9 | ||
|
|
47dc5922ca | ||
|
|
22b2265053 | ||
|
|
d6b31e4578 | ||
|
|
93b3726240 | ||
|
|
67f40fb237 | ||
|
|
1d191fdf03 | ||
|
|
43cab7c283 | ||
|
|
d4df8f4925 | ||
|
|
824f83fd20 | ||
|
|
275a0f25d3 | ||
|
|
ee7b8f32e3 | ||
|
|
3c014a67ea | ||
|
|
7281d95aee | ||
|
|
b50030b1d0 | ||
|
|
26ed00118b | ||
|
|
8212d97317 | ||
|
|
17f324b836 | ||
|
|
1b0aab621b | ||
|
|
3d2daa2d03 | ||
|
|
ae4865efa1 | ||
|
|
09630e48ce | ||
|
|
98f7729848 | ||
|
|
8fa9264430 | ||
|
|
467504da01 | ||
|
|
30b7344eb0 | ||
|
|
00ee84e1e1 | ||
|
|
9bbfd5efd4 | ||
|
|
ddea7cb702 | ||
|
|
0992588811 | ||
|
|
ed584e2ffd | ||
|
|
64ececb72f | ||
|
|
8c936edeb2 | ||
|
|
6dde019d93 | ||
|
|
4bd95f8b44 | ||
|
|
521759ee18 | ||
|
|
fb7b715b7b | ||
|
|
bc25545fbb | ||
|
|
722fb2d251 | ||
|
|
43fecb0acb | ||
|
|
fff2dd2627 | ||
|
|
a63d4a6cc2 | ||
|
|
0dce9a21ce | ||
|
|
1e06e81b3d | ||
|
|
2c1620ce1f | ||
|
|
3ea03a1188 | ||
|
|
fce0036a67 | ||
|
|
1aa4599ddd | ||
|
|
bbe8d51bd9 | ||
|
|
e5ce5e2a43 | ||
|
|
78913211a9 | ||
|
|
84b245f187 | ||
|
|
7203b58e87 | ||
|
|
b4c65c253f | ||
|
|
7ce8860b6b | ||
|
|
8047340d75 | ||
|
|
117158fcd5 | ||
|
|
1c9210bc2b | ||
|
|
e9751d2ac0 | ||
|
|
401af50dc0 | ||
|
|
abd0fcfc86 | ||
|
|
e13d462f77 | ||
|
|
a5aa03acaf | ||
|
|
1b7f622410 | ||
|
|
664bc44f30 | ||
|
|
d50f649cf8 | ||
|
|
ef63ab5724 | ||
|
|
0a4eb4dbf2 | ||
|
|
b61336483b | ||
|
|
d0f31ccf33 | ||
|
|
da199e4407 | ||
|
|
fe03e7bcb7 | ||
|
|
a67651406d | ||
|
|
0e1b5faad5 | ||
|
|
c5f52b845b | ||
|
|
755b01439b | ||
|
|
acaccb37ec | ||
|
|
dd5353a405 | ||
|
|
ab8012bd80 | ||
|
|
a83124361e | ||
|
|
2eb844e0b4 | ||
|
|
2195046365 | ||
|
|
5efd3f0dca | ||
|
|
3c2b377711 | ||
|
|
2fe7e6bef0 | ||
|
|
3db2b23060 | ||
|
|
02fa8dff85 | ||
|
|
831137b807 | ||
|
|
16a6a47a7b | ||
|
|
6e2fb56d40 | ||
|
|
257848587f | ||
|
|
1d899e1783 | ||
|
|
7a30e87d2b | ||
|
|
ab1e36dcf9 | ||
|
|
d977d268e8 | ||
|
|
f7782f8082 | ||
|
|
969e4bbe6a | ||
|
|
3911d5af32 | ||
|
|
67a5bfc6d8 | ||
|
|
0d7de08e06 | ||
|
|
64a909ef51 | ||
|
|
a1528364b3 | ||
|
|
3386477b29 | ||
|
|
be3ae9d13c | ||
|
|
c5d8ffef58 | ||
|
|
130fde8130 | ||
|
|
951fc7e993 | ||
|
|
d874702fe1 | ||
|
|
1a1cceaf6f | ||
|
|
8fb255dc34 | ||
|
|
2d11b17419 | ||
|
|
f925165942 | ||
|
|
f2ed736b29 | ||
|
|
36ccdc952c | ||
|
|
17298af61e | ||
|
|
f7c4f9a640 | ||
|
|
29e9db0c58 | ||
|
|
bb7f5b5501 | ||
|
|
a6eff059b9 | ||
|
|
967ceba5b7 | ||
|
|
c1481bb0ab | ||
|
|
4651c4381e | ||
|
|
de2a2e296b | ||
|
|
bdbe8c9ae2 | ||
|
|
e242b1785f | ||
|
|
1f0aaece3a | ||
|
|
645045a799 | ||
|
|
d288ae8eb9 | ||
|
|
ce936edf62 | ||
|
|
d4a874b81e | ||
|
|
5a4a2b1db3 | ||
|
|
e84325bd1d | ||
|
|
f54a96d6a2 | ||
|
|
3ff259a262 | ||
|
|
1be0fde45c | ||
|
|
0891cf7d2d | ||
|
|
33ac0fd09f | ||
|
|
bbe2e22fcb | ||
|
|
f4fcc14cfb | ||
|
|
946f870e3c | ||
|
|
3a309d93b1 | ||
|
|
9f001b09a8 | ||
|
|
55995869e5 | ||
|
|
f380904bd9 | ||
|
|
36c6d2fa7d | ||
|
|
e23d5a64cf | ||
|
|
c6ee273410 | ||
|
|
354e688d8e | ||
|
|
acc208418b | ||
|
|
2b7236d249 | ||
|
|
519cef813e | ||
|
|
cbc489dff5 | ||
|
|
eed2f36ae2 | ||
|
|
082b12128d | ||
|
|
f2d532c404 | ||
|
|
c03dd3b2f9 | ||
|
|
54a1d9ecb7 | ||
|
|
1a1d11fa32 | ||
|
|
5ae3ddcc9a | ||
|
|
66b96822fb | ||
|
|
9aaf888b42 | ||
|
|
dd7d2e0810 | ||
|
|
f7697ff393 | ||
|
|
f4c17378b3 | ||
|
|
95c9cc8114 | ||
|
|
add6f4556e | ||
|
|
7a99639cff | ||
|
|
b4eccfd02d | ||
|
|
30d0cf4885 | ||
|
|
75feece208 | ||
|
|
0077958ad0 | ||
|
|
d735278c9f | ||
|
|
e9a684d741 | ||
|
|
e042f485ed | ||
|
|
3376875bc8 | ||
|
|
0d9b450701 | ||
|
|
f99491cbf7 | ||
|
|
bd33aa313e | ||
|
|
5d8164167e | ||
|
|
b8cfb0d7b2 | ||
|
|
999cedb90f | ||
|
|
cbf7674025 | ||
|
|
94fe6e523d | ||
|
|
254cfa6c31 | ||
|
|
9f6976b74e | ||
|
|
278f3592d4 | ||
|
|
5d66b427e2 | ||
|
|
c3f64d9799 | ||
|
|
4e7107a572 | ||
|
|
fad7d9317b | ||
|
|
0bb57bf5bf | ||
|
|
9d0d6d3830 | ||
|
|
698a6a9d7d | ||
|
|
19920e25f9 | ||
|
|
0786716c5a | ||
|
|
7a5a4fe271 | ||
|
|
88a9103b3c | ||
|
|
3048433809 | ||
|
|
61e85a8ce0 | ||
|
|
061eb6fa6b | ||
|
|
7dec35d7cc | ||
|
|
364bb61df3 | ||
|
|
8844d031e4 | ||
|
|
f32020ef3d | ||
|
|
f0fbab7ca7 | ||
|
|
3a1bbcc2ef | ||
|
|
c8437f97ae | ||
|
|
90202b4c0d | ||
|
|
ff8c4188f4 | ||
|
|
65888e2006 | ||
|
|
36bd10779c | ||
|
|
e99e6c883d | ||
|
|
3cfb02f166 | ||
|
|
18820471ae | ||
|
|
22bd23114a | ||
|
|
9936aa3f87 | ||
|
|
522d454e34 | ||
|
|
3baf6b5319 | ||
|
|
a58fa27c24 | ||
|
|
bf1570cb25 | ||
|
|
6edffd0df5 | ||
|
|
b677f03407 | ||
|
|
9f5486c7e2 | ||
|
|
056abbcf31 | ||
|
|
86aa16bea6 | ||
|
|
4dea24e105 | ||
|
|
4892e4c5fc | ||
|
|
9a56912ad1 | ||
|
|
0e3f29cc99 | ||
|
|
a8aa1998ce | ||
|
|
44e6e348d6 | ||
|
|
39a8deb95f | ||
|
|
9f10d3fb63 | ||
|
|
4120f32292 | ||
|
|
b3be4710aa | ||
|
|
b56c635d64 | ||
|
|
3d6240ba1b | ||
|
|
3c4c069802 | ||
|
|
b64e0575fd | ||
|
|
9aaccd4735 | ||
|
|
1818da2ef3 | ||
|
|
8ee43e24f3 | ||
|
|
c3280d83e7 | ||
|
|
ede1f547e7 | ||
|
|
295ea12411 | ||
|
|
72bd172b30 | ||
|
|
3ba61656bd | ||
|
|
2ae7ced721 | ||
|
|
acb743da64 | ||
|
|
83229d3ffe | ||
|
|
54df549b5f | ||
|
|
b5b1f2c527 | ||
|
|
f148727b78 | ||
|
|
d4dba88236 | ||
|
|
f5c554dfe3 | ||
|
|
593faf14c4 | ||
|
|
db0a5aed39 | ||
|
|
efc4da4be9 | ||
|
|
426f326d35 | ||
|
|
9142179f81 | ||
|
|
7080e9632c | ||
|
|
00960133c2 | ||
|
|
f3308daa6f | ||
|
|
994ff738c8 | ||
|
|
a24eafacc9 | ||
|
|
2c83894257 | ||
|
|
cbd9ae5256 | ||
|
|
e4404fbef0 | ||
|
|
65971f5160 | ||
|
|
79c4ec1102 | ||
|
|
f8bc3f6964 | ||
|
|
3862ef9a9f | ||
|
|
ec314c951d | ||
|
|
16d42368a6 | ||
|
|
908f5159cf | ||
|
|
5be60d6929 | ||
|
|
863d4cd862 | ||
|
|
0d6116d86b | ||
|
|
0aff87b808 | ||
|
|
27dafa5ed5 | ||
|
|
d8557834c0 | ||
|
|
a01f6c9ae7 | ||
|
|
66fd3e4a7b | ||
|
|
3a6b3d230c | ||
|
|
94f9330d3e | ||
|
|
6d1eabfeaa | ||
|
|
432e8275a9 | ||
|
|
d8c834c95d | ||
|
|
c8e9c0d89a | ||
|
|
713ea1800d | ||
|
|
3a3db4dcf0 | ||
|
|
9b7f583b0c | ||
|
|
f882d53fcd | ||
|
|
772f0b4159 | ||
|
|
3c7e1b80ac | ||
|
|
3551368424 | ||
|
|
73ff0687f2 | ||
|
|
b1dbbd32eb | ||
|
|
1b9d161f94 | ||
|
|
549c79d11e | ||
|
|
746b752b8e | ||
|
|
1f92ffb5b7 | ||
|
|
723d598d32 | ||
|
|
40274fec9c | ||
|
|
50f56227c6 | ||
|
|
c27e5c4b0b | ||
|
|
748509a93c | ||
|
|
34472302d6 | ||
|
|
6e68a68d18 | ||
|
|
57e00ef262 | ||
|
|
7f3c0d1ea8 | ||
|
|
41b688e25f | ||
|
|
89f2ddd2d0 | ||
|
|
b7ca945877 | ||
|
|
e6dccaf18e | ||
|
|
ae58035573 | ||
|
|
8b8d189bc0 | ||
|
|
8f7ff854b0 | ||
|
|
8bfa11b138 | ||
|
|
8cee03b118 | ||
|
|
1673e19cb9 | ||
|
|
af3e45419c | ||
|
|
53ea2b5ce2 | ||
|
|
074d713bfb | ||
|
|
a9f3030371 | ||
|
|
98fb0bf68a | ||
|
|
040f6f6711 | ||
|
|
1bfa6ae6e4 | ||
|
|
dde0c204e7 | ||
|
|
c76fe77f42 | ||
|
|
35e7d9c0f1 | ||
|
|
06f70973f7 | ||
|
|
32b3549cce | ||
|
|
056cb288d9 | ||
|
|
f67d06194f | ||
|
|
d0601b0a1f | ||
|
|
aeadf7607d | ||
|
|
aee704ebe1 | ||
|
|
7cce2f664c | ||
|
|
000a12783c | ||
|
|
4deb4936d5 | ||
|
|
0ec51441de | ||
|
|
731f359292 | ||
|
|
0bd3f3291d | ||
|
|
2b080cf599 | ||
|
|
f705cb5f7a | ||
|
|
24b03561bd | ||
|
|
bd9f850e85 | ||
|
|
d6201fc4b7 | ||
|
|
165734522e | ||
|
|
3833d3846d | ||
|
|
43efb46328 | ||
|
|
c6bc5b69c2 | ||
|
|
3819634469 | ||
|
|
b83d0b35e9 | ||
|
|
823a961ecc | ||
|
|
3510499a9e | ||
|
|
17c649da3d | ||
|
|
6f70283909 | ||
|
|
98b6d35c4f | ||
|
|
9b12bc788f | ||
|
|
19b671c5cd | ||
|
|
f4decdc4a3 | ||
|
|
eb099b9893 | ||
|
|
4a9eac20b9 | ||
|
|
6a09e7d7ae | ||
|
|
04fa999cfe | ||
|
|
ebd9f550e8 | ||
|
|
5699fc9d0e | ||
|
|
a2e0d92eeb | ||
|
|
f3b1a933fc | ||
|
|
a0fb7a76cd | ||
|
|
20f85feecc | ||
|
|
404dae80a9 | ||
|
|
9011815d86 | ||
|
|
858ed6d2f7 | ||
|
|
fa87e90cfa | ||
|
|
76217064ac | ||
|
|
a13d22f921 | ||
|
|
1950295735 | ||
|
|
e0d7740a22 | ||
|
|
f3e46d0c52 | ||
|
|
12fab63928 | ||
|
|
dc93f25bb8 | ||
|
|
393d0c1679 | ||
|
|
79f404a287 | ||
|
|
8e8aac89a5 | ||
|
|
c773053f58 | ||
|
|
a654914de4 | ||
|
|
359a8aa760 | ||
|
|
a3a33db409 | ||
|
|
ca9eb81d0b | ||
|
|
1c55310bcc | ||
|
|
b7ab70c71c | ||
|
|
cf6daa0966 | ||
|
|
4a9c60cdfb | ||
|
|
81a1e17238 | ||
|
|
0dbd928cee | ||
|
|
9a334d41e3 | ||
|
|
805c6534f8 | ||
|
|
22cb7cd953 | ||
|
|
91f2168dd5 | ||
|
|
ee7bebc94f | ||
|
|
4efed58df1 | ||
|
|
0212dc65b7 | ||
|
|
9ebd4dabf2 | ||
|
|
9273cca432 | ||
|
|
126373ac70 | ||
|
|
e954604ae0 | ||
|
|
fe08e3a54f | ||
|
|
8fd8bb36b3 | ||
|
|
3b24e83731 | ||
|
|
bb489066e8 | ||
|
|
109b363ddc | ||
|
|
075ca64521 | ||
|
|
be2879ce89 | ||
|
|
ee0058d174 | ||
|
|
1f2daf4304 | ||
|
|
1c7f9b16f0 | ||
|
|
ceb169008d | ||
|
|
04db848dc7 | ||
|
|
4b630c452d | ||
|
|
719dca2515 | ||
|
|
d67ea6b29f | ||
|
|
7ff585333e | ||
|
|
9a507c67ad | ||
|
|
9d7ef05caf | ||
|
|
e693e52442 | ||
|
|
9d0192de4a | ||
|
|
f09f8097d5 | ||
|
|
d19e4f0ba4 | ||
|
|
f961456b29 | ||
|
|
22521ea9e2 | ||
|
|
04353cc85e | ||
|
|
183edefddd | ||
|
|
aedb859177 | ||
|
|
7e359c648b | ||
|
|
aaef1851a7 | ||
|
|
60401d461a | ||
|
|
b106532b32 | ||
|
|
8e6e9eaea5 | ||
|
|
acea9352a9 | ||
|
|
9058a7031f | ||
|
|
a787467569 | ||
|
|
4078336d38 | ||
|
|
2f96b1982a | ||
|
|
bedab235f9 | ||
|
|
83158e0e7f | ||
|
|
d8066e999d | ||
|
|
504420c51d | ||
|
|
2c040edef8 | ||
|
|
9c72c71c05 | ||
|
|
f4c50f1cfc | ||
|
|
ae70e98ed4 | ||
|
|
8faf2dc75b | ||
|
|
36ae417c9f | ||
|
|
2e0cd20a1d | ||
|
|
65f6324573 | ||
|
|
d8137178bb | ||
|
|
39a380b621 | ||
|
|
e0f5df579b | ||
|
|
8ee153f234 | ||
|
|
fd379db286 | ||
|
|
096d1e4512 | ||
|
|
949c5c9180 | ||
|
|
7799410950 | ||
|
|
2ca7b05552 | ||
|
|
f8e9ef5cd0 | ||
|
|
020386b61c | ||
|
|
c3000b6f69 | ||
|
|
6ec6f51326 | ||
|
|
4542643025 | ||
|
|
fca3308cc3 | ||
|
|
e19dfe1c32 | ||
|
|
affcbe4139 | ||
|
|
6a515b95a8 | ||
|
|
c13be69a8e | ||
|
|
035a0a2b6e | ||
|
|
e813541e3f | ||
|
|
4bf3f2d3c0 | ||
|
|
556c8a9a4f | ||
|
|
4300c7dba2 | ||
|
|
74d0df7324 | ||
|
|
d7e3b36a09 | ||
|
|
fcce1483fa | ||
|
|
2430dfac31 | ||
|
|
fe29cc192d | ||
|
|
41eb705477 | ||
|
|
2ec835f572 | ||
|
|
59a41e8fcd | ||
|
|
d6442407f5 | ||
|
|
b5c43be135 | ||
|
|
b8f9ac5411 | ||
|
|
21f43ba9b0 | ||
|
|
3c9c3687d6 | ||
|
|
408b74d74c | ||
|
|
fdfcee7b1e | ||
|
|
64f2b213bb | ||
|
|
91fc075a33 | ||
|
|
3aa7dd23c9 | ||
|
|
fccbe9aa4d | ||
|
|
0334058fa4 | ||
|
|
6206f431cf | ||
|
|
46a1102852 | ||
|
|
1b586f3a73 | ||
|
|
53ca6ae1f3 | ||
|
|
95b352064e | ||
|
|
24652228af | ||
|
|
845b5a2a58 | ||
|
|
7381b7ac71 | ||
|
|
0e87bc7be6 | ||
|
|
01d64914c5 | ||
|
|
366239b8b9 | ||
|
|
02041bf2e0 | ||
|
|
216b6a494e | ||
|
|
b948de36fb | ||
|
|
4fb5ff86ee | ||
|
|
9f5f156b9d | ||
|
|
7e12a601b8 | ||
|
|
2a8d7ee0f8 | ||
|
|
fd38799049 | ||
|
|
fa391eed9d | ||
|
|
37ab061f4d | ||
|
|
aaa8867d4a | ||
|
|
062bd81814 | ||
|
|
f4d55c91fe | ||
|
|
326ff54649 | ||
|
|
90a36942b4 | ||
|
|
1ea4b77a9a | ||
|
|
0496de26d3 | ||
|
|
f22be4ebd9 | ||
|
|
34f26ea862 | ||
|
|
9e0a3d46b6 | ||
|
|
90b1cc5103 | ||
|
|
58e0f4ac50 | ||
|
|
e5635f4ab3 | ||
|
|
2065373f67 | ||
|
|
a81539db25 | ||
|
|
2f4e8511cd | ||
|
|
4c02e54298 | ||
|
|
5f3c3ec5e6 | ||
|
|
c4489a0543 | ||
|
|
0eba162ab5 | ||
|
|
f3ca8623f7 | ||
|
|
77020281ae | ||
|
|
f1a9923308 | ||
|
|
2a8a564fbd | ||
|
|
0d28a3edb9 | ||
|
|
ff736d6f6f | ||
|
|
d88d3b0b3a | ||
|
|
b6bdb0dbda | ||
|
|
ed6a5b78ad | ||
|
|
d5de1bf853 | ||
|
|
eb9a3ec654 | ||
|
|
6143f63560 | ||
|
|
37a2015cc5 | ||
|
|
958e273336 | ||
|
|
c92e6a45eb | ||
|
|
0a7e4fa5ce | ||
|
|
8192310dad | ||
|
|
ef369249cb | ||
|
|
a7261ae059 | ||
|
|
635ef16432 | ||
|
|
57fa14b5be | ||
|
|
dbdcb58d64 | ||
|
|
81d64ab939 | ||
|
|
c0a79cc919 | ||
|
|
7e18d3b6ff | ||
|
|
9d5e5c08ab | ||
|
|
5572f735b6 | ||
|
|
e632b1fda7 | ||
|
|
941040e9e8 | ||
|
|
dfa915a6af | ||
|
|
fbcaf0ea18 | ||
|
|
e6978a4e26 | ||
|
|
587914169c | ||
|
|
ed22e9ba3e | ||
|
|
dcbe936c50 | ||
|
|
dffa9f6da6 | ||
|
|
660f8613fd | ||
|
|
06d93b36f9 | ||
|
|
b2d880d749 | ||
|
|
6196aa45ed | ||
|
|
15018291b2 | ||
|
|
bfb272b9e0 | ||
|
|
c0035d1694 | ||
|
|
1e9d8e110b | ||
|
|
b0c08c8c17 | ||
|
|
011c7f5718 | ||
|
|
1cb5de2cd5 | ||
|
|
861fad5819 | ||
|
|
22b4c28f85 | ||
|
|
0e52d9860a | ||
|
|
aba75e1233 | ||
|
|
624cdeacc4 | ||
|
|
41f6948545 | ||
|
|
8332044f75 | ||
|
|
d5ec336eef | ||
|
|
f38d16483a | ||
|
|
e77abc261b | ||
|
|
c69642a460 | ||
|
|
3c4b78e166 | ||
|
|
7d6b6f6681 | ||
|
|
4ba9b34012 | ||
|
|
cb6cf5e257 | ||
|
|
661d9d1901 | ||
|
|
aeb62f9ae3 | ||
|
|
d80174d7c3 | ||
|
|
e2bfa471fa | ||
|
|
04fffe6562 | ||
|
|
0d6b2341b8 | ||
|
|
8b4fb4fe14 | ||
|
|
b230a86d33 | ||
|
|
5167332131 | ||
|
|
7a4b10cc4c | ||
|
|
a5deadf082 | ||
|
|
26a9b4d48e | ||
|
|
7731edf2f5 | ||
|
|
229b908d2e | ||
|
|
3ca84026db | ||
|
|
0af73014cc | ||
|
|
4e7bde8c9e | ||
|
|
9d6128acdc | ||
|
|
e79c6b6312 | ||
|
|
f352fe82a5 | ||
|
|
d265df589e | ||
|
|
7c87747db0 | ||
|
|
425958b616 | ||
|
|
4cc0cd6cab | ||
|
|
d936317143 | ||
|
|
359b4e9ed9 | ||
|
|
1d399c3c88 | ||
|
|
4d7fa05b43 | ||
|
|
4054c4eadd | ||
|
|
f8b98d8329 | ||
|
|
88ca6c94d9 | ||
|
|
f91f212d9f | ||
|
|
36821d095a | ||
|
|
d5e256486e | ||
|
|
42054c3cad | ||
|
|
598aad2140 | ||
|
|
475c60eefc | ||
|
|
86854c7071 | ||
|
|
e3f8777ee8 | ||
|
|
ec8589e4c9 | ||
|
|
b864e7afe4 | ||
|
|
75a811a6df | ||
|
|
2b000474d9 | ||
|
|
0be3c70cd8 | ||
|
|
081f9325f5 | ||
|
|
a7ffa972f3 | ||
|
|
558a016e2c | ||
|
|
3a2171e406 | ||
|
|
42cec5c893 | ||
|
|
55b11e6d38 | ||
|
|
0b7a66ab97 | ||
|
|
ea5b59bfe6 | ||
|
|
8d8fdcb4be | ||
|
|
821b7f22fe | ||
|
|
25afc7da0d | ||
|
|
e2aa117798 | ||
|
|
516982242d | ||
|
|
8bf00084b6 | ||
|
|
81794fcd31 | ||
|
|
22602cc37b | ||
|
|
1b693543aa | ||
|
|
ab2594e341 | ||
|
|
2ff2ea5f3b | ||
|
|
21ffa7c4ba | ||
|
|
696eee9475 | ||
|
|
a9058bf294 | ||
|
|
39c91d3624 | ||
|
|
000730ecaa | ||
|
|
c9fa667252 | ||
|
|
c2ec2ad8fb | ||
|
|
6433f71e8f | ||
|
|
a3fe307400 | ||
|
|
1a1b48e51a | ||
|
|
e8ad47a6ca | ||
|
|
b648e98ad0 | ||
|
|
7ef75f9f75 | ||
|
|
51b9a0d0c4 | ||
|
|
1d350b8ac6 | ||
|
|
a488c266c3 | ||
|
|
86e6ad76cb | ||
|
|
58d9b10d70 | ||
|
|
0a8b5d160b | ||
|
|
18c22faf4d | ||
|
|
5cb524673e | ||
|
|
a66a99bfd8 | ||
|
|
a160b70ced | ||
|
|
8b3b2d04a8 | ||
|
|
936e25b164 | ||
|
|
5ab0a4a671 | ||
|
|
aa65e1edb3 | ||
|
|
d007cb8903 | ||
|
|
d292a81e95 | ||
|
|
22ff397fb1 | ||
|
|
7f70b60f4d | ||
|
|
2a6660ba59 | ||
|
|
1abb449dfb | ||
|
|
65dc960e3b | ||
|
|
0e978349a5 | ||
|
|
e9fa7625f4 | ||
|
|
c0c07fb1b6 | ||
|
|
aa8e8acb7d | ||
|
|
f837d166e5 | ||
|
|
9249242119 | ||
|
|
641a3d39e1 | ||
|
|
6ff2d54347 | ||
|
|
11d21081b4 | ||
|
|
34c290b678 | ||
|
|
ea5061e409 | ||
|
|
4c5bfe2d10 | ||
|
|
c6f1d47dcb | ||
|
|
3179d23cee | ||
|
|
bdd78c31b6 | ||
|
|
c39093d801 | ||
|
|
94ef8879cd | ||
|
|
b7d59060e2 | ||
|
|
032b0e9369 | ||
|
|
0d5d16074f | ||
|
|
7027fd5343 | ||
|
|
7da2fdc3cd | ||
|
|
2673374d18 | ||
|
|
651c870d77 | ||
|
|
aa3569cd57 | ||
|
|
8cd9fedf58 | ||
|
|
e23ae63970 | ||
|
|
31f6a6fa70 | ||
|
|
e54a4f1f48 | ||
|
|
d43019163d | ||
|
|
00c4d6562e | ||
|
|
e86b47175f | ||
|
|
20f40c3229 | ||
|
|
dbfba6a20e | ||
|
|
7ede3ec4b1 | ||
|
|
872f9af6ae | ||
|
|
8f59bacb92 | ||
|
|
be66a9ecf6 | ||
|
|
4836bcc957 | ||
|
|
89852d38ef | ||
|
|
526dd54252 | ||
|
|
8a1a5c236d | ||
|
|
5e11d2b349 | ||
|
|
34fe5a30c6 | ||
|
|
26664dd180 | ||
|
|
4434e43fa1 | ||
|
|
7a55c1a884 | ||
|
|
28e51c9eb1 | ||
|
|
af9d885f8c | ||
|
|
9e8eba797e | ||
|
|
8f1eced69d | ||
|
|
751485fe6b | ||
|
|
a632037866 | ||
|
|
c0e39864c6 | ||
|
|
6e552e15fa | ||
|
|
0851751615 | ||
|
|
6f1c00869c | ||
|
|
1934dca6de | ||
|
|
7a26e4f484 | ||
|
|
9a2913ed1c | ||
|
|
c6926c374d | ||
|
|
3a2fb201a5 | ||
|
|
a95b06fc6b | ||
|
|
92d4b51ad5 | ||
|
|
7e7fb0b7a3 | ||
|
|
ea8bf81058 | ||
|
|
f243851ccd | ||
|
|
7c934ae501 | ||
|
|
aa58c7ec74 | ||
|
|
b56634e691 | ||
|
|
fb3f9cff33 | ||
|
|
da33b31c7d | ||
|
|
9a348fc840 | ||
|
|
007878781c | ||
|
|
cfc4c33801 | ||
|
|
28596edf07 | ||
|
|
7ccdf8be77 | ||
|
|
f5d04750db | ||
|
|
92e9a5e0a7 | ||
|
|
84d59c2873 | ||
|
|
d8a7f8bff2 | ||
|
|
3dd0b69e46 | ||
|
|
7d588b0c7c | ||
|
|
cd14188bc8 | ||
|
|
db109ca0fc | ||
|
|
f1236734bb | ||
|
|
9de53bf788 | ||
|
|
3900fed849 | ||
|
|
96f0dd3cbc | ||
|
|
fa7c61dfab | ||
|
|
d241c2a592 | ||
|
|
f17e663493 | ||
|
|
e45c1dbd6f | ||
|
|
7693ef3bd6 | ||
|
|
99a21dc05d | ||
|
|
abc24c1876 | ||
|
|
6f5e0fe955 | ||
|
|
6a388aaa7c | ||
|
|
2af846e711 | ||
|
|
4915c2b871 | ||
|
|
cceff157dd | ||
|
|
32aba40830 | ||
|
|
f576057274 | ||
|
|
0621eca05e | ||
|
|
a39df51d8a | ||
|
|
e4d43401eb | ||
|
|
d136737872 | ||
|
|
75b1d881ec | ||
|
|
c3bd9415cc | ||
|
|
1e8ca3a3cf | ||
|
|
ab14c30493 | ||
|
|
f22b35e4e5 | ||
|
|
a243d6b057 | ||
|
|
f738424403 | ||
|
|
753a8e8bc4 | ||
|
|
e955089da0 | ||
|
|
9309e609cd | ||
|
|
ade9a05236 | ||
|
|
c48740e20b | ||
|
|
b178dccb9c | ||
|
|
3b83aeb403 | ||
|
|
115afdb07d | ||
|
|
cf814b2d34 | ||
|
|
ecb7f9fe58 | ||
|
|
fa47bebfbc | ||
|
|
8eb802a55b | ||
|
|
af33ebb13b | ||
|
|
9220dc466a | ||
|
|
d18ced9cdd | ||
|
|
7463442e58 | ||
|
|
354d17523f | ||
|
|
a0a3de60be | ||
|
|
5685b565c3 | ||
|
|
76e52b5daf | ||
|
|
fa655ce196 | ||
|
|
194c8c761e | ||
|
|
11115e4d23 | ||
|
|
c91727b75a | ||
|
|
9f76dcd682 | ||
|
|
ef7dd8db2d | ||
|
|
6ab8b63bdd | ||
|
|
68e8b595de | ||
|
|
722d4842df | ||
|
|
de575c80b9 | ||
|
|
3a2e9f20f6 | ||
|
|
7e66b859b2 | ||
|
|
aaf7c5b35e | ||
|
|
c030e77861 | ||
|
|
219a74c014 | ||
|
|
7370fd5560 | ||
|
|
e284a95cc3 | ||
|
|
616986a5f3 | ||
|
|
b19d273beb | ||
|
|
31b40eebe8 | ||
|
|
035deae1c6 | ||
|
|
5161239c9f | ||
|
|
9a65fa304c | ||
|
|
7c1c9af5d4 | ||
|
|
4f8eeaedef | ||
|
|
d680e28a11 | ||
|
|
7fd538c1b6 | ||
|
|
f522849a4d | ||
|
|
077812b2ab | ||
|
|
bdf958df30 | ||
|
|
70fc42cb28 | ||
|
|
5ebf39784a | ||
|
|
9780e55274 | ||
|
|
4f5b896a0b | ||
|
|
813b581127 | ||
|
|
778413168b | ||
|
|
0807139c1d | ||
|
|
fa1cdb09fc | ||
|
|
8cc8f280eb | ||
|
|
9896314f5b | ||
|
|
c4045f57e3 | ||
|
|
6557a096d6 | ||
|
|
f44cc517a2 | ||
|
|
abfd4da287 | ||
|
|
59fba2d6ea | ||
|
|
ed570e4b2a | ||
|
|
484adac0bb | ||
|
|
f64e080d9a | ||
|
|
e44c1d3ace | ||
|
|
186b355b28 | ||
|
|
0d3e309ebc | ||
|
|
2110dc5a6d | ||
|
|
aef3846c13 | ||
|
|
4af5424242 | ||
|
|
c5175526dd | ||
|
|
3299f687f5 | ||
|
|
9c7d183a94 | ||
|
|
d02f671737 | ||
|
|
d709622bd2 | ||
|
|
e64afde073 | ||
|
|
2a1090a637 | ||
|
|
228c68a9cd | ||
|
|
6e1dfb0d1a | ||
|
|
de8b585ab7 | ||
|
|
c4b592d379 | ||
|
|
fe99ea9aab | ||
|
|
7f19a39a3b | ||
|
|
a06c38b486 | ||
|
|
63b9e598a3 | ||
|
|
60ccb41fac | ||
|
|
06593fb0f2 | ||
|
|
a193ced7fa | ||
|
|
c8870b7c69 | ||
|
|
b6a08208e1 | ||
|
|
fb4b800820 | ||
|
|
0cba23716d | ||
|
|
b85bf25e97 | ||
|
|
2474c2ae94 | ||
|
|
92d95cc9d3 | ||
|
|
7c61249ae6 | ||
|
|
686516f90a | ||
|
|
ea2cc2b907 | ||
|
|
cdfa11f550 |
10
.gitmodules
vendored
Normal file
10
.gitmodules
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
[submodule "lib/axtls"]
|
||||
path = lib/axtls
|
||||
url = https://github.com/pfalcon/axtls
|
||||
branch = micropython
|
||||
[submodule "lib/libffi"]
|
||||
path = lib/libffi
|
||||
url = https://github.com/atgreen/libffi
|
||||
[submodule "lib/lwip"]
|
||||
path = lib/lwip
|
||||
url = http://git.savannah.gnu.org/r/lwip.git
|
||||
25
.travis.yml
25
.travis.yml
@@ -1,22 +1,31 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
before_script:
|
||||
- sudo add-apt-repository -y ppa:fkrull/deadsnakes
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
# Extra CPython versions
|
||||
# - sudo add-apt-repository -y ppa:fkrull/deadsnakes
|
||||
# Extra gcc versions
|
||||
# - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y python3.4 python3 gcc-4.7 gcc-multilib gcc-arm-none-eabi qemu-system mingw32
|
||||
- sudo dpkg --add-architecture i386
|
||||
- sudo apt-get update -qq || true
|
||||
- sudo apt-get install -y python3 gcc-multilib gcc-arm-none-eabi pkg-config libffi-dev libffi-dev:i386 qemu-system mingw32
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
# For coverage testing
|
||||
- sudo pip install cpp-coveralls
|
||||
- gcc --version
|
||||
- arm-none-eabi-gcc --version
|
||||
- python3 --version
|
||||
|
||||
script:
|
||||
- make -C minimal test
|
||||
- make -C unix CC=gcc-4.7
|
||||
- make -C unix-cpy CC=gcc-4.7
|
||||
- make -C unix deplibs
|
||||
- make -C unix
|
||||
- make -C unix nanbox
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm test
|
||||
- make -C stmhal
|
||||
@@ -32,12 +41,12 @@ script:
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native)
|
||||
|
||||
# run tests with coverage info
|
||||
- make -C unix CC=gcc-4.7 coverage
|
||||
- make -C unix coverage
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --emit native)
|
||||
|
||||
after_success:
|
||||
- (cd unix && coveralls --root .. --build-root . --gcov $(which gcov-4.7) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
- (cd unix && coveralls --root .. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
The Micro Python project was proudly and successfully crowdfunded
|
||||
The MicroPython project was proudly and successfully crowdfunded
|
||||
via a Kickstarter campaign which ended on 13th December 2013. The
|
||||
project was supported by 1923 very generous backers, who pledged
|
||||
for a total of 2320 pyboards.
|
||||
|
||||
@@ -33,37 +33,50 @@ Braces:
|
||||
closing brace.
|
||||
|
||||
Header files:
|
||||
- Try to stick to the Plan 9 header style, where header files do not
|
||||
include other header files.
|
||||
- Don't protect a header file from multiple inclusion with #if directives.
|
||||
- Header files should be protected from multiple inclusion with #if
|
||||
directives. See an existing header for naming convention.
|
||||
|
||||
Type names and declarations:
|
||||
- When defining a type, put '_t' after it.
|
||||
Names:
|
||||
- Use underscore_case, not camelCase for all names.
|
||||
- Use CAPS_WITH_UNDERSCORE for enums and macros.
|
||||
- When defining a type use underscore_case and put '_t' after it.
|
||||
|
||||
Integer types: Micro Python runs on 32 and 64 bit machines (and one day
|
||||
maybe 16 bit), so it's important to use the correctly-sized (and signed)
|
||||
integer types. The general guidelines are:
|
||||
Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's
|
||||
important to use the correctly-sized (and signed) integer types. The
|
||||
general guidelines are:
|
||||
- For most cases use mp_int_t for signed and mp_uint_t for unsigned
|
||||
integer values. These are guaranteed to be machine-word sized and
|
||||
therefore big enough to hold the value from a Micro Python small-int
|
||||
therefore big enough to hold the value from a MicroPython small-int
|
||||
object.
|
||||
- Use size_t for things that count bytes / sizes of objects.
|
||||
- You can use int/uint, but remember that they may be 16-bits wide.
|
||||
- If in doubt, use mp_int_t/mp_uint_t.
|
||||
|
||||
Comments:
|
||||
- Be concise and only write comments for things that are not obvious.
|
||||
- Use `// ` prefix, NOT `/* ... */`. No extra fluff.
|
||||
|
||||
Memory allocation:
|
||||
- Use m_new, m_renew, m_del (and friends) to allocate and free heap memory.
|
||||
These macros are defined in py/misc.h.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Braces and spaces:
|
||||
Braces, spaces, names and comments:
|
||||
|
||||
int foo(int x, int y) {
|
||||
if (x < y) {
|
||||
foo(y, x);
|
||||
#define TO_ADD (123)
|
||||
|
||||
// This function will always recurse indefinitely and is only used to show
|
||||
// coding style
|
||||
int foo_function(int x, int some_value) {
|
||||
if (x < some_value) {
|
||||
foo(some_value, x);
|
||||
} else {
|
||||
foo(x + 1, y - 1);
|
||||
foo(x + TO_ADD, some_value - 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x; i++) {
|
||||
for (int my_counter = 0; my_counter < x; my_counter++) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
106
README.md
106
README.md
@@ -8,19 +8,20 @@
|
||||
[istats-issue-img]: http://issuestats.com/github/micropython/micropython/badge/issue
|
||||
[istats-issue-repo]: http://issuestats.com/github/micropython/micropython
|
||||
|
||||
The Micro Python project
|
||||
========================
|
||||
The MicroPython project
|
||||
=======================
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/micropython/micropython/master/logo/upython-with-micro.jpg" alt="MicroPython Logo"/>
|
||||
</p>
|
||||
|
||||
This is the Micro Python project, which aims to put an implementation
|
||||
This is the MicroPython project, which aims to put an implementation
|
||||
of Python 3.x on microcontrollers and small embedded systems.
|
||||
You can find the official website at [micropython.org](http://www.micropython.org).
|
||||
|
||||
WARNING: this project is in beta stage and is subject to changes of the
|
||||
code-base, including project-wide name changes and API changes.
|
||||
|
||||
Micro Python implements the entire Python 3.4 syntax (including exceptions,
|
||||
MicroPython implements the entire Python 3.4 syntax (including exceptions,
|
||||
"with", "yield from", etc.). The following core datatypes are provided:
|
||||
str (including basic Unicode support), bytes, bytearray, tuple, list, dict,
|
||||
set, frozenset, array.array, collections.namedtuple, classes and instances.
|
||||
@@ -33,20 +34,20 @@ Python board, the officially supported reference electronic circuit board.
|
||||
Major components in this repository:
|
||||
- py/ -- the core Python implementation, including compiler, runtime, and
|
||||
core library.
|
||||
- unix/ -- a version of Micro Python that runs on Unix.
|
||||
- stmhal/ -- a version of Micro Python that runs on the Micro Python board
|
||||
- unix/ -- a version of MicroPython that runs on Unix.
|
||||
- stmhal/ -- a version of MicroPython that runs on the MicroPython board
|
||||
with an STM32F405RG (using ST's Cube HAL drivers).
|
||||
- minimal/ -- a minimal Micro Python port. Start with this if you want
|
||||
to port Micro Python to another microcontroller.
|
||||
- minimal/ -- a minimal MicroPython port. Start with this if you want
|
||||
to port MicroPython to another microcontroller.
|
||||
|
||||
Additional components:
|
||||
- bare-arm/ -- a bare minimum version of Micro Python for ARM MCUs. Used
|
||||
- bare-arm/ -- a bare minimum version of MicroPython for ARM MCUs. Used
|
||||
mostly to control code size.
|
||||
- teensy/ -- a version of Micro Python that runs on the Teensy 3.1
|
||||
- teensy/ -- a version of MicroPython that runs on the Teensy 3.1
|
||||
(preliminary but functional).
|
||||
- pic16bit/ -- a version of Micro Python for 16-bit PIC microcontrollers.
|
||||
- cc3200/ -- a version of Micro Python that runs on the CC3200 from TI.
|
||||
- unix-cpy/ -- a version of Micro Python that outputs bytecode (for testing).
|
||||
- pic16bit/ -- a version of MicroPython for 16-bit PIC microcontrollers.
|
||||
- cc3200/ -- a version of MicroPython that runs on the CC3200 from TI.
|
||||
- esp8266/ -- an experimental port for ESP8266 WiFi modules.
|
||||
- tests/ -- test framework and test scripts.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
- examples/ -- a few example Python scripts.
|
||||
@@ -64,7 +65,7 @@ as ARM and MIPS. Making full-featured port to another architecture requires
|
||||
writing some assembly code for the exception handling and garbage collection.
|
||||
Alternatively, fallback implementation based on setjmp/longjmp can be used.
|
||||
|
||||
To build:
|
||||
To build (*):
|
||||
|
||||
$ cd unix
|
||||
$ make
|
||||
@@ -74,21 +75,62 @@ Then to give it a try:
|
||||
$ ./micropython
|
||||
>>> list(5 * x + y for x in range(10) for y in [4, 2, 1])
|
||||
|
||||
Use `CTRL-D` (i.e. EOF) to exit the shell.
|
||||
Learn about command-line options (in particular, how to increase heap size
|
||||
which may be needed for larger applications):
|
||||
|
||||
$ ./micropython --help
|
||||
|
||||
Run complete testsuite:
|
||||
|
||||
$ make test
|
||||
|
||||
Debian/Ubuntu/Mint derivative Linux distros will require build-essentials and
|
||||
libreadline-dev packages installed. To build FFI (Foreign Function Interface)
|
||||
module, libffi-dev and pkg-config packages are required. If you have problems
|
||||
with some dependencies, they can be disabled in unix/mpconfigport.mk .
|
||||
Unix version comes with a builtin package manager called upip, e.g.:
|
||||
|
||||
$ ./micropython -m upip install micropython-pystone
|
||||
$ ./micropython -m pystone
|
||||
|
||||
Browse available modules on
|
||||
[PyPI](https://pypi.python.org/pypi?%3Aaction=search&term=micropython).
|
||||
Standard library modules come from
|
||||
[micropython-lib](https://github.com/micropython/micropython-lib) project.
|
||||
|
||||
External dependencies
|
||||
---------------------
|
||||
|
||||
Building Unix version requires some dependencies installed. For
|
||||
Debian/Ubuntu/Mint derivative Linux distros, install `build-essential`
|
||||
(includes toolchain and make), `libffi-dev`, and `pkg-config` packages.
|
||||
|
||||
Other dependencies can be built together with MicroPython. Oftentimes,
|
||||
you need to do this to enable extra features or capabilities. To build
|
||||
these additional dependencies, first fetch git submodules for them:
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
Use this same command to get the latest versions of dependencies, as
|
||||
they are updated from time to time. After that, in `unix/` dir, execute:
|
||||
|
||||
$ make deplibs
|
||||
|
||||
This will build all available dependencies (regardless whether they
|
||||
are used or not). If you intend to build MicroPython with additional
|
||||
options (like cross-compiling), the same set of options should be passed
|
||||
to `make deplibs`. To actually enabled use of dependencies, edit
|
||||
`unix/mpconfigport.mk` file, which has inline descriptions of the options.
|
||||
For example, to build SSL module (required for `upip` tool described above),
|
||||
set `MICROPY_PY_USSL` to 1.
|
||||
|
||||
In `unix/mpconfigport.mk`, you can also disable some dependencies enabled
|
||||
by default, like FFI support, which requires libffi development files to
|
||||
be installed.
|
||||
|
||||
The STM version
|
||||
---------------
|
||||
|
||||
The "stmhal" port requires an ARM compiler, arm-none-eabi-gcc, and associated
|
||||
bin-utils. For those using Arch Linux, you need arm-none-eabi-binutils and
|
||||
arm-none-eabi-gcc packages from the AUR. Otherwise, try here:
|
||||
arm-none-eabi-gcc packages. Otherwise, try here:
|
||||
https://launchpad.net/gcc-arm-embedded
|
||||
|
||||
To build:
|
||||
@@ -104,25 +146,7 @@ Then to flash the code via USB DFU to your device:
|
||||
|
||||
$ make deploy
|
||||
|
||||
You will need the dfu-util program, on Arch Linux it's dfu-util-git in the
|
||||
AUR. If the above does not work it may be because you don't have the
|
||||
correct permissions. Try then:
|
||||
|
||||
$ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV10/firmware.dfu
|
||||
|
||||
Building the documentation locally
|
||||
----------------------------------
|
||||
|
||||
Install Sphinx, and optionally (for the RTD-styling), sphinx_rtd_theme,
|
||||
preferably in a virtualenv:
|
||||
|
||||
pip install sphinx
|
||||
pip install sphinx_rtd_theme
|
||||
|
||||
In `micropython/docs`, build the docs:
|
||||
|
||||
make MICROPY_PORT=<port_name> BUILDDIR=<port_name>/build html
|
||||
|
||||
Where `<port_name>` can be `unix`, `pyboard`, `wipy` or `esp8266`.
|
||||
|
||||
You'll find the index page at `micropython/docs/<port_name>/build/html/index.html`.
|
||||
This will use the included `tools/pydfu.py` script. If flashing the firmware
|
||||
does not work it may be because you don't have the correct permissions, and
|
||||
need to use `sudo make deploy`.
|
||||
See the README.md file in the stmhal/ directory for further details.
|
||||
|
||||
@@ -8,7 +8,7 @@ include ../py/py.mk
|
||||
|
||||
CROSS_COMPILE = arm-none-eabi-
|
||||
|
||||
INC = -I.
|
||||
INC += -I.
|
||||
INC += -I..
|
||||
INC += -I$(BUILD)
|
||||
|
||||
@@ -42,7 +42,7 @@ all: $(BUILD)/firmware.elf
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
include ../py/mkrules.mk
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/repl.h"
|
||||
|
||||
void do_str(const char *src) {
|
||||
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
if (lex == NULL) {
|
||||
return;
|
||||
@@ -16,8 +16,8 @@ void do_str(const char *src) {
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT);
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
@@ -28,7 +28,8 @@ void do_str(const char *src) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
mp_init();
|
||||
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\n')");
|
||||
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
|
||||
do_str("for i in range(10):\n print(i)", MP_PARSE_FILE_INPUT);
|
||||
mp_deinit();
|
||||
return 0;
|
||||
}
|
||||
@@ -44,7 +45,7 @@ mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// options to control how Micro Python is built
|
||||
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
#define MICROPY_ALLOC_PATH_MAX (512)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
@@ -18,9 +19,12 @@
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_REVERSED (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
||||
@@ -53,6 +57,9 @@ typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// dummy print
|
||||
#define MP_PLAT_PRINT_STRN(str, len) (void)0
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
|
||||
1
bare-arm/mphalport.h
Normal file
1
bare-arm/mphalport.h
Normal file
@@ -0,0 +1 @@
|
||||
// empty file
|
||||
@@ -83,7 +83,7 @@
|
||||
#define configUSE_TICK_HOOK 1
|
||||
#define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 )
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 64 )
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 )
|
||||
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16384 ) )
|
||||
#define configMAX_TASK_NAME_LEN ( 8 )
|
||||
#define configUSE_TRACE_FACILITY 0
|
||||
|
||||
@@ -17,11 +17,11 @@ include ../py/mkenv.mk
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -march=armv7e-m -mabi=aapcs -mcpu=cortex-m4 -msoft-float -mfloat-abi=soft -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4)
|
||||
CFLAGS = -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) -Os
|
||||
CFLAGS += -g -ffunction-sections -fdata-sections -fno-common -fsigned-char -mno-unaligned-access
|
||||
CFLAGS += -Iboards/$(BOARD)
|
||||
|
||||
LDFLAGS = -Wl,-nostdlib -Wl,--gc-sections -Wl,-Map=$@.map --specs=nano.specs
|
||||
LDFLAGS = -Wl,-nostdlib -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
ifeq ($(BTARGET), application)
|
||||
# qstr definitions (must come before including py.mk)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Build Instructions for the CC3200
|
||||
|
||||
Currently the CC3200 port of Micro Python builds under Linux and OSX **but not under Windows**.
|
||||
Currently the CC3200 port of MicroPython builds under Linux and OSX **but not under Windows**.
|
||||
|
||||
The tool chain required for the build can be found at <https://launchpad.net/gcc-arm-embedded>.
|
||||
|
||||
@@ -25,7 +25,7 @@ make BTARGET=bootloader BTYPE=release BOARD=LAUNCHXL
|
||||
```
|
||||
|
||||
## Regarding old revisions of the CC3200-LAUNCHXL
|
||||
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and Micro Python cannot run
|
||||
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and MicroPython cannot run
|
||||
there. Make sure to use a **v4.1 (or higer) LAUNCHXL board** when trying this port, otherwise it won't work.
|
||||
|
||||
## Flashing the CC3200
|
||||
@@ -40,12 +40,19 @@ there. Make sure to use a **v4.1 (or higer) LAUNCHXL board** when trying this po
|
||||
- Flash the latest service pack (servicepack_1.0.0.10.0.bin) using the "Service Pack Update" button.
|
||||
- Close CCS_Uniflash, remove the SOP2 jumper and reset the board.
|
||||
|
||||
## Updating the board to with new software version
|
||||
- Make sure the board is running and connected to the same network as the computer.
|
||||
|
||||
```bash
|
||||
make BTARGET=application BTYPE=release BOARD=LAUNCHXL WIPY_IP=192.168.1.1 WIPY_USER=micro WIPY_PWD=python deploy
|
||||
```
|
||||
|
||||
If `WIPY_IP`, `WIPY_USER` or `WIPY_PWD` are omitted the default values (the ones shown above) will be used.
|
||||
|
||||
## Playing with MicroPython and the CC3200:
|
||||
|
||||
Once the software is running, you have two options to access the MicroPython REPL:
|
||||
|
||||
- Through the UART.
|
||||
**Connect to PORT 22, baud rate = 115200, parity = none, stop bits = 1**
|
||||
- Through telnet.
|
||||
* Connect to the network created by the board (as boots up in AP mode), **ssid = "wipy-wlan", key = "www.wipy.io"**.
|
||||
* You can also reinitialize the WLAN in station mode and connect to another AP, or in AP mode but with a
|
||||
@@ -66,15 +73,15 @@ not 100% sure of it.
|
||||
|
||||
## Upgrading the firmware Over The Air:
|
||||
|
||||
OTA software updates can be performed through the FTP server. After building a new MCUIMG.BIN in release mode, upload it to:
|
||||
OTA software updates can be performed through the FTP server. After building a new **mcuimg.bin** in release mode, upload it to:
|
||||
`/flash/sys/mcuimg.bin` it will take around 6s (The TI simplelink file system is quite slow because every file is mirrored for
|
||||
safety). You won't see the file being stored inside `/flash/sys/` because it's actually saved bypassing FatFS, but rest assured that
|
||||
the file was successfully transferred, and it has been signed with a MD5 checksum to verify its integrity.
|
||||
Now, reset the MCU by pressing the switch on the board, or by typing:
|
||||
|
||||
```python
|
||||
import pyb
|
||||
pyb.reset()
|
||||
import machine
|
||||
machine.reset()
|
||||
```
|
||||
|
||||
### Note regarding FileZilla:
|
||||
|
||||
@@ -77,22 +77,22 @@ APP_HAL_SRC_C = $(addprefix hal/,\
|
||||
APP_MISC_SRC_C = $(addprefix misc/,\
|
||||
antenna.c \
|
||||
FreeRTOSHooks.c \
|
||||
pin_named_pins.c \
|
||||
help.c \
|
||||
mpcallback.c \
|
||||
mpirq.c \
|
||||
mperror.c \
|
||||
mpexception.c \
|
||||
mpsystick.c \
|
||||
)
|
||||
|
||||
APP_MODS_SRC_C = $(addprefix mods/,\
|
||||
modmachine.c \
|
||||
modnetwork.c \
|
||||
moduhashlib.c \
|
||||
modubinascii.c \
|
||||
modpyb.c \
|
||||
moduos.c \
|
||||
modusocket.c \
|
||||
modussl.c \
|
||||
modutime.c \
|
||||
modwipy.c \
|
||||
modwlan.c \
|
||||
pybadc.c \
|
||||
pybpin.c \
|
||||
@@ -151,18 +151,18 @@ APP_LIB_SRC_C = $(addprefix lib/,\
|
||||
mp-readline/readline.c \
|
||||
netutils/netutils.c \
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/printf.c \
|
||||
)
|
||||
|
||||
APP_STM_SRC_C = $(addprefix stmhal/,\
|
||||
bufhelper.c \
|
||||
file.c \
|
||||
builtin_open.c \
|
||||
import.c \
|
||||
input.c \
|
||||
irq.c \
|
||||
lexerfatfs.c \
|
||||
moduselect.c \
|
||||
printf.c \
|
||||
pyexec.c \
|
||||
pybstdio.c \
|
||||
)
|
||||
|
||||
@@ -183,31 +183,10 @@ $(BUILD)/drivers/cc3100/src/driver.o: CFLAGS += -fno-strict-aliasing
|
||||
|
||||
# Check if we would like to debug the port code
|
||||
ifeq ($(BTYPE), release)
|
||||
# Optimize everything and define the NDEBUG flag
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
CFLAGS += -DNDEBUG
|
||||
else
|
||||
ifeq ($(BTYPE), debug)
|
||||
# Define the DEBUG flag
|
||||
CFLAGS += -DDEBUG=DEBUG
|
||||
# Optimize the stable sources only
|
||||
$(BUILD)/extmod/%.o: CFLAGS += -Os
|
||||
$(BUILD)/lib/%.o: CFLAGS += -Os
|
||||
$(BUILD)/fatfs/src/%.o: CFLAGS += -Os
|
||||
$(BUILD)/FreeRTOS/Source/%.o: CFLAGS += -Os
|
||||
$(BUILD)/ftp/%.o: CFLAGS += -Os
|
||||
$(BUILD)/hal/%.o: CFLAGS += -Os
|
||||
$(BUILD)/misc/%.o: CFLAGS += -Os
|
||||
$(BUILD)/mods/%.o: CFLAGS += -Os
|
||||
$(BUILD)/py/%.o: CFLAGS += -Os
|
||||
$(BUILD)/simplelink/%.o: CFLAGS += -Os
|
||||
$(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os
|
||||
$(BUILD)/stmhal/%.o: CFLAGS += -Os
|
||||
$(BUILD)/telnet/%.o: CFLAGS += -Os
|
||||
$(BUILD)/util/%.o: CFLAGS += -Os
|
||||
$(BUILD)/pins.o: CFLAGS += -Os
|
||||
$(BUILD)/main.o: CFLAGS += -Os
|
||||
$(BUILD)/mptask.o: CFLAGS += -Os
|
||||
$(BUILD)/servertask.o: CFLAGS += -Os
|
||||
CFLAGS += -DNDEBUG
|
||||
else
|
||||
$(error Invalid BTYPE specified)
|
||||
endif
|
||||
@@ -215,9 +194,19 @@ endif
|
||||
|
||||
SHELL = bash
|
||||
APP_SIGN = appsign.sh
|
||||
UPDATE_WIPY ?= tools/update-wipy.py
|
||||
WIPY_IP ?= '192.168.1.1'
|
||||
WIPY_USER ?= 'micro'
|
||||
WIPY_PWD ?= 'python'
|
||||
|
||||
all: $(BUILD)/mcuimg.bin
|
||||
|
||||
.PHONY: deploy
|
||||
|
||||
deploy: $(BUILD)/mcuimg.bin
|
||||
$(ECHO) "Writing $< to the board"
|
||||
$(Q)$(PYTHON) $(UPDATE_WIPY) --verify --ip $(WIPY_IP) --user $(WIPY_USER) --password $(WIPY_PWD) --file $<
|
||||
|
||||
$(BUILD)/application.axf: $(OBJ) $(LINKER_SCRIPT)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||
@@ -229,7 +218,7 @@ $(BUILD)/application.bin: $(BUILD)/application.axf
|
||||
|
||||
$(BUILD)/mcuimg.bin: $(BUILD)/application.bin
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(SHELL) $(APP_SIGN) $(BOARD) $(BTYPE)
|
||||
$(Q)$(SHELL) $(APP_SIGN) $(BUILD)
|
||||
|
||||
MAKE_PINS = boards/make-pins.py
|
||||
BOARD_PINS = boards/$(BOARD)/pins.csv
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: appsign.sh *board type* *build type*"
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: appsign.sh *build dir*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BOARD=$1
|
||||
BTYPE=$2
|
||||
|
||||
# Build location
|
||||
# Based on build type and board type
|
||||
BUILD=build/${BOARD}/${BTYPE}
|
||||
BUILD=$1
|
||||
|
||||
# Generate the MD5 hash
|
||||
# md5 on Darwin, md5sum on Unix
|
||||
if [ `uname -s` = "Darwin" ]; then
|
||||
echo -n `md5 -q $BUILD/application.bin` > __md5hash.bin
|
||||
else
|
||||
echo -n `md5sum --binary $BUILD/application.bin | awk '{ print $1 }'` > __md5hash.bin
|
||||
fi
|
||||
|
||||
# Concatenate it with the application binary
|
||||
cat $BUILD/application.bin __md5hash.bin > $BUILD/mcuimg.bin
|
||||
|
||||
@@ -30,26 +30,18 @@
|
||||
#define MICROPY_HW_BOARD_NAME "LaunchPad"
|
||||
#define MICROPY_HW_MCU_NAME "CC3200"
|
||||
|
||||
#define MICROPY_HW_HAS_SDCARD (0)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
#define MICROPY_HW_ENABLE_RTC (1)
|
||||
#define MICROPY_HW_ANTENNA_DIVERSITY (0)
|
||||
|
||||
#define MICROPY_STDIO_UART 1
|
||||
#define MICROPY_STDIO_UART 0
|
||||
#define MICROPY_STDIO_UART_BAUD 115200
|
||||
#define MICROPY_STDIO_UART_RX_BUF_SIZE 128
|
||||
#define MICROPY_STDIO_UART_TX_PIN (pin_GPIO1)
|
||||
#define MICROPY_STDIO_UART_RX_PIN (pin_GPIO2)
|
||||
#define MICROPY_STDIO_UART_TX_PIN_AF PIN_MODE_3
|
||||
#define MICROPY_STDIO_UART_RX_PIN_AF PIN_MODE_3
|
||||
|
||||
#define MICROPY_SYS_LED_PRCM PRCM_GPIOA1
|
||||
#define MICROPY_SAFE_BOOT_PRCM PRCM_GPIOA2
|
||||
#define MICROPY_SYS_LED_PORT GPIOA1_BASE
|
||||
#define MICROPY_SAFE_BOOT_PORT GPIOA2_BASE
|
||||
#define MICROPY_SYS_LED_GPIO pin_GPIO9
|
||||
#define MICROPY_SYS_LED_PIN_NUM PIN_64 // GPIO9
|
||||
#define MICROPY_SAFE_BOOT_PIN_NUM PIN_15 // GPIO22
|
||||
#define MICROPY_SYS_LED_GPIO pin_GP9
|
||||
#define MICROPY_SYS_LED_PIN_NUM PIN_64 // GP9
|
||||
#define MICROPY_SAFE_BOOT_PIN_NUM PIN_15 // GP22
|
||||
#define MICROPY_SYS_LED_PORT_PIN GPIO_PIN_1
|
||||
#define MICROPY_SAFE_BOOT_PORT_PIN GPIO_PIN_6
|
||||
|
||||
|
||||
@@ -30,18 +30,15 @@
|
||||
#define MICROPY_HW_BOARD_NAME "WiPy"
|
||||
#define MICROPY_HW_MCU_NAME "CC3200"
|
||||
|
||||
#define MICROPY_HW_HAS_SDCARD (1)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
#define MICROPY_HW_ENABLE_RTC (1)
|
||||
#define MICROPY_HW_ANTENNA_DIVERSITY (1)
|
||||
|
||||
#define MICROPY_SYS_LED_PRCM PRCM_GPIOA3
|
||||
#define MICROPY_SAFE_BOOT_PRCM PRCM_GPIOA3
|
||||
#define MICROPY_SYS_LED_PORT GPIOA3_BASE
|
||||
#define MICROPY_SAFE_BOOT_PORT GPIOA3_BASE
|
||||
#define MICROPY_SYS_LED_GPIO pin_GPIO25
|
||||
#define MICROPY_SYS_LED_PIN_NUM PIN_21 // GPIO25 (SOP2)
|
||||
#define MICROPY_SAFE_BOOT_PIN_NUM PIN_18 // GPIO28
|
||||
#define MICROPY_SYS_LED_GPIO pin_GP25
|
||||
#define MICROPY_SYS_LED_PIN_NUM PIN_21 // GP25 (SOP2)
|
||||
#define MICROPY_SAFE_BOOT_PIN_NUM PIN_18 // GP28
|
||||
#define MICROPY_SYS_LED_PORT_PIN GPIO_PIN_1
|
||||
#define MICROPY_SAFE_BOOT_PORT_PIN GPIO_PIN_4
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
L2,GPIO2
|
||||
L3,GPIO1
|
||||
L4,GPIO23
|
||||
L5,GPIO24
|
||||
L6,GPIO11
|
||||
L7,GPIO12
|
||||
L8,GPIO13
|
||||
L9,GPIO14
|
||||
L10,GPIO15
|
||||
L11,GPIO16
|
||||
L12,GPIO17
|
||||
L13,GPIO22
|
||||
L14,GPIO28
|
||||
R4,GPIO10
|
||||
R5,GPIO9
|
||||
R6,GPIO8
|
||||
R7,GPIO7
|
||||
R8,GPIO6
|
||||
R9,GPIO30
|
||||
R10,GPIO31
|
||||
R11,GPIO3
|
||||
R12,GPIO0
|
||||
R13,GPIO4
|
||||
R14,GPIO5
|
||||
HBL,GPIO25
|
||||
L2,GP2
|
||||
L3,GP1
|
||||
L4,GP23
|
||||
L5,GP24
|
||||
L6,GP11
|
||||
L7,GP12
|
||||
L8,GP13
|
||||
L9,GP14
|
||||
L10,GP15
|
||||
L11,GP16
|
||||
L12,GP17
|
||||
L13,GP22
|
||||
L14,GP28
|
||||
R4,GP10
|
||||
R5,GP9
|
||||
R6,GP8
|
||||
R7,GP7
|
||||
R8,GP6
|
||||
R9,GP30
|
||||
R10,GP31
|
||||
R11,GP3
|
||||
R12,GP0
|
||||
R13,GP4
|
||||
R14,GP5
|
||||
HBL,GP25
|
||||
|
||||
|
@@ -1,25 +1,25 @@
|
||||
Pin,Name,Default,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,ADC
|
||||
1,GPIO10,GPIO10,GPIO10,I2C_SCL,,GT_PWM06,,,SDCARD_CLK,UART1_TX,,,,,GT_CCP01,,,,
|
||||
2,GPIO11,GPIO11,GPIO11,I2C_SDA,,GT_PWM07,pXCLK(XVCLK),,SDCARD_CMD,UART1_RX,,,,,GT_CCP02,McAFSX,,,
|
||||
3,GPIO12,GPIO12,GPIO12,,,McACLK,pVS(VSYNC),I2C_SCL,,UART0_TX,,,,,GT_CCP03,,,,
|
||||
4,GPIO13,GPIO13,GPIO13,,,,pHS(HSYNC),I2C_SDA,,UART0_RX,,,,,GT_CCP04,,,,
|
||||
5,GPIO14,GPIO14,GPIO14,,,,pDATA8(CAM_D4),2C_SCL,,GSPI_CLK,,,,,GT_CCP05,,,,
|
||||
6,GPIO15,GPIO15,GPIO15,,,,pDATA9(CAM_D5),I2C_SDA,,GSPI_MISO,,,,,,GT_CCP06,,,
|
||||
7,GPIO16,GPIO16,GPIO16,,,,pDATA10(CAM_D6),UART1_TX,,GSPI_MOSI,,,,,,GT_CCP07,,,
|
||||
8,GPIO17,GPIO17,GPIO17,,,,pDATA11(CAM_D7),UART1_RX,,GSPI_CS,,,,,,,,,
|
||||
1,GP10,GP10,GP10,I2C0_SCL,,TIM3_PWM,,,SD0_CLK,UART1_TX,,,,,TIM0_CC,,,,
|
||||
2,GP11,GP11,GP11,I2C0_SDA,,TIM3_PWM,pXCLK(XVCLK),,SD0_CMD,UART1_RX,,,,,TIM1_CC,I2S0_FS,,,
|
||||
3,GP12,GP12,GP12,,,I2S0_CLK,pVS(VSYNC),I2C0_SCL,,UART0_TX,,,,,TIM1_CC,,,,
|
||||
4,GP13,GP13,GP13,,,,pHS(HSYNC),I2C0_SDA,,UART0_RX,,,,,TIM2_CC,,,,
|
||||
5,GP14,GP14,GP14,,,,pDATA8(CAM_D4),I2C0_SCL,,SPI0_CLK,,,,,TIM2_CC,,,,
|
||||
6,GP15,GP15,GP15,,,,pDATA9(CAM_D5),I2C0_SDA,,SPI0_MISO,SD0_DAT0,,,,,TIM3_CC,,,
|
||||
7,GP16,GP16,GP16,,,,pDATA10(CAM_D6),UART1_TX,,SPI0_MOSI,SD0_CLK,,,,,TIM3_CC,,,
|
||||
8,GP17,GP17,GP17,,,,pDATA11(CAM_D7),UART1_RX,,SPI0_CS0,SD0_CMD,,,,,,,,
|
||||
9,VDD_DIG1,VDD_DIG1,VDD_DIG1,,,,,,,,,,,,,,,,
|
||||
10,VIN_IO1,VIN_IO1,VIN_IO1,,,,,,,,,,,,,,,,
|
||||
11,FLASH_SPI_CLK,FLASH_SPI_CLK,FLASH_SPI_CLK,,,,,,,,,,,,,,,,
|
||||
12,FLASH_SPI_DOUT,FLASH_SPI_DOUT,FLASH_SPI_DOUT,,,,,,,,,,,,,,,,
|
||||
13,FLASH_SPI_DIN,FLASH_SPI_DIN,FLASH_SPI_DIN,,,,,,,,,,,,,,,,
|
||||
14,FLASH_SPI_CS,FLASH_SPI_CS,FLASH_SPI_CS,,,,,,,,,,,,,,,,
|
||||
15,GPIO22,GPIO22,GPIO22,,,,,GT_CCP04,,McAFSX,,,,,,,,,
|
||||
16,GPIO23,TDI,GPIO23,TDI,UART1_TX,,,,,,,2C_SCL,,,,,,,
|
||||
17,GPIO24,TDO,GPIO24,TDO,UART1_RX,,GT_CCP06,PWM0,McAFSX,,,I2C_SDA,,,,,,,
|
||||
18,GPIO28,GPIO28,GPIO28,,,,,,,,,,,,,,,,
|
||||
19,TCK,TCK,,TCK,,,,,,,GT_PWM03,,,,,,,,
|
||||
20,GPIO29,TMS,GPIO29,TMS,,,,,,,,,,,,,,,
|
||||
21,GPIO25,SOP2,GPIO25,,McAFSX,,,,,,,GT_PWM02,,,,,,,
|
||||
15,GP22,GP22,GP22,,,,,TIM2_CC,,I2S0_FS,,,,,,,,,
|
||||
16,GP23,TDI,GP23,TDI,UART1_TX,,,,,,,I2C0_SCL,,,,,,,
|
||||
17,GP24,TDO,GP24,TDO,UART1_RX,,TIM3_CC,TIM0_PWM,I2S0_FS,,,I2C0_SDA,,,,,,,
|
||||
18,GP28,GP28,GP28,,,,,,,,,,,,,,,,
|
||||
19,TCK,TCK,,TCK,,,,,,,TIM1_PWM,,,,,,,,
|
||||
20,GP29,TMS,GP29,TMS,,,,,,,,,,,,,,,
|
||||
21,GP25,SOP2,GP25,,I2S0_FS,,,,,,,TIM1_PWM,,,,,,,
|
||||
22,WLAN_XTAL_N,WLAN_XTAL_N,WLAN_XTAL_N,,,,,,,,,,,,,,,,
|
||||
23,WLAN_XTAL_P,WLAN_XTAL_P,WLAN_XTAL_P,,,,,,,,,,,,,,,,
|
||||
24,VDD_PLL,VDD_PLL,VDD_PLL,,,,,,,,,,,,,,,,
|
||||
@@ -43,24 +43,24 @@ Pin,Name,Default,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF1
|
||||
42,DCDC_PA_OUT,DCDC_PA_O UT,DCDC_PA_O UT,,,,,,,,,,,,,,,,
|
||||
43,DCDC_DIG_SW,DCDC_DIG_ SW,DCDC_DIG_ SW,,,,,,,,,,,,,,,,
|
||||
44,VIN_DCDC_DIG,VIN_DCDC_ DIG,VIN_DCDC_ DIG,,,,,,,,,,,,,,,,
|
||||
45,GPIO31,DCDC_ANA2_SW_P,GPIO31,,UART1_RX,,,,McAXR0,GSPI_CLK,,UART0_RX,,,McAFSX,,,,
|
||||
45,GP31,DCDC_ANA2_SW_P,GP31,,UART1_RX,,,,I2S0_DAT0,SPI0_CLK,,UART0_RX,,,I2S0_FS,,,,
|
||||
46,DCDC_ANA2_SW_N,DCDC_ANA2_SW_N,DCDC_ANA2_SW_N,,,,,,,,,,,,,,,,
|
||||
47,VDD_ANA2,VDD_ANA2,VDD_ANA2,,,,,,,,,,,,,,,,
|
||||
48,VDD_ANA1,VDD_ANA1,VDD_ANA1,,,,,,,,,,,,,,,,
|
||||
49,VDD_RAM,VDD_RAM,VDD_RAM,,,,,,,,,,,,,,,,
|
||||
50,GPIO0,GPIO0,GPIO0,,,UART0_RTS,McAXR0,,McAXR1,GT_CCP00,,GSPI_CS,UART1_RTS,,UART0_CTS,,,,
|
||||
50,GP0,GP0,GP0,,,UART0_RTS,I2S0_DAT0,,I2S0_DAT1,TIM0_CC,,SPI0_CS0,UART1_RTS,,UART0_CTS,,,,
|
||||
51,RTC_XTAL_P,RTC_XTAL_P,RTC_XTAL_P,,,,,,,,,,,,,,,,
|
||||
52,RTC_XTAL_N,RTC_XTAL_N,GPIO32,,McACLK,,McAXR0,,UART0_RTS,,GSPI_MOSI,,,,,,,,
|
||||
53,GPIO30,GPIO30,GPIO30,,McACLK,McAFSX,GT_CCP05,,,GSPI_MISO,,UART0_TX,,,,,,,
|
||||
52,RTC_XTAL_N,RTC_XTAL_N,GP32,,I2S0_CLK,,I2S0_DAT0,,UART0_RTS,,SPI0_MOSI,,,,,,,,
|
||||
53,GP30,GP30,GP30,,I2S0_CLK,I2S0_FS,TIM2_CC,,,SPI0_MISO,,UART0_TX,,,,,,,
|
||||
54,VIN_IO2,VIN_IO2,VIN_IO2,,,,,,,,,,,,,,,,
|
||||
55,GPIO1,GPIO1,GPIO1,,,GSPI_MISO,pCLK (PIXCLK),,UART1_TX,GT_CCP01,,,,,,,,,
|
||||
55,GP1,GP1,GP1,,,UART0_TX,pCLK (PIXCLK),,UART1_TX,TIM0_CC,,,,,,,,,
|
||||
56,VDD_DIG2,VDD_DIG2,VDD_DIG2,,,,,,,,,,,,,,,,
|
||||
57,GPIO2,GPIO2,GPIO2,,,UART0_RX,,,UART1_RX,GT_CCP02,,,,,,,,,ADC_CH0
|
||||
58,GPIO3,GPIO3,GPIO3,,,,pDATA7(CAM_D3),,UART1_TX,,,,,,,,,,ADC_CH1
|
||||
59,GPIO4,GPIO4,GPIO4,,,,pDATA6(CAM_D2),,UART1_RX,,,,,,,,,,ADC_CH2
|
||||
60,GPIO5,GPIO5,GPIO5,,,,pDATA5(CAM_D1),,McAXR1,GT_CCP05,,,,,,,,,ADC_CH3
|
||||
61,GPIO6,GPIO6,GPIO6,,,UART1_CTS,pDATA4(CAM_D0),UART0_RTS,UART0_CTS,GT_CCP06,,,,,,,,,
|
||||
62,GPIO7,GPIO7,GPIO7,,,UART1_RTS,,,,,,,UART0_RTS,UART0_TX,,McACLKX,,,
|
||||
63,GPIO8,GPIO8,GPIO8,,,,,,SDCARD_IRQ,McAFSX,,,,,GT_CCP06,,,,
|
||||
64,GPIO9,GPIO9,GPIO9,,,GT_PWM05,,,SDCARD_DATA,McAXR0,,,,,GT_CCP00,,,,
|
||||
57,GP2,GP2,GP2,,,UART0_RX,,,UART1_RX,TIM1_CC,,,,,,,,,ADC0_CH0
|
||||
58,GP3,GP3,GP3,,,,pDATA7(CAM_D3),,UART1_TX,,,,,,,,,,ADC0_CH1
|
||||
59,GP4,GP4,GP4,,,,pDATA6(CAM_D2),,UART1_RX,,,,,,,,,,ADC0_CH2
|
||||
60,GP5,GP5,GP5,,,,pDATA5(CAM_D1),,I2S0_DAT1,TIM2_CC,,,,,,,,,ADC0_CH3
|
||||
61,GP6,GP6,GP6,,,UART1_CTS,pDATA4(CAM_D0),UART0_RTS,UART0_CTS,TIM3_CC,,,,,,,,,
|
||||
62,GP7,GP7,GP7,,,UART1_RTS,,,,,,,UART0_RTS,UART0_TX,,I2S0_CLK,,,
|
||||
63,GP8,GP8,GP8,,,,,,SD0_IRQ,I2S0_FS,,,,,TIM3_CC,,,,
|
||||
64,GP9,GP9,GP9,,,TIM2_PWM,,,SD0_DAT0,I2S0_DAT0,,,,,TIM0_CC,,,,
|
||||
65,GND_TAB,GND_TAB,GND_TAB,,,,,,,,,,,,,,,,
|
||||
|
||||
|
@@ -39,16 +39,31 @@
|
||||
#include "pybpin.h"
|
||||
|
||||
|
||||
#define PIN(p_pin_name, p_port, p_bit, p_pin_num) \
|
||||
#define AF(af_name, af_idx, af_fn, af_unit, af_type) \
|
||||
{ \
|
||||
.name = MP_QSTR_ ## af_name, \
|
||||
.idx = (af_idx), \
|
||||
.fn = PIN_FN_ ## af_fn, \
|
||||
.unit = (af_unit), \
|
||||
.type = PIN_TYPE_ ## af_fn ## _ ## af_type, \
|
||||
}
|
||||
|
||||
|
||||
#define PIN(p_pin_name, p_port, p_bit, p_pin_num, p_af_list, p_num_afs) \
|
||||
{ \
|
||||
{ &pin_type }, \
|
||||
.name = MP_QSTR_ ## p_pin_name, \
|
||||
.port = PORT_A ## p_port, \
|
||||
.type = PIN_TYPE_STD, \
|
||||
.bit = (p_bit), \
|
||||
.pin_num = (p_pin_num), \
|
||||
.af = PIN_MODE_0, \
|
||||
.strength = PIN_STRENGTH_4MA, \
|
||||
.mode = GPIO_DIR_MODE_IN, \
|
||||
.isused = false, \
|
||||
.name = MP_QSTR_ ## p_pin_name, \
|
||||
.port = PORT_A ## p_port, \
|
||||
.af_list = (p_af_list), \
|
||||
.pull = PIN_TYPE_STD, \
|
||||
.bit = (p_bit), \
|
||||
.pin_num = (p_pin_num), \
|
||||
.af = PIN_MODE_0, \
|
||||
.strength = PIN_STRENGTH_4MA, \
|
||||
.mode = GPIO_DIR_MODE_IN, \
|
||||
.num_afs = (p_num_afs), \
|
||||
.value = 0, \
|
||||
.used = false, \
|
||||
.irq_trigger = 0, \
|
||||
.irq_flags = 0, \
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
"""Generates the pins files for the CC3200."""
|
||||
"""Generates the pins file for the CC3200."""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
@@ -8,20 +8,44 @@ import sys
|
||||
import csv
|
||||
|
||||
|
||||
SUPPORTED_AFS = { 'UART': ('TX', 'RX', 'RTS', 'CTS'),
|
||||
'SPI': ('CLK', 'MOSI', 'MISO', 'CS0'),
|
||||
#'I2S': ('CLK', 'FS', 'DAT0', 'DAT1'),
|
||||
'I2C': ('SDA', 'SCL'),
|
||||
'TIM': ('PWM'),
|
||||
'SD': ('CLK', 'CMD', 'DAT0'),
|
||||
'ADC': ('CH0', 'CH1', 'CH2', 'CH3')
|
||||
}
|
||||
|
||||
def parse_port_pin(name_str):
|
||||
"""Parses a string and returns a (port, gpio_bit) tuple."""
|
||||
if len(name_str) < 5:
|
||||
raise ValueError("Expecting pin name to be at least 5 characters")
|
||||
if name_str[:4] != 'GPIO':
|
||||
raise ValueError("Expecting pin name to start with GPIO")
|
||||
if not name_str[4:].isdigit():
|
||||
if len(name_str) < 3:
|
||||
raise ValueError("Expecting pin name to be at least 3 characters")
|
||||
if name_str[:2] != 'GP':
|
||||
raise ValueError("Expecting pin name to start with GP")
|
||||
if not name_str[2:].isdigit():
|
||||
raise ValueError("Expecting numeric GPIO number")
|
||||
port = int(int(name_str[4:]) / 8)
|
||||
gpio_bit = 1 << int(int(name_str[4:]) % 8)
|
||||
port = int(int(name_str[2:]) / 8)
|
||||
gpio_bit = 1 << int(int(name_str[2:]) % 8)
|
||||
return (port, gpio_bit)
|
||||
|
||||
|
||||
class Pin(object):
|
||||
class AF:
|
||||
"""Holds the description of an alternate function"""
|
||||
def __init__(self, name, idx, fn, unit, type):
|
||||
self.name = name
|
||||
self.idx = idx
|
||||
if self.idx > 15:
|
||||
self.idx = -1
|
||||
self.fn = fn
|
||||
self.unit = unit
|
||||
self.type = type
|
||||
|
||||
def print(self):
|
||||
print (' AF({:16s}, {:4d}, {:8s}, {:4d}, {:8s}), // {}'.format(self.name, self.idx, self.fn, self.unit, self.type, self.name))
|
||||
|
||||
|
||||
class Pin:
|
||||
"""Holds the information associated with a pin."""
|
||||
def __init__(self, name, port, gpio_bit, pin_num):
|
||||
self.name = name
|
||||
@@ -29,45 +53,48 @@ class Pin(object):
|
||||
self.gpio_bit = gpio_bit
|
||||
self.pin_num = pin_num
|
||||
self.board_pin = False
|
||||
self.afs = []
|
||||
|
||||
def cpu_pin_name(self):
|
||||
return self.name
|
||||
|
||||
def is_board_pin(self):
|
||||
return self.board_pin
|
||||
|
||||
def set_is_board_pin(self):
|
||||
self.board_pin = True
|
||||
def add_af(self, af):
|
||||
self.afs.append(af)
|
||||
|
||||
def print(self):
|
||||
print('pin_obj_t pin_{:6s} = PIN({:6s}, {:1d}, {:3d}, {:2d});'.format(
|
||||
self.name, self.name, self.port, self.gpio_bit, self.pin_num))
|
||||
print('// {}'.format(self.name))
|
||||
if len(self.afs):
|
||||
print('const pin_af_t pin_{}_af[] = {{'.format(self.name))
|
||||
for af in self.afs:
|
||||
af.print()
|
||||
print('};')
|
||||
print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, pin_{}_af, {});\n'.format(
|
||||
self.name, self.name, self.port, self.gpio_bit, self.pin_num, self.name, len(self.afs)))
|
||||
else:
|
||||
print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, NULL, 0);\n'.format(
|
||||
self.name, self.name, self.port, self.gpio_bit, self.pin_num))
|
||||
|
||||
def print_header(self, hdr_file):
|
||||
hdr_file.write('extern pin_obj_t pin_{:s};\n'.format(self.name))
|
||||
|
||||
|
||||
class Pins(object):
|
||||
|
||||
class Pins:
|
||||
def __init__(self):
|
||||
self.cpu_pins = [] # list of pin objects
|
||||
self.board_pins = [] # list of pin objects
|
||||
|
||||
def find_pin(self, port, gpio_bit):
|
||||
for pin in self.cpu_pins:
|
||||
for pin in self.board_pins:
|
||||
if pin.port == port and pin.gpio_bit == gpio_bit:
|
||||
return pin
|
||||
|
||||
def find_pin_by_num(self, pin_num):
|
||||
for pin in self.cpu_pins:
|
||||
for pin in self.board_pins:
|
||||
if pin.pin_num == pin_num:
|
||||
return pin
|
||||
|
||||
def find_pin_by_name(self, name):
|
||||
for pin in self.cpu_pins:
|
||||
for pin in self.board_pins:
|
||||
if pin.name == name:
|
||||
return pin
|
||||
|
||||
def parse_af_file(self, filename, pin_col, pinname_col):
|
||||
def parse_af_file(self, filename, pin_col, pinname_col, af_start_col):
|
||||
with open(filename, 'r') as csvfile:
|
||||
rows = csv.reader(csvfile)
|
||||
for row in rows:
|
||||
@@ -76,11 +103,21 @@ class Pins(object):
|
||||
except:
|
||||
continue
|
||||
if not row[pin_col].isdigit():
|
||||
raise ValueError("Invalid pin number: {:s} in row {:s}".format(row[pin_col]), row)
|
||||
raise ValueError("Invalid pin number {:s} in row {:s}".format(row[pin_col]), row)
|
||||
# Pin numbers must start from 0 when used with the TI API
|
||||
pin_num = int(row[pin_col]) - 1;
|
||||
pin = Pin(row[pinname_col], port_num, gpio_bit, pin_num)
|
||||
self.cpu_pins.append(pin)
|
||||
self.board_pins.append(pin)
|
||||
af_idx = 0
|
||||
for af in row[af_start_col:]:
|
||||
af_splitted = af.split('_')
|
||||
fn_name = af_splitted[0].rstrip('0123456789')
|
||||
if fn_name in SUPPORTED_AFS:
|
||||
type_name = af_splitted[1]
|
||||
if type_name in SUPPORTED_AFS[fn_name]:
|
||||
unit_idx = af_splitted[0][-1]
|
||||
pin.add_af(AF(af, af_idx, fn_name, int(unit_idx), type_name))
|
||||
af_idx += 1
|
||||
|
||||
def parse_board_file(self, filename, cpu_pin_col):
|
||||
with open(filename, 'r') as csvfile:
|
||||
@@ -92,37 +129,44 @@ class Pins(object):
|
||||
else:
|
||||
pin = self.find_pin_by_name(row[cpu_pin_col])
|
||||
if pin:
|
||||
pin.set_is_board_pin()
|
||||
pin.board_pin = True
|
||||
|
||||
def print_named(self, label, pins):
|
||||
print('')
|
||||
print('STATIC const mp_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label))
|
||||
for pin in pins:
|
||||
if pin.is_board_pin():
|
||||
print(' {{ MP_OBJ_NEW_QSTR(MP_QSTR_{:6s}), (mp_obj_t)&pin_{:6s} }},'.format(pin.cpu_pin_name(), pin.cpu_pin_name()))
|
||||
if pin.board_pin:
|
||||
print(' {{ MP_OBJ_NEW_QSTR(MP_QSTR_{:6s}), (mp_obj_t)&pin_{:6s} }},'.format(pin.name, pin.name))
|
||||
print('};')
|
||||
print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
|
||||
|
||||
def print(self):
|
||||
for pin in self.cpu_pins:
|
||||
if pin.is_board_pin():
|
||||
for pin in self.board_pins:
|
||||
if pin.board_pin:
|
||||
pin.print()
|
||||
self.print_named('cpu', self.cpu_pins)
|
||||
self.print_named('board', self.board_pins)
|
||||
print('')
|
||||
|
||||
def print_header(self, hdr_filename):
|
||||
with open(hdr_filename, 'wt') as hdr_file:
|
||||
for pin in self.cpu_pins:
|
||||
if pin.is_board_pin():
|
||||
for pin in self.board_pins:
|
||||
if pin.board_pin:
|
||||
pin.print_header(hdr_file)
|
||||
|
||||
def print_qstr(self, qstr_filename):
|
||||
with open(qstr_filename, 'wt') as qstr_file:
|
||||
qstr_set = set([])
|
||||
for pin in self.cpu_pins:
|
||||
if pin.is_board_pin():
|
||||
qstr_set |= set([pin.cpu_pin_name()])
|
||||
for qstr in sorted(qstr_set):
|
||||
pin_qstr_set = set([])
|
||||
af_qstr_set = set([])
|
||||
for pin in self.board_pins:
|
||||
if pin.board_pin:
|
||||
pin_qstr_set |= set([pin.name])
|
||||
for af in pin.afs:
|
||||
af_qstr_set |= set([af.name])
|
||||
print('// Board pins', file=qstr_file)
|
||||
for qstr in sorted(pin_qstr_set):
|
||||
print('Q({})'.format(qstr), file=qstr_file)
|
||||
print('\n// Pin AFs', file=qstr_file)
|
||||
for qstr in sorted(af_qstr_set):
|
||||
print('Q({})'.format(qstr), file=qstr_file)
|
||||
|
||||
|
||||
@@ -169,12 +213,12 @@ def main():
|
||||
print('//')
|
||||
if args.af_filename:
|
||||
print('// --af {:s}'.format(args.af_filename))
|
||||
pins.parse_af_file(args.af_filename, 0, 1)
|
||||
pins.parse_af_file(args.af_filename, 0, 1, 3)
|
||||
|
||||
if args.board_filename:
|
||||
print('// --board {:s}'.format(args.board_filename))
|
||||
pins.parse_board_file(args.board_filename, 1)
|
||||
|
||||
pins.parse_board_file(args.board_filename, 1)
|
||||
|
||||
if args.prefix_filename:
|
||||
print('// --prefix {:s}'.format(args.prefix_filename))
|
||||
print('')
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: bootgen.sh *board type* *build type*"
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: bootgen.sh *build dir*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BOARD=$1
|
||||
BTYPE=$2
|
||||
BUILD=$1
|
||||
|
||||
# Re-locator Path
|
||||
RELOCATOR=bootmgr/relocator
|
||||
|
||||
# Boot Manager Path
|
||||
# First parameter passed is the board type
|
||||
BOOTMGR=bootmgr/build/${BOARD}/${BTYPE}
|
||||
# Build location
|
||||
BOOTMGR=${BUILD}
|
||||
|
||||
# Check for re-locator binary
|
||||
if [ ! -f $RELOCATOR/relocator.bin ]; then
|
||||
|
||||
@@ -19,6 +19,7 @@ BOOT_CPPDEFINES = -Dgcc -DBOOTLOADER -DTARGET_IS_CC3200 -DSL_TINY
|
||||
BOOT_HAL_SRC_C = $(addprefix hal/,\
|
||||
cpu.c \
|
||||
interrupt.c \
|
||||
gpio.c \
|
||||
pin.c \
|
||||
prcm.c \
|
||||
shamd5.c \
|
||||
@@ -64,16 +65,13 @@ BOOT_PY_SRC_C = $(addprefix py/,\
|
||||
mpprint.c \
|
||||
)
|
||||
|
||||
BOOT_STM_SRC_C = $(addprefix stmhal/,\
|
||||
printf.c \
|
||||
)
|
||||
|
||||
BOOT_LIB_SRC_C = $(addprefix lib/,\
|
||||
libc/string0.c \
|
||||
utils/printf.c \
|
||||
)
|
||||
|
||||
OBJ = $(addprefix $(BUILD)/, $(BOOT_HAL_SRC_C:.c=.o) $(BOOT_SL_SRC_C:.c=.o) $(BOOT_CC3100_SRC_C:.c=.o) $(BOOT_UTIL_SRC_C:.c=.o) $(BOOT_MISC_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o) $(BOOT_STM_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(BOOT_LIB_SRC_C:.c=.o))
|
||||
|
||||
# Add the linker script
|
||||
@@ -123,7 +121,7 @@ $(BUILD)/bootmgr.bin: $(BUILD)/bootmgr.axf
|
||||
|
||||
$(BUILD)/bootloader.bin: $(BUILD)/bootmgr.bin
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(SHELL) $(BOOT_GEN) $(BOARD) $(BTYPE)
|
||||
$(Q)$(SHELL) $(BOOT_GEN) $(BUILD)
|
||||
|
||||
# Create an empty "qstrdefs.generated.h" needed by py/mkrules.mk
|
||||
$(HEADER_BUILD)/qstrdefs.generated.h: | $(HEADER_BUILD)
|
||||
|
||||
@@ -43,23 +43,31 @@ extern "C"
|
||||
*******************************************************************************/
|
||||
#define IMG_BOOT_INFO "/sys/bootinfo.bin"
|
||||
#define IMG_FACTORY "/sys/factimg.bin"
|
||||
#define IMG_UPDATE "/sys/updtimg.bin"
|
||||
#define IMG_UPDATE1 "/sys/updtimg1.bin"
|
||||
#define IMG_UPDATE2 "/sys/updtimg2.bin"
|
||||
#define IMG_PREFIX "/sys/updtimg"
|
||||
|
||||
#define IMG_SRVPACK "/sys/servicepack.ucf"
|
||||
#define SRVPACK_SIGN "/sys/servicepack.sig"
|
||||
|
||||
#define CA_FILE "/cert/ca.pem"
|
||||
#define CERT_FILE "/cert/cert.pem"
|
||||
#define KEY_FILE "/cert/private.key"
|
||||
|
||||
/******************************************************************************
|
||||
Image file sizes
|
||||
Special file sizes
|
||||
*******************************************************************************/
|
||||
#define IMG_SIZE (232 * 1024) /* 16KB are reserved for the bootloader and at least 8KB for the heap*/
|
||||
#define IMG_SIZE (192 * 1024) /* 16KB are reserved for the bootloader and at least 48KB for the heap*/
|
||||
#define SRVPACK_SIZE (16 * 1024)
|
||||
#define SIGN_SIZE (2 * 1024)
|
||||
#define CA_KEY_SIZE (4 * 1024)
|
||||
|
||||
/******************************************************************************
|
||||
Active Image
|
||||
*******************************************************************************/
|
||||
#define IMG_ACT_FACTORY 0
|
||||
#define IMG_ACT_UPDATE 1
|
||||
#define IMG_ACT_UPDATE1 1
|
||||
#define IMG_ACT_UPDATE2 2
|
||||
|
||||
#define IMG_STATUS_CHECK 0
|
||||
#define IMG_STATUS_READY 1
|
||||
@@ -67,13 +75,13 @@ extern "C"
|
||||
/******************************************************************************
|
||||
Boot Info structure
|
||||
*******************************************************************************/
|
||||
typedef struct sBootInfo
|
||||
typedef struct _sBootInfo_t
|
||||
{
|
||||
_u8 ActiveImg;
|
||||
_u8 Status;
|
||||
_u8 PrevImg;
|
||||
_u8 : 8;
|
||||
_u8 : 8;
|
||||
}sBootInfo_t;
|
||||
} sBootInfo_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "hw_ints.h"
|
||||
#include "hw_types.h"
|
||||
#include "hw_gpio.h"
|
||||
@@ -39,7 +38,6 @@
|
||||
#include "hw_common_reg.h"
|
||||
#include "pin.h"
|
||||
#include "gpio.h"
|
||||
#include "rom.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "simplelink.h"
|
||||
@@ -64,11 +62,16 @@
|
||||
#define BOOTMGR_HASH_SIZE 32
|
||||
#define BOOTMGR_BUFF_SIZE 512
|
||||
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_MS 1200
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 200
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_0_MS 500
|
||||
|
||||
#define BOOTMGR_SAFE_MODE_ENTER_MS 800
|
||||
#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 80
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_1_MS 3000
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_1_BLINK_MS 500
|
||||
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_2_MS 3000
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_2_BLINK_MS 250
|
||||
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_3_MS 1500
|
||||
#define BOOTMGR_WAIT_SAFE_MODE_3_BLINK_MS 100
|
||||
|
||||
//*****************************************************************************
|
||||
// Exported functions declarations
|
||||
@@ -79,9 +82,11 @@ extern void bootmgr_run_app (_u32 base);
|
||||
// Local functions declarations
|
||||
//*****************************************************************************
|
||||
static void bootmgr_board_init (void);
|
||||
static bool bootmgr_verify (void);
|
||||
static bool bootmgr_verify (_u8 *image);
|
||||
static void bootmgr_load_and_execute (_u8 *image);
|
||||
static bool safe_mode_boot (void);
|
||||
static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force_wait);
|
||||
static bool safe_boot_request_start (uint32_t wait_time);
|
||||
static void wait_for_safe_boot (sBootInfo_t *psBootInfo);
|
||||
static void bootmgr_image_loader (sBootInfo_t *psBootInfo);
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -140,16 +145,22 @@ void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
|
||||
//! Board Initialization & Configuration
|
||||
//*****************************************************************************
|
||||
static void bootmgr_board_init(void) {
|
||||
// Set vector table base
|
||||
// set the vector table base
|
||||
MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
|
||||
|
||||
// Enable Processor Interrupts
|
||||
// enable processor interrupts
|
||||
MAP_IntMasterEnable();
|
||||
MAP_IntEnable(FAULT_SYSTICK);
|
||||
|
||||
// Mandatory MCU Initialization
|
||||
// mandatory MCU initialization
|
||||
PRCMCC3200MCUInit();
|
||||
|
||||
// clear all the special bits, since we can't trust their content after reset
|
||||
// except for the WDT reset one!!
|
||||
PRCMClearSpecialBit(PRCM_SAFE_BOOT_BIT);
|
||||
PRCMClearSpecialBit(PRCM_FIRST_BOOT_BIT);
|
||||
|
||||
// check the reset after clearing the special bits
|
||||
mperror_bootloader_check_reset_cause();
|
||||
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
@@ -157,28 +168,25 @@ static void bootmgr_board_init(void) {
|
||||
antenna_init0();
|
||||
#endif
|
||||
|
||||
// Enable the Data Hashing Engine
|
||||
// enable the data hashing engine
|
||||
CRYPTOHASH_Init();
|
||||
|
||||
// Init the system led and the system switch
|
||||
// init the system led and the system switch
|
||||
mperror_init0();
|
||||
|
||||
// clear the safe boot flag, since we can't trust its content after reset
|
||||
PRCMClearSafeBootRequest();
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//! Verifies the integrity of the new application binary
|
||||
//*****************************************************************************
|
||||
static bool bootmgr_verify (void) {
|
||||
static bool bootmgr_verify (_u8 *image) {
|
||||
SlFsFileInfo_t FsFileInfo;
|
||||
_u32 reqlen, offset = 0;
|
||||
_i32 fHandle;
|
||||
|
||||
// open the file for reading
|
||||
if (0 == sl_FsOpen((_u8 *)IMG_UPDATE, FS_MODE_OPEN_READ, NULL, &fHandle)) {
|
||||
if (0 == sl_FsOpen(image, FS_MODE_OPEN_READ, NULL, &fHandle)) {
|
||||
// get the file size
|
||||
sl_FsGetInfo((_u8 *)IMG_UPDATE, 0, &FsFileInfo);
|
||||
sl_FsGetInfo(image, 0, &FsFileInfo);
|
||||
|
||||
if (FsFileInfo.FileLen > BOOTMGR_HASH_SIZE) {
|
||||
FsFileInfo.FileLen -= BOOTMGR_HASH_SIZE;
|
||||
@@ -242,47 +250,81 @@ static void bootmgr_load_and_execute (_u8 *image) {
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//! Check for the safe mode pin
|
||||
//! Wait while the safe mode pin is being held high and blink the system led
|
||||
//! with the specified period
|
||||
//*****************************************************************************
|
||||
static bool safe_mode_boot (void) {
|
||||
_u32 count = 0;
|
||||
while (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) &&
|
||||
((BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * count++) < BOOTMGR_WAIT_SAFE_MODE_MS)) {
|
||||
static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force_wait) {
|
||||
_u32 count;
|
||||
for (count = 0; (force_wait || MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) &&
|
||||
((period * count) < wait_time); count++) {
|
||||
// toogle the led
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * 1000));
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(period * 1000));
|
||||
}
|
||||
return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false;
|
||||
}
|
||||
|
||||
static bool safe_boot_request_start (uint32_t wait_time) {
|
||||
if (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(wait_time * 1000));
|
||||
}
|
||||
mperror_deinit_sfe_pin();
|
||||
return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//! Load the proper image based on information from boot info and executes it.
|
||||
//! Check for the safe mode pin
|
||||
//*****************************************************************************
|
||||
static void wait_for_safe_boot (sBootInfo_t *psBootInfo) {
|
||||
if (safe_boot_request_start(BOOTMGR_WAIT_SAFE_MODE_0_MS)) {
|
||||
if (wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_1_MS, BOOTMGR_WAIT_SAFE_MODE_1_BLINK_MS, false)) {
|
||||
// go back one step in time
|
||||
psBootInfo->ActiveImg = psBootInfo->PrevImg;
|
||||
if (wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_2_MS, BOOTMGR_WAIT_SAFE_MODE_2_BLINK_MS, false)) {
|
||||
// go back directly to the factory image
|
||||
psBootInfo->ActiveImg = IMG_ACT_FACTORY;
|
||||
wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_3_MS, BOOTMGR_WAIT_SAFE_MODE_3_BLINK_MS, true);
|
||||
}
|
||||
}
|
||||
// turn off the system led
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
|
||||
// request a safe boot to the application
|
||||
PRCMSetSpecialBit(PRCM_SAFE_BOOT_BIT);
|
||||
}
|
||||
// deinit the safe boot pin
|
||||
mperror_deinit_sfe_pin();
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//! Load the proper image based on the information from the boot info
|
||||
//! and launch it.
|
||||
//*****************************************************************************
|
||||
static void bootmgr_image_loader(sBootInfo_t *psBootInfo) {
|
||||
_i32 fhandle;
|
||||
if (safe_mode_boot()) {
|
||||
_u32 count = 0;
|
||||
while ((BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * count++) < BOOTMGR_SAFE_MODE_ENTER_MS) {
|
||||
// toogle the led
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * 1000));
|
||||
}
|
||||
psBootInfo->ActiveImg = IMG_ACT_FACTORY;
|
||||
// turn the led off
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
|
||||
// request a safe boot to the application
|
||||
PRCMRequestSafeBoot();
|
||||
_u8 *image;
|
||||
|
||||
// search for the active image
|
||||
switch (psBootInfo->ActiveImg) {
|
||||
case IMG_ACT_UPDATE1:
|
||||
image = (unsigned char *)IMG_UPDATE1;
|
||||
break;
|
||||
case IMG_ACT_UPDATE2:
|
||||
image = (unsigned char *)IMG_UPDATE2;
|
||||
break;
|
||||
default:
|
||||
image = (unsigned char *)IMG_FACTORY;
|
||||
break;
|
||||
}
|
||||
// do we have a new update image that needs to be verified?
|
||||
else if ((psBootInfo->ActiveImg == IMG_ACT_UPDATE) && (psBootInfo->Status == IMG_STATUS_CHECK)) {
|
||||
if (!bootmgr_verify()) {
|
||||
// delete the corrupted file
|
||||
sl_FsDel((_u8 *)IMG_UPDATE, 0);
|
||||
// switch to the factory image
|
||||
psBootInfo->ActiveImg = IMG_ACT_FACTORY;
|
||||
|
||||
// do we have a new image that needs to be verified?
|
||||
if ((psBootInfo->ActiveImg != IMG_ACT_FACTORY) && (psBootInfo->Status == IMG_STATUS_CHECK)) {
|
||||
if (!bootmgr_verify(image)) {
|
||||
// verification failed, delete the broken file
|
||||
sl_FsDel(image, 0);
|
||||
// switch to the previous image
|
||||
psBootInfo->ActiveImg = psBootInfo->PrevImg;
|
||||
psBootInfo->PrevImg = IMG_ACT_FACTORY;
|
||||
}
|
||||
// in any case, set the status as "READY"
|
||||
// in any case, change the status to "READY"
|
||||
psBootInfo->Status = IMG_STATUS_READY;
|
||||
// write the new boot info
|
||||
if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_WRITE, NULL, &fhandle)) {
|
||||
@@ -292,24 +334,34 @@ static void bootmgr_image_loader(sBootInfo_t *psBootInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
// now boot the active image
|
||||
if (IMG_ACT_UPDATE == psBootInfo->ActiveImg) {
|
||||
bootmgr_load_and_execute((unsigned char *)IMG_UPDATE);
|
||||
}
|
||||
else {
|
||||
bootmgr_load_and_execute((unsigned char *)IMG_FACTORY);
|
||||
// this one might modify the boot info hence it MUST be called after
|
||||
// bootmgr_verify! (so that the changes are not saved to flash)
|
||||
wait_for_safe_boot(psBootInfo);
|
||||
|
||||
// select the active image again, since it might have changed
|
||||
switch (psBootInfo->ActiveImg) {
|
||||
case IMG_ACT_UPDATE1:
|
||||
image = (unsigned char *)IMG_UPDATE1;
|
||||
break;
|
||||
case IMG_ACT_UPDATE2:
|
||||
image = (unsigned char *)IMG_UPDATE2;
|
||||
break;
|
||||
default:
|
||||
image = (unsigned char *)IMG_FACTORY;
|
||||
break;
|
||||
}
|
||||
bootmgr_load_and_execute(image);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//! Main function
|
||||
//*****************************************************************************
|
||||
int main (void) {
|
||||
sBootInfo_t sBootInfo = { .ActiveImg = IMG_ACT_FACTORY, .Status = IMG_STATUS_READY };
|
||||
sBootInfo_t sBootInfo = { .ActiveImg = IMG_ACT_FACTORY, .Status = IMG_STATUS_READY, .PrevImg = IMG_ACT_FACTORY };
|
||||
bool bootapp = false;
|
||||
_i32 fhandle;
|
||||
|
||||
// Board Initialization
|
||||
// board setup
|
||||
bootmgr_board_init();
|
||||
|
||||
// start simplelink since we need it to access the sflash
|
||||
@@ -322,17 +374,20 @@ int main (void) {
|
||||
}
|
||||
sl_FsClose(fhandle, 0, 0, 0);
|
||||
}
|
||||
// boot info file not present, it means that this is the first boot after being programmed
|
||||
if (!bootapp) {
|
||||
// create a new boot info file
|
||||
_u32 BootInfoCreateFlag = _FS_FILE_OPEN_FLAG_COMMIT | _FS_FILE_PUBLIC_WRITE | _FS_FILE_PUBLIC_READ;
|
||||
if (!sl_FsOpen ((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_CREATE((2 * sizeof(sBootInfo_t)),
|
||||
BootInfoCreateFlag), NULL, &fhandle)) {
|
||||
// Write the default boot info.
|
||||
// write the default boot info.
|
||||
if (sizeof(sBootInfo_t) == sl_FsWrite(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) {
|
||||
bootapp = true;
|
||||
}
|
||||
sl_FsClose(fhandle, 0, 0, 0);
|
||||
}
|
||||
// signal the first boot to the application
|
||||
PRCMSetSpecialBit(PRCM_FIRST_BOOT_BIT);
|
||||
}
|
||||
|
||||
if (bootapp) {
|
||||
@@ -343,14 +398,14 @@ int main (void) {
|
||||
// stop simplelink
|
||||
sl_Stop(SL_STOP_TIMEOUT);
|
||||
|
||||
// if we've reached this point, then it means a fatal error occurred and the application
|
||||
// could not be loaded, so, loop forever and signal the crash to the user
|
||||
// if we've reached this point, then it means that a fatal error has occurred and the
|
||||
// application could not be loaded, so, loop forever and signal the crash to the user
|
||||
while (true) {
|
||||
// keep the bld on
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN);
|
||||
__asm volatile(" dsb \n"
|
||||
" isb \n"
|
||||
" wfi \n");
|
||||
__asm volatile(" dsb \n"
|
||||
" isb \n"
|
||||
" wfi \n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +414,7 @@ int main (void) {
|
||||
//*****************************************************************************
|
||||
#include "py/qstr.h"
|
||||
|
||||
const byte *qstr_data(qstr q, mp_uint_t *len) {
|
||||
const byte *qstr_data(qstr q, size_t *len) {
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -10,21 +10,21 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "py/runtime.h"
|
||||
#include "py/obj.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h" /* FatFs lower layer API */
|
||||
#include "sflash_diskio.h" /* Serial flash disk IO API */
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
#include "sd_diskio.h" /* SDCARD disk IO API */
|
||||
#endif
|
||||
#include "sd_diskio.h" /* SDCARD disk IO API */
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "timeutils.h"
|
||||
|
||||
/* Definitions of physical drive number for each drive */
|
||||
#define SFLASH 0 /* Map SFLASH drive to drive number 0 */
|
||||
#define SDCARD 1 /* Map SD card to drive number 1 */
|
||||
#include "pybsd.h"
|
||||
#include "moduos.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -35,21 +35,20 @@ DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case SFLASH :
|
||||
return sflash_disk_status();
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
case SDCARD :
|
||||
return sd_disk_status();
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return STA_NODISK;
|
||||
if (pdrv == PD_FLASH) {
|
||||
return sflash_disk_status();
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
if (mount_obj->writeblocks[0] == MP_OBJ_NULL) {
|
||||
return STA_PROTECT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return STA_NODISK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -58,29 +57,22 @@ DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
DSTATUS stat = 0;
|
||||
|
||||
switch (pdrv) {
|
||||
case SFLASH :
|
||||
if (RES_OK != sflash_disk_init()) {
|
||||
stat = STA_NOINIT;
|
||||
}
|
||||
return stat;
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
case SDCARD :
|
||||
if (RES_OK != sd_disk_init()) {
|
||||
stat = STA_NOINIT;
|
||||
if (pdrv == PD_FLASH) {
|
||||
if (RES_OK != sflash_disk_init()) {
|
||||
return STA_NOINIT;
|
||||
}
|
||||
return stat;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return STA_NOINIT;
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
if (mount_obj->writeblocks[0] == MP_OBJ_NULL) {
|
||||
return STA_PROTECT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return STA_NODISK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -92,22 +84,25 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case SFLASH :
|
||||
return sflash_disk_read(buff, sector, count);
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
case SDCARD :
|
||||
return sd_disk_read(buff, sector, count);
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
if (pdrv == PD_FLASH) {
|
||||
return sflash_disk_read(buff, sector, count);
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
// optimization for the built-in sd card device
|
||||
if (mount_obj->device == (mp_obj_t)&pybsd_obj) {
|
||||
return sd_disk_read(buff, sector, count);
|
||||
}
|
||||
mount_obj->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
|
||||
mount_obj->readblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, buff);
|
||||
return mp_obj_get_int(mp_call_method_n_kw(2, 0, mount_obj->readblocks));
|
||||
}
|
||||
// nothing mounted
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -120,18 +115,23 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case SFLASH :
|
||||
return sflash_disk_write(buff, sector, count);
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
case SDCARD :
|
||||
return sd_disk_write(buff, sector, count);
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
if (pdrv == PD_FLASH) {
|
||||
return sflash_disk_write(buff, sector, count);
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
// optimization for the built-in sd card device
|
||||
if (mount_obj->device == (mp_obj_t)&pybsd_obj) {
|
||||
return sd_disk_write(buff, sector, count);
|
||||
}
|
||||
mount_obj->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
|
||||
mount_obj->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, (void *)buff);
|
||||
return mp_obj_get_int(mp_call_method_n_kw(2, 0, mount_obj->writeblocks));
|
||||
}
|
||||
// nothing mounted
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -147,41 +147,47 @@ DRESULT disk_ioctl (
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case SFLASH:
|
||||
if (pdrv == PD_FLASH) {
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
return sflash_disk_flush();
|
||||
case GET_SECTOR_COUNT:
|
||||
*((DWORD*)buff) = SFLASH_SECTOR_COUNT;
|
||||
return RES_OK;
|
||||
break;
|
||||
case GET_SECTOR_SIZE:
|
||||
*((WORD*)buff) = SFLASH_SECTOR_SIZE;
|
||||
*((DWORD*)buff) = SFLASH_SECTOR_SIZE;
|
||||
return RES_OK;
|
||||
break;
|
||||
case GET_BLOCK_SIZE:
|
||||
*((DWORD*)buff) = 1; // high-level sector erase size in units of the block size
|
||||
return RES_OK;
|
||||
}
|
||||
break;
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
case SDCARD:
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
return RES_OK;
|
||||
case GET_SECTOR_COUNT:
|
||||
*(WORD*)buff = sd_disk_info.ulNofBlock;
|
||||
break;
|
||||
case GET_SECTOR_SIZE :
|
||||
*(WORD*)buff = SD_SECTOR_SIZE;
|
||||
break;
|
||||
case GET_BLOCK_SIZE:
|
||||
*((DWORD*)buff) = 1; // high-level sector erase size in units of the block size
|
||||
return RES_OK;
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
if (mount_obj->sync[0] != MP_OBJ_NULL) {
|
||||
mp_call_method_n_kw(0, 0, mount_obj->sync);
|
||||
}
|
||||
return RES_OK;
|
||||
case GET_SECTOR_COUNT:
|
||||
// optimization for the built-in sd card device
|
||||
if (mount_obj->device == (mp_obj_t)&pybsd_obj) {
|
||||
*((DWORD*)buff) = sd_disk_info.ulNofBlock * (sd_disk_info.ulBlockSize / 512);
|
||||
} else {
|
||||
*((DWORD*)buff) = mp_obj_get_int(mp_call_method_n_kw(0, 0, mount_obj->count));
|
||||
}
|
||||
return RES_OK;
|
||||
case GET_SECTOR_SIZE:
|
||||
*((DWORD*)buff) = SD_SECTOR_SIZE; // Sector size is fixed to 512 bytes, as with SD cards
|
||||
return RES_OK;
|
||||
case GET_BLOCK_SIZE:
|
||||
*((DWORD*)buff) = 1; // high-level sector erase size in units of the block size
|
||||
return RES_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
// nothing mounted
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
@@ -193,12 +199,7 @@ DWORD get_fattime (
|
||||
)
|
||||
{
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// Get the time from the on-chip RTC and convert it to struct_time
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
|
||||
return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) |
|
||||
((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) |
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2014 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _USE_WRITE 1 /* 1: Enable disk_write function */
|
||||
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
|
||||
|
||||
#include "integer.h"
|
||||
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -38,11 +38,10 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/mphal.h"
|
||||
#include "hw_types.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "hw_ints.h"
|
||||
#include "rom.h"
|
||||
#include "rom_map.h"
|
||||
#include "diskio.h"
|
||||
#include "sd_diskio.h"
|
||||
@@ -187,7 +186,7 @@ static unsigned int CardSelect (DiskInfo_t *sDiskInfo) {
|
||||
}
|
||||
|
||||
// Delay 250ms for the card to become ready
|
||||
HAL_Delay (250);
|
||||
mp_hal_delay_ms(250);
|
||||
|
||||
return ulRet;
|
||||
}
|
||||
@@ -279,8 +278,6 @@ DSTATUS sd_disk_init (void) {
|
||||
sd_disk_info.bStatus = 0;
|
||||
}
|
||||
}
|
||||
// Set card rd/wr block len
|
||||
MAP_SDHostBlockSizeSet(SDHOST_BASE, SD_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
return sd_disk_info.bStatus;
|
||||
@@ -302,28 +299,6 @@ void sd_disk_deinit (void) {
|
||||
sd_disk_info.usRCA = 0;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Gets the disk status.
|
||||
//!
|
||||
//! This function gets the current status of the drive.
|
||||
//!
|
||||
//! \return Returns the current status of the specified drive
|
||||
//
|
||||
//*****************************************************************************
|
||||
DSTATUS sd_disk_status (void) {
|
||||
return sd_disk_info.bStatus;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Returns wether the sd card is ready to be accessed or not
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool sd_disk_ready (void) {
|
||||
return (!sd_disk_info.bStatus);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Reads sector(s) from the disk drive.
|
||||
@@ -376,6 +351,7 @@ DRESULT sd_disk_read (BYTE* pBuffer, DWORD ulSectorNumber, UINT SectorCount) {
|
||||
pBuffer += 4;
|
||||
}
|
||||
CardSendCmd(CMD_STOP_TRANS, 0);
|
||||
while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC));
|
||||
Res = RES_OK;
|
||||
}
|
||||
}
|
||||
@@ -395,61 +371,62 @@ DRESULT sd_disk_read (BYTE* pBuffer, DWORD ulSectorNumber, UINT SectorCount) {
|
||||
//
|
||||
//*****************************************************************************
|
||||
DRESULT sd_disk_write (const BYTE* pBuffer, DWORD ulSectorNumber, UINT SectorCount) {
|
||||
DRESULT Res = RES_ERROR;
|
||||
unsigned long ulSize;
|
||||
DRESULT Res = RES_ERROR;
|
||||
unsigned long ulSize;
|
||||
|
||||
if (SectorCount > 0) {
|
||||
// Return if disk not initialized
|
||||
if (sd_disk_info.bStatus & STA_NOINIT) {
|
||||
return RES_NOTRDY;
|
||||
}
|
||||
if (SectorCount > 0) {
|
||||
// Return if disk not initialized
|
||||
if (sd_disk_info.bStatus & STA_NOINIT) {
|
||||
return RES_NOTRDY;
|
||||
}
|
||||
|
||||
// SDSC uses linear address, SDHC uses block address
|
||||
if (sd_disk_info.ulCapClass == CARD_CAP_CLASS_SDSC) {
|
||||
ulSectorNumber = ulSectorNumber * SD_SECTOR_SIZE;
|
||||
}
|
||||
// SDSC uses linear address, SDHC uses block address
|
||||
if (sd_disk_info.ulCapClass == CARD_CAP_CLASS_SDSC) {
|
||||
ulSectorNumber = ulSectorNumber * SD_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
// Set the block count
|
||||
MAP_SDHostBlockCountSet(SDHOST_BASE, SectorCount);
|
||||
// Set the block count
|
||||
MAP_SDHostBlockCountSet(SDHOST_BASE, SectorCount);
|
||||
|
||||
// Compute the number of words
|
||||
ulSize = (SD_SECTOR_SIZE * SectorCount) / 4;
|
||||
// Compute the number of words
|
||||
ulSize = (SD_SECTOR_SIZE * SectorCount) / 4;
|
||||
|
||||
// Check if 1 block or multi block transfer
|
||||
if (SectorCount == 1) {
|
||||
// Send single block write command
|
||||
if (CardSendCmd(CMD_WRITE_SINGLE_BLK, ulSectorNumber) == 0) {
|
||||
// Write the data
|
||||
while (ulSize--) {
|
||||
MAP_SDHostDataWrite (SDHOST_BASE, (*(unsigned long *)pBuffer));
|
||||
pBuffer += 4;
|
||||
}
|
||||
// Wait for data transfer complete
|
||||
while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC));
|
||||
Res = RES_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Set the card write block count
|
||||
if (sd_disk_info.ucCardType == CARD_TYPE_SDCARD) {
|
||||
CardSendCmd(CMD_APP_CMD,sd_disk_info.usRCA << 16);
|
||||
CardSendCmd(CMD_SET_BLK_CNT, SectorCount);
|
||||
}
|
||||
// Check if 1 block or multi block transfer
|
||||
if (SectorCount == 1) {
|
||||
// Send single block write command
|
||||
if (CardSendCmd(CMD_WRITE_SINGLE_BLK, ulSectorNumber) == 0) {
|
||||
// Write the data
|
||||
while (ulSize--) {
|
||||
MAP_SDHostDataWrite (SDHOST_BASE, (*(unsigned long *)pBuffer));
|
||||
pBuffer += 4;
|
||||
}
|
||||
// Wait for data transfer complete
|
||||
while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC));
|
||||
Res = RES_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Set the card write block count
|
||||
if (sd_disk_info.ucCardType == CARD_TYPE_SDCARD) {
|
||||
CardSendCmd(CMD_APP_CMD,sd_disk_info.usRCA << 16);
|
||||
CardSendCmd(CMD_SET_BLK_CNT, SectorCount);
|
||||
}
|
||||
|
||||
// Send multi block write command
|
||||
if (CardSendCmd(CMD_WRITE_MULTI_BLK, ulSectorNumber) == 0) {
|
||||
// Write the data buffer
|
||||
while (ulSize--) {
|
||||
MAP_SDHostDataWrite(SDHOST_BASE, (*(unsigned long *)pBuffer));
|
||||
pBuffer += 4;
|
||||
}
|
||||
// Wait for transfer complete
|
||||
while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC));
|
||||
CardSendCmd(CMD_STOP_TRANS, 0);
|
||||
Res = RES_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send multi block write command
|
||||
if (CardSendCmd(CMD_WRITE_MULTI_BLK, ulSectorNumber) == 0) {
|
||||
// Write the data buffer
|
||||
while (ulSize--) {
|
||||
MAP_SDHostDataWrite(SDHOST_BASE, (*(unsigned long *)pBuffer));
|
||||
pBuffer += 4;
|
||||
}
|
||||
// Wait for transfer complete
|
||||
while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC));
|
||||
CardSendCmd(CMD_STOP_TRANS, 0);
|
||||
while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC));
|
||||
Res = RES_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Res;
|
||||
return Res;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ extern DiskInfo_t sd_disk_info;
|
||||
|
||||
DSTATUS sd_disk_init (void);
|
||||
void sd_disk_deinit (void);
|
||||
DSTATUS sd_disk_status (void);
|
||||
bool sd_disk_ready (void);
|
||||
DRESULT sd_disk_read (BYTE* pBuffer, DWORD ulSectorNumber, UINT bSectorCount);
|
||||
DRESULT sd_disk_write (const BYTE* pBuffer, DWORD ulSectorNumber, UINT bSectorCount);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "simplelink.h"
|
||||
#include "diskio.h"
|
||||
@@ -54,13 +53,25 @@ DRESULT sflash_disk_init (void) {
|
||||
// Allocate space for the block cache
|
||||
ASSERT ((sflash_block_cache = mem_Malloc(SFLASH_BLOCK_SIZE)) != NULL);
|
||||
sflash_init_done = true;
|
||||
sflash_prblock = UINT32_MAX;
|
||||
sflash_cache_is_dirty = false;
|
||||
|
||||
// Proceed to format the memory if not done yet
|
||||
// In order too speed up booting, check the last block, if exists, then
|
||||
// it means that the file system has been already created
|
||||
print_block_name (SFLASH_BLOCK_COUNT - 1);
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
if (!sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo)) {
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
return RES_OK;
|
||||
}
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
|
||||
// Proceed to format the memory
|
||||
for (int i = 0; i < SFLASH_BLOCK_COUNT; i++) {
|
||||
print_block_name (i);
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
// Create the block file if it doesn't exist
|
||||
if (sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo) < 0) {
|
||||
if (sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo) != 0) {
|
||||
if (!sl_FsOpen(sflash_block_name, FS_MODE_OPEN_CREATE(SFLASH_BLOCK_SIZE, 0), NULL, &fileHandle)) {
|
||||
sl_FsClose(fileHandle, NULL, NULL, 0);
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
@@ -77,8 +88,6 @@ DRESULT sflash_disk_init (void) {
|
||||
}
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
}
|
||||
sflash_prblock = UINT32_MAX;
|
||||
sflash_cache_is_dirty = false;
|
||||
}
|
||||
return RES_OK;
|
||||
}
|
||||
@@ -87,7 +96,7 @@ DRESULT sflash_disk_status(void) {
|
||||
if (!sflash_init_done) {
|
||||
return STA_NOINIT;
|
||||
}
|
||||
return 0;
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
DRESULT sflash_disk_read(BYTE *buff, DWORD sector, UINT count) {
|
||||
@@ -117,7 +126,7 @@ DRESULT sflash_disk_read(BYTE *buff, DWORD sector, UINT count) {
|
||||
}
|
||||
// Copy the requested sector from the block cache
|
||||
memcpy (buff, &sflash_block_cache[(secindex * SFLASH_SECTOR_SIZE)], SFLASH_SECTOR_SIZE);
|
||||
buff += SFLASH_BLOCK_SIZE;
|
||||
buff += SFLASH_SECTOR_SIZE;
|
||||
}
|
||||
return RES_OK;
|
||||
}
|
||||
@@ -152,7 +161,7 @@ DRESULT sflash_disk_write(const BYTE *buff, DWORD sector, UINT count) {
|
||||
}
|
||||
// Copy the input sector to the block cache
|
||||
memcpy (&sflash_block_cache[(secindex * SFLASH_SECTOR_SIZE)], buff, SFLASH_SECTOR_SIZE);
|
||||
buff += SFLASH_BLOCK_SIZE;
|
||||
buff += SFLASH_SECTOR_SIZE;
|
||||
sflash_cache_is_dirty = true;
|
||||
} while (++index < count);
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
#include "ff.h"
|
||||
#include "ffconf.h"
|
||||
#include "diskio.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/ffconf.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "moduos.h"
|
||||
|
||||
#if _FS_RPATH
|
||||
extern BYTE ff_CurrVol;
|
||||
@@ -65,31 +65,29 @@ int ff_get_ldnumber (const TCHAR **path) {
|
||||
}
|
||||
|
||||
if (check_path(path, "/flash", 6)) {
|
||||
return 0;
|
||||
return PD_FLASH;
|
||||
}
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
else if (check_path(path, "/sd", 3)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
return -1;
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (check_path(path, mount_obj->path, mount_obj->pathlen)) {
|
||||
return mount_obj->vol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ff_get_volname(BYTE vol, TCHAR **dest) {
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
if (vol == 0)
|
||||
#endif
|
||||
{
|
||||
if (vol == PD_FLASH) {
|
||||
memcpy(*dest, "/flash", 6);
|
||||
*dest += 7;
|
||||
*dest += 6;
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(vol))) {
|
||||
memcpy(*dest, mount_obj->path, mount_obj->pathlen);
|
||||
*dest += mount_obj->pathlen;
|
||||
}
|
||||
}
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
else
|
||||
{
|
||||
memcpy(*dest, "/sd", 3);
|
||||
*dest += 3;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* Original file from:
|
||||
* FatFs - FAT file system module configuration file R0.10c (C)ChaN, 2014
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _FFCONF
|
||||
#define _FFCONF 32020 /* Revision ID */
|
||||
|
||||
#include <stdint.h>
|
||||
#include "py/mpconfig.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Functions and Buffer Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 1
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||
/ data transfer. */
|
||||
|
||||
|
||||
#define _FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
|
||||
/ f_truncate() and f_rename() function are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define _USE_STRFUNC 0
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
|
||||
/ f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define _USE_FIND 0
|
||||
/* This option switches filtered directory read feature and related functions,
|
||||
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_MKFS 1
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FASTSEEK 0
|
||||
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable)
|
||||
/ To enable it, also _FS_TINY need to be set to 1. */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _CODE_PAGE (MICROPY_LFN_CODE_PAGE)
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 775 - Baltic
|
||||
/ 850 - Multilingual Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 858 - Multilingual Latin 1 + Euro
|
||||
/ 862 - Hebrew
|
||||
/ 866 - Russian
|
||||
/ 874 - Thai
|
||||
/ 932 - Japanese Shift_JIS (DBCS)
|
||||
/ 936 - Simplified Chinese GBK (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese Big5 (DBCS)
|
||||
*/
|
||||
|
||||
|
||||
#define _USE_LFN (MICROPY_ENABLE_LFN)
|
||||
#define _MAX_LFN (MICROPY_ALLOC_PATH_MAX)
|
||||
/* The _USE_LFN option switches the LFN feature.
|
||||
/
|
||||
/ 0: Disable LFN feature. _MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
|
||||
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree(), must be added to the project. */
|
||||
|
||||
|
||||
#define _LFN_UNICODE 0
|
||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
||||
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
|
||||
/ to 1. This option also affects behavior of string I/O functions. */
|
||||
|
||||
|
||||
#define _STRF_ENCODE 3
|
||||
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||
/
|
||||
/ 0: ANSI/OEM
|
||||
/ 1: UTF-16LE
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
/
|
||||
/ When _LFN_UNICODE is 0, this option has no effect. */
|
||||
|
||||
|
||||
#define _FS_RPATH 2
|
||||
/* This option configures relative path feature.
|
||||
/
|
||||
/ 0: Disable relative path feature and remove related functions.
|
||||
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
/
|
||||
/ Note that directory items read via f_readdir() are affected by this option. */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 2
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
||||
/* _STR_VOLUME_ID option switches string volume ID feature.
|
||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
||||
/ the drive ID strings are: A-Z and 0-9. */
|
||||
|
||||
|
||||
#define _MULTI_PARTITION 0
|
||||
/* This option switches multi-partition feature. By default (0), each logical drive
|
||||
/ number is bound to the same physical drive number and only an FAT volume found on
|
||||
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
|
||||
/ each logical drive number is bound to arbitrary physical drive and partition
|
||||
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
|
||||
|
||||
|
||||
#define _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
|
||||
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_NORTC 0
|
||||
#define _NORTC_MON 2
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2015
|
||||
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
||||
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
||||
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
||||
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
||||
|
||||
|
||||
#define _FS_LOCK 2
|
||||
/* The _FS_LOCK option switches file lock feature to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock feature. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock feature. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock feature is independent of re-entrancy. */
|
||||
|
||||
|
||||
#define _FS_REENTRANT 1
|
||||
#define _FS_TIMEOUT 2500 // milliseconds
|
||||
#define _SYNC_t SemaphoreHandle_t
|
||||
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this feature.
|
||||
/
|
||||
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||
/ function, must be added to the project. Samples are available in
|
||||
/ option/syscall.c.
|
||||
/
|
||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc.. */
|
||||
|
||||
|
||||
#define _WORD_ACCESS 0
|
||||
/* The _WORD_ACCESS option is an only platform dependent option. It defines
|
||||
/ which access method is used to the word data on the FAT volume.
|
||||
/
|
||||
/ 0: Byte-by-byte access. Always compatible with all platforms.
|
||||
/ 1: Word access. Do not choose this unless under both the following conditions.
|
||||
/
|
||||
/ * Address misaligned memory access is always allowed to ALL instructions.
|
||||
/ * Byte order on the memory is little-endian.
|
||||
/
|
||||
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||
/ Following table shows allowable settings of some processor types.
|
||||
/
|
||||
/ ARM7TDMI 0 ColdFire 0 V850E 0
|
||||
/ Cortex-M3 0 Z80 0/1 V850ES 0/1
|
||||
/ Cortex-M0 0 x86 0/1 TLCS-870 0/1
|
||||
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
|
||||
/ AVR32 0 RL78 0 R32C 0
|
||||
/ PIC18 0/1 SH-2 0 M16C 0/1
|
||||
/ PIC24 0 H8S 0 MSP430 0
|
||||
/ PIC32 0 H8/300H 0 8051 0/1
|
||||
*/
|
||||
|
||||
#endif // _FFCONF
|
||||
185
cc3200/ftp/ftp.c
185
cc3200/ftp/ftp.c
@@ -28,8 +28,7 @@
|
||||
#include <ctype.h>
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/mpstate.h"
|
||||
#include "py/obj.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@@ -47,10 +46,9 @@
|
||||
#include "ff.h"
|
||||
#include "fifo.h"
|
||||
#include "socketfifo.h"
|
||||
#include "diskio.h"
|
||||
#include "sd_diskio.h"
|
||||
#include "updater.h"
|
||||
#include "timeutils.h"
|
||||
#include "moduos.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
@@ -94,16 +92,12 @@ typedef enum {
|
||||
E_FTP_STE_SUB_DISCONNECTED = 0,
|
||||
E_FTP_STE_SUB_LISTEN_FOR_DATA,
|
||||
E_FTP_STE_SUB_DATA_CONNECTED
|
||||
} ftp_data_substate_t;
|
||||
|
||||
typedef union {
|
||||
ftp_data_substate_t data;
|
||||
} ftp_substate_t;
|
||||
|
||||
typedef struct {
|
||||
bool uservalid : 1;
|
||||
bool passvalid : 1;
|
||||
}ftp_loggin_t;
|
||||
} ftp_loggin_t;
|
||||
|
||||
typedef enum {
|
||||
E_FTP_NOTHING_OPEN = 0,
|
||||
@@ -129,25 +123,26 @@ typedef struct {
|
||||
int16_t c_sd;
|
||||
int16_t d_sd;
|
||||
int16_t dtimeout;
|
||||
ftp_state_t state;
|
||||
ftp_substate_t substate;
|
||||
uint16_t volcount;
|
||||
uint8_t state;
|
||||
uint8_t substate;
|
||||
uint8_t txRetries;
|
||||
uint8_t logginRetries;
|
||||
ftp_loggin_t loggin;
|
||||
uint8_t e_open;
|
||||
bool closechild;
|
||||
bool enabled;
|
||||
bool swupdating;
|
||||
|
||||
bool special_file;
|
||||
bool listroot;
|
||||
} ftp_data_t;
|
||||
|
||||
typedef struct {
|
||||
char * cmd;
|
||||
}ftp_cmd_t;
|
||||
} ftp_cmd_t;
|
||||
|
||||
typedef struct {
|
||||
char * month;
|
||||
}ftp_month_t;
|
||||
} ftp_month_t;
|
||||
|
||||
typedef enum {
|
||||
E_FTP_CMD_NOT_SUPPORTED = -1,
|
||||
@@ -174,7 +169,7 @@ typedef enum {
|
||||
E_FTP_CMD_NOOP,
|
||||
E_FTP_CMD_QUIT,
|
||||
E_FTP_NUM_FTP_CMDS
|
||||
}ftp_cmd_index_t;
|
||||
} ftp_cmd_index_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
@@ -194,7 +189,7 @@ static const ftp_month_t ftp_month[] = { { "Jan" }, { "Feb" }, { "Mar" }, { "Apr
|
||||
{ "May" }, { "Jun" }, { "Jul" }, { "Ago" },
|
||||
{ "Sep" }, { "Oct" }, { "Nov" }, { "Dec" } };
|
||||
|
||||
static SocketFifoElement_t *ftp_fifoelements;
|
||||
static SocketFifoElement_t ftp_fifoelements[FTP_SOCKETFIFO_ELEMENTS_MAX];
|
||||
static FIFO_t ftp_socketfifo;
|
||||
|
||||
/******************************************************************************
|
||||
@@ -219,7 +214,7 @@ static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name);
|
||||
static bool ftp_open_file (const char *path, int mode);
|
||||
static ftp_result_t ftp_read_file (char *filebuf, uint32_t desiredsize, uint32_t *actualsize);
|
||||
static ftp_result_t ftp_write_file (char *filebuf, uint32_t size);
|
||||
static ftp_result_t ftp_open_dir_for_listing (const char *path, char *list, uint32_t maxlistsize, uint32_t *listsize);
|
||||
static ftp_result_t ftp_open_dir_for_listing (const char *path);
|
||||
static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *listsize);
|
||||
static void ftp_open_child (char *pwd, char *dir);
|
||||
static void ftp_close_child (char *pwd);
|
||||
@@ -234,7 +229,6 @@ void ftp_init (void) {
|
||||
ASSERT ((ftp_path = mem_Malloc(FTP_MAX_PARAM_SIZE)) != NULL);
|
||||
ASSERT ((ftp_scratch_buffer = mem_Malloc(FTP_MAX_PARAM_SIZE)) != NULL);
|
||||
ASSERT ((ftp_cmd_buffer = mem_Malloc(FTP_MAX_PARAM_SIZE + FTP_CMD_SIZE_MAX)) != NULL);
|
||||
ASSERT ((ftp_fifoelements = mem_Malloc(FTP_SOCKETFIFO_ELEMENTS_MAX * sizeof(SocketFifoElement_t))) != NULL);
|
||||
SOCKETFIFO_Init (&ftp_socketfifo, (void *)ftp_fifoelements, FTP_SOCKETFIFO_ELEMENTS_MAX);
|
||||
ftp_data.c_sd = -1;
|
||||
ftp_data.d_sd = -1;
|
||||
@@ -242,8 +236,9 @@ void ftp_init (void) {
|
||||
ftp_data.ld_sd = -1;
|
||||
ftp_data.e_open = E_FTP_NOTHING_OPEN;
|
||||
ftp_data.state = E_FTP_STE_DISABLED;
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.swupdating = false;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.special_file = false;
|
||||
ftp_data.volcount = 0;
|
||||
}
|
||||
|
||||
void ftp_run (void) {
|
||||
@@ -252,12 +247,12 @@ void ftp_run (void) {
|
||||
ftp_wait_for_enabled();
|
||||
break;
|
||||
case E_FTP_STE_START:
|
||||
if (wlan_is_connected() && ftp_create_listening_socket(&ftp_data.lc_sd, FTP_CMD_PORT, FTP_CMD_CLIENTS_MAX)) {
|
||||
if (wlan_is_connected() && ftp_create_listening_socket(&ftp_data.lc_sd, FTP_CMD_PORT, FTP_CMD_CLIENTS_MAX - 1)) {
|
||||
ftp_data.state = E_FTP_STE_READY;
|
||||
}
|
||||
break;
|
||||
case E_FTP_STE_READY:
|
||||
if (ftp_data.c_sd < 0 && ftp_data.substate.data == E_FTP_STE_SUB_DISCONNECTED) {
|
||||
if (ftp_data.c_sd < 0 && ftp_data.substate == E_FTP_STE_SUB_DISCONNECTED) {
|
||||
if (E_FTP_RESULT_OK == ftp_wait_for_connection(ftp_data.lc_sd, &ftp_data.c_sd)) {
|
||||
ftp_data.txRetries = 0;
|
||||
ftp_data.logginRetries = 0;
|
||||
@@ -270,7 +265,7 @@ void ftp_run (void) {
|
||||
}
|
||||
}
|
||||
if (SOCKETFIFO_IsEmpty()) {
|
||||
if (ftp_data.c_sd > 0 && ftp_data.substate.data != E_FTP_STE_SUB_LISTEN_FOR_DATA) {
|
||||
if (ftp_data.c_sd > 0 && ftp_data.substate != E_FTP_STE_SUB_LISTEN_FOR_DATA) {
|
||||
ftp_process_cmd();
|
||||
if (ftp_data.state != E_FTP_STE_READY) {
|
||||
break;
|
||||
@@ -287,8 +282,7 @@ void ftp_run (void) {
|
||||
ftp_list_dir((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, &listsize);
|
||||
if (listsize > 0) {
|
||||
ftp_send_data(listsize);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ftp_send_reply(226, NULL);
|
||||
ftp_data.state = E_FTP_STE_END_TRANSFER;
|
||||
}
|
||||
@@ -325,7 +319,7 @@ void ftp_run (void) {
|
||||
ftp_data.dtimeout = 0;
|
||||
ftp_data.ctimeout = 0;
|
||||
// its a software update
|
||||
if (ftp_data.swupdating) {
|
||||
if (ftp_data.special_file) {
|
||||
if (updater_write(ftp_data.dBuffer, len)) {
|
||||
break;
|
||||
}
|
||||
@@ -345,8 +339,8 @@ void ftp_run (void) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ftp_data.swupdating) {
|
||||
ftp_data.swupdating = false;
|
||||
if (ftp_data.special_file) {
|
||||
ftp_data.special_file = false;
|
||||
updater_finnish();
|
||||
}
|
||||
ftp_close_files();
|
||||
@@ -359,19 +353,19 @@ void ftp_run (void) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ftp_data.substate.data) {
|
||||
switch (ftp_data.substate) {
|
||||
case E_FTP_STE_SUB_DISCONNECTED:
|
||||
break;
|
||||
case E_FTP_STE_SUB_LISTEN_FOR_DATA:
|
||||
if (E_FTP_RESULT_OK == ftp_wait_for_connection(ftp_data.ld_sd, &ftp_data.d_sd)) {
|
||||
ftp_data.dtimeout = 0;
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DATA_CONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DATA_CONNECTED;
|
||||
}
|
||||
else if (ftp_data.dtimeout++ > FTP_DATA_TIMEOUT_MS / FTP_CYCLE_TIME_MS) {
|
||||
ftp_data.dtimeout = 0;
|
||||
// close the listening socket
|
||||
servers_close_socket(&ftp_data.ld_sd);
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
}
|
||||
break;
|
||||
case E_FTP_STE_SUB_DATA_CONNECTED:
|
||||
@@ -380,7 +374,7 @@ void ftp_run (void) {
|
||||
servers_close_socket(&ftp_data.ld_sd);
|
||||
servers_close_socket(&ftp_data.d_sd);
|
||||
ftp_close_filesystem_on_error ();
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -392,7 +386,7 @@ void ftp_run (void) {
|
||||
|
||||
// check the state of the data sockets
|
||||
if (ftp_data.d_sd < 0 && (ftp_data.state > E_FTP_STE_READY)) {
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.state = E_FTP_STE_READY;
|
||||
}
|
||||
}
|
||||
@@ -413,7 +407,8 @@ void ftp_reset (void) {
|
||||
servers_close_socket(&ftp_data.ld_sd);
|
||||
ftp_close_cmd_data();
|
||||
ftp_data.state = E_FTP_STE_START;
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.volcount = 0;
|
||||
SOCKETFIFO_Flush();
|
||||
}
|
||||
|
||||
@@ -557,7 +552,7 @@ static void ftp_send_from_fifo (void) {
|
||||
servers_close_socket(&ftp_data.ld_sd);
|
||||
// this one is the command socket
|
||||
servers_close_socket(fifoelement.sd);
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
}
|
||||
ftp_close_filesystem_on_error();
|
||||
}
|
||||
@@ -578,8 +573,8 @@ static void ftp_send_from_fifo (void) {
|
||||
// close the listening and the data sockets
|
||||
servers_close_socket(&ftp_data.ld_sd);
|
||||
servers_close_socket(&ftp_data.d_sd);
|
||||
if (ftp_data.swupdating) {
|
||||
ftp_data.swupdating = false;
|
||||
if (ftp_data.special_file) {
|
||||
ftp_data.special_file = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -607,7 +602,6 @@ static void ftp_process_cmd (void) {
|
||||
_i32 len;
|
||||
char *bufptr = (char *)ftp_cmd_buffer;
|
||||
ftp_result_t result;
|
||||
uint32_t listsize;
|
||||
FRESULT fres;
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
@@ -617,7 +611,7 @@ static void ftp_process_cmd (void) {
|
||||
|
||||
ftp_data.closechild = false;
|
||||
// also use the reply buffer to receive new commands
|
||||
if (E_FTP_RESULT_OK == (result = ftp_recv_non_blocking(ftp_data.c_sd, ftp_cmd_buffer, FTP_BUFFER_SIZE, &len))) {
|
||||
if (E_FTP_RESULT_OK == (result = ftp_recv_non_blocking(ftp_data.c_sd, ftp_cmd_buffer, FTP_MAX_PARAM_SIZE + FTP_CMD_SIZE_MAX, &len))) {
|
||||
// bufptr is moved as commands are being popped
|
||||
ftp_cmd_index_t cmd = ftp_pop_command(&bufptr);
|
||||
if (!ftp_data.loggin.passvalid && (cmd != E_FTP_CMD_USER && cmd != E_FTP_CMD_PASS && cmd != E_FTP_CMD_QUIT)) {
|
||||
@@ -709,10 +703,10 @@ static void ftp_process_cmd (void) {
|
||||
{
|
||||
// some servers (e.g. google chrome) send PASV several times very quickly
|
||||
servers_close_socket(&ftp_data.d_sd);
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_DISCONNECTED;
|
||||
ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED;
|
||||
bool socketcreated = true;
|
||||
if (ftp_data.ld_sd < 0) {
|
||||
socketcreated = ftp_create_listening_socket(&ftp_data.ld_sd, FTP_PASIVE_DATA_PORT, FTP_DATA_CLIENTS_MAX);
|
||||
socketcreated = ftp_create_listening_socket(&ftp_data.ld_sd, FTP_PASIVE_DATA_PORT, FTP_DATA_CLIENTS_MAX - 1);
|
||||
}
|
||||
if (socketcreated) {
|
||||
uint32_t ip;
|
||||
@@ -721,7 +715,7 @@ static void ftp_process_cmd (void) {
|
||||
wlan_get_ip(&ip);
|
||||
snprintf((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, "(%u,%u,%u,%u,%u,%u)",
|
||||
pip[3], pip[2], pip[1], pip[0], (FTP_PASIVE_DATA_PORT >> 8), (FTP_PASIVE_DATA_PORT & 0xFF));
|
||||
ftp_data.substate.data = E_FTP_STE_SUB_LISTEN_FOR_DATA;
|
||||
ftp_data.substate = E_FTP_STE_SUB_LISTEN_FOR_DATA;
|
||||
ftp_send_reply(227, (char *)ftp_data.dBuffer);
|
||||
}
|
||||
else {
|
||||
@@ -730,13 +724,7 @@ static void ftp_process_cmd (void) {
|
||||
}
|
||||
break;
|
||||
case E_FTP_CMD_LIST:
|
||||
if ((result = ftp_open_dir_for_listing(ftp_path, (char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, &listsize)) == E_FTP_RESULT_OK) {
|
||||
ftp_data.state = E_FTP_STE_END_TRANSFER;
|
||||
ftp_send_reply(150, NULL);
|
||||
ftp_send_data(listsize);
|
||||
ftp_send_reply(226, NULL);
|
||||
}
|
||||
else if (result == E_FTP_RESULT_CONTINUE) {
|
||||
if (ftp_open_dir_for_listing(ftp_path) == E_FTP_RESULT_CONTINUE) {
|
||||
ftp_data.state = E_FTP_STE_CONTINUE_LISTING;
|
||||
ftp_send_reply(150, NULL);
|
||||
}
|
||||
@@ -759,15 +747,14 @@ static void ftp_process_cmd (void) {
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
// first check if a software update is being requested
|
||||
if (updater_check_path (ftp_path)) {
|
||||
// start by erasing the previous status file
|
||||
// must be done before starting the updater
|
||||
f_unlink(ftp_path);
|
||||
if (updater_start()) {
|
||||
ftp_data.swupdating = true;
|
||||
ftp_data.special_file = true;
|
||||
ftp_data.state = E_FTP_STE_CONTINUE_FILE_RX;
|
||||
ftp_send_reply(150, NULL);
|
||||
}
|
||||
else {
|
||||
// to unlock the updater
|
||||
updater_finnish();
|
||||
ftp_data.state = E_FTP_STE_END_TRANSFER;
|
||||
ftp_send_reply(550, NULL);
|
||||
}
|
||||
@@ -861,9 +848,9 @@ static void ftp_close_files (void) {
|
||||
|
||||
static void ftp_close_filesystem_on_error (void) {
|
||||
ftp_close_files();
|
||||
if (ftp_data.swupdating) {
|
||||
if (ftp_data.special_file) {
|
||||
updater_finnish ();
|
||||
ftp_data.swupdating = false;
|
||||
ftp_data.special_file = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +886,6 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
|
||||
|
||||
char *type = (fno->fattrib & AM_DIR) ? "d" : "-";
|
||||
uint32_t tseconds;
|
||||
uint16_t mseconds;
|
||||
uint mindex = (((fno->fdate >> 5) & 0x0f) > 0) ? (((fno->fdate >> 5) & 0x0f) - 1) : 0;
|
||||
uint day = ((fno->fdate & 0x1f) > 0) ? (fno->fdate & 0x1f) : 1;
|
||||
uint fseconds = timeutils_seconds_since_2000(1980 + ((fno->fdate >> 9) & 0x7f),
|
||||
@@ -908,7 +894,7 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
|
||||
(fno->ftime >> 11) & 0x1f,
|
||||
(fno->ftime >> 5) & 0x3f,
|
||||
2 * (fno->ftime & 0x1f));
|
||||
MAP_PRCMRTCGet(&tseconds, &mseconds);
|
||||
tseconds = pyb_rtc_get_seconds();
|
||||
if (FTP_UNIX_SECONDS_180_DAYS < tseconds - fseconds) {
|
||||
return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %5u %s\r\n",
|
||||
type, (_u32)fno->fsize, ftp_month[mindex].month, day,
|
||||
@@ -932,12 +918,11 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
|
||||
static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t tseconds;
|
||||
uint16_t mseconds;
|
||||
char *type = "d";
|
||||
|
||||
timeutils_seconds_since_2000_to_struct_time((FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101), &tm);
|
||||
|
||||
MAP_PRCMRTCGet(&tseconds, &mseconds);
|
||||
tseconds = pyb_rtc_get_seconds();
|
||||
if (FTP_UNIX_SECONDS_180_DAYS < tseconds - (FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101)) {
|
||||
return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %5u %s\r\n",
|
||||
type, 0, ftp_month[(tm.tm_mon - 1)].month, tm.tm_mday, tm.tm_year, name);
|
||||
@@ -985,32 +970,25 @@ static ftp_result_t ftp_write_file (char *filebuf, uint32_t size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static ftp_result_t ftp_open_dir_for_listing (const char *path, char *list, uint32_t maxlistsize, uint32_t *listsize) {
|
||||
uint next = 0;
|
||||
// "hack" to list root directory
|
||||
static ftp_result_t ftp_open_dir_for_listing (const char *path) {
|
||||
// "hack" to detect the root directory
|
||||
if (path[0] == '/' && path[1] == '\0') {
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), "flash");
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
if (sd_disk_ready()) {
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), "sd");
|
||||
ftp_data.listroot = true;
|
||||
} else {
|
||||
FRESULT res;
|
||||
res = f_opendir(&ftp_data.dp, path); /* Open the directory */
|
||||
if (res != FR_OK) {
|
||||
return E_FTP_RESULT_FAILED;
|
||||
}
|
||||
#endif
|
||||
*listsize = next;
|
||||
return E_FTP_RESULT_OK;
|
||||
ftp_data.e_open = E_FTP_DIR_OPEN;
|
||||
ftp_data.listroot = false;
|
||||
}
|
||||
|
||||
FRESULT res;
|
||||
res = f_opendir(&ftp_data.dp, path); /* Open the directory */
|
||||
if (res != FR_OK) {
|
||||
return E_FTP_RESULT_FAILED;
|
||||
}
|
||||
ftp_data.e_open = E_FTP_DIR_OPEN;
|
||||
return E_FTP_RESULT_CONTINUE;
|
||||
}
|
||||
|
||||
static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *listsize) {
|
||||
uint next = 0;
|
||||
uint count = 0;
|
||||
uint listcount = 0;
|
||||
FRESULT res;
|
||||
ftp_result_t result = E_FTP_RESULT_CONTINUE;
|
||||
FILINFO fno;
|
||||
@@ -1019,22 +997,40 @@ static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *li
|
||||
fno.lfsize = _MAX_LFN;
|
||||
|
||||
// read up to 2 directory items
|
||||
while (count < 2) {
|
||||
while (listcount < 2) {
|
||||
#else
|
||||
// read up to 4 directory items
|
||||
while (count < 4) {
|
||||
while (listcount < 4) {
|
||||
#endif
|
||||
res = f_readdir(&ftp_data.dp, &fno); /* Read a directory item */
|
||||
if (res != FR_OK || fno.fname[0] == 0) {
|
||||
result = E_FTP_RESULT_OK;
|
||||
break; /* Break on error or end of dp */
|
||||
}
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */
|
||||
if (ftp_data.listroot) {
|
||||
// root directory "hack"
|
||||
if (0 == ftp_data.volcount) {
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), "flash");
|
||||
} else if (ftp_data.volcount <= MP_STATE_PORT(mount_obj_list).len) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[(ftp_data.volcount - 1)]));
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), (char *)&mount_obj->path[1]);
|
||||
} else {
|
||||
if (!next) {
|
||||
// no volume found this time, we are done
|
||||
ftp_data.volcount = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ftp_data.volcount++;
|
||||
} else {
|
||||
// a "normal" directory
|
||||
res = f_readdir(&ftp_data.dp, &fno); /* Read a directory item */
|
||||
if (res != FR_OK || fno.fname[0] == 0) {
|
||||
result = E_FTP_RESULT_OK;
|
||||
break; /* Break on error or end of dp */
|
||||
}
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */
|
||||
|
||||
// add the entry to the list
|
||||
next += ftp_print_eplf_item((list + next), (maxlistsize - next), &fno);
|
||||
count++;
|
||||
// add the entry to the list
|
||||
next += ftp_print_eplf_item((list + next), (maxlistsize - next), &fno);
|
||||
}
|
||||
listcount++;
|
||||
}
|
||||
if (result == E_FTP_RESULT_OK) {
|
||||
ftp_close_files();
|
||||
@@ -1049,8 +1045,7 @@ static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *li
|
||||
static void ftp_open_child (char *pwd, char *dir) {
|
||||
if (dir[0] == '/') {
|
||||
strcpy (pwd, dir);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (strlen(pwd) > 1) {
|
||||
strcat (pwd, "/");
|
||||
}
|
||||
@@ -1070,8 +1065,7 @@ static void ftp_close_child (char *pwd) {
|
||||
}
|
||||
if (len == 0) {
|
||||
strcpy (pwd, "/");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pwd[len] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -1084,8 +1078,7 @@ static void ftp_return_to_previous_path (char *pwd, char *dir) {
|
||||
else {
|
||||
if (newlen == 0) {
|
||||
strcpy (pwd, "/");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pwd[newlen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "simplelink.h"
|
||||
#include "flc.h"
|
||||
@@ -11,6 +36,7 @@
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "debug.h"
|
||||
#include "osi.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
@@ -18,6 +44,9 @@
|
||||
#define UPDATER_IMG_PATH "/flash/sys/mcuimg.bin"
|
||||
#define UPDATER_SRVPACK_PATH "/flash/sys/servicepack.ucf"
|
||||
#define UPDATER_SIGN_PATH "/flash/sys/servicepack.sig"
|
||||
#define UPDATER_CA_PATH "/flash/cert/ca.pem"
|
||||
#define UPDATER_CERT_PATH "/flash/cert/cert.pem"
|
||||
#define UPDATER_KEY_PATH "/flash/cert/private.key"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
@@ -32,33 +61,65 @@ typedef struct {
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
static updater_data_t updater_data;
|
||||
static updater_data_t updater_data = { .path = NULL, .fhandle = -1, .fsize = 0, .foffset = 0 };
|
||||
static OsiLockObj_t updater_LockObj;
|
||||
static sBootInfo_t sBootInfo;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void updater_pre_init (void) {
|
||||
// create the updater lock
|
||||
ASSERT(OSI_OK == sl_LockObjCreate(&updater_LockObj, "UpdaterLock"));
|
||||
}
|
||||
|
||||
bool updater_check_path (void *path) {
|
||||
sl_LockObjLock (&updater_LockObj, SL_OS_WAIT_FOREVER);
|
||||
if (!strcmp(UPDATER_IMG_PATH, path)) {
|
||||
updater_data.path = IMG_UPDATE;
|
||||
updater_data.fsize = IMG_SIZE;
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(UPDATER_SRVPACK_PATH, path)) {
|
||||
updater_data.path = IMG_UPDATE1;
|
||||
// the launchxl doesn't have enough flash space for 2 user update images
|
||||
#ifdef WIPY
|
||||
// check which one should be the next active image
|
||||
_i32 fhandle;
|
||||
if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) {
|
||||
ASSERT (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t)));
|
||||
sl_FsClose(fhandle, 0, 0, 0);
|
||||
// if we still have an image pending for verification, keep overwriting it
|
||||
if ((sBootInfo.Status == IMG_STATUS_CHECK && sBootInfo.ActiveImg == IMG_ACT_UPDATE2) ||
|
||||
(sBootInfo.ActiveImg == IMG_ACT_UPDATE1 && sBootInfo.Status != IMG_STATUS_CHECK)) {
|
||||
updater_data.path = IMG_UPDATE2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (!strcmp(UPDATER_SRVPACK_PATH, path)) {
|
||||
updater_data.path = IMG_SRVPACK;
|
||||
updater_data.fsize = SRVPACK_SIZE;
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(UPDATER_SIGN_PATH, path)) {
|
||||
} else if (!strcmp(UPDATER_SIGN_PATH, path)) {
|
||||
updater_data.path = SRVPACK_SIGN;
|
||||
updater_data.fsize = SIGN_SIZE;
|
||||
return true;
|
||||
} else if (!strcmp(UPDATER_CA_PATH, path)) {
|
||||
updater_data.path = CA_FILE;
|
||||
updater_data.fsize = CA_KEY_SIZE;
|
||||
} else if (!strcmp(UPDATER_CERT_PATH, path)) {
|
||||
updater_data.path = CERT_FILE;
|
||||
updater_data.fsize = CA_KEY_SIZE;
|
||||
} else if (!strcmp(UPDATER_KEY_PATH, path)) {
|
||||
updater_data.path = KEY_FILE;
|
||||
updater_data.fsize = CA_KEY_SIZE;
|
||||
} else {
|
||||
sl_LockObjUnlock (&updater_LockObj);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool updater_start (void) {
|
||||
_u32 AccessModeAndMaxSize = FS_MODE_OPEN_WRITE;
|
||||
SlFsFileInfo_t FsFileInfo;
|
||||
bool result = false;
|
||||
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
if (0 != sl_FsGetInfo((_u8 *)updater_data.path, 0, &FsFileInfo)) {
|
||||
// file doesn't exist, create it
|
||||
@@ -66,49 +127,76 @@ bool updater_start (void) {
|
||||
}
|
||||
if (!sl_FsOpen((_u8 *)updater_data.path, AccessModeAndMaxSize, NULL, &updater_data.fhandle)) {
|
||||
updater_data.foffset = 0;
|
||||
return true;
|
||||
result = true;
|
||||
}
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool updater_write (uint8_t *buf, uint32_t len) {
|
||||
bool result = false;
|
||||
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
if (len == sl_FsWrite(updater_data.fhandle, updater_data.foffset, buf, len)) {
|
||||
updater_data.foffset += len;
|
||||
return true;
|
||||
result = true;
|
||||
}
|
||||
return false;
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void updater_finnish (void) {
|
||||
sBootInfo_t sBootInfo;
|
||||
_i32 fhandle;
|
||||
|
||||
if (updater_data.fhandle > 0) {
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
// close the file being updated
|
||||
sl_FsClose(updater_data.fhandle, NULL, NULL, 0);
|
||||
|
||||
if (!strcmp (IMG_UPDATE, updater_data.path)) {
|
||||
// open the boot info file for reading
|
||||
#ifdef WIPY
|
||||
// if we still have an image pending for verification, leave the boot info as it is
|
||||
if (!strncmp(IMG_PREFIX, updater_data.path, strlen(IMG_PREFIX)) && sBootInfo.Status != IMG_STATUS_CHECK) {
|
||||
#else
|
||||
if (!strncmp(IMG_PREFIX, updater_data.path, strlen(IMG_PREFIX))) {
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) {
|
||||
|
||||
ASSERT (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t)));
|
||||
sl_FsClose(fhandle, 0, 0, 0);
|
||||
// open the file for writing
|
||||
#endif
|
||||
// open the boot info file for writing
|
||||
ASSERT (sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_WRITE, NULL, &fhandle) == 0);
|
||||
#ifdef DEBUG
|
||||
}
|
||||
else {
|
||||
// the boot info file doesn't exist yet
|
||||
_u32 BootInfoCreateFlag = _FS_FILE_OPEN_FLAG_COMMIT | _FS_FILE_PUBLIC_WRITE | _FS_FILE_PUBLIC_READ;
|
||||
ASSERT (sl_FsOpen ((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_CREATE((2 * sizeof(sBootInfo_t)),
|
||||
BootInfoCreateFlag), NULL, &fhandle) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// write the new boot info
|
||||
sBootInfo.ActiveImg = IMG_ACT_UPDATE;
|
||||
// save the new boot info
|
||||
#ifdef WIPY
|
||||
sBootInfo.PrevImg = sBootInfo.ActiveImg;
|
||||
if (sBootInfo.ActiveImg == IMG_ACT_UPDATE1) {
|
||||
sBootInfo.ActiveImg = IMG_ACT_UPDATE2;
|
||||
} else {
|
||||
sBootInfo.ActiveImg = IMG_ACT_UPDATE1;
|
||||
}
|
||||
// the launchxl doesn't have enough flash space for 2 user updates
|
||||
#else
|
||||
sBootInfo.PrevImg = IMG_ACT_FACTORY;
|
||||
sBootInfo.ActiveImg = IMG_ACT_UPDATE1;
|
||||
#endif
|
||||
sBootInfo.Status = IMG_STATUS_CHECK;
|
||||
ASSERT (sizeof(sBootInfo_t) == sl_FsWrite(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t)));
|
||||
sl_FsClose(fhandle, 0, 0, 0);
|
||||
}
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
updater_data.fhandle = -1;
|
||||
}
|
||||
updater_data.fhandle = -1;
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
sl_LockObjUnlock (&updater_LockObj);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,38 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UPDATER_H_
|
||||
#define UPDATER_H_
|
||||
|
||||
bool updater_check_path (void *path);
|
||||
bool updater_start (void);
|
||||
bool updater_write (uint8_t *buf, uint32_t len);
|
||||
void updater_finnish (void);
|
||||
bool updater_verify (uint8_t *rbuff, uint8_t *hasbuff);
|
||||
extern void updater_pre_init (void);
|
||||
extern bool updater_check_path (void *path);
|
||||
extern bool updater_start (void);
|
||||
extern bool updater_write (uint8_t *buf, uint32_t len);
|
||||
extern void updater_finnish (void);
|
||||
extern bool updater_verify (uint8_t *rbuff, uint8_t *hasbuff);
|
||||
|
||||
#endif /* UPDATER_H_ */
|
||||
|
||||
@@ -67,6 +67,18 @@ static inline void __set_PRIMASK(uint32_t priMask) {
|
||||
__asm volatile ("msr primask, %0" : : "r" (priMask) : "memory");
|
||||
}
|
||||
|
||||
__attribute__(( always_inline ))
|
||||
static inline uint32_t __get_BASEPRI(void) {
|
||||
uint32_t result;
|
||||
__asm volatile ("mrs %0, basepri" : "=r" (result));
|
||||
return(result);
|
||||
}
|
||||
|
||||
__attribute__(( always_inline ))
|
||||
static inline void __set_BASEPRI(uint32_t value) {
|
||||
__asm volatile ("msr basepri, %0" : : "r" (value) : "memory");
|
||||
}
|
||||
|
||||
__attribute__(( always_inline ))
|
||||
static inline void enable_irq(mp_uint_t state) {
|
||||
__set_PRIMASK(state);
|
||||
|
||||
@@ -31,12 +31,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objstr.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "systick.h"
|
||||
@@ -45,6 +49,9 @@
|
||||
#include "mpexception.h"
|
||||
#include "telnet.h"
|
||||
#include "pybuart.h"
|
||||
#include "utils.h"
|
||||
#include "irq.h"
|
||||
#include "moduos.h"
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
#include "FreeRTOS.h"
|
||||
@@ -65,11 +72,6 @@ static void hal_TickInit (void);
|
||||
******************************************************************************/
|
||||
static volatile uint32_t HAL_tickCount;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
struct _pyb_uart_obj_t *pyb_stdio_uart;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE IMPORTED DATA
|
||||
******************************************************************************/
|
||||
@@ -102,21 +104,32 @@ void HAL_IncrementTick(void) {
|
||||
HAL_tickCount++;
|
||||
}
|
||||
|
||||
uint32_t HAL_GetTick(void) {
|
||||
mp_uint_t mp_hal_ticks_ms(void) {
|
||||
return HAL_tickCount;
|
||||
}
|
||||
|
||||
void HAL_Delay(uint32_t delay) {
|
||||
#ifdef USE_FREERTOS
|
||||
vTaskDelay (delay / portTICK_PERIOD_MS);
|
||||
#else
|
||||
uint32_t start = HAL_tickCount;
|
||||
// Wraparound of tick is taken care of by 2's complement arithmetic.
|
||||
while (HAL_tickCount - start < delay) {
|
||||
// Enter sleep mode, waiting for (at least) the SysTick interrupt.
|
||||
__WFI();
|
||||
void mp_hal_delay_ms(mp_uint_t delay) {
|
||||
// only if we are not within interrupt context and interrupts are enabled
|
||||
if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) {
|
||||
#ifdef USE_FREERTOS
|
||||
vTaskDelay (delay / portTICK_PERIOD_MS);
|
||||
#else
|
||||
uint32_t start = HAL_tickCount;
|
||||
// wraparound of tick is taken care of by 2's complement arithmetic.
|
||||
while (HAL_tickCount - start < delay) {
|
||||
// enter sleep mode, waiting for (at least) the SysTick interrupt.
|
||||
__WFI();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
for (int ms = 0; ms < delay; ms++) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(1000));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NORETURN void mp_hal_raise(int errno) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, mp_obj_new_int(errno)));
|
||||
}
|
||||
|
||||
void mp_hal_set_interrupt_char (int c) {
|
||||
@@ -127,37 +140,60 @@ void mp_hal_stdout_tx_str(const char *str) {
|
||||
mp_hal_stdout_tx_strn(str, strlen(str));
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
|
||||
// send stdout to UART
|
||||
if (pyb_stdio_uart != NULL) {
|
||||
uart_tx_strn(pyb_stdio_uart, str, len);
|
||||
void mp_hal_stdout_tx_strn(const char *str, size_t len) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj)) {
|
||||
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
|
||||
uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len);
|
||||
} else {
|
||||
MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_str_of_type(&mp_type_str, (const byte *)str, len);
|
||||
mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->write);
|
||||
}
|
||||
}
|
||||
// and also to telnet
|
||||
if (telnet_is_active()) {
|
||||
telnet_tx_strn(str, len);
|
||||
}
|
||||
telnet_tx_strn(str, len);
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
|
||||
// send stdout to UART
|
||||
if (pyb_stdio_uart != NULL) {
|
||||
uart_tx_strn_cooked(pyb_stdio_uart, str, len);
|
||||
void mp_hal_stdout_tx_strn_cooked (const char *str, size_t len) {
|
||||
int32_t nslen = 0;
|
||||
const char *_str = str;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
mp_hal_stdout_tx_strn(_str, nslen);
|
||||
mp_hal_stdout_tx_strn("\r\n", 2);
|
||||
_str += nslen + 1;
|
||||
nslen = 0;
|
||||
} else {
|
||||
nslen++;
|
||||
}
|
||||
}
|
||||
// and also to telnet
|
||||
if (telnet_is_active()) {
|
||||
telnet_tx_strn_cooked(str, len);
|
||||
if (_str < str + len) {
|
||||
mp_hal_stdout_tx_strn(_str, nslen);
|
||||
}
|
||||
}
|
||||
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
for ( ;; ) {
|
||||
// read telnet first
|
||||
if (telnet_rx_any()) {
|
||||
return telnet_rx_char();
|
||||
} else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup
|
||||
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
|
||||
if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) {
|
||||
return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o);
|
||||
}
|
||||
} else {
|
||||
MP_STATE_PORT(os_term_dup_obj)->read[2] = mp_obj_new_int(1);
|
||||
mp_obj_t data = mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->read);
|
||||
// data len is > 0
|
||||
if (mp_obj_is_true(data)) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
return ((int *)(bufinfo.buf))[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pyb_stdio_uart != NULL && uart_rx_any(pyb_stdio_uart)) {
|
||||
return uart_rx_char(pyb_stdio_uart);
|
||||
}
|
||||
HAL_Delay(1);
|
||||
mp_hal_delay_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#define HAL_FCPU_MHZ 80U
|
||||
#define HAL_FCPU_HZ (1000000U * HAL_FCPU_MHZ)
|
||||
#define HAL_SYSTICK_PERIOD_US 1000U
|
||||
#define UTILS_DELAY_US_TO_COUNT(us) (((us) * HAL_FCPU_MHZ) / 3)
|
||||
#define UTILS_DELAY_US_TO_COUNT(us) (((us) * HAL_FCPU_MHZ) / 6)
|
||||
|
||||
#define HAL_NVIC_INT_CTRL_REG (*((volatile uint32_t *) 0xE000ED04 ) )
|
||||
#define HAL_VECTACTIVE_MASK (0x1FUL)
|
||||
@@ -55,11 +55,6 @@
|
||||
" isb \n"); \
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
extern struct _pyb_uart_obj_t *pyb_stdio_uart;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
@@ -67,13 +62,7 @@ extern struct _pyb_uart_obj_t *pyb_stdio_uart;
|
||||
extern void HAL_SystemInit (void);
|
||||
extern void HAL_SystemDeInit (void);
|
||||
extern void HAL_IncrementTick(void);
|
||||
extern uint32_t HAL_GetTick(void);
|
||||
extern void HAL_Delay(uint32_t delay);
|
||||
extern NORETURN void mp_hal_raise(int errno);
|
||||
extern void mp_hal_set_interrupt_char (int c);
|
||||
|
||||
int mp_hal_stdin_rx_chr(void);
|
||||
void mp_hal_stdout_tx_str(const char *str);
|
||||
void mp_hal_stdout_tx_strn(const char *str, uint32_t len);
|
||||
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len);
|
||||
|
||||
#endif /* CC3200_LAUNCHXL_HAL_CC3200_HAL_H_ */
|
||||
|
||||
@@ -112,28 +112,29 @@
|
||||
// following wrapper can be used to convert the value from cycles to
|
||||
// millisecond:
|
||||
//
|
||||
// CYCLES_U16MS(cycles) ((cycles *1000)/ 1024),
|
||||
// CYCLES_U16MS(cycles) ((cycles * 1000) / 1024),
|
||||
//
|
||||
// Similarly, before setting the value, it must be first converted (from ms to
|
||||
// cycles).
|
||||
//
|
||||
// U16MS_CYCLES(msec) ((msec *1024)/1000)
|
||||
// U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
//
|
||||
// Note: There is a precision loss of 1 ms with the above scheme.
|
||||
//
|
||||
//
|
||||
#define SCC_U64MSEC_GET() (MAP_PRCMSlowClkCtrGet() >> 5)
|
||||
#define SCC_U64MSEC_GET() (RTCFastDomainCounterGet() >> 5)
|
||||
#define SCC_U64MSEC_MATCH_SET(u64Msec) (MAP_PRCMSlowClkCtrMatchSet(u64Msec << 5))
|
||||
#define SCC_U64MSEC_MATCH_GET() (MAP_PRCMSlowClkCtrMatchGet() >> 5)
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Bit: 31 is used to indicate use of RTC. If set as '1', RTC feature is used.
|
||||
// Bit: 30 is used to indicate that a safe boot should be performed
|
||||
// bit: 29 is used to indicate that the last reset was caused by the WDT
|
||||
// Bits: 28 to 26 are unused
|
||||
// Bit: 30 is used to indicate that a safe boot should be performed.
|
||||
// bit: 29 is used to indicate that the last reset was caused by the WDT.
|
||||
// bit: 28 is used to indicate that the board is booting for the first time after being programmed in factory.
|
||||
// Bits: 27 and 26 are unused.
|
||||
// Bits: 25 to 16 are used to save millisecond part of RTC reference.
|
||||
// Bits: 15 to 0 are being used for HW Changes / ECO
|
||||
// Bits: 15 to 0 are being used for HW Changes / ECO.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
@@ -207,6 +208,39 @@ static void RTCU32SecRegWrite(unsigned long u32Msec)
|
||||
MAP_PRCMHIBRegWrite(RTC_SECS_U32_REG_ADDR, u32Msec);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Fast function to get the most accurate RTC counter value
|
||||
//*****************************************************************************
|
||||
static unsigned long long RTCFastDomainCounterGet (void) {
|
||||
|
||||
#define BRK_IF_RTC_CTRS_ALIGN(c2, c1) if (c2 - c1 <= 1) { \
|
||||
itr++; \
|
||||
break; \
|
||||
}
|
||||
|
||||
unsigned long long rtc_count1, rtc_count2, rtc_count3;
|
||||
unsigned int itr;
|
||||
|
||||
do {
|
||||
rtc_count1 = PRCMSlowClkCtrFastGet();
|
||||
rtc_count2 = PRCMSlowClkCtrFastGet();
|
||||
rtc_count3 = PRCMSlowClkCtrFastGet();
|
||||
itr = 0;
|
||||
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count2, rtc_count1);
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count2);
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count1);
|
||||
|
||||
// Consistent values in two consecutive reads implies a correct
|
||||
// value of the counter. Do note, the counter does not give the
|
||||
// calendar time but a hardware that ticks upwards continuously.
|
||||
// The 48-bit counter operates at 32,768 HZ.
|
||||
|
||||
} while (true);
|
||||
|
||||
return (1 == itr) ? rtc_count2 : rtc_count3;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Macros
|
||||
//*****************************************************************************
|
||||
@@ -254,94 +288,49 @@ static const PRCM_PeriphRegs_t PRCM_PeriphRegsList[] =
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Requests a safe boot
|
||||
//! Set a special bit
|
||||
//!
|
||||
//! \return None.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void PRCMRequestSafeBoot(void)
|
||||
void PRCMSetSpecialBit(unsigned char bit)
|
||||
{
|
||||
unsigned int uiRegValue;
|
||||
|
||||
uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) | (1 << 30);
|
||||
uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) | (1 << bit);
|
||||
|
||||
PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Clear the safe boot request
|
||||
//! Clear a special bit
|
||||
//!
|
||||
//! \return None.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void PRCMClearSafeBootRequest(void)
|
||||
void PRCMClearSpecialBit(unsigned char bit)
|
||||
{
|
||||
unsigned int uiRegValue;
|
||||
|
||||
uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (~(1 << 30));
|
||||
uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (~(1 << bit));
|
||||
|
||||
PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Read the safe boot request bit. This bit is cleared after reading.
|
||||
//! Read a special bit
|
||||
//!
|
||||
//! \return Value of the safe boot bit
|
||||
//! \return Value of the bit
|
||||
//
|
||||
//*****************************************************************************
|
||||
tBoolean PRCMIsSafeBootRequested(void)
|
||||
tBoolean PRCMGetSpecialBit(unsigned char bit)
|
||||
{
|
||||
tBoolean safeboot = (MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (1 << 30)) ? true : false;
|
||||
|
||||
PRCMClearSafeBootRequest();
|
||||
|
||||
return safeboot;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Signals that a WDT reset has occurred
|
||||
//!
|
||||
//! \return None.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void PRCMSignalWDTReset(void)
|
||||
{
|
||||
unsigned int uiRegValue;
|
||||
|
||||
uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) | (1 << 29);
|
||||
|
||||
PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Clear the WDT reset signal
|
||||
//!
|
||||
//! \return None.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void PRCMClearWDTResetSignal(void)
|
||||
{
|
||||
unsigned int uiRegValue;
|
||||
|
||||
uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (~(1 << 29));
|
||||
|
||||
PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Read the WDT reset signal bit
|
||||
//!
|
||||
//! \return Value of the WDT reset signal bit
|
||||
//
|
||||
//*****************************************************************************
|
||||
tBoolean PRCMWasResetBecauseOfWDT(void)
|
||||
{
|
||||
return (MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (1 << 29)) ? true : false;
|
||||
tBoolean value = (MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (1 << bit)) ? true : false;
|
||||
// special bits must be cleared immediatelly after reading
|
||||
PRCMClearSpecialBit(bit);
|
||||
return value;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -1289,6 +1278,35 @@ unsigned long long PRCMSlowClkCtrGet(void)
|
||||
return ullRTCVal;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Gets the current value of the internal slow clock counter
|
||||
//!
|
||||
//! This function is similar to \sa PRCMSlowClkCtrGet() but reads the counter
|
||||
//! value from a relatively faster interface using an auto-latch mechainsm.
|
||||
//!
|
||||
//! \note Due to the nature of implemetation of auto latching, when using this
|
||||
//! API, the recommendation is to read the value thrice and identify the right
|
||||
//! value (as 2 out the 3 read values will always be correct and with a max. of
|
||||
//! 1 LSB change)
|
||||
//!
|
||||
//! \return 64-bit current counter vlaue.
|
||||
//
|
||||
//*****************************************************************************
|
||||
unsigned long long PRCMSlowClkCtrFastGet(void)
|
||||
{
|
||||
unsigned long long ullRTCVal;
|
||||
|
||||
//
|
||||
// Read as 2 32-bit values
|
||||
//
|
||||
ullRTCVal = HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_MSW_1P2);
|
||||
ullRTCVal = ullRTCVal << 32;
|
||||
ullRTCVal |= HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_LSW_1P2);
|
||||
|
||||
return ullRTCVal;
|
||||
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
|
||||
@@ -192,17 +192,21 @@ unsigned char ulRstReg;
|
||||
// PRCM_ADC should never be used in any user code.
|
||||
#define PRCM_ADC 0x000000FF
|
||||
|
||||
//*****************************************************************************
|
||||
// User bits in the PRCM persistent registers
|
||||
//*****************************************************************************
|
||||
#define PRCM_SAFE_BOOT_BIT 30
|
||||
#define PRCM_WDT_RESET_BIT 29
|
||||
#define PRCM_FIRST_BOOT_BIT 28
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// API Function prototypes
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern void PRCMRequestSafeBoot(void);
|
||||
extern void PRCMClearSafeBootRequest(void);
|
||||
extern tBoolean PRCMIsSafeBootRequested(void);
|
||||
extern void PRCMSignalWDTReset(void);
|
||||
extern void PRCMClearWDTResetSignal(void);
|
||||
extern tBoolean PRCMWasResetBecauseOfWDT(void);
|
||||
extern void PRCMSetSpecialBit(unsigned char bit);
|
||||
extern void PRCMClearSpecialBit(unsigned char bit);
|
||||
extern tBoolean PRCMGetSpecialBit(unsigned char bit);
|
||||
extern void PRCMSOCReset(void);
|
||||
extern void PRCMMCUReset(tBoolean bIncludeSubsystem);
|
||||
extern unsigned long PRCMSysResetCauseGet(void);
|
||||
@@ -243,6 +247,7 @@ extern void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc);
|
||||
extern void PRCMHibernateIntervalSet(unsigned long long ullTicks);
|
||||
|
||||
extern unsigned long long PRCMSlowClkCtrGet(void);
|
||||
extern unsigned long long PRCMSlowClkCtrFastGet(void);
|
||||
extern void PRCMSlowClkCtrMatchSet(unsigned long long ullTicks);
|
||||
extern unsigned long long PRCMSlowClkCtrMatchGet(void);
|
||||
|
||||
|
||||
@@ -782,15 +782,9 @@ SPIConfigSetExpClk(unsigned long ulBase,unsigned long ulSPIClk,
|
||||
}
|
||||
|
||||
//
|
||||
// Mask the configurations and set clock divider granularity
|
||||
// to 1 cycle
|
||||
// set clock divider granularity to 1 cycle
|
||||
//
|
||||
ulRegData = (ulRegData & (~(MCSPI_CH0CONF_WL_M |
|
||||
MCSPI_CH0CONF_EPOL |
|
||||
MCSPI_CH0CONF_POL |
|
||||
MCSPI_CH0CONF_PHA |
|
||||
MCSPI_CH0CONF_TURBO ) |
|
||||
MCSPI_CH0CONF_CLKG));
|
||||
ulRegData |= MCSPI_CH0CONF_CLKG;
|
||||
|
||||
//
|
||||
// Get the divider value
|
||||
@@ -798,7 +792,7 @@ SPIConfigSetExpClk(unsigned long ulBase,unsigned long ulSPIClk,
|
||||
ulDivider = ((ulSPIClk/ulBitRate) - 1);
|
||||
|
||||
//
|
||||
// The least significant four bits of the divider is used fo configure
|
||||
// The least significant four bits of the divider is used to configure
|
||||
// CLKD in MCSPI_CHCONF next eight least significant bits are used to
|
||||
// configure the EXTCLK in MCSPI_CHCTRL
|
||||
//
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/mphal.h"
|
||||
#include "mptask.h"
|
||||
#include "simplelink.h"
|
||||
#include "pybwdt.h"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/mphal.h"
|
||||
#include "py/obj.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "pybuart.h"
|
||||
@@ -70,10 +70,7 @@ void vApplicationMallocFailedHook (void)
|
||||
__asm volatile ("bkpt #0 \n");
|
||||
#endif
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
__fatal_error("FreeRTOS malloc failed!");
|
||||
}
|
||||
__fatal_error("FreeRTOS malloc failed!");
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -92,10 +89,7 @@ void vApplicationStackOverflowHook (OsiTaskHandle *pxTask, signed char *pcTaskNa
|
||||
__asm volatile ("bkpt #0 \n");
|
||||
#endif
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
__fatal_error("Stack overflow!");
|
||||
}
|
||||
__fatal_error("Stack overflow!");
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
STATIC const char help_text[] = "Welcome to Micro Python!\n"
|
||||
STATIC const char help_text[] = "Welcome to MicroPython!\n"
|
||||
"For online help please visit http://micropython.org/help/.\n"
|
||||
"For further help on a specific object, type help(obj)\n";
|
||||
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
const mp_arg_t mpcallback_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_wakes, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYB_PWR_MODE_ACTIVE} },
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mpcallback_init0 (void) {
|
||||
// initialize the callback objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mpcallback_obj_list), 0);
|
||||
}
|
||||
|
||||
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods) {
|
||||
mpcallback_obj_t *self = m_new_obj(mpcallback_obj_t);
|
||||
self->base.type = &pyb_callback_type;
|
||||
self->handler = handler;
|
||||
self->parent = parent;
|
||||
self->methods = (mp_cb_methods_t *)methods;
|
||||
self->isenabled = true;
|
||||
// remove any old callback if present
|
||||
mpcallback_remove(self->parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mpcallback_obj_list), self);
|
||||
return self;
|
||||
}
|
||||
|
||||
mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
if (callback_obj->parent == parent) {
|
||||
return callback_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mpcallback_wake_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
if (callback_obj->isenabled) {
|
||||
callback_obj->methods->enable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mpcallback_remove (const mp_obj_t parent) {
|
||||
mpcallback_obj_t *callback_obj;
|
||||
if ((callback_obj = mpcallback_find(parent))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mpcallback_obj_list), callback_obj);
|
||||
}
|
||||
}
|
||||
|
||||
uint mpcallback_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > 7) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
switch (priority) {
|
||||
case 1:
|
||||
return INT_PRIORITY_LVL_7;
|
||||
case 2:
|
||||
return INT_PRIORITY_LVL_6;
|
||||
case 3:
|
||||
return INT_PRIORITY_LVL_5;
|
||||
case 4:
|
||||
return INT_PRIORITY_LVL_4;
|
||||
case 5:
|
||||
return INT_PRIORITY_LVL_3;
|
||||
case 6:
|
||||
return INT_PRIORITY_LVL_2;
|
||||
case 7:
|
||||
return INT_PRIORITY_LVL_1;
|
||||
default:
|
||||
return INT_PRIORITY_LVL_7;
|
||||
}
|
||||
}
|
||||
|
||||
void mpcallback_handler (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
if (self && self->handler != mp_const_none) {
|
||||
// disable interrupts to avoid nesting
|
||||
uint primsk = disable_irq();
|
||||
// when executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations. We must also catch any exceptions.
|
||||
gc_lock();
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_1(self->handler, self->parent);
|
||||
nlr_pop();
|
||||
}
|
||||
else {
|
||||
// uncaught exception; disable the callback so that it doesn't run again
|
||||
self->methods->disable (self->parent);
|
||||
self->handler = mp_const_none;
|
||||
// printing an exception here will cause a stack overflow that will end up in
|
||||
// a hard fault, so is better to signal the uncaught (probably non-recoverable)
|
||||
// exception by blinking the system led instead.
|
||||
mperror_signal_error();
|
||||
}
|
||||
gc_unlock();
|
||||
enable_irq(primsk);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \method init()
|
||||
/// Initializes the interrupt callback. With no parameters passed, everything will default
|
||||
/// to the values assigned to mpcallback_init_args[].
|
||||
STATIC mp_obj_t callback_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mpcallback_obj_t *self = pos_args[0];
|
||||
// this is a bit of a hack, but it let us reuse the callback_create method from our parent
|
||||
((mp_obj_t *)pos_args)[0] = self->parent;
|
||||
self->methods->init (n_args, pos_args, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(callback_init_obj, 1, callback_init);
|
||||
|
||||
/// \method enable()
|
||||
/// Enables the interrupt callback
|
||||
STATIC mp_obj_t callback_enable (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
self->methods->enable(self->parent);
|
||||
self->isenabled = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_enable_obj, callback_enable);
|
||||
|
||||
/// \method disable()
|
||||
/// Disables the interrupt callback
|
||||
STATIC mp_obj_t callback_disable (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
self->methods->disable(self->parent);
|
||||
self->isenabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_disable_obj, callback_disable);
|
||||
|
||||
/// \method \call()
|
||||
/// Triggers the interrupt callback
|
||||
STATIC mp_obj_t callback_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
mpcallback_handler (self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t callback_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&callback_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&callback_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&callback_disable_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(callback_locals_dict, callback_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_callback_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_callback,
|
||||
.call = callback_call,
|
||||
.locals_dict = (mp_obj_t)&callback_locals_dict,
|
||||
};
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "hw_ints.h"
|
||||
#include "hw_types.h"
|
||||
#include "hw_gpio.h"
|
||||
@@ -45,7 +45,6 @@
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
#endif
|
||||
#include "rom.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybuart.h"
|
||||
@@ -56,10 +55,10 @@
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define MPERROR_TOOGLE_MS (40)
|
||||
#define MPERROR_SIGNAL_ERROR_MS (1000)
|
||||
#define MPERROR_TOOGLE_MS (50)
|
||||
#define MPERROR_SIGNAL_ERROR_MS (1200)
|
||||
#define MPERROR_HEARTBEAT_ON_MS (80)
|
||||
#define MPERROR_HEARTBEAT_OFF_MS (4920)
|
||||
#define MPERROR_HEARTBEAT_OFF_MS (3920)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
@@ -94,7 +93,7 @@ void mperror_init0 (void) {
|
||||
MAP_GPIODirModeSet(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, GPIO_DIR_MODE_OUT);
|
||||
#else
|
||||
// configure the system led
|
||||
pin_config ((pin_obj_t *)&MICROPY_SYS_LED_GPIO, PIN_MODE_0, GPIO_DIR_MODE_OUT, PIN_TYPE_STD, PIN_STRENGTH_6MA);
|
||||
pin_config ((pin_obj_t *)&MICROPY_SYS_LED_GPIO, PIN_MODE_0, GPIO_DIR_MODE_OUT, PIN_TYPE_STD, 0, PIN_STRENGTH_6MA);
|
||||
#endif
|
||||
mperror_heart_beat.enabled = true;
|
||||
mperror_heartbeat_switch_off();
|
||||
@@ -115,7 +114,7 @@ void mperror_bootloader_check_reset_cause (void) {
|
||||
|
||||
// since the reset cause will be changed, we must store the right reason
|
||||
// so that the application knows it when booting for the next time
|
||||
PRCMSignalWDTReset();
|
||||
PRCMSetSpecialBit(PRCM_WDT_RESET_BIT);
|
||||
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
// set the sleep interval to 10ms
|
||||
@@ -149,18 +148,14 @@ void mperror_heartbeat_switch_off (void) {
|
||||
void mperror_heartbeat_signal (void) {
|
||||
if (mperror_heart_beat.do_disable) {
|
||||
mperror_heart_beat.do_disable = false;
|
||||
mperror_heartbeat_switch_off();
|
||||
mperror_heart_beat.enabled = false;
|
||||
}
|
||||
else if (mperror_heart_beat.enabled) {
|
||||
} else if (mperror_heart_beat.enabled) {
|
||||
if (!mperror_heart_beat.beating) {
|
||||
if ((mperror_heart_beat.on_time = HAL_GetTick()) - mperror_heart_beat.off_time > MPERROR_HEARTBEAT_OFF_MS) {
|
||||
if ((mperror_heart_beat.on_time = mp_hal_ticks_ms()) - mperror_heart_beat.off_time > MPERROR_HEARTBEAT_OFF_MS) {
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN);
|
||||
mperror_heart_beat.beating = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((mperror_heart_beat.off_time = HAL_GetTick()) - mperror_heart_beat.on_time > MPERROR_HEARTBEAT_ON_MS) {
|
||||
} else {
|
||||
if ((mperror_heart_beat.off_time = mp_hal_ticks_ms()) - mperror_heart_beat.on_time > MPERROR_HEARTBEAT_ON_MS) {
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
|
||||
mperror_heart_beat.beating = false;
|
||||
}
|
||||
@@ -199,48 +194,21 @@ void nlr_jump_fail(void *val) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \classmethod \constructor()
|
||||
///
|
||||
/// Return the heart beat object
|
||||
STATIC mp_obj_t pyb_heartbeat_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// return constant object
|
||||
return (mp_obj_t)&pyb_heartbeat_obj;
|
||||
void mperror_enable_heartbeat (bool enable) {
|
||||
if (enable) {
|
||||
#ifndef BOOTLOADER
|
||||
// configure the led again
|
||||
pin_config ((pin_obj_t *)&MICROPY_SYS_LED_GPIO, PIN_MODE_0, GPIO_DIR_MODE_OUT, PIN_TYPE_STD, 0, PIN_STRENGTH_6MA);
|
||||
#endif
|
||||
mperror_heart_beat.enabled = true;
|
||||
mperror_heart_beat.do_disable = false;
|
||||
mperror_heartbeat_switch_off();
|
||||
} else {
|
||||
mperror_heart_beat.do_disable = true;
|
||||
mperror_heart_beat.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// \function enable()
|
||||
/// Enables the heartbeat signal
|
||||
STATIC mp_obj_t pyb_enable_heartbeat(mp_obj_t self) {
|
||||
mperror_heart_beat.enabled = true;
|
||||
return mp_const_none;
|
||||
bool mperror_is_heartbeat_enabled (void) {
|
||||
return mperror_heart_beat.enabled;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_enable_heartbeat_obj, pyb_enable_heartbeat);
|
||||
|
||||
/// \function disable()
|
||||
/// Disables the heartbeat signal
|
||||
STATIC mp_obj_t pyb_disable_heartbeat(mp_obj_t self) {
|
||||
mperror_heart_beat.do_disable = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_disable_heartbeat_obj, pyb_disable_heartbeat);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_heartbeat_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&pyb_enable_heartbeat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&pyb_disable_heartbeat_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_heartbeat_locals_dict, pyb_heartbeat_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_heartbeat_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_HeartBeat,
|
||||
.make_new = pyb_heartbeat_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_heartbeat_locals_dict,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,5 +40,7 @@ void mperror_deinit_sfe_pin (void);
|
||||
void mperror_signal_error (void);
|
||||
void mperror_heartbeat_switch_off (void);
|
||||
void mperror_heartbeat_signal (void);
|
||||
void mperror_enable_heartbeat (bool enable);
|
||||
bool mperror_is_heartbeat_enabled (void);
|
||||
|
||||
#endif // MPERROR_H_
|
||||
|
||||
201
cc3200/misc/mpirq.c
Normal file
201
cc3200/misc/mpirq.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
#include "mpirq.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
const mp_arg_t mp_irq_init_args[] = {
|
||||
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // the lowest priority
|
||||
{ MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4,
|
||||
INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 };
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mp_irq_init0 (void) {
|
||||
// initialize the callback objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0);
|
||||
}
|
||||
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) {
|
||||
mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t);
|
||||
self->base.type = &mp_irq_type;
|
||||
self->handler = handler;
|
||||
self->parent = parent;
|
||||
self->methods = (mp_irq_methods_t *)methods;
|
||||
self->isenabled = true;
|
||||
// remove it in case it was already registered
|
||||
mp_irq_remove(parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self);
|
||||
return self;
|
||||
}
|
||||
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->parent == parent) {
|
||||
return callback_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mp_irq_wake_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->isenabled) {
|
||||
callback_obj->methods->enable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mp_irq_disable_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
callback_obj->methods->disable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_irq_remove (const mp_obj_t parent) {
|
||||
mp_irq_obj_t *callback_obj;
|
||||
if ((callback_obj = mp_irq_find(parent))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj);
|
||||
}
|
||||
}
|
||||
|
||||
uint mp_irq_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
return mp_irq_priorities[priority - 1];
|
||||
}
|
||||
|
||||
void mp_irq_handler (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
if (self && self->handler != mp_const_none) {
|
||||
// when executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations.
|
||||
gc_lock();
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_1(self->handler, self->parent);
|
||||
nlr_pop();
|
||||
}
|
||||
else {
|
||||
// uncaught exception; disable the callback so that it doesn't run again
|
||||
self->methods->disable (self->parent);
|
||||
self->handler = mp_const_none;
|
||||
// signal the error using the heart beat led and
|
||||
// by printing a message
|
||||
printf("Uncaught exception in callback handler\n");
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
mperror_signal_error();
|
||||
}
|
||||
gc_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
STATIC mp_obj_t mp_irq_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_irq_obj_t *self = pos_args[0];
|
||||
// this is a bit of a hack, but it let us reuse the callback_create method from our parent
|
||||
((mp_obj_t *)pos_args)[0] = self->parent;
|
||||
self->methods->init (n_args, pos_args, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init);
|
||||
|
||||
STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->enable(self->parent);
|
||||
self->isenabled = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable);
|
||||
|
||||
STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->disable(self->parent);
|
||||
self->isenabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_disable);
|
||||
|
||||
STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
return mp_obj_new_int(self->methods->flags(self->parent));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags);
|
||||
|
||||
STATIC mp_obj_t mp_irq_call (mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
mp_irq_handler (self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_irq_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&mp_irq_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&mp_irq_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&mp_irq_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_flags), (mp_obj_t)&mp_irq_flags_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t mp_irq_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_irq,
|
||||
.call = mp_irq_call,
|
||||
.locals_dict = (mp_obj_t)&mp_irq_locals_dict,
|
||||
};
|
||||
|
||||
@@ -24,50 +24,52 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MPCALLBACK_H_
|
||||
#define MPCALLBACK_H_
|
||||
#ifndef MPIRQ_H_
|
||||
#define MPIRQ_H_
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define mpcallback_INIT_NUM_ARGS 5
|
||||
#define mp_irq_INIT_NUM_ARGS 4
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef void (*mp_cb_method_t) (mp_obj_t self);
|
||||
typedef mp_obj_t (*mp_cb_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
typedef mp_obj_t (*mp_irq_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
typedef void (*mp_irq_void_method_t) (mp_obj_t self);
|
||||
typedef int (*mp_irq_int_method_t) (mp_obj_t self);
|
||||
|
||||
typedef struct {
|
||||
mp_cb_init_t init;
|
||||
mp_cb_method_t enable;
|
||||
mp_cb_method_t disable;
|
||||
} mp_cb_methods_t;
|
||||
mp_irq_init_t init;
|
||||
mp_irq_void_method_t enable;
|
||||
mp_irq_void_method_t disable;
|
||||
mp_irq_int_method_t flags;
|
||||
} mp_irq_methods_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t parent;
|
||||
mp_obj_t handler;
|
||||
mp_cb_methods_t *methods;
|
||||
mp_irq_methods_t *methods;
|
||||
bool isenabled;
|
||||
} mpcallback_obj_t;
|
||||
} mp_irq_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
extern const mp_arg_t mpcallback_init_args[];
|
||||
extern const mp_obj_type_t pyb_callback_type;
|
||||
extern const mp_arg_t mp_irq_init_args[];
|
||||
extern const mp_obj_type_t mp_irq_type;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mpcallback_init0 (void);
|
||||
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods);
|
||||
mpcallback_obj_t *mpcallback_find (mp_obj_t parent);
|
||||
void mpcallback_wake_all (void);
|
||||
void mpcallback_remove (const mp_obj_t parent);
|
||||
void mpcallback_handler (mp_obj_t self_in);
|
||||
uint mpcallback_translate_priority (uint priority);
|
||||
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods);
|
||||
void mp_irq_init0 (void);
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods);
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent);
|
||||
void mp_irq_wake_all (void);
|
||||
void mp_irq_disable_all (void);
|
||||
void mp_irq_remove (const mp_obj_t parent);
|
||||
void mp_irq_handler (mp_obj_t self_in);
|
||||
uint mp_irq_translate_priority (uint priority);
|
||||
|
||||
#endif /* MPCALLBACK_H_ */
|
||||
#endif /* MPIRQ_H_ */
|
||||
@@ -26,9 +26,8 @@
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "irq.h"
|
||||
#include "py/mphal.h"
|
||||
#include "mpsystick.h"
|
||||
#include "systick.h"
|
||||
#include "inc/hw_types.h"
|
||||
@@ -41,12 +40,12 @@
|
||||
|
||||
|
||||
bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
|
||||
return HAL_GetTick() - start_tick >= delay_ms;
|
||||
return mp_hal_ticks_ms() - start_tick >= delay_ms;
|
||||
}
|
||||
|
||||
// waits until at least delay_ms milliseconds have passed from the sampling of
|
||||
// startTick. Handles overflow properly. Assumes stc was taken from
|
||||
// HAL_GetTick() some time before calling this function.
|
||||
// mp_hal_ticks_ms() some time before calling this function.
|
||||
void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
|
||||
#ifdef USE_FREERTOS
|
||||
vTaskDelay (delay_ms / portTICK_PERIOD_MS);
|
||||
@@ -59,32 +58,14 @@ void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
|
||||
|
||||
// The SysTick timer counts down at HAL_FCPU_HZ, so we can use that knowledge
|
||||
// to grab a microsecond counter.
|
||||
//
|
||||
// We assume that HAL_GetTick returns milliseconds.
|
||||
// We assume that mp_hal_ticks_ms returns milliseconds.
|
||||
uint32_t sys_tick_get_microseconds(void) {
|
||||
mp_uint_t irq_state = disable_irq();
|
||||
uint32_t counter = SysTickValueGet();
|
||||
uint32_t milliseconds = HAL_GetTick();
|
||||
uint32_t status = (HWREG(NVIC_ST_CTRL));
|
||||
uint32_t milliseconds = mp_hal_ticks_ms();
|
||||
enable_irq(irq_state);
|
||||
|
||||
// It's still possible for the countflag bit to get set if the counter was
|
||||
// reloaded between reading VAL and reading CTRL. With interrupts disabled
|
||||
// it definitely takes less than 50 HCLK cycles between reading VAL and
|
||||
// reading CTRL, so the test (counter > 50) is to cover the case where VAL
|
||||
// is +ve and very close to zero, and the COUNTFLAG bit is also set.
|
||||
if ((status & NVIC_ST_CTRL_COUNT) && counter > 50) {
|
||||
// This means that the HW reloaded VAL between the time we read VAL and the
|
||||
// time we read CTRL, which implies that there is an interrupt pending
|
||||
// to increment the tick counter.
|
||||
milliseconds++;
|
||||
}
|
||||
uint32_t load = (HWREG(NVIC_ST_RELOAD));
|
||||
uint32_t load = SysTickPeriodGet();
|
||||
counter = load - counter; // Convert from decrementing to incrementing
|
||||
|
||||
// ((load + 1) / 1000) is the number of counts per microsecond.
|
||||
//
|
||||
// counter / ((load + 1) / 1000) scales from the systick clock to microseconds
|
||||
// and is the same thing as (counter * 1000) / (load + 1)
|
||||
return milliseconds * 1000 + (counter * 1000) / (load + 1);
|
||||
return (milliseconds * 1000) + ((counter * 1000) / load);
|
||||
}
|
||||
|
||||
217
cc3200/mods/modmachine.c
Normal file
217
cc3200/mods/modmachine.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "irq.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "inc/hw_uart.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybuart.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybrtc.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "moduos.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "portable.h"
|
||||
#include "task.h"
|
||||
#include "mpexception.h"
|
||||
#include "random.h"
|
||||
#include "pybadc.h"
|
||||
#include "pybi2c.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybwdt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybspi.h"
|
||||
#include "pybtimer.h"
|
||||
#include "utils.h"
|
||||
#include "gccollect.h"
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
extern OsiTaskHandle mpTaskHandle;
|
||||
extern OsiTaskHandle svTaskHandle;
|
||||
extern OsiTaskHandle xSimpleLinkSpawnTaskHndl;
|
||||
#endif
|
||||
|
||||
|
||||
/// \module machine - functions related to the SoC
|
||||
///
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings;
|
||||
|
||||
STATIC mp_obj_t machine_reset(void) {
|
||||
// disable wlan
|
||||
wlan_stop(SL_STOP_TIMEOUT_LONG);
|
||||
// reset the cpu and it's peripherals
|
||||
MAP_PRCMMCUReset(true);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
|
||||
#ifdef DEBUG
|
||||
STATIC mp_obj_t machine_info(uint n_args, const mp_obj_t *args) {
|
||||
// FreeRTOS info
|
||||
{
|
||||
printf("---------------------------------------------\n");
|
||||
printf("FreeRTOS\n");
|
||||
printf("---------------------------------------------\n");
|
||||
printf("Total heap: %u\n", configTOTAL_HEAP_SIZE);
|
||||
printf("Free heap: %u\n", xPortGetFreeHeapSize());
|
||||
printf("MpTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)mpTaskHandle));
|
||||
printf("ServersTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)svTaskHandle));
|
||||
printf("SlTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xSimpleLinkSpawnTaskHndl));
|
||||
printf("IdleTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xTaskGetIdleTaskHandle()));
|
||||
|
||||
uint32_t *pstack = (uint32_t *)&_stack;
|
||||
while (*pstack == 0x55555555) {
|
||||
pstack++;
|
||||
}
|
||||
printf("MAIN min free stack: %u\n", pstack - ((uint32_t *)&_stack));
|
||||
printf("---------------------------------------------\n");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t machine_freq(void) {
|
||||
mp_obj_t tuple[1] = {
|
||||
mp_obj_new_int(HAL_FCPU_HZ),
|
||||
};
|
||||
return mp_obj_new_tuple(1, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
|
||||
|
||||
STATIC mp_obj_t machine_unique_id(void) {
|
||||
uint8_t mac[SL_BSSID_LENGTH];
|
||||
wlan_get_mac (mac);
|
||||
return mp_obj_new_bytes(mac, SL_BSSID_LENGTH);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
||||
|
||||
STATIC mp_obj_t machine_main(mp_obj_t main) {
|
||||
if (MP_OBJ_IS_STR(main)) {
|
||||
MP_STATE_PORT(machine_config_main) = main;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(machine_main_obj, machine_main);
|
||||
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
__WFI();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
STATIC mp_obj_t machine_sleep (void) {
|
||||
pyb_sleep_sleep();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
|
||||
|
||||
STATIC mp_obj_t machine_deepsleep (void) {
|
||||
pyb_sleep_deepsleep();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
|
||||
|
||||
STATIC mp_obj_t machine_reset_cause (void) {
|
||||
return mp_obj_new_int(pyb_sleep_get_reset_cause());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
||||
|
||||
STATIC mp_obj_t machine_wake_reason (void) {
|
||||
return mp_obj_new_int(pyb_sleep_get_wake_reason());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_wake_reason_obj, machine_wake_reason);
|
||||
|
||||
STATIC const mp_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_umachine) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&machine_reset_obj },
|
||||
#ifdef DEBUG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&machine_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&machine_unique_id_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&machine_main_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&machine_rng_get_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&machine_idle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&machine_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deepsleep), (mp_obj_t)&machine_deepsleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&machine_reset_cause_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&machine_wake_reason_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sd_type },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t machine_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_umachine,
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
@@ -28,13 +28,29 @@
|
||||
#include <std.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "modnetwork.h"
|
||||
#include "mpexception.h"
|
||||
#include "serverstask.h"
|
||||
#include "simplelink.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
} network_server_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC network_server_obj_t network_server_obj;
|
||||
STATIC const mp_obj_type_t network_server_type;
|
||||
|
||||
/// \module network - network configuration
|
||||
///
|
||||
/// This module provides network drivers and server configuration.
|
||||
@@ -43,48 +59,93 @@ void mod_network_init0(void) {
|
||||
}
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
STATIC mp_obj_t network_server_running(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 0) {
|
||||
// set
|
||||
if (mp_obj_is_true(args[0])) {
|
||||
servers_start();
|
||||
} else {
|
||||
servers_stop();
|
||||
}
|
||||
return mp_const_none;
|
||||
} else {
|
||||
// get
|
||||
return MP_BOOL(servers_are_enabled());
|
||||
STATIC mp_obj_t network_server_init_helper(mp_obj_t self, const mp_arg_val_t *args) {
|
||||
const char *user = SERVERS_DEF_USER;
|
||||
const char *pass = SERVERS_DEF_PASS;
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *login;
|
||||
mp_obj_get_array_fixed_n(args[0].u_obj, 2, &login);
|
||||
user = mp_obj_str_get_str(login[0]);
|
||||
pass = mp_obj_str_get_str(login[1]);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_running_obj, 0, 1, network_server_running);
|
||||
|
||||
STATIC mp_obj_t network_server_login(mp_obj_t user, mp_obj_t pass) {
|
||||
const char *_user = mp_obj_str_get_str(user);
|
||||
const char *_pass = mp_obj_str_get_str(pass);
|
||||
if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
uint32_t timeout = SERVERS_DEF_TIMEOUT_MS / 1000;
|
||||
if (args[1].u_obj != MP_OBJ_NULL) {
|
||||
timeout = mp_obj_get_int(args[1].u_obj);
|
||||
}
|
||||
servers_set_login ((char *)_user, (char *)_pass);
|
||||
|
||||
// configure the new login
|
||||
servers_set_login ((char *)user, (char *)pass);
|
||||
|
||||
// configure the timeout
|
||||
servers_set_timeout(timeout * 1000);
|
||||
|
||||
// start the servers
|
||||
servers_start();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(network_server_login_obj, network_server_login);
|
||||
|
||||
STATIC const mp_arg_t network_server_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_login, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t network_server_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), network_server_args, args);
|
||||
|
||||
// check the server id
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
if (mp_obj_get_int(args[0].u_obj) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
}
|
||||
|
||||
// setup the object and initialize it
|
||||
network_server_obj_t *self = &network_server_obj;
|
||||
self->base.type = &network_server_type;
|
||||
network_server_init_helper(self, &args[1]);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t network_server_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &network_server_args[1], args);
|
||||
return network_server_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_server_init_obj, 1, network_server_init);
|
||||
|
||||
// timeout value given in seconds
|
||||
STATIC mp_obj_t network_server_timeout(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 0) {
|
||||
uint32_t _timeout = mp_obj_get_int(args[0]);
|
||||
if (!servers_set_timeout(_timeout * 1000)) {
|
||||
// timeout is too low
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
if (n_args > 1) {
|
||||
uint32_t timeout = mp_obj_get_int(args[1]);
|
||||
servers_set_timeout(timeout * 1000);
|
||||
return mp_const_none;
|
||||
} else {
|
||||
// get
|
||||
return mp_obj_new_int(servers_get_timeout() / 1000);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 0, 1, network_server_timeout);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 1, 2, network_server_timeout);
|
||||
|
||||
STATIC mp_obj_t network_server_running(mp_obj_t self_in) {
|
||||
// get
|
||||
return mp_obj_new_bool(servers_are_enabled());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_running_obj, network_server_running);
|
||||
|
||||
STATIC mp_obj_t network_server_deinit(mp_obj_t self_in) {
|
||||
// simply stop the servers
|
||||
servers_stop();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_deinit_obj, network_server_deinit);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
|
||||
@@ -92,9 +153,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&mod_network_nic_type_wlan },
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_running), (mp_obj_t)&network_server_running_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_login), (mp_obj_t)&network_server_login_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_timeout), (mp_obj_t)&network_server_timeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Server), (mp_obj_t)&network_server_type },
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -105,3 +164,21 @@ const mp_obj_module_t mp_module_network = {
|
||||
.name = MP_QSTR_network,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
STATIC const mp_map_elem_t network_server_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&network_server_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&network_server_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&network_server_timeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isrunning), (mp_obj_t)&network_server_running_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(network_server_locals_dict, network_server_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t network_server_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Server,
|
||||
.make_new = network_server_make_new,
|
||||
.locals_dict = (mp_obj_t)&network_server_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -40,18 +40,25 @@ typedef struct _mod_network_nic_type_t {
|
||||
mp_obj_type_t base;
|
||||
} mod_network_nic_type_t;
|
||||
|
||||
typedef struct _mod_network_socket_obj_t {
|
||||
mp_obj_base_t base;
|
||||
typedef struct _mod_network_socket_base_t {
|
||||
union {
|
||||
struct {
|
||||
// this order is important so that fileno gets > 0 once
|
||||
// the socket descriptor is assigned after being created.
|
||||
uint8_t domain;
|
||||
int8_t fileno;
|
||||
uint8_t type;
|
||||
uint8_t proto;
|
||||
int8_t fileno;
|
||||
} u_param;
|
||||
int16_t sd;
|
||||
};
|
||||
bool closed;
|
||||
bool has_timeout;
|
||||
bool cert_req;
|
||||
} mod_network_socket_base_t;
|
||||
|
||||
typedef struct _mod_network_socket_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mod_network_socket_base_t sock_base;
|
||||
} mod_network_socket_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "irq.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "inc/hw_uart.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pyexec.h"
|
||||
#include "pybuart.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpsystick.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "moduos.h"
|
||||
#include "telnet.h"
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "portable.h"
|
||||
#include "task.h"
|
||||
#include "mpexception.h"
|
||||
#include "mpcallback.h"
|
||||
#include "random.h"
|
||||
#include "pybadc.h"
|
||||
#include "pybi2c.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybwdt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybspi.h"
|
||||
#include "pybtimer.h"
|
||||
#include "utils.h"
|
||||
#include "gccollect.h"
|
||||
#include "mperror.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
extern OsiTaskHandle mpTaskHandle;
|
||||
extern OsiTaskHandle svTaskHandle;
|
||||
extern OsiTaskHandle xSimpleLinkSpawnTaskHndl;
|
||||
#endif
|
||||
|
||||
|
||||
/// \module pyb - functions related to the pyboard
|
||||
///
|
||||
/// The `pyb` module contains specific functions related to the pyboard.
|
||||
|
||||
/// \function reset()
|
||||
/// Resets the pyboard in a manner similar to pushing the external
|
||||
/// reset button.
|
||||
STATIC mp_obj_t pyb_reset(void) {
|
||||
// disable wlan
|
||||
wlan_stop(SL_STOP_TIMEOUT_LONG);
|
||||
// reset the cpu and it's peripherals
|
||||
MAP_PRCMMCUReset(true);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_reset_obj, pyb_reset);
|
||||
|
||||
#ifdef DEBUG
|
||||
/// \function info([dump_alloc_table])
|
||||
/// Print out some run time info which is helpful duirng development.
|
||||
STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
|
||||
// FreeRTOS info
|
||||
{
|
||||
printf("---------------------------------------------\n");
|
||||
printf("FreeRTOS\n");
|
||||
printf("---------------------------------------------\n");
|
||||
printf("Total heap: %u\n", configTOTAL_HEAP_SIZE);
|
||||
printf("Free heap: %u\n", xPortGetFreeHeapSize());
|
||||
printf("MpTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)mpTaskHandle));
|
||||
printf("ServersTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)svTaskHandle));
|
||||
printf("SlTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xSimpleLinkSpawnTaskHndl));
|
||||
printf("IdleTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xTaskGetIdleTaskHandle()));
|
||||
|
||||
uint32_t *pstack = (uint32_t *)&_stack;
|
||||
while (*pstack == 0x55555555) {
|
||||
pstack++;
|
||||
}
|
||||
printf("MAIN min free stack: %u\n", pstack - ((uint32_t *)&_stack));
|
||||
printf("---------------------------------------------\n");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
|
||||
#endif
|
||||
|
||||
/// \function freq()
|
||||
/// Returns the CPU frequency: (F_CPU).
|
||||
STATIC mp_obj_t pyb_freq(void) {
|
||||
mp_obj_t tuple[1] = {
|
||||
mp_obj_new_int(HAL_FCPU_HZ),
|
||||
};
|
||||
return mp_obj_new_tuple(1, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq);
|
||||
|
||||
/// \function unique_id()
|
||||
/// Returns a string of 6 bytes (48 bits), which is the unique ID for the MCU.
|
||||
STATIC mp_obj_t pyb_unique_id(void) {
|
||||
uint8_t mac[SL_BSSID_LENGTH];
|
||||
wlan_get_mac (mac);
|
||||
return mp_obj_new_bytes(mac, SL_BSSID_LENGTH);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
|
||||
|
||||
/// \function millis()
|
||||
/// Returns the number of milliseconds since the board was last reset.
|
||||
///
|
||||
/// The result is always a micropython smallint (31-bit signed number), so
|
||||
/// after 2^30 milliseconds (about 12.4 days) this will start to return
|
||||
/// negative numbers.
|
||||
STATIC mp_obj_t pyb_millis(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a small-int. This means
|
||||
// copying the MSB down 1 bit (extending the sign down), which is
|
||||
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
|
||||
return MP_OBJ_NEW_SMALL_INT(HAL_GetTick());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis);
|
||||
|
||||
/// \function elapsed_millis(start)
|
||||
/// Returns the number of milliseconds which have elapsed since `start`.
|
||||
///
|
||||
/// This function takes care of counter wrap, and always returns a positive
|
||||
/// number. This means it can be used to measure periods upto about 12.4 days.
|
||||
///
|
||||
/// Example:
|
||||
/// start = pyb.millis()
|
||||
/// while pyb.elapsed_millis(start) < 1000:
|
||||
/// # Perform some operation
|
||||
STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) {
|
||||
uint32_t startMillis = mp_obj_get_int(start);
|
||||
uint32_t currMillis = HAL_GetTick();
|
||||
return MP_OBJ_NEW_SMALL_INT((currMillis - startMillis) & 0x3fffffff);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis);
|
||||
|
||||
/// \function micros()
|
||||
/// Returns the number of microseconds since the board was last reset.
|
||||
///
|
||||
/// The result is always a micropython smallint (31-bit signed number), so
|
||||
/// after 2^30 microseconds (about 17.8 minutes) this will start to return
|
||||
/// negative numbers.
|
||||
STATIC mp_obj_t pyb_micros(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a small-int. This means
|
||||
// copying the MSB down 1 bit (extending the sign down), which is
|
||||
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
|
||||
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_micros_obj, pyb_micros);
|
||||
|
||||
/// \function elapsed_micros(start)
|
||||
/// Returns the number of microseconds which have elapsed since `start`.
|
||||
///
|
||||
/// This function takes care of counter wrap, and always returns a positive
|
||||
/// number. This means it can be used to measure periods upto about 17.8 minutes.
|
||||
///
|
||||
/// Example:
|
||||
/// start = pyb.micros()
|
||||
/// while pyb.elapsed_micros(start) < 1000:
|
||||
/// # Perform some operation
|
||||
STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) {
|
||||
uint32_t startMicros = mp_obj_get_int(start);
|
||||
uint32_t currMicros = sys_tick_get_microseconds();
|
||||
return MP_OBJ_NEW_SMALL_INT((currMicros - startMicros) & 0x3fffffff);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros);
|
||||
|
||||
/// \function delay(ms)
|
||||
/// Delay for the given number of milliseconds.
|
||||
STATIC mp_obj_t pyb_delay(mp_obj_t ms_in) {
|
||||
mp_int_t ms = mp_obj_get_int(ms_in);
|
||||
if (ms > 0) {
|
||||
HAL_Delay(ms);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay);
|
||||
|
||||
/// \function udelay(us)
|
||||
/// Delay for the given number of microseconds.
|
||||
STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) {
|
||||
mp_int_t usec = mp_obj_get_int(usec_in);
|
||||
if (usec > 0) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
|
||||
|
||||
/// \function repl_uart(uart)
|
||||
/// Get or set the UART object that the REPL is repeated on.
|
||||
STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
if (pyb_stdio_uart == NULL) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return pyb_stdio_uart;
|
||||
}
|
||||
} else {
|
||||
if (args[0] == mp_const_none) {
|
||||
pyb_stdio_uart = NULL;
|
||||
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
|
||||
pyb_stdio_uart = args[0];
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
|
||||
|
||||
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&pyb_reset_obj },
|
||||
#ifdef DEBUG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_repl_info), (mp_obj_t)&pyb_set_repl_info_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_millis), (mp_obj_t)&pyb_elapsed_millis_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_micros), (mp_obj_t)&pyb_micros_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_micros), (mp_obj_t)&pyb_elapsed_micros_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&pyb_rng_get_obj },
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ENABLE_RTC
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_type },
|
||||
#endif
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Sleep), (mp_obj_t)&pyb_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HeartBeat), (mp_obj_t)&pyb_heartbeat_type },
|
||||
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sd_type },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);
|
||||
|
||||
const mp_obj_module_t pyb_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_pyb,
|
||||
.globals = (mp_obj_dict_t*)&pyb_module_globals,
|
||||
};
|
||||
@@ -26,7 +26,6 @@
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
@@ -51,6 +50,8 @@ STATIC const mp_map_elem_t mp_module_binascii_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hexlify), (mp_obj_t)&mod_binascii_hexlify_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unhexlify), (mp_obj_t)&mod_binascii_unhexlify_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_a2b_base64), (mp_obj_t)&mod_binascii_a2b_base64_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_b2a_base64), (mp_obj_t)&mod_binascii_b2a_base64_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);
|
||||
|
||||
@@ -28,21 +28,22 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "ff.h"
|
||||
#include "moduos.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "file.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
#include "random.h"
|
||||
#include "sd_diskio.h"
|
||||
#include "mpexception.h"
|
||||
#include "version.h"
|
||||
#include "timeutils.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybuart.h"
|
||||
|
||||
/// \module os - basic "operating system" services
|
||||
///
|
||||
@@ -52,20 +53,161 @@
|
||||
/// drives are accessible from here. They are currently:
|
||||
///
|
||||
/// /flash -- the serial flash filesystem
|
||||
/// /sd -- the SD card (if it exists)
|
||||
///
|
||||
/// On boot up, the current directory is `/flash` if no SD card is inserted,
|
||||
/// otherwise it is `/sd`.
|
||||
/// On boot up, the current directory is `/flash`.
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint32_t os_num_mounted_devices;
|
||||
STATIC os_term_dup_obj_t os_term_dup_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void unmount (os_fs_mount_t *mount_obj);
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical);
|
||||
STATIC void append_dir_item (mp_obj_t dirlist, const char *item, bool string);
|
||||
STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonly);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
void moduos_init0 (void) {
|
||||
// initialize the mount objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mount_obj_list), 0);
|
||||
os_num_mounted_devices = 0;
|
||||
}
|
||||
|
||||
os_fs_mount_t *osmount_find_by_path (const char *path) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (!strcmp(path, mount_obj->path)) {
|
||||
return mount_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_fs_mount_t *osmount_find_by_volume (uint8_t vol) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (vol == mount_obj->vol) {
|
||||
return mount_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_fs_mount_t *osmount_find_by_device (mp_obj_t device) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (device == mount_obj->device) {
|
||||
return mount_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void osmount_unmount_all (void) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
unmount(mount_obj);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC bool sd_in_root(void) {
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
return sd_disk_ready();
|
||||
#else
|
||||
return false;
|
||||
|
||||
// Checks for path equality, ignoring trailing slashes:
|
||||
// path_equal(/, /) -> true
|
||||
// path_equal(/flash//, /flash) -> true
|
||||
// second argument must be in canonical form (meaning no trailing slash, unless it's just /)
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical) {
|
||||
for (; *path_canonical != '\0' && *path == *path_canonical; ++path, ++path_canonical) {
|
||||
}
|
||||
if (*path_canonical != '\0') {
|
||||
return false;
|
||||
}
|
||||
for (; *path == '/'; ++path) {
|
||||
}
|
||||
return *path == '\0';
|
||||
}
|
||||
|
||||
STATIC void append_dir_item (mp_obj_t dirlist, const char *item, bool string) {
|
||||
// make a string object for this entry
|
||||
mp_obj_t entry_o;
|
||||
if (string) {
|
||||
entry_o = mp_obj_new_str(item, strlen(item), false);
|
||||
} else {
|
||||
entry_o = mp_obj_new_bytes((const byte*)item, strlen(item));
|
||||
}
|
||||
|
||||
// add the entry to the list
|
||||
mp_obj_list_append(dirlist, entry_o);
|
||||
}
|
||||
|
||||
STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonly) {
|
||||
// is the mount point already in use?
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
// cannot mount twice or on existing paths
|
||||
if (f_stat(path, &fno) == FR_OK || osmount_find_by_device(device)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
|
||||
// create a new object
|
||||
os_fs_mount_t *self = m_new_obj(os_fs_mount_t);
|
||||
self->device = device;
|
||||
self->path = path;
|
||||
self->pathlen = pathlen;
|
||||
self->vol = os_num_mounted_devices + 1; // '/flash' is volume 0
|
||||
|
||||
if (device == (mp_obj_t)&pybsd_obj) {
|
||||
// need to make it different to NULL, otherwise it's read only by default
|
||||
self->writeblocks[0] = mp_const_none;
|
||||
self->sync[0] = MP_OBJ_NULL; // no need to sync the SD card
|
||||
self->count[0] = MP_OBJ_NULL;
|
||||
} else {
|
||||
// load block protocol methods
|
||||
mp_load_method(device, MP_QSTR_readblocks, self->readblocks);
|
||||
mp_load_method_maybe(device, MP_QSTR_writeblocks, self->writeblocks);
|
||||
mp_load_method_maybe(device, MP_QSTR_sync, self->sync);
|
||||
mp_load_method(device, MP_QSTR_count, self->count);
|
||||
}
|
||||
|
||||
// Read-only device indicated by writeblocks[0] == MP_OBJ_NULL.
|
||||
// User can specify read-only device by:
|
||||
// 1. readonly=True keyword argument
|
||||
// 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already)
|
||||
if (readonly) {
|
||||
self->writeblocks[0] = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
// we need to add it before doing the actual mount, so that the volume can be found
|
||||
mp_obj_list_append(&MP_STATE_PORT(mount_obj_list), self);
|
||||
|
||||
// actually mount it
|
||||
if (f_mount(&self->fatfs, self->path, 1) != FR_OK) {
|
||||
// remove it and raise
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mount_obj_list), self);
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
// mount succeeded, increment the count
|
||||
os_num_mounted_devices++;
|
||||
}
|
||||
|
||||
STATIC void unmount (os_fs_mount_t *mount_obj) {
|
||||
// remove it from the list and then call FatFs
|
||||
f_mount (NULL, mount_obj->path, 1);
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mount_obj_list), mount_obj);
|
||||
os_num_mounted_devices--;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -117,25 +259,20 @@ STATIC mp_obj_t os_chdir(mp_obj_t path_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir);
|
||||
|
||||
/// \function getcwd()
|
||||
/// Get the current directory.
|
||||
STATIC mp_obj_t os_getcwd(void) {
|
||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||
FRESULT res = f_getcwd(buf, sizeof buf);
|
||||
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
|
||||
return mp_obj_new_str(buf, strlen(buf), false);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd);
|
||||
|
||||
/// \function listdir([dir])
|
||||
/// With no argument, list the current directory. Otherwise list the given directory.
|
||||
STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
bool is_str_type = true;
|
||||
const char *path;
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
|
||||
if (n_args == 1) {
|
||||
if (mp_obj_get_type(args[0]) == &mp_type_bytes) {
|
||||
@@ -146,66 +283,51 @@ STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
path = "";
|
||||
}
|
||||
|
||||
// "hack" to list root directory
|
||||
// "hack" to list the root directory
|
||||
if (path[0] == '/' && path[1] == '\0') {
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
mp_obj_list_append(dir_list, MP_OBJ_NEW_QSTR(MP_QSTR_flash));
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
if (sd_in_root()) {
|
||||
mp_obj_list_append(dir_list, MP_OBJ_NEW_QSTR(MP_QSTR_sd));
|
||||
// add 'flash' to the list
|
||||
append_dir_item (dir_list, "flash", is_str_type);
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
append_dir_item (dir_list, &mount_obj->path[1], is_str_type);
|
||||
}
|
||||
#endif
|
||||
return dir_list;
|
||||
}
|
||||
} else {
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
char lfn_buf[_MAX_LFN + 1];
|
||||
fno.lfname = lfn_buf;
|
||||
fno.lfsize = sizeof(lfn_buf);
|
||||
#endif
|
||||
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
char lfn_buf[_MAX_LFN + 1];
|
||||
fno.lfname = lfn_buf;
|
||||
fno.lfsize = sizeof(lfn_buf);
|
||||
#endif
|
||||
|
||||
res = f_opendir(&dir, path); /* Open the directory */
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
|
||||
for (;;) {
|
||||
res = f_readdir(&dir, &fno); /* Read a directory item */
|
||||
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */
|
||||
|
||||
#if _USE_LFN
|
||||
char *fn = *fno.lfname ? fno.lfname : fno.fname;
|
||||
#else
|
||||
char *fn = fno.fname;
|
||||
#endif
|
||||
|
||||
// make a string object for this entry
|
||||
mp_obj_t entry_o;
|
||||
if (is_str_type) {
|
||||
entry_o = mp_obj_new_str(fn, strlen(fn), false);
|
||||
} else {
|
||||
entry_o = mp_obj_new_bytes((const byte*)fn, strlen(fn));
|
||||
res = f_opendir(&dir, path); /* Open the directory */
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
// add the entry to the list
|
||||
mp_obj_list_append(dir_list, entry_o);
|
||||
}
|
||||
for ( ; ; ) {
|
||||
res = f_readdir(&dir, &fno); /* Read a directory item */
|
||||
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */
|
||||
|
||||
f_closedir(&dir);
|
||||
#if _USE_LFN
|
||||
char *fn = *fno.lfname ? fno.lfname : fno.fname;
|
||||
#else
|
||||
char *fn = fno.fname;
|
||||
#endif
|
||||
|
||||
// add the entry to the list
|
||||
append_dir_item (dir_list, fn, is_str_type);
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
return dir_list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
|
||||
|
||||
/// \function mkdir(path)
|
||||
/// Create a new directory.
|
||||
STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
FRESULT res = f_mkdir(path);
|
||||
@@ -221,8 +343,6 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
|
||||
|
||||
/// \function rename(old_path, new_path)
|
||||
/// Rename a file
|
||||
STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) {
|
||||
const char *old_path = mp_obj_str_get_str(path_in);
|
||||
const char *new_path = mp_obj_str_get_str(path_out);
|
||||
@@ -233,12 +353,9 @@ STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) {
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
|
||||
|
||||
/// \function remove(path)
|
||||
/// Remove a file or a directory
|
||||
STATIC mp_obj_t os_remove(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
FRESULT res = f_unlink(path);
|
||||
@@ -251,49 +368,33 @@ STATIC mp_obj_t os_remove(mp_obj_t path_o) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
|
||||
|
||||
// Checks for path equality, ignoring trailing slashes:
|
||||
// path_equal(/, /) -> true
|
||||
// path_equal(/flash//, /flash) -> true
|
||||
// second argument must be in canonical form (meaning no trailing slash, unless it's just /)
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical) {
|
||||
for (; *path_canonical != '\0' && *path == *path_canonical; ++path, ++path_canonical) {
|
||||
}
|
||||
if (*path_canonical != '\0') {
|
||||
return false;
|
||||
}
|
||||
for (; *path == '/'; ++path) {
|
||||
}
|
||||
return *path == '\0';
|
||||
}
|
||||
|
||||
/// \function stat(path)
|
||||
/// Get the status of a file or directory.
|
||||
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FRESULT res;
|
||||
bool isbuilt_in = false;
|
||||
FILINFO fno;
|
||||
FRESULT res;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
|
||||
if (path_equal(path, "/") || path_equal(path, "/flash") || path_equal(path, "/sd")) {
|
||||
// check on the user mounted devices
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (path_equal(path, mount_obj->path)) {
|
||||
isbuilt_in = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (path_equal(path, "/") || path_equal(path, "/flash") || isbuilt_in) {
|
||||
// stat built-in directory
|
||||
if (path[1] == 's' && !sd_in_root()) {
|
||||
// no /sd directory
|
||||
res = FR_NO_PATH;
|
||||
goto error;
|
||||
}
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
} else {
|
||||
res = f_stat(path, &fno);
|
||||
if (res != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
} else if ((res = f_stat(path, &fno)) != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
|
||||
@@ -321,26 +422,16 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
t->items[7] = mp_obj_new_int(seconds); // st_atime
|
||||
t->items[8] = t->items[7]; // st_mtime
|
||||
t->items[9] = t->items[7]; // st_ctime
|
||||
|
||||
return t;
|
||||
|
||||
error:
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
|
||||
|
||||
/// \function sync()
|
||||
/// Sync all filesystems.
|
||||
STATIC mp_obj_t os_sync(void) {
|
||||
sflash_disk_flush();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
/// \function urandom(n)
|
||||
/// Return a bytes object with n random bytes, generated by the hardware
|
||||
/// random number generator.
|
||||
STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
mp_int_t n = mp_obj_get_int(num);
|
||||
vstr_t vstr;
|
||||
@@ -351,19 +442,136 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
|
||||
#endif
|
||||
|
||||
/// \function mkfs('path')
|
||||
/// Formats the selected drive, useful when the filesystem has been damaged beyond repair
|
||||
STATIC mp_obj_t os_mkfs(mp_obj_t path_o) {
|
||||
STATIC mp_obj_t os_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t mount_args[] = {
|
||||
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_obj_t device = pos_args[0];
|
||||
mp_obj_t mount_point = pos_args[1];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(mount_args)];
|
||||
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(mount_args), mount_args, args);
|
||||
|
||||
// get the mount point
|
||||
mp_uint_t pathlen;
|
||||
const char *path_in = mp_obj_str_get_data(mount_point, &pathlen);
|
||||
if (pathlen == 0) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
char *path = m_new(char, pathlen + 1);
|
||||
memcpy(path, path_in, pathlen);
|
||||
path[pathlen] = '\0';
|
||||
|
||||
// "remove" any extra slahes at the end
|
||||
while (path[(pathlen - 1)] == '/') {
|
||||
path[--pathlen] = '\0';
|
||||
}
|
||||
|
||||
// is the mount point valid?
|
||||
if (pathlen < 2 || path[0] !='/' || strchr(&path[1], '/')) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// now mount it
|
||||
mount(device, path, pathlen, args[0].u_bool);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(os_mount_obj, 2, os_mount);
|
||||
|
||||
STATIC mp_obj_t os_unmount(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
if (FR_OK != f_mkfs(path, 1, 0)) {
|
||||
|
||||
// '/flash' cannot be unmounted, also not the current working directory
|
||||
if (path_equal(path, "/flash")) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
|
||||
// now unmount it
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_path(path))) {
|
||||
unmount (mount_obj);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_unmount_obj, os_unmount);
|
||||
|
||||
STATIC mp_obj_t os_mkfs(mp_obj_t device) {
|
||||
const char *path = "/__mkfs__mnt__";
|
||||
os_fs_mount_t *mount_obj = NULL;
|
||||
bool unmt = false;
|
||||
FRESULT res;
|
||||
|
||||
if (MP_OBJ_IS_STR_OR_BYTES(device)) {
|
||||
path = mp_obj_str_get_str(device);
|
||||
// otherwise the relative path check will pass...
|
||||
if (path[0] != '/') {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
} else {
|
||||
// mount it briefly
|
||||
mount(device, path, strlen(path), false);
|
||||
unmt = true;
|
||||
}
|
||||
|
||||
byte sfd = 0;
|
||||
if (!memcmp(path, "/flash", strlen("/flash"))) {
|
||||
sfd = 1;
|
||||
} else if ((mount_obj = osmount_find_by_path(path))) {
|
||||
if (mount_obj->device != (mp_obj_t)&pybsd_obj &&
|
||||
mp_obj_get_int(mp_call_method_n_kw(0, 0, mount_obj->count)) < 2048) {
|
||||
sfd = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// now format the device
|
||||
res = f_mkfs(path, sfd, 0);
|
||||
|
||||
if (unmt && mount_obj) {
|
||||
unmount (mount_obj);
|
||||
}
|
||||
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkfs_obj, os_mkfs);
|
||||
|
||||
STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return MP_STATE_PORT(os_term_dup_obj)->stream_o;
|
||||
}
|
||||
} else {
|
||||
mp_obj_t stream_o = args[0];
|
||||
if (stream_o == mp_const_none) {
|
||||
MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
|
||||
} else {
|
||||
if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) {
|
||||
// must be a stream-like object providing at least read and write methods
|
||||
mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
|
||||
mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
|
||||
}
|
||||
os_term_dup_obj.stream_o = stream_o;
|
||||
MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
|
||||
|
||||
STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
|
||||
|
||||
@@ -374,14 +582,17 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&os_mkdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rename), (mp_obj_t)&os_rename_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&os_remove_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_remove_obj }, // rmdir aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_remove_obj }, // rmdir aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&os_stat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj },
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_urandom), (mp_obj_t)&os_urandom_obj },
|
||||
#endif
|
||||
|
||||
// MicroPython additions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&os_mount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unmount), (mp_obj_t)&os_unmount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&os_mkfs_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dupterm), (mp_obj_t)&os_dupterm_obj },
|
||||
|
||||
/// \constant sep - separation character used in paths
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },
|
||||
|
||||
@@ -28,5 +28,35 @@
|
||||
#ifndef MODUOS_H_
|
||||
#define MODUOS_H_
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _os_fs_mount_t {
|
||||
mp_obj_t device;
|
||||
const char *path;
|
||||
mp_uint_t pathlen;
|
||||
mp_obj_t readblocks[4];
|
||||
mp_obj_t writeblocks[4];
|
||||
mp_obj_t sync[2];
|
||||
mp_obj_t count[2];
|
||||
FATFS fatfs;
|
||||
uint8_t vol;
|
||||
} os_fs_mount_t;
|
||||
|
||||
typedef struct _os_term_dup_obj_t {
|
||||
mp_obj_t stream_o;
|
||||
mp_obj_t read[3];
|
||||
mp_obj_t write[3];
|
||||
} os_term_dup_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void moduos_init0 (void);
|
||||
os_fs_mount_t *osmount_find_by_path (const char *path);
|
||||
os_fs_mount_t *osmount_find_by_volume (uint8_t vol);
|
||||
void osmount_unmount_all (void);
|
||||
|
||||
#endif // MODUOS_H_
|
||||
|
||||
@@ -29,9 +29,11 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "simplelink.h"
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "netutils.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
@@ -54,6 +56,7 @@ typedef struct {
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t socket_type;
|
||||
STATIC OsiLockObj_t modusocket_LockObj;
|
||||
STATIC modusocket_sock_t modusocket_sockets[MOD_NETWORK_MAX_SOCKETS] = {{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1},
|
||||
{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}};
|
||||
@@ -103,8 +106,10 @@ void modusocket_enter_sleep (void) {
|
||||
}
|
||||
}
|
||||
|
||||
// wait for any of the sockets to become ready...
|
||||
sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
|
||||
if (maxfd > 0) {
|
||||
// wait for any of the sockets to become ready...
|
||||
sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void modusocket_close_all_user_sockets (void) {
|
||||
@@ -121,27 +126,28 @@ void modusocket_close_all_user_sockets (void) {
|
||||
/******************************************************************************/
|
||||
// socket class
|
||||
|
||||
STATIC const mp_obj_type_t socket_type;
|
||||
|
||||
// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None)
|
||||
STATIC mp_obj_t socket_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 4, false);
|
||||
|
||||
// create socket object
|
||||
mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
|
||||
s->base.type = (mp_obj_t)&socket_type;
|
||||
s->u_param.domain = AF_INET;
|
||||
s->u_param.type = SOCK_STREAM;
|
||||
s->u_param.proto = IPPROTO_TCP;
|
||||
s->u_param.fileno = -1;
|
||||
s->sock_base.u_param.domain = AF_INET;
|
||||
s->sock_base.u_param.type = SOCK_STREAM;
|
||||
s->sock_base.u_param.proto = IPPROTO_TCP;
|
||||
s->sock_base.u_param.fileno = -1;
|
||||
s->sock_base.has_timeout = false;
|
||||
s->sock_base.cert_req = false;
|
||||
|
||||
if (n_args > 0) {
|
||||
s->u_param.domain = mp_obj_get_int(args[0]);
|
||||
s->sock_base.u_param.domain = mp_obj_get_int(args[0]);
|
||||
if (n_args > 1) {
|
||||
s->u_param.type = mp_obj_get_int(args[1]);
|
||||
s->sock_base.u_param.type = mp_obj_get_int(args[1]);
|
||||
if (n_args > 2) {
|
||||
s->u_param.proto = mp_obj_get_int(args[2]);
|
||||
s->sock_base.u_param.proto = mp_obj_get_int(args[2]);
|
||||
if (n_args > 3) {
|
||||
s->u_param.fileno = mp_obj_get_int(args[3]);
|
||||
s->sock_base.u_param.fileno = mp_obj_get_int(args[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,10 +156,10 @@ STATIC mp_obj_t socket_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_
|
||||
// create the socket
|
||||
int _errno;
|
||||
if (wlan_socket_socket(s, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
|
||||
modusocket_socket_add(s->sd, true);
|
||||
// add the socket to the list
|
||||
modusocket_socket_add(s->sock_base.sd, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -176,23 +182,29 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
// call the NIC to bind the socket
|
||||
int _errno;
|
||||
if (wlan_socket_bind(self, ip, port, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
|
||||
|
||||
// method socket.listen(backlog)
|
||||
STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
// method socket.listen([backlog])
|
||||
STATIC mp_obj_t socket_listen(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mod_network_socket_obj_t *self = args[0];
|
||||
|
||||
int32_t backlog = 0;
|
||||
if (n_args > 1) {
|
||||
backlog = mp_obj_get_int(args[1]);
|
||||
backlog = (backlog < 0) ? 0 : backlog;
|
||||
}
|
||||
|
||||
int _errno;
|
||||
if (wlan_socket_listen(self, mp_obj_get_int(backlog), &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
if (wlan_socket_listen(self, backlog, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
|
||||
|
||||
// method socket.accept()
|
||||
STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
|
||||
@@ -200,18 +212,19 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
|
||||
|
||||
// create new socket object
|
||||
mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
|
||||
socket2->base.type = (mp_obj_t)&socket_type;
|
||||
// the new socket inherits all properties from its parent
|
||||
memcpy (socket2, self, sizeof(mod_network_socket_obj_t));
|
||||
|
||||
// accept incoming connection
|
||||
// accept the incoming connection
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port;
|
||||
int _errno;
|
||||
if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
|
||||
// add the socket to the list
|
||||
modusocket_socket_add(socket2->sd, true);
|
||||
modusocket_socket_add(socket2->sock_base.sd, true);
|
||||
|
||||
// make the return value
|
||||
mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
|
||||
@@ -229,10 +242,13 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
|
||||
|
||||
// call the NIC to connect the socket
|
||||
// connect the socket
|
||||
int _errno;
|
||||
if (wlan_socket_connect(self, ip, port, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) {
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -244,9 +260,9 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
||||
int _errno;
|
||||
mp_uint_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno);
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno);
|
||||
if (ret < 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_obj_new_int_from_uint(ret);
|
||||
}
|
||||
@@ -259,9 +275,12 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, len);
|
||||
int _errno;
|
||||
mp_uint_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno);
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno);
|
||||
if (ret < 0) {
|
||||
if (_errno == EAGAIN && self->sock_base.has_timeout) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out"));
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
if (ret == 0) {
|
||||
return mp_const_empty_bytes;
|
||||
@@ -287,8 +306,8 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
|
||||
// call the nic to sendto
|
||||
int _errno;
|
||||
mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
if (ret < 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_obj_new_int(ret);
|
||||
}
|
||||
@@ -303,8 +322,11 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
mp_uint_t port;
|
||||
int _errno;
|
||||
mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno);
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
if (ret < 0) {
|
||||
if (_errno == EAGAIN && self->sock_base.has_timeout) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out"));
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
mp_obj_t tuple[2];
|
||||
if (ret == 0) {
|
||||
@@ -342,7 +364,7 @@ STATIC mp_obj_t socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
|
||||
int _errno;
|
||||
if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -358,11 +380,11 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
|
||||
if (timeout_in == mp_const_none) {
|
||||
timeout = -1;
|
||||
} else {
|
||||
timeout = 1000 * mp_obj_get_int(timeout_in);
|
||||
timeout = mp_obj_get_int(timeout_in);
|
||||
}
|
||||
int _errno;
|
||||
if (wlan_socket_settimeout(self, timeout, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -378,30 +400,84 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
|
||||
|
||||
STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// TODO: CPython explicitly says that closing the returned object doesn't
|
||||
// close the original socket (Python2 at all says that fd is dup()ed). But
|
||||
// we save on the bloat.
|
||||
mod_network_socket_obj_t *self = args[0];
|
||||
if (n_args > 1) {
|
||||
const char *mode = mp_obj_str_get_str(args[1]);
|
||||
if (strcmp(mode, "rb") && strcmp(mode, "wb")) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
|
||||
|
||||
STATIC const mp_map_elem_t socket_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendall), (mp_obj_t)&socket_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&socket_makefile_obj },
|
||||
|
||||
// stream methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
|
||||
MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
|
||||
|
||||
mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
|
||||
STATIC mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_int_t ret = wlan_socket_recv(self, buf, size, errcode);
|
||||
if (ret < 0) {
|
||||
// we need to ignore the socket closed error here because a readall() or read() without params
|
||||
// only returns when the socket is closed by the other end
|
||||
if (*errcode != SL_ESECCLOSED) {
|
||||
ret = MP_STREAM_ERROR;
|
||||
// needed to convert simplelink's negative error codes to POSIX
|
||||
(*errcode) *= -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_int_t ret = wlan_socket_send(self, buf, size, errcode);
|
||||
if (ret < 0) {
|
||||
ret = MP_STREAM_ERROR;
|
||||
// needed to convert simplelink's negative error codes to POSIX
|
||||
(*errcode) *= -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
return wlan_socket_ioctl(self, request, arg, errcode);
|
||||
}
|
||||
|
||||
STATIC const mp_stream_p_t socket_stream_p = {
|
||||
const mp_stream_p_t socket_stream_p = {
|
||||
.read = socket_read,
|
||||
.write = socket_write,
|
||||
.ioctl = socket_ioctl,
|
||||
.is_text = false,
|
||||
};
|
||||
@@ -427,8 +503,8 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
|
||||
// ipv4 only
|
||||
uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
int32_t result = wlan_gethostbyname(host, hlen, out_ip, AF_INET);
|
||||
if (result != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(result)));
|
||||
if (result < 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-result)));
|
||||
}
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET);
|
||||
@@ -446,18 +522,19 @@ STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&socket_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_usocket_getaddrinfo_obj },
|
||||
|
||||
// class exceptions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_error), (mp_obj_t)&mp_type_OSError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&mp_type_TimeoutError },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_SEC), MP_OBJ_NEW_SMALL_INT(SL_SEC_SOCKET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(IPPROTO_RAW) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#ifndef MODUSOCKET_H_
|
||||
#define MODUSOCKET_H_
|
||||
|
||||
extern const mp_obj_dict_t socket_locals_dict;
|
||||
extern const mp_stream_p_t socket_stream_p;
|
||||
|
||||
extern void modusocket_pre_init (void);
|
||||
extern void modusocket_socket_add (int16_t sd, bool user);
|
||||
extern void modusocket_socket_delete (int16_t sd);
|
||||
|
||||
158
cc3200/mods/modussl.c
Normal file
158
cc3200/mods/modussl.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <std.h>
|
||||
|
||||
#include "simplelink.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modusocket.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define SSL_CERT_NONE (0)
|
||||
#define SSL_CERT_OPTIONAL (1)
|
||||
#define SSL_CERT_REQUIRED (2)
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _mp_obj_ssl_socket_t {
|
||||
mp_obj_base_t base;
|
||||
mod_network_socket_base_t sock_base;
|
||||
mp_obj_t o_sock;
|
||||
} mp_obj_ssl_socket_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t ssl_socket_type;
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings; SSL class
|
||||
|
||||
// ssl sockets inherit from normal socket, so we take its
|
||||
// locals and stream methods
|
||||
STATIC const mp_obj_type_t ssl_socket_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ussl,
|
||||
.getiter = NULL,
|
||||
.iternext = NULL,
|
||||
.stream_p = &socket_stream_p,
|
||||
.locals_dict = (mp_obj_t)&socket_locals_dict,
|
||||
};
|
||||
|
||||
STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_keyfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_certfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SSL_CERT_NONE} },
|
||||
{ MP_QSTR_ca_certs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
// parse arguments
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// chech if ca validation is required
|
||||
if (args[4].u_int != SSL_CERT_NONE && args[5].u_obj == mp_const_none) {
|
||||
goto arg_error;
|
||||
}
|
||||
|
||||
// retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix)
|
||||
const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]);
|
||||
const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]);
|
||||
const char *cafile = (args[5].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
|
||||
NULL : &(mp_obj_str_get_str(args[5].u_obj)[6]);
|
||||
|
||||
// server side requires both certfile and keyfile
|
||||
if (args[3].u_bool && (!keyfile || !certfile)) {
|
||||
goto arg_error;
|
||||
}
|
||||
|
||||
_i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
|
||||
_i16 _errno;
|
||||
_u8 method = SL_SO_SEC_METHOD_TLSV1;
|
||||
if ((_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
if (keyfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, keyfile, strlen(keyfile))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
if (certfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, certfile, strlen(certfile))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
if (cafile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, cafile, strlen(cafile))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
|
||||
// create the ssl socket
|
||||
mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t);
|
||||
// ssl sockets inherit all properties from the original socket
|
||||
memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t));
|
||||
ssl_sock->base.type = &ssl_socket_type;
|
||||
ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false;
|
||||
ssl_sock->o_sock = args[0].u_obj;
|
||||
|
||||
return ssl_sock;
|
||||
|
||||
socket_error:
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
|
||||
arg_error:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_ussl_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ussl) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wrap_socket), (mp_obj_t)&mod_ssl_wrap_socket_obj },
|
||||
|
||||
// class exceptions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SSLError), (mp_obj_t)&mp_type_OSError },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_NONE), MP_OBJ_NEW_SMALL_INT(SSL_CERT_NONE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_OPTIONAL), MP_OBJ_NEW_SMALL_INT(SSL_CERT_OPTIONAL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_REQUIRED), MP_OBJ_NEW_SMALL_INT(SSL_CERT_REQUIRED) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_ussl_globals, mp_module_ussl_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ussl = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ussl,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ussl_globals,
|
||||
};
|
||||
|
||||
@@ -29,28 +29,35 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/smallint.h"
|
||||
#include "py/mphal.h"
|
||||
#include "timeutils.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "systick.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpsystick.h"
|
||||
#include "mpexception.h"
|
||||
#include "utils.h"
|
||||
|
||||
/// \module time - time related functions
|
||||
///
|
||||
/// The `time` module provides functions for getting the current time and date,
|
||||
/// and for sleeping.
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \function localtime([secs])
|
||||
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
|
||||
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
/// If secs is not provided or None, then the current time from the RTC is used.
|
||||
/// year includes the century (for example 2014)
|
||||
/// year includes the century (for example 2015)
|
||||
/// month is 1-12
|
||||
/// mday is 1-31
|
||||
/// hour is 0-23
|
||||
@@ -61,14 +68,9 @@
|
||||
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0 || args[0] == mp_const_none) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
// get the seconds from the RTC
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
@@ -99,11 +101,6 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
|
||||
|
||||
|
||||
/// \function mktime()
|
||||
/// This is inverse function of localtime. It's argument is a full 8-tuple
|
||||
/// which expresses a time as per localtime. It returns an integer which is
|
||||
/// the number of seconds since Jan 1, 2000.
|
||||
STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
mp_uint_t len;
|
||||
mp_obj_t *elem;
|
||||
@@ -115,40 +112,84 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
|
||||
}
|
||||
|
||||
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
|
||||
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
|
||||
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
|
||||
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]),
|
||||
mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
|
||||
|
||||
STATIC mp_obj_t time_time(void) {
|
||||
return mp_obj_new_int(pyb_rtc_get_seconds());
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
|
||||
|
||||
/// \function sleep(milliseconds)
|
||||
/// Sleep for the given number of milliseconds.
|
||||
STATIC mp_obj_t time_sleep(mp_obj_t milliseconds_o) {
|
||||
HAL_Delay(mp_obj_get_int(milliseconds_o));
|
||||
STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
|
||||
int32_t sleep_s = mp_obj_get_int(seconds_o);
|
||||
if (sleep_s > 0) {
|
||||
mp_hal_delay_ms(sleep_s * 1000);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
|
||||
|
||||
/// \function time()
|
||||
/// Returns the number of seconds, as an integer, since 1/1/2000.
|
||||
STATIC mp_obj_t time_time(void) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
return mp_obj_new_int(seconds);
|
||||
STATIC mp_obj_t time_sleep_ms (mp_obj_t ms_in) {
|
||||
mp_int_t ms = mp_obj_get_int(ms_in);
|
||||
if (ms > 0) {
|
||||
mp_hal_delay_ms(ms);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_ms_obj, time_sleep_ms);
|
||||
|
||||
STATIC mp_obj_t time_sleep_us (mp_obj_t usec_in) {
|
||||
mp_int_t usec = mp_obj_get_int(usec_in);
|
||||
if (usec > 0) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_ms(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms);
|
||||
|
||||
STATIC mp_obj_t time_ticks_us(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_cpu(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT((SysTickPeriodGet() - SysTickValueGet()) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu);
|
||||
|
||||
STATIC mp_obj_t time_ticks_diff(mp_obj_t t0, mp_obj_t t1) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
uint32_t start = mp_obj_get_int(t0);
|
||||
uint32_t end = mp_obj_get_int(t1);
|
||||
return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff);
|
||||
|
||||
STATIC const mp_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj },
|
||||
|
||||
// MicroPython additions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&time_ticks_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
|
||||
|
||||
31
cc3200/mods/modwipy.c
Normal file
31
cc3200/mods/modwipy.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "mperror.h"
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
STATIC mp_obj_t mod_wipy_heartbeat (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args) {
|
||||
mperror_enable_heartbeat (mp_obj_is_true(args[0]));
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return mp_obj_new_bool(mperror_is_heartbeat_enabled());
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_wipy_heartbeat_obj, 0, 1, mod_wipy_heartbeat);
|
||||
|
||||
STATIC const mp_map_elem_t wipy_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_wipy) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heartbeat), (mp_obj_t)&mod_wipy_heartbeat_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table);
|
||||
|
||||
const mp_obj_module_t wipy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_wipy,
|
||||
.globals = (mp_obj_dict_t*)&wipy_module_globals,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,10 @@
|
||||
#define SL_STOP_TIMEOUT 35
|
||||
#define SL_STOP_TIMEOUT_LONG 575
|
||||
|
||||
#define MODWLAN_WIFI_EVENT_ANY 0x01
|
||||
|
||||
#define MODWLAN_SSID_LEN_MAX 32
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
@@ -43,7 +47,35 @@ typedef enum {
|
||||
MODWLAN_ERROR_INVALID_PARAMS = -1,
|
||||
MODWLAN_ERROR_TIMEOUT = -2,
|
||||
MODWLAN_ERROR_UNKNOWN = -3,
|
||||
}modwlan_Status_t;
|
||||
} modwlan_Status_t;
|
||||
|
||||
typedef struct _wlan_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t irq_obj;
|
||||
uint32_t status;
|
||||
|
||||
uint32_t ip;
|
||||
|
||||
int8_t mode;
|
||||
uint8_t auth;
|
||||
uint8_t channel;
|
||||
uint8_t antenna;
|
||||
|
||||
// my own ssid, key and mac
|
||||
uint8_t ssid[(MODWLAN_SSID_LEN_MAX + 1)];
|
||||
uint8_t key[65];
|
||||
uint8_t mac[SL_MAC_ADDR_LEN];
|
||||
|
||||
// the sssid (or name) and mac of the other device
|
||||
uint8_t ssid_o[33];
|
||||
uint8_t bssid[6];
|
||||
uint8_t irq_flags;
|
||||
bool irq_enabled;
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
bool servers_enabled;
|
||||
#endif
|
||||
} wlan_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
@@ -54,15 +86,16 @@ extern _SlLockObj_t wlan_LockObj;
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
extern void wlan_pre_init (void);
|
||||
extern modwlan_Status_t wlan_sl_enable (SlWlanMode_t mode, const char *ssid, uint8_t ssid_len, uint8_t sec,
|
||||
const char *key, uint8_t key_len, uint8_t channel);
|
||||
extern void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth, const char *key, uint8_t key_len,
|
||||
uint8_t channel, uint8_t antenna, bool add_mac);
|
||||
extern void wlan_first_start (void);
|
||||
extern void wlan_update(void);
|
||||
extern void wlan_stop (uint32_t timeout);
|
||||
extern void wlan_start (void);
|
||||
extern void wlan_get_mac (uint8_t *macAddress);
|
||||
extern void wlan_get_ip (uint32_t *ip);
|
||||
extern bool wlan_is_connected (void);
|
||||
extern void wlan_set_current_time (uint32_t seconds_since_2000);
|
||||
extern void wlan_off_on (void);
|
||||
|
||||
extern int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family);
|
||||
extern int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno);
|
||||
@@ -75,8 +108,8 @@ extern int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uin
|
||||
extern int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno);
|
||||
extern int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno);
|
||||
extern int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno);
|
||||
extern int wlan_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
|
||||
extern int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_ms, int *_errno);
|
||||
extern int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
|
||||
extern int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno);
|
||||
extern int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno);
|
||||
|
||||
#endif /* MODWLAN_H_ */
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
@@ -52,19 +51,6 @@
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class ADC - analog to digital conversion: read analog values on a pin
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// adc = pyb.ADC(channel) # create an adc object on the given channel (1 to 4)
|
||||
/// this automatically configures the pin associated to
|
||||
/// that analog channel.
|
||||
/// adc.read() # read channel value
|
||||
///
|
||||
/// The sample rate is fixed to 62.5KHz and the resolution to 12 bits.
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE CONSTANTS
|
||||
******************************************************************************/
|
||||
@@ -75,129 +61,176 @@
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
byte channel;
|
||||
byte idx;
|
||||
bool enabled;
|
||||
} pyb_adc_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
pin_obj_t *pin;
|
||||
byte channel;
|
||||
byte id;
|
||||
bool enabled;
|
||||
} pyb_adc_channel_obj_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_adc_channel_obj_t pyb_adc_channel_obj[PYB_ADC_NUM_CHANNELS] = { {.pin = &pin_GP2, .channel = ADC_CH_0, .id = 0, .enabled = false},
|
||||
{.pin = &pin_GP3, .channel = ADC_CH_1, .id = 1, .enabled = false},
|
||||
{.pin = &pin_GP4, .channel = ADC_CH_2, .id = 2, .enabled = false},
|
||||
{.pin = &pin_GP5, .channel = ADC_CH_3, .id = 3, .enabled = false} };
|
||||
STATIC pyb_adc_obj_t pyb_adc_obj = {.enabled = false};
|
||||
|
||||
STATIC const mp_obj_type_t pyb_adc_channel_type;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pybadc_init (pyb_adc_obj_t *self) {
|
||||
// enable the ADC channel
|
||||
MAP_ADCChannelEnable(ADC_BASE, self->channel);
|
||||
STATIC void pyb_adc_init (pyb_adc_obj_t *self) {
|
||||
// enable and configure the timer
|
||||
MAP_ADCTimerConfig(ADC_BASE, (1 << 17) - 1);
|
||||
MAP_ADCTimerEnable(ADC_BASE);
|
||||
// enable the ADC peripheral
|
||||
MAP_ADCEnable(ADC_BASE);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_adc_obj_t pyb_adc_obj[PYB_ADC_NUM_CHANNELS];
|
||||
STATIC void pyb_adc_check_init(void) {
|
||||
// not initialized
|
||||
if (!pyb_adc_obj.enabled) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_adc_channel_init (pyb_adc_channel_obj_t *self) {
|
||||
// the ADC block must be enabled first
|
||||
pyb_adc_check_init();
|
||||
// configure the pin in analog mode
|
||||
pin_config (self->pin, -1, PIN_TYPE_ANALOG, PIN_TYPE_STD, -1, PIN_STRENGTH_2MA);
|
||||
// enable the ADC channel
|
||||
MAP_ADCChannelEnable(ADC_BASE, self->channel);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_adc_deinit_all_channels (void) {
|
||||
for (int i = 0; i < PYB_ADC_NUM_CHANNELS; i++) {
|
||||
adc_channel_deinit(&pyb_adc_channel_obj[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Micro Python bindings : adc object */
|
||||
|
||||
STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_adc_obj_t *self = self_in;
|
||||
mp_printf(print, "<ADC, channel=%u>", (self->idx + 1));
|
||||
if (self->enabled) {
|
||||
mp_printf(print, "ADC(0, bits=12)");
|
||||
} else {
|
||||
mp_printf(print, "ADC(0)");
|
||||
}
|
||||
}
|
||||
|
||||
/// \classmethod \constructor(channel)
|
||||
/// Create an ADC object associated with the given channel.
|
||||
/// This allows you to then read analog values on that pin.
|
||||
STATIC mp_obj_t adc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check number of arguments
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
STATIC const mp_arg_t pyb_adc_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 12} },
|
||||
};
|
||||
STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_adc_init_args, args);
|
||||
|
||||
// the first argument is the channel number
|
||||
int32_t idx = mp_obj_get_int(args[0]) - 1;
|
||||
const pin_obj_t *pin;
|
||||
uint channel;
|
||||
switch (idx) {
|
||||
case 0:
|
||||
channel = ADC_CH_0;
|
||||
pin = &pin_GPIO2;
|
||||
break;
|
||||
case 1:
|
||||
channel = ADC_CH_1;
|
||||
pin = &pin_GPIO3;
|
||||
break;
|
||||
case 2:
|
||||
channel = ADC_CH_2;
|
||||
pin = &pin_GPIO4;
|
||||
break;
|
||||
case 3:
|
||||
channel = ADC_CH_3;
|
||||
pin = &pin_GPIO5;
|
||||
break;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
break;
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// disable the callback before re-configuring
|
||||
pyb_adc_obj_t *self = &pyb_adc_obj[idx];
|
||||
// check the number of bits
|
||||
if (args[1].u_int != 12) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_adc_obj_t *self = &pyb_adc_obj;
|
||||
self->base.type = &pyb_adc_type;
|
||||
self->channel = channel;
|
||||
self->idx = idx;
|
||||
|
||||
// configure the pin in analog mode
|
||||
pin_config ((pin_obj_t *)pin, PIN_MODE_0, GPIO_DIR_MODE_IN, PYBPIN_ANALOG_TYPE, PIN_STRENGTH_2MA);
|
||||
|
||||
// initialize it
|
||||
pybadc_init (self);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pybadc_init);
|
||||
|
||||
// initialize and register with the sleep module
|
||||
pyb_adc_init(self);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// \method read()
|
||||
/// Read the value on the analog pin and return it. The returned value
|
||||
/// will be between 0 and 4095.
|
||||
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
|
||||
pyb_adc_obj_t *self = self_in;
|
||||
uint32_t sample;
|
||||
|
||||
// wait until a new value is available
|
||||
while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel));
|
||||
// read the sample
|
||||
sample = MAP_ADCFIFORead(ADC_BASE, self->channel);
|
||||
// the 12 bit sampled value is stored in bits [13:2]
|
||||
return MP_OBJ_NEW_SMALL_INT((sample & 0x3FFF) >> 2);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
|
||||
|
||||
/// \method enable()
|
||||
/// Enable the adc channel
|
||||
STATIC mp_obj_t adc_enable(mp_obj_t self_in) {
|
||||
pyb_adc_obj_t *self = self_in;
|
||||
|
||||
pybadc_init(self);
|
||||
STATIC mp_obj_t adc_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args);
|
||||
// check the number of bits
|
||||
if (args[0].u_int != 12) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
pyb_adc_init(pos_args[0]);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_enable_obj, adc_enable);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_init_obj, 1, adc_init);
|
||||
|
||||
/// \method disable()
|
||||
/// Disable the adc channel
|
||||
STATIC mp_obj_t adc_disable(mp_obj_t self_in) {
|
||||
STATIC mp_obj_t adc_deinit(mp_obj_t self_in) {
|
||||
pyb_adc_obj_t *self = self_in;
|
||||
|
||||
MAP_ADCChannelDisable(ADC_BASE, self->channel);
|
||||
// first deinit all channels
|
||||
pyb_adc_deinit_all_channels();
|
||||
MAP_ADCDisable(ADC_BASE);
|
||||
self->enabled = false;
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove ((const mp_obj_t)self);
|
||||
pyb_sleep_remove ((const mp_obj_t)self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_disable_obj, adc_disable);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit);
|
||||
|
||||
STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_adc_channel_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_channel_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args);
|
||||
|
||||
uint ch_id;
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
ch_id = mp_obj_get_int(args[0].u_obj);
|
||||
if (ch_id >= PYB_ADC_NUM_CHANNELS) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_os_resource_not_avaliable));
|
||||
} else if (args[1].u_obj != mp_const_none) {
|
||||
uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
|
||||
if (ch_id != pin_ch_id) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_adc_channel_obj_t *self = &pyb_adc_channel_obj[ch_id];
|
||||
self->base.type = &pyb_adc_channel_type;
|
||||
pyb_adc_channel_init (self);
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
|
||||
return self;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel);
|
||||
|
||||
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&adc_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&adc_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&adc_channel_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
|
||||
@@ -210,3 +243,69 @@ const mp_obj_type_t pyb_adc_type = {
|
||||
.locals_dict = (mp_obj_t)&adc_locals_dict,
|
||||
};
|
||||
|
||||
STATIC void adc_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
if (self->enabled) {
|
||||
mp_printf(print, "ADCChannel(%u, pin=%q)", self->id, self->pin->name);
|
||||
} else {
|
||||
mp_printf(print, "ADCChannel(%u)", self->id);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t adc_channel_init(mp_obj_t self_in) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
// re-enable it
|
||||
pyb_adc_channel_init(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_init_obj, adc_channel_init);
|
||||
|
||||
STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
|
||||
MAP_ADCChannelDisable(ADC_BASE, self->channel);
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove ((const mp_obj_t)self);
|
||||
self->enabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_deinit_obj, adc_channel_deinit);
|
||||
|
||||
STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
uint32_t value;
|
||||
|
||||
// the channel must be enabled
|
||||
if (!self->enabled) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
|
||||
// wait until a new value is available
|
||||
while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel));
|
||||
// read the sample
|
||||
value = MAP_ADCFIFORead(ADC_BASE, self->channel);
|
||||
// the 12 bit sampled value is stored in bits [13:2]
|
||||
return MP_OBJ_NEW_SMALL_INT((value & 0x3FFF) >> 2);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_value_obj, adc_channel_value);
|
||||
|
||||
STATIC mp_obj_t adc_channel_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
return adc_channel_value (self_in);
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t adc_channel_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_channel_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_channel_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&adc_channel_value_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_channel_locals_dict, adc_channel_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pyb_adc_channel_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADCChannel,
|
||||
.print = adc_channel_print,
|
||||
.call = adc_channel_call,
|
||||
.locals_dict = (mp_obj_t)&adc_channel_locals_dict,
|
||||
};
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "bufhelper.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_i2c.h"
|
||||
@@ -44,50 +44,11 @@
|
||||
#include "mpexception.h"
|
||||
#include "pybsleep.h"
|
||||
#include "utils.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class I2C - a two-wire serial protocol
|
||||
///
|
||||
/// I2C is a two-wire protocol for communicating between devices. At the physical
|
||||
/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
|
||||
///
|
||||
/// I2C objects are created attached to a specific bus. They can be initialised
|
||||
/// when created, or initialised later on:
|
||||
///
|
||||
/// from pyb import I2C
|
||||
///
|
||||
/// i2c = I2C(1) # create
|
||||
/// i2c = I2C(1, I2C.MASTER, baudrate=50000) # create and init with a 50KHz baudrate
|
||||
/// i2c.init(I2C.MASTER, baudrate=100000) # init with a 100KHz baudrate
|
||||
/// i2c.deinit() # turn off the peripheral
|
||||
///
|
||||
/// Printing the i2c object gives you information about its configuration.
|
||||
///
|
||||
/// Basic methods for slave are send and recv:
|
||||
///
|
||||
/// i2c.send('abc') # send 3 bytes
|
||||
/// i2c.send(0x42) # send a single byte, given by the number
|
||||
/// data = i2c.recv(3) # receive 3 bytes
|
||||
///
|
||||
/// To receive inplace, first create a bytearray:
|
||||
///
|
||||
/// data = bytearray(3) # create a buffer
|
||||
/// i2c.recv(data) # receive 3 bytes, writing them into data
|
||||
///
|
||||
/// A master must specify the recipient's address:
|
||||
///
|
||||
/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
|
||||
/// i2c.send(b'456', addr=0x42) # keyword for address
|
||||
///
|
||||
/// Master also has other methods:
|
||||
///
|
||||
/// i2c.is_ready(0x42) # check if slave 0x42 is ready
|
||||
/// i2c.scan() # scan for slaves on the bus, returning
|
||||
/// # a list of valid addresses
|
||||
/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
|
||||
/// # starting at address 2 in the slave
|
||||
/// i2c.mem_write('abc', 0x42, 2) # write 3 bytes to memory of slave 0x42,
|
||||
/// # starting at address 2 in the slave
|
||||
|
||||
typedef struct _pyb_i2c_obj_t {
|
||||
mp_obj_base_t base;
|
||||
@@ -102,7 +63,7 @@ typedef struct _pyb_i2c_obj_t {
|
||||
#define PYBI2C_MIN_BAUD_RATE_HZ (50000)
|
||||
#define PYBI2C_MAX_BAUD_RATE_HZ (400000)
|
||||
|
||||
#define PYBI2C_TRANSC_TIMEOUT_MS (10)
|
||||
#define PYBI2C_TRANSC_TIMEOUT_MS (20)
|
||||
#define PYBI2C_TRANSAC_WAIT_DELAY_US (10)
|
||||
|
||||
#define PYBI2C_TIMEOUT_TO_COUNT(to_us, baud) (((baud) * to_us) / 16000000)
|
||||
@@ -117,6 +78,12 @@ typedef struct _pyb_i2c_obj_t {
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_i2c_obj_t pyb_i2c_obj = {.baudrate = 0};
|
||||
STATIC const mp_obj_t pyb_i2c_def_pin[2] = {&pin_GP13, &pin_GP23};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
@@ -144,13 +111,13 @@ STATIC bool pyb_i2c_transaction(uint cmd) {
|
||||
// Wait until the current byte has been transferred.
|
||||
// Poll on the raw interrupt status.
|
||||
while ((MAP_I2CMasterIntStatusEx(I2CA0_BASE, false) & (I2C_MASTER_INT_DATA | I2C_MASTER_INT_TIMEOUT)) == 0) {
|
||||
// wait for a few microseconds
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBI2C_TRANSAC_WAIT_DELAY_US));
|
||||
timeout -= PYBI2C_TRANSAC_WAIT_DELAY_US;
|
||||
if (timeout < 0) {
|
||||
// the peripheral is not responding, so stop
|
||||
return false;
|
||||
}
|
||||
// wait for a few microseconds
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBI2C_TRANSAC_WAIT_DELAY_US));
|
||||
timeout -= PYBI2C_TRANSAC_WAIT_DELAY_US;
|
||||
}
|
||||
|
||||
// Check for any errors in the transfer
|
||||
@@ -174,9 +141,69 @@ STATIC bool pyb_i2c_transaction(uint cmd) {
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_write(byte devAddr, byte *data, uint len, bool stop) {
|
||||
STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) {
|
||||
// not initialized
|
||||
if (!self->baudrate) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_scan_device(byte devAddr) {
|
||||
bool ret = false;
|
||||
// Set the I2C slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, true);
|
||||
// Initiate the transfer.
|
||||
if (pyb_i2c_transaction(I2C_MASTER_CMD_SINGLE_RECEIVE)) {
|
||||
ret = true;
|
||||
}
|
||||
// Send the stop bit to cancel the read transaction
|
||||
MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
|
||||
if (!ret) {
|
||||
uint8_t data = 0;
|
||||
if (pyb_i2c_write(devAddr, &data, sizeof(data), true)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_mem_addr_write (byte addr, byte *mem_addr, uint mem_addr_len) {
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, false);
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, false);
|
||||
// Write the first byte to the controller.
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *mem_addr++);
|
||||
// Initiate the transfer.
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_START));
|
||||
|
||||
// Loop until the completion of transfer or error
|
||||
while (--mem_addr_len) {
|
||||
// Write the next byte of data
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *mem_addr++);
|
||||
// Transact over I2C to send the next byte
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_mem_write (byte addr, byte *mem_addr, uint mem_addr_len, byte *data, uint data_len) {
|
||||
if (pyb_i2c_mem_addr_write (addr, mem_addr, mem_addr_len)) {
|
||||
// Loop until the completion of transfer or error
|
||||
while (data_len--) {
|
||||
// Write the next byte of data
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *data++);
|
||||
// Transact over I2C to send the byte
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT));
|
||||
}
|
||||
// send the stop bit
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_STOP));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop) {
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, false);
|
||||
// Write the first byte to the controller.
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *data++);
|
||||
// Initiate the transfer.
|
||||
@@ -190,34 +217,20 @@ STATIC bool pyb_i2c_write(byte devAddr, byte *data, uint len, bool stop) {
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT));
|
||||
}
|
||||
|
||||
// If a stop bit is to be sent, send it.
|
||||
// If a stop bit is to be sent, do it.
|
||||
if (stop) {
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_STOP));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_read(byte devAddr, byte *data, uint len) {
|
||||
uint cmd;
|
||||
|
||||
STATIC bool pyb_i2c_read(byte addr, byte *data, uint len) {
|
||||
// Initiate a burst or single receive sequence
|
||||
uint cmd = --len > 0 ? I2C_MASTER_CMD_BURST_RECEIVE_START : I2C_MASTER_CMD_SINGLE_RECEIVE;
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, true);
|
||||
|
||||
// Check if its a single receive or burst receive
|
||||
if (len > 1) {
|
||||
// Initiate a burst receive sequence
|
||||
cmd = I2C_MASTER_CMD_BURST_RECEIVE_START;
|
||||
}
|
||||
else {
|
||||
// Configure for a single receive
|
||||
cmd = I2C_MASTER_CMD_SINGLE_RECEIVE;
|
||||
}
|
||||
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, true);
|
||||
// Initiate the transfer.
|
||||
RET_IF_ERR(pyb_i2c_transaction(cmd));
|
||||
// Decrement the count
|
||||
len--;
|
||||
// Loop until the completion of reception or error
|
||||
while (len) {
|
||||
// Receive the byte over I2C
|
||||
@@ -225,8 +238,7 @@ STATIC bool pyb_i2c_read(byte devAddr, byte *data, uint len) {
|
||||
if (--len) {
|
||||
// Continue with reception
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_RECEIVE_CONT));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Complete the last reception
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_RECEIVE_FINISH));
|
||||
}
|
||||
@@ -234,19 +246,38 @@ STATIC bool pyb_i2c_read(byte devAddr, byte *data, uint len) {
|
||||
|
||||
// Receive the last byte over I2C
|
||||
*data = MAP_I2CMasterDataGet(I2CA0_BASE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_scan_device(byte devAddr) {
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, true);
|
||||
// Initiate the transfer.
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_SINGLE_RECEIVE));
|
||||
// Since this is a hack, send the stop bit anyway
|
||||
MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
|
||||
STATIC void pyb_i2c_read_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
// get the buffer to receive into
|
||||
pyb_buf_get_for_recv(args[1].u_obj, vstr);
|
||||
|
||||
return true;
|
||||
// receive the data
|
||||
if (!pyb_i2c_read(args[0].u_int, (byte *)vstr->buf, vstr->len)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
// get the buffer to receive into
|
||||
pyb_buf_get_for_recv(args[2].u_obj, vstr);
|
||||
|
||||
// get the addresses
|
||||
mp_uint_t i2c_addr = args[0].u_int;
|
||||
mp_uint_t mem_addr = args[1].u_int;
|
||||
// determine the width of mem_addr (1 or 2 bytes)
|
||||
mp_uint_t mem_addr_size = args[3].u_int >> 3;
|
||||
|
||||
// write the register address to be read from
|
||||
if (pyb_i2c_mem_addr_write (i2c_addr, (byte *)&mem_addr, mem_addr_size)) {
|
||||
// Read the specified length of data
|
||||
if (!pyb_i2c_read (i2c_addr, (byte *)vstr->buf, vstr->len)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -255,79 +286,82 @@ STATIC bool pyb_i2c_scan_device(byte devAddr) {
|
||||
STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_i2c_obj_t *self = self_in;
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "<I2C1, I2C.MASTER, baudrate=%u>)", self->baudrate);
|
||||
}
|
||||
else {
|
||||
mp_print_str(print, "<I2C1>");
|
||||
mp_printf(print, "I2C(0, I2C.MASTER, baudrate=%u)", self->baudrate);
|
||||
} else {
|
||||
mp_print_str(print, "I2C(0)");
|
||||
}
|
||||
}
|
||||
|
||||
/// \method init(mode, *, baudrate=100000)
|
||||
///
|
||||
/// Initialise the I2C bus with the given parameters:
|
||||
///
|
||||
/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE`
|
||||
/// - `baudrate` is the SCL clock rate (only sensible for a master)
|
||||
STATIC const mp_arg_t pyb_i2c_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
};
|
||||
#define PYB_I2C_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_init_args)
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t vals[PYB_I2C_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args, args, kw_args, PYB_I2C_INIT_NUM_ARGS, pyb_i2c_init_args, vals);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *args) {
|
||||
// verify that mode is master
|
||||
if (vals[0].u_int != PYBI2C_MASTER) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
if (args[0].u_int != PYBI2C_MASTER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// make sure the baudrate is between the valid range
|
||||
self->baudrate = MIN(MAX(vals[1].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
self->baudrate = MIN(MAX(args[1].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[2].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_i2c_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, 2, &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
}
|
||||
|
||||
// init the I2C bus
|
||||
i2c_init(self);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
/// \classmethod \constructor(bus, ...)
|
||||
///
|
||||
/// Construct an I2C object on the given bus. `bus` can only be 1.
|
||||
/// With no additional parameters, the I2C object is created but not
|
||||
/// initialised (it has the settings from the last initialisation of
|
||||
/// the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
/// See `init` for parameters of initialisation.
|
||||
STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
STATIC const mp_arg_t pyb_i2c_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = PYBI2C_MASTER} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_i2c_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_i2c_obj_t *self = &pyb_i2c_obj;
|
||||
self->base.type = &pyb_i2c_type;
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// start the peripheral
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_i2c_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
// start the peripheral
|
||||
pyb_i2c_init_helper(self, &args[1]);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
STATIC mp_obj_t pyb_i2c_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_i2c_init_args[1], args);
|
||||
return pyb_i2c_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init);
|
||||
|
||||
/// \method deinit()
|
||||
/// Turn off the I2C bus.
|
||||
STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
|
||||
// disable the peripheral
|
||||
MAP_I2CMasterDisable(I2CA0_BASE);
|
||||
@@ -335,221 +369,169 @@ STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
|
||||
// invalidate the baudrate
|
||||
pyb_i2c_obj.baudrate = 0;
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove ((const mp_obj_t)self_in);
|
||||
pyb_sleep_remove ((const mp_obj_t)self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
|
||||
|
||||
/// \method is_ready(addr)
|
||||
/// Check if an I2C device responds to the given address. Only valid when in master mode.
|
||||
STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
|
||||
mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (pyb_i2c_scan_device(i2c_addr)) {
|
||||
return mp_const_true;
|
||||
}
|
||||
}
|
||||
return mp_const_false;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
|
||||
|
||||
/// \method scan()
|
||||
/// Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
|
||||
/// Only valid when in master mode.
|
||||
STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
mp_obj_t list = mp_obj_new_list(0, NULL);
|
||||
for (uint addr = 1; addr <= 127; addr++) {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pyb_i2c_scan_device(addr)) {
|
||||
mp_obj_list_append(list, mp_obj_new_int(addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
|
||||
|
||||
/// \method send(send, addr=0x00)
|
||||
/// Send data on the bus:
|
||||
///
|
||||
/// - `send` is the data to send (an integer to send, or a buffer object)
|
||||
/// - `addr` is the address to send to (only required in master mode)
|
||||
/// Return value: `None`.
|
||||
STATIC const mp_arg_t pyb_i2c_send_args[] = {
|
||||
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addr, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
#define PYB_I2C_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_send_args)
|
||||
STATIC mp_obj_t pyb_i2c_readfrom(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t vals[PYB_I2C_SEND_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_SEND_NUM_ARGS, pyb_i2c_send_args, vals);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_args, args);
|
||||
|
||||
vstr_t vstr;
|
||||
pyb_i2c_read_into(args, &vstr);
|
||||
|
||||
// return the received data
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_obj, 3, pyb_i2c_readfrom);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_into_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_into_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_into_args, args);
|
||||
|
||||
vstr_t vstr;
|
||||
pyb_i2c_read_into(args, &vstr);
|
||||
|
||||
// return the number of bytes received
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 1, pyb_i2c_readfrom_into);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_writeto_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_writeto_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_writeto_args, args);
|
||||
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
|
||||
// get the buffer to send from
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint8_t data[1];
|
||||
pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
|
||||
pyb_buf_get_for_send(args[1].u_obj, &bufinfo, data);
|
||||
|
||||
// send the data
|
||||
if (!pyb_i2c_write(vals[1].u_int, bufinfo.buf, bufinfo.len, true)) {
|
||||
if (!pyb_i2c_write(args[0].u_int, bufinfo.buf, bufinfo.len, args[2].u_bool)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto);
|
||||
|
||||
/// \method recv(recv, addr=0x00)
|
||||
///
|
||||
/// Receive data on the bus:
|
||||
///
|
||||
/// - `recv` can be an integer, which is the number of bytes to receive,
|
||||
/// or a mutable buffer, which will be filled with received bytes
|
||||
/// - `addr` is the address to receive from (only required in master mode)
|
||||
///
|
||||
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
|
||||
/// otherwise the same buffer that was passed in to `recv`.
|
||||
STATIC const mp_arg_t pyb_i2c_recv_args[] = {
|
||||
{ MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addr, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
#define PYB_I2C_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_recv_args)
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_mem_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t vals[PYB_I2C_RECV_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_RECV_NUM_ARGS, pyb_i2c_recv_args, vals);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_mem_args, args);
|
||||
|
||||
// get the buffer to receive into
|
||||
vstr_t vstr;
|
||||
mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
|
||||
|
||||
// receive the data
|
||||
if (!pyb_i2c_read(vals[1].u_int, (byte *)vstr.buf, vstr.len)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
// return the received data
|
||||
if (o_ret != MP_OBJ_NULL) {
|
||||
return o_ret;
|
||||
}
|
||||
else {
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 1, pyb_i2c_readfrom_mem);
|
||||
|
||||
/// \method mem_read(data, addr, memaddr, addr_size=8)
|
||||
///
|
||||
/// Read from the memory of an I2C device:
|
||||
///
|
||||
/// - `data` can be an integer or a buffer to read into
|
||||
/// - `addr` is the I2C device address
|
||||
/// - `memaddr` is the memory location within the I2C device
|
||||
/// - `addr_size` selects the width of memaddr: 8 or 16 bits
|
||||
///
|
||||
/// Returns the read data.
|
||||
/// This is only valid in master mode.
|
||||
STATIC const mp_arg_t pyb_i2c_mem_read_args[] = {
|
||||
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_addr_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_mem_into_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
};
|
||||
#define PYB_I2C_MEM_READ_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_mem_read_args)
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_mem_read(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_mem_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t vals[PYB_I2C_MEM_READ_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_MEM_READ_NUM_ARGS, pyb_i2c_mem_read_args, vals);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_mem_into_args, args);
|
||||
|
||||
// get the buffer to read into
|
||||
vstr_t vstr;
|
||||
mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
|
||||
|
||||
// get the addresses
|
||||
mp_uint_t i2c_addr = vals[1].u_int;
|
||||
mp_uint_t mem_addr = vals[2].u_int;
|
||||
// determine the width of mem_addr (1 or 2 bytes)
|
||||
mp_uint_t mem_addr_size = vals[3].u_int >> 3;
|
||||
|
||||
// Write the register address to be read from.
|
||||
if (pyb_i2c_write (i2c_addr, (byte *)&mem_addr, mem_addr_size, false)) {
|
||||
// Read the specified length of data
|
||||
if (pyb_i2c_read (i2c_addr, (byte *)vstr.buf, vstr.len)) {
|
||||
// return the read data
|
||||
if (o_ret != MP_OBJ_NULL) {
|
||||
return o_ret;
|
||||
} else {
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
|
||||
return mp_const_none;
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into);
|
||||
|
||||
/// \method mem_write(data, addr, memaddr, addr_size=8)
|
||||
///
|
||||
/// Write to the memory of an I2C device:
|
||||
///
|
||||
/// - `data` can be an integer or a buffer to write from
|
||||
/// - `addr` is the I2C device address
|
||||
/// - `memaddr` is the memory location within the I2C device
|
||||
/// - `addr_size` selects the width of memaddr: 8 or 16 bits
|
||||
///
|
||||
/// Returns `None`.
|
||||
/// This is only valid in master mode.
|
||||
STATIC mp_obj_t pyb_i2c_mem_write(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
// parse args (same as mem_read)
|
||||
mp_arg_val_t vals[PYB_I2C_MEM_READ_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_MEM_READ_NUM_ARGS, pyb_i2c_mem_read_args, vals);
|
||||
STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args), pyb_i2c_readfrom_mem_into_args, args);
|
||||
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
|
||||
// get the buffer to write from
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint8_t data[1];
|
||||
pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
|
||||
pyb_buf_get_for_send(args[2].u_obj, &bufinfo, data);
|
||||
|
||||
// get the addresses
|
||||
mp_uint_t i2c_addr = vals[1].u_int;
|
||||
mp_uint_t mem_addr = vals[2].u_int;
|
||||
mp_uint_t i2c_addr = args[0].u_int;
|
||||
mp_uint_t mem_addr = args[1].u_int;
|
||||
// determine the width of mem_addr (1 or 2 bytes)
|
||||
mp_uint_t mem_addr_size = vals[3].u_int >> 3;
|
||||
mp_uint_t mem_addr_size = args[3].u_int >> 3;
|
||||
|
||||
// Write the register address to write to.
|
||||
if (pyb_i2c_write (i2c_addr, (byte *)&mem_addr, mem_addr_size, false)) {
|
||||
// Write the specified length of data
|
||||
if (pyb_i2c_write (i2c_addr, bufinfo.buf, bufinfo.len, true)) {
|
||||
return mp_const_none;
|
||||
}
|
||||
// write the register address to write to.
|
||||
if (pyb_i2c_mem_write (i2c_addr, (byte *)&mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len)) {
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
}
|
||||
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_i2c_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_i2c_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_is_ready), (mp_obj_t)&pyb_i2c_is_ready_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_i2c_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_i2c_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_read), (mp_obj_t)&pyb_i2c_mem_read_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_i2c_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_i2c_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom), (mp_obj_t)&pyb_i2c_readfrom_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_into), (mp_obj_t)&pyb_i2c_readfrom_into_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeto), (mp_obj_t)&pyb_i2c_writeto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_mem), (mp_obj_t)&pyb_i2c_readfrom_mem_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_mem_into), (mp_obj_t)&pyb_i2c_readfrom_mem_into_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeto_mem), (mp_obj_t)&pyb_i2c_writeto_mem_obj },
|
||||
|
||||
// class constants
|
||||
/// \constant MASTER - for initialising the bus to master mode
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYBI2C_MASTER) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYBI2C_MASTER) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
|
||||
|
||||
1211
cc3200/mods/pybpin.c
1211
cc3200/mods/pybpin.c
File diff suppressed because it is too large
Load Diff
@@ -28,26 +28,90 @@
|
||||
#ifndef PYBPIN_H_
|
||||
#define PYBPIN_H_
|
||||
|
||||
#define PYBPIN_ANALOG_TYPE 0xFF
|
||||
enum {
|
||||
PORT_A0 = GPIOA0_BASE,
|
||||
PORT_A1 = GPIOA1_BASE,
|
||||
PORT_A2 = GPIOA2_BASE,
|
||||
PORT_A3 = GPIOA3_BASE,
|
||||
};
|
||||
|
||||
enum {
|
||||
PORT_A0 = GPIOA0_BASE,
|
||||
PORT_A1 = GPIOA1_BASE,
|
||||
PORT_A2 = GPIOA2_BASE,
|
||||
PORT_A3 = GPIOA3_BASE
|
||||
PIN_FN_UART = 0,
|
||||
PIN_FN_SPI,
|
||||
PIN_FN_I2S,
|
||||
PIN_FN_I2C,
|
||||
PIN_FN_TIM,
|
||||
PIN_FN_SD,
|
||||
PIN_FN_ADC,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_UART_TX = 0,
|
||||
PIN_TYPE_UART_RX,
|
||||
PIN_TYPE_UART_RTS,
|
||||
PIN_TYPE_UART_CTS,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_SPI_CLK = 0,
|
||||
PIN_TYPE_SPI_MOSI,
|
||||
PIN_TYPE_SPI_MISO,
|
||||
PIN_TYPE_SPI_CS0,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_I2S_CLK = 0,
|
||||
PIN_TYPE_I2S_FS,
|
||||
PIN_TYPE_I2S_DAT0,
|
||||
PIN_TYPE_I2S_DAT1,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_I2C_SDA = 0,
|
||||
PIN_TYPE_I2C_SCL,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_TIM_PWM = 0,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_SD_CLK = 0,
|
||||
PIN_TYPE_SD_CMD,
|
||||
PIN_TYPE_SD_DAT0,
|
||||
};
|
||||
|
||||
enum {
|
||||
PIN_TYPE_ADC_CH0 = 0,
|
||||
PIN_TYPE_ADC_CH1,
|
||||
PIN_TYPE_ADC_CH2,
|
||||
PIN_TYPE_ADC_CH3,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
qstr name;
|
||||
int8_t idx;
|
||||
uint8_t fn;
|
||||
uint8_t unit;
|
||||
uint8_t type;
|
||||
} pin_af_t;
|
||||
|
||||
typedef struct {
|
||||
const mp_obj_base_t base;
|
||||
const qstr name;
|
||||
const uint32_t port;
|
||||
uint16_t type;
|
||||
const pin_af_t *af_list;
|
||||
uint16_t pull;
|
||||
const uint8_t bit;
|
||||
const uint8_t pin_num;
|
||||
uint8_t af;
|
||||
int8_t af;
|
||||
uint8_t strength;
|
||||
uint8_t mode;
|
||||
bool isused;
|
||||
uint8_t mode; // this is now a combination of type and mode
|
||||
const uint8_t num_afs; // 255 AFs
|
||||
uint8_t value;
|
||||
uint8_t used;
|
||||
uint8_t irq_trigger;
|
||||
uint8_t irq_flags;
|
||||
} pin_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pin_type;
|
||||
@@ -63,18 +127,15 @@ typedef struct {
|
||||
const pin_named_pin_t *named_pins;
|
||||
} pin_named_pins_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pin_cpu_pins_obj_type;
|
||||
extern const mp_obj_dict_t pin_cpu_pins_locals_dict;
|
||||
extern const mp_obj_type_t pin_board_pins_obj_type;
|
||||
extern const mp_obj_dict_t pin_board_pins_locals_dict;
|
||||
|
||||
void pin_init0(void);
|
||||
void pin_verify_af (uint af);
|
||||
void pin_config(pin_obj_t *self, uint af, uint mode, uint type, uint strength);
|
||||
void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority);
|
||||
void pin_config(pin_obj_t *self, int af, uint mode, uint type, int value, uint strength);
|
||||
pin_obj_t *pin_find(mp_obj_t user_obj);
|
||||
pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name);
|
||||
pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit);
|
||||
uint32_t pin_get_mode(const pin_obj_t *self);
|
||||
uint32_t pin_get_type(const pin_obj_t *self);
|
||||
uint32_t pin_get_strenght(const pin_obj_t *self);
|
||||
void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit);
|
||||
uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type);
|
||||
uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit);
|
||||
int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type);;
|
||||
|
||||
#endif // PYBPIN_H_
|
||||
|
||||
@@ -25,10 +25,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <std.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "inc/hw_types.h"
|
||||
@@ -37,212 +36,438 @@
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "timeutils.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class RTC - real time clock
|
||||
///
|
||||
/// The RTC is and independent clock that keeps track of the date
|
||||
/// and time.
|
||||
///
|
||||
/// Example usage:
|
||||
///
|
||||
/// rtc = pyb.RTC()
|
||||
/// rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
|
||||
/// print(rtc.datetime())
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBRTC_CLOCK_FREQUENCY_HZ 32768
|
||||
#define PYBRTC_MIN_INTERVAL_VALUE 25
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
byte prwmode;
|
||||
} pybrtc_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pybrtc_data_t pybrtc_data;
|
||||
STATIC const mp_cb_methods_t pybrtc_cb_methods;
|
||||
STATIC const mp_obj_base_t pyb_rtc_obj = {&pyb_rtc_type};
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods;
|
||||
STATIC pyb_rtc_obj_t pyb_rtc_obj;
|
||||
|
||||
/******************************************************************************
|
||||
FUNCTION-LIKE MACROS
|
||||
******************************************************************************/
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs);
|
||||
STATIC uint32_t pyb_rtc_reset (void);
|
||||
STATIC void pyb_rtc_disable_interupt (void);
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in);
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in);
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds);
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime);
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds);
|
||||
STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pybrtc_init(void) {
|
||||
// if the RTC was previously set, leave it alone
|
||||
void pyb_rtc_pre_init(void) {
|
||||
// only if comming out of a power-on reset
|
||||
if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) {
|
||||
// fresh reset; configure the RTC Calendar
|
||||
// set the date to 1st Jan 2015
|
||||
// set the time to 00:00:00
|
||||
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
|
||||
|
||||
// Mark the RTC in use first
|
||||
MAP_PRCMRTCInUseSet();
|
||||
|
||||
// Now set the RTC calendar seconds
|
||||
MAP_PRCMRTCSet(seconds, 0);
|
||||
// reset the time and date
|
||||
pyb_rtc_reset();
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_callback_disable (mp_obj_t self_in) {
|
||||
// check the wake from param
|
||||
if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// disable the slow clock interrupt
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) {
|
||||
uint16_t cycles;
|
||||
MAP_PRCMRTCGet (secs, &cycles);
|
||||
*msecs = RTC_CYCLES_U16MS(cycles);
|
||||
}
|
||||
|
||||
uint32_t pyb_rtc_get_seconds (void) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) {
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
// get the current time
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
// calculate the future seconds
|
||||
*f_seconds = c_seconds + (a_mseconds / 1000);
|
||||
// calculate the "remaining" future mseconds
|
||||
*f_mseconds = a_mseconds % 1000;
|
||||
// add the current milliseconds
|
||||
rtc_msec_add (c_mseconds, f_seconds, f_mseconds);
|
||||
}
|
||||
|
||||
void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) {
|
||||
if (self->repeat) {
|
||||
uint32_t f_seconds, c_seconds;
|
||||
uint16_t f_mseconds, c_mseconds;
|
||||
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// substract the time elapsed between waking up and setting up the alarm again
|
||||
int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms);
|
||||
int32_t next_alarm = self->alarm_ms - wake_ms;
|
||||
next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS;
|
||||
pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds);
|
||||
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
}
|
||||
// disable wake from ldps and hibernate
|
||||
pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE);
|
||||
// read the interrupt status to clear any pending interrupt
|
||||
(void)MAP_PRCMIntStatus();
|
||||
}
|
||||
|
||||
void pyb_rtc_disable_alarm (void) {
|
||||
pyb_rtc_obj.alarmset = false;
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) {
|
||||
// check the wake from param
|
||||
if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// enable the slow clock interrupt
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) {
|
||||
// add the RTC access time
|
||||
rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs);
|
||||
// convert from mseconds to cycles
|
||||
msecs = RTC_U16MS_CYCLES(msecs);
|
||||
// now set the time
|
||||
MAP_PRCMRTCSet(secs, msecs);
|
||||
}
|
||||
|
||||
STATIC uint32_t pyb_rtc_reset (void) {
|
||||
// fresh reset; configure the RTC Calendar
|
||||
// set the date to 1st Jan 2015
|
||||
// set the time to 00:00:00
|
||||
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
|
||||
// disable any running alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
// Now set the RTC calendar time
|
||||
pyb_rtc_set_time(seconds, 0);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_disable_interupt (void) {
|
||||
uint primsk = disable_irq();
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
(void)MAP_PRCMIntStatus();
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
// we always need interrupts if repeat is enabled
|
||||
if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
else {
|
||||
// just in case it was already enabled before
|
||||
} else { // just in case it was already enabled before
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
pybsleep_configure_timer_wakeup (pybrtc_data.prwmode);
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
self->irq_enabled = false;
|
||||
if (!self->repeat) { // we always need interrupts if repeat is enabled
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t useconds;
|
||||
|
||||
// set date and time
|
||||
mp_obj_t *items;
|
||||
uint len;
|
||||
mp_obj_get_array(datetime, &len, &items);
|
||||
|
||||
// verify the tuple
|
||||
if (len < 3 || len > 8) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
tm.tm_year = mp_obj_get_int(items[0]);
|
||||
tm.tm_mon = mp_obj_get_int(items[1]);
|
||||
tm.tm_mday = mp_obj_get_int(items[2]);
|
||||
if (len < 7) {
|
||||
useconds = 0;
|
||||
} else {
|
||||
useconds = mp_obj_get_int(items[6]);
|
||||
}
|
||||
if (len < 6) {
|
||||
tm.tm_sec = 0;
|
||||
} else {
|
||||
tm.tm_sec = mp_obj_get_int(items[5]);
|
||||
}
|
||||
if (len < 5) {
|
||||
tm.tm_min = 0;
|
||||
} else {
|
||||
tm.tm_min = mp_obj_get_int(items[4]);
|
||||
}
|
||||
if (len < 4) {
|
||||
tm.tm_hour = 0;
|
||||
} else {
|
||||
tm.tm_hour = mp_obj_get_int(items[3]);
|
||||
}
|
||||
*seconds = timeutils_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
return useconds;
|
||||
}
|
||||
|
||||
/// The 8-tuple has the same format as CPython's datetime object:
|
||||
///
|
||||
/// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None)
|
||||
///
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) {
|
||||
uint32_t seconds;
|
||||
uint32_t useconds;
|
||||
|
||||
if (datetime != MP_OBJ_NULL) {
|
||||
useconds = pyb_rtc_datetime_s_us(datetime, &seconds);
|
||||
pyb_rtc_set_time (seconds, useconds / 1000);
|
||||
} else {
|
||||
seconds = pyb_rtc_reset();
|
||||
}
|
||||
|
||||
// set WLAN time and date, this is needed to verify certificates
|
||||
wlan_set_current_time(seconds);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) {
|
||||
// disable the interrupt before updating anything
|
||||
if (self->irq_enabled) {
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds));
|
||||
self->alarmset = true;
|
||||
self->alarm_time_s = seconds;
|
||||
self->alarm_time_ms = mseconds;
|
||||
// enabled the interrupts again if applicable
|
||||
if (self->irq_enabled || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) {
|
||||
if (msecs_1 + *msecs_2 >= 1000) { // larger than one second
|
||||
*msecs_2 = (msecs_1 + *msecs_2) - 1000;
|
||||
*secs += 1; // carry flag
|
||||
} else {
|
||||
// simply add the mseconds
|
||||
*msecs_2 = msecs_1 + *msecs_2;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \classmethod \constructor()
|
||||
/// Create an RTC object.
|
||||
STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
STATIC const mp_arg_t pyb_rtc_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_datetime, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_rtc_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_rtc_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_rtc_obj_t *self = &pyb_rtc_obj;
|
||||
self->base.type = &pyb_rtc_type;
|
||||
|
||||
// set the time and date
|
||||
pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj);
|
||||
|
||||
// pass it to the sleep module
|
||||
pyb_sleep_set_rtc_obj (self);
|
||||
|
||||
// return constant object
|
||||
return (mp_obj_t)&pyb_rtc_obj;
|
||||
}
|
||||
|
||||
/// \method datetime([datetimetuple])
|
||||
/// Get or set the date and time of the RTC.
|
||||
///
|
||||
/// With no arguments, this method returns an 8-tuple with the current
|
||||
/// date and time. With 1 argument (being an 8-tuple) it sets the date
|
||||
/// and time.
|
||||
///
|
||||
/// The 8-tuple has the following format:
|
||||
///
|
||||
/// (year, month, day, weekday, hours, minutes, seconds, milliseconds)
|
||||
///
|
||||
/// `weekday` is 0-6 for Monday through Sunday.
|
||||
///
|
||||
mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t pyb_rtc_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_rtc_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_rtc_init_args[1], args);
|
||||
return pyb_rtc_datetime(pos_args[0], args[0].u_obj);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_init_obj, 1, pyb_rtc_init);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
if (n_args == 1) {
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
// get the time from the RTC
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
mp_obj_new_int(tm.tm_mday),
|
||||
mp_obj_new_int(tm.tm_wday),
|
||||
mp_obj_new_int(tm.tm_hour),
|
||||
mp_obj_new_int(tm.tm_min),
|
||||
mp_obj_new_int(tm.tm_sec),
|
||||
mp_obj_new_int(mseconds)
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
mp_obj_new_int(tm.tm_mday),
|
||||
mp_obj_new_int(tm.tm_hour),
|
||||
mp_obj_new_int(tm.tm_min),
|
||||
mp_obj_new_int(tm.tm_sec),
|
||||
mp_obj_new_int(mseconds * 1000),
|
||||
mp_const_none
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) {
|
||||
pyb_rtc_reset();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
pyb_rtc_obj_t *self = pos_args[0];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
|
||||
|
||||
// check the alarm id
|
||||
if (args[0].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
bool repeat = args[2].u_bool;
|
||||
if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given
|
||||
// repeat cannot be used with a datetime tuple
|
||||
if (repeat) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000;
|
||||
} else { // then it must be an integer
|
||||
self->alarm_ms = mp_obj_get_int(args[1].u_obj);
|
||||
pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds);
|
||||
}
|
||||
|
||||
// store the repepat flag
|
||||
self->repeat = repeat;
|
||||
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_rtc_obj_t *self = args[0];
|
||||
int32_t ms_left;
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// get the current time
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// calculate the ms left
|
||||
ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds);
|
||||
if (!self->alarmset || ms_left < 0) {
|
||||
ms_left = 0;
|
||||
}
|
||||
return mp_obj_new_int(ms_left);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
// disable the alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_rtc_obj_t *self = pos_args[0];
|
||||
|
||||
// save the power mode data for later
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// check the trigger
|
||||
if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) {
|
||||
self->pwrmode = pwrmode;
|
||||
pyb_rtc_irq_enable((mp_obj_t)self);
|
||||
} else {
|
||||
// set date and time
|
||||
mp_obj_t *items;
|
||||
mp_obj_get_array_fixed_n(args[1], 8, &items);
|
||||
|
||||
tm.tm_year = mp_obj_get_int(items[0]);
|
||||
tm.tm_mon = mp_obj_get_int(items[1]);
|
||||
tm.tm_mday = mp_obj_get_int(items[2]);
|
||||
// Skip the weekday
|
||||
tm.tm_hour = mp_obj_get_int(items[4]);
|
||||
tm.tm_min = mp_obj_get_int(items[5]);
|
||||
tm.tm_sec = mp_obj_get_int(items[6]);
|
||||
mseconds = mp_obj_get_int(items[7]);
|
||||
|
||||
seconds = timeutils_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
mseconds = RTC_U16MS_CYCLES(mseconds);
|
||||
MAP_PRCMRTCSet(seconds, mseconds);
|
||||
|
||||
return mp_const_none;
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup irqs are always called first when resuming from sleep
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods);
|
||||
self->irq_obj = _irq;
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime);
|
||||
|
||||
/// \method callback(handler, value, pwrmode)
|
||||
/// Creates a callback object associated with the real time clock
|
||||
/// min num of arguments is 1 (value). The value is the alarm time
|
||||
/// in the future, in msec
|
||||
STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
|
||||
// check if any parameters were passed
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
|
||||
if (kw_args->used > 0 || !_callback) {
|
||||
uint32_t f_mseconds = MAX(1, args[3].u_int);
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
|
||||
// configure the rtc alarm accordingly
|
||||
seconds += f_mseconds / 1000;
|
||||
mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
|
||||
|
||||
// disable the interrupt before updating anything
|
||||
// (the object is not relevant here, the function already knows it)
|
||||
pyb_rtc_callback_disable(NULL);
|
||||
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, mseconds);
|
||||
|
||||
// save the power mode data for later
|
||||
pybrtc_data.prwmode = args[4].u_int;
|
||||
|
||||
// create the callback
|
||||
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods);
|
||||
|
||||
// set the lpds callback
|
||||
pybsleep_set_timer_lpds_callback(_callback);
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup callbacks are always called first when resuming from sleep
|
||||
|
||||
// enable the interrupt (the object is not relevant here, the function already knows it)
|
||||
pyb_rtc_callback_enable(NULL);
|
||||
}
|
||||
return _callback;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_callback_obj, 1, pyb_rtc_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_rtc_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_rtc_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_rtc_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_now), (mp_obj_t)&pyb_rtc_now_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_cancel), (mp_obj_t)&pyb_rtc_alarm_cancel_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(PYB_RTC_ALARM0) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
|
||||
|
||||
@@ -253,8 +478,9 @@ const mp_obj_type_t pyb_rtc_type = {
|
||||
.locals_dict = (mp_obj_t)&pyb_rtc_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pybrtc_cb_methods = {
|
||||
.init = pyb_rtc_callback,
|
||||
.enable = pyb_rtc_callback_enable,
|
||||
.disable = pyb_rtc_callback_disable,
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods = {
|
||||
.init = pyb_rtc_irq,
|
||||
.enable = pyb_rtc_irq_enable,
|
||||
.disable = pyb_rtc_irq_disable,
|
||||
.flags = pyb_rtc_irq_flags
|
||||
};
|
||||
|
||||
@@ -28,12 +28,32 @@
|
||||
#ifndef PYBRTC_H_
|
||||
#define PYBRTC_H_
|
||||
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
// RTC triggers
|
||||
#define PYB_RTC_ALARM0 (0x01)
|
||||
|
||||
#define RTC_ACCESS_TIME_MSEC (5)
|
||||
#define PYB_RTC_MIN_ALARM_TIME_MS (RTC_ACCESS_TIME_MSEC * 2)
|
||||
|
||||
typedef struct _pyb_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t irq_obj;
|
||||
uint32_t irq_flags;
|
||||
uint32_t alarm_ms;
|
||||
uint32_t alarm_time_s;
|
||||
uint16_t alarm_time_ms;
|
||||
byte pwrmode;
|
||||
bool alarmset;
|
||||
bool repeat;
|
||||
bool irq_enabled;
|
||||
} pyb_rtc_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pyb_rtc_type;
|
||||
|
||||
void pybrtc_init(void);
|
||||
void pyb_rtc_callback_disable (mp_obj_t self_in);
|
||||
extern void pyb_rtc_pre_init(void);
|
||||
extern void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs);
|
||||
extern uint32_t pyb_rtc_get_seconds (void);
|
||||
extern void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds);
|
||||
extern void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self);
|
||||
extern void pyb_rtc_disable_alarm (void);
|
||||
|
||||
#endif // PYBRTC_H_
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "inc/hw_types.h"
|
||||
@@ -37,61 +36,46 @@
|
||||
#include "prcm.h"
|
||||
#include "gpio.h"
|
||||
#include "sdhost.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybsd.h"
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "sd_diskio.h"
|
||||
#include "simplelink.h"
|
||||
#include "debug.h"
|
||||
#include "pybsd.h"
|
||||
#include "mpexception.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
|
||||
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBSD_FREQUENCY_HZ 15000000 // 15MHz
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
FATFS *fatfs;
|
||||
pin_obj_t *pin_clk;
|
||||
bool pinsset;
|
||||
bool enabled;
|
||||
} pybsd_obj_t;
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
pybsd_obj_t pybsd_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pybsd_obj_t pybsd_obj;
|
||||
STATIC const mp_obj_t pyb_sd_def_pin[3] = {&pin_GP10, &pin_GP11, &pin_GP15};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t pybsd_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
|
||||
STATIC mp_obj_t pybsd_disable (mp_obj_t self_in);
|
||||
STATIC mp_obj_t pybsd_enable (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pybsd_init0 (void) {
|
||||
// allocate memory for the sd file system
|
||||
ASSERT ((pybsd_obj.fatfs = mem_Malloc(sizeof(FATFS))) != NULL);
|
||||
}
|
||||
|
||||
void pybsd_deinit (void) {
|
||||
pybsd_disable ((mp_obj_t)&pybsd_obj);
|
||||
}
|
||||
STATIC void pyb_sd_hw_init (pybsd_obj_t *self);
|
||||
STATIC mp_obj_t pyb_sd_make_new (const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
|
||||
STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
/// Initalizes the sd card driver
|
||||
STATIC void pybsd_init (pybsd_obj_t *self) {
|
||||
// Configure the clock pin as output only
|
||||
MAP_PinDirModeSet(self->pin_clk->pin_num, PIN_DIR_MODE_OUT);
|
||||
/// Initalizes the sd card hardware driver
|
||||
STATIC void pyb_sd_hw_init (pybsd_obj_t *self) {
|
||||
if (self->pin_clk) {
|
||||
// Configure the clock pin as output only
|
||||
MAP_PinDirModeSet(((pin_obj_t *)(self->pin_clk))->pin_num, PIN_DIR_MODE_OUT);
|
||||
}
|
||||
// Enable SD peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// Reset MMCHS
|
||||
@@ -100,110 +84,95 @@ STATIC void pybsd_init (pybsd_obj_t *self) {
|
||||
MAP_SDHostInit(SDHOST_BASE);
|
||||
// Configure the card clock
|
||||
MAP_SDHostSetExpClk(SDHOST_BASE, MAP_PRCMPeripheralClockGet(PRCM_SDHOST), PYBSD_FREQUENCY_HZ);
|
||||
// Set card rd/wr block len
|
||||
MAP_SDHostBlockSizeSet(SDHOST_BASE, SD_SECTOR_SIZE);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args) {
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[0].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_sd_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, MP_ARRAY_SIZE(pyb_sd_def_pin), &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, MP_ARRAY_SIZE(pyb_sd_def_pin), PIN_TYPE_STD_PU, PIN_FN_SD, 0);
|
||||
// save the pins clock
|
||||
self->pin_clk = pin_find(pins[0]);
|
||||
}
|
||||
|
||||
pyb_sd_hw_init (self);
|
||||
if (sd_disk_init() != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
//
|
||||
|
||||
/// \classmethod \constructor()
|
||||
/// Configure the pins used for the sd card.
|
||||
/// May receive 0, or 6 arguments.
|
||||
///
|
||||
/// Usage:
|
||||
/// sd = pyb.SD()
|
||||
////
|
||||
/// sd = pyb.SD(d0_pin, d0_af, clk_pin, clk_af, cmd_pin, cmd_af)
|
||||
///
|
||||
STATIC mp_obj_t pybsd_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 6, false);
|
||||
|
||||
if (n_args == 6) {
|
||||
// save the clock pin for later use
|
||||
pybsd_obj.pin_clk = (pin_obj_t *)pin_find(args[2]);
|
||||
|
||||
// configure the data pin with pull-up enabled
|
||||
pin_config ((pin_obj_t *)pin_find(args[0]), mp_obj_get_int(args[1]), 0, PIN_TYPE_STD_PU, PIN_STRENGTH_4MA);
|
||||
// configure the clock pin
|
||||
pin_config (pybsd_obj.pin_clk, mp_obj_get_int(args[3]), 0, PIN_TYPE_STD, PIN_STRENGTH_4MA);
|
||||
// configure the command pin with pull-up enabled
|
||||
pin_config ((pin_obj_t *)pin_find(args[4]), mp_obj_get_int(args[5]), 0, PIN_TYPE_STD_PU, PIN_STRENGTH_4MA);
|
||||
|
||||
pybsd_obj.pinsset = true;
|
||||
pybsd_obj.base.type = &pyb_sd_type;
|
||||
}
|
||||
else if (!pybsd_obj.pinsset) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
|
||||
}
|
||||
|
||||
return &pybsd_obj;
|
||||
}
|
||||
|
||||
/// \method enable()
|
||||
/// Enables the sd card and mounts the file system
|
||||
STATIC mp_obj_t pybsd_enable (mp_obj_t self_in) {
|
||||
pybsd_obj_t *self = self_in;
|
||||
|
||||
if (!self->enabled) {
|
||||
// do the init first
|
||||
pybsd_init (self);
|
||||
|
||||
// try to mount the sd card on /sd
|
||||
if (FR_OK != f_mount(self->fatfs, "/sd", 1)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd));
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib));
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)&pybsd_obj, (WakeUpCB_t)pybsd_init);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pybsd_enable_obj, pybsd_enable);
|
||||
|
||||
/// \method disable()
|
||||
/// Disables the sd card and unmounts the file system
|
||||
STATIC mp_obj_t pybsd_disable (mp_obj_t self_in) {
|
||||
pybsd_obj_t *self = self_in;
|
||||
if (self->enabled) {
|
||||
self->enabled = false;
|
||||
// unmount the sd card
|
||||
f_mount (NULL, "/sd", 1);
|
||||
// remove sd paths from mp_sys_path
|
||||
mp_obj_list_remove(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd));
|
||||
mp_obj_list_remove(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib));
|
||||
|
||||
// disable the peripheral
|
||||
MAP_PRCMPeripheralClkDisable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
// de-initialze de sd card at diskio level
|
||||
sd_disk_deinit();
|
||||
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove (self);
|
||||
|
||||
// change the drive in case it was /sd
|
||||
f_chdrive("/flash");
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pybsd_disable_obj, pybsd_disable);
|
||||
|
||||
STATIC const mp_map_elem_t pybsd_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&pybsd_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&pybsd_disable_obj },
|
||||
STATIC const mp_arg_t pyb_sd_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pybsd_locals_dict, pybsd_locals_dict_table);
|
||||
STATIC mp_obj_t pyb_sd_make_new (const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_sd_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_sd_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// setup and initialize the object
|
||||
mp_obj_t self = &pybsd_obj;
|
||||
pybsd_obj.base.type = &pyb_sd_type;
|
||||
pyb_sd_init_helper (self, &args[1]);
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_sd_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_sd_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_sd_init_args[1], args);
|
||||
return pyb_sd_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_sd_init_obj, 1, pyb_sd_init);
|
||||
|
||||
STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) {
|
||||
pybsd_obj_t *self = self_in;
|
||||
// disable the peripheral
|
||||
self->enabled = false;
|
||||
MAP_PRCMPeripheralClkDisable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// de-initialze the sd card at diskio level
|
||||
sd_disk_deinit();
|
||||
// unregister it from the sleep module
|
||||
pyb_sleep_remove (self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sd_deinit_obj, pyb_sd_deinit);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_sd_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_sd_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_sd_deinit_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_sd_locals_dict, pyb_sd_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_sd_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SD,
|
||||
.make_new = pybsd_make_new,
|
||||
.locals_dict = (mp_obj_t)&pybsd_locals_dict,
|
||||
.make_new = pyb_sd_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_sd_locals_dict,
|
||||
};
|
||||
|
||||
#endif // MICROPY_HW_HAS_SDCARD
|
||||
|
||||
@@ -26,11 +26,19 @@
|
||||
#ifndef PYBSD_H_
|
||||
#define PYBSD_H_
|
||||
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t pin_clk;
|
||||
bool enabled;
|
||||
} pybsd_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
extern pybsd_obj_t pybsd_obj;
|
||||
extern const mp_obj_type_t pyb_sd_type;
|
||||
|
||||
void pybsd_init0 (void);
|
||||
void pybsd_deinit (void);
|
||||
#endif
|
||||
|
||||
#endif // PYBSD_H_
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "spi.h"
|
||||
#include "pin.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybpin.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@@ -50,11 +51,12 @@
|
||||
#include "osi.h"
|
||||
#include "debug.h"
|
||||
#include "mpexception.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mperror.h"
|
||||
#include "sleeprestore.h"
|
||||
#include "serverstask.h"
|
||||
#include "antenna.h"
|
||||
#include "cryptohash.h"
|
||||
#include "pybrtc.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
@@ -69,7 +71,7 @@
|
||||
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
|
||||
#define WAKEUP_TIME_HIB (32768) // 1 s
|
||||
|
||||
#define FORCED_TIMER_INTERRUPT_MS (1)
|
||||
#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
|
||||
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
|
||||
|
||||
/******************************************************************************
|
||||
@@ -109,35 +111,37 @@ typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t obj;
|
||||
WakeUpCB_t wakeup;
|
||||
} pybsleep_obj_t;
|
||||
} pyb_sleep_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_t wlan_lpds_wake_cb;
|
||||
mp_obj_t timer_lpds_wake_cb;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
uint timer_wake_pwrmode;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
wlan_obj_t *wlan_obj;
|
||||
pyb_rtc_obj_t *rtc_obj;
|
||||
} pybsleep_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t pybsleep_type;
|
||||
STATIC nvic_reg_store_t *nvic_reg_store;
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL, 0};
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
|
||||
volatile arm_cm4_core_regs_t vault_arm_registers;
|
||||
STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
|
||||
STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
|
||||
STATIC const mp_obj_type_t pyb_sleep_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_sleep,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj);
|
||||
STATIC void pybsleep_flash_powerdown (void);
|
||||
STATIC NORETURN void pybsleep_suspend_enter (void);
|
||||
void pybsleep_suspend_exit (void);
|
||||
STATIC void pybsleep_obj_wakeup (void);
|
||||
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj);
|
||||
STATIC void pyb_sleep_flash_powerdown (void);
|
||||
STATIC NORETURN void pyb_sleep_suspend_enter (void);
|
||||
void pyb_sleep_suspend_exit (void);
|
||||
STATIC void pyb_sleep_obj_wakeup (void);
|
||||
STATIC void PRCMInterruptHandler (void);
|
||||
STATIC void pybsleep_iopark (bool hibernate);
|
||||
STATIC void pyb_sleep_iopark (bool hibernate);
|
||||
STATIC bool setup_timer_lpds_wake (void);
|
||||
STATIC bool setup_timer_hibernate_wake (void);
|
||||
|
||||
@@ -145,14 +149,14 @@ STATIC bool setup_timer_hibernate_wake (void);
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pybsleep_pre_init (void) {
|
||||
void pyb_sleep_pre_init (void) {
|
||||
// allocate memory for nvic registers vault
|
||||
ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL);
|
||||
}
|
||||
|
||||
void pybsleep_init0 (void) {
|
||||
void pyb_sleep_init0 (void) {
|
||||
// initialize the sleep objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0);
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0);
|
||||
|
||||
// register and enable the PRCM interrupt
|
||||
osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
|
||||
@@ -163,7 +167,7 @@ void pybsleep_init0 (void) {
|
||||
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
|
||||
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
|
||||
|
||||
// store the reset casue (if it's soft reset, leave it as it is)
|
||||
// check the reset casue (if it's soft reset, leave it as it is)
|
||||
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
|
||||
switch (MAP_PRCMSysResetCauseGet()) {
|
||||
case PRCM_POWER_ON:
|
||||
@@ -178,7 +182,7 @@ void pybsleep_init0 (void) {
|
||||
pybsleep_reset_cause = PYB_SLP_WDT_RESET;
|
||||
break;
|
||||
case PRCM_HIB_EXIT:
|
||||
if (PRCMWasResetBecauseOfWDT()) {
|
||||
if (PRCMGetSpecialBit(PRCM_WDT_RESET_BIT)) {
|
||||
pybsleep_reset_cause = PYB_SLP_WDT_RESET;
|
||||
}
|
||||
else {
|
||||
@@ -187,6 +191,7 @@ void pybsleep_init0 (void) {
|
||||
switch (MAP_PRCMHibernateWakeupCauseGet()) {
|
||||
case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK:
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
// TODO repeat the alarm
|
||||
break;
|
||||
case PRCM_HIB_WAKEUP_CAUSE_GPIO:
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
@@ -202,55 +207,109 @@ void pybsleep_init0 (void) {
|
||||
}
|
||||
}
|
||||
|
||||
void pybsleep_signal_soft_reset (void) {
|
||||
void pyb_sleep_signal_soft_reset (void) {
|
||||
pybsleep_reset_cause = PYB_SLP_SOFT_RESET;
|
||||
}
|
||||
|
||||
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
|
||||
pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t);
|
||||
sleep_obj->base.type = &pybsleep_type;
|
||||
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
|
||||
pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t);
|
||||
sleep_obj->base.type = &pyb_sleep_type;
|
||||
sleep_obj->obj = obj;
|
||||
sleep_obj->wakeup = wakeup;
|
||||
// only add objects once
|
||||
if (!pybsleep_find(sleep_obj)) {
|
||||
mp_obj_list_append(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
|
||||
// remove it in case it was already registered
|
||||
pyb_sleep_remove (obj);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
|
||||
}
|
||||
|
||||
void pyb_sleep_remove (const mp_obj_t obj) {
|
||||
pyb_sleep_obj_t *sleep_obj;
|
||||
if ((sleep_obj = pyb_sleep_find(obj))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void pybsleep_remove (const mp_obj_t obj) {
|
||||
pybsleep_obj_t *sleep_obj;
|
||||
if ((sleep_obj = pybsleep_find(obj))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.wlan_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
|
||||
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.gpio_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.timer_lpds_wake_cb = cb_obj;
|
||||
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) {
|
||||
pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
|
||||
}
|
||||
|
||||
void pybsleep_configure_timer_wakeup (uint pwrmode) {
|
||||
pybsleep_data.timer_wake_pwrmode = pwrmode;
|
||||
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) {
|
||||
pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
|
||||
}
|
||||
|
||||
pybsleep_reset_cause_t pybsleep_get_reset_cause (void) {
|
||||
void pyb_sleep_sleep (void) {
|
||||
nlr_buf_t nlr;
|
||||
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
|
||||
if (!setup_timer_lpds_wake()) {
|
||||
// lpds entering is not possible, wait for the forced interrupt and return
|
||||
mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
}
|
||||
|
||||
// do we need network wake-up?
|
||||
if (pybsleep_data.wlan_obj->irq_enabled) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
server_sleep_sockets();
|
||||
} else {
|
||||
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
|
||||
}
|
||||
|
||||
// entering and exiting suspended mode must be an atomic operation
|
||||
// therefore interrupts need to be disabled
|
||||
uint primsk = disable_irq();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
pyb_sleep_suspend_enter();
|
||||
nlr_pop();
|
||||
}
|
||||
|
||||
// an exception is always raised when exiting suspend mode
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
void pyb_sleep_deepsleep (void) {
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
|
||||
if (!setup_timer_hibernate_wake()) {
|
||||
// hibernating is not possible, wait for the forced interrupt and return
|
||||
mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as hibernate wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
}
|
||||
|
||||
wlan_stop(SL_STOP_TIMEOUT);
|
||||
pyb_sleep_flash_powerdown();
|
||||
// must be done just before entering hibernate mode
|
||||
pyb_sleep_iopark(true);
|
||||
MAP_PRCMHibernateEnter();
|
||||
}
|
||||
|
||||
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) {
|
||||
return pybsleep_reset_cause;
|
||||
}
|
||||
|
||||
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) {
|
||||
return pybsleep_wake_reason;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
|
||||
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
|
||||
// search for the object and then remove it
|
||||
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)(MP_STATE_PORT(pybsleep_obj_list).items[i]));
|
||||
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i]));
|
||||
if (sleep_obj->obj == obj) {
|
||||
return sleep_obj;
|
||||
}
|
||||
@@ -258,7 +317,7 @@ STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC void pybsleep_flash_powerdown (void) {
|
||||
STATIC void pyb_sleep_flash_powerdown (void) {
|
||||
uint32_t status;
|
||||
|
||||
// Enable clock for SSPI module
|
||||
@@ -303,7 +362,7 @@ STATIC void pybsleep_flash_powerdown (void) {
|
||||
MAP_SPICSDisable(SSPI_BASE);
|
||||
}
|
||||
|
||||
STATIC NORETURN void pybsleep_suspend_enter (void) {
|
||||
STATIC NORETURN void pyb_sleep_suspend_enter (void) {
|
||||
// enable full RAM retention
|
||||
MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
|
||||
|
||||
@@ -340,7 +399,7 @@ STATIC NORETURN void pybsleep_suspend_enter (void) {
|
||||
mperror_heartbeat_switch_off();
|
||||
|
||||
// park the gpio pins
|
||||
pybsleep_iopark(false);
|
||||
pyb_sleep_iopark(false);
|
||||
|
||||
// store the cpu registers
|
||||
sleep_store();
|
||||
@@ -353,7 +412,7 @@ STATIC NORETURN void pybsleep_suspend_enter (void) {
|
||||
for ( ; ; );
|
||||
}
|
||||
|
||||
void pybsleep_suspend_exit (void) {
|
||||
void pyb_sleep_suspend_exit (void) {
|
||||
// take the I2C semaphore
|
||||
uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
|
||||
reg = (reg & ~0x3) | 0x1;
|
||||
@@ -407,10 +466,13 @@ void pybsleep_suspend_exit (void) {
|
||||
sl_IfOpen (NULL, 0);
|
||||
|
||||
// restore the configuration of all active peripherals
|
||||
pybsleep_obj_wakeup();
|
||||
pyb_sleep_obj_wakeup();
|
||||
|
||||
// reconfigure all the previously enabled interrupts
|
||||
mpcallback_wake_all();
|
||||
mp_irq_wake_all();
|
||||
|
||||
// we need to init the crypto hash engine again
|
||||
//CRYPTOHASH_Init();
|
||||
|
||||
// trigger a sw interrupt
|
||||
MAP_IntPendSet(INT_PRCM);
|
||||
@@ -422,25 +484,35 @@ void pybsleep_suspend_exit (void) {
|
||||
STATIC void PRCMInterruptHandler (void) {
|
||||
// reading the interrupt status automatically clears the interrupt
|
||||
if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
|
||||
// this interrupt is triggered during active mode
|
||||
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
|
||||
}
|
||||
else {
|
||||
// reconfigure it again (if repeat is true)
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// need to check if irq's are enabled from the user point of view
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
}
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
} else {
|
||||
// interrupt has been triggered while waking up from LPDS
|
||||
switch (MAP_PRCMLPDSWakeupCauseGet()) {
|
||||
case PRCM_LPDS_HOST_IRQ:
|
||||
mpcallback_handler(pybsleep_data.wlan_lpds_wake_cb);
|
||||
pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
|
||||
mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
|
||||
pybsleep_data.wlan_obj->irq_flags = 0;
|
||||
break;
|
||||
case PRCM_LPDS_GPIO:
|
||||
mpcallback_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
break;
|
||||
case PRCM_LPDS_TIMER:
|
||||
// disable the timer as wake-up source
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
|
||||
// reconfigure it again if repeat is true
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// next one clears the wake cause flag
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
break;
|
||||
default:
|
||||
@@ -449,18 +521,17 @@ STATIC void PRCMInterruptHandler (void) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pybsleep_obj_wakeup (void) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
|
||||
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]);
|
||||
STATIC void pyb_sleep_obj_wakeup (void) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
|
||||
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]);
|
||||
sleep_obj->wakeup(sleep_obj->obj);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pybsleep_iopark (bool hibernate) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_cpu_pins_locals_dict);
|
||||
STATIC void pyb_sleep_iopark (bool hibernate) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
|
||||
for (uint i = 0; i < named_map->used; i++) {
|
||||
pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
|
||||
// skip the sflash pins since these are shared with the network processor
|
||||
switch (pin->pin_num) {
|
||||
#ifdef DEBUG
|
||||
// skip the JTAG pins
|
||||
@@ -471,9 +542,9 @@ STATIC void pybsleep_iopark (bool hibernate) {
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// enable a weak pull-down if the pin is unused
|
||||
if (!pin->isused) {
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD);
|
||||
// enable a weak pull-up if the pin is unused
|
||||
if (!pin->used) {
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
|
||||
}
|
||||
if (hibernate) {
|
||||
// make it an input
|
||||
@@ -515,191 +586,72 @@ STATIC void pybsleep_iopark (bool hibernate) {
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_lpds_wake (void) {
|
||||
uint64_t t_match, t_curr, t_remaining;
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
if (t_match > t_curr) {
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes for wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// setup a timer interrupt immediately
|
||||
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes to wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
|
||||
// LPDS wake by timer was not possible, force
|
||||
// an interrupt in active mode instead
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_hibernate_wake (void) {
|
||||
uint64_t t_match, t_curr, t_remaining;
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
if (t_match > t_curr) {
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// setup a timer interrupt immediately
|
||||
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
|
||||
// hibernate wake by timer was not possible, force
|
||||
// an interrupt in active mode instead
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings; Sleep class
|
||||
|
||||
/// \function idle()
|
||||
/// Gates the processor clock until an interrupt is triggered
|
||||
STATIC mp_obj_t pyb_sleep_idle (mp_obj_t self_in) {
|
||||
__WFI();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle);
|
||||
|
||||
/// \function suspend(wlan)
|
||||
/// Enters suspended mode. Wake up sources should have been enable prior to
|
||||
/// calling this method.
|
||||
STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
|
||||
nlr_buf_t nlr;
|
||||
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (!setup_timer_lpds_wake()) {
|
||||
// lpds entering is not possible, wait for the forced interrupt and return
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
// do we need network wake-up?
|
||||
if (pybsleep_data.wlan_lpds_wake_cb) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
server_sleep_sockets();
|
||||
}
|
||||
else {
|
||||
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
|
||||
}
|
||||
|
||||
// entering and exiting suspended mode must be an atomic operation
|
||||
// therefore interrupts need to be disabled
|
||||
uint primsk = disable_irq();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
pybsleep_suspend_enter();
|
||||
nlr_pop();
|
||||
}
|
||||
|
||||
// an exception is always raised when exiting suspend mode
|
||||
enable_irq(primsk);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend);
|
||||
|
||||
/// \function hibernate()
|
||||
/// Enters hibernate mode. Wake up sources should have been enable prior to
|
||||
/// calling this method.
|
||||
STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) {
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (!setup_timer_hibernate_wake()) {
|
||||
// hibernating is not possible, wait for the forced interrupt and return
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE;
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
wlan_stop(SL_STOP_TIMEOUT);
|
||||
pybsleep_flash_powerdown();
|
||||
// must be done just before entering hibernate mode
|
||||
pybsleep_iopark(true);
|
||||
MAP_PRCMHibernateEnter();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_hibernate_obj, pyb_sleep_hibernate);
|
||||
|
||||
/// \function reset_cause()
|
||||
/// Returns the last reset casue
|
||||
STATIC mp_obj_t pyb_sleep_reset_cause (mp_obj_t self_in) {
|
||||
return MP_OBJ_NEW_SMALL_INT(pybsleep_reset_cause);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_reset_cause_obj, pyb_sleep_reset_cause);
|
||||
|
||||
/// \function wake_reason()
|
||||
/// Returns the wake up reson from ldps or hibernate
|
||||
STATIC mp_obj_t pyb_sleep_wake_reason (mp_obj_t self_in) {
|
||||
return MP_OBJ_NEW_SMALL_INT(pybsleep_wake_reason);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_wake_reason_obj, pyb_sleep_wake_reason);
|
||||
|
||||
STATIC const mp_map_elem_t pybsleep_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&pyb_sleep_idle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_suspend), (mp_obj_t)&pyb_sleep_suspend_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hibernate), (mp_obj_t)&pyb_sleep_hibernate_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&pyb_sleep_reset_cause_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&pyb_sleep_wake_reason_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SUSPENDED), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIBERNATING), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIB_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pybsleep_locals_dict, pybsleep_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pybsleep_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Sleep,
|
||||
.locals_dict = (mp_obj_t)&pybsleep_locals_dict,
|
||||
};
|
||||
|
||||
const mp_obj_base_t pyb_sleep_obj = {&pybsleep_type};
|
||||
|
||||
@@ -54,23 +54,20 @@ typedef enum {
|
||||
|
||||
typedef void (*WakeUpCB_t)(const mp_obj_t self);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED VARIABLES
|
||||
******************************************************************************/
|
||||
extern const mp_obj_base_t pyb_sleep_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE FUNCTIONS
|
||||
******************************************************************************/
|
||||
void pybsleep_pre_init (void);
|
||||
void pybsleep_init0 (void);
|
||||
void pybsleep_signal_soft_reset (void);
|
||||
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
|
||||
void pybsleep_remove (const mp_obj_t obj);
|
||||
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_configure_timer_wakeup (uint pwrmode);
|
||||
pybsleep_reset_cause_t pybsleep_get_reset_cause (void);
|
||||
void pyb_sleep_pre_init (void);
|
||||
void pyb_sleep_init0 (void);
|
||||
void pyb_sleep_signal_soft_reset (void);
|
||||
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
|
||||
void pyb_sleep_remove (const mp_obj_t obj);
|
||||
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
|
||||
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj);
|
||||
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj);
|
||||
void pyb_sleep_sleep (void);
|
||||
void pyb_sleep_deepsleep (void);
|
||||
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void);
|
||||
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void);
|
||||
|
||||
#endif /* PYBSLEEP_H_ */
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/runtime.h"
|
||||
#include "bufhelper.h"
|
||||
#include "inc/hw_types.h"
|
||||
@@ -43,28 +42,11 @@
|
||||
#include "pybspi.h"
|
||||
#include "mpexception.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class SPI - a master-driven serial protocol
|
||||
///
|
||||
/// SPI is a serial protocol that is driven by a master. At the physical level
|
||||
/// there are 3 lines: SCK, MOSI, MISO.
|
||||
///
|
||||
/// See usage model of I2C; SPI is very similar. Main difference is
|
||||
/// parameters to init the SPI bus:
|
||||
///
|
||||
/// from pyb import SPI
|
||||
/// spi = SPI(1, SPI.MASTER, baudrate=2000000, bits=8, polarity=0, phase=0, nss=SPI.ACTIVE_LOW)
|
||||
///
|
||||
/// Only required parameter is the baudrate, in Hz. polarity and phase may be 0 or 1.
|
||||
/// Bit accepts 8, 16, 32. Chip select values are ACTIVE_LOW and ACTIVE_HIGH
|
||||
///
|
||||
/// Additional method for SPI:
|
||||
///
|
||||
/// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
|
||||
/// buf = bytearray(4)
|
||||
/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
|
||||
/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
@@ -73,10 +55,6 @@ typedef struct _pyb_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint baudrate;
|
||||
uint config;
|
||||
vstr_t tx_vstr;
|
||||
vstr_t rx_vstr;
|
||||
uint tx_index;
|
||||
uint rx_index;
|
||||
byte polarity;
|
||||
byte phase;
|
||||
byte submode;
|
||||
@@ -86,13 +64,15 @@ typedef struct _pyb_spi_obj_t {
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBSPI_DEF_BAUDRATE 1000000 // 1MHz
|
||||
#define PYBSPI_FIRST_BIT_MSB 0
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_spi_obj_t pyb_spi_obj = {.baudrate = 0};
|
||||
|
||||
STATIC const mp_obj_t pyb_spi_def_pin[3] = {&pin_GP14, &pin_GP16, &pin_GP30};
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
@@ -112,21 +92,19 @@ STATIC void pybspi_init (const pyb_spi_obj_t *self) {
|
||||
}
|
||||
|
||||
STATIC void pybspi_tx (pyb_spi_obj_t *self, const void *data) {
|
||||
uint32_t txdata = 0xFFFFFFFF;
|
||||
if (data) {
|
||||
switch (self->wlen) {
|
||||
case 1:
|
||||
txdata = (uint8_t)(*(char *)data);
|
||||
break;
|
||||
case 2:
|
||||
txdata = (uint16_t)(*(uint16_t *)data);
|
||||
break;
|
||||
case 4:
|
||||
txdata = (uint32_t)(*(uint32_t *)data);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
uint32_t txdata;
|
||||
switch (self->wlen) {
|
||||
case 1:
|
||||
txdata = (uint8_t)(*(char *)data);
|
||||
break;
|
||||
case 2:
|
||||
txdata = (uint16_t)(*(uint16_t *)data);
|
||||
break;
|
||||
case 4:
|
||||
txdata = (uint32_t)(*(uint32_t *)data);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
MAP_SPIDataPut (GSPI_BASE, txdata);
|
||||
}
|
||||
@@ -151,11 +129,14 @@ STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len) {
|
||||
STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len, uint32_t *txchar) {
|
||||
if (!self->baudrate) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
// send and receive the data
|
||||
MAP_SPICSEnable(GSPI_BASE);
|
||||
for (int i = 0; i < len / self->wlen; i += self->wlen) {
|
||||
pybspi_tx(self, txdata ? (const void *)&txdata[i] : NULL);
|
||||
for (int i = 0; i < len; i += self->wlen) {
|
||||
pybspi_tx(self, txdata ? (const void *)&txdata[i] : txchar);
|
||||
pybspi_rx(self, rxdata ? (void *)&rxdata[i] : NULL);
|
||||
}
|
||||
MAP_SPICSDisable(GSPI_BASE);
|
||||
@@ -166,41 +147,15 @@ STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxda
|
||||
/******************************************************************************/
|
||||
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_spi_obj_t *self = self_in;
|
||||
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "<SPI1, SPI.MASTER, baudrate=%u, bits=%u, polarity=%u, phase=%u, nss=%q>",
|
||||
self->baudrate, (self->wlen * 8), self->polarity, self->phase,
|
||||
(self->config & SPI_CS_ACTIVELOW) ? MP_QSTR_ACTIVE_LOW : MP_QSTR_ACTIVE_HIGH);
|
||||
}
|
||||
else {
|
||||
mp_print_str(print, "<SPI1>");
|
||||
mp_printf(print, "SPI(0, SPI.MASTER, baudrate=%u, bits=%u, polarity=%u, phase=%u, firstbit=SPI.MSB)",
|
||||
self->baudrate, (self->wlen * 8), self->polarity, self->phase);
|
||||
} else {
|
||||
mp_print_str(print, "SPI(0)");
|
||||
}
|
||||
}
|
||||
|
||||
/// \method init(mode, *, baudrate=1000000, bits=8, polarity=0, phase=0, nss=SPI.ACTIVELOW)
|
||||
///
|
||||
/// Initialise the SPI bus with the given parameters:
|
||||
///
|
||||
/// - `mode` must be MASTER.
|
||||
/// - `baudrate` is the SCK clock rate.
|
||||
/// - `bits` is the transfer width size (8, 16, 32).
|
||||
/// - `polarity` (0, 1).
|
||||
/// - `phase` (0, 1).
|
||||
/// - `nss` can be ACTIVE_LOW or ACTIVE_HIGH.
|
||||
static const mp_arg_t pybspi_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBSPI_DEF_BAUDRATE} },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_nss, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_CS_ACTIVELOW} },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pybspi_init_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(pybspi_init_args), pybspi_init_args, args);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *args) {
|
||||
// verify that mode is master
|
||||
if (args[0].u_int != SPI_MODE_MASTER) {
|
||||
goto invalid_args;
|
||||
@@ -228,24 +183,37 @@ STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, mp_uint_t n_args, const
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
uint nss = args[5].u_int;
|
||||
if (nss != SPI_CS_ACTIVELOW && nss != SPI_CS_ACTIVEHIGH) {
|
||||
uint firstbit = args[5].u_int;
|
||||
if (firstbit != PYBSPI_FIRST_BIT_MSB) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// build the configuration
|
||||
self->baudrate = args[1].u_int;
|
||||
self->wlen = args[2].u_int >> 3;
|
||||
self->config = bits | nss | SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF;
|
||||
self->config = bits | SPI_CS_ACTIVELOW | SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF;
|
||||
self->polarity = polarity;
|
||||
self->phase = phase;
|
||||
self->submode = (polarity << 1) | phase;
|
||||
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[6].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_spi_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, 3, &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, 3, PIN_TYPE_STD_PU, PIN_FN_SPI, 0);
|
||||
}
|
||||
|
||||
// init the bus
|
||||
pybspi_init((const pyb_spi_obj_t *)self);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
|
||||
pyb_sleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -253,33 +221,43 @@ invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
/// \classmethod \constructor(bus, ...)
|
||||
///
|
||||
/// Construct an SPI object with the given baudrate. Bus can only be 1.
|
||||
/// With no extra parameters, the SPI object is created but not
|
||||
/// initialised (it has the settings from the last initialisation of
|
||||
/// the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
/// See `init` for parameters of initialisation.
|
||||
///
|
||||
STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
static const mp_arg_t pyb_spi_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = SPI_MODE_MASTER} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000000} }, // 1MHz
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBSPI_FIRST_BIT_MSB} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_spi_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_spi_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_spi_obj_t *self = &pyb_spi_obj;
|
||||
self->base.type = &pyb_spi_type;
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// start the peripheral
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_spi_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
// start the peripheral
|
||||
pyb_spi_init_helper(self, &args[1]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_spi_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pyb_spi_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
STATIC mp_obj_t pyb_spi_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_spi_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_spi_init_args[1], args);
|
||||
return pyb_spi_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
|
||||
|
||||
@@ -292,128 +270,117 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
|
||||
// invalidate the baudrate
|
||||
pyb_spi_obj.baudrate = 0;
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove((const mp_obj_t)self_in);
|
||||
pyb_sleep_remove((const mp_obj_t)self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);
|
||||
|
||||
/// \method send(send)
|
||||
/// Send data on the bus:
|
||||
///
|
||||
/// - `send` is the data to send (a byte to send, or a buffer object).
|
||||
///
|
||||
STATIC mp_obj_t pyb_spi_send (mp_obj_t self_in, mp_obj_t send_o) {
|
||||
STATIC mp_obj_t pyb_spi_write (mp_obj_t self_in, mp_obj_t buf) {
|
||||
// parse args
|
||||
pyb_spi_obj_t *self = self_in;
|
||||
|
||||
// get the buffer to send from
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint8_t data[1];
|
||||
pyb_buf_get_for_send(send_o, &bufinfo, data);
|
||||
pyb_buf_get_for_send(buf, &bufinfo, data);
|
||||
|
||||
// just send
|
||||
pybspi_transfer(self, (const char *)bufinfo.buf, NULL, bufinfo.len);
|
||||
pybspi_transfer(self, (const char *)bufinfo.buf, NULL, bufinfo.len, NULL);
|
||||
|
||||
return mp_const_none;
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_send_obj, pyb_spi_send);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
pyb_spi_obj_t *self = pos_args[0];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
|
||||
|
||||
/// \method recv(recv)
|
||||
///
|
||||
/// Receive data on the bus:
|
||||
///
|
||||
/// - `recv` can be an integer, which is the number of bytes to receive,
|
||||
/// or a mutable buffer, which will be filled with received bytes.
|
||||
///
|
||||
/// Return: if `recv` is an integer then a new buffer of the bytes received,
|
||||
/// otherwise the same buffer that was passed in to `recv`.
|
||||
STATIC mp_obj_t pyb_spi_recv(mp_obj_t self_in, mp_obj_t recv_o) {
|
||||
pyb_spi_obj_t *self = self_in;
|
||||
// get the buffer to receive into
|
||||
vstr_t vstr;
|
||||
mp_obj_t o_ret = pyb_buf_get_for_recv(recv_o, &vstr);
|
||||
pyb_buf_get_for_recv(args[0].u_obj, &vstr);
|
||||
|
||||
// just receive
|
||||
pybspi_transfer(self, NULL, vstr.buf, vstr.len);
|
||||
uint32_t write = args[1].u_int;
|
||||
pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write);
|
||||
|
||||
// return the received data
|
||||
if (o_ret != MP_OBJ_NULL) {
|
||||
return o_ret;
|
||||
} else {
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_recv_obj, pyb_spi_recv);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_read_obj, 1, pyb_spi_read);
|
||||
|
||||
/// \method send_recv(send, recv)
|
||||
///
|
||||
/// Send and receive data on the bus at the same time:
|
||||
///
|
||||
/// - `send` is the data to send (an integer to send, or a buffer object).
|
||||
/// - `recv` is a mutable buffer which will be filled with received bytes.
|
||||
/// It can be the same as `send`, or omitted. If omitted, a new buffer will
|
||||
/// be created.
|
||||
///
|
||||
/// Return: the buffer with the received bytes.
|
||||
STATIC mp_obj_t pyb_spi_send_recv (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_spi_obj_t *self = args[0];
|
||||
STATIC mp_obj_t pyb_spi_readinto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} },
|
||||
};
|
||||
|
||||
// get buffers to send from/receive to
|
||||
mp_buffer_info_t bufinfo_send;
|
||||
// parse args
|
||||
pyb_spi_obj_t *self = pos_args[0];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
|
||||
|
||||
// get the buffer to receive into
|
||||
vstr_t vstr;
|
||||
pyb_buf_get_for_recv(args[0].u_obj, &vstr);
|
||||
|
||||
// just receive
|
||||
uint32_t write = args[1].u_int;
|
||||
pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write);
|
||||
|
||||
// return the number of bytes received
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_readinto_obj, 1, pyb_spi_readinto);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write_readinto (mp_obj_t self, mp_obj_t writebuf, mp_obj_t readbuf) {
|
||||
// get buffers to write from/read to
|
||||
mp_buffer_info_t bufinfo_write;
|
||||
uint8_t data_send[1];
|
||||
mp_buffer_info_t bufinfo_recv;
|
||||
vstr_t vstr_recv;
|
||||
mp_obj_t o_ret;
|
||||
mp_buffer_info_t bufinfo_read;
|
||||
|
||||
if (args[1] == args[2]) {
|
||||
// same object for sending and receiving, it must be a r/w buffer
|
||||
mp_get_buffer_raise(args[1], &bufinfo_send, MP_BUFFER_RW);
|
||||
bufinfo_recv = bufinfo_send;
|
||||
o_ret = args[1];
|
||||
if (writebuf == readbuf) {
|
||||
// same object for writing and reading, it must be a r/w buffer
|
||||
mp_get_buffer_raise(writebuf, &bufinfo_write, MP_BUFFER_RW);
|
||||
bufinfo_read = bufinfo_write;
|
||||
} else {
|
||||
// get the buffer to send from
|
||||
pyb_buf_get_for_send(args[1], &bufinfo_send, data_send);
|
||||
// get the buffer to write from
|
||||
pyb_buf_get_for_send(writebuf, &bufinfo_write, data_send);
|
||||
|
||||
// get the buffer to receive into
|
||||
if (n_args == 2) {
|
||||
// only the send was argument given, so create a fresh buffer of the send length
|
||||
vstr_init_len(&vstr_recv, bufinfo_send.len);
|
||||
bufinfo_recv.len = vstr_recv.len;
|
||||
bufinfo_recv.buf = vstr_recv.buf;
|
||||
o_ret = MP_OBJ_NULL;
|
||||
}
|
||||
else {
|
||||
// recv argument given
|
||||
mp_get_buffer_raise(args[2], &bufinfo_recv, MP_BUFFER_WRITE);
|
||||
if (bufinfo_recv.len != bufinfo_send.len) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
o_ret = args[2];
|
||||
// get the read buffer
|
||||
mp_get_buffer_raise(readbuf, &bufinfo_read, MP_BUFFER_WRITE);
|
||||
if (bufinfo_read.len != bufinfo_write.len) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
}
|
||||
|
||||
// send and receive
|
||||
pybspi_transfer(self, (const char *)bufinfo_send.buf, vstr_recv.buf, bufinfo_send.len);
|
||||
pybspi_transfer(self, (const char *)bufinfo_write.buf, bufinfo_read.buf, bufinfo_write.len, NULL);
|
||||
|
||||
// return the received data
|
||||
if (o_ret != MP_OBJ_NULL) {
|
||||
return o_ret;
|
||||
} else {
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr_recv);
|
||||
}
|
||||
// return the number of transferred bytes
|
||||
return mp_obj_new_int(bufinfo_write.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_send_recv_obj, 2, 3, pyb_spi_send_recv);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_spi_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_spi_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_spi_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_spi_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_spi_write_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_spi_read_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&pyb_spi_readinto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write_readinto), (mp_obj_t)&pyb_spi_write_readinto_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE_LOW), MP_OBJ_NEW_SMALL_INT(SPI_CS_ACTIVELOW) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE_HIGH), MP_OBJ_NEW_SMALL_INT(SPI_CS_ACTIVEHIGH) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MSB), MP_OBJ_NEW_SMALL_INT(PYBSPI_FIRST_BIT_MSB) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table);
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
@@ -43,9 +43,12 @@
|
||||
#include "interrupt.h"
|
||||
#include "prcm.h"
|
||||
#include "timer.h"
|
||||
#include "pin.h"
|
||||
#include "pybtimer.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
@@ -55,30 +58,8 @@
|
||||
/// Each timer consists of a counter that counts up at a certain rate. The rate
|
||||
/// at which it counts is the peripheral clock frequency (in Hz) divided by the
|
||||
/// timer prescaler. When the counter reaches the timer period it triggers an
|
||||
/// event, and the counter resets back to zero. By using the callback method,
|
||||
/// event, and the counter resets back to zero. By using the irq method,
|
||||
/// the timer event can call a Python function.
|
||||
///
|
||||
/// Example usage to toggle an LED at a fixed frequency:
|
||||
///
|
||||
/// tim = pyb.Timer(4) # create a timer object using timer 4
|
||||
/// tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
|
||||
/// tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
|
||||
/// tim_ch.callback(handler=lambda t:led.toggle()) # toggle a led on every cycle of the timer
|
||||
///
|
||||
/// Further examples:
|
||||
///
|
||||
/// tim1 = pyb.Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
|
||||
/// tim2 = pyb.Timer(1, mode=Timer.PWM) # initialize it in PWM mode
|
||||
/// tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
|
||||
/// tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
|
||||
/// tim_ch.time() # get the current time in usec (can also be set)
|
||||
/// tim_ch.freq(20) # set the frequency (can also get)
|
||||
/// tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
|
||||
/// tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
|
||||
/// tim_ch.event_count() # get the number of captured events
|
||||
/// tim_ch.event_time() # get the the time of the last captured event
|
||||
/// tim_ch.period(2000000) # change the period to 2 seconds
|
||||
///
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
@@ -87,6 +68,9 @@
|
||||
#define PYBTIMER_POLARITY_POS (0x01)
|
||||
#define PYBTIMER_POLARITY_NEG (0x02)
|
||||
|
||||
#define PYBTIMER_TIMEOUT_TRIGGER (0x01)
|
||||
#define PYBTIMER_MATCH_TRIGGER (0x02)
|
||||
|
||||
#define PYBTIMER_SRC_FREQ_HZ HAL_FCPU_HZ
|
||||
|
||||
/******************************************************************************
|
||||
@@ -96,7 +80,8 @@ typedef struct _pyb_timer_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t timer;
|
||||
uint32_t config;
|
||||
uint16_t intflags;
|
||||
uint16_t irq_trigger;
|
||||
uint16_t irq_flags;
|
||||
uint8_t peripheral;
|
||||
uint8_t id;
|
||||
} pyb_timer_obj_t;
|
||||
@@ -107,25 +92,27 @@ typedef struct _pyb_timer_channel_obj_t {
|
||||
uint32_t frequency;
|
||||
uint32_t period;
|
||||
uint16_t channel;
|
||||
uint16_t duty_cycle;
|
||||
uint8_t polarity;
|
||||
uint8_t duty_cycle;
|
||||
} pyb_timer_channel_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods;
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods;
|
||||
STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0},
|
||||
{.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1},
|
||||
{.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2},
|
||||
{.timer = TIMERA3_BASE, .peripheral = PRCM_TIMERA3}};
|
||||
STATIC const mp_obj_type_t pyb_timer_channel_type;
|
||||
STATIC const mp_obj_t pyb_timer_pwm_pin[8] = {&pin_GP24, MP_OBJ_NULL, &pin_GP25, MP_OBJ_NULL, MP_OBJ_NULL, &pin_GP9, &pin_GP10, &pin_GP11};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim);
|
||||
STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch);
|
||||
STATIC void TIMER0AIntHandler(void);
|
||||
STATIC void TIMER0BIntHandler(void);
|
||||
STATIC void TIMER1AIntHandler(void);
|
||||
@@ -142,38 +129,26 @@ void timer_init0 (void) {
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0);
|
||||
}
|
||||
|
||||
void timer_disable_all (void) {
|
||||
pyb_timer_obj_t timer = {
|
||||
.timer = TIMERA0_BASE,
|
||||
.intflags = TIMER_CAPB_EVENT | TIMER_CAPB_MATCH |
|
||||
TIMER_TIMB_TIMEOUT | TIMER_CAPA_EVENT |
|
||||
TIMER_CAPA_MATCH | TIMER_TIMA_TIMEOUT,
|
||||
.peripheral = PRCM_TIMERA0
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < PYBTIMER_NUM_TIMERS; i++) {
|
||||
// in case it's not clocked
|
||||
MAP_PRCMPeripheralClkEnable(timer.peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
timer_disable(&timer);
|
||||
// timer base offset according to hw_memmap.h
|
||||
timer.timer += 0x1000;
|
||||
// peripheral offset according to prcm.h
|
||||
timer.peripheral++;
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_timer_channel_callback_enable (mp_obj_t self_in) {
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
void pyb_timer_channel_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
return self->timer->irq_flags;
|
||||
}
|
||||
|
||||
STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) {
|
||||
pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i]));
|
||||
// any 32-bit timer must be matched by any of its 16-bit versions
|
||||
@@ -184,26 +159,37 @@ pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channe
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
pyb_timer_channel_obj_t *channel;
|
||||
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove((const mp_obj_t)channel);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
// remove it in case it already exists
|
||||
pyb_timer_channel_remove(ch);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
|
||||
}
|
||||
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim) {
|
||||
// disable all timers and it's interrupts
|
||||
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
|
||||
MAP_TimerIntDisable(tim->timer, tim->intflags);
|
||||
MAP_TimerIntClear(tim->timer, tim->intflags);
|
||||
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
|
||||
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
|
||||
pyb_timer_channel_obj_t *ch;
|
||||
// disable its channels
|
||||
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_A))) {
|
||||
pyb_sleep_remove(ch);
|
||||
}
|
||||
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_B))) {
|
||||
pyb_sleep_remove(ch);
|
||||
}
|
||||
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t));
|
||||
}
|
||||
|
||||
// computes prescaler period and match value so timer triggers at freq-Hz
|
||||
@@ -216,20 +202,23 @@ STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t
|
||||
if (period_c == 0) {
|
||||
goto error;
|
||||
}
|
||||
prescaler = period_c >> 16;
|
||||
|
||||
prescaler = period_c >> 16; // The prescaler is an extension of the timer counter
|
||||
*period_out = period_c;
|
||||
|
||||
if (prescaler > 0xFF && maxcount == 0xFFFF) {
|
||||
goto error;
|
||||
}
|
||||
// check limit values for the duty cycle
|
||||
if (ch->duty_cycle == 0) {
|
||||
*match_out = period_c - 1;
|
||||
}
|
||||
else {
|
||||
*match_out = period_c - ((period_c * ch->duty_cycle) / 100);
|
||||
}
|
||||
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM && (*match_out > 0xFFFF)) {
|
||||
goto error;
|
||||
} else {
|
||||
if (period_c > 0xFFFF) {
|
||||
uint32_t match = (period_c * 100) / 10000;
|
||||
*match_out = period_c - ((match * ch->duty_cycle) / 100);
|
||||
} else {
|
||||
*match_out = period_c - ((period_c * ch->duty_cycle) / 10000);
|
||||
}
|
||||
}
|
||||
return prescaler;
|
||||
|
||||
@@ -261,17 +250,7 @@ STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch) {
|
||||
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
|
||||
// set the match value (which is simply the duty cycle translated to ticks)
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
|
||||
}
|
||||
// configure the event edge type if we are in such mode
|
||||
else if ((ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_COUNT || (ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_TIME) {
|
||||
uint32_t polarity = TIMER_EVENT_BOTH_EDGES;
|
||||
if (ch->polarity == PYBTIMER_POLARITY_POS) {
|
||||
polarity = TIMER_EVENT_POS_EDGE;
|
||||
}
|
||||
else if (ch->polarity == PYBTIMER_POLARITY_NEG) {
|
||||
polarity = TIMER_EVENT_NEG_EDGE;
|
||||
}
|
||||
MAP_TimerControlEvent(ch->timer->timer, ch->channel, polarity);
|
||||
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -293,40 +272,22 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
|
||||
// timer mode
|
||||
qstr mode_qst = MP_QSTR_PWM;
|
||||
switch(mode) {
|
||||
case TIMER_CFG_A_ONE_SHOT:
|
||||
case TIMER_CFG_A_ONE_SHOT_UP:
|
||||
mode_qst = MP_QSTR_ONE_SHOT;
|
||||
break;
|
||||
case TIMER_CFG_A_PERIODIC:
|
||||
case TIMER_CFG_A_PERIODIC_UP:
|
||||
mode_qst = MP_QSTR_PERIODIC;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_COUNT:
|
||||
mode_qst = MP_QSTR_EDGE_COUNT;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_TIME:
|
||||
mode_qst = MP_QSTR_EDGE_TIME;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mp_printf(print, "<Timer%u, mode=Timer.%q>", (tim->id + 1), mode_qst);
|
||||
mp_printf(print, "Timer(%u, mode=Timer.%q)", tim->id, mode_qst);
|
||||
}
|
||||
|
||||
/// \method init(mode, *, width)
|
||||
/// Initialise the timer. Initialisation must give the desired mode
|
||||
/// and an optional timer width
|
||||
///
|
||||
/// tim.init(mode=Timer.PERIODIC) # configure in free running periodic mode
|
||||
/// tim.init(mode=Timer.ONE_SHOT, width=16) # one shot mode splitted into two 16-bit independent timers
|
||||
///
|
||||
/// Keyword arguments:
|
||||
///
|
||||
/// - `width` - specifies the width of the timer. Default is 32 bit mode. When in 16 bit mode
|
||||
/// the timer is splitted into 2 independent channels.
|
||||
///
|
||||
STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
||||
{ MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
@@ -335,8 +296,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
|
||||
|
||||
// check the mode
|
||||
uint32_t _mode = args[0].u_int;
|
||||
if (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC && _mode != TIMER_CFG_A_CAP_COUNT &&
|
||||
_mode != TIMER_CFG_A_CAP_TIME && _mode != TIMER_CFG_A_PWM) {
|
||||
if (_mode != TIMER_CFG_A_ONE_SHOT_UP && _mode != TIMER_CFG_A_PERIODIC_UP && _mode != TIMER_CFG_A_PWM) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -346,7 +306,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
|
||||
}
|
||||
bool is16bit = (args[1].u_int == 16);
|
||||
|
||||
if (!is16bit && (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC)) {
|
||||
if (!is16bit && _mode == TIMER_CFG_A_PWM) {
|
||||
// 32-bit mode is only available when in free running modes
|
||||
goto error;
|
||||
}
|
||||
@@ -354,7 +314,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
|
||||
|
||||
timer_init(tim);
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
|
||||
pyb_sleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -362,16 +322,12 @@ error:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
/// \classmethod \constructor(id, ...)
|
||||
/// Construct a new timer object of the given id. If additional
|
||||
/// arguments are given, then the timer is initialised by `init(...)`.
|
||||
/// `id` can be 1 to 4
|
||||
STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// create a new Timer object
|
||||
int32_t timer_idx = mp_obj_get_int(args[0]) - 1;
|
||||
int32_t timer_idx = mp_obj_get_int(args[0]);
|
||||
if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
@@ -389,15 +345,11 @@ STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
|
||||
return (mp_obj_t)tim;
|
||||
}
|
||||
|
||||
// \method init()
|
||||
/// initializes the timer
|
||||
STATIC mp_obj_t pyb_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
|
||||
|
||||
// \method deinit()
|
||||
/// disables the timer
|
||||
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
|
||||
pyb_timer_obj_t *self = self_in;
|
||||
timer_disable(self);
|
||||
@@ -405,24 +357,6 @@ STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
||||
|
||||
/// \method channel(channel, *, freq, polarity, duty_cycle)
|
||||
/// Initialise the timer channel. Initialization requires at least a frequency param. With no
|
||||
/// extra params given besides the channel id, the channel is returned with the previous configuration
|
||||
/// os 'None', if it hasn't been initialized before.
|
||||
///
|
||||
/// tim1.channel(Timer.A, freq=1000) # set channel A frequency to 1KHz
|
||||
/// tim2.channel(Timer.AB, freq=10) # both channels (because it's a 32 bit timer) combined to create a 10Hz timer
|
||||
///
|
||||
/// when initialiazing the channel of a 32-bit timer, channel ID MUST be = Timer.AB
|
||||
///
|
||||
/// Keyword arguments:
|
||||
///
|
||||
/// - `freq` - specifies the frequency in Hz.
|
||||
/// - `period` - specifies the period in microseconds.
|
||||
/// - `polarity` - in PWM specifies the polarity of the pulse. In capture mode specifies the edge to capture.
|
||||
/// in order to capture on both negative and positive edges, make it = Timer.POSITIVE | Timer.NEGATIVE.
|
||||
/// - `duty_cycle` - sets the duty cycle value
|
||||
///
|
||||
STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
@@ -484,12 +418,21 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
|
||||
ch->frequency = args[0].u_int;
|
||||
ch->period = args[1].u_int;
|
||||
ch->polarity = args[2].u_int;
|
||||
ch->duty_cycle = MIN(100, MAX(0, args[3].u_int));
|
||||
ch->duty_cycle = MIN(10000, MAX(0, args[3].u_int));
|
||||
|
||||
timer_channel_init(ch);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
|
||||
// assign the pin
|
||||
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) {
|
||||
uint32_t ch_idx = (ch->channel == TIMER_A) ? 0 : 1;
|
||||
// use the default pin if available
|
||||
mp_obj_t pin_o = (mp_obj_t)pyb_timer_pwm_pin[(ch->timer->id * 2) + ch_idx];
|
||||
if (pin_o != MP_OBJ_NULL) {
|
||||
pin_obj_t *pin = pin_find(pin_o);
|
||||
pin_config (pin, pin_find_af_index(pin, PIN_FN_TIM, ch->timer->id, PIN_TYPE_TIM_PWM),
|
||||
0, PIN_TYPE_STD, -1, PIN_STRENGTH_4MA);
|
||||
}
|
||||
}
|
||||
|
||||
// add the timer to the list
|
||||
pyb_timer_channel_add(ch);
|
||||
@@ -510,13 +453,13 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_A), MP_OBJ_NEW_SMALL_INT(TIMER_A) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_B), MP_OBJ_NEW_SMALL_INT(TIMER_B) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_COUNT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_COUNT) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_TIME), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_TIME) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT_UP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC_UP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWM), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PWM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POSITIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_POS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_NEGATIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_NEG) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_TIMEOUT), MP_OBJ_NEW_SMALL_INT(PYBTIMER_TIMEOUT_TRIGGER) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MATCH), MP_OBJ_NEW_SMALL_INT(PYBTIMER_MATCH_TRIGGER) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
|
||||
|
||||
@@ -528,21 +471,20 @@ const mp_obj_type_t pyb_timer_type = {
|
||||
.locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods = {
|
||||
.init = pyb_timer_channel_callback,
|
||||
.enable = pyb_timer_channel_callback_enable,
|
||||
.disable = pyb_timer_channel_callback_disable,
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
|
||||
.init = pyb_timer_channel_irq,
|
||||
.enable = pyb_timer_channel_irq_enable,
|
||||
.disable = pyb_timer_channel_irq_disable,
|
||||
.flags = pyb_timer_channel_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
|
||||
pyb_timer_channel_obj_t *self;
|
||||
uint32_t status;
|
||||
|
||||
if ((self = pyb_timer_channel_find(timer, channel))) {
|
||||
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
|
||||
MAP_TimerIntClear(self->timer->timer, status);
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,16 +526,14 @@ STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, m
|
||||
// timer channel
|
||||
if (ch->channel == TIMER_A) {
|
||||
ch_id = "A";
|
||||
}
|
||||
else if (ch->channel == TIMER_B) {
|
||||
} else if (ch->channel == TIMER_B) {
|
||||
ch_id = "B";
|
||||
}
|
||||
|
||||
mp_printf(print, "<%q %s, timer=%u, %q=%u", MP_QSTR_TimerChannel,
|
||||
ch_id, (ch->timer->id + 1), MP_QSTR_freq, ch->frequency);
|
||||
mp_printf(print, "timer.channel(Timer.%s, %q=%u", ch_id, MP_QSTR_freq, ch->frequency);
|
||||
|
||||
uint32_t mode = ch->timer->config & 0xFF;
|
||||
if (mode == TIMER_CFG_A_CAP_COUNT || mode == TIMER_CFG_A_CAP_TIME || mode == TIMER_CFG_A_PWM) {
|
||||
if (mode == TIMER_CFG_A_PWM) {
|
||||
mp_printf(print, ", %q=Timer.", MP_QSTR_polarity);
|
||||
switch (ch->polarity) {
|
||||
case PYBTIMER_POLARITY_POS:
|
||||
@@ -606,15 +546,11 @@ STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, m
|
||||
mp_printf(print, "BOTH");
|
||||
break;
|
||||
}
|
||||
if (mode == TIMER_CFG_A_PWM) {
|
||||
mp_printf(print, ", %q=%u", MP_QSTR_duty_cycle, ch->duty_cycle);
|
||||
}
|
||||
mp_printf(print, ", %q=%u.%02u", MP_QSTR_duty_cycle, ch->duty_cycle / 100, ch->duty_cycle % 100);
|
||||
}
|
||||
mp_printf(print, ">");
|
||||
mp_printf(print, ")");
|
||||
}
|
||||
|
||||
/// \method freq([value])
|
||||
/// get or set the frequency of the timer channel
|
||||
STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
if (n_args == 1) {
|
||||
@@ -634,8 +570,6 @@ STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_freq_obj, 1, 2, pyb_timer_channel_freq);
|
||||
|
||||
/// \method period([value])
|
||||
/// get or set the period of the timer channel in microseconds
|
||||
STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
if (n_args == 1) {
|
||||
@@ -655,74 +589,17 @@ STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args)
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_period_obj, 1, 2, pyb_timer_channel_period);
|
||||
|
||||
/// \method time([value])
|
||||
/// get or set the value of the timer channel in microseconds
|
||||
STATIC mp_obj_t pyb_timer_channel_time(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
uint32_t value;
|
||||
// calculate the period, the prescaler and the match value
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
(void)compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
value = (ch->channel == TIMER_B) ? HWREG(ch->timer->timer + TIMER_O_TBV) : HWREG(ch->timer->timer + TIMER_O_TAV);
|
||||
// return the current timer value in microseconds
|
||||
// substract value to period since we are always operating in count-down mode
|
||||
uint32_t time_t = (1000 * (period_c - value)) / period_c;
|
||||
return mp_obj_new_int((time_t * 1000) / ch->frequency);
|
||||
}
|
||||
else {
|
||||
// set
|
||||
value = (mp_obj_get_int(args[1]) * ((ch->frequency * period_c) / 1000)) / 1000;
|
||||
if ((value > 0xFFFF) && (ch->timer->config & TIMER_CFG_SPLIT_PAIR)) {
|
||||
// this exceeds the maximum value of a 16-bit timer
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
// write period minus value since we are always operating in count-down mode
|
||||
TimerValueSet (ch->timer->timer, ch->channel, (period_c - value));
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_time_obj, 1, 2, pyb_timer_channel_time);
|
||||
|
||||
/// \method event_count()
|
||||
/// get the number of events triggered by the configured edge
|
||||
STATIC mp_obj_t pyb_timer_channel_event_count(mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *ch = self_in;
|
||||
return mp_obj_new_int(MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_count_obj, pyb_timer_channel_event_count);
|
||||
|
||||
/// \method event_time()
|
||||
/// get the time at which the last event was triggered
|
||||
STATIC mp_obj_t pyb_timer_channel_event_time(mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *ch = self_in;
|
||||
// calculate the period, the prescaler and the match value
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
(void)compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
uint32_t value = MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel);
|
||||
// substract value to period since we are always operating in count-down mode
|
||||
uint32_t time_t = (1000 * (period_c - value)) / period_c;
|
||||
return mp_obj_new_int((time_t * 1000) / ch->frequency);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_time_obj, pyb_timer_channel_event_time);
|
||||
|
||||
/// \method duty_cycle()
|
||||
/// get or set the duty cycle when in PWM mode
|
||||
STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
return mp_obj_new_int(ch->duty_cycle);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// duty cycle must be converted from percentage to ticks
|
||||
// calculate the period, the prescaler and the match value
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
ch->duty_cycle = MIN(100, MAX(0, mp_obj_get_int(args[1])));
|
||||
ch->duty_cycle = MIN(10000, MAX(0, mp_obj_get_int(args[1])));
|
||||
compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
if (n_args == 3) {
|
||||
// set the new polarity if requested
|
||||
@@ -730,140 +607,121 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
|
||||
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
|
||||
}
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
|
||||
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
|
||||
|
||||
/// \method callback(handler, value, priority)
|
||||
/// create a callback object associated with the timer channel
|
||||
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_timer_channel_obj_t *ch = pos_args[0];
|
||||
mp_obj_t _callback = mpcallback_find(ch);
|
||||
if (kw_args->used > 0 || !_callback) {
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
|
||||
// validate the power mode
|
||||
uint pwrmode = args[4].u_int;
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// validate the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the trigger
|
||||
uint trigger = mp_obj_get_int(args[0].u_obj);
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_irq_disable(ch);
|
||||
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT_UP:
|
||||
case TIMER_CFG_A_PERIODIC_UP:
|
||||
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
|
||||
if (trigger != PYBTIMER_TIMEOUT_TRIGGER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_callback_disable(ch);
|
||||
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT:
|
||||
case TIMER_CFG_A_PERIODIC:
|
||||
ch->timer->intflags |= TIMER_TIMA_TIMEOUT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_COUNT:
|
||||
ch->timer->intflags |= TIMER_CAPA_MATCH << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_TIME:
|
||||
ch->timer->intflags |= TIMER_CAPA_EVENT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the match interrupt
|
||||
ch->timer->intflags |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the PWM match interrupt
|
||||
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
if (trigger != PYBTIMER_MATCH_TRIGGER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
// again a special case for the pwm match interrupt
|
||||
if (_config == TIMER_CFG_A_PWM) {
|
||||
ch->timer->intflags |= TIMER_TIMB_MATCH;
|
||||
} else {
|
||||
ch->timer->intflags |= (ch->timer->intflags << 8);
|
||||
}
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
_callback = mpcallback_new (ch, args[1].u_obj, &pyb_timer_channel_cb_methods);
|
||||
|
||||
// get the value if given
|
||||
uint32_t c_value = MAX(0, args[3].u_int);
|
||||
ch->duty_cycle = MIN(100, c_value);
|
||||
|
||||
// reload the timer
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c);
|
||||
// set the appropiate match value
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, (_config == TIMER_CFG_A_PWM) ? match : c_value);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_callback_enable(ch);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return _callback;
|
||||
// special case for a 32-bit timer
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8);
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_irq_enable(ch);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_callback_obj, 1, pyb_timer_channel_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_timer_channel_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_period), (mp_obj_t)&pyb_timer_channel_period_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&pyb_timer_channel_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_count), (mp_obj_t)&pyb_timer_channel_event_count_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_time), (mp_obj_t)&pyb_timer_channel_event_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
|
||||
|
||||
|
||||
@@ -34,5 +34,4 @@ extern const mp_obj_type_t pyb_timer_type;
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void timer_init0 (void);
|
||||
void timer_disable_all (void);
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
@@ -45,64 +45,51 @@
|
||||
#include "prcm.h"
|
||||
#include "uart.h"
|
||||
#include "pybuart.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybioctl.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "osi.h"
|
||||
#include "utils.h"
|
||||
#include "pin.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
#include "moduos.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class UART - duplex serial communication bus
|
||||
///
|
||||
/// UART implements the standard UART/USART duplex serial communications protocol. At
|
||||
/// the physical level it consists of 2 lines: RX and TX.
|
||||
///
|
||||
/// UART objects can be created and initialised using:
|
||||
///
|
||||
/// from pyb import UART
|
||||
///
|
||||
/// uart = UART(1, 9600) # init with given baudrate
|
||||
/// uart.init(9600, bits=8, stop=1, parity=None) # init with given parameters
|
||||
///
|
||||
/// Bits can be 5, 6, 7, 8, parity can be None, 0 (even), 1 (odd). Stop can be 1 or 2.
|
||||
///
|
||||
/// A UART object acts like a stream object and reading and writing is done
|
||||
/// using the standard stream methods:
|
||||
///
|
||||
/// uart.read(10) # read 10 characters, returns a bytes object
|
||||
/// uart.readall() # read all available characters
|
||||
/// uart.readline() # read a line
|
||||
/// uart.readinto(buf) # read and store into the given buffer
|
||||
/// uart.write('abc') # write the 3 characters
|
||||
///
|
||||
/// Individual characters can be read/written using:
|
||||
///
|
||||
/// uart.readchar() # read 1 character and returns it as an integer
|
||||
/// uart.writechar(42) # write 1 character
|
||||
///
|
||||
/// To check if there is anything to be read, use:
|
||||
///
|
||||
/// uart.any() # returns True if any characters waiting
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBUART_TX_WAIT_MS 1
|
||||
#define PYBUART_TX_MAX_TIMEOUT_MS 5
|
||||
*******-***********************************************************************/
|
||||
#define PYBUART_FRAME_TIME_US(baud) ((11 * 1000000) / baud)
|
||||
#define PYBUART_2_FRAMES_TIME_US(baud) (PYBUART_FRAME_TIME_US(baud) * 2)
|
||||
#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud) * 8) // we need at least characters in the FIFO
|
||||
|
||||
#define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1)
|
||||
#define PYBUART_TX_MAX_TIMEOUT_MS (5)
|
||||
|
||||
#define PYBUART_RX_BUFFER_LEN (256)
|
||||
|
||||
// interrupt triggers
|
||||
#define UART_TRIGGER_RX_ANY (0x01)
|
||||
#define UART_TRIGGER_RX_HALF (0x02)
|
||||
#define UART_TRIGGER_RX_FULL (0x04)
|
||||
#define UART_TRIGGER_TX_DONE (0x08)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void uart_init (pyb_uart_obj_t *self);
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self, uint32_t timeout);
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self);
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self);
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler);
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id);
|
||||
STATIC void UART0IntHandler(void);
|
||||
STATIC void UART1IntHandler(void);
|
||||
STATIC void uart_callback_enable (mp_obj_t self_in);
|
||||
STATIC void uart_callback_disable (mp_obj_t self_in);
|
||||
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in);
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
@@ -115,36 +102,46 @@ struct _pyb_uart_obj_t {
|
||||
uint config;
|
||||
uint flowcontrol;
|
||||
byte *read_buf; // read buffer pointer
|
||||
uint16_t timeout; // timeout waiting for first char
|
||||
uint16_t timeout_char; // timeout waiting between chars
|
||||
uint16_t read_buf_len; // len in chars; buf can hold len-1 chars
|
||||
volatile uint16_t read_buf_head; // indexes first empty slot
|
||||
uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
|
||||
byte peripheral;
|
||||
byte irq_trigger;
|
||||
bool irq_enabled;
|
||||
byte irq_flags;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = {{.reg = UARTA0_BASE, .baudrate = 0, .peripheral = PRCM_UARTA0},
|
||||
{.reg = UARTA1_BASE, .baudrate = 0, .peripheral = PRCM_UARTA1}};
|
||||
STATIC const mp_cb_methods_t uart_cb_methods;
|
||||
STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0},
|
||||
{.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} };
|
||||
STATIC const mp_irq_methods_t uart_irq_methods;
|
||||
|
||||
STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} };
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void uart_init0 (void) {
|
||||
// save references of the UART objects, to prevent the read buffers from being trashed by the gc
|
||||
MP_STATE_PORT(pyb_uart_objs)[0] = &pyb_uart_obj[0];
|
||||
MP_STATE_PORT(pyb_uart_objs)[1] = &pyb_uart_obj[1];
|
||||
}
|
||||
|
||||
bool uart_rx_any(pyb_uart_obj_t *self) {
|
||||
return (self->read_buf_tail != self->read_buf_head || MAP_UARTCharsAvail(self->reg));
|
||||
uint32_t uart_rx_any(pyb_uart_obj_t *self) {
|
||||
if (self->read_buf_tail != self->read_buf_head) {
|
||||
// buffering via irq
|
||||
return (self->read_buf_head > self->read_buf_tail) ? self->read_buf_head - self->read_buf_tail :
|
||||
PYBUART_RX_BUFFER_LEN - self->read_buf_tail + self->read_buf_head;
|
||||
}
|
||||
return MAP_UARTCharsAvail(self->reg) ? 1 : 0;
|
||||
}
|
||||
|
||||
int uart_rx_char(pyb_uart_obj_t *self) {
|
||||
if (self->read_buf_tail != self->read_buf_head) {
|
||||
// buffering via IRQ
|
||||
// buffering via irq
|
||||
int data = self->read_buf[self->read_buf_tail];
|
||||
self->read_buf_tail = (self->read_buf_tail + 1) % self->read_buf_len;
|
||||
self->read_buf_tail = (self->read_buf_tail + 1) % PYBUART_RX_BUFFER_LEN;
|
||||
return data;
|
||||
} else {
|
||||
// no buffering
|
||||
@@ -154,12 +151,11 @@ int uart_rx_char(pyb_uart_obj_t *self) {
|
||||
|
||||
bool uart_tx_char(pyb_uart_obj_t *self, int c) {
|
||||
uint32_t timeout = 0;
|
||||
|
||||
while (!MAP_UARTCharPutNonBlocking(self->reg, c)) {
|
||||
if (timeout++ > (PYBUART_TX_MAX_TIMEOUT_MS / PYBUART_TX_WAIT_MS)) {
|
||||
if (timeout++ > ((PYBUART_TX_MAX_TIMEOUT_MS * 1000) / PYBUART_TX_WAIT_US(self->baudrate))) {
|
||||
return false;
|
||||
}
|
||||
HAL_Delay (PYBUART_TX_WAIT_MS);
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBUART_TX_WAIT_US(self->baudrate)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -173,52 +169,6 @@ bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) {
|
||||
for (const char *top = str + len; str < top; str++) {
|
||||
if (*str == '\n') {
|
||||
uart_tx_char(self, '\r');
|
||||
}
|
||||
uart_tx_char(self, *str);
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, uint rxbuffer_size, mp_int_t priority) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_callback_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
}
|
||||
else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// check the rx buffer size
|
||||
if (rxbuffer_size > 0) {
|
||||
// allocate the read buffer
|
||||
self->read_buf_len = rxbuffer_size;
|
||||
self->read_buf = m_new(byte, rxbuffer_size);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _callback = mpcallback_new ((mp_obj_t)self, handler, &uart_cb_methods);
|
||||
|
||||
// enable the interrupts now
|
||||
uart_callback_enable (self);
|
||||
|
||||
return _callback;
|
||||
}
|
||||
|
||||
void uart_disable_all (void) {
|
||||
for (int i = 0; i < PYB_NUM_UARTS; i++) {
|
||||
// in case it's not clocked
|
||||
MAP_PRCMPeripheralClkEnable(pyb_uart_obj[i].peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
pyb_uart_deinit(&pyb_uart_obj[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
@@ -230,6 +180,12 @@ STATIC void uart_init (pyb_uart_obj_t *self) {
|
||||
// Reset the uart
|
||||
MAP_PRCMPeripheralReset(self->peripheral);
|
||||
|
||||
// re-allocate the read buffer after resetting the uart (which automatically disables any irqs)
|
||||
self->read_buf_head = 0;
|
||||
self->read_buf_tail = 0;
|
||||
self->read_buf = MP_OBJ_NULL; // free the read buffer before allocating again
|
||||
self->read_buf = m_new(byte, PYBUART_RX_BUFFER_LEN);
|
||||
|
||||
// Initialize the UART
|
||||
MAP_UARTConfigSetExpClk(self->reg, MAP_PRCMPeripheralClockGet(self->peripheral),
|
||||
self->baudrate, self->config);
|
||||
@@ -244,16 +200,17 @@ STATIC void uart_init (pyb_uart_obj_t *self) {
|
||||
UARTFlowControlSet(self->reg, self->flowcontrol);
|
||||
}
|
||||
|
||||
// Waits at most timeout milliseconds for at least 1 char to become ready for
|
||||
// Waits at most timeout microseconds for at least 1 char to become ready for
|
||||
// reading (from buf or for direct reading).
|
||||
// Returns true if something available, false if not.
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self, uint32_t timeout) {
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self) {
|
||||
int timeout = PYBUART_RX_TIMEOUT_US(self->baudrate);
|
||||
for ( ; ; ) {
|
||||
if (uart_rx_any(self)) {
|
||||
return true; // have at least 1 char ready for reading
|
||||
return true; // we have at least 1 char ready for reading
|
||||
}
|
||||
if (timeout > 0) {
|
||||
HAL_Delay (1);
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(1));
|
||||
timeout--;
|
||||
}
|
||||
else {
|
||||
@@ -262,6 +219,27 @@ STATIC bool uart_rx_wait (pyb_uart_obj_t *self, uint32_t timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_irq_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
} else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods);
|
||||
|
||||
// enable the interrupts now
|
||||
self->irq_trigger = trigger;
|
||||
uart_irq_enable (self);
|
||||
return _irq;
|
||||
}
|
||||
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
pyb_uart_obj_t *self;
|
||||
uint32_t status;
|
||||
@@ -270,15 +248,16 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
status = MAP_UARTIntStatus(self->reg, true);
|
||||
// receive interrupt
|
||||
if (status & (UART_INT_RX | UART_INT_RT)) {
|
||||
// set the flags
|
||||
self->irq_flags = UART_TRIGGER_RX_ANY;
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
while (UARTCharsAvail(self->reg)) {
|
||||
int data = MAP_UARTCharGetNonBlocking(self->reg);
|
||||
if (pyb_stdio_uart == self && data == user_interrupt_char) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == user_interrupt_char) {
|
||||
// raise an exception when interrupts are finished
|
||||
mpexception_keyboard_nlr_jump();
|
||||
}
|
||||
else if (self->read_buf_len != 0) {
|
||||
uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
|
||||
} else { // there's always a read buffer available
|
||||
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
|
||||
if (next_head != self->read_buf_tail) {
|
||||
// only store data if room in buf
|
||||
self->read_buf[self->read_buf_head] = data;
|
||||
@@ -286,9 +265,22 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the flags to see if the user handler should be called
|
||||
if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) {
|
||||
// call the user defined handler
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
|
||||
// clear the flags
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self) {
|
||||
// not initialized
|
||||
if (!self->baudrate) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,15 +292,24 @@ STATIC void UART1IntHandler(void) {
|
||||
UARTGenericIntHandler(1);
|
||||
}
|
||||
|
||||
STATIC void uart_callback_enable (mp_obj_t self_in) {
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
// check for any of the rx interrupt types
|
||||
if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) {
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
}
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void uart_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
self->irq_enabled = false;
|
||||
}
|
||||
|
||||
STATIC int uart_irq_flags (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -317,7 +318,7 @@ STATIC void uart_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "<UART%u, baudrate=%u, bits=", (self->uart_id + 1), self->baudrate);
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=", self->uart_id, self->baudrate);
|
||||
switch (self->config & UART_CONFIG_WLEN_MASK) {
|
||||
case UART_CONFIG_WLEN_5:
|
||||
mp_print_str(print, "5");
|
||||
@@ -337,100 +338,96 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
|
||||
if ((self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_NONE) {
|
||||
mp_print_str(print, ", parity=None");
|
||||
} else {
|
||||
mp_printf(print, ", parity=%u", (self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_EVEN ? 0 : 1);
|
||||
mp_printf(print, ", parity=UART.%q", (self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_EVEN ? MP_QSTR_EVEN : MP_QSTR_ODD);
|
||||
}
|
||||
mp_printf(print, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u>",
|
||||
(self->config & UART_CONFIG_STOP_MASK) == UART_CONFIG_STOP_ONE ? 1 : 2,
|
||||
self->timeout, self->timeout_char, self->read_buf_len);
|
||||
mp_printf(print, ", stop=%u)", (self->config & UART_CONFIG_STOP_MASK) == UART_CONFIG_STOP_ONE ? 1 : 2);
|
||||
}
|
||||
else {
|
||||
mp_printf(print, "<UART%u>", (self->uart_id + 1));
|
||||
mp_printf(print, "UART(%u)", self->uart_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0)
|
||||
///
|
||||
/// Initialise the UART bus with the given parameters:
|
||||
///
|
||||
/// - `baudrate` is the clock rate.
|
||||
/// - `bits` is the number of bits per byte, 5, 6, 7, 8
|
||||
/// - `parity` is the parity, `None`, 0 (even) or 1 (odd).
|
||||
/// - `stop` is the number of stop bits, 1 or 2.
|
||||
/// - `flow` is the flow control mode, `None`, `UART.RTS`,
|
||||
/// `UART.CTS', or `UART.CTS | UART.RTS`
|
||||
/// - `timeout` is the timeout (in milliseconds) when waiting for the first character.
|
||||
/// - `timeout_char` is the timeout (in milliseconds) between characters.
|
||||
STATIC const mp_arg_t pyb_uart_init_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = UART_FLOWCONTROL_NONE} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
|
||||
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_uart_init_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(pyb_uart_init_args), pyb_uart_init_args, args);
|
||||
|
||||
// set timeouts
|
||||
self->timeout = args[5].u_int;
|
||||
self->timeout_char = args[6].u_int;
|
||||
|
||||
// no read buffer for the moment
|
||||
self->read_buf_head = 0;
|
||||
self->read_buf_tail = 0;
|
||||
self->read_buf_len = 0;
|
||||
self->read_buf = NULL;
|
||||
|
||||
STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *args) {
|
||||
// get the baudrate
|
||||
self->baudrate = args[0].u_int;
|
||||
if (args[0].u_int <= 0) {
|
||||
goto error;
|
||||
}
|
||||
uint baudrate = args[0].u_int;
|
||||
uint config;
|
||||
switch (args[1].u_int) {
|
||||
case 5:
|
||||
config = UART_CONFIG_WLEN_5;
|
||||
break;
|
||||
case 6:
|
||||
config = UART_CONFIG_WLEN_6;
|
||||
break;
|
||||
case 7:
|
||||
config = UART_CONFIG_WLEN_7;
|
||||
break;
|
||||
case 8:
|
||||
config = UART_CONFIG_WLEN_8;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
// parity
|
||||
if (args[2].u_obj == mp_const_none) {
|
||||
config |= UART_CONFIG_PAR_NONE;
|
||||
} else {
|
||||
uint parity = mp_obj_get_int(args[2].u_obj);
|
||||
if (parity != UART_CONFIG_PAR_ODD && parity != UART_CONFIG_PAR_EVEN) {
|
||||
goto error;
|
||||
}
|
||||
config |= parity;
|
||||
}
|
||||
// stop bits
|
||||
config |= (args[3].u_int == 1 ? UART_CONFIG_STOP_ONE : UART_CONFIG_STOP_TWO);
|
||||
|
||||
// set the UART configuration values
|
||||
if (n_args > 1) {
|
||||
switch (args[1].u_int) {
|
||||
case 5:
|
||||
self->config = UART_CONFIG_WLEN_5;
|
||||
break;
|
||||
case 6:
|
||||
self->config = UART_CONFIG_WLEN_6;
|
||||
break;
|
||||
case 7:
|
||||
self->config = UART_CONFIG_WLEN_7;
|
||||
break;
|
||||
case 8:
|
||||
self->config = UART_CONFIG_WLEN_8;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
// Parity
|
||||
if (args[2].u_obj == mp_const_none) {
|
||||
self->config |= UART_CONFIG_PAR_NONE;
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[4].u_obj;
|
||||
uint flowcontrol = UART_FLOWCONTROL_NONE;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 2;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_uart_def_pin[self->uart_id];
|
||||
} else {
|
||||
self->config |= ((mp_obj_get_int(args[2].u_obj) & 1) ? UART_CONFIG_PAR_ODD : UART_CONFIG_PAR_EVEN);
|
||||
mp_obj_get_array(pins_o, &n_pins, &pins);
|
||||
if (n_pins != 2 && n_pins != 4) {
|
||||
goto error;
|
||||
}
|
||||
if (n_pins == 4) {
|
||||
if (pins[PIN_TYPE_UART_RTS] != mp_const_none && pins[PIN_TYPE_UART_RX] == mp_const_none) {
|
||||
goto error; // RTS pin given in TX only mode
|
||||
} else if (pins[PIN_TYPE_UART_CTS] != mp_const_none && pins[PIN_TYPE_UART_TX] == mp_const_none) {
|
||||
goto error; // CTS pin given in RX only mode
|
||||
} else {
|
||||
if (pins[PIN_TYPE_UART_RTS] != mp_const_none) {
|
||||
flowcontrol |= UART_FLOWCONTROL_RX;
|
||||
}
|
||||
if (pins[PIN_TYPE_UART_CTS] != mp_const_none) {
|
||||
flowcontrol |= UART_FLOWCONTROL_TX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Stop bits
|
||||
self->config |= (args[3].u_int == 1 ? UART_CONFIG_STOP_ONE : UART_CONFIG_STOP_TWO);
|
||||
// Flow control
|
||||
if (args[4].u_int != UART_FLOWCONTROL_NONE || args[4].u_int != UART_FLOWCONTROL_TX ||
|
||||
args[4].u_int != UART_FLOWCONTROL_RX || args[4].u_int != (UART_FLOWCONTROL_TX | UART_FLOWCONTROL_RX)) {
|
||||
goto error;
|
||||
}
|
||||
self->flowcontrol = args[4].u_int;
|
||||
}
|
||||
else {
|
||||
self->config = UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE;
|
||||
self->flowcontrol = UART_FLOWCONTROL_NONE;
|
||||
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_UART, self->uart_id);
|
||||
}
|
||||
|
||||
self->baudrate = baudrate;
|
||||
self->config = config;
|
||||
self->flowcontrol = flowcontrol;
|
||||
|
||||
// initialize and enable the uart
|
||||
uart_init (self);
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
|
||||
// enable the callback
|
||||
uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none);
|
||||
// disable the irq (from the user point of view)
|
||||
uart_irq_disable(self);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -438,27 +435,43 @@ error:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
/// \classmethod \constructor(bus, ...)
|
||||
///
|
||||
/// Construct a UART object on the given bus id. `bus id` can be 1 or 2
|
||||
/// With no additional parameters, the UART object is created but not
|
||||
/// initialised (it has the settings from the last initialisation of
|
||||
/// the bus, if any).
|
||||
/// When only the baud rate is given the UART object is created and
|
||||
/// initialized with the default configuration of: 8 bit transfers,
|
||||
/// 1 stop bit, no parity and flow control disabled.
|
||||
/// See `init` for parameters of initialisation.
|
||||
/// If extra arguments are given, the bus is initialised with these arguments
|
||||
/// See `init` for parameters of initialisation.
|
||||
///
|
||||
STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_ARRAY_SIZE(pyb_uart_init_args), true);
|
||||
STATIC const mp_arg_t pyb_uart_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 9600} },
|
||||
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_uart_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_uart_init_args, args);
|
||||
|
||||
// work out the uart id
|
||||
int32_t uart_id = mp_obj_get_int(args[0]) - 1;
|
||||
uint uart_id;
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
if (args[5].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 2;
|
||||
mp_obj_get_array(args[5].u_obj, &n_pins, &pins);
|
||||
// check the Tx pin (or the Rx if Tx is None)
|
||||
if (pins[0] == mp_const_none) {
|
||||
uart_id = pin_find_peripheral_unit(pins[1], PIN_FN_UART, PIN_TYPE_UART_RX);
|
||||
} else {
|
||||
uart_id = pin_find_peripheral_unit(pins[0], PIN_FN_UART, PIN_TYPE_UART_TX);
|
||||
}
|
||||
} else {
|
||||
// default id
|
||||
uart_id = 0;
|
||||
}
|
||||
} else {
|
||||
uart_id = mp_obj_get_int(args[0].u_obj);
|
||||
}
|
||||
|
||||
if (uart_id < PYB_UART_0 || uart_id > PYB_UART_1) {
|
||||
if (uart_id > PYB_UART_1) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
@@ -467,30 +480,29 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
|
||||
self->base.type = &pyb_uart_type;
|
||||
self->uart_id = uart_id;
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// start the peripheral
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
// start the peripheral
|
||||
pyb_uart_init_helper(self, &args[1]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_uart_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
STATIC mp_obj_t pyb_uart_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_uart_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_uart_init_args[1], args);
|
||||
return pyb_uart_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
|
||||
|
||||
/// \method deinit()
|
||||
/// Turn off the UART bus.
|
||||
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove (self);
|
||||
pyb_sleep_remove (self);
|
||||
// invalidate the baudrate
|
||||
self->baudrate = 0;
|
||||
// free the read buffer
|
||||
m_del(byte, self->read_buf, PYBUART_RX_BUFFER_LEN);
|
||||
MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTDisable(self->reg);
|
||||
MAP_PRCMPeripheralClkDisable(self->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
@@ -498,95 +510,63 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
|
||||
|
||||
/// \method any()
|
||||
/// Return `True` if any characters waiting, else `False`.
|
||||
STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
if (uart_rx_any(self)) {
|
||||
return mp_const_true;
|
||||
} else {
|
||||
return mp_const_false;
|
||||
}
|
||||
uart_check_init(self);
|
||||
return mp_obj_new_int(uart_rx_any(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
|
||||
|
||||
/// \method callback(handler, value, priority)
|
||||
/// Creates a callback object associated with the uart
|
||||
/// min num of arguments is 1 (value). The value is the size of the rx buffer
|
||||
STATIC mp_obj_t pyb_uart_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
|
||||
// check if any parameters were passed
|
||||
pyb_uart_obj_t *self = pos_args[0];
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)self);
|
||||
if (kw_args->used > 0 || !_callback) {
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
|
||||
// check the power mode
|
||||
if (PYB_PWR_MODE_ACTIVE != args[4].u_int) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
return uart_callback_new (self, args[1].u_obj, args[3].u_int, priority);
|
||||
}
|
||||
return _callback;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_callback);
|
||||
|
||||
/// \method writechar(char)
|
||||
/// Write a single character on the bus. `char` is an integer to write.
|
||||
/// Return value: `None`.
|
||||
STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
|
||||
// get the character to write
|
||||
uint8_t data = mp_obj_get_int(char_in);
|
||||
|
||||
// send the character
|
||||
if (!uart_tx_char(self, data)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar);
|
||||
|
||||
/// \method readchar()
|
||||
/// Receive a single character on the bus.
|
||||
/// Return value: The character read, as an integer. Returns -1 on timeout.
|
||||
STATIC mp_obj_t pyb_uart_readchar(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
if (uart_rx_wait(self, self->timeout)) {
|
||||
return mp_obj_new_int(uart_rx_char(self));
|
||||
} else {
|
||||
// return -1 on timeout
|
||||
return MP_OBJ_NEW_SMALL_INT(-1);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);
|
||||
|
||||
/// \method sendbreak()
|
||||
STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
uart_check_init(self);
|
||||
// send a break signal for at least 2 complete frames
|
||||
MAP_UARTBreakCtl(self->reg, true);
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT((22 * 1000000) / self->baudrate));
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBUART_2_FRAMES_TIME_US(self->baudrate)));
|
||||
MAP_UARTBreakCtl(self->reg, false);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
|
||||
// check if any parameters were passed
|
||||
pyb_uart_obj_t *self = pos_args[0];
|
||||
uart_check_init(self);
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// check the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (PYB_PWR_MODE_ACTIVE != pwrmode) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// check the trigger
|
||||
uint trigger = mp_obj_get_int(args[0].u_obj);
|
||||
if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
return uart_irq_new (self, trigger, priority, args[2].u_obj);
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_uart_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_uart_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_uart_irq_obj },
|
||||
|
||||
/// \method read([nbytes])
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
@@ -599,13 +579,10 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
/// \method write(buf)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writechar), (mp_obj_t)&pyb_uart_writechar_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readchar), (mp_obj_t)&pyb_uart_readchar_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CTS), MP_OBJ_NEW_SMALL_INT(UART_FLOWCONTROL_TX) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTS), MP_OBJ_NEW_SMALL_INT(UART_FLOWCONTROL_RX) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_EVEN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_ODD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
|
||||
@@ -613,6 +590,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
|
||||
STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
byte *buf = buf_in;
|
||||
uart_check_init(self);
|
||||
|
||||
// make sure we want at least 1 char
|
||||
if (size == 0) {
|
||||
@@ -620,17 +598,17 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
|
||||
}
|
||||
|
||||
// wait for first char to become available
|
||||
if (!uart_rx_wait(self, self->timeout)) {
|
||||
// we can either return 0 to indicate EOF (then read() method returns b'')
|
||||
// or return EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
return 0;
|
||||
if (!uart_rx_wait(self)) {
|
||||
// return EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
*errcode = EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
// read the data
|
||||
byte *orig_buf = buf;
|
||||
for ( ; ; ) {
|
||||
*buf++ = uart_rx_char(self);
|
||||
if (--size == 0 || !uart_rx_wait(self, self->timeout_char)) {
|
||||
if (--size == 0 || !uart_rx_wait(self)) {
|
||||
// return number of bytes read
|
||||
return buf - orig_buf;
|
||||
}
|
||||
@@ -640,6 +618,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
|
||||
STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
const char *buf = buf_in;
|
||||
uart_check_init(self);
|
||||
|
||||
// write the data
|
||||
if (!uart_tx_strn(self, buf, size)) {
|
||||
@@ -651,6 +630,8 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t
|
||||
STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
mp_uint_t ret;
|
||||
uart_check_init(self);
|
||||
|
||||
if (request == MP_IOCTL_POLL) {
|
||||
mp_uint_t flags = arg;
|
||||
ret = 0;
|
||||
@@ -674,10 +655,11 @@ STATIC const mp_stream_p_t uart_stream_p = {
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t uart_cb_methods = {
|
||||
.init = pyb_uart_callback,
|
||||
.enable = uart_callback_enable,
|
||||
.disable = uart_callback_disable,
|
||||
STATIC const mp_irq_methods_t uart_irq_methods = {
|
||||
.init = pyb_uart_irq,
|
||||
.enable = uart_irq_enable,
|
||||
.disable = uart_irq_disable,
|
||||
.flags = uart_irq_flags
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_uart_type = {
|
||||
|
||||
@@ -38,12 +38,9 @@ typedef struct _pyb_uart_obj_t pyb_uart_obj_t;
|
||||
extern const mp_obj_type_t pyb_uart_type;
|
||||
|
||||
void uart_init0(void);
|
||||
bool uart_rx_any(pyb_uart_obj_t *uart_obj);
|
||||
uint32_t uart_rx_any(pyb_uart_obj_t *uart_obj);
|
||||
int uart_rx_char(pyb_uart_obj_t *uart_obj);
|
||||
bool uart_tx_char(pyb_uart_obj_t *self, int c);
|
||||
bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
|
||||
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
|
||||
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, uint rxbuffer_size, mp_int_t priority);
|
||||
void uart_disable_all (void);
|
||||
|
||||
#endif // PYBUART_H_
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@@ -53,17 +53,17 @@
|
||||
DECLARE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bool servers;
|
||||
bool servers_sleeping;
|
||||
bool simplelink;
|
||||
bool running;
|
||||
} pybwdt_data_t;
|
||||
} pyb_wdt_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pybwdt_data_t pybwdt_data = {.servers = false, .servers_sleeping = false, .simplelink = false, .running = false};
|
||||
STATIC const mp_obj_base_t pyb_wdt_obj = {&pyb_wdt_type};
|
||||
STATIC pyb_wdt_obj_t pyb_wdt_obj = {.servers = false, .servers_sleeping = false, .simplelink = false, .running = false};
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
@@ -74,73 +74,79 @@ void pybwdt_init0 (void) {
|
||||
}
|
||||
|
||||
void pybwdt_srv_alive (void) {
|
||||
pybwdt_data.servers = true;
|
||||
pyb_wdt_obj.servers = true;
|
||||
}
|
||||
|
||||
void pybwdt_srv_sleeping (bool state) {
|
||||
pybwdt_data.servers_sleeping = state;
|
||||
pyb_wdt_obj.servers_sleeping = state;
|
||||
}
|
||||
|
||||
void pybwdt_sl_alive (void) {
|
||||
pybwdt_data.simplelink = true;
|
||||
pyb_wdt_obj.simplelink = true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \function constructor('msec')
|
||||
/// Enables the watchdog timer with msec timeout value
|
||||
STATIC mp_obj_t pyb_wdt_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
STATIC const mp_arg_t pyb_wdt_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} }, // 5 s
|
||||
};
|
||||
STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// check the arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_wdt_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_wdt_init_args, args);
|
||||
|
||||
if (n_args > 0) {
|
||||
mp_int_t msec = mp_obj_get_int(args[0]);
|
||||
if (msec < PYBWDT_MIN_TIMEOUT_MS) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
if (pybwdt_data.running) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
|
||||
// Enable the WDT peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
// Unlock to be able to configure the registers
|
||||
MAP_WatchdogUnlock(WDT_BASE);
|
||||
|
||||
#ifdef DEBUG
|
||||
// make the WDT stall when the debugger stops on a breakpoint
|
||||
MAP_WatchdogStallEnable (WDT_BASE);
|
||||
#endif
|
||||
|
||||
// set the watchdog timer reload value
|
||||
// the WDT trigger a system reset after the second timeout
|
||||
// so, divide by 2 the timeout value received
|
||||
MAP_WatchdogReloadSet(WDT_BASE, PYBWDT_MILLISECONDS_TO_TICKS(msec / 2));
|
||||
|
||||
// start the timer. Once it's started, it cannot be disabled.
|
||||
MAP_WatchdogEnable(WDT_BASE);
|
||||
pybwdt_data.running = true;
|
||||
if (args[0].u_obj != mp_const_none && mp_obj_get_int(args[0].u_obj) > 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
uint timeout_ms = args[1].u_int;
|
||||
if (timeout_ms < PYBWDT_MIN_TIMEOUT_MS) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
if (pyb_wdt_obj.running) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
|
||||
}
|
||||
|
||||
// Enable the WDT peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
// Unlock to be able to configure the registers
|
||||
MAP_WatchdogUnlock(WDT_BASE);
|
||||
|
||||
#ifdef DEBUG
|
||||
// make the WDT stall when the debugger stops on a breakpoint
|
||||
MAP_WatchdogStallEnable (WDT_BASE);
|
||||
#endif
|
||||
|
||||
// set the watchdog timer reload value
|
||||
// the WDT trigger a system reset after the second timeout
|
||||
// so, divide by 2 the timeout value received
|
||||
MAP_WatchdogReloadSet(WDT_BASE, PYBWDT_MILLISECONDS_TO_TICKS(timeout_ms / 2));
|
||||
|
||||
// start the timer. Once it's started, it cannot be disabled.
|
||||
MAP_WatchdogEnable(WDT_BASE);
|
||||
pyb_wdt_obj.base.type = &pyb_wdt_type;
|
||||
pyb_wdt_obj.running = true;
|
||||
|
||||
return (mp_obj_t)&pyb_wdt_obj;
|
||||
}
|
||||
|
||||
/// \function wdt_kick()
|
||||
/// Kicks the watchdog timer
|
||||
STATIC mp_obj_t pyb_kick_wdt(mp_obj_t self) {
|
||||
if ((pybwdt_data.servers || pybwdt_data.servers_sleeping) && pybwdt_data.simplelink && pybwdt_data.running) {
|
||||
pybwdt_data.servers = false;
|
||||
pybwdt_data.simplelink = false;
|
||||
STATIC mp_obj_t pyb_wdt_feed(mp_obj_t self_in) {
|
||||
pyb_wdt_obj_t *self = self_in;
|
||||
if ((self->servers || self->servers_sleeping) && self->simplelink && self->running) {
|
||||
self->servers = false;
|
||||
self->simplelink = false;
|
||||
MAP_WatchdogIntClear(WDT_BASE);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_kick_wdt_obj, pyb_kick_wdt);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_wdt_feed_obj, pyb_wdt_feed);
|
||||
|
||||
STATIC const mp_map_elem_t pybwdt_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_kick), (mp_obj_t)&pyb_kick_wdt_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&pyb_wdt_feed_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pybwdt_locals_dict, pybwdt_locals_dict_table);
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#endif
|
||||
|
||||
// options to control how Micro Python is built
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (128)
|
||||
@@ -43,33 +48,54 @@
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
#ifndef DEBUG // we need ram on the launchxl while debugging
|
||||
#define MICROPY_CPYTHON_COMPAT (1)
|
||||
#else
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#endif
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
|
||||
// fatfs configuration used in ffconf.h
|
||||
#define MICROPY_FATFS_ENABLE_LFN (2)
|
||||
#define MICROPY_FATFS_MAX_LFN (MICROPY_ALLOC_PATH_MAX)
|
||||
#define MICROPY_FATFS_LFN_CODE_PAGE (437) // 1=SFN/ANSI 437=LFN/U.S.(OEM)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
#define MICROPY_FATFS_VOLUMES (2)
|
||||
#define MICROPY_FATFS_REENTRANT (1)
|
||||
#define MICROPY_FATFS_TIMEOUT (2500)
|
||||
#define MICROPY_FATFS_SYNC_T SemaphoreHandle_t
|
||||
#define MICROPY_FSUSERMOUNT_ADHOC (1)
|
||||
|
||||
/* Enable FatFS LFNs
|
||||
0: Disable LFN feature.
|
||||
1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
|
||||
2: Enable LFN with dynamic working buffer on the STACK.
|
||||
3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
*/
|
||||
#define MICROPY_ENABLE_LFN (2)
|
||||
#define MICROPY_LFN_CODE_PAGE (437) // 1=SFN/ANSI 437=LFN/U.S.(OEM)
|
||||
#define MICROPY_STREAMS_NON_BLOCK (1)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
|
||||
#ifndef DEBUG
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||
#define MICROPY_PY_BUILTINS_EXECFILE (1)
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
|
||||
#else
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_EXECFILE (0)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)
|
||||
#define MICROPY_PY_SYS_MAXSIZE (0)
|
||||
#endif
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
|
||||
#define MICROPY_PY_SYS_MAXSIZE (1)
|
||||
#define MICROPY_PY_SYS_EXIT (1)
|
||||
#define MICROPY_PY_SYS_STDFILES (1)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
@@ -80,7 +106,7 @@
|
||||
#define MICROPY_PY_UZLIB (0)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
#define MICROPY_PY_URE (1)
|
||||
#define MICROPY_PY_UHEAPQ (1)
|
||||
#define MICROPY_PY_UHEAPQ (0)
|
||||
#define MICROPY_PY_UHASHLIB (0)
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
@@ -96,52 +122,57 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, \
|
||||
|
||||
// extra built in modules to add to the list of known ones
|
||||
extern const struct _mp_obj_module_t pyb_module;
|
||||
extern const struct _mp_obj_module_t machine_module;
|
||||
extern const struct _mp_obj_module_t wipy_module;
|
||||
extern const struct _mp_obj_module_t mp_module_ure;
|
||||
extern const struct _mp_obj_module_t mp_module_ujson;
|
||||
extern const struct _mp_obj_module_t mp_module_uheapq;
|
||||
extern const struct _mp_obj_module_t mp_module_uos;
|
||||
extern const struct _mp_obj_module_t mp_module_utime;
|
||||
extern const struct _mp_obj_module_t mp_module_uselect;
|
||||
extern const struct _mp_obj_module_t mp_module_usocket;
|
||||
extern const struct _mp_obj_module_t mp_module_network;
|
||||
extern const struct _mp_obj_module_t mp_module_uhashlib;
|
||||
extern const struct _mp_obj_module_t mp_module_ubinascii;
|
||||
extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wipy), (mp_obj_t)&wipy_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_uos }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&mp_module_utime }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uselect), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii), (mp_obj_t)&mp_module_ubinascii }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ussl), (mp_obj_t)&mp_module_ussl }, \
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&mp_module_uos }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_utime }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
|
||||
|
||||
// extra constants
|
||||
#define MICROPY_PORT_CONSTANTS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \
|
||||
|
||||
// vm state and root pointers for the gc
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
mp_obj_t mp_const_user_interrupt; \
|
||||
mp_obj_t pyb_config_main; \
|
||||
mp_obj_list_t pybsleep_obj_list; \
|
||||
mp_obj_list_t mpcallback_obj_list; \
|
||||
mp_obj_t machine_config_main; \
|
||||
mp_obj_list_t pyb_sleep_obj_list; \
|
||||
mp_obj_list_t mp_irq_obj_list; \
|
||||
mp_obj_list_t pyb_timer_channel_obj_list; \
|
||||
mp_obj_list_t mount_obj_list; \
|
||||
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \
|
||||
struct _os_term_dup_obj_t *os_term_dup_obj; \
|
||||
|
||||
|
||||
// type definitions for the specific machine
|
||||
@@ -158,7 +189,6 @@ typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len);
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
|
||||
@@ -182,10 +212,9 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len);
|
||||
// Include board specific configuration
|
||||
#include "mpconfigboard.h"
|
||||
|
||||
#define MICROPY_HAL_H "cc3200_hal.h"
|
||||
#define MICROPY_MPHALPORT_H "cc3200_hal.h"
|
||||
#define MICROPY_PORT_HAS_TELNET (1)
|
||||
#define MICROPY_PORT_HAS_FTP (1)
|
||||
#define MICROPY_PORT_WLAN_URN (0)
|
||||
#define MICROPY_PY_SYS_PLATFORM "WiPy"
|
||||
|
||||
#define MICROPY_PORT_WLAN_AP_SSID "wipy-wlan"
|
||||
|
||||
122
cc3200/mptask.c
122
cc3200/mptask.c
@@ -28,10 +28,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "pybuart.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybrtc.h"
|
||||
#include "pyexec.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "gccollect.h"
|
||||
#include "gchelper.h"
|
||||
#include "readline.h"
|
||||
@@ -61,12 +61,14 @@
|
||||
#include "mpexception.h"
|
||||
#include "random.h"
|
||||
#include "pybi2c.h"
|
||||
#include "pybsd.h"
|
||||
#include "pins.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybtimer.h"
|
||||
#include "mpcallback.h"
|
||||
#include "cryptohash.h"
|
||||
#include "mpirq.h"
|
||||
#include "updater.h"
|
||||
#include "moduos.h"
|
||||
#include "antenna.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
@@ -104,10 +106,14 @@ void TASK_Micropython (void *pvParameters) {
|
||||
// initialize the garbage collector with the top of our stack
|
||||
uint32_t sp = gc_helper_get_sp();
|
||||
gc_collect_init (sp);
|
||||
bool safeboot = false;
|
||||
|
||||
bool safeboot = false;
|
||||
mptask_pre_init();
|
||||
|
||||
#ifndef DEBUG
|
||||
safeboot = PRCMGetSpecialBit(PRCM_SAFE_BOOT_BIT);
|
||||
#endif
|
||||
|
||||
soft_reset:
|
||||
|
||||
// GC init
|
||||
@@ -121,36 +127,18 @@ soft_reset:
|
||||
|
||||
// execute all basic initializations
|
||||
mpexception_init0();
|
||||
mpcallback_init0();
|
||||
pybsleep_init0();
|
||||
mp_irq_init0();
|
||||
pyb_sleep_init0();
|
||||
pin_init0();
|
||||
mperror_init0();
|
||||
uart_init0();
|
||||
pin_init0();
|
||||
timer_init0();
|
||||
readline_init0();
|
||||
mod_network_init0();
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
moduos_init0();
|
||||
rng_init0();
|
||||
#endif
|
||||
|
||||
#ifdef LAUNCHXL
|
||||
// configure the stdio uart pins with the correct alternate functions
|
||||
// param 3 ("mode") is DON'T CARE" for AFs others than GPIO
|
||||
pin_config ((pin_obj_t *)&MICROPY_STDIO_UART_TX_PIN, MICROPY_STDIO_UART_TX_PIN_AF, 0, PIN_TYPE_STD_PU, PIN_STRENGTH_2MA);
|
||||
pin_config ((pin_obj_t *)&MICROPY_STDIO_UART_RX_PIN, MICROPY_STDIO_UART_RX_PIN_AF, 0, PIN_TYPE_STD_PU, PIN_STRENGTH_2MA);
|
||||
// instantiate the stdio uart
|
||||
mp_obj_t args[2] = {
|
||||
mp_obj_new_int(MICROPY_STDIO_UART),
|
||||
mp_obj_new_int(MICROPY_STDIO_UART_BAUD),
|
||||
};
|
||||
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
|
||||
// create a callback for the uart, in order to enable the rx interrupts
|
||||
uart_callback_new (pyb_stdio_uart, mp_const_none, MICROPY_STDIO_UART_RX_BUF_SIZE, INT_PRIORITY_LVL_3);
|
||||
#else
|
||||
pyb_stdio_uart = MP_OBJ_NULL;
|
||||
#endif
|
||||
|
||||
pybsleep_reset_cause_t rstcause = pybsleep_get_reset_cause();
|
||||
pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause();
|
||||
if (rstcause < PYB_SLP_SOFT_RESET) {
|
||||
if (rstcause == PYB_SLP_HIB_RESET) {
|
||||
// when waking up from hibernate we just want
|
||||
@@ -160,9 +148,6 @@ soft_reset:
|
||||
else {
|
||||
// only if not comming out of hibernate or a soft reset
|
||||
mptask_enter_ap_mode();
|
||||
#ifndef DEBUG
|
||||
safeboot = PRCMIsSafeBootRequested();
|
||||
#endif
|
||||
}
|
||||
|
||||
// enable telnet and ftp
|
||||
@@ -177,7 +162,7 @@ soft_reset:
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib));
|
||||
|
||||
// reset config variables; they should be set by boot.py
|
||||
MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(machine_config_main) = MP_OBJ_NULL;
|
||||
|
||||
if (!safeboot) {
|
||||
// run boot.py
|
||||
@@ -201,10 +186,10 @@ soft_reset:
|
||||
// run the main script from the current directory.
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
|
||||
const char *main_py;
|
||||
if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) {
|
||||
if (MP_STATE_PORT(machine_config_main) == MP_OBJ_NULL) {
|
||||
main_py = "main.py";
|
||||
} else {
|
||||
main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main));
|
||||
main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main));
|
||||
}
|
||||
int ret = pyexec_file(main_py);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
@@ -234,13 +219,15 @@ soft_reset:
|
||||
soft_reset_exit:
|
||||
|
||||
// soft reset
|
||||
pybsleep_signal_soft_reset();
|
||||
pyb_sleep_signal_soft_reset();
|
||||
mp_printf(&mp_plat_print, "PYB: soft reboot\n");
|
||||
|
||||
// disable all peripherals that could trigger a callback
|
||||
pyb_rtc_callback_disable(NULL);
|
||||
timer_disable_all();
|
||||
uart_disable_all();
|
||||
// disable all callbacks to avoid undefined behaviour
|
||||
// when coming out of a soft reset
|
||||
mp_irq_disable_all();
|
||||
|
||||
// cancel the RTC alarm which might be running independent of the irq state
|
||||
pyb_rtc_disable_alarm();
|
||||
|
||||
// flush the serial flash buffer
|
||||
sflash_disk_flush();
|
||||
@@ -248,12 +235,11 @@ soft_reset_exit:
|
||||
// clean-up the user socket space
|
||||
modusocket_close_all_user_sockets();
|
||||
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
pybsd_deinit();
|
||||
#endif
|
||||
// unmount all user file systems
|
||||
osmount_unmount_all();
|
||||
|
||||
// wait for pending transactions to complete
|
||||
HAL_Delay(20);
|
||||
mp_hal_delay_ms(20);
|
||||
|
||||
goto soft_reset;
|
||||
}
|
||||
@@ -263,9 +249,8 @@ soft_reset_exit:
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
STATIC void mptask_pre_init (void) {
|
||||
#if MICROPY_HW_ENABLE_RTC
|
||||
pybrtc_init();
|
||||
#endif
|
||||
// this one only makes sense after a poweron reset
|
||||
pyb_rtc_pre_init();
|
||||
|
||||
// Create the simple link spawn task
|
||||
ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY));
|
||||
@@ -274,19 +259,18 @@ STATIC void mptask_pre_init (void) {
|
||||
ASSERT ((sflash_fatfs = mem_Malloc(sizeof(FATFS))) != NULL);
|
||||
|
||||
// this one allocates memory for the nvic vault
|
||||
pybsleep_pre_init();
|
||||
pyb_sleep_pre_init();
|
||||
|
||||
// this one allocates memory for the WLAN semaphore
|
||||
wlan_pre_init();
|
||||
|
||||
// this one allocates memory for the Socket semaphore
|
||||
// this one allocates memory for the updater semaphore
|
||||
updater_pre_init();
|
||||
|
||||
// this one allocates memory for the socket semaphore
|
||||
modusocket_pre_init();
|
||||
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
pybsd_init0();
|
||||
#endif
|
||||
|
||||
CRYPTOHASH_Init();
|
||||
//CRYPTOHASH_Init();
|
||||
|
||||
#ifdef DEBUG
|
||||
ASSERT (OSI_OK == osi_TaskCreate(TASK_Servers,
|
||||
@@ -308,7 +292,6 @@ STATIC void mptask_init_sflash_filesystem (void) {
|
||||
|
||||
// Initialise the local flash filesystem.
|
||||
// Create it if needed, and mount in on /flash.
|
||||
// try to mount the flash
|
||||
FRESULT res = f_mount(sflash_fatfs, "/flash", 1);
|
||||
if (res == FR_NO_FILESYSTEM) {
|
||||
// no filesystem, so create a fresh one
|
||||
@@ -334,7 +317,20 @@ STATIC void mptask_init_sflash_filesystem (void) {
|
||||
// It is set to the internal flash filesystem by default.
|
||||
f_chdrive("/flash");
|
||||
|
||||
// Make sure we have a /flash/boot.py. Create it if needed.
|
||||
// create /flash/sys, /flash/lib and /flash/cert if they don't exist
|
||||
if (FR_OK != f_chdir ("/flash/sys")) {
|
||||
f_mkdir("/flash/sys");
|
||||
}
|
||||
if (FR_OK != f_chdir ("/flash/lib")) {
|
||||
f_mkdir("/flash/lib");
|
||||
}
|
||||
if (FR_OK != f_chdir ("/flash/cert")) {
|
||||
f_mkdir("/flash/cert");
|
||||
}
|
||||
|
||||
f_chdir ("/flash");
|
||||
|
||||
// make sure we have a /flash/boot.py. Create it if needed.
|
||||
res = f_stat("/flash/boot.py", &fno);
|
||||
if (res == FR_OK) {
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
@@ -356,9 +352,12 @@ STATIC void mptask_init_sflash_filesystem (void) {
|
||||
}
|
||||
|
||||
STATIC void mptask_enter_ap_mode (void) {
|
||||
// enable simplelink in low power mode
|
||||
wlan_sl_enable (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID), MICROPY_PORT_WLAN_AP_SECURITY,
|
||||
MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY), MICROPY_PORT_WLAN_AP_CHANNEL);
|
||||
// append the mac only if it's not the first boot
|
||||
bool add_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT);
|
||||
// enable simplelink in ap mode (use the MAC address to make the ssid unique)
|
||||
wlan_sl_init (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID),
|
||||
MICROPY_PORT_WLAN_AP_SECURITY, MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY),
|
||||
MICROPY_PORT_WLAN_AP_CHANNEL, ANTENNA_TYPE_INTERNAL, add_mac);
|
||||
}
|
||||
|
||||
STATIC void mptask_create_main_py (void) {
|
||||
@@ -370,10 +369,3 @@ STATIC void mptask_create_main_py (void) {
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_main(mp_obj_t main) {
|
||||
if (MP_OBJ_IS_STR(main)) {
|
||||
MP_STATE_PORT(pyb_config_main) = main;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);
|
||||
|
||||
@@ -25,60 +25,58 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// qstrs specific to this port
|
||||
Q(__name__)
|
||||
Q(help)
|
||||
Q(pyb)
|
||||
// for machine module
|
||||
Q(umachine)
|
||||
#ifdef DEBUG
|
||||
Q(info)
|
||||
#endif
|
||||
Q(reset)
|
||||
Q(main)
|
||||
Q(sync)
|
||||
Q(gc)
|
||||
Q(rng)
|
||||
Q(delay)
|
||||
Q(time)
|
||||
Q(open)
|
||||
Q(on)
|
||||
Q(off)
|
||||
Q(toggle)
|
||||
Q(write)
|
||||
Q(read)
|
||||
Q(readall)
|
||||
Q(readline)
|
||||
Q(input)
|
||||
Q(os)
|
||||
Q(freq)
|
||||
Q(unique_id)
|
||||
Q(repl_info)
|
||||
Q(disable_irq)
|
||||
Q(enable_irq)
|
||||
Q(millis)
|
||||
Q(micros)
|
||||
Q(elapsed_millis)
|
||||
Q(elapsed_micros)
|
||||
Q(udelay)
|
||||
Q(flush)
|
||||
Q(FileIO)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
// Entries for sys.path
|
||||
Q(idle)
|
||||
Q(sleep)
|
||||
Q(deepsleep)
|
||||
Q(reset_cause)
|
||||
Q(wake_reason)
|
||||
Q(IDLE)
|
||||
Q(SLEEP)
|
||||
Q(DEEPSLEEP)
|
||||
Q(POWER_ON)
|
||||
Q(HARD_RESET)
|
||||
Q(WDT_RESET)
|
||||
Q(DEEPSLEEP_RESET)
|
||||
Q(SOFT_RESET)
|
||||
Q(WLAN_WAKE)
|
||||
Q(PIN_WAKE)
|
||||
Q(RTC_WAKE)
|
||||
|
||||
// for wipy module
|
||||
Q(wipy)
|
||||
Q(heartbeat)
|
||||
|
||||
// entries for sys.path
|
||||
Q(/flash)
|
||||
Q(/flash/lib)
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
Q(/sd)
|
||||
Q(/sd/lib)
|
||||
#endif
|
||||
|
||||
// interactive help
|
||||
Q(help)
|
||||
|
||||
// for module weak links
|
||||
Q(struct)
|
||||
Q(binascii)
|
||||
Q(re)
|
||||
Q(json)
|
||||
Q(heapq)
|
||||
Q(hashlib)
|
||||
//Q(hashlib)
|
||||
|
||||
// for os module
|
||||
Q(uos)
|
||||
Q(os)
|
||||
Q(uos)
|
||||
Q(sysname)
|
||||
Q(nodename)
|
||||
Q(release)
|
||||
@@ -87,9 +85,6 @@ Q(machine)
|
||||
Q(uname)
|
||||
Q(/)
|
||||
Q(flash)
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
Q(sd)
|
||||
#endif
|
||||
Q(chdir)
|
||||
Q(getcwd)
|
||||
Q(listdir)
|
||||
@@ -102,101 +97,129 @@ Q(sep)
|
||||
Q(stat)
|
||||
Q(urandom)
|
||||
Q(mkfs)
|
||||
Q(mount)
|
||||
Q(unmount)
|
||||
Q(dupterm)
|
||||
Q(readonly)
|
||||
Q(readblocks)
|
||||
Q(writeblocks)
|
||||
Q(sync)
|
||||
Q(count)
|
||||
|
||||
// for file class
|
||||
Q(seek)
|
||||
Q(tell)
|
||||
Q(input)
|
||||
Q(flush)
|
||||
|
||||
// for Pin class
|
||||
Q(Pin)
|
||||
Q(board)
|
||||
Q(init)
|
||||
Q(value)
|
||||
Q(low)
|
||||
Q(high)
|
||||
Q(toggle)
|
||||
Q(info)
|
||||
Q(name)
|
||||
Q(af)
|
||||
Q(id)
|
||||
Q(mode)
|
||||
Q(type)
|
||||
Q(strength)
|
||||
Q(pull)
|
||||
Q(drive)
|
||||
Q(alt)
|
||||
Q(alt_list)
|
||||
Q(IN)
|
||||
Q(OUT)
|
||||
Q(STD)
|
||||
Q(STD_PU)
|
||||
Q(STD_PD)
|
||||
Q(OD)
|
||||
Q(OD_PU)
|
||||
Q(OD_PD)
|
||||
Q(INT_RISING)
|
||||
Q(INT_FALLING)
|
||||
Q(INT_RISING_FALLING)
|
||||
Q(INT_LOW_LEVEL)
|
||||
Q(INT_HIGH_LEVEL)
|
||||
Q(S2MA)
|
||||
Q(S4MA)
|
||||
Q(S6MA)
|
||||
Q(OPEN_DRAIN)
|
||||
Q(ALT)
|
||||
Q(ALT_OPEN_DRAIN)
|
||||
Q(PULL_UP)
|
||||
Q(PULL_DOWN)
|
||||
Q(LOW_POWER)
|
||||
Q(MED_POWER)
|
||||
Q(HIGH_POWER)
|
||||
Q(IRQ_RISING)
|
||||
Q(IRQ_FALLING)
|
||||
Q(IRQ_LOW_LEVEL)
|
||||
Q(IRQ_HIGH_LEVEL)
|
||||
|
||||
// for UART class
|
||||
Q(UART)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(any)
|
||||
Q(sendbreak)
|
||||
Q(id)
|
||||
Q(baudrate)
|
||||
Q(bits)
|
||||
Q(stop)
|
||||
Q(parity)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(all)
|
||||
Q(writechar)
|
||||
Q(readchar)
|
||||
Q(sendbreak)
|
||||
Q(readinto)
|
||||
Q(read_buf_len)
|
||||
Q(timeout)
|
||||
Q(timeout_char)
|
||||
Q(repl_uart)
|
||||
Q(flow)
|
||||
Q(RTS)
|
||||
Q(CTS)
|
||||
Q(pins)
|
||||
Q(EVEN)
|
||||
Q(ODD)
|
||||
Q(RX_ANY)
|
||||
|
||||
// for I2C class
|
||||
Q(I2C)
|
||||
Q(id)
|
||||
Q(mode)
|
||||
Q(baudrate)
|
||||
Q(pins)
|
||||
Q(addr)
|
||||
Q(data)
|
||||
Q(nbytes)
|
||||
Q(buf)
|
||||
Q(stop)
|
||||
Q(memaddr)
|
||||
Q(addr_size)
|
||||
Q(addrsize)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(is_ready)
|
||||
Q(scan)
|
||||
Q(send)
|
||||
Q(recv)
|
||||
Q(mem_read)
|
||||
Q(mem_write)
|
||||
Q(readfrom)
|
||||
Q(readfrom_into)
|
||||
Q(writeto)
|
||||
Q(readfrom_mem)
|
||||
Q(readfrom_mem_into)
|
||||
Q(writeto_mem)
|
||||
Q(MASTER)
|
||||
|
||||
// for ADC class
|
||||
Q(ADC)
|
||||
Q(read)
|
||||
Q(ADCChannel)
|
||||
Q(value)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(channel)
|
||||
Q(id)
|
||||
Q(pin)
|
||||
|
||||
#if MICROPY_HW_HAS_SDCARD
|
||||
// for SD class
|
||||
Q(SD)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
#endif
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(id)
|
||||
Q(pins)
|
||||
|
||||
// for RTC class
|
||||
Q(RTC)
|
||||
Q(id)
|
||||
Q(init)
|
||||
Q(alarm)
|
||||
Q(alarm_left)
|
||||
Q(alarm_cancel)
|
||||
Q(now)
|
||||
Q(deinit)
|
||||
Q(datetime)
|
||||
Q(repeat)
|
||||
Q(ALARM0)
|
||||
|
||||
// for time class
|
||||
Q(time)
|
||||
Q(utime)
|
||||
Q(localtime)
|
||||
Q(mktime)
|
||||
Q(sleep)
|
||||
Q(time)
|
||||
Q(sleep_ms)
|
||||
Q(sleep_us)
|
||||
Q(ticks_ms)
|
||||
Q(ticks_us)
|
||||
Q(ticks_cpu)
|
||||
Q(ticks_diff)
|
||||
|
||||
// for select class
|
||||
Q(select)
|
||||
@@ -205,6 +228,10 @@ Q(register)
|
||||
Q(unregister)
|
||||
Q(modify)
|
||||
Q(poll)
|
||||
Q(POLLIN)
|
||||
Q(POLLOUT)
|
||||
Q(POLLERR)
|
||||
Q(POLLHUP)
|
||||
|
||||
// for socket class
|
||||
Q(socket)
|
||||
@@ -213,6 +240,7 @@ Q(getaddrinfo)
|
||||
Q(family)
|
||||
Q(type)
|
||||
Q(send)
|
||||
Q(sendall)
|
||||
Q(sendto)
|
||||
Q(recv)
|
||||
Q(recvfrom)
|
||||
@@ -223,113 +251,107 @@ Q(settimeout)
|
||||
Q(setblocking)
|
||||
Q(setsockopt)
|
||||
Q(close)
|
||||
Q(makefile)
|
||||
Q(protocol)
|
||||
Q(error)
|
||||
Q(timeout)
|
||||
Q(AF_INET)
|
||||
Q(AF_INET6)
|
||||
Q(SOCK_STREAM)
|
||||
Q(SOCK_DGRAM)
|
||||
Q(SOCK_RAW)
|
||||
Q(IPPROTO_SEC)
|
||||
Q(IPPROTO_TCP)
|
||||
Q(IPPROTO_UDP)
|
||||
Q(IPPROTO_RAW)
|
||||
|
||||
// for ssl class
|
||||
Q(ssl)
|
||||
Q(ussl)
|
||||
Q(wrap_socket)
|
||||
Q(sock)
|
||||
Q(keyfile)
|
||||
Q(certfile)
|
||||
Q(server_side)
|
||||
Q(cert_reqs)
|
||||
Q(ca_certs)
|
||||
Q(SSLError)
|
||||
Q(CERT_NONE)
|
||||
Q(CERT_OPTIONAL)
|
||||
Q(CERT_REQUIRED)
|
||||
|
||||
// for network class
|
||||
Q(network)
|
||||
Q(server_running)
|
||||
Q(server_login)
|
||||
Q(server_timeout)
|
||||
Q(Server)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(login)
|
||||
Q(timeout)
|
||||
Q(isrunning)
|
||||
|
||||
// for WLAN class
|
||||
Q(WLAN)
|
||||
Q(key)
|
||||
Q(security)
|
||||
Q(id)
|
||||
Q(init)
|
||||
Q(mode)
|
||||
Q(auth)
|
||||
Q(ssid)
|
||||
Q(bssid)
|
||||
Q(mac)
|
||||
Q(antenna)
|
||||
Q(scan)
|
||||
Q(connect)
|
||||
Q(isconnected)
|
||||
Q(disconnect)
|
||||
Q(sec)
|
||||
Q(channel)
|
||||
Q(rssi)
|
||||
Q(ifconfig)
|
||||
Q(info)
|
||||
Q(connections)
|
||||
Q(urn)
|
||||
Q(mode)
|
||||
Q(ip)
|
||||
Q(subnet)
|
||||
Q(gateway)
|
||||
Q(dns)
|
||||
Q(mac)
|
||||
Q(antenna)
|
||||
Q(config)
|
||||
//Q(connections)
|
||||
//Q(urn)
|
||||
Q(STA)
|
||||
Q(AP)
|
||||
Q(P2P)
|
||||
Q(OPEN)
|
||||
Q(WEP)
|
||||
Q(WPA_WPA2)
|
||||
Q(WPA_ENT)
|
||||
Q(WPS_PBC)
|
||||
Q(WPS_PIN)
|
||||
Q(INT_ANTENNA)
|
||||
Q(EXT_ANTENNA)
|
||||
Q(WPA)
|
||||
Q(WPA2)
|
||||
Q(INT_ANT)
|
||||
Q(EXT_ANT)
|
||||
Q(ANY_EVENT)
|
||||
|
||||
// for WDT class
|
||||
Q(WDT)
|
||||
Q(kick)
|
||||
Q(feed)
|
||||
Q(timeout)
|
||||
|
||||
// for HeartBeat class
|
||||
Q(HeartBeat)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
|
||||
// for callback class
|
||||
// for irq class
|
||||
Q(irq)
|
||||
Q(init)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
Q(callback)
|
||||
Q(flags)
|
||||
Q(trigger)
|
||||
Q(handler)
|
||||
Q(mode)
|
||||
Q(value)
|
||||
Q(priority)
|
||||
Q(wakes)
|
||||
|
||||
// for Sleep class
|
||||
Q(Sleep)
|
||||
Q(idle)
|
||||
Q(suspend)
|
||||
Q(hibernate)
|
||||
Q(reset_cause)
|
||||
Q(wake_reason)
|
||||
Q(ACTIVE)
|
||||
Q(SUSPENDED)
|
||||
Q(HIBERNATING)
|
||||
Q(POWER_ON)
|
||||
Q(HARD_RESET)
|
||||
Q(WDT_RESET)
|
||||
Q(HIB_RESET)
|
||||
Q(SOFT_RESET)
|
||||
Q(WLAN_WAKE)
|
||||
Q(PIN_WAKE)
|
||||
Q(RTC_WAKE)
|
||||
Q(wake)
|
||||
|
||||
// for SPI class
|
||||
Q(SPI)
|
||||
Q(id)
|
||||
Q(mode)
|
||||
Q(baudrate)
|
||||
Q(bits)
|
||||
Q(polarity)
|
||||
Q(phase)
|
||||
Q(nss)
|
||||
Q(firstbit)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(send)
|
||||
Q(recv)
|
||||
Q(send_recv)
|
||||
Q(write)
|
||||
Q(read)
|
||||
Q(readinto)
|
||||
Q(write_readinto)
|
||||
Q(nbytes)
|
||||
Q(buf)
|
||||
Q(MASTER)
|
||||
Q(ACTIVE_LOW)
|
||||
Q(ACTIVE_HIGH)
|
||||
Q(MSB)
|
||||
|
||||
// for Timer class
|
||||
Q(Timer)
|
||||
@@ -343,28 +365,28 @@ Q(width)
|
||||
Q(channel)
|
||||
Q(polarity)
|
||||
Q(duty_cycle)
|
||||
Q(time)
|
||||
Q(event_count)
|
||||
Q(event_time)
|
||||
Q(A)
|
||||
Q(B)
|
||||
Q(ONE_SHOT)
|
||||
Q(PERIODIC)
|
||||
Q(EDGE_COUNT)
|
||||
Q(EDGE_TIME)
|
||||
Q(PWM)
|
||||
Q(POSITIVE)
|
||||
Q(NEGATIVE)
|
||||
Q(TIMEOUT)
|
||||
Q(MATCH)
|
||||
|
||||
// for uhashlib module
|
||||
Q(uhashlib)
|
||||
Q(update)
|
||||
Q(digest)
|
||||
//Q(uhashlib)
|
||||
//Q(update)
|
||||
//Q(digest)
|
||||
//Q(md5)
|
||||
Q(sha1)
|
||||
Q(sha256)
|
||||
//Q(sha1)
|
||||
//Q(sha256)
|
||||
|
||||
// for ubinascii module
|
||||
Q(ubinascii)
|
||||
Q(hexlify)
|
||||
Q(unhexlify)
|
||||
Q(a2b_base64)
|
||||
Q(b2a_base64)
|
||||
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/misc.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/mphal.h"
|
||||
#include "serverstask.h"
|
||||
#include "simplelink.h"
|
||||
#include "debug.h"
|
||||
@@ -37,16 +38,9 @@
|
||||
#include "ftp.h"
|
||||
#include "pybwdt.h"
|
||||
#include "modusocket.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DEFINITIONS
|
||||
******************************************************************************/
|
||||
|
||||
#define SERVERS_DEF_USER "micro"
|
||||
#define SERVERS_DEF_PASS "python"
|
||||
#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes
|
||||
#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds
|
||||
#include "mpexception.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
@@ -57,13 +51,13 @@ typedef struct {
|
||||
bool do_disable;
|
||||
bool do_enable;
|
||||
bool do_reset;
|
||||
bool do_wlan_cycle_power;
|
||||
} servers_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
static servers_data_t servers_data = {.timeout = SERVERS_DEF_TIMEOUT_MS, .enabled = false, .do_disable = false,
|
||||
.do_enable = false, .do_reset = false};
|
||||
static servers_data_t servers_data = {.timeout = SERVERS_DEF_TIMEOUT_MS};
|
||||
static volatile bool sleep_sockets = false;
|
||||
|
||||
/******************************************************************************
|
||||
@@ -107,12 +101,15 @@ void TASK_Servers (void *pvParameters) {
|
||||
servers_data.do_disable = false;
|
||||
servers_data.enabled = false;
|
||||
}
|
||||
else if (servers_data.do_reset && servers_data.enabled) {
|
||||
telnet_reset();
|
||||
ftp_reset();
|
||||
else if (servers_data.do_reset) {
|
||||
// resetting the servers is needed to prevent half-open sockets
|
||||
servers_data.do_reset = false;
|
||||
// resetting the servers is needed to preven half-open sockets
|
||||
// and we should also close all user sockets
|
||||
if (servers_data.enabled) {
|
||||
telnet_reset();
|
||||
ftp_reset();
|
||||
}
|
||||
// and we should also close all user sockets. We do it here
|
||||
// for convinience and to save on code size.
|
||||
modusocket_close_all_user_sockets();
|
||||
}
|
||||
|
||||
@@ -124,10 +121,16 @@ void TASK_Servers (void *pvParameters) {
|
||||
}
|
||||
|
||||
if (sleep_sockets) {
|
||||
sleep_sockets = false;
|
||||
pybwdt_srv_sleeping(true);
|
||||
modusocket_enter_sleep();
|
||||
pybwdt_srv_sleeping(false);
|
||||
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 2);
|
||||
if (servers_data.do_wlan_cycle_power) {
|
||||
servers_data.do_wlan_cycle_power = false;
|
||||
wlan_off_on();
|
||||
}
|
||||
sleep_sockets = false;
|
||||
|
||||
}
|
||||
|
||||
// set the alive flag for the wdt
|
||||
@@ -135,34 +138,38 @@ void TASK_Servers (void *pvParameters) {
|
||||
|
||||
// move to the next cycle
|
||||
cycle = cycle ? false : true;
|
||||
HAL_Delay(SERVERS_CYCLE_TIME_MS);
|
||||
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void servers_start (void) {
|
||||
servers_data.do_enable = true;
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS * 5);
|
||||
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 3);
|
||||
}
|
||||
|
||||
void servers_stop (void) {
|
||||
servers_data.do_disable = true;
|
||||
do {
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS);
|
||||
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS);
|
||||
} while (servers_are_enabled());
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS * 5);
|
||||
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 3);
|
||||
}
|
||||
|
||||
void servers_reset (void) {
|
||||
servers_data.do_reset = true;
|
||||
}
|
||||
|
||||
void servers_wlan_cycle_power (void) {
|
||||
servers_data.do_wlan_cycle_power = true;
|
||||
}
|
||||
|
||||
bool servers_are_enabled (void) {
|
||||
return servers_data.enabled;
|
||||
}
|
||||
|
||||
void server_sleep_sockets (void) {
|
||||
sleep_sockets = true;
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS + 1);
|
||||
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS + 1);
|
||||
}
|
||||
|
||||
void servers_close_socket (int16_t *sd) {
|
||||
@@ -174,16 +181,19 @@ void servers_close_socket (int16_t *sd) {
|
||||
}
|
||||
|
||||
void servers_set_login (char *user, char *pass) {
|
||||
if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
memcpy(servers_user, user, SERVERS_USER_PASS_LEN_MAX);
|
||||
memcpy(servers_pass, pass, SERVERS_USER_PASS_LEN_MAX);
|
||||
}
|
||||
|
||||
bool servers_set_timeout (uint32_t timeout) {
|
||||
void servers_set_timeout (uint32_t timeout) {
|
||||
if (timeout < SERVERS_MIN_TIMEOUT_MS) {
|
||||
return false;
|
||||
// timeout is too low
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
servers_data.timeout = timeout;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t servers_get_timeout (void) {
|
||||
|
||||
@@ -31,14 +31,19 @@
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define SERVERS_PRIORITY 2
|
||||
#define SERVERS_STACK_SIZE 1072
|
||||
#define SERVERS_STACK_SIZE 1024
|
||||
|
||||
#define SERVERS_SSID_LEN_MAX 16
|
||||
#define SERVERS_KEY_LEN_MAX 16
|
||||
|
||||
#define SERVERS_USER_PASS_LEN_MAX 16
|
||||
#define SERVERS_USER_PASS_LEN_MAX 32
|
||||
|
||||
#define SERVERS_CYCLE_TIME_MS 5
|
||||
#define SERVERS_CYCLE_TIME_MS 2
|
||||
|
||||
#define SERVERS_DEF_USER "micro"
|
||||
#define SERVERS_DEF_PASS "python"
|
||||
#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes
|
||||
#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
@@ -57,11 +62,12 @@ extern void TASK_Servers (void *pvParameters);
|
||||
extern void servers_start (void);
|
||||
extern void servers_stop (void);
|
||||
extern void servers_reset (void);
|
||||
extern void servers_wlan_cycle_power (void);
|
||||
extern bool servers_are_enabled (void);
|
||||
extern void servers_close_socket (int16_t *sd);
|
||||
extern void servers_set_login (char *user, char *pass);
|
||||
extern void server_sleep_sockets (void);
|
||||
extern bool servers_set_timeout (uint32_t timeout);
|
||||
extern void servers_set_timeout (uint32_t timeout);
|
||||
extern uint32_t servers_get_timeout (void);
|
||||
|
||||
#endif /* SERVERSTASK_H_ */
|
||||
|
||||
@@ -44,9 +44,7 @@
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
#include "portmacro.h"
|
||||
#include <osi.h>
|
||||
|
||||
#include "rom.h"
|
||||
#include "osi.h"
|
||||
#include "rom_map.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "interrupt.h"
|
||||
@@ -457,7 +455,7 @@ OsiReturnVal_e VStartSimpleLinkSpawnTask(unsigned portBASE_TYPE uxPriority)
|
||||
ASSERT (xSimpleLinkSpawnQueue != NULL);
|
||||
|
||||
ASSERT (pdPASS == xTaskCreate( vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN",\
|
||||
736 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl ));
|
||||
896 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl ));
|
||||
|
||||
return OSI_OK;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "telnet.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "mpexception.h"
|
||||
#include "serverstask.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "irq.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
@@ -46,7 +47,7 @@
|
||||
// rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256
|
||||
#define TELNET_RX_BUFFER_SIZE 256
|
||||
#define TELNET_MAX_CLIENTS 1
|
||||
#define TELNET_TX_RETRIES_MAX 25
|
||||
#define TELNET_TX_RETRIES_MAX 50
|
||||
#define TELNET_WAIT_TIME_MS 5
|
||||
#define TELNET_LOGIN_RETRIES_MAX 3
|
||||
#define TELNET_CYCLE_TIME_MS (SERVERS_CYCLE_TIME_MS * 2)
|
||||
@@ -107,9 +108,9 @@ typedef struct {
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
static telnet_data_t telnet_data;
|
||||
static const char* telnet_welcome_msg = "Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
|
||||
static const char* telnet_request_user = "Login as:";
|
||||
static const char* telnet_request_password = "Password:";
|
||||
static const char* telnet_welcome_msg = "MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
|
||||
static const char* telnet_request_user = "Login as: ";
|
||||
static const char* telnet_request_password = "Password: ";
|
||||
static const char* telnet_invalid_loggin = "\r\nInvalid credentials, try again.\r\n";
|
||||
static const char* telnet_loggin_success = "\r\nLogin succeeded!\r\nType \"help()\" for more information.\r\n";
|
||||
static const uint8_t telnet_options_user[] = // IAC WONT ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE
|
||||
@@ -243,34 +244,14 @@ void telnet_run (void) {
|
||||
}
|
||||
|
||||
void telnet_tx_strn (const char *str, int len) {
|
||||
if (len > 0 && telnet_data.n_sd > 0) {
|
||||
if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) {
|
||||
telnet_send_with_retries(telnet_data.n_sd, str, len);
|
||||
}
|
||||
}
|
||||
|
||||
void telnet_tx_strn_cooked (const char *str, uint len) {
|
||||
int32_t nslen = 0;
|
||||
const char *_str = str;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
|
||||
telnet_send_with_retries(telnet_data.n_sd, "\r\n", 2);
|
||||
_str += nslen + 1;
|
||||
nslen = 0;
|
||||
}
|
||||
else {
|
||||
nslen++;
|
||||
}
|
||||
}
|
||||
if (_str < str + len) {
|
||||
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
|
||||
}
|
||||
}
|
||||
|
||||
bool telnet_rx_any (void) {
|
||||
return (telnet_data.n_sd > 0) ? ((telnet_data.rxRindex != telnet_data.rxWindex) &&
|
||||
(telnet_data.state == E_TELNET_STE_LOGGED_IN)) : false;
|
||||
return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex &&
|
||||
telnet_data.state == E_TELNET_STE_LOGGED_IN) : false;
|
||||
}
|
||||
|
||||
int telnet_rx_char (void) {
|
||||
@@ -299,14 +280,6 @@ void telnet_reset (void) {
|
||||
telnet_data.state = E_TELNET_STE_START;
|
||||
}
|
||||
|
||||
bool telnet_is_enabled (void) {
|
||||
return telnet_data.enabled;
|
||||
}
|
||||
|
||||
bool telnet_is_active (void) {
|
||||
return (telnet_data.state == E_TELNET_STE_LOGGED_IN);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
@@ -478,9 +451,13 @@ static void telnet_parse_input (uint8_t *str, int16_t *len) {
|
||||
(*len)--;
|
||||
_str++;
|
||||
}
|
||||
else {
|
||||
else if (*_str > 0) {
|
||||
*str++ = *_str++;
|
||||
}
|
||||
else {
|
||||
_str++;
|
||||
*len -= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// in case we have received an incomplete telnet option, unlikely, but possible
|
||||
@@ -492,8 +469,9 @@ static void telnet_parse_input (uint8_t *str, int16_t *len) {
|
||||
|
||||
static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len) {
|
||||
int32_t retries = 0;
|
||||
// abort sending if we happen to be within interrupt context
|
||||
if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0) {
|
||||
uint32_t delay = TELNET_WAIT_TIME_MS;
|
||||
// only if we are not within interrupt context and interrupts are enabled
|
||||
if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) {
|
||||
do {
|
||||
_i16 result = sl_Send(sd, pBuf, len, 0);
|
||||
if (result > 0) {
|
||||
@@ -502,7 +480,8 @@ static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len)
|
||||
else if (SL_EAGAIN != result) {
|
||||
return false;
|
||||
}
|
||||
HAL_Delay (TELNET_WAIT_TIME_MS);
|
||||
// start with the default delay and increment it on each retry
|
||||
mp_hal_delay_ms(delay++);
|
||||
} while (++retries <= TELNET_TX_RETRIES_MAX);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -33,13 +33,10 @@
|
||||
extern void telnet_init (void);
|
||||
extern void telnet_run (void);
|
||||
extern void telnet_tx_strn (const char *str, int len);
|
||||
extern void telnet_tx_strn_cooked (const char *str, uint len);
|
||||
extern bool telnet_rx_any (void);
|
||||
extern int telnet_rx_char (void);
|
||||
extern void telnet_enable (void);
|
||||
extern void telnet_disable (void);
|
||||
extern void telnet_reset (void);
|
||||
extern bool telnet_is_enabled (void);
|
||||
extern bool telnet_is_active (void);
|
||||
|
||||
#endif /* TELNET_H_ */
|
||||
|
||||
76
cc3200/tools/smoke.py
Normal file
76
cc3200/tools/smoke.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from machine import Pin
|
||||
from machine import RTC
|
||||
import time
|
||||
import os
|
||||
|
||||
"""
|
||||
Execute it like this:
|
||||
|
||||
python3 run-tests --target wipy --device 192.168.1.1 ../cc3200/tools/smoke.py
|
||||
"""
|
||||
|
||||
pin_map = [23, 24, 11, 12, 13, 14, 15, 16, 17, 22, 28, 10, 9, 8, 7, 6, 30, 31, 3, 0, 4, 5]
|
||||
test_bytes = os.urandom(1024)
|
||||
|
||||
def test_pin_read (pull):
|
||||
# enable the pull resistor on all pins, then read the value
|
||||
for p in pin_map:
|
||||
pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull)
|
||||
# read the pin value
|
||||
print(pin())
|
||||
|
||||
def test_pin_shorts (pull):
|
||||
if pull == Pin.PULL_UP:
|
||||
pull_inverted = Pin.PULL_DOWN
|
||||
else:
|
||||
pull_inverted = Pin.PULL_UP
|
||||
# enable all pulls of the specified type
|
||||
for p in pin_map:
|
||||
pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull_inverted)
|
||||
# then change the pull one pin at a time and read its value
|
||||
i = 0
|
||||
while i < len(pin_map):
|
||||
pin = Pin('GP' + str(pin_map[i]), mode=Pin.IN, pull=pull)
|
||||
Pin('GP' + str(pin_map[i - 1]), mode=Pin.IN, pull=pull_inverted)
|
||||
i += 1
|
||||
# read the pin value
|
||||
print(pin())
|
||||
|
||||
test_pin_read(Pin.PULL_UP)
|
||||
test_pin_read(Pin.PULL_DOWN)
|
||||
test_pin_shorts(Pin.PULL_UP)
|
||||
test_pin_shorts(Pin.PULL_DOWN)
|
||||
|
||||
# create a test directory
|
||||
os.mkdir('/flash/test')
|
||||
os.chdir('/flash/test')
|
||||
print(os.getcwd())
|
||||
# create a new file
|
||||
f = open('test.txt', 'w')
|
||||
n_w = f.write(test_bytes)
|
||||
print(n_w == len(test_bytes))
|
||||
f.close()
|
||||
f = open('test.txt', 'r')
|
||||
r = bytes(f.readall(), 'ascii')
|
||||
# check that we can write and read it correctly
|
||||
print(r == test_bytes)
|
||||
f.close()
|
||||
os.remove('test.txt')
|
||||
os.chdir('..')
|
||||
os.rmdir('test')
|
||||
|
||||
ls = os.listdir()
|
||||
print('test' not in ls)
|
||||
print(ls)
|
||||
|
||||
# test the real time clock
|
||||
rtc = RTC()
|
||||
while rtc.now()[6] > 800:
|
||||
pass
|
||||
|
||||
time1 = rtc.now()
|
||||
time.sleep_ms(1000)
|
||||
time2 = rtc.now()
|
||||
print(time2[5] - time1[5] == 1)
|
||||
print(time2[6] - time1[6] < 5000) # microseconds
|
||||
|
||||
95
cc3200/tools/smoke.py.exp
Normal file
95
cc3200/tools/smoke.py.exp
Normal file
@@ -0,0 +1,95 @@
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
/flash/test
|
||||
True
|
||||
True
|
||||
True
|
||||
['main.py', 'sys', 'lib', 'cert', 'boot.py']
|
||||
True
|
||||
True
|
||||
81
cc3200/tools/uniflash.py
Normal file
81
cc3200/tools/uniflash.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Flash the WiPy (format, update service pack and program).
|
||||
|
||||
Example:
|
||||
|
||||
> python uniflash.py -u "C:\ti\uniflash_3.2\uniflashCLI.bat" -c "C:\VirtualBoxShared\GitHub\wipy_uniflash.usf" -p 8 -s "C:\ti\CC31xx_CC32xx_ServicePack_1.0.0.10.0\servicepack_1.0.0.10.0.bin"
|
||||
|
||||
or:
|
||||
|
||||
> python uniflash.py -u "C:\ti\uniflash_3.2\uniflashCLI.bat" -c "C:\VirtualBoxShared\GitHub\launchxl_uniflash.usf" -p 8 -s "C:\ti\CC31xx_CC32xx_ServicePack_1.0.0.10.0\servicepack_1.0.0.10.0.bin"
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
|
||||
def print_exception(e):
|
||||
print ('Exception: {}, on line {}'.format(e, sys.exc_info()[-1].tb_lineno))
|
||||
|
||||
|
||||
def execute(command):
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
cmd_log = ""
|
||||
|
||||
# Poll process for new output until finished
|
||||
while True:
|
||||
nextline = process.stdout.readline()
|
||||
if nextline == '' and process.poll() != None:
|
||||
break
|
||||
sys.stdout.write(nextline)
|
||||
sys.stdout.flush()
|
||||
cmd_log += nextline
|
||||
|
||||
output = process.communicate()[0]
|
||||
exitCode = process.returncode
|
||||
|
||||
if exitCode == 0:
|
||||
return cmd_log
|
||||
else:
|
||||
raise ProcessException(command, exitCode, output)
|
||||
|
||||
def main():
|
||||
cmd_parser = argparse.ArgumentParser(description='Flash the WiPy and optionally run a small test on it.')
|
||||
cmd_parser.add_argument('-u', '--uniflash', default=None, help='the path to the uniflash cli executable')
|
||||
cmd_parser.add_argument('-c', '--config', default=None, help='the path to the uniflash config file')
|
||||
cmd_parser.add_argument('-p', '--port', default=8, help='the com serial port')
|
||||
cmd_parser.add_argument('-s', '--servicepack', default=None, help='the path to the servicepack file')
|
||||
args = cmd_parser.parse_args()
|
||||
|
||||
output = ""
|
||||
com_port = 'com=' + str(args.port)
|
||||
servicepack_path = 'spPath=' + args.servicepack
|
||||
|
||||
try:
|
||||
if args.uniflash == None or args.config == None:
|
||||
raise ValueError('uniflash path and config path are mandatory')
|
||||
if args.servicepack == None:
|
||||
output += execute([args.uniflash, '-config', args.config, '-setOptions', com_port, '-operations', 'format', 'program'])
|
||||
else:
|
||||
output += execute([args.uniflash, '-config', args.config, '-setOptions', com_port, servicepack_path, '-operations', 'format', 'servicePackUpdate', 'program'])
|
||||
except Exception as e:
|
||||
print_exception(e)
|
||||
output = ""
|
||||
finally:
|
||||
if "Finish Executing operation: program" in output:
|
||||
print("======================================")
|
||||
print("Board programmed OK")
|
||||
print("======================================")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("======================================")
|
||||
print("ERROR: Programming failed!")
|
||||
print("======================================")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
200
cc3200/tools/update-wipy.py
Normal file
200
cc3200/tools/update-wipy.py
Normal file
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
The WiPy firmware update script. Transmits the specified firmware file
|
||||
over FTP, and then resets the WiPy and optionally verifies that software
|
||||
was correctly updated.
|
||||
|
||||
Usage:
|
||||
|
||||
./update-wipy.py --file "path_to_mcuimg.bin" --verify
|
||||
|
||||
Or:
|
||||
|
||||
python update-wipy.py --file "path_to_mcuimg.bin"
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
import socket
|
||||
from ftplib import FTP
|
||||
from telnetlib import Telnet
|
||||
|
||||
|
||||
def print_exception(e):
|
||||
print ('Exception: {}, on line {}'.format(e, sys.exc_info()[-1].tb_lineno))
|
||||
|
||||
|
||||
def ftp_directory_exists(ftpobj, directory_name):
|
||||
filelist = []
|
||||
ftpobj.retrlines('LIST',filelist.append)
|
||||
for f in filelist:
|
||||
if f.split()[-1] == directory_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def transfer_file(args):
|
||||
with FTP(args.ip, timeout=20) as ftp:
|
||||
print ('FTP connection established')
|
||||
|
||||
if '230' in ftp.login(args.user, args.password):
|
||||
print ('Login successful')
|
||||
|
||||
if '250' in ftp.cwd('/flash'):
|
||||
if not ftp_directory_exists(ftp, 'sys'):
|
||||
print ('/flash/sys directory does not exist')
|
||||
if not '550' in ftp.mkd('sys'):
|
||||
print ('/flash/sys directory created')
|
||||
else:
|
||||
print ('Error: cannot create /flash/sys directory')
|
||||
return False
|
||||
if '250' in ftp.cwd('sys'):
|
||||
print ("Entered '/flash/sys' directory")
|
||||
with open(args.file, "rb") as fwfile:
|
||||
print ('Firmware image found, initiating transfer...')
|
||||
if '226' in ftp.storbinary("STOR " + 'mcuimg.bin', fwfile, 512):
|
||||
print ('File transfer complete')
|
||||
return True
|
||||
else:
|
||||
print ('Error: file transfer failed')
|
||||
else:
|
||||
print ('Error: cannot enter /flash/sys directory')
|
||||
else:
|
||||
print ('Error: cannot enter /flash directory')
|
||||
else:
|
||||
print ('Error: ftp login failed')
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def reset_board(args):
|
||||
success = False
|
||||
|
||||
try:
|
||||
tn = Telnet(args.ip, timeout=5)
|
||||
print("Connected via Telnet, trying to login now")
|
||||
|
||||
if b'Login as:' in tn.read_until(b"Login as:", timeout=5):
|
||||
tn.write(bytes(args.user, 'ascii') + b"\r\n")
|
||||
|
||||
if b'Password:' in tn.read_until(b"Password:", timeout=5):
|
||||
# needed because of internal implementation details of the WiPy's telnet server
|
||||
time.sleep(0.2)
|
||||
tn.write(bytes(args.password, 'ascii') + b"\r\n")
|
||||
|
||||
if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
|
||||
print("Telnet login succeeded")
|
||||
tn.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
|
||||
time.sleep(1)
|
||||
tn.write(b'\r\x02') # ctrl-B: enter friendly REPL
|
||||
if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
|
||||
tn.write(b"import machine\r\n")
|
||||
tn.write(b"machine.reset()\r\n")
|
||||
time.sleep(2)
|
||||
print("Reset performed")
|
||||
success = True
|
||||
else:
|
||||
print("Error: cannot enter friendly REPL")
|
||||
else:
|
||||
print("Error: telnet login failed")
|
||||
|
||||
except Exception as e:
|
||||
print_exception(e)
|
||||
finally:
|
||||
try:
|
||||
tn.close()
|
||||
except Exception as e:
|
||||
pass
|
||||
return success
|
||||
|
||||
|
||||
def verify_update(args):
|
||||
success = False
|
||||
firmware_tag = ''
|
||||
|
||||
def find_tag (tag):
|
||||
if tag in firmware_tag:
|
||||
print("Verification passed")
|
||||
return True
|
||||
else:
|
||||
print("Error: verification failed, the git tag doesn't match")
|
||||
return False
|
||||
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
# Specify a longer time out value here because the board has just been
|
||||
# reset and the wireless connection might not be fully established yet
|
||||
tn = Telnet(args.ip, timeout=10)
|
||||
print("Connected via telnet again, lets check the git tag")
|
||||
break
|
||||
except socket.timeout:
|
||||
if retries < 5:
|
||||
print("Timeout while connecting via telnet, retrying...")
|
||||
retries += 1
|
||||
else:
|
||||
print('Error: Telnet connection timed out!')
|
||||
return False
|
||||
|
||||
try:
|
||||
firmware_tag = tn.read_until (b'with CC3200')
|
||||
tag_file_path = args.file.rstrip('mcuimg.bin') + 'genhdr/mpversion.h'
|
||||
|
||||
if args.tag is not None:
|
||||
success = find_tag(bytes(args.tag, 'ascii'))
|
||||
else:
|
||||
with open(tag_file_path) as tag_file:
|
||||
for line in tag_file:
|
||||
bline = bytes(line, 'ascii')
|
||||
if b'MICROPY_GIT_HASH' in bline:
|
||||
bline = bline.lstrip(b'#define MICROPY_GIT_HASH ').replace(b'"', b'').replace(b'\r', b'').replace(b'\n', b'')
|
||||
success = find_tag(bline)
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print_exception(e)
|
||||
finally:
|
||||
try:
|
||||
tn.close()
|
||||
except Exception as e:
|
||||
pass
|
||||
return success
|
||||
|
||||
|
||||
def main():
|
||||
cmd_parser = argparse.ArgumentParser(description='Update the WiPy firmware with the specified image file')
|
||||
cmd_parser.add_argument('-f', '--file', default=None, help='the path of the firmware file')
|
||||
cmd_parser.add_argument('-u', '--user', default='micro', help='the username')
|
||||
cmd_parser.add_argument('-p', '--password', default='python', help='the login password')
|
||||
cmd_parser.add_argument('--ip', default='192.168.1.1', help='the ip address of the WiPy')
|
||||
cmd_parser.add_argument('--verify', action='store_true', help='verify that the update succeeded')
|
||||
cmd_parser.add_argument('-t', '--tag', default=None, help='git tag of the firmware image')
|
||||
args = cmd_parser.parse_args()
|
||||
|
||||
result = 1
|
||||
|
||||
try:
|
||||
if args.file is None:
|
||||
raise ValueError('the image file path must be specified')
|
||||
if transfer_file(args):
|
||||
if reset_board(args):
|
||||
if args.verify:
|
||||
print ('Waiting for the WiFi connection to come up again...')
|
||||
# this time is to allow the system's wireless network card to
|
||||
# connect to the WiPy again.
|
||||
time.sleep(5)
|
||||
if verify_update(args):
|
||||
result = 0
|
||||
else:
|
||||
result = 0
|
||||
|
||||
except Exception as e:
|
||||
print_exception(e)
|
||||
finally:
|
||||
sys.exit(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -41,7 +41,6 @@
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void CRYPTOHASH_Init (void) {
|
||||
// Enable the Data Hashing and Transform Engine
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_DTHE, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "py/gc.h"
|
||||
#include "gccollect.h"
|
||||
#include "gchelper.h"
|
||||
#include MICROPY_HAL_H
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
|
||||
@@ -32,22 +32,21 @@
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "random.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* LOCAL TYPES
|
||||
******************************************************************************/
|
||||
typedef union Id_t {
|
||||
typedef union _rng_id_t {
|
||||
uint32_t id32;
|
||||
uint16_t id16[3];
|
||||
uint8_t id8[6];
|
||||
} Id_t;
|
||||
} rng_id_t;
|
||||
|
||||
/******************************************************************************
|
||||
* LOCAL VARIABLES
|
||||
@@ -57,45 +56,38 @@ static uint32_t s_seed;
|
||||
/******************************************************************************
|
||||
* LOCAL FUNCTION DECLARATIONS
|
||||
******************************************************************************/
|
||||
static uint32_t lfsr (uint32_t input);
|
||||
STATIC uint32_t lfsr (uint32_t input);
|
||||
|
||||
/******************************************************************************
|
||||
* PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
static uint32_t lfsr (uint32_t input) {
|
||||
STATIC uint32_t lfsr (uint32_t input) {
|
||||
assert( input != 0 );
|
||||
|
||||
/*lint -save -e501*/
|
||||
return (input >> 1) ^ (-(input & 0x01) & 0x00E10000);
|
||||
/*lint -restore*/
|
||||
}
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
/// \moduleref rng
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings;
|
||||
|
||||
/// \function rng()
|
||||
/// Return a 24-bit hardware generated random number.
|
||||
STATIC mp_obj_t pyb_rng_get(void) {
|
||||
STATIC mp_obj_t machine_rng_get(void) {
|
||||
return mp_obj_new_int(rng_get());
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
|
||||
#endif
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_rng_get_obj, machine_rng_get);
|
||||
|
||||
/******************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void rng_init0 (void) {
|
||||
Id_t juggler;
|
||||
rng_id_t juggler;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
|
||||
wlan_get_mac (juggler.id8);
|
||||
|
||||
// Flatten the 48-bit board identification to 24 bits
|
||||
// flatten the 48-bit board identification to 24 bits
|
||||
juggler.id16[0] ^= juggler.id16[2];
|
||||
|
||||
juggler.id8[0] ^= juggler.id8[3];
|
||||
@@ -104,7 +96,8 @@ void rng_init0 (void) {
|
||||
|
||||
s_seed = juggler.id32 & 0x00FFFFFF;
|
||||
s_seed += (seconds & 0x000FFFFF) + mseconds;
|
||||
// The seed must not be zero
|
||||
|
||||
// the seed must not be zero
|
||||
if (s_seed == 0) {
|
||||
s_seed = 1;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
void rng_init0 (void);
|
||||
uint32_t rng_get (void);
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_rng_get_obj);
|
||||
#endif
|
||||
MP_DECLARE_CONST_FUN_OBJ(machine_rng_get_obj);
|
||||
|
||||
#endif // __RANDOM_H
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@ global variable with the backup registers
|
||||
.extern vault_arm_registers
|
||||
@ global function that performs the wake up actions
|
||||
.extern pybsleep_suspend_exit
|
||||
.extern pyb_sleep_suspend_exit
|
||||
|
||||
@ uint sleep_store(void)
|
||||
.global sleep_store
|
||||
@@ -58,4 +58,4 @@ sleep_restore:
|
||||
msr basepri, r0
|
||||
dsb
|
||||
isb
|
||||
bl pybsleep_suspend_exit
|
||||
bl pyb_sleep_suspend_exit
|
||||
|
||||
@@ -27,6 +27,6 @@
|
||||
#ifndef VERSION_H_
|
||||
#define VERSION_H_
|
||||
|
||||
#define WIPY_SW_VERSION_NUMBER "0.9.1"
|
||||
#define WIPY_SW_VERSION_NUMBER "1.2.0"
|
||||
|
||||
#endif /* VERSION_H_ */
|
||||
|
||||
28
docs/README.md
Normal file
28
docs/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
MicroPython Documentation
|
||||
=========================
|
||||
|
||||
The MicroPython documentation can be found at:
|
||||
http://docs.micropython.org/en/latest/
|
||||
|
||||
The documentation you see there is generated from the files in the docs tree:
|
||||
https://github.com/micropython/micropython/tree/master/docs
|
||||
|
||||
Building the documentation locally
|
||||
----------------------------------
|
||||
|
||||
If you're making changes to the documentation, you may want to build the
|
||||
documentation locally so that you can preview your changes.
|
||||
|
||||
Install Sphinx, and optionally (for the RTD-styling), sphinx_rtd_theme,
|
||||
preferably in a virtualenv:
|
||||
|
||||
pip install sphinx
|
||||
pip install sphinx_rtd_theme
|
||||
|
||||
In `micropython/docs`, build the docs:
|
||||
|
||||
make MICROPY_PORT=<port_name> BUILDDIR=build/<port_name> html
|
||||
|
||||
Where `<port_name>` can be `unix`, `pyboard`, `wipy` or `esp8266`.
|
||||
|
||||
You'll find the index page at `micropython/docs/build/<port_name>/html/index.html`.
|
||||
76
docs/conf.py
76
docs/conf.py
@@ -21,6 +21,40 @@ import os
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# Work out the port to generate the docs for
|
||||
from collections import OrderedDict
|
||||
micropy_port = os.getenv('MICROPY_PORT') or 'pyboard'
|
||||
tags.add('port_' + micropy_port)
|
||||
ports = OrderedDict((
|
||||
('unix', ('unix', 'unix')),
|
||||
('pyboard', ('pyboard', 'the pyboard')),
|
||||
('wipy', ('WiPy', 'the WiPy')),
|
||||
('esp8266', ('ESP8266', 'the ESP8266')),
|
||||
))
|
||||
|
||||
# The members of the html_context dict are available inside topindex.html
|
||||
micropy_version = os.getenv('MICROPY_VERSION') or 'latest'
|
||||
micropy_all_versions = (os.getenv('MICROPY_ALL_VERSIONS') or 'latest').split(',')
|
||||
url_pattern = '%s/en/%%s/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',)
|
||||
html_context = {
|
||||
'port':micropy_port,
|
||||
'port_short_name':ports[micropy_port][0],
|
||||
'port_name':ports[micropy_port][1],
|
||||
'port_version':micropy_version,
|
||||
'all_ports':[
|
||||
(port_name[0], url_pattern % (micropy_version, port_id))
|
||||
for port_id, port_name in ports.items()
|
||||
],
|
||||
'all_versions':[
|
||||
(ver, url_pattern % (ver, micropy_port))
|
||||
for ver in micropy_all_versions
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# Specify a custom master document based on the port name
|
||||
master_doc = micropy_port + '_' + 'index'
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
@@ -51,16 +85,16 @@ source_suffix = '.rst'
|
||||
|
||||
# General information about the project.
|
||||
project = 'MicroPython'
|
||||
copyright = '2014, Damien P. George'
|
||||
copyright = '2014-2016, Damien P. George and contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.4'
|
||||
version = '1.7'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.4.4'
|
||||
release = '1.7'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -213,8 +247,8 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'MicroPython.tex', 'MicroPython Documentation',
|
||||
'Damien P. George', 'manual'),
|
||||
(master_doc, 'MicroPython.tex', 'MicroPython Documentation',
|
||||
'Damien P. George and contributors', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@@ -244,7 +278,7 @@ latex_documents = [
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'micropython', 'MicroPython Documentation',
|
||||
['Damien P. George'], 1),
|
||||
['Damien P. George and contributors'], 1),
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
@@ -257,8 +291,8 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'MicroPython', 'MicroPython Documentation',
|
||||
'Damien P. George', 'MicroPython', 'One line description of project.',
|
||||
(master_doc, 'MicroPython', 'MicroPython Documentation',
|
||||
'Damien P. George and contributors', 'MicroPython', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
@@ -278,28 +312,8 @@ texinfo_documents = [
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
|
||||
|
||||
# Work out the port to generate the docs for
|
||||
from collections import OrderedDict
|
||||
micropy_port = os.getenv('MICROPY_PORT') or 'pyboard'
|
||||
tags.add('port_' + micropy_port)
|
||||
ports = OrderedDict((
|
||||
("unix", "unix"),
|
||||
("pyboard", "the pyboard"),
|
||||
("wipy", "the WiPy"),
|
||||
("esp8266", "esp8266"),
|
||||
))
|
||||
|
||||
# The members of the html_context dict are available inside topindex.html
|
||||
url_prefix = os.getenv('MICROPY_URL_PREFIX') or '/'
|
||||
html_context = {
|
||||
'port':micropy_port,
|
||||
'port_name':ports[micropy_port],
|
||||
'all_ports':[(n, url_prefix + p) for p, n in ports.items()],
|
||||
}
|
||||
|
||||
# Append the other ports' specific folders/files to the exclude pattern
|
||||
exclude_patterns.extend([port + '*' for port in ports if port != micropy_port])
|
||||
|
||||
# Specify a custom master document based on the port name
|
||||
master_doc = micropy_port + '_' + 'index'
|
||||
# Exclude pyb module if the port is the WiPy
|
||||
if micropy_port == 'wipy':
|
||||
exclude_patterns.append('library/pyb*')
|
||||
|
||||
254
docs/esp8266/quickref.rst
Normal file
254
docs/esp8266/quickref.rst
Normal file
@@ -0,0 +1,254 @@
|
||||
.. _quickref:
|
||||
|
||||
Quick reference for the ESP8266
|
||||
===============================
|
||||
|
||||
.. image:: https://learn.adafruit.com/system/assets/assets/000/028/689/medium640/adafruit_products_pinoutstop.jpg
|
||||
:alt: Adafruit Feather HUZZAH board
|
||||
:width: 640px
|
||||
|
||||
The Adafruit Feather HUZZAH board (image attribution: Adafruit).
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
|
||||
The MicroPython REPL is on UART0 (GPIO1=TX, GPIO3=RX) at baudrate 115200.
|
||||
Tab-completion is useful to find out what methods an object has.
|
||||
Paste mode (ctrl-E) is useful to paste a large slab of Python code into
|
||||
the REPL.
|
||||
|
||||
The ``machine`` module::
|
||||
|
||||
import machine
|
||||
|
||||
machine.freq() # get the current frequency of the CPU
|
||||
machine.freq(160000000) # set the CPU frequency to 160 MHz
|
||||
|
||||
The ``esp`` module::
|
||||
|
||||
import esp
|
||||
|
||||
esp.osdebug(None) # turn off vendor O/S debugging messages
|
||||
esp.osdebug(0) # redirect vendor O/S debugging messages to UART(0)
|
||||
|
||||
Networking
|
||||
----------
|
||||
|
||||
The ``network`` module::
|
||||
|
||||
import network
|
||||
|
||||
wlan = network.WLAN(network.STA_IF) # create station interface
|
||||
wlan.active(True) # activate the interface
|
||||
wlan.scan() # scan for access points
|
||||
wlan.isconnected() # check if the station is connected to an AP
|
||||
wlan.connect('essid', 'password') # connect to an AP
|
||||
wlan.mac() # get the interface's MAC adddress
|
||||
wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses
|
||||
|
||||
ap = network.WLAN(network.AP_IF) # create access-point interface
|
||||
ap.active(True) # activate the interface
|
||||
ap.config(essid='ESP-AP') # set the ESSID of the access point
|
||||
|
||||
A useful function for connecting to your local WiFi network is::
|
||||
|
||||
def do_connect():
|
||||
import network
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
if not wlan.isconnected():
|
||||
print('connecting to network...')
|
||||
wlan.connect('essid', 'password')
|
||||
while not wlan.isconnected():
|
||||
pass
|
||||
print('network config:', wlan.ifconfig())
|
||||
|
||||
Once the network is established the ``socket`` module can be used
|
||||
to create and use TCP/UDP sockets as usual.
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
Use the ``time`` module::
|
||||
|
||||
import time
|
||||
|
||||
time.sleep(1) # sleep for 1 second
|
||||
time.sleep_ms(500) # sleep for 500 milliseconds
|
||||
time.sleep_us(10) # sleep for 10 microseconds
|
||||
start = time.ticks_ms() # get millisecond counter
|
||||
delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference
|
||||
|
||||
Timers
|
||||
------
|
||||
|
||||
Virtual (RTOS-based) timers are supported. Use the ``machine.Timer`` class
|
||||
with timer ID of -1::
|
||||
|
||||
from machine import Timer
|
||||
|
||||
tim = Timer(-1)
|
||||
tim.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
|
||||
tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))
|
||||
|
||||
The period is in milliseconds.
|
||||
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
Use the ``machine.Pin`` class::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
p0 = Pin(0, Pin.OUT) # create output pin on GPIO0
|
||||
p0.high() # set pin to high
|
||||
p0.low() # set pin to low
|
||||
p0.value(1) # set pin to high
|
||||
|
||||
p2 = Pin(2, Pin.IN) # create input pin on GPIO2
|
||||
print(p2.value()) # get value, 0 or 1
|
||||
|
||||
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
|
||||
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
|
||||
|
||||
Available pins are: 0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16, which correspond
|
||||
to the actual GPIO pin numbers of ESP8266 chip. Note that many end-user
|
||||
boards use their own adhoc pin numbering (marked e.g. D0, D1, ...). As
|
||||
MicroPython supports different boards and modules, physical pin numbering
|
||||
was chosen as the lowest common denominator. For mapping between board
|
||||
logical pins and physical chip pins, consult your board documentation.
|
||||
|
||||
Note that Pin(1) and Pin(3) are REPL UART TX and RX respectively.
|
||||
Also note that Pin(16) is a special pin (used for wakeup from deepsleep
|
||||
mode) and may be not available for use with higher-level classes like
|
||||
``Neopixel``.
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
|
||||
PWM can be enabled on all pins except Pin(16). There is a single frequency
|
||||
for all channels, with range between 1 and 1000 (measured in Hz). The duty
|
||||
cycle is between 0 and 1023 inclusive.
|
||||
|
||||
Use the ``machine.PWM`` class::
|
||||
|
||||
from machine import Pin, PWM
|
||||
|
||||
pwm0 = PWM(Pin(0)) # create PWM object from a pin
|
||||
pwm0.freq() # get current frequency
|
||||
pwm0.freq(1000) # set frequency
|
||||
pwm0.duty() # get current duty cycle
|
||||
pwm0.duty(200) # set duty cycle
|
||||
pwm0.deinit() # turn off PWM on the pin
|
||||
|
||||
pwm2 = PWM(Pin(2), freq=500, duty=512) # create and configure in one go
|
||||
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
ADC is available on a dedicated pin.
|
||||
Note that input voltages on the ADC pin must be between 0v and 1.0v.
|
||||
|
||||
Use the ``machine.ADC`` class::
|
||||
|
||||
from machine import ADC
|
||||
|
||||
adc = ADC(0) # create ADC object on ADC pin
|
||||
adc.read() # read value, 0-1024
|
||||
|
||||
SPI bus
|
||||
-------
|
||||
|
||||
The SPI driver is implemented in software and works on all pins::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
# construct an SPI bus on the given pins
|
||||
# polarity is the idle state of SCK
|
||||
# phase=0 means sample on the first edge of SCK, phase=1 means the second
|
||||
spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
spi.read(10) # read 10 bytes on MISO
|
||||
spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI
|
||||
|
||||
buf = bytearray(50) # create a buffer
|
||||
spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case)
|
||||
spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI
|
||||
|
||||
spi.write(b'12345') # write 5 bytes on MOSI
|
||||
|
||||
buf = bytearray(4) # create a buffer
|
||||
spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer
|
||||
spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf
|
||||
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
The I2C driver is implemented in software and works on all pins::
|
||||
|
||||
from machine import Pin, I2C
|
||||
|
||||
# construct an I2C bus
|
||||
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
|
||||
|
||||
i2c.readfrom(0x3a, 4) # read 4 bytes from slave device with address 0x3a
|
||||
i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a
|
||||
|
||||
buf = bytearray(10) # create a buffer with 10 bytes
|
||||
i2c.writeto(0x3a, buf) # write the given buffer to the slave
|
||||
|
||||
i2c.readfrom(0x3a, 4, stop=False) # don't send a stop bit after reading
|
||||
i2c.writeto(0x3a, buf, stop=False) # don't send a stop bit after writing
|
||||
|
||||
OneWire driver
|
||||
--------------
|
||||
|
||||
The OneWire driver is implemented in software and works on all pins::
|
||||
|
||||
from machine import Pin
|
||||
import onewire
|
||||
|
||||
ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12
|
||||
ow.scan() # return a list of devices on the bus
|
||||
ow.reset() # reset the bus
|
||||
ow.read_byte() # read a byte
|
||||
ow.read_bytes(5) # read 5 bytes
|
||||
ow.write_byte(0x12) # write a byte on the bus
|
||||
ow.write_bytes('123') # write bytes on the bus
|
||||
ow.select_rom(b'12345678') # select a specific device by its ROM code
|
||||
|
||||
There is a specific driver for DS18B20 devices::
|
||||
|
||||
import time
|
||||
ds = onewire.DS18B20(ow)
|
||||
roms = ds.scan()
|
||||
ds.start_measure()
|
||||
time.sleep_ms(750)
|
||||
for rom in roms:
|
||||
print(ds.get_temp(rom))
|
||||
|
||||
Be sure to put a 4.7k pull-up resistor on the data line.
|
||||
|
||||
NeoPixel driver
|
||||
---------------
|
||||
|
||||
Use the ``neopixel`` module::
|
||||
|
||||
from machine import Pin
|
||||
from neopixel import NeoPixel
|
||||
|
||||
pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
|
||||
np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
|
||||
np[0] = (255, 255, 255) # set the first pixel to white
|
||||
np.write() # write data to all pixels
|
||||
r, g, b = np[0] # get first pixel colour
|
||||
|
||||
import neopixel
|
||||
neopixel.demo(np) # run a demo
|
||||
|
||||
For low-level driving of a NeoPixel::
|
||||
|
||||
import esp
|
||||
esp.neopixel_write(pin, grb_buf, is800khz)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user