Merge branch 'family/ambz2'
This commit is contained in:
3
.github/workflows/docs.yml
vendored
3
.github/workflows/docs.yml
vendored
@@ -25,7 +25,8 @@ jobs:
|
||||
run: |
|
||||
mkdir -p site/
|
||||
boardgen ltci
|
||||
python docs/scripts/update_docs.py
|
||||
python docs/scripts/write_boards.py
|
||||
python docs/scripts/write_apis.py
|
||||
python docs/scripts/prepare_doxygen.py
|
||||
python docs/scripts/build_json.py
|
||||
cp *.json site/
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -264,3 +264,5 @@ docs/status/supported_*.md
|
||||
docs/status/unsupported_boards_*.md
|
||||
boards/**/*.svg
|
||||
boards/**/*.md
|
||||
# other generated files
|
||||
docs/contrib/lt-api-functions.md
|
||||
|
||||
11
SUMMARY.md
11
SUMMARY.md
@@ -47,10 +47,13 @@
|
||||
* [Macros](ltapi/macros.md)
|
||||
* [File list](ltapi/files.md)
|
||||
* 👷 Contributor's manual (WIP)
|
||||
* [📁 Project structure](docs/dev/project-structure.md)
|
||||
* [✈️ OTA format](docs/dev/ota/README.md)
|
||||
* [uf2ota.py tool](docs/dev/ota/uf2ota.md)
|
||||
* [uf2ota.h library](docs/dev/ota/library.md)
|
||||
* [Porting new families](docs/contrib/porting.md)
|
||||
* [API functions guide](docs/contrib/lt-api.md)
|
||||
* [C standard library](docs/contrib/stdlib.md)
|
||||
* [📁 Project structure](docs/contrib/project-structure.md)
|
||||
* [✈️ OTA format](docs/contrib/ota/README.md)
|
||||
* [uf2ota.py tool](docs/contrib/ota/uf2ota.md)
|
||||
* [uf2ota.h library](docs/contrib/ota/library.md)
|
||||
* [📓 TODO](docs/TODO.md)
|
||||
* [](SUMMARY.md)
|
||||
* [🔗 Resources](docs/resources/)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03"
|
||||
},
|
||||
"flash": {
|
||||
"tuya": "0x1ED000+0x13000"
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,9 @@
|
||||
"pcb": {
|
||||
"templates": [
|
||||
"esp12s",
|
||||
"esp12s-shield",
|
||||
"pcb-black",
|
||||
"rf-type1"
|
||||
],
|
||||
"vars": {
|
||||
"MASK_PRESET": "mask_black",
|
||||
"TRACE_COLOR": "#FAFD9D",
|
||||
"SILK_COLOR": "white"
|
||||
},
|
||||
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
|
||||
"pinout": {
|
||||
"1": {
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
"flash": {
|
||||
"ota1": "0x00B000+0x75000",
|
||||
"ota2": "0x080000+0x75000",
|
||||
"kvs": "0xF5000+0x6000",
|
||||
"userdata": "0xFB000+0x104000",
|
||||
"rdp": "0x1FF000+0x1000"
|
||||
"kvs": "0x0F5000+0x8000",
|
||||
"userdata": "0x0FD000+0x102000"
|
||||
},
|
||||
"upload": {
|
||||
"flash_size": 2097152,
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
"flash": {
|
||||
"ota1": "0x00B000+0xC5000",
|
||||
"ota2": "0x0D0000+0xC5000",
|
||||
"kvs": "0x195000+0x6000",
|
||||
"userdata": "0x19B000+0x64000",
|
||||
"rdp": "0x1FF000+0x1000"
|
||||
"kvs": "0x195000+0x8000",
|
||||
"userdata": "0x19D000+0x62000"
|
||||
},
|
||||
"upload": {
|
||||
"flash_size": 2097152,
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
"ota1": "0x00B000+0xF5000",
|
||||
"ota2": "0x100000+0xF5000",
|
||||
"kvs": "0x1F5000+0x8000",
|
||||
"userdata": "0x1FD000+0x202000",
|
||||
"rdp": "0x3FF000+0x1000"
|
||||
"userdata": "0x1FD000+0x202000"
|
||||
},
|
||||
"upload": {
|
||||
"flash_size": 4194304,
|
||||
|
||||
5
boards/_base/realtek-ambz-tuya.json
Normal file
5
boards/_base/realtek-ambz-tuya.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"flash": {
|
||||
"tuya": "0x1EB000+0x15000"
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,8 @@
|
||||
"boot_xip": "0x000000+0x4000",
|
||||
"boot_ram": "0x004000+0x4000",
|
||||
"system": "0x009000+0x1000",
|
||||
"calibration": "0x00A000+0x1000"
|
||||
"calibration": "0x00A000+0x1000",
|
||||
"rdp": "0x1FF000+0x1000"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
@@ -47,10 +48,6 @@
|
||||
"General info": "../../docs/platform/realtek-amb/README.md",
|
||||
"Flashing guide": "../../docs/platform/realtek-ambz/flashing.md",
|
||||
"Debugging": "../../docs/platform/realtek-ambz/debugging.md"
|
||||
},
|
||||
"extra": [
|
||||
"RDP is most likely not used in Tuya firmwares, as the System Data partition contains an incorrect offset 0xFF000 for RDP, which is in the middle of OTA2 image.",
|
||||
"Additionally, Tuya firmware uses an encrypted KV or file storage, which resides at the end of flash memory. This seems to overlap system RDP area."
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
boards/_base/realtek-ambz2-2mb-900k.json
Normal file
12
boards/_base/realtek-ambz2-2mb-900k.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"flash": {
|
||||
"ota1": "0x010000+0xE0000",
|
||||
"ota2": "0x0F0000+0xE0000",
|
||||
"kvs": "0x1D0000+0x8000",
|
||||
"userdata": "0x1D8000+0x28000"
|
||||
},
|
||||
"upload": {
|
||||
"flash_size": 2097152,
|
||||
"maximum_size": 917504
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,7 @@
|
||||
"flash": {
|
||||
"ota1": "0x00C000+0xF8000",
|
||||
"ota2": "0x104000+0xF8000",
|
||||
"kvs": "0x1FC000+0x2000",
|
||||
"userdata": "0x1FE000+0x2000"
|
||||
"kvs": "0x1FC000+0x4000"
|
||||
},
|
||||
"upload": {
|
||||
"flash_size": 2097152,
|
||||
|
||||
96
boards/_base/realtek-ambz2-image.json
Normal file
96
boards/_base/realtek-ambz2-image.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"image": {
|
||||
"keys": {
|
||||
"decryption": "a0d6dae7e062ca94cbb294bf896b9f68cf8438774256ac7403ca4fd9a1c9564f",
|
||||
"keyblock": {
|
||||
"part_table": "882aa16c8c44a7760aa8c9ab22e3568c6fa16c2afa4f0cea29a10abcdf60e44f",
|
||||
"boot": "882aa16c8c44a7760aa8c9ab22e3568c6fa16c2afa4f0cea29a10abcdf60e44f"
|
||||
},
|
||||
"hash_keys": {
|
||||
"part_table": "47e5661335a4c5e0a94d69f3c737d54f2383791332939753ef24279608f6d72b",
|
||||
"boot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ota1": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e5f",
|
||||
"ota2": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e5f"
|
||||
},
|
||||
"user_keys": {
|
||||
"boot": "aa0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
|
||||
"ota1": "bb0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
|
||||
"ota2": "bb0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||
},
|
||||
"xip_sce_key": "a0d6dae7e062ca94cbb294bf896b9f68",
|
||||
"xip_sce_iv": "94879487948794879487948794879487"
|
||||
},
|
||||
"ptable": {
|
||||
"boot": "BOOT",
|
||||
"ota1": "FW1",
|
||||
"ota2": "FW2"
|
||||
},
|
||||
"boot": {
|
||||
"name": "boot.sram",
|
||||
"type": "SRAM",
|
||||
"entry": "__ram_start_table_start__",
|
||||
"elf": [
|
||||
".ram.func.table",
|
||||
".data",
|
||||
".ram.code_text",
|
||||
".ram.code_rodata"
|
||||
],
|
||||
"is_boot": true
|
||||
},
|
||||
"fw": [
|
||||
{
|
||||
"type": "FWHS_S",
|
||||
"sections": [
|
||||
{
|
||||
"name": "fwhs.sram",
|
||||
"type": "SRAM",
|
||||
"entry": "__ram_start_table_start__",
|
||||
"elf": [
|
||||
".ram.img.signature",
|
||||
".ram.func.table",
|
||||
".data",
|
||||
".ram.code_text",
|
||||
".ram.code_rodata"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fwhs.psram",
|
||||
"type": "PSRAM",
|
||||
"entry": "__psram_start__",
|
||||
"elf": [
|
||||
".psram.data",
|
||||
".psram.code_text",
|
||||
".psram.code_rodata"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "XIP",
|
||||
"sections": [
|
||||
{
|
||||
"name": "fwhs.xip_c",
|
||||
"entry": "XIP_RamImgSignature_s",
|
||||
"type": "XIP",
|
||||
"elf": [
|
||||
".xip.code_c"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "XIP",
|
||||
"sections": [
|
||||
{
|
||||
"name": "fwhs.xip_p",
|
||||
"entry": "__xip_code_rodata_start__",
|
||||
"type": "XIP",
|
||||
"elf": [
|
||||
".xip.code_p"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
5
boards/_base/realtek-ambz2-tuya.json
Normal file
5
boards/_base/realtek-ambz2-tuya.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"flash": {
|
||||
"tuya": "0x1D5000+0x10000"
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,20 @@
|
||||
},
|
||||
"debug": {
|
||||
"protocol": "openocd",
|
||||
"protocols": []
|
||||
"protocols": [
|
||||
"openocd"
|
||||
],
|
||||
"openocd_config": "amebaz2.cfg",
|
||||
"gdb_init": [
|
||||
"mem 0x9b000000 0x9c000000 ro"
|
||||
]
|
||||
},
|
||||
"upload": {
|
||||
"maximum_ram_size": 262144
|
||||
"maximum_ram_size": 262144,
|
||||
"protocol": "uart",
|
||||
"protocols": [
|
||||
"uart"
|
||||
]
|
||||
},
|
||||
"doc": {
|
||||
"params": {
|
||||
|
||||
26
boards/bw15.json
Normal file
26
boards/bw15.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz2",
|
||||
"realtek-ambz2-8720",
|
||||
"realtek-ambz2-image",
|
||||
"realtek-ambz2-2mb-992k",
|
||||
"ic/rtl8720cf",
|
||||
"pcb/bw15"
|
||||
],
|
||||
"build": {
|
||||
"mcu": "rtl8720cf",
|
||||
"variant": "bw15"
|
||||
},
|
||||
"name": "BW15",
|
||||
"url": "https://docs.ai-thinker.com/_media/rtl8710/docs/bw15_datasheet_en.pdf",
|
||||
"vendor": "Ai-Thinker Co., Ltd.",
|
||||
"pcb": {
|
||||
"symbol": "BW15"
|
||||
},
|
||||
"doc": {
|
||||
"fccid": "2AXVG-BW15",
|
||||
"links": {
|
||||
"Vendor datasheet": "https://docs.ai-thinker.com/_media/rtl8710/docs/bw15_datasheet_en.pdf"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cb1s",
|
||||
"pcb/cb1s-test"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cb2l",
|
||||
"pcb/cb2l-test"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cb2s",
|
||||
"pcb/cb2s-test"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cb3l"
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cb3s"
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cb3se"
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cblc5",
|
||||
"pcb/cblc5-test"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/cbu",
|
||||
"pcb/cbu-test"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"generic",
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32"
|
||||
],
|
||||
"build": {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32"
|
||||
],
|
||||
"build": {
|
||||
|
||||
102
boards/generic-rtl8720cf-2mb-992k.json
Normal file
102
boards/generic-rtl8720cf-2mb-992k.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"_base": [
|
||||
"generic",
|
||||
"realtek-ambz2",
|
||||
"realtek-ambz2-8720",
|
||||
"realtek-ambz2-image",
|
||||
"realtek-ambz2-2mb-992k",
|
||||
"ic/rtl8720cf"
|
||||
],
|
||||
"build": {
|
||||
"mcu": "rtl8720cf",
|
||||
"variant": "generic-rtl8720cf-2mb-992k"
|
||||
},
|
||||
"name": "Generic - RTL8720CF (2M/992k)",
|
||||
"symbol": "RTL8720CF (2M/992k)",
|
||||
"url": "https://docs.libretiny.eu/boards/generic-rtl8720cf-2mb-992k/",
|
||||
"vendor": "Generic",
|
||||
"pcb": {
|
||||
"pinout": {
|
||||
"1": {
|
||||
"IC": 15,
|
||||
"ARD": "D0"
|
||||
},
|
||||
"2": {
|
||||
"IC": 16,
|
||||
"ARD": "D1"
|
||||
},
|
||||
"3": {
|
||||
"IC": 18,
|
||||
"ARD": "D2"
|
||||
},
|
||||
"4": {
|
||||
"IC": 19,
|
||||
"ARD": "D3"
|
||||
},
|
||||
"5": {
|
||||
"IC": 20,
|
||||
"ARD": "D4"
|
||||
},
|
||||
"6": {
|
||||
"IC": 21,
|
||||
"ARD": "D5"
|
||||
},
|
||||
"7": {
|
||||
"IC": 22,
|
||||
"ARD": "D6"
|
||||
},
|
||||
"8": {
|
||||
"IC": 23,
|
||||
"ARD": "D7"
|
||||
},
|
||||
"9": {
|
||||
"IC": 24,
|
||||
"ARD": "D8"
|
||||
},
|
||||
"10": {
|
||||
"IC": 25,
|
||||
"ARD": "D9"
|
||||
},
|
||||
"11": {
|
||||
"IC": 26,
|
||||
"ARD": "D10"
|
||||
},
|
||||
"12": {
|
||||
"IC": 33,
|
||||
"ARD": "D11"
|
||||
},
|
||||
"13": {
|
||||
"IC": 34,
|
||||
"ARD": "D12"
|
||||
},
|
||||
"14": {
|
||||
"IC": 36,
|
||||
"ARD": "D13"
|
||||
},
|
||||
"15": {
|
||||
"IC": 37,
|
||||
"ARD": "D14"
|
||||
},
|
||||
"16": {
|
||||
"IC": 38,
|
||||
"ARD": "D15"
|
||||
},
|
||||
"17": {
|
||||
"IC": 39,
|
||||
"ARD": "D16"
|
||||
},
|
||||
"18": {
|
||||
"IC": 40,
|
||||
"ARD": "D17"
|
||||
},
|
||||
"19": {
|
||||
"IC": 1,
|
||||
"ARD": "D18"
|
||||
},
|
||||
"20": {
|
||||
"IC": 3,
|
||||
"ARD": "D19"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/lsc-lma35"
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/lsc-lma35"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wb1s"
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_base": [
|
||||
"beken-72xx",
|
||||
"beken-7231n",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wb2l",
|
||||
"pcb/wb2l-test",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wb2l",
|
||||
"pcb/wb2l-test"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wb2s",
|
||||
"pcb/wb2s-test"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wb3l"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wb3s"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"beken-72xx",
|
||||
"beken-7231",
|
||||
"beken-7231t",
|
||||
"beken-7231-crypt-tuya",
|
||||
"beken-7231-tuya",
|
||||
"ic/bk7231-qfn32",
|
||||
"pcb/wblc5",
|
||||
"pcb/wblc5-test"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"ic/rtl8710bn",
|
||||
"pcb/wr2-base",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"ic/rtl8710bn",
|
||||
"pcb/wr2-base",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"realtek-ambz-bx",
|
||||
"ic/rtl8710bn",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"realtek-ambz-bx",
|
||||
"ic/rtl8710bn",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"ic/rtl8710bn",
|
||||
"pcb/wr3-base",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"ic/rtl8710bn",
|
||||
"pcb/wr3-base",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"realtek-ambz-bx",
|
||||
"ic/rtl8710bn",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"realtek-ambz-bx",
|
||||
"ic/rtl8710bn",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"_base": [
|
||||
"realtek-ambz",
|
||||
"realtek-ambz-tuya",
|
||||
"realtek-ambz-2mb-788k",
|
||||
"ic/rtl8710bn",
|
||||
"pcb/wr3-base",
|
||||
|
||||
@@ -538,7 +538,7 @@ image_app_rblh = "${BUILD_DIR}/image_${MCULC}_app.${FLASH_RBL_OFFSET}.rblh"
|
||||
image_ota_rbl = "${BUILD_DIR}/image_${MCULC}_app.ota.rbl"
|
||||
env.Replace(
|
||||
# linker command (encryption + packaging)
|
||||
LINK="${LTCHIPTOOL} link2bin ${BOARD_JSON} '' ''",
|
||||
LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""',
|
||||
# UF2OTA input list
|
||||
UF2OTA=[
|
||||
# app binary image (enc+crc) for flasher
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright (c) Kuba Szczodrzyński 2022-07-20.
|
||||
|
||||
from os.path import join
|
||||
from os.path import isfile, join
|
||||
from shutil import copyfile
|
||||
|
||||
from platformio.platform.base import PlatformBase
|
||||
from platformio.platform.board import PlatformBoardConfig
|
||||
@@ -52,9 +53,10 @@ queue.AppendPublic(
|
||||
"-mthumb",
|
||||
"-mcmse",
|
||||
"-mfloat-abi=soft",
|
||||
"--specs=nosys.specs",
|
||||
"--specs=nano.specs",
|
||||
"-Wl,--use-blx",
|
||||
"-Wl,--undefined=gRamStartFun",
|
||||
"-Wl,--warn-section-align",
|
||||
"-Wl,-wrap,aesccmp_construct_mic_iv",
|
||||
"-Wl,-wrap,aesccmp_construct_mic_header1",
|
||||
"-Wl,-wrap,aesccmp_construct_ctr_preload",
|
||||
@@ -91,6 +93,7 @@ queue.AppendPublic(
|
||||
"-Wl,-wrap,memset",
|
||||
# TODO remove this if possible
|
||||
"-Wl,-wrap,putc",
|
||||
# rt_printf wrappers are not here, as they're just changing code using #defines
|
||||
],
|
||||
)
|
||||
|
||||
@@ -103,17 +106,7 @@ queue.AddLibrary(
|
||||
# cmsis
|
||||
"+<soc/realtek/8710c/cmsis/rtl8710c/source/ram/*.c>",
|
||||
"+<soc/realtek/8710c/cmsis/rtl8710c/source/ram_s/app_start.c>",
|
||||
# console
|
||||
"+<common/api/at_cmd/atcmd_bt.c>",
|
||||
"+<common/api/at_cmd/atcmd_lwip.c>",
|
||||
"+<common/api/at_cmd/atcmd_mp_ext2.c>",
|
||||
"+<common/api/at_cmd/atcmd_mp.c>",
|
||||
"+<common/api/at_cmd/atcmd_sys.c>",
|
||||
"+<common/api/at_cmd/atcmd_wifi.c>",
|
||||
"+<common/api/at_cmd/log_service.c>",
|
||||
"+<soc/realtek/8710c/app/shell/cmd_shell.c>",
|
||||
"+<soc/realtek/8710c/app/shell/ram_s/consol_cmds.c>",
|
||||
"+<soc/realtek/8710c/misc/driver/rtl_console.c>",
|
||||
"+<soc/realtek/8710c/misc/driver/flash_api_ext.c>",
|
||||
# utilities
|
||||
"+<common/utilities/cJSON.c>",
|
||||
"+<common/utilities/http_client.c>",
|
||||
@@ -125,11 +118,6 @@ queue.AddLibrary(
|
||||
"+<os/freertos/freertos_service.c>",
|
||||
"+<os/os_dep/device_lock.c>",
|
||||
"+<os/os_dep/osdep_service.c>",
|
||||
# os - freertos
|
||||
"+<os/freertos/freertos_v10.0.1/Source/*.c>",
|
||||
# os - freertos - portable
|
||||
"+<os/freertos/freertos_v10.0.1/Source/portable/MemMang/heap_5.c>",
|
||||
"+<os/freertos/freertos_v10.0.1/Source/portable/GCC/ARM_RTL8710C/port.c>",
|
||||
# peripheral - api
|
||||
"+<common/mbed/targets/hal/rtl8710c/*.c>",
|
||||
# peripheral - hal
|
||||
@@ -146,13 +134,9 @@ queue.AddLibrary(
|
||||
"+<common/file_system/fatfs/r0.10c/src/ff.c>",
|
||||
"+<common/file_system/fatfs/r0.10c/src/option/ccsbcs.c>",
|
||||
"+<common/file_system/ftl/ftl.c>",
|
||||
# TODO remove this
|
||||
"+<common/example/example_entry.c>",
|
||||
"+<common/example/wlan_fast_connect/example_wlan_fast_connect.c>",
|
||||
],
|
||||
includes=[
|
||||
"+<$SDK_DIR/project/realtek_amebaz2_v0_example/inc>",
|
||||
"+<common/api/at_cmd>",
|
||||
"+<common/api/platform>",
|
||||
"+<common/api>",
|
||||
"+<common/application>",
|
||||
@@ -170,11 +154,8 @@ queue.AddLibrary(
|
||||
"+<common/test>",
|
||||
"+<common/utilities>",
|
||||
"+<os/freertos>",
|
||||
"+<os/freertos/freertos_v10.0.1/Source/include>",
|
||||
"+<os/freertos/freertos_v10.0.1/Source/portable/GCC/ARM_RTL8710C>",
|
||||
"+<os/os_dep/include>",
|
||||
"+<soc/realtek/8710c/app/rtl_printf/include>",
|
||||
"+<soc/realtek/8710c/app/shell>",
|
||||
"+<soc/realtek/8710c/app/stdio_port>",
|
||||
"+<soc/realtek/8710c/cmsis/cmsis-core/include>",
|
||||
"+<soc/realtek/8710c/cmsis/rtl8710c/include>",
|
||||
@@ -205,6 +186,14 @@ queue.AddLibrary(
|
||||
),
|
||||
)
|
||||
|
||||
# Sources - FreeRTOS
|
||||
env.Replace(FREERTOS_PORT=env["FAMILY_NAME"], FREERTOS_PORT_DEFINE="REALTEK_AMBZ2")
|
||||
queue.AddExternalLibrary("freertos")
|
||||
queue.AddExternalLibrary("freertos-port")
|
||||
|
||||
# Sources - lwIP
|
||||
queue.AddExternalLibrary("lwip", port="ambz2")
|
||||
|
||||
# Sources - network utilities
|
||||
queue.AddLibrary(
|
||||
name="ambz2_net",
|
||||
@@ -214,6 +203,7 @@ queue.AddLibrary(
|
||||
"+<common/api/lwip_netconf.c>",
|
||||
# network - api - wifi
|
||||
"+<common/api/wifi/*.c>",
|
||||
"ARDUINO" in "ENV" and "-<common/api/wifi/wifi_ind.c>",
|
||||
# network - api - wifi - rtw_wpa_supplicant
|
||||
"+<common/api/wifi/rtw_wpa_supplicant/src/crypto/tls_polarssl.c>",
|
||||
"+<common/api/wifi/rtw_wpa_supplicant/wpa_supplicant/*.c>",
|
||||
@@ -231,7 +221,6 @@ queue.AddLibrary(
|
||||
"+<common/network/httpd/httpd_tls.c>",
|
||||
# network
|
||||
"+<common/network/dhcp/dhcps.c>",
|
||||
"+<common/network/sntp/sntp.c>",
|
||||
# network - websocket
|
||||
"+<common/network/websocket/*.c>",
|
||||
# network - mdns
|
||||
@@ -285,6 +274,7 @@ queue.AddLibrary(
|
||||
# "+<src/ble/profile/server/hids_rmc.c>",
|
||||
"+<src/ble/profile/server/simple_ble_service.c>",
|
||||
"+<src/mcu/module/data_uart_cmd/user_cmd_parse.c>",
|
||||
"-<board/common/src/bt_uart_bridge.c>",
|
||||
],
|
||||
includes=[
|
||||
"+<.>",
|
||||
@@ -315,34 +305,6 @@ queue.AddLibrary(
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# Sources - lwIP 2.0.2
|
||||
queue.AddLibrary(
|
||||
name="ambz2_lwip",
|
||||
base_dir=join(COMPONENT_DIR, "common", "network", "lwip", "lwip_v2.0.2"),
|
||||
srcs=[
|
||||
"+<port/realtek/freertos/*.c>",
|
||||
"+<src/api/*.c>",
|
||||
"+<src/apps/ping/*.c>",
|
||||
"+<src/apps/mdns/*.c>",
|
||||
"+<src/core/*.c>",
|
||||
"+<src/core/ipv4/*.c>",
|
||||
"+<src/core/ipv6/*.c>",
|
||||
"+<src/netif/ethernet.c>",
|
||||
],
|
||||
includes=[
|
||||
"+<port/realtek>",
|
||||
"+<port/realtek/freertos>",
|
||||
"+<src/include>",
|
||||
"+<src/include/netif>",
|
||||
],
|
||||
options=dict(
|
||||
CFLAGS=[
|
||||
"-Wno-implicit-function-declaration",
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
# Sources - mbedTLS
|
||||
queue.AddLibrary(
|
||||
name="ambz2_mbedtls",
|
||||
@@ -436,10 +398,38 @@ env.Replace(
|
||||
SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES",
|
||||
)
|
||||
|
||||
# Bootloader - copy for linking
|
||||
# fmt: off
|
||||
bootloader_src = env.subst("${SDK_DIR}/component/soc/realtek/8710c/misc/bsp/image/bootloader.axf")
|
||||
bootloader_dst = env.subst("${BUILD_DIR}/bootloader.axf")
|
||||
# fmt: on
|
||||
if not isfile(bootloader_dst):
|
||||
copyfile(bootloader_src, bootloader_dst)
|
||||
|
||||
# OTA2 clearing - 4096 bytes of 0xFF
|
||||
image_ota_clear = env.subst("${BUILD_DIR}/raw_ota_clear.bin")
|
||||
if not isfile(image_ota_clear):
|
||||
with open(image_ota_clear, "wb") as f:
|
||||
f.write(b"\xFF" * 4096)
|
||||
|
||||
# Build all libraries
|
||||
queue.BuildLibraries()
|
||||
|
||||
# Main firmware outputs and actions
|
||||
image_part_table = "${BUILD_DIR}/image_part_table.${FLASH_PART_TABLE_OFFSET}.bin"
|
||||
image_bootloader = "${BUILD_DIR}/image_bootloader.${FLASH_BOOT_OFFSET}.bin"
|
||||
image_firmware_is = "${BUILD_DIR}/image_firmware_is.${FLASH_OTA1_OFFSET}.bin"
|
||||
env.Replace(
|
||||
# TODO
|
||||
# linker command (dual .bin outputs)
|
||||
LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""',
|
||||
# UF2OTA input list
|
||||
UF2OTA=[
|
||||
# same OTA images for flasher and device
|
||||
f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2;flasher:ota1,ota2",
|
||||
# having flashed an application image, update the bootloader and partition table (incl. keys)
|
||||
f"{image_bootloader}=device:boot;flasher:boot",
|
||||
f"{image_part_table}=device:part_table;flasher:part_table",
|
||||
# clearing headers of the "other" OTA image (hence the indexes are swapped)
|
||||
f"{image_ota_clear},{image_ota_clear}=device:ota2,ota1;flasher:ota2,ota1",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ for f in family.inheritance:
|
||||
code = f"{f.code}_arduino"
|
||||
path = join("$CORES_DIR", f.name, "arduino")
|
||||
|
||||
found = found or env.AddCoreSources(queue, name=code, path=join(path, "src"))
|
||||
found = env.AddCoreSources(queue, name=code, path=join(path, "src")) or found
|
||||
env.AddArduinoLibraries(queue, name=code, path=join(path, "libraries"))
|
||||
|
||||
if f.short_name:
|
||||
@@ -73,13 +73,6 @@ queue.AppendPublic(
|
||||
("ARDUINO_SDK", 1),
|
||||
],
|
||||
LINKFLAGS=[
|
||||
"--specs=nosys.specs",
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,--build-id=none",
|
||||
"-Wl,--cref",
|
||||
"-Wl,--no-enum-size-warning",
|
||||
"-Wl,--no-undefined",
|
||||
"-Wl,--warn-common",
|
||||
# wrappers from posix/time.c
|
||||
"-Wl,-wrap,gettimeofday",
|
||||
"-Wl,-wrap,settimeofday",
|
||||
|
||||
@@ -95,7 +95,7 @@ for f in family.inheritance:
|
||||
env.Prepend(CPPDEFINES=[(f"LT_{f.code.upper()}", "1")])
|
||||
|
||||
# Sources - external libraries
|
||||
queue.AddExternalLibrary("ltchiptool") # uf2ota source code
|
||||
queue.AddExternalLibrary("uf2ota")
|
||||
queue.AddExternalLibrary("flashdb")
|
||||
queue.AddExternalLibrary("printf")
|
||||
|
||||
@@ -138,11 +138,14 @@ queue.AppendPublic(
|
||||
LINKFLAGS=[
|
||||
"-g2",
|
||||
"-Os",
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,--build-id=none",
|
||||
"-Wl,--cref",
|
||||
"-Wl,--gc-sections",
|
||||
"-Wl,--no-enum-size-warning",
|
||||
"-Wl,--no-wchar-size-warning",
|
||||
"-Wl,--no-undefined",
|
||||
"-Wl,--warn-common",
|
||||
# malloc.c wrappers
|
||||
"-Wl,-wrap,malloc",
|
||||
"-Wl,-wrap,calloc",
|
||||
|
||||
@@ -20,13 +20,21 @@ def env_load_defines(env: Environment, path: str):
|
||||
line = line[7:].strip()
|
||||
line = line.split(None, 2)
|
||||
if len(line) == 1:
|
||||
env.Append(CPPDEFINES=[(line[0], 1)])
|
||||
config[line[0]] = 1
|
||||
key, value = line[0], 1
|
||||
elif len(line) == 2:
|
||||
env.Append(CPPDEFINES=[(line[0], line[1])])
|
||||
config[line[0]] = line[1]
|
||||
key, value = line[0], line[1]
|
||||
else:
|
||||
raise ValueError(f"Unknown directive: {line}")
|
||||
for tpl in env["CPPDEFINES"]:
|
||||
if isinstance(tpl, tuple):
|
||||
k = tpl[0]
|
||||
else:
|
||||
k = tpl
|
||||
if k == key:
|
||||
env["CPPDEFINES"].remove(tpl)
|
||||
break
|
||||
env.Append(CPPDEFINES=[(key, value)])
|
||||
config[key] = value
|
||||
env.Append(
|
||||
CONFIG=config,
|
||||
)
|
||||
|
||||
@@ -46,10 +46,12 @@ def env_add_core_sources(env: Environment, queue, name: str, path: str) -> bool:
|
||||
base_dir=path,
|
||||
srcs=[
|
||||
"+<*.c*>",
|
||||
"+<api/*.c>",
|
||||
"+<common/*.c*>",
|
||||
"+<compat/*.c*>",
|
||||
"+<port/*.c*>",
|
||||
"+<posix/*.c>",
|
||||
"+<wiring/*.c>",
|
||||
"+<wraps/*.c>",
|
||||
],
|
||||
includes=[
|
||||
@@ -58,6 +60,7 @@ def env_add_core_sources(env: Environment, queue, name: str, path: str) -> bool:
|
||||
"!<compat>",
|
||||
"!<config>",
|
||||
"!<port>",
|
||||
"!<wiring>",
|
||||
],
|
||||
)
|
||||
queue.AddLibrary(
|
||||
|
||||
@@ -59,14 +59,23 @@ def env_uf2ota(env: Environment, *args, **kwargs):
|
||||
|
||||
|
||||
def env_flash_write(env: Environment):
|
||||
# UPLOAD_PROTOCOL = upload_protocol or board->upload.protocol
|
||||
# UPLOAD_PORT = upload_port (PIO can choose this automatically I guess)
|
||||
# UPLOAD_SPEED = upload_speed or board->upload.speed (**can be empty**)
|
||||
protocol = env.subst("${UPLOAD_PROTOCOL}")
|
||||
speed = env.subst("${UPLOAD_SPEED}")
|
||||
if protocol == "uart":
|
||||
# upload via UART
|
||||
if speed:
|
||||
return [
|
||||
"-d",
|
||||
"${UPLOAD_PORT}",
|
||||
"-b",
|
||||
"${UPLOAD_SPEED}",
|
||||
]
|
||||
return [
|
||||
"-d",
|
||||
"${UPLOAD_PORT}",
|
||||
"-b",
|
||||
"${UPLOAD_SPEED}",
|
||||
]
|
||||
else:
|
||||
# can't upload via ltchiptool
|
||||
|
||||
5
cores/beken-7231n/base/lt_defs.h
Normal file
5
cores/beken-7231n/base/lt_defs.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#error "Don't include this file directly"
|
||||
|
||||
#define LT_HW_BLE 1
|
||||
5
cores/beken-7231t/base/lt_defs.h
Normal file
5
cores/beken-7231t/base/lt_defs.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#error "Don't include this file directly"
|
||||
|
||||
#define LT_HW_BLE 1
|
||||
5
cores/beken-7251/base/lt_defs.h
Normal file
5
cores/beken-7251/base/lt_defs.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#error "Don't include this file directly"
|
||||
|
||||
#define LT_HW_BLE 1
|
||||
@@ -1,59 +1,40 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-23. */
|
||||
|
||||
#include "Serial.h"
|
||||
#include "SerialPrivate.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <uart_pub.h>
|
||||
|
||||
extern void bk_send_byte(uint8_t uport, uint8_t data);
|
||||
extern void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config);
|
||||
extern int uart_rx_callback_set(int uport, uart_callback callback, void *param);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#if HAS_SERIAL1
|
||||
#if LT_HW_UART1
|
||||
SerialClass Serial1(UART1_PORT);
|
||||
#endif
|
||||
#if HAS_SERIAL2
|
||||
#if LT_HW_UART2
|
||||
SerialClass Serial2(UART2_PORT);
|
||||
#endif
|
||||
|
||||
SerialClass::SerialClass(uint8_t port) {
|
||||
this->port = port;
|
||||
this->buf = NULL;
|
||||
}
|
||||
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT
|
||||
static uint8_t adrState = 0;
|
||||
static const uint8_t adrCmd[] = {0x01, 0xE0, 0xFC, 0x01, 0x00};
|
||||
|
||||
static void adrParse(uint8_t c) {
|
||||
// parse and respond to link check command (CMD_LinkCheck=0)
|
||||
adrState = (adrState + 1) * (c == adrCmd[adrState]);
|
||||
if (adrState == 5) {
|
||||
LT_I("Auto download mode: rebooting");
|
||||
LT.restart();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void callback(int port, void *param) {
|
||||
RingBuffer *buf = (RingBuffer *)param;
|
||||
int ch;
|
||||
while ((ch = uart_read_byte(port)) != -1) {
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT && defined(PIN_SERIAL1_RX)
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && PIN_SERIAL1_RX != PIN_INVALID
|
||||
// parse UART protocol commands on UART1
|
||||
if (port == UART1_PORT)
|
||||
adrParse(ch);
|
||||
SerialClass::adrParse(ch);
|
||||
#endif
|
||||
buf->store_char(ch);
|
||||
pBUF->store_char(ch);
|
||||
}
|
||||
}
|
||||
|
||||
void SerialClass::begin(unsigned long baudrate, uint16_t config) {
|
||||
if (!this->data) {
|
||||
this->data = new SerialData();
|
||||
this->buf = &BUF;
|
||||
}
|
||||
|
||||
if (this->baudrate != baudrate || this->config != config)
|
||||
this->configure(baudrate, config);
|
||||
}
|
||||
|
||||
void SerialClass::configure(unsigned long baudrate, uint16_t config) {
|
||||
if (!this->data)
|
||||
return;
|
||||
|
||||
uint8_t dataWidth = ((config & SERIAL_DATA_MASK) >> 8) - 1; // 0x100..0x400 -> 0..3
|
||||
uint8_t parity = 3 - (config & SERIAL_PARITY_MASK); // 0x3..0x1 -> 0..2
|
||||
uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2; // 0x10..0x30 -> 0..1
|
||||
@@ -66,17 +47,17 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) {
|
||||
.flow_control = FLOW_CTRL_DISABLED,
|
||||
};
|
||||
|
||||
if (this->buf) {
|
||||
this->buf->clear();
|
||||
} else {
|
||||
this->buf = new RingBuffer();
|
||||
}
|
||||
|
||||
uart_hw_set_change(port, &cfg);
|
||||
uart_rx_callback_set(port, callback, this->buf);
|
||||
uart_rx_callback_set(port, callback, &BUF);
|
||||
|
||||
this->baudrate = baudrate;
|
||||
this->config = config;
|
||||
}
|
||||
|
||||
void SerialClass::end() {
|
||||
if (!this->data)
|
||||
return;
|
||||
|
||||
uart_rx_callback_set(port, NULL, NULL);
|
||||
switch (port) {
|
||||
case 1:
|
||||
@@ -86,26 +67,22 @@ void SerialClass::end() {
|
||||
uart2_exit();
|
||||
break;
|
||||
}
|
||||
delete this->buf;
|
||||
}
|
||||
|
||||
int SerialClass::available() {
|
||||
return buf->available();
|
||||
}
|
||||
|
||||
int SerialClass::peek() {
|
||||
return buf->peek();
|
||||
}
|
||||
|
||||
int SerialClass::read() {
|
||||
return buf->read_char();
|
||||
delete DATA;
|
||||
this->data = NULL;
|
||||
this->buf = NULL;
|
||||
this->baudrate = 0;
|
||||
}
|
||||
|
||||
void SerialClass::flush() {
|
||||
if (!this->data)
|
||||
return;
|
||||
uart_wait_tx_over();
|
||||
}
|
||||
|
||||
size_t SerialClass::write(uint8_t c) {
|
||||
if (!this->data)
|
||||
return 0;
|
||||
bk_send_byte(port, c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
14
cores/beken-72xx/arduino/libraries/Serial/SerialPrivate.h
Normal file
14
cores/beken-72xx/arduino/libraries/Serial/SerialPrivate.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
typedef struct {
|
||||
RingBuffer buf;
|
||||
} SerialData;
|
||||
|
||||
#define DATA ((SerialData *)data)
|
||||
#define BUF (DATA->buf)
|
||||
#define pBUF ((RingBuffer *)param)
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#error "Don't include this file directly"
|
||||
|
||||
#define LT_ARD_HAS_WIFI 1
|
||||
#define LT_ARD_HAS_SERIAL 1
|
||||
|
||||
#define LT_ARD_HAS_WIFI 1
|
||||
#define LT_ARD_HAS_SERIAL 1
|
||||
#define LT_ARD_MD5_HOSTAPD 1
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <include.h>
|
||||
|
||||
#include <arm_arch.h>
|
||||
#include <bk_timer.h>
|
||||
#include <bk_timer_pub.h>
|
||||
#include <rtos_pub.h>
|
||||
#include <sys_rtos.h>
|
||||
#include "wiring_private.h"
|
||||
|
||||
#if LT_BK7231Q
|
||||
#undef LT_MICROS_HIGH_RES
|
||||
@@ -18,10 +11,6 @@
|
||||
#define US_PER_OVERFLOW (portTICK_PERIOD_MS * 1000)
|
||||
#define TICKS_PER_OVERFLOW (TICKS_PER_US * US_PER_OVERFLOW)
|
||||
|
||||
void delayMilliseconds(unsigned long ms) {
|
||||
rtos_delay_milliseconds(ms);
|
||||
}
|
||||
|
||||
#if LT_MICROS_HIGH_RES
|
||||
static uint32_t getTicksCount() {
|
||||
// copied from bk_timer_ctrl(), for speeds
|
||||
@@ -107,8 +96,22 @@ unsigned long micros() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void yield() {
|
||||
runPeriodicTasks();
|
||||
vTaskDelay(1);
|
||||
taskYIELD();
|
||||
void pinRemoveMode(PinInfo *pin, uint32_t mask) {
|
||||
PinData *data = pinData(pin);
|
||||
if ((mask & PIN_GPIO) && (pin->enabled & PIN_GPIO)) {
|
||||
gpio_config(pin->gpio, GMODE_INPUT_PULLDOWN);
|
||||
pinDisable(pin, PIN_GPIO);
|
||||
}
|
||||
if ((mask & PIN_IRQ) && (pin->enabled & PIN_IRQ)) {
|
||||
data->irqHandler = NULL;
|
||||
gpio_int_disable(pin->gpio);
|
||||
pinDisable(pin, PIN_IRQ);
|
||||
}
|
||||
if ((mask & PIN_PWM) && (pin->enabled & PIN_PWM)) {
|
||||
data->pwm->cfg.bits.en = PWM_DISABLE;
|
||||
__wrap_bk_printf_disable();
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, data->pwm);
|
||||
__wrap_bk_printf_enable();
|
||||
pinDisable(pin, PIN_PWM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <gpio_pub.h>
|
||||
#include <pwm_pub.h>
|
||||
#include <saradc_pub.h>
|
||||
#include "wiring_private.h"
|
||||
|
||||
static GPIO_INDEX pwmToGpio[] = {
|
||||
GPIO6, // PWM0
|
||||
@@ -59,11 +55,7 @@ static pwm_param_t pwm;
|
||||
static uint16_t adcData[1];
|
||||
|
||||
uint16_t analogReadVoltage(pin_size_t pinNumber) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return 0;
|
||||
if (!pinSupported(pin, PIN_ADC))
|
||||
return 0;
|
||||
pinCheckGetInfo(pinNumber, PIN_ADC, 0);
|
||||
|
||||
UINT32 status;
|
||||
saradc_desc_t adc;
|
||||
@@ -90,11 +82,10 @@ uint16_t analogReadMaxVoltage(pin_size_t pinNumber) {
|
||||
}
|
||||
|
||||
void analogWrite(pin_size_t pinNumber, int value) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (!pinSupported(pin, PIN_PWM))
|
||||
return;
|
||||
pinCheckGetData(pinNumber, PIN_PWM, );
|
||||
|
||||
// GPIO can't be used together with PWM
|
||||
pinRemoveMode(pin, PIN_GPIO | PIN_IRQ);
|
||||
|
||||
float percent = value * 1.0 / ((1 << _analogWriteResolution) - 1);
|
||||
uint32_t frequency = 26 * _analogWritePeriod - 1;
|
||||
@@ -122,8 +113,9 @@ void analogWrite(pin_size_t pinNumber, int value) {
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_LEVL_SET_HIGH, &pwm.channel);
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_UNIT_ENABLE, &pwm.channel);
|
||||
__wrap_bk_printf_enable();
|
||||
pin->enabled &= ~PIN_GPIO;
|
||||
pin->enabled |= PIN_PWM;
|
||||
// pass global PWM object pointer
|
||||
data->pwm = &pwm;
|
||||
pinEnable(pin, PIN_PWM);
|
||||
} else {
|
||||
// update duty cycle
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm);
|
||||
@@ -131,11 +123,7 @@ void analogWrite(pin_size_t pinNumber, int value) {
|
||||
} else {
|
||||
if (pinEnabled(pin, PIN_PWM)) {
|
||||
// disable PWM
|
||||
pwm.cfg.bits.en = PWM_DISABLE;
|
||||
__wrap_bk_printf_disable();
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, &pwm);
|
||||
__wrap_bk_printf_enable();
|
||||
pin->enabled &= ~PIN_PWM;
|
||||
pinRemoveMode(pin, PIN_PWM);
|
||||
}
|
||||
// force level as LOW
|
||||
pinMode(pinNumber, OUTPUT);
|
||||
|
||||
23
cores/beken-72xx/arduino/src/wiring_data.h
Normal file
23
cores/beken-72xx/arduino/src/wiring_data.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct PinData_s {
|
||||
pwm_param_t *pwm;
|
||||
PinMode gpioMode;
|
||||
PinStatus irqMode;
|
||||
void *irqHandler;
|
||||
void *irqParam;
|
||||
bool irqChange;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,20 +1,16 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <gpio_pub.h>
|
||||
#include "wiring_private.h"
|
||||
|
||||
void pinMode(pin_size_t pinNumber, PinMode pinMode) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (!pinSupported(pin, PIN_GPIO))
|
||||
return;
|
||||
if (pinEnabled(pin, PIN_PWM))
|
||||
// disable PWM before using the pin
|
||||
analogWrite(pinNumber, 0);
|
||||
if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode)
|
||||
pinCheckGetData(pinNumber, PIN_GPIO, );
|
||||
|
||||
if (pinEnabled(pin, PIN_GPIO) && data->gpioMode == pinMode)
|
||||
return;
|
||||
|
||||
// GPIO can't be used together with PWM
|
||||
pinRemoveMode(pin, PIN_PWM);
|
||||
|
||||
switch (pinMode) {
|
||||
case INPUT:
|
||||
gpio_config(pin->gpio, GMODE_INPUT);
|
||||
@@ -31,34 +27,21 @@ void pinMode(pin_size_t pinNumber, PinMode pinMode) {
|
||||
case OUTPUT_OPENDRAIN:
|
||||
gpio_config(pin->gpio, GMODE_SET_HIGH_IMPENDANCE);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
pin->enabled |= PIN_GPIO;
|
||||
pin->mode = pinMode;
|
||||
pinEnable(pin, PIN_GPIO);
|
||||
data->gpioMode = pinMode;
|
||||
}
|
||||
|
||||
void digitalWrite(pin_size_t pinNumber, PinStatus status) {
|
||||
// verify level is 0 or 1
|
||||
if (status > HIGH)
|
||||
return;
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
// pin is not GPIO yet or not OUTPUT; enable or disable input pullup
|
||||
if (!pinEnabled(pin, PIN_GPIO) || !pinIsOutput(pin)) {
|
||||
pinMode(pinNumber, status * INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
// write the new state
|
||||
gpio_output(pin->gpio, status);
|
||||
pinCheckGetData(pinNumber, PIN_GPIO, );
|
||||
pinSetOutputPull(pin, data, pinNumber, status);
|
||||
gpio_output(pin->gpio, !!status);
|
||||
}
|
||||
|
||||
PinStatus digitalRead(pin_size_t pinNumber) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return 0;
|
||||
// pin is not GPIO yet or not INPUT; change the mode
|
||||
if (!pinEnabled(pin, PIN_GPIO) || !pinIsInput(pin))
|
||||
pinMode(pinNumber, INPUT);
|
||||
// read the value
|
||||
pinCheckGetData(pinNumber, PIN_GPIO, LOW);
|
||||
pinSetInputMode(pin, data, pinNumber);
|
||||
return gpio_input(pin->gpio);
|
||||
}
|
||||
|
||||
@@ -1,98 +1,70 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-31. */
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <gpio_pub.h>
|
||||
|
||||
static void *irqHandlerList[PINS_COUNT] = {NULL};
|
||||
static void *irqHandlerArgs[PINS_COUNT] = {NULL};
|
||||
static bool irqChangeList[PINS_COUNT];
|
||||
#include "wiring_private.h"
|
||||
|
||||
static void irqHandler(unsigned char gpio) {
|
||||
PinInfo *pin = pinByGpio(gpio);
|
||||
if (pin == NULL)
|
||||
return;
|
||||
uint32_t index = pinIndex(pin);
|
||||
if (!irqHandlerList[index])
|
||||
PinData *data = pinData(pin);
|
||||
if (!data->irqHandler)
|
||||
return;
|
||||
if (irqChangeList[index]) {
|
||||
if (pin->mode == INPUT_PULLDOWN) {
|
||||
pin->mode = INPUT_PULLUP;
|
||||
if (data->irqChange) {
|
||||
if (data->gpioMode == INPUT_PULLDOWN) {
|
||||
data->gpioMode = INPUT_PULLUP;
|
||||
gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_FALLING, irqHandler);
|
||||
} else if (pin->mode == INPUT_PULLUP) {
|
||||
pin->mode = INPUT_PULLDOWN;
|
||||
} else if (data->gpioMode == INPUT_PULLUP) {
|
||||
data->gpioMode = INPUT_PULLDOWN;
|
||||
gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_RISING, irqHandler);
|
||||
}
|
||||
}
|
||||
if (irqHandlerArgs[index] == NULL) {
|
||||
((voidFuncPtr)irqHandlerList[index])();
|
||||
} else {
|
||||
((voidFuncPtrParam)irqHandlerList[index])(irqHandlerArgs[index]);
|
||||
}
|
||||
}
|
||||
|
||||
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
|
||||
attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL);
|
||||
if (!data->irqParam)
|
||||
((voidFuncPtr)data->irqHandler)();
|
||||
else
|
||||
((voidFuncPtrParam)data->irqHandler)(data->irqParam);
|
||||
}
|
||||
|
||||
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) {
|
||||
PinInfo *pin = pinInfo(interruptNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (!pinSupported(pin, PIN_IRQ))
|
||||
return;
|
||||
uint32_t index = pinIndex(pin);
|
||||
uint32_t event = 0;
|
||||
PinMode modeNew = 0;
|
||||
bool change = 0;
|
||||
pinCheckGetData(interruptNumber, PIN_IRQ, );
|
||||
|
||||
data->irqHandler = callback;
|
||||
data->irqParam = param;
|
||||
|
||||
if (pinEnabled(pin, PIN_IRQ) && data->irqMode == mode)
|
||||
return;
|
||||
|
||||
// GPIO can't be used together with PWM
|
||||
pinRemoveMode(pin, PIN_PWM);
|
||||
|
||||
uint32_t event = 0;
|
||||
bool change = false;
|
||||
switch (mode) {
|
||||
case LOW:
|
||||
event = GPIO_INT_LEVEL_LOW;
|
||||
modeNew = INPUT_PULLUP;
|
||||
change = false;
|
||||
event = GPIO_INT_LEVEL_LOW;
|
||||
break;
|
||||
case HIGH:
|
||||
event = GPIO_INT_LEVEL_HIGH;
|
||||
modeNew = INPUT_PULLDOWN;
|
||||
change = false;
|
||||
event = GPIO_INT_LEVEL_HIGH;
|
||||
break;
|
||||
case FALLING:
|
||||
event = GPIO_INT_LEVEL_FALLING;
|
||||
modeNew = INPUT_PULLUP;
|
||||
change = false;
|
||||
event = GPIO_INT_LEVEL_FALLING;
|
||||
break;
|
||||
case RISING:
|
||||
event = GPIO_INT_LEVEL_RISING;
|
||||
modeNew = INPUT_PULLDOWN;
|
||||
change = false;
|
||||
event = GPIO_INT_LEVEL_RISING;
|
||||
break;
|
||||
case CHANGE:
|
||||
event = GPIO_INT_LEVEL_FALLING;
|
||||
modeNew = INPUT_PULLUP;
|
||||
change = true;
|
||||
event = GPIO_INT_LEVEL_FALLING;
|
||||
change = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
irqHandlerList[index] = callback;
|
||||
irqHandlerArgs[index] = param;
|
||||
irqChangeList[index] = change;
|
||||
pinEnable(pin, PIN_IRQ);
|
||||
data->irqMode = mode;
|
||||
data->irqChange = change;
|
||||
|
||||
gpio_int_enable(pin->gpio, event, irqHandler);
|
||||
pin->enabled |= PIN_IRQ | PIN_GPIO;
|
||||
pin->mode = modeNew;
|
||||
}
|
||||
|
||||
void detachInterrupt(pin_size_t interruptNumber) {
|
||||
PinInfo *pin = pinInfo(interruptNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (!pinSupported(pin, PIN_IRQ))
|
||||
return;
|
||||
uint32_t index = pinIndex(pin);
|
||||
irqHandlerList[index] = NULL;
|
||||
irqHandlerArgs[index] = NULL;
|
||||
irqChangeList[index] = false;
|
||||
gpio_int_disable(pin->gpio);
|
||||
pin->enabled &= ~PIN_IRQ;
|
||||
pinModeRemove(interruptNumber, PIN_IRQ);
|
||||
}
|
||||
|
||||
13
cores/beken-72xx/base/api/lt_cpu.c
Normal file
13
cores/beken-72xx/base/api/lt_cpu.c
Normal file
@@ -0,0 +1,13 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
lt_cpu_model_t lt_cpu_get_model() {
|
||||
uint8_t chipId = *(uint8_t *)(SCTRL_CHIP_ID);
|
||||
return CPU_MODEL_ENUM(FAMILY, chipId);
|
||||
}
|
||||
|
||||
const char *lt_cpu_get_core_type() {
|
||||
return "ARM968E-S (ARMv5TE)";
|
||||
}
|
||||
41
cores/beken-72xx/base/api/lt_device.c
Normal file
41
cores/beken-72xx/base/api/lt_device.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
void lt_get_device_mac(uint8_t *mac) {
|
||||
cfg_load_mac(mac);
|
||||
}
|
||||
|
||||
void lt_reboot() {
|
||||
bk_reboot();
|
||||
}
|
||||
|
||||
bool lt_reboot_download_mode() {
|
||||
bk_reboot();
|
||||
return true;
|
||||
}
|
||||
|
||||
lt_reboot_reason_t lt_get_reboot_reason() {
|
||||
switch (bk_misc_get_start_type()) {
|
||||
case RESET_SOURCE_POWERON:
|
||||
return REBOOT_REASON_POWER;
|
||||
case RESET_SOURCE_REBOOT:
|
||||
return REBOOT_REASON_SOFTWARE;
|
||||
case RESET_SOURCE_WATCHDOG:
|
||||
return REBOOT_REASON_WATCHDOG;
|
||||
case RESET_SOURCE_CRASH_XAT0:
|
||||
case RESET_SOURCE_CRASH_UNDEFINED:
|
||||
case RESET_SOURCE_CRASH_PREFETCH_ABORT:
|
||||
case RESET_SOURCE_CRASH_DATA_ABORT:
|
||||
case RESET_SOURCE_CRASH_UNUSED:
|
||||
case RESET_SOURCE_CRASH_PER_XAT0:
|
||||
return REBOOT_REASON_CRASH;
|
||||
case RESET_SOURCE_DEEPPS_GPIO:
|
||||
case RESET_SOURCE_DEEPPS_RTC:
|
||||
case RESET_SOURCE_DEEPPS_USB:
|
||||
return REBOOT_REASON_SLEEP;
|
||||
default:
|
||||
return REBOOT_REASON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
26
cores/beken-72xx/base/api/lt_flash.c
Normal file
26
cores/beken-72xx/base/api/lt_flash.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
// can't include <flash.h> as it collides with <Flash.h> on Windows -_-
|
||||
#define REG_FLASH_BASE 0x00803000
|
||||
#define REG_FLASH_OPERATE_SW (REG_FLASH_BASE + 0 * 4)
|
||||
#define REG_FLASH_RDID (REG_FLASH_BASE + 4 * 4)
|
||||
#define FLASH_BUSY_SW (0x01UL << 31)
|
||||
#define FLASH_WP_VALUE (0x01UL << 30)
|
||||
#define FLASH_OP_SW (0x01UL << 29)
|
||||
#define FLASH_OP_TYPE_POS 24
|
||||
#define FLASH_OP_RDID 20
|
||||
|
||||
lt_flash_id_t lt_flash_get_id() {
|
||||
uint32_t data = (FLASH_OP_RDID << FLASH_OP_TYPE_POS) | FLASH_OP_SW | FLASH_WP_VALUE;
|
||||
REG_WRITE(REG_FLASH_OPERATE_SW, data);
|
||||
while (REG_READ(REG_FLASH_OPERATE_SW) & FLASH_BUSY_SW) {}
|
||||
lt_flash_id_t id = {
|
||||
.manufacturer_id = REG_RD8(REG_FLASH_RDID, 2),
|
||||
.chip_id = REG_RD8(REG_FLASH_RDID, 1),
|
||||
.chip_size_id = REG_RD8(REG_FLASH_RDID, 0),
|
||||
};
|
||||
return id;
|
||||
}
|
||||
9
cores/beken-72xx/base/api/lt_init.c
Normal file
9
cores/beken-72xx/base/api/lt_init.c
Normal file
@@ -0,0 +1,9 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
void lt_init_family() {
|
||||
// set default UART output port
|
||||
uart_print_port = LT_UART_DEFAULT_PORT - 1;
|
||||
}
|
||||
21
cores/beken-72xx/base/api/lt_mem.c
Normal file
21
cores/beken-72xx/base/api/lt_mem.c
Normal file
@@ -0,0 +1,21 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
uint32_t lt_ram_get_size() {
|
||||
return 256 * 1024;
|
||||
}
|
||||
|
||||
uint32_t lt_heap_get_size() {
|
||||
#if configDYNAMIC_HEAP_SIZE
|
||||
extern unsigned char _empty_ram;
|
||||
#if CFG_SOC_NAME == SOC_BK7231N
|
||||
return (0x00400000 + 192 * 1024) - (uint32_t)(&_empty_ram);
|
||||
#else
|
||||
return (0x00400000 + 256 * 1024) - (uint32_t)(&_empty_ram);
|
||||
#endif
|
||||
#else
|
||||
return configTOTAL_HEAP_SIZE;
|
||||
#endif
|
||||
}
|
||||
39
cores/beken-72xx/base/api/lt_ota.c
Normal file
39
cores/beken-72xx/base/api/lt_ota.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
lt_ota_type_t lt_ota_get_type() {
|
||||
return OTA_TYPE_SINGLE;
|
||||
}
|
||||
|
||||
bool lt_ota_is_valid(uint8_t index) {
|
||||
if (index != 0)
|
||||
return false;
|
||||
// check download RBL
|
||||
// TODO: maybe check header CRC or even binary hashes
|
||||
uint32_t magic;
|
||||
lt_flash_read(FLASH_DOWNLOAD_OFFSET, (uint8_t *)&magic, 4);
|
||||
return magic == 0x004C4252; // "RBL\0", little-endian
|
||||
}
|
||||
|
||||
uint8_t lt_ota_dual_get_current() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t lt_ota_dual_get_stored() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool lt_ota_switch(bool revert) {
|
||||
if (!lt_ota_is_valid(0))
|
||||
// no valid "download" image
|
||||
// - return false when trying to activate
|
||||
// - return true when trying to revert
|
||||
return revert;
|
||||
if (revert) {
|
||||
// there's a valid "download" image, which has to be removed
|
||||
return lt_flash_erase_block(FLASH_DOWNLOAD_OFFSET);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
18
cores/beken-72xx/base/api/lt_wdt.c
Normal file
18
cores/beken-72xx/base/api/lt_wdt.c
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
bool lt_wdt_enable(uint32_t timeout) {
|
||||
wdt_ctrl(WCMD_SET_PERIOD, &timeout);
|
||||
wdt_ctrl(WCMD_POWER_UP, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void lt_wdt_disable() {
|
||||
wdt_ctrl(WCMD_POWER_DOWN, NULL);
|
||||
}
|
||||
|
||||
void lt_wdt_feed() {
|
||||
wdt_ctrl(WCMD_RELOAD_PERIOD, NULL);
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */
|
||||
|
||||
#include <libretiny.h>
|
||||
#include <sdk_private.h>
|
||||
|
||||
// can't include <flash.h> as it collides with <Flash.h> on Windows -_-
|
||||
#define REG_FLASH_BASE 0x00803000
|
||||
#define REG_FLASH_OPERATE_SW (REG_FLASH_BASE + 0 * 4)
|
||||
#define REG_FLASH_RDID (REG_FLASH_BASE + 4 * 4)
|
||||
#define FLASH_BUSY_SW (0x01UL << 31)
|
||||
#define FLASH_WP_VALUE (0x01UL << 30)
|
||||
#define FLASH_OP_SW (0x01UL << 29)
|
||||
#define FLASH_OP_TYPE_POS 24
|
||||
#define FLASH_OP_RDID 20
|
||||
|
||||
void lt_init_family() {
|
||||
// set default UART output port
|
||||
uart_print_port = LT_UART_DEFAULT_PORT - 1;
|
||||
}
|
||||
|
||||
/* _____ _____ _ _
|
||||
/ ____| __ \| | | |
|
||||
| | | |__) | | | |
|
||||
| | | ___/| | | |
|
||||
| |____| | | |__| |
|
||||
\_____|_| \____*/
|
||||
lt_cpu_model_t lt_cpu_get_model() {
|
||||
uint8_t chipId = *(uint8_t *)(SCTRL_CHIP_ID);
|
||||
return CPU_MODEL_ENUM(FAMILY, chipId);
|
||||
}
|
||||
|
||||
uint32_t lt_cpu_get_unique_id() {
|
||||
return lt_cpu_get_mac_id();
|
||||
}
|
||||
|
||||
uint32_t lt_cpu_get_mac_id() {
|
||||
uint8_t mac[6];
|
||||
cfg_load_mac(mac); // force loading MAC from TLV (ignore user-set WiFi MAC)
|
||||
return (mac[3]) | (mac[4] << 8) | (mac[5] << 16);
|
||||
}
|
||||
|
||||
const char *lt_cpu_get_core_type() {
|
||||
return "ARM968E-S";
|
||||
}
|
||||
|
||||
/*_____ _
|
||||
| __ \ (_)
|
||||
| | | | _____ ___ ___ ___
|
||||
| | | |/ _ \ \ / / |/ __/ _ \
|
||||
| |__| | __/\ V /| | (_| __/
|
||||
|_____/ \___| \_/ |_|\___\__*/
|
||||
void lt_reboot() {
|
||||
bk_reboot();
|
||||
}
|
||||
|
||||
bool lt_reboot_download_mode() {
|
||||
bk_reboot();
|
||||
return true;
|
||||
}
|
||||
|
||||
lt_reboot_reason_t lt_get_reboot_reason() {
|
||||
switch (bk_misc_get_start_type()) {
|
||||
case RESET_SOURCE_POWERON:
|
||||
return REBOOT_REASON_POWER;
|
||||
case RESET_SOURCE_REBOOT:
|
||||
return REBOOT_REASON_SOFTWARE;
|
||||
case RESET_SOURCE_WATCHDOG:
|
||||
return REBOOT_REASON_WATCHDOG;
|
||||
case RESET_SOURCE_CRASH_XAT0:
|
||||
case RESET_SOURCE_CRASH_UNDEFINED:
|
||||
case RESET_SOURCE_CRASH_PREFETCH_ABORT:
|
||||
case RESET_SOURCE_CRASH_DATA_ABORT:
|
||||
case RESET_SOURCE_CRASH_UNUSED:
|
||||
case RESET_SOURCE_CRASH_PER_XAT0:
|
||||
return REBOOT_REASON_CRASH;
|
||||
case RESET_SOURCE_DEEPPS_GPIO:
|
||||
case RESET_SOURCE_DEEPPS_RTC:
|
||||
case RESET_SOURCE_DEEPPS_USB:
|
||||
return REBOOT_REASON_SLEEP;
|
||||
default:
|
||||
return REBOOT_REASON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*______ _ _
|
||||
| ____| | | |
|
||||
| |__ | | __ _ ___| |__
|
||||
| __| | |/ _` / __| '_ \
|
||||
| | | | (_| \__ \ | | |
|
||||
|_| |_|\__,_|___/_| |*/
|
||||
lt_flash_id_t lt_flash_get_id() {
|
||||
uint32_t data = (FLASH_OP_RDID << FLASH_OP_TYPE_POS) | FLASH_OP_SW | FLASH_WP_VALUE;
|
||||
REG_WRITE(REG_FLASH_OPERATE_SW, data);
|
||||
while (REG_READ(REG_FLASH_OPERATE_SW) & FLASH_BUSY_SW) {}
|
||||
lt_flash_id_t id = {
|
||||
.manufacturer_id = REG_RD8(REG_FLASH_RDID, 2),
|
||||
.chip_id = REG_RD8(REG_FLASH_RDID, 1),
|
||||
.chip_size_id = REG_RD8(REG_FLASH_RDID, 0),
|
||||
};
|
||||
return id;
|
||||
}
|
||||
|
||||
/*__ __
|
||||
| \/ |
|
||||
| \ / | ___ _ __ ___ ___ _ __ _ _
|
||||
| |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | |
|
||||
| | | | __/ | | | | | (_) | | | |_| |
|
||||
|_| |_|\___|_| |_| |_|\___/|_| \__, |
|
||||
__/ |
|
||||
|__*/
|
||||
uint32_t lt_ram_get_size() {
|
||||
return 256 * 1024;
|
||||
}
|
||||
|
||||
uint32_t lt_heap_get_size() {
|
||||
#if configDYNAMIC_HEAP_SIZE
|
||||
extern unsigned char _empty_ram;
|
||||
#if CFG_SOC_NAME == SOC_BK7231N
|
||||
return (0x00400000 + 192 * 1024) - (uint32_t)(&_empty_ram);
|
||||
#else
|
||||
return (0x00400000 + 256 * 1024) - (uint32_t)(&_empty_ram);
|
||||
#endif
|
||||
#else
|
||||
return configTOTAL_HEAP_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ____ _______
|
||||
/ __ \__ __|/\
|
||||
| | | | | | / \
|
||||
| | | | | | / /\ \
|
||||
| |__| | | |/ ____ \
|
||||
\____/ |_/_/ \*/
|
||||
|
||||
lt_ota_type_t lt_ota_get_type() {
|
||||
return OTA_TYPE_SINGLE;
|
||||
}
|
||||
|
||||
bool lt_ota_is_valid(uint8_t index) {
|
||||
if (index != 0)
|
||||
return false;
|
||||
// check download RBL
|
||||
// TODO: maybe check header CRC or even binary hashes
|
||||
uint32_t magic;
|
||||
lt_flash_read(FLASH_DOWNLOAD_OFFSET, (uint8_t *)&magic, 4);
|
||||
return magic == 0x004C4252; // "RBL\0", little-endian
|
||||
}
|
||||
|
||||
uint8_t lt_ota_dual_get_current() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t lt_ota_dual_get_stored() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool lt_ota_switch(bool revert) {
|
||||
if (!lt_ota_is_valid(0))
|
||||
// no valid "download" image
|
||||
// - return false when trying to activate
|
||||
// - return true when trying to revert
|
||||
return revert;
|
||||
if (revert) {
|
||||
// there's a valid "download" image, which has to be removed
|
||||
return lt_flash_erase_block(FLASH_DOWNLOAD_OFFSET);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*_ __ _ _ _
|
||||
\ \ / / | | | | | |
|
||||
\ \ /\ / /_ _| |_ ___| |__ __| | ___ __ _
|
||||
\ \/ \/ / _` | __/ __| '_ \ / _` |/ _ \ / _` |
|
||||
\ /\ / (_| | || (__| | | | (_| | (_) | (_| |
|
||||
\/ \/ \__,_|\__\___|_| |_|\__,_|\___/ \__, |
|
||||
__/ |
|
||||
|___*/
|
||||
bool lt_wdt_enable(uint32_t timeout) {
|
||||
wdt_ctrl(WCMD_SET_PERIOD, &timeout);
|
||||
wdt_ctrl(WCMD_POWER_UP, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void lt_wdt_disable() {
|
||||
wdt_ctrl(WCMD_POWER_DOWN, NULL);
|
||||
}
|
||||
|
||||
void lt_wdt_feed() {
|
||||
wdt_ctrl(WCMD_RELOAD_PERIOD, NULL);
|
||||
}
|
||||
@@ -2,11 +2,16 @@
|
||||
|
||||
#error "Don't include this file directly"
|
||||
|
||||
#define LT_HAS_PRINTF 1
|
||||
#define LT_HAS_LWIP 1
|
||||
#define LT_HAS_LWIP2 1
|
||||
#define LT_HAS_FREERTOS 1
|
||||
#define LT_HAS_MBEDTLS 1
|
||||
#define LT_HAS_FLASH 1
|
||||
#define LT_HAS_FREERTOS 1
|
||||
#define LT_HAS_LWIP 1
|
||||
#define LT_HAS_LWIP2 1
|
||||
#define LT_HAS_MBEDTLS 1
|
||||
#define LT_HAS_OTA 1
|
||||
#define LT_HAS_PRINTF 1
|
||||
#define LT_HW_DEEP_SLEEP 1
|
||||
#define LT_HW_WATCHDOG 1
|
||||
#define LT_HW_WIFI 1
|
||||
|
||||
#define LT_HEAP_FUNC xPortGetFreeHeapSize
|
||||
#define LT_REALLOC_FUNC pvPortRealloc
|
||||
|
||||
@@ -2,15 +2,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include LT_VARIANT_H
|
||||
#include <lt_pins.h>
|
||||
|
||||
// Choose the main UART output port
|
||||
#ifndef LT_UART_DEFAULT_PORT
|
||||
#if HAS_SERIAL2
|
||||
#if LT_HW_UART2
|
||||
#define LT_UART_DEFAULT_PORT 2
|
||||
#elif HAS_SERIAL1
|
||||
#elif LT_HW_UART1
|
||||
#define LT_UART_DEFAULT_PORT 1
|
||||
#else
|
||||
#error "No serial port is available"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Auto-download-reboot detection pattern
|
||||
// Link check command (CMD_LinkCheck=0)
|
||||
#define LT_UART_ADR_PATTERN 0x01, 0xE0, 0xFC, 0x01, 0x00
|
||||
|
||||
24
cores/beken-72xx/base/sdk_extern.h
Normal file
24
cores/beken-72xx/base/sdk_extern.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <uart_pub.h>
|
||||
|
||||
// SDK
|
||||
extern uint8_t system_mac[];
|
||||
extern int uart_print_port;
|
||||
uint32_t wdt_ctrl(uint32_t cmd, void *param);
|
||||
void bk_send_byte(uint8_t uport, uint8_t data);
|
||||
void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config);
|
||||
int uart_rx_callback_set(int uport, uart_callback callback, void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -6,12 +6,18 @@
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// most stuff is here
|
||||
// most stuff is here - this has to be before other includes!
|
||||
#include <include.h>
|
||||
// other includes
|
||||
#include <arm_arch.h>
|
||||
#include <bk_timer.h>
|
||||
#include <bk_timer_pub.h>
|
||||
#include <flash_pub.h>
|
||||
#include <gpio_pub.h>
|
||||
#include <param_config.h>
|
||||
#include <pwm_pub.h>
|
||||
#include <rtos_pub.h>
|
||||
#include <saradc_pub.h>
|
||||
#include <start_type_pub.h>
|
||||
#include <sys_ctrl.h>
|
||||
#include <sys_rtos.h>
|
||||
@@ -19,9 +25,7 @@ extern "C" {
|
||||
#include <wdt_pub.h>
|
||||
#include <wlan_ui_pub.h>
|
||||
|
||||
extern uint8_t system_mac[];
|
||||
extern uint32_t wdt_ctrl(uint32_t cmd, void *param);
|
||||
extern int uart_print_port;
|
||||
#include <sdk_extern.h>
|
||||
|
||||
// conflict with stl_algobase.h
|
||||
#undef min
|
||||
|
||||
36
cores/common/arduino/libraries/api/Serial/Serial.cpp
Normal file
36
cores/common/arduino/libraries/api/Serial/Serial.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */
|
||||
|
||||
#include "Serial.h"
|
||||
|
||||
SerialClass::SerialClass(uint32_t port, pin_size_t rx, pin_size_t tx) {
|
||||
this->port = port;
|
||||
this->rx = rx;
|
||||
this->tx = tx;
|
||||
this->buf = NULL;
|
||||
this->data = NULL;
|
||||
}
|
||||
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN)
|
||||
static uint8_t adrState = 0;
|
||||
static uint8_t adrCmd[] = {LT_UART_ADR_PATTERN};
|
||||
|
||||
void SerialClass::adrParse(uint8_t c) {
|
||||
adrState = (adrState + 1) * (c == adrCmd[adrState]);
|
||||
if (adrState == sizeof(adrCmd) / sizeof(uint8_t)) {
|
||||
LT_I("Auto download mode: rebooting");
|
||||
LT.restartDownloadMode();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int SerialClass::available() {
|
||||
return this->buf && this->buf->available();
|
||||
}
|
||||
|
||||
int SerialClass::peek() {
|
||||
return this->buf ? this->buf->peek() : -1;
|
||||
}
|
||||
|
||||
int SerialClass::read() {
|
||||
return this->buf ? this->buf->read_char() : -1;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/ArduinoAPI.h>
|
||||
#include <Arduino.h>
|
||||
#include <api/HardwareSerial.h>
|
||||
#include <api/RingBuffer.h>
|
||||
|
||||
@@ -10,17 +10,31 @@ using namespace arduino;
|
||||
|
||||
class SerialClass : public HardwareSerial {
|
||||
private:
|
||||
uint8_t port;
|
||||
RingBuffer *buf;
|
||||
uint32_t port;
|
||||
pin_size_t rx;
|
||||
pin_size_t tx;
|
||||
|
||||
public:
|
||||
SerialClass(uint8_t port);
|
||||
void *data;
|
||||
|
||||
private:
|
||||
RingBuffer *buf;
|
||||
uint32_t baudrate;
|
||||
uint16_t config;
|
||||
|
||||
public:
|
||||
SerialClass(uint32_t port, pin_size_t rx = PIN_INVALID, pin_size_t tx = PIN_INVALID);
|
||||
|
||||
inline void begin(unsigned long baudrate) {
|
||||
begin(baudrate, SERIAL_8N1);
|
||||
}
|
||||
|
||||
inline void configure(unsigned long baudrate) {
|
||||
configure(baudrate, SERIAL_8N1);
|
||||
}
|
||||
|
||||
void begin(unsigned long baudrate, uint16_t config);
|
||||
void configure(unsigned long baudrate, uint16_t config);
|
||||
void end();
|
||||
int available();
|
||||
int peek();
|
||||
@@ -32,5 +46,12 @@ class SerialClass : public HardwareSerial {
|
||||
return !!buf;
|
||||
}
|
||||
|
||||
public:
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT
|
||||
static void adrParse(uint8_t c);
|
||||
#endif
|
||||
|
||||
using Print::write;
|
||||
};
|
||||
|
||||
#define HAS_SERIAL_CLASS 1
|
||||
@@ -3,11 +3,11 @@
|
||||
#include "WiFi.h"
|
||||
|
||||
void WiFiClass::printDiag(Print &dest) {
|
||||
const char *modes[] = {"NULL", "STA", "AP", "STA+AP"};
|
||||
const char *enc[] = {"Open", "WEP", "WPA PSK", "WPA2 PSK", "WPA/WPA2", "WPA", "WPA2"};
|
||||
|
||||
dest.print("Mode: ");
|
||||
dest.println(modes[getMode()]);
|
||||
dest.println(WiFiModeText[getMode()]);
|
||||
|
||||
dest.print("Status: ");
|
||||
dest.println(WiFiStatusText[status()]);
|
||||
|
||||
if (getMode() & WIFI_MODE_STA) {
|
||||
dest.println("-- Station --");
|
||||
@@ -21,7 +21,7 @@ void WiFiClass::printDiag(Print &dest) {
|
||||
dest.print("RSSI: ");
|
||||
dest.println(RSSI());
|
||||
dest.print("Encryption: ");
|
||||
dest.println(enc[getEncryption()]);
|
||||
dest.println(WiFiAuthModeText[getEncryption()]);
|
||||
dest.print("IP: ");
|
||||
dest.println(localIP());
|
||||
dest.print("MAC: ");
|
||||
|
||||
@@ -11,7 +11,7 @@ bool WiFiClass::mode(WiFiMode mode) {
|
||||
pWiFi = this;
|
||||
|
||||
WiFiMode currentMode = getMode();
|
||||
LT_DM(WIFI, "Mode changing %u -> %u", currentMode, mode);
|
||||
LT_DM(WIFI, "Mode changing %s -> %s", WiFiModeText[currentMode], WiFiModeText[mode]);
|
||||
if (mode == currentMode)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -162,3 +162,28 @@ typedef enum {
|
||||
WLMODE_DISABLE = 1,
|
||||
WLMODE_ENABLE = 2,
|
||||
} WiFiModeAction;
|
||||
|
||||
static const char *WiFiModeText[] = {"NULL", "STA", "AP", "AP+STA"};
|
||||
static const char *WiFiStatusText[] = {
|
||||
"Idle",
|
||||
"No SSID",
|
||||
"Scan Completed",
|
||||
"Connected",
|
||||
"Connect failed",
|
||||
"Connection lost",
|
||||
"Disconnected",
|
||||
};
|
||||
static const char *WiFiAuthModeText[] = {
|
||||
"Open",
|
||||
"WEP",
|
||||
"WPA PSK",
|
||||
"WPA2 PSK",
|
||||
"WPA/WPA2 PSK",
|
||||
"WPA2 EAP",
|
||||
"WPA3 PSK",
|
||||
"WPA2/WPA3 PSK",
|
||||
"WAPI PSK",
|
||||
"WPA",
|
||||
"WPA2",
|
||||
"Auto",
|
||||
};
|
||||
|
||||
@@ -2,9 +2,25 @@
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) {
|
||||
cleanup();
|
||||
}
|
||||
static const UpdateError errorMap[] = {
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA scheme */
|
||||
UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_INVALID - invalid partition info tag */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */
|
||||
UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_PROTECT - target area is write-protected */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_ALLOC_FAILED - dynamic memory allocation failed */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize the update process.
|
||||
@@ -13,55 +29,93 @@ UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) {
|
||||
* @param command must be U_FLASH
|
||||
* @return false if parameters are invalid or update is running, true otherwise
|
||||
*/
|
||||
bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3, const char *unused4) {
|
||||
if (ctx)
|
||||
return false;
|
||||
cleanup();
|
||||
|
||||
LT_DM(OTA, "begin(%u, ...) / OTA curr: %u, scheme: %u", size, lt_ota_dual_get_current(), lt_ota_get_uf2_scheme());
|
||||
|
||||
ctx = uf2_ctx_init(lt_ota_get_uf2_scheme(), FAMILY);
|
||||
info = uf2_info_init();
|
||||
|
||||
if (!size) {
|
||||
cleanup(UPDATE_ERROR_SIZE);
|
||||
bool UpdateClass::begin(
|
||||
size_t size,
|
||||
int command,
|
||||
__attribute__((unused)) int ledPin,
|
||||
__attribute__((unused)) uint8_t ledOn,
|
||||
__attribute__((unused)) const char *label
|
||||
) {
|
||||
#if !LT_HAS_OTA
|
||||
LT_E("OTA is not yet supported on this chip!");
|
||||
this->errArd = UPDATE_ERROR_BAD_ARGUMENT;
|
||||
return false;
|
||||
#endif
|
||||
if (this->ctx) {
|
||||
return false;
|
||||
}
|
||||
this->clearError();
|
||||
if (size == 0) {
|
||||
this->errArd = UPDATE_ERROR_SIZE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command != U_FLASH) {
|
||||
cleanup(UPDATE_ERROR_BAD_ARGUMENT);
|
||||
this->errArd = UPDATE_ERROR_BAD_ARGUMENT;
|
||||
return false;
|
||||
}
|
||||
if (size == UPDATE_SIZE_UNKNOWN) {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
bytesTotal = size;
|
||||
this->ctx = static_cast<lt_ota_ctx_t *>(malloc(sizeof(lt_ota_ctx_t)));
|
||||
lt_ota_begin(this->ctx, size);
|
||||
this->ctx->callback = reinterpret_cast<void (*)(void *)>(progressHandler);
|
||||
this->ctx->callback_param = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finalize the update process. Check for errors and update completion, then activate the new firmware image.
|
||||
*
|
||||
* @param evenIfRemaining no idea
|
||||
* @return false in case of errors or no update running, true otherwise
|
||||
* @param evenIfRemaining don't raise errors if still in progress
|
||||
* @return false in case of errors or no update running; true otherwise
|
||||
*/
|
||||
bool UpdateClass::end(bool evenIfRemaining) {
|
||||
if (hasError() || !ctx)
|
||||
// false if not running
|
||||
if (!this->ctx)
|
||||
return false;
|
||||
|
||||
if (!isFinished() && !evenIfRemaining) {
|
||||
// update is running or finished; cleanup and end it
|
||||
if (!isFinished() && !evenIfRemaining)
|
||||
// abort if not finished
|
||||
cleanup(UPDATE_ERROR_ABORT);
|
||||
return false;
|
||||
}
|
||||
// TODO what is evenIfRemaining for?
|
||||
// try to activate the second OTA
|
||||
if (!lt_ota_switch(/* revert= */ false)) {
|
||||
cleanup(UPDATE_ERROR_ACTIVATE);
|
||||
return false;
|
||||
this->errArd = UPDATE_ERROR_ABORT;
|
||||
|
||||
this->cleanup(/* clearError= */ evenIfRemaining);
|
||||
return !this->hasError();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleanup (free) the update context.
|
||||
* Try activating the firmware if possible, set local error codes.
|
||||
*
|
||||
* @param clearError assume successful finish after correct activation
|
||||
*/
|
||||
void UpdateClass::cleanup(bool clearError) {
|
||||
if (!this->ctx)
|
||||
return;
|
||||
|
||||
if (!lt_ota_end(this->ctx)) {
|
||||
// activating firmware failed
|
||||
this->errArd = UPDATE_ERROR_ACTIVATE;
|
||||
this->errUf2 = UF2_ERR_OK;
|
||||
} else if (clearError) {
|
||||
// successful finish and activation, clear error codes
|
||||
this->clearError();
|
||||
} else if (this->ctx->error > UF2_ERR_IGNORE) {
|
||||
// make error code based on UF2OTA code
|
||||
this->errArd = errorMap[this->ctx->error];
|
||||
this->errUf2 = this->ctx->error;
|
||||
} else {
|
||||
// only keep Arduino error code (set by the caller)
|
||||
this->errUf2 = UF2_ERR_OK;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
return true;
|
||||
#if LT_DEBUG_OTA
|
||||
if (this->hasError())
|
||||
this->printErrorContext();
|
||||
#endif
|
||||
|
||||
free(this->ctx);
|
||||
this->ctx = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,60 +123,44 @@ bool UpdateClass::end(bool evenIfRemaining) {
|
||||
*
|
||||
* It's advised to write in 512-byte chunks (or its multiples).
|
||||
*
|
||||
* @param data
|
||||
* @param len
|
||||
* @return size_t
|
||||
* @param data chunk of data
|
||||
* @param len length of the chunk
|
||||
* @return size_t amount of bytes written
|
||||
*/
|
||||
size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
size_t written = 0;
|
||||
if (hasError() || !ctx)
|
||||
// 0 if not running
|
||||
size_t UpdateClass::write(const uint8_t *data, size_t len) {
|
||||
if (!this->ctx)
|
||||
return 0;
|
||||
|
||||
LT_VM(OTA, "write(%u) / buf %u/512", len, bufSize());
|
||||
|
||||
/* while (buf == bufPos && len >= UF2_BLOCK_SIZE) {
|
||||
// buffer empty and entire block is in data
|
||||
if (!tryWriteData(data, UF2_BLOCK_SIZE)) {
|
||||
// returns 0 if data contains an invalid block
|
||||
return written;
|
||||
}
|
||||
data += UF2_BLOCK_SIZE;
|
||||
len -= UF2_BLOCK_SIZE;
|
||||
written += UF2_BLOCK_SIZE;
|
||||
} */
|
||||
|
||||
// write until buffer space is available
|
||||
uint16_t toWrite; // 1..512
|
||||
while (len && (toWrite = min(len, bufLeft()))) {
|
||||
tryWriteData(data, toWrite);
|
||||
if (hasError()) {
|
||||
// return on errors
|
||||
printErrorContext2(data, toWrite);
|
||||
return written;
|
||||
}
|
||||
data += toWrite;
|
||||
len -= toWrite;
|
||||
written += toWrite;
|
||||
}
|
||||
size_t written = lt_ota_write(ctx, data, len);
|
||||
if (written != len)
|
||||
this->cleanup(/* clearError= */ false);
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write all data remaining in the given stream.
|
||||
*
|
||||
* If the stream doesn't produce any data within UPDATE_TIMEOUT_MS,
|
||||
* the update process will be aborted.
|
||||
*
|
||||
* @param data stream to read from
|
||||
* @return size_t amount of bytes written
|
||||
*/
|
||||
size_t UpdateClass::writeStream(Stream &data) {
|
||||
size_t written = 0;
|
||||
if (hasError() || !ctx)
|
||||
// 0 if not running
|
||||
if (!this->ctx)
|
||||
return 0;
|
||||
|
||||
size_t written = 0;
|
||||
uint32_t lastData = millis();
|
||||
// loop until the update is complete
|
||||
while (remaining()) {
|
||||
// check stream availability
|
||||
int available = data.available();
|
||||
auto available = data.available();
|
||||
if (available <= 0) {
|
||||
if (millis() - lastData > UPDATE_TIMEOUT_MS) {
|
||||
// waited for data too long; abort with error
|
||||
cleanup(UPDATE_ERROR_STREAM);
|
||||
this->errArd = UPDATE_ERROR_STREAM;
|
||||
this->cleanup(/* clearError= */ false);
|
||||
return written;
|
||||
}
|
||||
continue;
|
||||
@@ -131,94 +169,21 @@ size_t UpdateClass::writeStream(Stream &data) {
|
||||
lastData = millis();
|
||||
|
||||
// read data to fit in the remaining buffer space
|
||||
bufAlloc();
|
||||
uint16_t read = data.readBytes(bufPos, bufLeft());
|
||||
bufPos += read;
|
||||
written += read;
|
||||
tryWriteData();
|
||||
auto bufSize = this->ctx->buf_pos - this->ctx->buf;
|
||||
auto read = data.readBytes(this->ctx->buf_pos, UF2_BLOCK_SIZE - bufSize);
|
||||
// increment buffer writing head
|
||||
this->ctx->buf_pos += read;
|
||||
// process the block if complete
|
||||
if (bufSize + read == UF2_BLOCK_SIZE)
|
||||
lt_ota_write_block(this->ctx, reinterpret_cast<uf2_block_t *>(this->ctx->buf));
|
||||
// abort on errors
|
||||
if (hasError()) {
|
||||
// return on errors
|
||||
printErrorContext2(NULL, read); // buf is not valid anymore
|
||||
this->cleanup(/* clearError= */ false);
|
||||
return written;
|
||||
}
|
||||
written += read;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to use the buffer as a block to write. In case of UF2 errors,
|
||||
* error codes are set, the update is aborted and 0 is returned
|
||||
*
|
||||
* @param data received data to copy to buffer or NULL if already in buffer
|
||||
* @param len received data length - must be at most bufLeft()
|
||||
* @return size_t "used" data size - 0 or 512
|
||||
*/
|
||||
size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
|
||||
uf2_block_t *block = NULL;
|
||||
|
||||
LT_VM(OTA, "Writing %u to buffer (%u/512)", len, bufSize());
|
||||
|
||||
if (len == UF2_BLOCK_SIZE) {
|
||||
// data has a complete block
|
||||
block = (uf2_block_t *)data;
|
||||
} else if (data && len) {
|
||||
// data has a part of a block, copy it to buffer
|
||||
bufAlloc();
|
||||
memcpy(bufPos, data, len);
|
||||
bufPos += len;
|
||||
}
|
||||
|
||||
if (!block && bufSize() == UF2_BLOCK_SIZE) {
|
||||
// use buffer as block (only if not found above)
|
||||
block = (uf2_block_t *)buf;
|
||||
}
|
||||
|
||||
// a complete block has been found
|
||||
if (block) {
|
||||
if (checkUf2Error(uf2_check_block(ctx, block)))
|
||||
// block is invalid
|
||||
return 0;
|
||||
|
||||
if (errUf2 == UF2_ERR_IGNORE)
|
||||
// treat ignored blocks as valid
|
||||
return UF2_BLOCK_SIZE;
|
||||
|
||||
if (!bytesWritten) {
|
||||
// parse header block to allow retrieving firmware info
|
||||
if (checkUf2Error(uf2_parse_header(ctx, block, info)))
|
||||
// header is invalid
|
||||
return 0;
|
||||
|
||||
LT_IM(OTA, "%s v%s - LT v%s @ %s", info->fw_name, info->fw_version, info->lt_version, info->board);
|
||||
|
||||
if (bytesTotal == UPDATE_SIZE_UNKNOWN) {
|
||||
// set total update size from block count info
|
||||
bytesTotal = block->block_count * UF2_BLOCK_SIZE;
|
||||
} else if (bytesTotal != block->block_count * UF2_BLOCK_SIZE) {
|
||||
// given update size does not match the block count
|
||||
LT_EM(OTA, "Image size wrong; got %u, calculated %u", bytesTotal, block->block_count * UF2_BLOCK_SIZE);
|
||||
cleanup(UPDATE_ERROR_SIZE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// write data blocks normally
|
||||
if (checkUf2Error(uf2_write(ctx, block)))
|
||||
// block writing failed
|
||||
return 0;
|
||||
}
|
||||
|
||||
// increment total writing progress
|
||||
bytesWritten += UF2_BLOCK_SIZE;
|
||||
// call progress callback
|
||||
if (callback)
|
||||
callback(bytesWritten, bytesTotal);
|
||||
// reset the buffer as it's used already
|
||||
if (bufSize() == UF2_BLOCK_SIZE)
|
||||
bufPos = buf;
|
||||
return UF2_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UpdateClass Update;
|
||||
|
||||
@@ -4,39 +4,30 @@
|
||||
#include <functional>
|
||||
#include <uf2ota/uf2ota.h>
|
||||
|
||||
// No Error
|
||||
#define UPDATE_ERROR_OK (0)
|
||||
// Flash Write Failed
|
||||
#define UPDATE_ERROR_WRITE (1)
|
||||
// Flash Erase Failed
|
||||
#define UPDATE_ERROR_ERASE (2)
|
||||
// Flash Read Failed
|
||||
#define UPDATE_ERROR_READ (3)
|
||||
// Not Enough Space
|
||||
#define UPDATE_ERROR_SPACE (4)
|
||||
// Bad Size Given
|
||||
#define UPDATE_ERROR_SIZE (5)
|
||||
// Stream Read Timeout
|
||||
#define UPDATE_ERROR_STREAM (6)
|
||||
// MD5 Check Failed
|
||||
#define UPDATE_ERROR_MD5 (7)
|
||||
// Wrong Magic Byte
|
||||
#define UPDATE_ERROR_MAGIC_BYTE (8)
|
||||
// Could Not Activate The Firmware
|
||||
#define UPDATE_ERROR_ACTIVATE (9)
|
||||
// Partition Could Not be Found
|
||||
#define UPDATE_ERROR_NO_PARTITION (10)
|
||||
// Bad Argument
|
||||
#define UPDATE_ERROR_BAD_ARGUMENT (11)
|
||||
// Aborted
|
||||
#define UPDATE_ERROR_ABORT (12)
|
||||
typedef enum {
|
||||
UPDATE_ERROR_OK = 0, //!< No Error
|
||||
UPDATE_ERROR_WRITE = 1, //!< Flash Write Failed
|
||||
UPDATE_ERROR_ERASE = 2, //!< Flash Erase Failed
|
||||
UPDATE_ERROR_READ = 3, //!< Flash Read Failed
|
||||
UPDATE_ERROR_SPACE = 4, //!< Not Enough Space
|
||||
UPDATE_ERROR_SIZE = 5, //!< Bad Size Given
|
||||
UPDATE_ERROR_STREAM = 6, //!< Stream Read Timeout
|
||||
UPDATE_ERROR_MD5 = 7, //!< MD5 Check Failed
|
||||
UPDATE_ERROR_MAGIC_BYTE = 8, //!< Wrong Magic Byte
|
||||
UPDATE_ERROR_ACTIVATE = 9, //!< Could Not Activate The Firmware
|
||||
UPDATE_ERROR_NO_PARTITION = 10, //!< Partition Could Not be Found
|
||||
UPDATE_ERROR_BAD_ARGUMENT = 11, //!< Bad Argument
|
||||
UPDATE_ERROR_ABORT = 12, //!< Aborted
|
||||
} UpdateError;
|
||||
|
||||
typedef enum {
|
||||
U_FLASH = 0,
|
||||
U_SPIFFS = 100,
|
||||
U_AUTH = 200,
|
||||
} UpdateCommand;
|
||||
|
||||
#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#define U_FLASH 0
|
||||
#define U_SPIFFS 100
|
||||
#define U_AUTH 200
|
||||
|
||||
#define ENCRYPTED_BLOCK_SIZE 16
|
||||
|
||||
#define UPDATE_TIMEOUT_MS 30 * 1000
|
||||
@@ -46,109 +37,132 @@ class UpdateClass {
|
||||
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
||||
|
||||
public: /* Update.cpp */
|
||||
UpdateClass();
|
||||
bool begin(
|
||||
size_t size = UPDATE_SIZE_UNKNOWN,
|
||||
int command = U_FLASH,
|
||||
int unused2 = -1,
|
||||
uint8_t unused3 = LOW,
|
||||
const char *unused4 = NULL // this is for SPIFFS
|
||||
size_t size = UPDATE_SIZE_UNKNOWN,
|
||||
int command = U_FLASH,
|
||||
int ledPin = -1,
|
||||
uint8_t ledOn = LOW,
|
||||
const char *label = nullptr
|
||||
);
|
||||
bool end(bool evenIfRemaining = false);
|
||||
size_t write(uint8_t *data, size_t len);
|
||||
|
||||
size_t write(const uint8_t *data, size_t len);
|
||||
size_t writeStream(Stream &data);
|
||||
bool canRollBack();
|
||||
bool rollBack();
|
||||
// bool setMD5(const char *expected_md5);
|
||||
|
||||
private: /* Update.cpp */
|
||||
size_t tryWriteData(uint8_t *data = NULL, size_t len = 0);
|
||||
void cleanup(bool clearError = false);
|
||||
|
||||
public: /* UpdateUtil.cpp */
|
||||
UpdateClass &onProgress(THandlerFunction_Progress callback);
|
||||
void abort();
|
||||
void printError(Print &out);
|
||||
const char *errorString();
|
||||
const char *getFirmwareName();
|
||||
const char *getFirmwareVersion();
|
||||
const char *getLibreTinyVersion();
|
||||
const char *getBoardName();
|
||||
UpdateClass &onProgress(THandlerFunction_Progress handler);
|
||||
static bool canRollBack();
|
||||
static bool rollBack();
|
||||
uint16_t getErrorCode() const;
|
||||
bool hasError() const;
|
||||
void clearError();
|
||||
const char *errorString() const;
|
||||
void printError(Print &out) const;
|
||||
|
||||
private: /* UpdateUtil.cpp */
|
||||
void cleanup(uint8_t ardErr = UPDATE_ERROR_OK, uf2_err_t uf2Err = UF2_ERR_OK);
|
||||
bool checkUf2Error(uf2_err_t err);
|
||||
void bufAlloc();
|
||||
void printErrorContext1();
|
||||
void printErrorContext2(const uint8_t *data, size_t len);
|
||||
uint16_t bufLeft();
|
||||
uint16_t bufSize();
|
||||
static void progressHandler(UpdateClass *self);
|
||||
void printErrorContext();
|
||||
|
||||
private:
|
||||
// uf2ota context
|
||||
uf2_ota_t *ctx;
|
||||
uf2_info_t *info;
|
||||
// block buffer
|
||||
uint8_t *buf;
|
||||
uint8_t *bufPos;
|
||||
// update progress - multiplies of 512 bytes
|
||||
uint32_t bytesWritten;
|
||||
uint32_t bytesTotal;
|
||||
// errors
|
||||
uf2_err_t errUf2;
|
||||
uint8_t errArd;
|
||||
// progress callback
|
||||
THandlerFunction_Progress callback;
|
||||
// String _target_md5;
|
||||
// MD5Builder _md5;
|
||||
lt_ota_ctx_t *ctx{nullptr};
|
||||
uf2_err_t errUf2{UF2_ERR_OK};
|
||||
UpdateError errArd{UPDATE_ERROR_OK};
|
||||
THandlerFunction_Progress callback{nullptr};
|
||||
|
||||
public:
|
||||
String md5String(void) {
|
||||
// return _md5.toString();
|
||||
return "";
|
||||
/**
|
||||
* @brief Get Arduino error code of the update.
|
||||
*/
|
||||
inline UpdateError getError() const {
|
||||
return this->errArd;
|
||||
}
|
||||
|
||||
void md5(uint8_t *result) {
|
||||
// return _md5.getBytes(result);
|
||||
/**
|
||||
* @brief Get UF2OTA error code of the update.
|
||||
*/
|
||||
inline uf2_err_t getUF2Error() const {
|
||||
return this->ctx ? this->ctx->error : this->errUf2;
|
||||
}
|
||||
|
||||
uint8_t getError() {
|
||||
return errArd;
|
||||
/**
|
||||
* @brief Same as end().
|
||||
*/
|
||||
inline void abort() {
|
||||
this->end();
|
||||
}
|
||||
|
||||
uf2_err_t getUF2Error() {
|
||||
return errUf2;
|
||||
/**
|
||||
* @brief Check if the update process has been started.
|
||||
*/
|
||||
inline bool isRunning() {
|
||||
return this->ctx;
|
||||
}
|
||||
|
||||
uint16_t getErrorCode() {
|
||||
return (errArd << 8) | errUf2;
|
||||
/**
|
||||
* @brief Check if the update process hasn't been started or has been completed.
|
||||
*/
|
||||
inline bool isFinished() {
|
||||
return !(this->ctx && this->ctx->bytes_written != this->ctx->bytes_total);
|
||||
}
|
||||
|
||||
void clearError() {
|
||||
cleanup(UPDATE_ERROR_OK);
|
||||
/**
|
||||
* @brief Return complete update image size.
|
||||
*/
|
||||
inline size_t size() {
|
||||
return this->ctx ? this->ctx->bytes_total : 0;
|
||||
}
|
||||
|
||||
bool hasError() {
|
||||
return errArd != UPDATE_ERROR_OK;
|
||||
/**
|
||||
* @brief Return amount of bytes already written.
|
||||
*/
|
||||
inline size_t progress() {
|
||||
return this->ctx ? this->ctx->bytes_written : 0;
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
return ctx != NULL;
|
||||
/**
|
||||
* @brief Return amount of bytes remaining to write.
|
||||
*/
|
||||
inline size_t remaining() {
|
||||
return this->size() - this->progress();
|
||||
}
|
||||
|
||||
bool isFinished() {
|
||||
return bytesWritten == bytesTotal;
|
||||
/**
|
||||
* @brief Get firmware name from UF2 info.
|
||||
*/
|
||||
inline const char *getFirmwareName() {
|
||||
if (this->ctx)
|
||||
return this->ctx->info.fw_name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t size() {
|
||||
return bytesTotal;
|
||||
/**
|
||||
* @brief Get firmware version from UF2 info.
|
||||
*/
|
||||
inline const char *getFirmwareVersion() {
|
||||
if (this->ctx)
|
||||
return this->ctx->info.fw_version;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t progress() {
|
||||
return bytesWritten;
|
||||
/**
|
||||
* @brief Get LibreTiny version from UF2 info.
|
||||
*/
|
||||
inline const char *getLibreTinyVersion() {
|
||||
if (this->ctx)
|
||||
return this->ctx->info.lt_version;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t remaining() {
|
||||
return bytesTotal - bytesWritten;
|
||||
/**
|
||||
* @brief Get target board name from UF2 info.
|
||||
*/
|
||||
inline const char *getBoardName() {
|
||||
if (this->ctx)
|
||||
return this->ctx->info.board;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,26 +2,46 @@
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
extern "C" {
|
||||
#include <fal.h>
|
||||
}
|
||||
|
||||
static const uint8_t errorMap[] = {
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA scheme */
|
||||
UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_INVALID - invalid partition info tag */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */
|
||||
UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */
|
||||
UPDATE_ERROR_WRITE /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */
|
||||
static const char *errUf2Text[] = {
|
||||
nullptr, // UF2_ERR_OK (0)
|
||||
nullptr, // UF2_ERR_IGNORE (1)
|
||||
"Bad Magic Number", // UF2_ERR_MAGIC (2)
|
||||
"Bad Family ID", // UF2_ERR_FAMILY (3)
|
||||
"Missing Header", // UF2_ERR_NOT_HEADER (4)
|
||||
"Old OTA Format Found", // UF2_ERR_OTA_VER (5)
|
||||
"Image Not Applicable", // UF2_ERR_OTA_WRONG (6)
|
||||
"Partition Not Found", // UF2_ERR_PART_404 (7)
|
||||
"Partition Info Invalid", // UF2_ERR_PART_INVALID (8)
|
||||
"Partition Info Missing", // UF2_ERR_PART_UNSET (9)
|
||||
"Block Data Too Long", // UF2_ERR_DATA_TOO_LONG (10)
|
||||
"Bad Block Sequence Number", // UF2_ERR_SEQ_MISMATCH (11)
|
||||
"Flash Erase Failed", // UF2_ERR_ERASE_FAILED (12)
|
||||
"Flash Write Failed", // UF2_ERR_WRITE_FAILED (13)
|
||||
"Write Failed Length", // UF2_ERR_WRITE_LENGTH (14)
|
||||
"Partition Write-Protected", // UF2_ERR_WRITE_PROTECT (15)
|
||||
"Memory Alloc Failed", // UF2_ERR_ALLOC_FAILED (16)
|
||||
};
|
||||
|
||||
static const char *errArdText[] = {
|
||||
nullptr, // UPDATE_ERROR_OK (0)
|
||||
nullptr, // UPDATE_ERROR_WRITE (1)
|
||||
nullptr, // UPDATE_ERROR_ERASE (2)
|
||||
nullptr, // UPDATE_ERROR_READ (3)
|
||||
nullptr, // UPDATE_ERROR_SPACE (4)
|
||||
"Bad Size Given", // UPDATE_ERROR_SIZE (5)
|
||||
"Stream Read Timeout", // UPDATE_ERROR_STREAM (6)
|
||||
"MD5 Check Failed", // UPDATE_ERROR_MD5 (7)
|
||||
nullptr, // UPDATE_ERROR_MAGIC_BYTE (8)
|
||||
"Could Not Activate The Firmware", // UPDATE_ERROR_ACTIVATE (9)
|
||||
nullptr, // UPDATE_ERROR_NO_PARTITION (10)
|
||||
"Bad Argument", // UPDATE_ERROR_BAD_ARGUMENT (11)
|
||||
"Aborted", // UPDATE_ERROR_ABORT (12)
|
||||
};
|
||||
|
||||
static char errorStr[14];
|
||||
@@ -29,153 +49,14 @@ static char errorStr[14];
|
||||
/**
|
||||
* @brief Set the callback invoked after writing data to flash.
|
||||
*/
|
||||
UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress callback) {
|
||||
this->callback = callback;
|
||||
UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress handler) {
|
||||
this->callback = std::move(handler);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateClass::cleanup(uint8_t ardErr, uf2_err_t uf2Err) {
|
||||
errUf2 = uf2Err;
|
||||
errArd = ardErr;
|
||||
|
||||
#if LT_DEBUG_OTA
|
||||
if (hasError())
|
||||
printErrorContext1();
|
||||
#endif
|
||||
|
||||
uf2_ctx_free(ctx); // NULL in constructor
|
||||
ctx = NULL;
|
||||
uf2_info_free(info); // NULL in constructor
|
||||
info = NULL;
|
||||
free(buf); // NULL in constructor
|
||||
buf = bufPos = NULL;
|
||||
|
||||
bytesWritten = 0;
|
||||
bytesTotal = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for UF2 errors. Set errArd and errUf2 in case of errors.
|
||||
* Ignored blocks are not reported as errors.
|
||||
* Abort the update.
|
||||
* Use like: "if (errorUf2(...)) return false;"
|
||||
* @return true if err is not OK, false otherwise
|
||||
*/
|
||||
bool UpdateClass::checkUf2Error(uf2_err_t err) {
|
||||
if (err <= UF2_ERR_IGNORE)
|
||||
return false;
|
||||
cleanup(errorMap[err], err);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
|
||||
*/
|
||||
void UpdateClass::abort() {
|
||||
LT_DM(OTA, "Aborting update");
|
||||
cleanup(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void UpdateClass::bufAlloc() {
|
||||
if (!buf)
|
||||
buf = bufPos = (uint8_t *)malloc(UF2_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
uint16_t UpdateClass::bufLeft() {
|
||||
return buf + UF2_BLOCK_SIZE - bufPos;
|
||||
}
|
||||
|
||||
uint16_t UpdateClass::bufSize() {
|
||||
return bufPos - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print string error info to the stream.
|
||||
*/
|
||||
void UpdateClass::printError(Print &out) {
|
||||
out.println(errorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print details about the error and current OTA state.
|
||||
*/
|
||||
void UpdateClass::printErrorContext1() {
|
||||
#if LT_DEBUG_OTA
|
||||
LT_EM(OTA, "Error: %s", errorString());
|
||||
if (errArd == UPDATE_ERROR_ABORT)
|
||||
return;
|
||||
|
||||
LT_EM(OTA, "- written: %u of %u", bytesWritten, bytesTotal);
|
||||
LT_EM(OTA, "- buf: size=%u, left=%u", bufSize(), bufLeft());
|
||||
hexdump(buf, bufSize());
|
||||
|
||||
if (ctx)
|
||||
LT_EM(
|
||||
OTA,
|
||||
"- ctx: seq=%u, part=%s",
|
||||
ctx->seq - 1, // print last parsed block seq
|
||||
ctx->part ? ctx->part->name : NULL
|
||||
);
|
||||
|
||||
uf2_block_t *block = (uf2_block_t *)buf;
|
||||
if (buf)
|
||||
LT_EM(OTA, "- buf: seq=%u/%u, addr=%u, len=%u", block->block_seq, block->block_count, block->addr, block->len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdateClass::printErrorContext2(const uint8_t *data, size_t len) {
|
||||
#if LT_DEBUG_OTA
|
||||
LT_EM(OTA, "- while writing %u bytes", len);
|
||||
if (data)
|
||||
hexdump(data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get string representation of the error in format
|
||||
* "ard=..,uf2=..". Returns "" if no error.
|
||||
*/
|
||||
const char *UpdateClass::errorString() {
|
||||
if (!errArd && !errUf2)
|
||||
return "";
|
||||
sprintf(errorStr, "ard=%u,uf2=%u", errArd, errUf2);
|
||||
return errorStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware name from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getFirmwareName() {
|
||||
if (info)
|
||||
return info->fw_name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware version from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getFirmwareVersion() {
|
||||
if (info)
|
||||
return info->fw_version;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LibreTiny version from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getLibreTinyVersion() {
|
||||
if (info)
|
||||
return info->lt_version;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get target board name from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getBoardName() {
|
||||
if (info)
|
||||
return info->board;
|
||||
return NULL;
|
||||
void UpdateClass::progressHandler(UpdateClass *self) {
|
||||
if (self->callback)
|
||||
self->callback(self->ctx->bytes_written, self->ctx->bytes_total);
|
||||
}
|
||||
|
||||
/** @copydoc lt_ota_can_rollback() */
|
||||
@@ -187,5 +68,85 @@ bool UpdateClass::canRollBack() {
|
||||
bool UpdateClass::rollBack() {
|
||||
if (!lt_ota_can_rollback())
|
||||
return false;
|
||||
return lt_ota_switch(false);
|
||||
return lt_ota_switch(/* revert= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get combined error code of the update.
|
||||
*/
|
||||
uint16_t UpdateClass::getErrorCode() const {
|
||||
return (this->getError() << 8) | this->getUF2Error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if any error has occurred (incl. aborting the update).
|
||||
*/
|
||||
bool UpdateClass::hasError() const {
|
||||
return this->getError() != UPDATE_ERROR_OK || this->getUF2Error() > UF2_ERR_IGNORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all errors. This is NOT recommended.
|
||||
*/
|
||||
void UpdateClass::clearError() {
|
||||
this->errArd = UPDATE_ERROR_OK;
|
||||
this->errUf2 = UF2_ERR_OK;
|
||||
if (this->ctx)
|
||||
this->ctx->error = UF2_ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a textual description of the error.
|
||||
*/
|
||||
const char *UpdateClass::errorString() const {
|
||||
uint8_t err;
|
||||
if ((err = this->getUF2Error()) > UF2_ERR_IGNORE)
|
||||
return errUf2Text[err];
|
||||
if ((err = this->getError()) != UPDATE_ERROR_OK)
|
||||
return errArdText[err];
|
||||
if (!this->hasError())
|
||||
return "";
|
||||
sprintf(errorStr, "ard=%u,uf2=%u", this->getError(), this->getUF2Error());
|
||||
return errorStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print string error info to the stream.
|
||||
*/
|
||||
void UpdateClass::printError(Print &out) const {
|
||||
out.println(errorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print details about the error and current OTA state.
|
||||
*/
|
||||
void UpdateClass::printErrorContext() {
|
||||
#if LT_DEBUG_OTA
|
||||
if (!this->ctx)
|
||||
return;
|
||||
|
||||
LT_EM(OTA, "Error: %s", errorString());
|
||||
if (errArd == UPDATE_ERROR_ABORT)
|
||||
return;
|
||||
|
||||
LT_EM(OTA, "- written: %u of %u", this->ctx->bytes_written, this->ctx->bytes_total);
|
||||
LT_EM(
|
||||
OTA,
|
||||
"- buf: size=%lld, left=%lld",
|
||||
this->ctx->buf_pos - this->ctx->buf,
|
||||
this->ctx->buf + UF2_BLOCK_SIZE - this->ctx->buf_pos
|
||||
);
|
||||
hexdump(this->ctx->buf, this->ctx->buf_pos - this->ctx->buf);
|
||||
|
||||
if (ctx)
|
||||
LT_EM(
|
||||
OTA,
|
||||
"- ctx: seq=%u, part=%s",
|
||||
this->ctx->uf2.seq - 1, // print last parsed block seq
|
||||
this->ctx->uf2.part ? this->ctx->uf2.part->name : nullptr
|
||||
);
|
||||
|
||||
auto *block = (uf2_block_t *)this->ctx->buf;
|
||||
LT_EM(OTA, "- buf: seq=%u/%u, addr=%u, len=%u", block->block_seq, block->block_count, block->addr, block->len);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -72,11 +72,11 @@ uint8_t LwIPUDP::begin(IPAddress address, uint16_t port) {
|
||||
}
|
||||
|
||||
uint8_t LwIPUDP::begin(uint16_t p) {
|
||||
return begin(IPAddress(INADDR_ANY), p);
|
||||
return begin(IPAddress((uint32_t)INADDR_ANY), p);
|
||||
}
|
||||
|
||||
uint8_t LwIPUDP::beginMulticast(IPAddress a, uint16_t p) {
|
||||
if (begin(IPAddress(INADDR_ANY), p)) {
|
||||
if (begin(IPAddress((uint32_t)INADDR_ANY), p)) {
|
||||
if ((uint32_t)a != 0) {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)a;
|
||||
@@ -111,14 +111,14 @@ void LwIPUDP::stop() {
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip;
|
||||
mreq.imr_interface.s_addr = (in_addr_t)0;
|
||||
setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
multicast_ip = IPAddress(INADDR_ANY);
|
||||
multicast_ip = IPAddress((uint32_t)INADDR_ANY);
|
||||
}
|
||||
close(udp_server);
|
||||
udp_server = -1;
|
||||
}
|
||||
|
||||
int LwIPUDP::beginMulticastPacket() {
|
||||
if (!server_port || multicast_ip == IPAddress(INADDR_ANY))
|
||||
if (!server_port || multicast_ip == IPAddress((uint32_t)INADDR_ANY))
|
||||
return 0;
|
||||
remote_ip = multicast_ip;
|
||||
remote_port = server_port;
|
||||
|
||||
@@ -13,6 +13,13 @@ extern "C" {
|
||||
#include <lwip/netif.h>
|
||||
}
|
||||
|
||||
#if LWIP_VERSION_SIMPLE < 20100 && defined(LWIP_NETIF_EXT_STATUS_CALLBACK)
|
||||
#warning "LWIP_NETIF_EXT_STATUS_CALLBACK not available before lwIP 2.1.0"
|
||||
#undef LWIP_NETIF_EXT_STATUS_CALLBACK
|
||||
#endif
|
||||
|
||||
#if LWIP_MDNS_RESPONDER
|
||||
|
||||
static std::vector<char *> services_name;
|
||||
static std::vector<char *> services;
|
||||
static std::vector<uint8_t> protos;
|
||||
@@ -81,7 +88,11 @@ static bool enableMDNS(struct netif *netif) {
|
||||
err_t ret = mdns_resp_add_netif(netif, hostName, 255);
|
||||
if (ret == ERR_OK) {
|
||||
LT_DM(MDNS, "mDNS started on netif %u, announcing it to network", netif->num);
|
||||
#if LWIP_VERSION_SIMPLE >= 20100
|
||||
mdns_resp_announce(netif);
|
||||
#else
|
||||
#warning "lwIP version older than 2.1.0, mdns_resp_announce() unavailable"
|
||||
#endif
|
||||
return true;
|
||||
} else {
|
||||
LT_DM(MDNS, "Cannot start mDNS on netif %u; ret=%d, errno=%d", netif->num, ret, errno);
|
||||
@@ -188,3 +199,5 @@ bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *ite
|
||||
MDNSResponder MDNS;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@ using std::min;
|
||||
#include <api/ArduinoAPI.h>
|
||||
#ifdef __cplusplus
|
||||
#include <LT.h>
|
||||
using namespace arduino;
|
||||
#endif
|
||||
|
||||
// Include family-specific code
|
||||
@@ -42,15 +43,17 @@ using std::min;
|
||||
#if defined(__cplusplus) && LT_ARD_HAS_SERIAL
|
||||
#include <Serial.h>
|
||||
|
||||
#if HAS_SERIAL0
|
||||
#if HAS_SERIAL_CLASS
|
||||
#if LT_HW_UART0
|
||||
extern SerialClass Serial0;
|
||||
#endif
|
||||
#if HAS_SERIAL1
|
||||
#if LT_HW_UART1
|
||||
extern SerialClass Serial1;
|
||||
#endif
|
||||
#if HAS_SERIAL2
|
||||
#if LT_HW_UART2
|
||||
extern SerialClass Serial2;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SerialN(x) Serial##x
|
||||
#define SerialM(x) SerialN(x)
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Empty yield() hook.
|
||||
*
|
||||
* This function is intended to be used by library writers to build
|
||||
* libraries or sketches that supports cooperative threads.
|
||||
*
|
||||
* Its defined as a weak symbol and it can be redefined to implement a
|
||||
* real cooperative scheduler.
|
||||
*/
|
||||
static void __empty() {
|
||||
// Empty
|
||||
}
|
||||
|
||||
void yield(void) __attribute__((weak, alias("__empty")));
|
||||
|
||||
/**
|
||||
* SysTick hook
|
||||
*
|
||||
* This function is called from SysTick handler, before the default
|
||||
* handler provided by Arduino.
|
||||
*/
|
||||
static int __false() {
|
||||
// Return false
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysTickHook(void) __attribute__((weak, alias("__false")));
|
||||
|
||||
/**
|
||||
* SVC hook
|
||||
* PendSV hook
|
||||
*
|
||||
* These functions are called from SVC handler, and PensSV handler.
|
||||
* Default action is halting.
|
||||
*/
|
||||
static void __halt() {
|
||||
// Halts
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void svcHook(void) __attribute__((weak, alias("__halt")));
|
||||
void pendSVHook(void) __attribute__((weak, alias("__halt")));
|
||||
22
cores/common/arduino/src/wiring/wiring.c
Normal file
22
cores/common/arduino/src/wiring/wiring.c
Normal file
@@ -0,0 +1,22 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if LT_HAS_FREERTOS
|
||||
|
||||
__attribute__((weak)) void delay(uint32_t ms) {
|
||||
vTaskDelay(pdMS_TO_TICKS(ms));
|
||||
}
|
||||
|
||||
__attribute__((weak)) void yield() {
|
||||
runPeriodicTasks();
|
||||
vTaskDelay(1);
|
||||
taskYIELD();
|
||||
lt_wdt_feed();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
__attribute__((weak)) void yield() {}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
|
||||
|
||||
#include "wiring_custom.h"
|
||||
#include "wiring_private.h"
|
||||
|
||||
#if LT_HAS_FREERTOS
|
||||
#include <FreeRTOS.h>
|
||||
@@ -32,6 +32,18 @@ void runPeriodicTasks() {
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable modes specified by 'mask'.
|
||||
*/
|
||||
void pinModeRemove(pin_size_t pinNumber, uint32_t mask) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
pinRemoveMode(pin, mask);
|
||||
if (pin->enabled == PIN_NONE && mask == PIN_MODE_ALL)
|
||||
pinRemoveData(pin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PinInfo struct for the specified number.
|
||||
* Returns NULL if pin number is invalid.
|
||||
@@ -85,20 +97,6 @@ bool pinEnabled(PinInfo *pin, uint32_t mask) {
|
||||
return (pin->enabled & mask) == mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if GPIO pin is configured as output.
|
||||
*/
|
||||
bool pinIsOutput(PinInfo *pin) {
|
||||
return pin->mode == OUTPUT || pin->mode == OUTPUT_OPENDRAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if GPIO pin is configured as output.
|
||||
*/
|
||||
bool pinIsInput(PinInfo *pin) {
|
||||
return pin->mode == INPUT || pin->mode == INPUT_PULLUP || pin->mode == INPUT_PULLDOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read voltage from ADC and return a value between 0 and
|
||||
* the current reading resolution.
|
||||
@@ -21,6 +21,10 @@ extern "C" {
|
||||
#define PIN_SWD (1 << 10)
|
||||
#define PIN_UART (1 << 11)
|
||||
|
||||
#define PIN_MODE_ALL 0xFFFFFFFF
|
||||
|
||||
typedef struct PinData_s PinData;
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief GPIO name in the family SDK.
|
||||
@@ -35,9 +39,9 @@ typedef struct {
|
||||
*/
|
||||
uint32_t enabled;
|
||||
/**
|
||||
* @brief Pin mode (direction, IRQ level, etc.).
|
||||
* @brief Pin data (direction, IRQ level, etc.). The structure is family-specific.
|
||||
*/
|
||||
uint32_t mode;
|
||||
PinData *data;
|
||||
} PinInfo;
|
||||
|
||||
extern PinInfo lt_arduino_pin_info_list[PINS_COUNT];
|
||||
@@ -55,14 +59,21 @@ bool startMainTask(void);
|
||||
void mainTask(const void *arg); // implemented in main.cpp
|
||||
void runPeriodicTasks(); // implemented in wiring_custom.c
|
||||
|
||||
void pinModeRemove(pin_size_t pinNumber, uint32_t mask);
|
||||
PinInfo *pinInfo(pin_size_t pinNumber);
|
||||
PinInfo *pinByIndex(uint32_t index);
|
||||
PinInfo *pinByGpio(uint32_t gpio);
|
||||
uint32_t pinIndex(PinInfo *pin);
|
||||
bool pinSupported(PinInfo *pin, uint32_t mask);
|
||||
bool pinEnabled(PinInfo *pin, uint32_t mask);
|
||||
bool pinIsOutput(PinInfo *pin);
|
||||
bool pinIsInput(PinInfo *pin);
|
||||
void pinRemoveMode(PinInfo *pin, uint32_t mask);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the pin, by removing all enabled modes.
|
||||
*/
|
||||
inline void pinModeNone(pin_size_t pinNumber) {
|
||||
pinModeRemove(pinNumber, PIN_MODE_ALL);
|
||||
}
|
||||
|
||||
int analogRead(pin_size_t pinNumber);
|
||||
void analogReadResolution(int res);
|
||||
7
cores/common/arduino/src/wiring/wiring_irq.c
Normal file
7
cores/common/arduino/src/wiring/wiring_irq.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
|
||||
attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL);
|
||||
}
|
||||
25
cores/common/arduino/src/wiring/wiring_private.c
Normal file
25
cores/common/arduino/src/wiring/wiring_private.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
#if __has_include(<wiring_data.h>)
|
||||
/**
|
||||
* @brief Allocate and return a PinData structure (family-specific).
|
||||
*/
|
||||
PinData *pinData(PinInfo *pin) {
|
||||
if (pin->data == NULL) {
|
||||
pin->data = calloc(1, sizeof(PinData));
|
||||
}
|
||||
return (PinData *)pin->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deallocate the PinData structure.
|
||||
*/
|
||||
void pinRemoveData(PinInfo *pin) {
|
||||
if (pin->data != NULL) {
|
||||
free(pin->data);
|
||||
}
|
||||
pin->data = NULL;
|
||||
}
|
||||
#endif
|
||||
64
cores/common/arduino/src/wiring/wiring_private.h
Normal file
64
cores/common/arduino/src/wiring/wiring_private.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if __has_include(<sdk_private.h>)
|
||||
#include <sdk_private.h>
|
||||
#endif
|
||||
|
||||
#if __has_include(<wiring_data.h>)
|
||||
#include <wiring_data.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
PinData *pinData(PinInfo *pin);
|
||||
void pinRemoveData(PinInfo *pin);
|
||||
|
||||
inline void pinEnable(PinInfo *pin, uint32_t mask) {
|
||||
pin->enabled |= mask;
|
||||
}
|
||||
|
||||
inline void pinDisable(PinInfo *pin, uint32_t mask) {
|
||||
pin->enabled &= ~mask;
|
||||
}
|
||||
|
||||
#define pinCheckGetInfo(pinNumber, mask, ret) \
|
||||
PinInfo *pin = pinInfo(pinNumber); \
|
||||
if (!pin) \
|
||||
return ret; \
|
||||
if (!pinSupported(pin, mask)) \
|
||||
return ret;
|
||||
|
||||
#define pinCheckGetData(pinNumber, mask, ret) \
|
||||
PinInfo *pin = pinInfo(pinNumber); \
|
||||
if (!pin) \
|
||||
return ret; \
|
||||
if (!pinSupported(pin, mask)) \
|
||||
return ret; \
|
||||
PinData *data = pinData(pin);
|
||||
|
||||
#define pinIsOutput(pin, data) (pinEnabled(pin, PIN_GPIO) && (data->gpioMode ^ 0b101) < 5)
|
||||
#define pinIsInput(pin, data) (pinEnabled(pin, PIN_GPIO) && (data->gpioMode ^ 0b101) > 4)
|
||||
|
||||
#define pinSetOutputPull(pin, data, pinNumber, status) \
|
||||
do { \
|
||||
if (!pinIsOutput(pin, data)) { \
|
||||
pinMode(pinNumber, INPUT_PULLDOWN ^ !!status); \
|
||||
return; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define pinSetInputMode(pin, data, pinNumber) \
|
||||
do { \
|
||||
if (!pinIsInput(pin, data)) \
|
||||
pinMode(pinNumber, INPUT); \
|
||||
} while (0);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
58
cores/common/base/api/lt_cpu.c
Normal file
58
cores/common/base/api/lt_cpu.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||
|
||||
#include "lt_cpu.h"
|
||||
|
||||
#if LT_HAS_FREERTOS
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#endif
|
||||
|
||||
lt_cpu_family_t lt_cpu_get_family() {
|
||||
return FAMILY;
|
||||
}
|
||||
|
||||
const char *lt_cpu_get_family_name() {
|
||||
return STRINGIFY_MACRO(FAMILY) + 2;
|
||||
}
|
||||
|
||||
__attribute__((weak)) lt_cpu_model_t lt_cpu_get_model() {
|
||||
return MCU;
|
||||
}
|
||||
|
||||
const char *lt_cpu_get_model_name() {
|
||||
return STRINGIFY_MACRO(MCU);
|
||||
}
|
||||
|
||||
const char *lt_cpu_get_model_code() {
|
||||
return STRINGIFY_MACRO(MCULC);
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint32_t lt_cpu_get_unique_id() {
|
||||
return lt_cpu_get_mac_id();
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint32_t lt_cpu_get_mac_id() {
|
||||
uint8_t mac[6];
|
||||
lt_get_device_mac(mac);
|
||||
return (mac[3] << 0) | (mac[4] << 8) | (mac[5] << 16);
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint8_t lt_cpu_get_core_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LT_HAS_FREERTOS
|
||||
__attribute__((weak)) uint32_t lt_cpu_get_freq() {
|
||||
return configCPU_CLOCK_HZ;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t lt_cpu_get_freq_mhz() {
|
||||
return lt_cpu_get_freq() / 1000000;
|
||||
}
|
||||
|
||||
#if LT_HAS_FREERTOS
|
||||
__attribute__((weak)) uint32_t lt_cpu_get_cycle_count() {
|
||||
return xTaskGetTickCount() * (configCPU_CLOCK_HZ / configTICK_RATE_HZ);
|
||||
}
|
||||
#endif
|
||||
@@ -38,6 +38,7 @@ uint32_t lt_cpu_get_unique_id();
|
||||
/**
|
||||
* @brief Get CPU ID based on the last three octets of MAC address.
|
||||
* Note: the number is 24-bit (with the MSB being zero).
|
||||
* The 3rd-to-last octet is least-significant, the last octet is most-significant.
|
||||
*/
|
||||
uint32_t lt_cpu_get_mac_id();
|
||||
|
||||
|
||||
80
cores/common/base/api/lt_device.c
Normal file
80
cores/common/base/api/lt_device.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||
|
||||
#include "lt_device.h"
|
||||
|
||||
static char *device_name = NULL;
|
||||
|
||||
const char *lt_get_version() {
|
||||
return LT_VERSION_STR;
|
||||
}
|
||||
|
||||
const char *lt_get_board_code() {
|
||||
return LT_BOARD_STR;
|
||||
}
|
||||
|
||||
const char *lt_get_device_name() {
|
||||
if (device_name)
|
||||
return device_name;
|
||||
uint32_t chip_id = lt_cpu_get_mac_id();
|
||||
uint8_t *id = (uint8_t *)&chip_id;
|
||||
|
||||
const char *model = lt_cpu_get_model_code();
|
||||
uint8_t model_len = strlen(model);
|
||||
device_name = (char *)malloc(3 + model_len + 1 + 6 + 1);
|
||||
|
||||
sprintf(device_name, "LT-%s-%02x%02x%02x", model, id[0], id[1], id[2]);
|
||||
return device_name;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void lt_reboot() {
|
||||
// The Watchdog Way
|
||||
lt_wdt_enable(1L);
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
__attribute__((weak)) bool lt_reboot_wdt() {
|
||||
if (!lt_wdt_enable(1L))
|
||||
return false;
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
__attribute__((weak)) bool lt_reboot_download_mode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
__attribute__((weak)) lt_reboot_reason_t lt_get_reboot_reason() {
|
||||
return REBOOT_REASON_UNKNOWN;
|
||||
}
|
||||
|
||||
const char *lt_get_reboot_reason_name(lt_reboot_reason_t reason) {
|
||||
if (!reason)
|
||||
reason = lt_get_reboot_reason();
|
||||
switch (reason) {
|
||||
case REBOOT_REASON_POWER:
|
||||
return "Power-On";
|
||||
case REBOOT_REASON_BROWNOUT:
|
||||
return "Brownout";
|
||||
case REBOOT_REASON_HARDWARE:
|
||||
return "HW Reboot";
|
||||
case REBOOT_REASON_SOFTWARE:
|
||||
return "SW Reboot";
|
||||
case REBOOT_REASON_WATCHDOG:
|
||||
return "WDT Reset";
|
||||
case REBOOT_REASON_CRASH:
|
||||
return "Crash";
|
||||
case REBOOT_REASON_SLEEP:
|
||||
return "Sleep Wakeup";
|
||||
case REBOOT_REASON_DEBUGGER:
|
||||
return "Debugger";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((weak)) bool lt_set_debug_mode(lt_debug_mode_t mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void lt_gpio_recover() {
|
||||
lt_set_debug_mode(DEBUG_MODE_OFF);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user