mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-29 00:08:04 +01:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad847eb53 | ||
|
|
f268c48717 | ||
|
|
a0ebf0d255 | ||
|
|
6fcfe02b28 | ||
|
|
2edbf27033 | ||
|
|
46fb23b70f | ||
|
|
fce6c16153 | ||
|
|
a31e1453d0 | ||
|
|
d17502cb63 | ||
|
|
828679b6f3 | ||
|
|
bff6794303 | ||
|
|
2f86ea54d0 | ||
|
|
80e0d9e5dd | ||
|
|
4d8cfeae63 | ||
|
|
3271f399c9 | ||
|
|
862c08c00b | ||
|
|
77cbf92281 | ||
|
|
c4022e45f9 | ||
|
|
a13c220565 | ||
|
|
3989ecc3a3 | ||
|
|
cb0f029900 | ||
|
|
443714e9dc | ||
|
|
f3f163fa00 | ||
|
|
8848cfc0f8 | ||
|
|
6c91c78aa1 | ||
|
|
98baa020ff | ||
|
|
56e1e9e6b6 | ||
|
|
2817aa7e38 | ||
|
|
2292aeaf7e | ||
|
|
3472b5d4b6 | ||
|
|
19f6a093d3 | ||
|
|
d6734a7f79 | ||
|
|
da487fbc5f | ||
|
|
3b7fd7d1f6 | ||
|
|
f4273630ee | ||
|
|
0cbb9e770e | ||
|
|
9dfb37b376 | ||
|
|
e457475ea7 | ||
|
|
806b2dc9e0 | ||
|
|
2b7fc93043 | ||
|
|
6a711c99eb | ||
|
|
ffd0acff72 | ||
|
|
a9c9812525 | ||
|
|
03ce036083 | ||
|
|
a98ad537ea | ||
|
|
2726b4d2fe | ||
|
|
fd5adb40f8 | ||
|
|
89346b5d77 | ||
|
|
7ac57577df | ||
|
|
09f7466f6f | ||
|
|
55e50b1920 | ||
|
|
7cb5e13a7f | ||
|
|
6f08af2c67 | ||
|
|
e185ddd99b | ||
|
|
3079101c48 | ||
|
|
0b66a23ce4 | ||
|
|
41c7cb843f | ||
|
|
c43e71288d | ||
|
|
66cc62339f | ||
|
|
84bfb18261 | ||
|
|
ab3cef8dda | ||
|
|
c831f07b6e | ||
|
|
ba39f60e69 | ||
|
|
f409f493ec | ||
|
|
df783c6f8f | ||
|
|
f0e4d25d36 | ||
|
|
b4bf060a51 | ||
|
|
e3407468ea | ||
|
|
8daff632ba | ||
|
|
21a52e9b17 | ||
|
|
f9b4d163bc | ||
|
|
a78f2e3af5 |
81
.github/workflows/build-test.yml
vendored
Normal file
81
.github/workflows/build-test.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
name: Firmware build test
|
||||
|
||||
on: [push,pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
key: ${{ runner.os }}-pio
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install PlatformIO Core
|
||||
run: pip install --upgrade platformio
|
||||
|
||||
- name: Build Simple_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment Simple_AP
|
||||
pio run --target buildfs --environment Simple_AP
|
||||
|
||||
- name: Build OpenEPaperLink_Mini_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment OpenEPaperLink_Mini_AP
|
||||
pio run --target buildfs --environment OpenEPaperLink_Mini_AP
|
||||
|
||||
# - name: Build OpenEPaperLink_Nano_AP
|
||||
# run: |
|
||||
# cd ESP32_AP-Flasher
|
||||
# pio run --environment OpenEPaperLink_Nano_AP
|
||||
# pio run --target buildfs --environment OpenEPaperLink_Nano_AP
|
||||
|
||||
- name: Build OpenEPaperLink_AP_and_Flasher
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment OpenEPaperLink_AP_and_Flasher
|
||||
pio run --target buildfs --environment OpenEPaperLink_AP_and_Flasher
|
||||
|
||||
# - name: Build Wemos_d1_mini32_AP
|
||||
# run: |
|
||||
# cd ESP32_AP-Flasher
|
||||
# pio run --environment Wemos_d1_mini32_AP
|
||||
# pio run --target buildfs --environment Wemos_d1_mini32_AP
|
||||
|
||||
# - name: Build M5Stack_Core_ONE_AP
|
||||
# run: |
|
||||
# cd ESP32_AP-Flasher
|
||||
# pio run --environment M5Stack_Core_ONE_AP
|
||||
# pio run --target buildfs --environment M5Stack_Core_ONE_AP
|
||||
|
||||
- name: Build ESP32_S3_16_8_YELLOW_AP]
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment ESP32_S3_16_8_YELLOW_AP
|
||||
pio run --target buildfs --environment ESP32_S3_16_8_YELLOW_AP
|
||||
|
||||
# - name: Build Sonoff_zb_bridge_P_AP
|
||||
# run: |
|
||||
# cd ESP32_AP-Flasher
|
||||
# pio run --environment Sonoff_zb_bridge_P_AP
|
||||
# pio run --target buildfs --environment Sonoff_zb_bridge_P_AP
|
||||
|
||||
# - name: Build OpenEPaperLink_CC1352P
|
||||
# run: |
|
||||
# cd ESP32_AP-Flasher
|
||||
# pio run --environment OpenEPaperLink_CC1352P
|
||||
# pio run --target buildfs --environment OpenEPaperLink_CC1352P
|
||||
|
||||
# - name: OutdoorAP
|
||||
# run: |
|
||||
# cd ESP32_AP-Flasher
|
||||
# pio run --environment OutdoorAP
|
||||
# pio run --target buildfs --environment OutdoorAP
|
||||
57
.github/workflows/esp32-build-test.yml
vendored
57
.github/workflows/esp32-build-test.yml
vendored
@@ -1,57 +0,0 @@
|
||||
name: ESP32 firmware builf test
|
||||
|
||||
on: [push,pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
key: ${{ runner.os }}-pio
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install PlatformIO Core
|
||||
run: pip install --upgrade platformio
|
||||
|
||||
- name: Build Simple_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment Simple_AP
|
||||
pio run --target buildfs --environment Simple_AP
|
||||
|
||||
- name: Build OpenEPaperLink_Mini_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment OpenEPaperLink_Mini_AP
|
||||
pio run --target buildfs --environment OpenEPaperLink_Mini_AP
|
||||
|
||||
- name: Build OpenEPaperLink_Nano_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment OpenEPaperLink_Nano_AP
|
||||
pio run --target buildfs --environment OpenEPaperLink_Nano_AP
|
||||
|
||||
- name: Build OpenEPaperLink_AP_and_Flasher
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment OpenEPaperLink_AP_and_Flasher
|
||||
pio run --target buildfs --environment OpenEPaperLink_AP_and_Flasher
|
||||
|
||||
- name: Build Wemos_d1_mini32_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment Wemos_d1_mini32_AP
|
||||
pio run --target buildfs --environment Wemos_d1_mini32_AP
|
||||
|
||||
- name: Build M5Stack_Core_ONE_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --environment M5Stack_Core_ONE_AP
|
||||
pio run --target buildfs --environment M5Stack_Core_ONE_AP
|
||||
30
.github/workflows/release.yml
vendored
30
.github/workflows/release.yml
vendored
@@ -21,6 +21,18 @@ jobs:
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
# - name: Zip web files
|
||||
# run: |
|
||||
# cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_AP-Flasher
|
||||
# python gzip_wwwfiles.py
|
||||
|
||||
# - name: Commit zipped files
|
||||
# run: |
|
||||
# git config --global user.name 'Bot'
|
||||
# git config --global user.email "bot@openepaperlink.de"
|
||||
# git commit -am "Zipped web files"
|
||||
# git push origin HEAD:master
|
||||
|
||||
- name: Install PlatformIO Core
|
||||
run: pip install --upgrade platformio
|
||||
|
||||
@@ -138,6 +150,24 @@ jobs:
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||
cp OpenEPaperLink_AP_and_Flasher/firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher.bin
|
||||
cp OpenEPaperLink_AP_and_Flasher/merged-firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher_full.bin
|
||||
|
||||
- name: Build firmware for ESP32_S3_16_8_YELLOW_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
pio run --environment ESP32_S3_16_8_YELLOW_AP
|
||||
pio run --target buildfs --environment ESP32_S3_16_8_YELLOW_AP
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP/boot_app0.bin
|
||||
cp .pio/build/ESP32_S3_16_8_YELLOW_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP/firmware.bin
|
||||
cp .pio/build/ESP32_S3_16_8_YELLOW_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP/bootloader.bin
|
||||
cp .pio/build/ESP32_S3_16_8_YELLOW_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP/partitions.bin
|
||||
cp .pio/build/ESP32_S3_16_8_YELLOW_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP/littlefs.bin
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_YELLOW_AP
|
||||
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||
cp ESP32_S3_16_8_YELLOW_AP/firmware.bin espbinaries/ESP32_S3_16_8_YELLOW_AP.bin
|
||||
cp ESP32_S3_16_8_YELLOW_AP/merged-firmware.bin espbinaries/ESP32_S3_16_8_YELLOW_AP_full.bin
|
||||
|
||||
- name: generate release json file
|
||||
run: |
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
build
|
||||
*.axf
|
||||
# Allow
|
||||
!*.bin
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
const char font[256][40]={
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x20
|
||||
{0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x21
|
||||
{0x00,0x00,0xC0,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x22
|
||||
{0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x22,0x00,0x11,0x00,0x11,0x00,0x11,0xE0,0xFF,0x80,0x08,0x80,0x08,0x80,0x08,0xE0,0x7F,0x40,0x04,0x40,0x04,0x20,0x02,0x20,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x23
|
||||
{0x00,0x00,0x00,0x04,0x00,0x1F,0x80,0x3F,0xC0,0x24,0xC0,0x04,0xC0,0x04,0x80,0x07,0x00,0x07,0x00,0x1C,0x00,0x1C,0x00,0x34,0x00,0x34,0x40,0x34,0xC0,0x1F,0x80,0x0F,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x24
|
||||
{0x00,0x00,0x00,0x00,0xE0,0x81,0x30,0x43,0x30,0x23,0x30,0x13,0x30,0x0B,0x30,0x0B,0xE0,0x05,0x00,0x7A,0x00,0xCD,0x00,0xCD,0x80,0xCC,0x40,0xCC,0x20,0xCC,0x10,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x25
|
||||
{0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x1F,0x80,0x19,0x80,0x19,0x80,0x0D,0x00,0x07,0xC0,0x03,0x60,0xC6,0x30,0xCE,0x30,0xCC,0x30,0x78,0x70,0x78,0xE0,0x7F,0xC0,0xEF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x26
|
||||
{0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x27
|
||||
{0x00,0x00,0x00,0x30,0x00,0x3C,0x00,0x0E,0x00,0x06,0x00,0x03,0x00,0x03,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x0E,0x00,0x3C,0x00,0x30,0x00,0x00}, // 0x28
|
||||
{0x00,0x00,0xC0,0x00,0xC0,0x03,0x00,0x07,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x07,0xC0,0x03,0xC0,0x00,0x00,0x00}, // 0x29
|
||||
{0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x60,0x33,0xE0,0x3C,0x00,0x00,0x80,0x0D,0xC0,0x19,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x2A
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0xE0,0x7F,0xE0,0x7F,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x2B
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x06,0x00,0x02,0x00,0x03,0x00,0x00}, // 0x2C
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3F,0xC0,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x2D
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x2E
|
||||
{0x00,0x00,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x03,0x80,0x01,0x80,0x01,0x80,0x01,0xC0,0x00,0xC0,0x00,0x60,0x00,0x00,0x00}, // 0x2F
|
||||
{0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x1F,0xC0,0x30,0xC0,0x30,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xC0,0x30,0xC0,0x30,0x80,0x1F,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x30
|
||||
{0x00,0x00,0x00,0x00,0x00,0x06,0xC0,0x07,0x60,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0xE0,0x7F,0xE0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x31
|
||||
{0x00,0x00,0x00,0x00,0x80,0x0F,0xC0,0x1F,0x40,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x80,0x01,0xC0,0x00,0xC0,0x3F,0xC0,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x32
|
||||
{0x00,0x00,0x00,0x00,0x80,0x0F,0xC0,0x3F,0x40,0x30,0x00,0x30,0x00,0x18,0x80,0x0F,0x80,0x0F,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x30,0x40,0x38,0xC0,0x1F,0xC0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x33
|
||||
{0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x1C,0x00,0x1E,0x00,0x1A,0x00,0x19,0x80,0x19,0xC0,0x18,0x40,0x18,0xE0,0x7F,0xE0,0x7F,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x34
|
||||
{0x00,0x00,0x00,0x00,0x80,0x3F,0x80,0x3F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x0F,0x80,0x1F,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x38,0x80,0x1F,0x80,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x35
|
||||
{0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x1F,0xC0,0x11,0xC0,0x00,0x60,0x00,0x60,0x0E,0x60,0x1F,0xE0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0xC0,0x38,0xC0,0x1F,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x36
|
||||
{0x00,0x00,0x00,0x00,0xC0,0x7F,0xC0,0x7F,0x00,0x60,0x00,0x30,0x00,0x10,0x00,0x18,0x00,0x0C,0x00,0x04,0x00,0x06,0x00,0x02,0x00,0x03,0x00,0x03,0x80,0x01,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x37
|
||||
{0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x1F,0xC0,0x18,0xC0,0x18,0xC0,0x19,0x80,0x0F,0x00,0x07,0xC0,0x1E,0x60,0x38,0x60,0x30,0x60,0x30,0xE0,0x38,0xC0,0x1F,0x80,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x38
|
||||
{0x00,0x00,0x00,0x00,0x80,0x07,0xC0,0x1F,0xE0,0x18,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x38,0xC0,0x37,0x80,0x33,0x00,0x30,0x00,0x18,0x40,0x1C,0xC0,0x0F,0x80,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x39
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x3A
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x06,0x00,0x02,0x00,0x03,0x00,0x00}, // 0x3B
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x70,0x00,0x3C,0x00,0x0E,0x80,0x03,0xE0,0x00,0x80,0x03,0x00,0x0E,0x00,0x3C,0x00,0x70,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x3C
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x7F,0xE0,0x7F,0x00,0x00,0x00,0x00,0xE0,0x7F,0xE0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x3D
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xE0,0x00,0xC0,0x03,0x00,0x07,0x00,0x1C,0x00,0x70,0x00,0x1C,0x00,0x07,0xC0,0x03,0xE0,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x3E
|
||||
{0x00,0x00,0x00,0x00,0xE0,0x0F,0xE0,0x3F,0x20,0x38,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x3F
|
||||
{0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x31,0xC0,0x60,0x60,0x7C,0x30,0x66,0x30,0x63,0x30,0x63,0x30,0x73,0x30,0x73,0x30,0x6F,0x60,0xE6,0x60,0x00,0xC0,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x40
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0F,0x00,0x0F,0x00,0x0D,0x80,0x19,0x80,0x19,0xC0,0x38,0xC0,0x30,0xC0,0x3F,0xE0,0x7F,0x60,0x60,0x60,0x60,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x41
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x0F,0xE0,0x1F,0x60,0x18,0x60,0x18,0x60,0x0C,0xE0,0x07,0xE0,0x0F,0x60,0x18,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x1F,0xE0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x42
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x80,0x7F,0xC0,0x41,0xC0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xC0,0x00,0xC0,0x43,0x80,0x7F,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x43
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x0F,0xE0,0x1F,0x60,0x38,0x60,0x70,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x30,0x60,0x38,0xE0,0x1F,0xE0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x44
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x7F,0xC0,0x7F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x3F,0xC0,0x3F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x7F,0xC0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x45
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x7F,0xC0,0x7F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x3F,0xC0,0x3F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x46
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x80,0x7F,0xC0,0x41,0xC0,0x00,0x60,0x00,0x60,0x00,0x60,0x78,0x60,0x78,0x60,0x60,0xC0,0x60,0xC0,0x61,0x80,0x7F,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x47
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x3F,0xE0,0x3F,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x48
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x1F,0xE0,0x1F,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0xE0,0x1F,0xE0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x49
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1F,0x80,0x1F,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0xC0,0x0F,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x4A
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x70,0x60,0x38,0x60,0x1C,0x60,0x0E,0x60,0x06,0x60,0x03,0xE0,0x03,0x60,0x07,0x60,0x0E,0x60,0x1C,0x60,0x38,0x60,0x70,0x60,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x4B
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x7F,0xC0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x4C
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x70,0x70,0xF0,0x78,0xB0,0x68,0xB0,0x68,0xB0,0x6D,0x30,0x65,0x30,0x65,0x30,0x67,0x30,0x62,0x30,0x60,0x30,0x60,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x4D
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x60,0xE0,0x60,0xE0,0x61,0xE0,0x61,0x60,0x63,0x60,0x67,0x60,0x66,0x60,0x6E,0x60,0x6C,0x60,0x78,0x60,0x78,0x60,0x70,0x60,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x4E
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0xC0,0x1F,0xE0,0x38,0x70,0x70,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x70,0x70,0xE0,0x38,0xC0,0x1F,0x80,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x4F
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x1F,0xC0,0x3F,0xC0,0x70,0xC0,0x60,0xC0,0x60,0xC0,0x70,0xC0,0x3F,0xC0,0x0F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x50
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0xC0,0x1F,0xE0,0x38,0x70,0x70,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x60,0x30,0xE0,0x38,0xC0,0x1F,0x80,0x0F,0x00,0x38,0x00,0xF0,0x00,0x40,0x00,0x00}, // 0x51
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0xE0,0x1F,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x1C,0xE0,0x0F,0xE0,0x07,0x60,0x0E,0x60,0x1C,0x60,0x38,0x60,0x70,0x60,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x52
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0xC0,0x1F,0x60,0x10,0x60,0x00,0xE0,0x00,0xC0,0x03,0x80,0x0F,0x00,0x3C,0x00,0x30,0x00,0x30,0x60,0x38,0xE0,0x1F,0xC0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x53
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x54
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x38,0xC0,0x1F,0x80,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x55
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xC0,0x60,0x60,0x60,0x60,0xE0,0x60,0xC0,0x30,0xC0,0x30,0xC0,0x31,0x80,0x19,0x80,0x1B,0x00,0x0B,0x00,0x0F,0x00,0x0F,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x56
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xC0,0x30,0xC0,0x30,0xC0,0x20,0x46,0x20,0x46,0x20,0x6E,0x60,0x6F,0x60,0x69,0x60,0x69,0x60,0x39,0xC0,0x39,0xC0,0x39,0xC0,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x57
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xE0,0xE0,0x60,0xC0,0x30,0x80,0x19,0x80,0x0F,0x00,0x0F,0x00,0x06,0x00,0x0F,0x80,0x1D,0x80,0x19,0xC0,0x30,0x60,0x70,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x58
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xC0,0x60,0x60,0xC0,0x30,0xC0,0x31,0x80,0x19,0x00,0x0F,0x00,0x0F,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x59
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x7F,0xE0,0x7F,0x00,0x60,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x80,0x01,0xC0,0x00,0x60,0x00,0xE0,0x7F,0xE0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x5A
|
||||
{0x00,0x00,0x00,0x3F,0x00,0x3F,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x3F,0x00,0x3F,0x00,0x00}, // 0x5B
|
||||
{0x00,0x00,0x60,0x00,0xC0,0x00,0xC0,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x00}, // 0x5C
|
||||
{0x00,0x00,0xC0,0x0F,0xC0,0x0F,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0xC0,0x0F,0xC0,0x0F,0x00,0x00}, // 0x5D
|
||||
{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x0E,0x00,0x0A,0x00,0x0B,0x00,0x1B,0x80,0x11,0x80,0x31,0xC0,0x30,0xC0,0x20,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x5E
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00}, // 0x5F
|
||||
{0x00,0x06,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x60
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1F,0xC0,0x3F,0x40,0x30,0x00,0x30,0x00,0x30,0x80,0x3F,0xC0,0x30,0x60,0x30,0x60,0x38,0xE0,0xFF,0xC0,0xE7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x61
|
||||
{0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x0E,0x60,0x1F,0xE0,0x39,0xE0,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x18,0xE0,0x1F,0x60,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x62
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xC0,0x3F,0xC0,0x21,0xE0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xE0,0x00,0xC0,0x01,0xC0,0x3F,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x63
|
||||
{0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x80,0x37,0xC0,0x3F,0xC0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x38,0xC0,0x3F,0x80,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x64
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x1F,0xC0,0x38,0x60,0x30,0xE0,0x3F,0xE0,0x3F,0x60,0x00,0x60,0x00,0xC0,0x20,0xC0,0x3F,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x65
|
||||
{0x00,0x00,0x00,0x7E,0x00,0x7F,0x00,0x03,0x00,0x03,0xE0,0x7F,0xE0,0x7F,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x66
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x37,0xC0,0x3F,0xC0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x38,0xC0,0x3F,0x80,0x37,0x00,0x30,0x40,0x38,0xC0,0x1F,0x80,0x0F}, // 0x67
|
||||
{0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x1E,0x60,0x3F,0xE0,0x31,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x68
|
||||
{0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0xC0,0x0F,0xC0,0x0F,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x69
|
||||
{0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x80,0x1F,0x80,0x1F,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0xC0,0x0F,0xC0,0x07}, // 0x6A
|
||||
{0x00,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x70,0xC0,0x38,0xC0,0x1C,0xC0,0x0E,0xC0,0x06,0xC0,0x07,0xC0,0x0E,0xC0,0x1C,0xC0,0x38,0xC0,0x70,0xC0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x6B
|
||||
{0x00,0x00,0xC0,0x0F,0xC0,0x0F,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x6C
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x39,0xF0,0x7F,0x70,0x67,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x6D
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x1E,0x60,0x3F,0xE0,0x31,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x6E
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x3F,0xC0,0x30,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xC0,0x30,0xC0,0x3F,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x6F
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x0F,0xE0,0x1F,0xE0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x18,0xE0,0x1F,0x60,0x0F,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00}, // 0x70
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x37,0xC0,0x3F,0xC0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xE0,0x38,0xC0,0x37,0x80,0x33,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30}, // 0x71
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3C,0xC0,0x3E,0xC0,0x23,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x72
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1F,0xC0,0x1F,0xC0,0x00,0xC0,0x00,0xC0,0x03,0x00,0x1F,0x00,0x38,0x00,0x30,0x40,0x30,0xC0,0x1F,0x80,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x73
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0xE0,0x7F,0xE0,0x7F,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x7F,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x74
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x3C,0xE0,0x37,0xC0,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x75
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xC0,0x20,0xC0,0x30,0xC0,0x30,0x80,0x11,0x80,0x19,0x80,0x19,0x00,0x0B,0x00,0x0F,0x00,0x0F,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x76
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xC0,0x30,0xC6,0x30,0xC6,0x20,0x4E,0x60,0x4F,0x60,0x49,0x60,0x69,0x60,0x79,0xC0,0x39,0xC0,0x30,0xC0,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x77
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x70,0xC0,0x30,0x80,0x19,0x80,0x0B,0x00,0x0F,0x00,0x06,0x00,0x0F,0x80,0x1D,0x80,0x19,0xC0,0x30,0x60,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x78
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xC0,0x20,0xC0,0x30,0xC0,0x31,0x80,0x19,0x80,0x19,0x00,0x0B,0x00,0x0F,0x00,0x0F,0x00,0x06,0x00,0x06,0x00,0x02,0x00,0x03,0xC0,0x03,0xC0,0x01}, // 0x79
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x3F,0xE0,0x3F,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x80,0x01,0xC0,0x00,0xE0,0x3F,0xE0,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x7A
|
||||
{0x00,0x00,0x00,0x3C,0x00,0x3E,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0xC0,0x03,0xC0,0x03,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x3E,0x00,0x3C,0x00,0x00}, // 0x7B
|
||||
{0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00}, // 0x7C
|
||||
{0x00,0x00,0xC0,0x03,0xC0,0x07,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x3C,0x00,0x3C,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0xC0,0x07,0xC0,0x03,0x00,0x00}, // 0x7D
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x43,0xE0,0x7F,0x20,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x7E
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3F,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0xC0,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // 0x7F
|
||||
};
|
||||
BIN
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/88MZ100_7.4_BETA-0.2.bin
Executable file
BIN
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/88MZ100_7.4_BETA-0.2.bin
Executable file
Binary file not shown.
BIN
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/88MZ100_7.4_BETA-0.2_ota.bin
Executable file
BIN
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/88MZ100_7.4_BETA-0.2_ota.bin
Executable file
Binary file not shown.
BIN
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/88MZ100_7.4_BETA.bin
Normal file
BIN
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/88MZ100_7.4_BETA.bin
Normal file
Binary file not shown.
@@ -1,10 +1,11 @@
|
||||
|
||||
MZ_FLASHER=python ../88MZ100_Flasher/88MZ100_Uart_flasher.py
|
||||
|
||||
ARMGCC=armgcc/bin/
|
||||
ARMGCC=/usr/bin/
|
||||
CC=$(ARMGCC)arm-none-eabi-gcc
|
||||
AS=$(ARMGCC)arm-none-eabi-as
|
||||
OBJCOPY=$(ARMGCC)arm-none-eabi-objcopy
|
||||
|
||||
#-Wall
|
||||
CC_WARNING_FLAGS=-Wall -Wformat=0 -Wattributes -Wstrict-aliasing=0
|
||||
CC_FlAGS=-mcpu=cortex-m3 -g -O0 -mthumb -fdata-sections -ffunction-sections -std=c99
|
||||
@@ -16,10 +17,15 @@ C_EXECUTABLE :=$(C_SOURCES:.c=)
|
||||
COMPORT = COM12
|
||||
|
||||
|
||||
build: clean compile create_ota_img flash_uart_flash
|
||||
build: compile
|
||||
only: clean compile create_ota_img
|
||||
uart: clean compile flash_uart
|
||||
|
||||
#build: clean compile create_ota_img flash_uart_flash
|
||||
#only: clean compile create_ota_img
|
||||
#uart: clean compile flash_uart
|
||||
|
||||
|
||||
compile:
|
||||
@mkdir -p build
|
||||
@$(AS) -mcpu=cortex-m3 --gdwarf-2 -mthumb-interwork -o build/startup.o startup.S
|
||||
@@ -40,16 +46,8 @@ compile:
|
||||
@$(CC) $(CC_FlAGS) -c mz100_gpt.c -o build/mz100_gpt.o
|
||||
@$(CC) $(CC_FlAGS) -c mz100_sleep.c -o build/mz100_sleep.o
|
||||
@$(CC) $(CC_FlAGS) -c mz100_uart.c -o build/mz100_uart.o
|
||||
# UZLIB
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/adler32.c -o build/adler32.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/crc32.c -o build/crc32.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/defl_static.c -o build/defl_static.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/genlz77.c -o build/genlz77.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/tinfgzip.c -o build/tinfgzip.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/tinflate.c -o build/tinflate.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c uzlib/src/tinfzlib.c -o build/tinfzlib.o
|
||||
# UZLIB END
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c compression.c -o build/compression.o
|
||||
@$(CC) $(CC_FlAGS) -c mz100_aon_ram.c -o build/mz100_aon_ram.o
|
||||
@$(CC) $(CC_FlAGS) -c printf.c -o build/printf.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c zigbee.c -o build/zigbee.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c ccm.c -o build/ccm.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c chars.c -o build/chars.o
|
||||
@@ -61,10 +59,10 @@ compile:
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c timer.c -o build/timer.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c util.c -o build/util.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c gpio.c -o build/gpio.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c nfc.c -o build/nfc.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c epd.c -o build/epd.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c userinterface.c -o build/userinterface.o
|
||||
@$(CC) $(CC_FlAGS) $(CC_WARNING_FLAGS) -c main.c -o build/main.o
|
||||
@$(CC) $(CC_END_FLAGS) $(CC_WARNING_FLAGS) build/main.o build/adler32.o build/crc32.o build/defl_static.o build/genlz77.o build/tinfgzip.o build/tinflate.o build/tinfzlib.o build/compression.o build/zigbee.o build/ccm.o build/chars.o build/drawing.o build/powermgt.o build/syncedproto.o build/comms.o build/settings.o build/timer.o build/util.o build/gpio.o build/nfc.o build/epd.o build/mz100_sleep.o build/core_cm3.o build/mz100_ssp.o build/mz100_wdt.o build/mz100_gpio.o build/mz100_driver.o build/mz100_adc.o build/mz100_flash.o build/mz100_clock.o build/mz100_rtc.o build/mz100_pinmux.o build/mz100_pmu.o build/mz100_qspi.o build/mz100_aes.o build/mz100_gpt.o build/mz100_uart.o build/startup.o -o main.axf
|
||||
@$(CC) $(CC_END_FLAGS) $(CC_WARNING_FLAGS) build/main.o build/userinterface.o build/printf.o build/mz100_aon_ram.o build/zigbee.o build/chars.o build/drawing.o build/powermgt.o build/syncedproto.o build/comms.o build/settings.o build/timer.o build/util.o build/gpio.o build/epd.o build/mz100_sleep.o build/core_cm3.o build/mz100_ssp.o build/mz100_wdt.o build/mz100_gpio.o build/mz100_driver.o build/mz100_adc.o build/mz100_flash.o build/mz100_clock.o build/mz100_rtc.o build/mz100_pinmux.o build/mz100_pmu.o build/mz100_qspi.o build/mz100_aes.o build/mz100_gpt.o build/mz100_uart.o build/startup.o -o main.axf
|
||||
@$(OBJCOPY) -v -O binary main.axf main.bin
|
||||
|
||||
clean:
|
||||
@@ -83,4 +81,4 @@ flash_dump:
|
||||
@$(MZ_FLASHER) $(COMPORT) read dump.bin
|
||||
|
||||
create_ota_img:
|
||||
@$(MZ_FLASHER) img main.bin UPDT0028.BIN
|
||||
@$(MZ_FLASHER) img main.bin UPDT0028.BIN
|
||||
|
||||
@@ -1,96 +1,32 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "comms.h"
|
||||
#include "proto.h"
|
||||
|
||||
#include <stdint.h>
|
||||
//#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccm.h"
|
||||
#include "proto.h"
|
||||
|
||||
extern uint8_t Zigbee_tx_buffer(uint8_t tx_buffer[], int len);
|
||||
|
||||
static uint8_t packet[128];
|
||||
static uint8_t mSeq = 0;
|
||||
uint8_t mLastLqi = 0;
|
||||
int8_t mLastRSSI = 0;
|
||||
|
||||
uint8_t commsGetLastPacketLQI(void)
|
||||
{
|
||||
return mLastLqi;
|
||||
uint8_t commsGetLastPacketLQI(void) {
|
||||
return mLastLqi;
|
||||
}
|
||||
|
||||
int8_t commsGetLastPacketRSSI(void)
|
||||
{
|
||||
return mLastRSSI;
|
||||
int8_t commsGetLastPacketRSSI(void) {
|
||||
return mLastRSSI;
|
||||
}
|
||||
|
||||
static inline void __attribute__((always_inline)) macCopy(uint8_t *restrict dst, const uint8_t *restrict src)
|
||||
{
|
||||
((uint32_t *)dst)[0] = ((const uint32_t *)src)[0];
|
||||
((uint32_t *)dst)[1] = ((const uint32_t *)src)[1];
|
||||
static inline void __attribute__((always_inline)) macCopy(uint8_t *restrict dst, const uint8_t *restrict src) {
|
||||
((uint32_t *)dst)[0] = ((const uint32_t *)src)[0];
|
||||
((uint32_t *)dst)[1] = ((const uint32_t *)src)[1];
|
||||
}
|
||||
|
||||
static inline bool __attribute__((always_inline)) macIsEq(const uint8_t *restrict dst, const uint8_t *restrict src)
|
||||
{
|
||||
return ((uint32_t *)dst)[0] == ((const uint32_t *)src)[0] && ((uint32_t *)dst)[1] == ((const uint32_t *)src)[1];
|
||||
}
|
||||
|
||||
bool commsTx(struct CommsInfo *info, bool bcast, const void *packet_in, uint32_t len)
|
||||
{
|
||||
uint8_t nonce[AES_CCM_NONCE_SIZE] = {};
|
||||
struct MacFrameNormal *mfn;
|
||||
struct MacFrameBcast *mfb;
|
||||
uint32_t hdrSz;
|
||||
char *payload;
|
||||
static const struct MacFcs normalFcs = {
|
||||
.frameType = FRAME_TYPE_DATA,
|
||||
.panIdCompressed = 1,
|
||||
.destAddrType = ADDR_MODE_LONG,
|
||||
.srcAddrType = ADDR_MODE_LONG,
|
||||
};
|
||||
static const struct MacFcs broadcastFcs = {
|
||||
.frameType = FRAME_TYPE_DATA,
|
||||
.destAddrType = ADDR_MODE_SHORT,
|
||||
.srcAddrType = ADDR_MODE_LONG,
|
||||
};
|
||||
|
||||
if (len > COMMS_MAX_PACKET_SZ)
|
||||
return false;
|
||||
|
||||
if (bcast)
|
||||
{
|
||||
mfb = (struct MacFrameBcast *)packet;
|
||||
hdrSz = sizeof(struct MacFrameBcast);
|
||||
payload = (char *)(mfb + 1);
|
||||
mfb->fcs = broadcastFcs;
|
||||
mfb->seq = mSeq++;
|
||||
mfb->dstPan = 0xffff;
|
||||
mfb->dstAddr = 0xffff;
|
||||
mfb->srcPan = PROTO_PAN_ID;
|
||||
macCopy(mfb->src, info->myMac);
|
||||
}
|
||||
else
|
||||
{
|
||||
mfn = (struct MacFrameNormal *)packet;
|
||||
hdrSz = sizeof(struct MacFrameNormal);
|
||||
payload = (char *)(mfn + 1);
|
||||
mfn->fcs = normalFcs;
|
||||
mfn->seq = mSeq++;
|
||||
mfn->pan = PROTO_PAN_ID;
|
||||
macCopy(mfn->dst, info->masterMac);
|
||||
macCopy(mfn->src, info->myMac);
|
||||
}
|
||||
|
||||
*(uint32_t *)nonce = (*info->nextIV)++;
|
||||
macCopy(nonce + sizeof(uint32_t), info->myMac);
|
||||
memcpy(payload, packet_in, len);
|
||||
|
||||
aesCcmEnc((void *)packet, (void *)packet, hdrSz, len, info->encrKey, nonce);
|
||||
*(uint32_t *)(payload + len + AES_CCM_MIC_SIZE) = *(uint32_t *)nonce; // send nonce
|
||||
|
||||
len += hdrSz;
|
||||
len += AES_CCM_MIC_SIZE;
|
||||
len += sizeof(uint32_t);
|
||||
|
||||
return !Zigbee_tx_buffer((uint8_t *)&packet, len);
|
||||
static inline bool __attribute__((always_inline)) macIsEq(const uint8_t *restrict dst, const uint8_t *restrict src) {
|
||||
return ((uint32_t *)dst)[0] == ((const uint32_t *)src)[0] && ((uint32_t *)dst)[1] == ((const uint32_t *)src)[1];
|
||||
}
|
||||
|
||||
extern volatile uint8_t rx_buffer[0x400];
|
||||
@@ -98,94 +34,16 @@ extern volatile uint8_t new_rx;
|
||||
extern volatile uint8_t new_rssi;
|
||||
extern volatile int rx_len;
|
||||
|
||||
int32_t __attribute__((noinline)) commsRx(struct CommsInfo *info, void *data, uint8_t *fromMacP)
|
||||
{
|
||||
uint8_t *buf = packet, nonce[13] = {}, fromMac[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint32_t len, minNeedLen, hdrLen = 0;
|
||||
struct MacFrameFromMaster *mfm;
|
||||
struct MacFrameNormal *mfn;
|
||||
|
||||
// sort out how many bytes minimum are a valid packet
|
||||
minNeedLen = sizeof(struct MacFrameFromMaster); // mac header
|
||||
minNeedLen += sizeof(uint8_t); // packet type
|
||||
minNeedLen += AES_CCM_MIC_SIZE; // MIC
|
||||
minNeedLen += sizeof(uint32_t); // nonce counter
|
||||
minNeedLen += 2 * sizeof(uint8_t); // RSSI/LQI
|
||||
|
||||
if (!new_rx)
|
||||
return COMMS_RX_ERR_NO_PACKETS;
|
||||
|
||||
// some basic checks
|
||||
mfm = (struct MacFrameFromMaster *)rx_buffer;
|
||||
if (rx_len >= sizeof(packet) || rx_len < minNeedLen || mfm->fcs.frameType != FRAME_TYPE_DATA ||
|
||||
mfm->fcs.secure || mfm->fcs.frameVer || mfm->fcs.destAddrType != ADDR_MODE_LONG || !mfm->fcs.panIdCompressed ||
|
||||
(mfm->fcs.srcAddrType != ADDR_MODE_LONG && mfm->fcs.srcAddrType != ADDR_MODE_SHORT) ||
|
||||
mfm->pan != PROTO_PAN_ID || !macIsEq(mfm->dst, info->myMac))
|
||||
{
|
||||
new_rx = 0;
|
||||
return COMMS_RX_ERR_INVALID_PACKET;
|
||||
}
|
||||
|
||||
// copy out and release buffer
|
||||
memcpy(buf, &rx_buffer, len = rx_len - 2 * sizeof(uint8_t));
|
||||
mLastLqi = rx_buffer[len + 0];
|
||||
mLastRSSI = rx_buffer[len + 1];
|
||||
|
||||
mfm = (struct MacFrameFromMaster *)buf;
|
||||
mfn = (struct MacFrameNormal *)buf;
|
||||
new_rx = 0;
|
||||
|
||||
// sort out header len, copy mac into nonce
|
||||
if (mfm->fcs.srcAddrType == ADDR_MODE_LONG)
|
||||
{
|
||||
|
||||
macCopy(fromMac, mfn->src);
|
||||
hdrLen = sizeof(struct MacFrameNormal);
|
||||
|
||||
// re-verify needed length
|
||||
minNeedLen -= sizeof(struct MacFrameFromMaster);
|
||||
minNeedLen += sizeof(struct MacFrameNormal);
|
||||
|
||||
if (rx_len < minNeedLen)
|
||||
return COMMS_RX_ERR_INVALID_PACKET;
|
||||
}
|
||||
else if (mfm->fcs.srcAddrType == ADDR_MODE_SHORT)
|
||||
{
|
||||
|
||||
macCopy(fromMac, info->masterMac);
|
||||
hdrLen = sizeof(struct MacFrameFromMaster);
|
||||
}
|
||||
|
||||
// sort out the nonce
|
||||
macCopy(nonce + sizeof(uint32_t), fromMac);
|
||||
*(uint32_t *)nonce = *(uint32_t *)(buf + len - sizeof(uint32_t));
|
||||
|
||||
// decrypt and auth
|
||||
len -= hdrLen + AES_CCM_MIC_SIZE + sizeof(uint32_t);
|
||||
|
||||
if (!aesCcmDec(buf, buf, hdrLen, len, info->encrKey, nonce))
|
||||
return COMMS_RX_ERR_MIC_FAIL;
|
||||
|
||||
if (fromMacP)
|
||||
macCopy(fromMacP, fromMac);
|
||||
|
||||
memcpy(data, buf + hdrLen, len);
|
||||
|
||||
return len;
|
||||
int32_t __attribute__((noinline)) commsRxUnenc(void *data) {
|
||||
if (!new_rx)
|
||||
return COMMS_RX_ERR_NO_PACKETS;
|
||||
memcpy(data, (uint8_t*)&rx_buffer, rx_len);
|
||||
mLastLqi = 255 - new_rssi;
|
||||
mLastRSSI = new_rssi;
|
||||
new_rx = 0;
|
||||
return rx_len;
|
||||
}
|
||||
|
||||
int32_t __attribute__((noinline)) commsRxUnenc(void *data)
|
||||
{
|
||||
if (!new_rx)
|
||||
return COMMS_RX_ERR_NO_PACKETS;
|
||||
memcpy(data, &rx_buffer, rx_len);
|
||||
mLastLqi = 255 - new_rssi;
|
||||
mLastRSSI = new_rssi;
|
||||
new_rx = 0;
|
||||
return rx_len;
|
||||
}
|
||||
|
||||
void commsTxNoCpy(uint8_t *packetp)
|
||||
{
|
||||
Zigbee_tx_buffer((uint8_t *)&packetp[1], (packetp[0] - 2));
|
||||
void commsTxNoCpy(uint8_t *packetp) {
|
||||
Zigbee_tx_buffer((uint8_t *)&packetp[1], (packetp[0] - 2));
|
||||
}
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
#include <stdint.h>
|
||||
#include "ccm.h"
|
||||
|
||||
struct CommsInfo {
|
||||
const uint8_t *myMac;
|
||||
const uint8_t *masterMac;
|
||||
const void *encrKey;
|
||||
uint32_t *nextIV;
|
||||
};
|
||||
extern uint8_t mLastLqi;
|
||||
extern int8_t mLastRSSI;
|
||||
|
||||
@@ -23,8 +17,6 @@ extern int8_t mLastRSSI;
|
||||
|
||||
#define COMMS_MAX_PACKET_SZ (127 /* max phy len */ - 21 /* max mac frame with panID compression */ - 2 /* FCS len */ - AES_CCM_MIC_SIZE - COMMS_IV_SIZE)
|
||||
|
||||
bool commsTx(struct CommsInfo *info, bool bcast, const void *packet, uint32_t len);
|
||||
int32_t commsRx(struct CommsInfo *info, void *data, uint8_t *fromMac); //returns length or COMMS_RX_ERR_*
|
||||
|
||||
uint8_t commsGetLastPacketLQI(void);
|
||||
int8_t commsGetLastPacketRSSI(void);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
#include "compression.h"
|
||||
#include "uzlib/src/uzlib.h"
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "uzlib/src/uzlib.h"
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdbool.h>
|
||||
#include "printf.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "eeprom.h"
|
||||
@@ -11,366 +12,22 @@
|
||||
#include "util.h"
|
||||
#include "epd.h"
|
||||
|
||||
#define COMPRESSION_BITPACKED_3x5_to_7 0x62700357 // 3 pixels of 5 possible colors in 7 bits
|
||||
#define COMPRESSION_BITPACKED_5x3_to_8 0x62700538 // 5 pixels of 3 possible colors in 8 bits
|
||||
#define COMPRESSION_BITPACKED_3x6_to_8 0x62700368 // 3 pixels of 6 possible colors in 8 bits
|
||||
|
||||
struct BitmapFileHeader
|
||||
{
|
||||
uint8_t sig[2];
|
||||
uint32_t fileSz;
|
||||
uint8_t rfu[4];
|
||||
uint32_t dataOfst;
|
||||
uint32_t headerSz; // 40
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
uint16_t colorplanes; // must be one
|
||||
uint16_t bpp;
|
||||
uint32_t compression;
|
||||
uint32_t dataLen; // may be 0
|
||||
uint32_t pixelsPerMeterX;
|
||||
uint32_t pixelsPerMeterY;
|
||||
uint32_t numColors; // if zero, assume 2^bpp
|
||||
uint32_t numImportantColors;
|
||||
};
|
||||
|
||||
struct BitmapClutEntry
|
||||
{
|
||||
uint8_t b, g, r, x;
|
||||
};
|
||||
|
||||
struct BitmapDrawInfo
|
||||
{
|
||||
// dimensions
|
||||
uint16_t w, h, effectiveW, effectiveH, stride /* 0 -> 1, 5 - >7, 255 -> 256 */;
|
||||
uint8_t numColorsM1;
|
||||
|
||||
// data start
|
||||
uint32_t dataAddr;
|
||||
|
||||
// compression state
|
||||
uint8_t packetPixelDivVal;
|
||||
uint8_t packetNumPixels;
|
||||
uint8_t packetBitSz;
|
||||
uint8_t packetBitMask; // derived from the above
|
||||
|
||||
// flags
|
||||
uint8_t bpp : 4;
|
||||
uint8_t bottomUp : 1;
|
||||
};
|
||||
|
||||
uint8_t mPassNo = 0;
|
||||
|
||||
static const uint8_t mColorMap[][6] = {
|
||||
// colors are: B, DG, G, LG, W, R
|
||||
// phase 0 (LUTS: B:W:R:G, purpose: BWR, prepare greys)
|
||||
{1, 1, 1, 1, 0, 0}, // lo plane (B)
|
||||
|
||||
{0, 0, 0, 0, 0, 1} // hi plane (R)
|
||||
};
|
||||
|
||||
static uint8_t mClutMap[256];
|
||||
static uint8_t mClutMapRed[256];
|
||||
static struct BitmapDrawInfo mDrawInfo;
|
||||
|
||||
static uint32_t drawPrvParseHeader(uint32_t addr) // return clut addr or zero on error
|
||||
{
|
||||
/*struct BitmapFileHeader bmph;
|
||||
uint16_t packetsPerRow;
|
||||
|
||||
addr += sizeof(struct EepromImageHeader);
|
||||
eepromRead(addr, &bmph, sizeof(bmph));
|
||||
|
||||
if (bmph.sig[0] != 'B' || bmph.sig[1] != 'M')
|
||||
goto fail;
|
||||
|
||||
if (bmph.colorplanes != 1)
|
||||
goto fail;
|
||||
|
||||
if ((&bmph.headerSz - 40)) // < 40
|
||||
goto fail;
|
||||
|
||||
if (bmph.bpp > 8)
|
||||
goto fail;
|
||||
|
||||
mDrawInfo.bpp = bmph.bpp;
|
||||
|
||||
if (!(&bmph.headerSz - 257)) // >= 257
|
||||
goto fail;
|
||||
|
||||
if ((&bmph.numColors))
|
||||
mDrawInfo.numColorsM1 = (uint8_t)bmph.numColors - (uint8_t)1;
|
||||
else
|
||||
mDrawInfo.numColorsM1 = (uint8_t)((uint8_t)1 << (uint8_t)mDrawInfo.bpp) - (uint8_t)1;
|
||||
|
||||
if (!(&bmph.height))
|
||||
goto fail;
|
||||
|
||||
if ((&bmph.width - 1) || !(&bmph.width - 0xffff))
|
||||
goto fail;
|
||||
mDrawInfo.w = bmph.width;
|
||||
|
||||
if ((&bmph.height) < 0)
|
||||
{
|
||||
if ((&bmph.height + 0xffff)) // carries if val too negative
|
||||
goto fail;
|
||||
mDrawInfo.h = -bmph.height;
|
||||
mDrawInfo.bottomUp = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(&bmph.headerSz - 0xffff)) // no carry if val too big
|
||||
goto fail;
|
||||
mDrawInfo.h = bmph.height;
|
||||
mDrawInfo.bottomUp = true;
|
||||
}
|
||||
|
||||
if (bmph.compression)
|
||||
{
|
||||
printf("compression is not supported ;(");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mDrawInfo.packetPixelDivVal = 0;
|
||||
mDrawInfo.packetNumPixels = 1;
|
||||
if (mDrawInfo.bpp > 1)
|
||||
{
|
||||
mDrawInfo.packetBitSz = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDrawInfo.packetBitSz = 1; // mDrawInfo.bpp;
|
||||
}
|
||||
|
||||
// mDrawInfo.stride = mathPrvDiv32x8(mathPrvMul16x8((mDrawInfo.w + mDrawInfo.packetNumPixels - 1), mDrawInfo.packetBitSz) + 31, 32) * 4UL;
|
||||
// mDrawInfo.packetBitMask = (uint8_t)(((uint8_t)1) << (uint8_t)mDrawInfo.packetBitSz) - (uint8_t)1;
|
||||
|
||||
packetsPerRow = (mDrawInfo.w + mDrawInfo.packetNumPixels - 1) / (mDrawInfo.packetNumPixels);
|
||||
mDrawInfo.stride = (((packetsPerRow * mDrawInfo.packetBitSz) + 31) / 32) * 4UL;
|
||||
mDrawInfo.packetBitMask = (uint8_t)(((uint8_t)1) << (uint8_t)mDrawInfo.packetBitSz) - (uint8_t)1;
|
||||
|
||||
// calc effective size
|
||||
mDrawInfo.effectiveH = (mDrawInfo.h > SCREEN_HEIGHT) ? SCREEN_HEIGHT : mDrawInfo.h;
|
||||
mDrawInfo.effectiveW = (mDrawInfo.w > SCREEN_WIDTH) ? SCREEN_WIDTH : mDrawInfo.w;
|
||||
|
||||
// calc addrs
|
||||
mDrawInfo.dataAddr = addr + bmph.dataOfst;
|
||||
return addr + bmph.dataOfst - sizeof(struct BitmapClutEntry) * (1 + mDrawInfo.numColorsM1);
|
||||
|
||||
fail:
|
||||
printf("Tried to parse the bmp header, didn't work...");*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drawPrvLoadAndMapClut(uint32_t clutAddr)
|
||||
{
|
||||
/*struct BitmapClutEntry clut;
|
||||
uint8_t i;
|
||||
|
||||
// convert clut to our understanding of color
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
uint8_t entry;
|
||||
|
||||
eepromRead(clutAddr, &clut, sizeof(clut));
|
||||
clutAddr += sizeof(struct BitmapClutEntry);
|
||||
|
||||
if (SCREEN_EXTRA_COLOR_INDEX >= 0 && clut.r == 0xff && (clut.g == 0xff || clut.g == 0) && clut.b == 0) // yellow/red
|
||||
entry = SCREEN_EXTRA_COLOR_INDEX;
|
||||
else
|
||||
{
|
||||
uint16_t intensity = 0;
|
||||
|
||||
intensity += (0x37 * clut.r);
|
||||
intensity += (0xB7 * clut.g);
|
||||
intensity += (0x12 * clut.b);
|
||||
// adds up to 0xff00 -> fix it
|
||||
intensity += (uint8_t)(intensity >> 8);
|
||||
|
||||
entry = (intensity * SCREEN_NUM_GREYS) >> 16;
|
||||
entry += SCREEN_FIRST_GREY_IDX;
|
||||
}
|
||||
// printf("mapped clut %u (%d %d %d) -> %d\n", i, clut.r, clut.g, clut.b, entry);
|
||||
mClutMap[i] = entry;
|
||||
} while (i++ != mDrawInfo.numColorsM1);
|
||||
|
||||
// replicate clut down if not a full 256-entry clut
|
||||
if (mDrawInfo.bpp != 8)
|
||||
{
|
||||
uint8_t num = (uint8_t)((uint8_t)1 << (uint8_t)mDrawInfo.bpp);
|
||||
|
||||
// we can use the fact that our memcpy always copies forward
|
||||
memcpy(mClutMap + num, mClutMap, (uint8_t)256 - (uint8_t)num);
|
||||
}*/
|
||||
}
|
||||
|
||||
static void drawPrvDecodeImageOnce(void)
|
||||
{
|
||||
/*uint8_t rowBuf[SCREEN_WIDTH];
|
||||
uint16_t er, c;
|
||||
if (mDrawInfo.bottomUp)
|
||||
er = mDrawInfo.effectiveH - 1;
|
||||
else
|
||||
er = 0;
|
||||
while (1)
|
||||
{ // we account differently for loop gets compiled worse
|
||||
uint8_t inIdx = 0, bitpoolInUsed = 0, bitpoolIn = 0;
|
||||
uint16_t nBytesOut = 0;
|
||||
|
||||
#if SCREEN_TX_BPP == 4
|
||||
uint8_t txPrev = 0;
|
||||
bool emit = false;
|
||||
#else
|
||||
uint8_t bitpoolOutUsedUsed = 0;
|
||||
uint16_t bitpoolOut = 0;
|
||||
#endif
|
||||
// get a row
|
||||
epdDeselect();
|
||||
eepromRead((er * mDrawInfo.stride) + mDrawInfo.dataAddr, rowBuf, mDrawInfo.stride);
|
||||
epdSelect();
|
||||
// convert to our format
|
||||
c = mDrawInfo.effectiveW;
|
||||
do
|
||||
{
|
||||
// uartTx('.');
|
||||
uint8_t packet, packetIdx, packetMembers = mDrawInfo.packetNumPixels;
|
||||
|
||||
if (bitpoolInUsed >= mDrawInfo.packetBitSz)
|
||||
{
|
||||
bitpoolInUsed -= mDrawInfo.packetBitSz;
|
||||
packet = bitpoolIn >> bitpoolInUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t packetBitSz = mDrawInfo.packetBitSz;
|
||||
uint8_t t = rowBuf[inIdx++];
|
||||
|
||||
packet = (bitpoolIn << (packetBitSz - bitpoolInUsed)) | (t >> (8 - (packetBitSz - bitpoolInUsed)));
|
||||
bitpoolInUsed += 8 - packetBitSz;
|
||||
|
||||
bitpoolIn = t;
|
||||
}
|
||||
packet &= mDrawInfo.packetBitMask;
|
||||
|
||||
// val is now a packet - unpack it
|
||||
if (packetMembers > c)
|
||||
packetMembers = c;
|
||||
|
||||
for (packetIdx = 0; packetIdx < packetMembers; packetIdx++)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
// extract
|
||||
if (mDrawInfo.packetPixelDivVal)
|
||||
{
|
||||
val = packet % mDrawInfo.packetPixelDivVal;
|
||||
packet /= mDrawInfo.packetPixelDivVal;
|
||||
}
|
||||
else
|
||||
val = packet;
|
||||
|
||||
// map
|
||||
val = mClutMap[val];
|
||||
|
||||
// get bits out
|
||||
#if SCREEN_TX_BPP == 4
|
||||
|
||||
if (emit)
|
||||
{
|
||||
emit = false;
|
||||
ByteDecode(txPrev | val);
|
||||
nBytesOut++;
|
||||
txPrev = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
emit = true;
|
||||
txPrev = val << 4;
|
||||
}
|
||||
|
||||
#else
|
||||
bitpoolOut <<= SCREEN_TX_BPP;
|
||||
bitpoolOut |= val;
|
||||
bitpoolOutUsedUsed += SCREEN_TX_BPP;
|
||||
if (bitpoolOutUsedUsed >= 8)
|
||||
{
|
||||
ByteDecode(bitpoolOut >> (bitpoolOutUsedUsed -= 8));
|
||||
bitpoolOut &= (1 << bitpoolOutUsedUsed) - 1;
|
||||
nBytesOut++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
c -= packetMembers;
|
||||
} while (c);
|
||||
|
||||
#if SCREEN_TX_BPP == 4
|
||||
|
||||
if (emit)
|
||||
{
|
||||
ByteDecode(txPrev);
|
||||
nBytesOut++;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (bitpoolOutUsedUsed)
|
||||
{
|
||||
ByteDecode(bitpoolOut);
|
||||
nBytesOut++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// if we did not produce enough bytes, do so
|
||||
nBytesOut = ((long)SCREEN_WIDTH * SCREEN_TX_BPP + 7) / 8 - nBytesOut;
|
||||
while (nBytesOut--)
|
||||
ByteDecode(SCREEN_BYTE_FILL);
|
||||
|
||||
// update row
|
||||
if (mDrawInfo.bottomUp)
|
||||
{
|
||||
if (er)
|
||||
er--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
er++;
|
||||
if (er == mDrawInfo.effectiveH)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fill the rest of the screen
|
||||
for (er = mDrawInfo.effectiveH - SCREEN_HEIGHT; er; er--)
|
||||
{
|
||||
for (c = ((long)SCREEN_WIDTH * SCREEN_TX_BPP + 7) / 8; c; c--)
|
||||
{
|
||||
ByteDecode(SCREEN_BYTE_FILL);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
static uint8_t prev, step = 0;
|
||||
|
||||
void ByteDecode(uint8_t byte)
|
||||
{
|
||||
/*prev <<= 2;
|
||||
prev |= (mColorMap[mPassNo][byte >> 4] << 1) | mColorMap[mPassNo][byte & 0x0f];
|
||||
if (++step == 4)
|
||||
{
|
||||
step = 0;
|
||||
Display_Write_byte(prev);
|
||||
}*/
|
||||
}
|
||||
|
||||
void drawImageAtAddress(uint32_t addr, uint8_t lut)
|
||||
{
|
||||
struct EepromImageHeader *eih = (struct EepromImageHeader *)mClutMap;
|
||||
eepromRead(addr, mClutMap, sizeof(struct EepromImageHeader));
|
||||
uint8_t prevVal = 0;
|
||||
switch (eih->dataType)
|
||||
{
|
||||
case DATATYPE_IMG_RAW_1BPP:
|
||||
@@ -430,34 +87,6 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut)
|
||||
display_send_stop();
|
||||
epd_refresh_and_sleep();
|
||||
break;
|
||||
case DATATYPE_IMG_BMP:;
|
||||
uint32_t clutAddr;
|
||||
printf("sending BMP to EPD - ");
|
||||
/*clutAddr = drawPrvParseHeader(addr);
|
||||
if (!clutAddr)
|
||||
return;
|
||||
drawPrvLoadAndMapClut(clutAddr);
|
||||
|
||||
epdSetup();
|
||||
if (lut)
|
||||
selectLUT(lut);
|
||||
mPassNo = 0;
|
||||
beginFullscreenImage();
|
||||
beginWriteFramebuffer(EPD_COLOR_BLACK);
|
||||
prev = 0;
|
||||
step = 0;
|
||||
drawPrvDecodeImageOnce();
|
||||
endWriteFramebuffer();
|
||||
mPassNo++;
|
||||
beginFullscreenImage();
|
||||
beginWriteFramebuffer(EPD_COLOR_RED);
|
||||
prev = 0;
|
||||
step = 0;
|
||||
drawPrvDecodeImageOnce();
|
||||
endWriteFramebuffer();*/
|
||||
|
||||
printf(" complete.\n");
|
||||
break;
|
||||
default: // prevent drawing from an unknown file image type
|
||||
printf("Image with type 0x%02X was requested, but we don't know what to do with that currently...\n", eih->dataType);
|
||||
return;
|
||||
|
||||
1110
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/epd.c
Normal file → Executable file
1110
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/epd.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DISPLAY_WIDTH (640)
|
||||
#define DISPLAY_HEIGHT (384)
|
||||
@@ -16,6 +17,18 @@
|
||||
#define FORE_COLOR_2 4
|
||||
#define FORE_COLOR_3 0
|
||||
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_FAST 3
|
||||
|
||||
#define EPD_DIRECTION_X false
|
||||
#define EPD_DIRECTION_Y true
|
||||
#define EPD_SIZE_SINGLE false
|
||||
#define EPD_SIZE_DOUBLE true
|
||||
#define EPD_COLOR_RED true
|
||||
#define EPD_COLOR_BLACK false
|
||||
|
||||
void init_GPIO_EPD();
|
||||
void display_send_buffer();
|
||||
|
||||
@@ -25,5 +38,16 @@ void display_tx_byte(uint8_t data);
|
||||
void display_send_start(uint8_t inverted);
|
||||
void display_send_stop();
|
||||
|
||||
void setDisplayWindow(uint16_t x, uint16_t y, uint16_t xe, uint16_t ye);
|
||||
|
||||
void init_epd();
|
||||
void refresh_epd();
|
||||
void refresh_epd();
|
||||
|
||||
void lutBeginTX(uint8_t reg);
|
||||
void lutEndTX();
|
||||
|
||||
void epd_pin_enable(int a1);
|
||||
|
||||
|
||||
void fillWindow(uint16_t x, uint16_t y, uint16_t xe, uint16_t ye, uint8_t color);
|
||||
void epdPrintf(uint16_t x, uint16_t y, bool color, const char* c, ...);
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
#include "nfc.h"
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "mz100_pinmux.h"
|
||||
#include "mz100_gpio.h"
|
||||
#include "util.h"
|
||||
#include "printf.h"
|
||||
|
||||
|
||||
void NVIC_some_IRQ1(unsigned int a1)
|
||||
{
|
||||
|
||||
898
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/main.c
Normal file → Executable file
898
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/main.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -4,8 +4,9 @@ GROUP(-lgcc -lc -lnosys)
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x100000, LENGTH = 80k
|
||||
RAM (rwx) : ORIGIN = 0x20100000 + 80k, LENGTH = 160k - 80k - 16k
|
||||
RAM1 (rwx) : ORIGIN = 0x20124000 , LENGTH = 16k
|
||||
RAM (rwx) : ORIGIN = 0x20100000 + 80k, LENGTH = 160k - 80k - 2k
|
||||
AONSHADOW (rwx) : ORIGIN = 0x20128000 - 2k, LENGTH = 2k
|
||||
AON (rwx) : ORIGIN = 0x20130000 , LENGTH = 4k
|
||||
}
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
@@ -123,6 +124,27 @@ SECTIONS
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
|
||||
.aon (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_start_of_aon = .;
|
||||
*(.aon)
|
||||
*(.aon.*)
|
||||
. = ALIGN(4);
|
||||
_end_of_aon = .;
|
||||
|
||||
} > AON
|
||||
.aonshadow (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_start_of_aonshadow = .;
|
||||
*(.aonshadow)
|
||||
*(.aonshadow.*)
|
||||
. = ALIGN(4);
|
||||
_end_of_aonshadow = .;
|
||||
|
||||
} > AONSHADOW
|
||||
}
|
||||
|
||||
|
||||
|
||||
43
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/mz100_aon_ram.c
Normal file
43
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/mz100_aon_ram.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "mz100_aon_ram.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
__attribute__((section(".aon"))) volatile uint32_t aonChecksum;
|
||||
__attribute__((section(".aon"))) volatile uint8_t aonShadow[AONSHADOW_SIZE];
|
||||
|
||||
bool aonRamValid = false;
|
||||
|
||||
void clearAonRam() {
|
||||
memset((void *)0x130000, 0, 4096);
|
||||
}
|
||||
|
||||
bool loadValidateAonRam() {
|
||||
uint32_t testchecksum = aonChecksum;
|
||||
aonChecksum = 0x00000000;
|
||||
uint32_t checksum = 0xABBA5FF5;
|
||||
for (uint32_t c = 0x130000; c < 0x131000; c += 4) {
|
||||
checksum += *(uint32_t *)c;
|
||||
}
|
||||
if (checksum == testchecksum) {
|
||||
// immediately invalidate the checksum; if we reboot, we want a clean reboot
|
||||
aonChecksum = 0x5445A00A;
|
||||
memcpy((void *)(0x128000 - AONSHADOW_SIZE), (uint8_t*)aonShadow, AONSHADOW_SIZE);
|
||||
return true;
|
||||
} else {
|
||||
clearAonRam();
|
||||
memset((void *)(0x128000 - AONSHADOW_SIZE), 0, AONSHADOW_SIZE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void saveAonRam() {
|
||||
memcpy((uint8_t*)aonShadow, (void *)(0x128000 - AONSHADOW_SIZE), AONSHADOW_SIZE);
|
||||
aonChecksum = 0x00000000;
|
||||
uint32_t checksum = 0xABBA5FF5;
|
||||
for (uint32_t c = 0x130000; c < 0x131000; c += 4) {
|
||||
checksum += *(uint32_t *)c;
|
||||
}
|
||||
aonChecksum = checksum;
|
||||
}
|
||||
11
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/mz100_aon_ram.h
Normal file
11
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/mz100_aon_ram.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
|
||||
#define AONSHADOW_SIZE 2048
|
||||
|
||||
extern bool aonRamValid;
|
||||
|
||||
bool loadValidateAonRam();
|
||||
void saveAonRam();
|
||||
void clearAonRam();
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "core_cm3.h"
|
||||
#include "mz100_gpio.h"
|
||||
@@ -14,6 +14,9 @@
|
||||
#include "gpio.h"
|
||||
#include "main.h"
|
||||
#include "proto.h"
|
||||
#include "printf.h"
|
||||
|
||||
extern void saveAonRam();
|
||||
|
||||
void AON_level_VDD(int state)
|
||||
{
|
||||
@@ -90,9 +93,11 @@ extern struct AvailDataInfo curDataInfo; // last 'AvailDataInfo' we received fro
|
||||
extern bool requestPartialBlock; // if we should ask the AP to get this block from the host or not
|
||||
void sleep_with_with_wakeup(uint32_t sleep_time_ms)
|
||||
{
|
||||
memcpy((uint8_t *)&(*(volatile unsigned int *)0x130500), (uint8_t *)&curBlock, sizeof(struct blockRequest));
|
||||
memcpy((uint8_t *)&(*(volatile unsigned int *)0x130600), (uint8_t *)&curDataInfo, sizeof(struct AvailDataInfo));
|
||||
printf("sleep: %u\r\n", sleep_time_ms);
|
||||
saveAonRam();
|
||||
//memcpy((uint8_t *)&(*(volatile unsigned int *)0x130500), (uint8_t *)&curBlock, sizeof(struct blockRequest));
|
||||
//memcpy((uint8_t *)&(*(volatile unsigned int *)0x130600), (uint8_t *)&curDataInfo, sizeof(struct AvailDataInfo));
|
||||
//sleep_time_ms = 10000;
|
||||
printf("sleep! %u\n", sleep_time_ms);
|
||||
uint32_t sleep_time_ms_1;
|
||||
AON_level_VDD(7);
|
||||
AON_level_VAA(0);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "core_cm3.h"
|
||||
#include "mz100_gpio.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "nfc.h"
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "timer.h"
|
||||
#include "epd.h"
|
||||
#include "proto.h"
|
||||
#include "printf.h"
|
||||
|
||||
|
||||
#define WHO_AM_I 0x04
|
||||
uint8_t i2c_address = 0xAA;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
143
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/powermgt.c
Normal file → Executable file
143
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/powermgt.c
Normal file → Executable file
@@ -3,64 +3,69 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
// #include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mz100_sleep.h"
|
||||
#include "zigbee.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "screen.h"
|
||||
#include "eeprom.h"
|
||||
#include "main.h"
|
||||
#include "util.h"
|
||||
#include "mz100_sleep.h"
|
||||
#include "printf.h"
|
||||
#include "screen.h"
|
||||
#include "syncedproto.h"
|
||||
#include <stdbool.h>
|
||||
#include "util.h"
|
||||
#include "zigbee.h"
|
||||
|
||||
uint16_t dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
|
||||
uint8_t dataReqAttemptArrayIndex = 0;
|
||||
uint8_t dataReqLastAttempt = 0;
|
||||
uint16_t nextCheckInFromAP = 0;
|
||||
uint8_t wakeUpReason = 0;
|
||||
uint8_t scanAttempts = 0;
|
||||
__attribute__((section(".aonshadow"))) uint16_t dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
|
||||
__attribute__((section(".aonshadow"))) uint8_t dataReqAttemptArrayIndex = 0;
|
||||
__attribute__((section(".aonshadow"))) uint8_t dataReqLastAttempt = 0;
|
||||
__attribute__((section(".aonshadow"))) uint16_t nextCheckInFromAP = 0;
|
||||
__attribute__((section(".aonshadow"))) uint8_t wakeUpReason = 0;
|
||||
__attribute__((section(".aonshadow"))) uint8_t scanAttempts = 0;
|
||||
|
||||
int8_t temperature = 0;
|
||||
uint16_t batteryVoltage = 0;
|
||||
bool lowBattery = false;
|
||||
uint16_t longDataReqCounter = 0;
|
||||
uint16_t voltageCheckCounter = 0;
|
||||
__attribute__((section(".aonshadow"))) int8_t temperature = 0;
|
||||
__attribute__((section(".aonshadow"))) uint16_t batteryVoltage = 0;
|
||||
__attribute__((section(".aonshadow"))) bool lowBattery = false;
|
||||
__attribute__((section(".aonshadow"))) uint16_t longDataReqCounter = 0;
|
||||
__attribute__((section(".aonshadow"))) uint16_t voltageCheckCounter = 0;
|
||||
|
||||
uint8_t capabilities = 0;
|
||||
__attribute__((section(".aonshadow"))) uint8_t capabilities = 0;
|
||||
|
||||
bool spiActive = false;
|
||||
bool uartActive = false;
|
||||
bool eepromActive = false;
|
||||
bool i2cActive = false;
|
||||
extern int8_t adcSampleTemperature(void); // in degrees C
|
||||
|
||||
uint8_t checkButtonOrJig()
|
||||
{
|
||||
extern int8_t adcSampleTemperature(void); // in degrees C
|
||||
|
||||
uint8_t checkButtonOrJig() {
|
||||
return DETECT_P1_0_NOTHING;
|
||||
}
|
||||
|
||||
void setupPortsInitial()
|
||||
{
|
||||
void setupPortsInitial() {
|
||||
}
|
||||
|
||||
void initPowerSaving(const uint16_t initialValue)
|
||||
{
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++)
|
||||
{
|
||||
uint16_t doVoltageReading() {
|
||||
batteryVoltage = (uint16_t)measureBattery();
|
||||
if (batteryVoltage < BATTERY_VOLTAGE_MINIMUM) {
|
||||
lowBattery = true;
|
||||
} else {
|
||||
lowBattery = false;
|
||||
}
|
||||
return batteryVoltage;
|
||||
}
|
||||
|
||||
void initPowerSaving(const uint16_t initialValue) {
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
dataReqAttemptArr[c] = initialValue;
|
||||
}
|
||||
}
|
||||
|
||||
static void configSPI(const bool setup)
|
||||
{
|
||||
|
||||
static void configSPI(const bool setup) {
|
||||
spiActive = setup;
|
||||
}
|
||||
|
||||
static void configUART(const bool setup)
|
||||
{
|
||||
static void configUART(const bool setup) {
|
||||
/* if (setup == uartActive)
|
||||
return;
|
||||
uartActive = setup;
|
||||
@@ -70,69 +75,64 @@ static void configUART(const bool setup)
|
||||
Serial.end();*/
|
||||
}
|
||||
|
||||
static void configEEPROM(const bool setup)
|
||||
{
|
||||
static void configEEPROM(const bool setup) {
|
||||
}
|
||||
|
||||
static void configI2C(const bool setup)
|
||||
{
|
||||
static void configI2C(const bool setup) {
|
||||
}
|
||||
|
||||
void powerUp(const uint8_t parts)
|
||||
{
|
||||
printf("Power up: %d\r\n", parts);
|
||||
if (parts & INIT_RADIO)
|
||||
{
|
||||
void powerUp(const uint8_t parts) {
|
||||
// printf("Power up: %d\r\n", parts);
|
||||
if (parts & INIT_RADIO) {
|
||||
radioInit();
|
||||
// radioRxFilterCfg(mSelfMac, 0x10000, PROTO_PAN_ID);
|
||||
// radioSetTxPower(10);
|
||||
if (currentChannel >= 11 && currentChannel <= 27)
|
||||
{
|
||||
if (currentChannel >= 11 && currentChannel <= 27) {
|
||||
radioSetChannel(currentChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
radioSetChannel(RADIO_FIRST_CHANNEL);
|
||||
}
|
||||
}
|
||||
if (parts & INIT_UART) {
|
||||
configUART(true);
|
||||
}
|
||||
if (parts & INIT_EPD) {
|
||||
configSPI(true);
|
||||
}
|
||||
if (parts & INIT_EEPROM) {
|
||||
configEEPROM(true);
|
||||
}
|
||||
if (parts & INIT_I2C) {
|
||||
configI2C(true);
|
||||
}
|
||||
}
|
||||
|
||||
void powerDown(const uint8_t parts)
|
||||
{
|
||||
printf("Power down: %d\r\n", parts);
|
||||
void powerDown(const uint8_t parts) {
|
||||
// printf("Power down: %d\r\n", parts);
|
||||
}
|
||||
|
||||
void doSleep(const uint32_t t)
|
||||
{
|
||||
void doSleep(const uint32_t t) {
|
||||
printf("Sleeping for: %d ms\r\n", t);
|
||||
// sleepForMs(t);
|
||||
delay(t);
|
||||
}
|
||||
|
||||
uint32_t getNextScanSleep(const bool increment)
|
||||
{
|
||||
if (increment)
|
||||
{
|
||||
uint32_t getNextScanSleep(const bool increment) {
|
||||
if (increment) {
|
||||
if (scanAttempts < 255)
|
||||
scanAttempts++;
|
||||
}
|
||||
|
||||
if (scanAttempts < INTERVAL_1_ATTEMPTS)
|
||||
{
|
||||
if (scanAttempts < INTERVAL_1_ATTEMPTS) {
|
||||
return INTERVAL_1_TIME;
|
||||
}
|
||||
else if (scanAttempts < (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS))
|
||||
{
|
||||
} else if (scanAttempts < (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS)) {
|
||||
return INTERVAL_2_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return INTERVAL_3_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void addAverageValue()
|
||||
{
|
||||
void addAverageValue() {
|
||||
uint16_t curval = INTERVAL_AT_MAX_ATTEMPTS - INTERVAL_BASE;
|
||||
curval *= dataReqLastAttempt;
|
||||
curval /= DATA_REQ_MAX_ATTEMPTS;
|
||||
@@ -141,14 +141,11 @@ void addAverageValue()
|
||||
dataReqAttemptArrayIndex++;
|
||||
}
|
||||
|
||||
uint16_t getNextSleep()
|
||||
{
|
||||
/*uint16_t avg = 0;
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++)
|
||||
{
|
||||
uint16_t getNextSleep() {
|
||||
uint16_t avg = 0;
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
avg += dataReqAttemptArr[c];
|
||||
}
|
||||
avg /= POWER_SAVING_SMOOTHING;
|
||||
return avg;*/
|
||||
return 30;
|
||||
return avg;
|
||||
}
|
||||
@@ -60,20 +60,22 @@ extern void doSleep(const uint32_t t);
|
||||
extern void addAverageValue();
|
||||
extern uint16_t getNextSleep();
|
||||
|
||||
extern uint16_t doVoltageReading();
|
||||
|
||||
extern uint32_t getNextScanSleep(const bool increment);
|
||||
extern void initPowerSaving(const uint16_t initialValue);
|
||||
|
||||
extern uint8_t wakeUpReason;
|
||||
|
||||
extern uint8_t capabilities;
|
||||
extern __attribute__((section(".aonshadow"))) uint8_t capabilities;
|
||||
|
||||
extern uint16_t nextCheckInFromAP;
|
||||
extern uint8_t dataReqLastAttempt;
|
||||
extern int8_t temperature;
|
||||
extern uint16_t batteryVoltage;
|
||||
extern bool lowBattery;
|
||||
extern uint8_t scanAttempts;
|
||||
extern uint16_t longDataReqCounter;
|
||||
extern uint16_t voltageCheckCounter;
|
||||
extern __attribute__((section(".aonshadow"))) uint8_t dataReqLastAttempt;
|
||||
extern __attribute__((section(".aonshadow"))) int8_t temperature;
|
||||
extern __attribute__((section(".aonshadow"))) uint16_t batteryVoltage;
|
||||
extern __attribute__((section(".aonshadow"))) bool lowBattery;
|
||||
extern __attribute__((section(".aonshadow"))) uint8_t scanAttempts;
|
||||
extern __attribute__((section(".aonshadow"))) uint16_t longDataReqCounter;
|
||||
extern __attribute__((section(".aonshadow"))) uint16_t voltageCheckCounter;
|
||||
|
||||
#endif
|
||||
914
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/printf.c
Normal file
914
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/printf.c
Normal file
@@ -0,0 +1,914 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "printf.h"
|
||||
|
||||
|
||||
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||
// printf_config.h header file
|
||||
// default: undefined
|
||||
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||
#include "printf_config.h"
|
||||
#endif
|
||||
|
||||
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// float number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
#endif
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
#endif
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#ifndef PRINTF_MAX_FLOAT
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
#endif
|
||||
|
||||
// support for the long long types (%llu or %p)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
#endif
|
||||
|
||||
// support for the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_LONG_LONG (1U << 9U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void* arg);
|
||||
void* arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
if (idx < maxlen) {
|
||||
((char*)buffer)[idx] = character;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)character; (void)buffer; (void)idx; (void)maxlen;
|
||||
}
|
||||
|
||||
|
||||
// internal _putchar wrapper
|
||||
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)buffer; (void)idx; (void)maxlen;
|
||||
if (character) {
|
||||
_putchar(character);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)idx; (void)maxlen;
|
||||
if (character) {
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||
{
|
||||
const char* s;
|
||||
for (s = str; *s && maxsize--; ++s);
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch)
|
||||
{
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char** str)
|
||||
{
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
for (size_t i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
}
|
||||
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
}
|
||||
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
}
|
||||
else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
}
|
||||
else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||
#endif
|
||||
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else if (diff < 0.5) {
|
||||
}
|
||||
else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
}
|
||||
else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
}
|
||||
else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
}
|
||||
else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
}
|
||||
else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) {
|
||||
value /= conv.F;
|
||||
}
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||
{
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format)
|
||||
{
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
|
||||
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
|
||||
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
|
||||
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
|
||||
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
|
||||
default : n = 0U; break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
}
|
||||
else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
}
|
||||
else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
}
|
||||
else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'l' :
|
||||
flags |= FLAGS_LONG;
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
flags |= FLAGS_LONG_LONG;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'h' :
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't' :
|
||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
case 'j' :
|
||||
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
case 'z' :
|
||||
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
case 'X' :
|
||||
case 'o' :
|
||||
case 'b' : {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
}
|
||||
else if (*format == 'o') {
|
||||
base = 8U;
|
||||
}
|
||||
else if (*format == 'b') {
|
||||
base = 2U;
|
||||
}
|
||||
else {
|
||||
base = 10U;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
}
|
||||
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f' :
|
||||
case 'F' :
|
||||
if (*format == 'F') flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c' : {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's' : {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p' : {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%' :
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default :
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int printf_(const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char buffer[1];
|
||||
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int sprintf_(char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int vprintf_(const char* format, va_list va)
|
||||
{
|
||||
char buffer[1];
|
||||
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
}
|
||||
|
||||
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
|
||||
{
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
116
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/printf.h
Normal file
116
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/printf.h
Normal file
@@ -0,0 +1,116 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Output a character to a custom device like UART, used by the printf() function
|
||||
* This function is declared here only. You have to write your custom implementation somewhere
|
||||
* \param character Character to output
|
||||
*/
|
||||
void _putchar(char character);
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
||||
* and internal underscore-appended functions like printf_() are used
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||
*/
|
||||
#define printf printf_
|
||||
int printf_(const char* format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define sprintf sprintf_
|
||||
int sprintf_(char* buffer, const char* format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||
* is non-negative and less than count, the string has been completely written.
|
||||
*/
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny vprintf implementation
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define vprintf vprintf_
|
||||
int vprintf_(const char* format, va_list va);
|
||||
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||
* \param out An output function which takes one character and an argument pointer
|
||||
* \param arg An argument pointer for user data passed to output function
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _PRINTF_H_
|
||||
@@ -4,49 +4,49 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
All communications are direct from tag to station, EXCEPT association (tag will broadcast).
|
||||
All comms shall be encrypted and authenticated with AES-CCM. Shared key shall be burned into the firmware.
|
||||
Master shall provision new key at association. All non-bcast packets shall have pan id compression.
|
||||
Master may skip "from" field. Tag checking in confirms it got the master's provisioning reply.
|
||||
|
||||
Sadly filtering on MZ100 fails for long addr with no src addr. so short addr for src is used
|
||||
|
||||
T = tag, S = station
|
||||
|
||||
PACKET TYPE USE PAYLOAD STRUCT NOTES
|
||||
ASSOC_REQ T2bcast TagInfo tag's info and assoc request (encrypted with shared key)
|
||||
ASSOC_RESP S2T AssocInfo tag's association info (encrypted with shared key)
|
||||
CHECKIN T2S CheckinInfo tag checking in occasionally
|
||||
CHECKOUT S2T PendingInfo station's checkin reply telling tag what we have for it
|
||||
CHUNK_REQ T2S ChunkReqInfo tag requesting a piece of data
|
||||
CHUNK_RESP S2T ChunkInfo station provides chunk
|
||||
All communications are direct from tag to station, EXCEPT association (tag will broadcast).
|
||||
All comms shall be encrypted and authenticated with AES-CCM. Shared key shall be burned into the firmware.
|
||||
Master shall provision new key at association. All non-bcast packets shall have pan id compression.
|
||||
Master may skip "from" field. Tag checking in confirms it got the master's provisioning reply.
|
||||
|
||||
Sadly filtering on MZ100 fails for long addr with no src addr. so short addr for src is used
|
||||
|
||||
T = tag, S = station
|
||||
|
||||
PACKET TYPE USE PAYLOAD STRUCT NOTES
|
||||
ASSOC_REQ T2bcast TagInfo tag's info and assoc request (encrypted with shared key)
|
||||
ASSOC_RESP S2T AssocInfo tag's association info (encrypted with shared key)
|
||||
CHECKIN T2S CheckinInfo tag checking in occasionally
|
||||
CHECKOUT S2T PendingInfo station's checkin reply telling tag what we have for it
|
||||
CHUNK_REQ T2S ChunkReqInfo tag requesting a piece of data
|
||||
CHUNK_RESP S2T ChunkInfo station provides chunk
|
||||
|
||||
*/
|
||||
|
||||
#define PROTO_PRESHARED_KEY {0x34D906D3, 0xE3E5298E, 0x3429BF58, 0xC1022081}
|
||||
#define PROTO_PRESHARED_KEY \
|
||||
{ 0x34D906D3, 0xE3E5298E, 0x3429BF58, 0xC1022081 }
|
||||
|
||||
#define PROTO_PAN_ID (0x4447) //PAN ID compression shall be used
|
||||
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
||||
|
||||
#define PKT_ASSOC_REQ (0xF0)
|
||||
#define PKT_ASSOC_RESP (0xF1)
|
||||
#define PKT_CHECKIN (0xF2)
|
||||
#define PKT_CHECKOUT (0xF3)
|
||||
#define PKT_CHUNK_REQ (0xF4)
|
||||
#define PKT_CHUNK_RESP (0xF5)
|
||||
#define PKT_ASSOC_REQ (0xF0)
|
||||
#define PKT_ASSOC_RESP (0xF1)
|
||||
#define PKT_CHECKIN (0xF2)
|
||||
#define PKT_CHECKOUT (0xF3)
|
||||
#define PKT_CHUNK_REQ (0xF4)
|
||||
#define PKT_CHUNK_RESP (0xF5)
|
||||
|
||||
#define PROTO_VER_0 (0)
|
||||
#define PROTO_VER_CURRENT (PROTO_VER_0)
|
||||
#define PROTO_VER_0 (0)
|
||||
#define PROTO_VER_CURRENT (PROTO_VER_0)
|
||||
|
||||
#define PROTO_COMPR_TYPE_LZ (0x0001)
|
||||
#define PROTO_COMPR_TYPE_BITPACK (0x0002)
|
||||
|
||||
#define PROTO_MAX_DL_LEN (88)
|
||||
#define PROTO_COMPR_TYPE_LZ (0x0001)
|
||||
#define PROTO_COMPR_TYPE_BITPACK (0x0002)
|
||||
|
||||
#define PROTO_MAX_DL_LEN (88)
|
||||
|
||||
//////////////// NEW
|
||||
|
||||
#include "tag_types.h"
|
||||
|
||||
/*
|
||||
// power saving algorithm
|
||||
#define INTERVAL_BASE 40 // interval (in seconds) (when 1 packet is sent/received) for target current (7.2µA)
|
||||
#define INTERVAL_AT_MAX_ATTEMPTS 600 // interval (in seconds) (at max attempts) for target average current
|
||||
@@ -68,7 +68,7 @@
|
||||
#define INTERVAL_2_TIME 7200UL // Try every 2 hours
|
||||
#define INTERVAL_2_ATTEMPTS 12 // for 12 attempts (an additional day)
|
||||
#define INTERVAL_3_TIME 86400UL // Finally, try every day
|
||||
|
||||
*/
|
||||
#pragma pack(1)
|
||||
enum TagScreenType {
|
||||
TagScreenEink_BW_1bpp,
|
||||
@@ -96,8 +96,6 @@ enum TagScreenType {
|
||||
TagScreenTypeOther = 0x7f,
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define RADIO_MAX_PACKET_LEN (125) // useful payload, not including the crc
|
||||
|
||||
#define ADDR_MODE_NONE (0)
|
||||
@@ -122,7 +120,7 @@ struct MacFcs {
|
||||
uint8_t destAddrType : 2;
|
||||
uint8_t frameVer : 2;
|
||||
uint8_t srcAddrType : 2;
|
||||
} ;
|
||||
};
|
||||
|
||||
struct MacFrameFromMaster {
|
||||
struct MacFcs fcs;
|
||||
@@ -130,7 +128,7 @@ struct MacFrameFromMaster {
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint16_t from;
|
||||
} ;
|
||||
};
|
||||
|
||||
struct MacFrameNormal {
|
||||
struct MacFcs fcs;
|
||||
@@ -138,7 +136,7 @@ struct MacFrameNormal {
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint8_t src[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct MacFrameBcast {
|
||||
struct MacFcs fcs;
|
||||
@@ -147,7 +145,7 @@ struct MacFrameBcast {
|
||||
uint16_t dstAddr;
|
||||
uint16_t srcPan;
|
||||
uint8_t src[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
#define PKT_AVAIL_DATA_SHORTREQ 0xE3
|
||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
||||
@@ -175,7 +173,7 @@ struct AvailDataReq {
|
||||
uint8_t currentChannel;
|
||||
uint8_t customMode;
|
||||
uint8_t reserved[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct oldAvailDataReq {
|
||||
uint8_t checksum;
|
||||
@@ -186,7 +184,7 @@ struct oldAvailDataReq {
|
||||
uint8_t hwType;
|
||||
uint8_t wakeupReason;
|
||||
uint8_t capabilities;
|
||||
} ;
|
||||
};
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
@@ -195,31 +193,31 @@ struct AvailDataInfo {
|
||||
uint8_t dataType;
|
||||
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
|
||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
||||
} ;
|
||||
} __attribute__((packed)) ;
|
||||
|
||||
struct pendingData {
|
||||
struct AvailDataInfo availdatainfo;
|
||||
uint16_t attemptsLeft;
|
||||
uint8_t targetMac[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct blockPart {
|
||||
uint8_t checksum;
|
||||
uint8_t blockId;
|
||||
uint8_t blockPart;
|
||||
uint8_t data[];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct blockData {
|
||||
uint16_t size;
|
||||
uint16_t checksum;
|
||||
uint8_t data[];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct burstMacData {
|
||||
uint16_t offset;
|
||||
uint8_t targetMac[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
#define BLOCK_PART_DATA_SIZE 99
|
||||
#define BLOCK_MAX_PARTS 42
|
||||
@@ -238,140 +236,131 @@ struct blockRequest {
|
||||
struct blockRequestAck {
|
||||
uint8_t checksum;
|
||||
uint16_t pleaseWaitMs;
|
||||
} ;
|
||||
};
|
||||
|
||||
struct espBlockRequest {
|
||||
uint8_t checksum;
|
||||
uint64_t ver;
|
||||
uint8_t blockId;
|
||||
uint8_t src[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct espXferComplete {
|
||||
uint8_t checksum;
|
||||
uint8_t src[8];
|
||||
} ;
|
||||
};
|
||||
|
||||
struct espAvailDataReq {
|
||||
uint8_t checksum;
|
||||
uint8_t src[8];
|
||||
struct AvailDataReq adr;
|
||||
} ;
|
||||
};
|
||||
|
||||
struct espSetChannelPower {
|
||||
uint8_t checksum;
|
||||
uint8_t channel;
|
||||
uint8_t power;
|
||||
} ;
|
||||
};
|
||||
#pragma pack(0)
|
||||
///////////////// NEW END
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
struct TagState {
|
||||
uint64_t swVer;
|
||||
uint16_t hwType;
|
||||
uint16_t batteryMv;
|
||||
uint64_t swVer;
|
||||
uint16_t hwType;
|
||||
uint16_t batteryMv;
|
||||
} __packed;
|
||||
|
||||
struct TagInfo {
|
||||
uint8_t protoVer; //PROTO_VER_*
|
||||
struct TagState state;
|
||||
uint8_t rfu1[1]; //shall be ignored for now
|
||||
uint16_t screenPixWidth;
|
||||
uint16_t screenPixHeight;
|
||||
uint16_t screenMmWidth;
|
||||
uint16_t screenMmHeight;
|
||||
uint16_t compressionsSupported; //COMPR_TYPE_* bitfield
|
||||
uint16_t maxWaitMsec; //how long tag will wait for packets before going to sleep
|
||||
uint8_t screenType; //enum TagScreenType
|
||||
uint8_t rfu[11]; //shall be zero for now
|
||||
uint8_t protoVer; // PROTO_VER_*
|
||||
struct TagState state;
|
||||
uint8_t rfu1[1]; // shall be ignored for now
|
||||
uint16_t screenPixWidth;
|
||||
uint16_t screenPixHeight;
|
||||
uint16_t screenMmWidth;
|
||||
uint16_t screenMmHeight;
|
||||
uint16_t compressionsSupported; // COMPR_TYPE_* bitfield
|
||||
uint16_t maxWaitMsec; // how long tag will wait for packets before going to sleep
|
||||
uint8_t screenType; // enum TagScreenType
|
||||
uint8_t rfu[11]; // shall be zero for now
|
||||
} __packed;
|
||||
|
||||
struct AssocInfo {
|
||||
uint32_t checkinDelay; //space between checkins, in msec
|
||||
uint32_t retryDelay; //if download fails mid-way wait thi smany msec to retry (IFF progress was made)
|
||||
uint16_t failedCheckinsTillBlank; //how many fails till we go blank
|
||||
uint16_t failedCheckinsTillDissoc; //how many fails till we dissociate
|
||||
uint32_t newKey[4];
|
||||
uint8_t rfu[8]; //shall be zero for now
|
||||
uint32_t checkinDelay; // space between checkins, in msec
|
||||
uint32_t retryDelay; // if download fails mid-way wait thi smany msec to retry (IFF progress was made)
|
||||
uint16_t failedCheckinsTillBlank; // how many fails till we go blank
|
||||
uint16_t failedCheckinsTillDissoc; // how many fails till we dissociate
|
||||
uint32_t newKey[4];
|
||||
uint8_t rfu[8]; // shall be zero for now
|
||||
} __packed;
|
||||
|
||||
#define CHECKIN_TEMP_OFFSET 0x7f
|
||||
#define CHECKIN_TEMP_OFFSET 0x7f
|
||||
|
||||
struct CheckinInfo {
|
||||
struct TagState state;
|
||||
uint8_t lastPacketLQI; //zero if not reported/not supported to be reported
|
||||
int8_t lastPacketRSSI; //zero if not reported/not supported to be reported
|
||||
uint8_t temperature; //zero if not reported/not supported to be reported. else, this minus CHECKIN_TEMP_OFFSET is temp in degrees C
|
||||
uint8_t rfu[6]; //shall be zero for now
|
||||
struct TagState state;
|
||||
uint8_t lastPacketLQI; // zero if not reported/not supported to be reported
|
||||
int8_t lastPacketRSSI; // zero if not reported/not supported to be reported
|
||||
uint8_t temperature; // zero if not reported/not supported to be reported. else, this minus CHECKIN_TEMP_OFFSET is temp in degrees C
|
||||
uint8_t rfu[6]; // shall be zero for now
|
||||
} __packed;
|
||||
|
||||
struct PendingInfo {
|
||||
uint64_t imgUpdateVer;
|
||||
uint32_t imgUpdateSize;
|
||||
uint64_t osUpdateVer; //version of OS update avail
|
||||
uint32_t osUpdateSize;
|
||||
uint8_t rfu[8]; //shall be zero for now
|
||||
uint64_t imgUpdateVer;
|
||||
uint32_t imgUpdateSize;
|
||||
uint64_t osUpdateVer; // version of OS update avail
|
||||
uint32_t osUpdateSize;
|
||||
uint8_t rfu[8]; // shall be zero for now
|
||||
} __packed;
|
||||
|
||||
struct ChunkReqInfo {
|
||||
uint64_t versionRequested;
|
||||
uint32_t offset;
|
||||
uint8_t len;
|
||||
uint8_t osUpdatePlz : 1;
|
||||
uint8_t rfu[6]; //shall be zero for now
|
||||
uint64_t versionRequested;
|
||||
uint32_t offset;
|
||||
uint8_t len;
|
||||
uint8_t osUpdatePlz : 1;
|
||||
uint8_t rfu[6]; // shall be zero for now
|
||||
} __packed;
|
||||
|
||||
struct ChunkInfo {
|
||||
uint32_t offset;
|
||||
uint8_t osUpdatePlz : 1;
|
||||
uint8_t rfu; //shall be zero for now
|
||||
uint8_t data[]; //no data means request is out of bounds of this version no longer exists
|
||||
uint32_t offset;
|
||||
uint8_t osUpdatePlz : 1;
|
||||
uint8_t rfu; // shall be zero for now
|
||||
uint8_t data[]; // no data means request is out of bounds of this version no longer exists
|
||||
} __packed;
|
||||
|
||||
#define MACFMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MACCVT(x) ((const uint8_t*)(x))[7], ((const uint8_t*)(x))[6], ((const uint8_t*)(x))[5], ((const uint8_t*)(x))[4], ((const uint8_t*)(x))[3], ((const uint8_t*)(x))[2], ((const uint8_t*)(x))[1], ((const uint8_t*)(x))[0]
|
||||
|
||||
#define VERSION_SIGNIFICANT_MASK (0x0000ffffffffffffull)
|
||||
|
||||
#define MACFMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MACCVT(x) ((const uint8_t*)(x))[7], ((const uint8_t*)(x))[6], ((const uint8_t*)(x))[5], ((const uint8_t*)(x))[4], ((const uint8_t*)(x))[3], ((const uint8_t*)(x))[2], ((const uint8_t*)(x))[1], ((const uint8_t*)(x))[0]
|
||||
#define HW_TYPE_42_INCH_SAMSUNG (1)
|
||||
#define HW_TYPE_42_INCH_SAMSUNG_ROM_VER_OFST (0xEFF8)
|
||||
|
||||
#define HW_TYPE_74_INCH_DISPDATA (2)
|
||||
#define HW_TYPE_74_INCH_DISPDATA_FRAME_MODE (3)
|
||||
#define HW_TYPE_74_INCH_DISPDATA_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define VERSION_SIGNIFICANT_MASK (0x0000ffffffffffffull)
|
||||
#define HW_TYPE_ZBD_EPOP50 (4)
|
||||
#define HW_TYPE_ZBD_EPOP50_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_42_INCH_SAMSUNG (1)
|
||||
#define HW_TYPE_42_INCH_SAMSUNG_ROM_VER_OFST (0xEFF8)
|
||||
#define HW_TYPE_ZBD_EPOP900 (5)
|
||||
#define HW_TYPE_ZBD_EPOP900_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_74_INCH_DISPDATA (2)
|
||||
#define HW_TYPE_74_INCH_DISPDATA_FRAME_MODE (3)
|
||||
#define HW_TYPE_74_INCH_DISPDATA_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_ZBD_EPOP50 (4)
|
||||
#define HW_TYPE_ZBD_EPOP50_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_ZBD_EPOP900 (5)
|
||||
#define HW_TYPE_ZBD_EPOP900_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_29_INCH_DISPDATA (6)
|
||||
#define HW_TYPE_29_INCH_DISPDATA_FRAME_MODE (7)
|
||||
#define HW_TYPE_29_INCH_DISPDATA_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_29_INCH_ZBS_026 (8)
|
||||
#define HW_TYPE_29_INCH_ZBS_026_FRAME_MODE (9)
|
||||
#define HW_TYPE_29_INCH_ZBS_025 (10)
|
||||
#define HW_TYPE_29_INCH_ZBS_025_FRAME_MODE (11)
|
||||
#define HW_TYPE_29_INCH_ZBS_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_74_INCH_BWR (40)
|
||||
#define HW_TYPE_74_INCH_BWR_ROM_VER_OFST (0x0160)
|
||||
#define HW_TYPE_58_INCH_BWR (41)
|
||||
#define HW_TYPE_58_INCH_BWR_ROM_VER_OFST (0x0160)
|
||||
#define HW_TYPE_42_INCH_BWR (42)
|
||||
#define HW_TYPE_42_INCH_BWR_ROM_VER_OFST (0x0160)
|
||||
#define HW_TYPE_29_INCH_DISPDATA (6)
|
||||
#define HW_TYPE_29_INCH_DISPDATA_FRAME_MODE (7)
|
||||
#define HW_TYPE_29_INCH_DISPDATA_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_29_INCH_ZBS_026 (8)
|
||||
#define HW_TYPE_29_INCH_ZBS_026_FRAME_MODE (9)
|
||||
#define HW_TYPE_29_INCH_ZBS_025 (10)
|
||||
#define HW_TYPE_29_INCH_ZBS_025_FRAME_MODE (11)
|
||||
#define HW_TYPE_29_INCH_ZBS_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_74_INCH_BWR (40)
|
||||
#define HW_TYPE_74_INCH_BWR_ROM_VER_OFST (0x0160)
|
||||
#define HW_TYPE_58_INCH_BWR (41)
|
||||
#define HW_TYPE_58_INCH_BWR_ROM_VER_OFST (0x0160)
|
||||
#define HW_TYPE_42_INCH_BWR (42)
|
||||
#define HW_TYPE_42_INCH_BWR_ROM_VER_OFST (0x0160)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,143 +3,24 @@
|
||||
#include "eeprom.h"
|
||||
#include "util.h"
|
||||
#include "mz100_flash.h"
|
||||
#include "powermgt.h"
|
||||
|
||||
__attribute__((section(".aonshadow"))) struct tagsettings tagSettings = {0};
|
||||
extern uint8_t blockXferBuffer[];
|
||||
uint8_t* infopageTempBuffer = 1024 + blockXferBuffer;
|
||||
|
||||
|
||||
#define EEPROM_NUM_SETTINGS_PAGES (EEPROM_SETTINGS_AREA_LEN / EEPROM_PAGE_SIZE)
|
||||
#define SETTINGS_MAGIC (0x31415926)
|
||||
|
||||
|
||||
|
||||
static uint32_t mCurSettingsAddr;
|
||||
|
||||
static void settingsPrvDoWriteAtLocation(uint32_t addr, struct Settings* settings)
|
||||
{
|
||||
settings->hdr.revision++;
|
||||
mCurSettingsAddr = addr;
|
||||
FLASH_Write(false, addr, (uint8_t*)settings, sizeof(struct Settings));
|
||||
}
|
||||
|
||||
//this is impossible to call before calling read. thus mCurSettingsAddr will be set
|
||||
void settingsPrvDoWrite(struct Settings* settings)
|
||||
{
|
||||
struct SettingsHeader sh;
|
||||
uint32_t i, addr;
|
||||
uint8_t byte;
|
||||
|
||||
|
||||
//first we try to fit in the current page, after current (latest) settings
|
||||
if (mCurSettingsAddr) {
|
||||
|
||||
FLASH_Read(0, mCurSettingsAddr, (uint8_t*)&sh, sizeof(struct SettingsHeader));
|
||||
addr = mCurSettingsAddr + sh.structSize;
|
||||
|
||||
//is there space?
|
||||
if (addr % EEPROM_PAGE_SIZE != 0 && addr % EEPROM_PAGE_SIZE + sizeof(struct Settings) <= EEPROM_PAGE_SIZE) {
|
||||
|
||||
//is it erased
|
||||
for (i = 0; i < sizeof(struct Settings); i++) {
|
||||
|
||||
FLASH_Read(0, addr, &byte, 1);
|
||||
if (byte != 0xff)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == sizeof(struct Settings)) {
|
||||
|
||||
settingsPrvDoWriteAtLocation(addr, settings);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//we need to erase - use next page (or 0th page if no current page at all)
|
||||
if (mCurSettingsAddr) {
|
||||
|
||||
addr = (mCurSettingsAddr + EEPROM_PAGE_SIZE - 1) / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
|
||||
if (addr == EEPROM_SETTINGS_AREA_START + EEPROM_SETTINGS_AREA_LEN)
|
||||
addr = EEPROM_SETTINGS_AREA_START;
|
||||
}
|
||||
else
|
||||
addr = EEPROM_SETTINGS_AREA_START;
|
||||
|
||||
qspiEraseRange(addr, EEPROM_PAGE_SIZE);
|
||||
settingsPrvDoWriteAtLocation(addr, settings);
|
||||
}
|
||||
|
||||
void settingsRead(struct Settings* settings)
|
||||
{
|
||||
uint32_t bestAddr = 0, page, ofst;
|
||||
uint64_t bestRevision = 0;
|
||||
struct SettingsHeader sh;
|
||||
bool doWrite = true;
|
||||
|
||||
for (page = 0; page < EEPROM_NUM_SETTINGS_PAGES; page++) {
|
||||
|
||||
for (ofst = 0; ofst < EEPROM_PAGE_SIZE - sizeof(struct SettingsHeader); ofst += sh.structSize) {
|
||||
|
||||
uint32_t addr = EEPROM_SETTINGS_AREA_START + page * EEPROM_PAGE_SIZE + ofst;
|
||||
|
||||
FLASH_Read(0, addr, (uint8_t*)&sh, sizeof(struct SettingsHeader));
|
||||
|
||||
//sanity checks. struct is only allowed to grow in size...
|
||||
if (sh.magic != SETTINGS_MAGIC || ofst + sh.structSize > EEPROM_PAGE_SIZE || sh.structSize > sizeof(struct Settings))
|
||||
break;
|
||||
|
||||
if (sh.revision > bestRevision) {
|
||||
bestRevision = sh.revision;
|
||||
bestAddr = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestAddr) {
|
||||
FLASH_Read(0, bestAddr, (uint8_t*)&sh, sizeof(struct SettingsHeader)); //to get size
|
||||
FLASH_Read(0, bestAddr, (uint8_t*)settings, sh.structSize);
|
||||
mCurSettingsAddr = bestAddr;
|
||||
}
|
||||
else {
|
||||
settings->hdr.structVersion = SETTINGS_VER_NONE;
|
||||
settings->hdr.revision = 1;
|
||||
mCurSettingsAddr = 0;
|
||||
}
|
||||
|
||||
//migrate
|
||||
switch (settings->hdr.structVersion) {
|
||||
|
||||
//current version here - mark as such
|
||||
case SETTINGS_CURRENT:
|
||||
doWrite = false;
|
||||
break;
|
||||
|
||||
case SETTINGS_VER_NONE: //migrate to v1
|
||||
memset(settings, 0, sizeof(*settings));
|
||||
settings->hdr.magic = SETTINGS_MAGIC;
|
||||
//fallthrough
|
||||
|
||||
case SETTINGS_VER_1: //migrate to v2
|
||||
settings->prevDlProgress = 0xffff;
|
||||
//fallthrough
|
||||
|
||||
case SETTINGS_VER_2: //migrate to v3
|
||||
settings->lastRxedRSSI = 0;
|
||||
//fallthrough
|
||||
|
||||
//new migrations here in order from lower vers to higher vers
|
||||
|
||||
settings->hdr.structVersion = SETTINGS_CURRENT;
|
||||
settings->hdr.structSize = sizeof(struct Settings);
|
||||
break;
|
||||
}
|
||||
|
||||
if (doWrite)
|
||||
settingsPrvDoWrite(settings);
|
||||
}
|
||||
|
||||
void settingsWrite(struct Settings* settings)
|
||||
{
|
||||
struct Settings s;
|
||||
|
||||
settingsRead(&s);
|
||||
if (memcmp(&s, settings, sizeof(struct Settings)))
|
||||
settingsPrvDoWrite(settings);
|
||||
void loadDefaultSettings() {
|
||||
tagSettings.settingsVer = SETTINGS_STRUCT_VERSION;
|
||||
tagSettings.enableFastBoot = DEFAULT_SETTING_FASTBOOT;
|
||||
tagSettings.enableRFWake = DEFAULT_SETTING_RFWAKE;
|
||||
tagSettings.enableTagRoaming = DEFAULT_SETTING_TAGROAMING;
|
||||
tagSettings.enableScanForAPAfterTimeout = DEFAULT_SETTING_SCANFORAP;
|
||||
tagSettings.enableLowBatSymbol = DEFAULT_SETTING_LOWBATSYMBOL;
|
||||
tagSettings.enableNoRFSymbol = DEFAULT_SETTING_NORFSYMBOL;
|
||||
tagSettings.customMode = 0;
|
||||
tagSettings.fastBootCapabilities = 0;
|
||||
tagSettings.minimumCheckInTime = INTERVAL_BASE;
|
||||
tagSettings.fixedChannel = 0;
|
||||
tagSettings.batLowVoltage = BATTERY_VOLTAGE_MINIMUM;
|
||||
}
|
||||
@@ -1,65 +1,41 @@
|
||||
#ifndef _SETTINGS_H_
|
||||
#define _SETTINGS_H_
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SETTINGS_VER_NONE (0x00000000)
|
||||
#define SETTINGS_VER_1 (0x00000001)
|
||||
#define SETTINGS_VER_2 (0x00000002)
|
||||
#define SETTINGS_VER_3 (0x00000003)
|
||||
#define FW_VERSION 20 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-75" // suffix, like -RC1 or whatever.
|
||||
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
|
||||
// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
|
||||
|
||||
struct SettingsHeader {
|
||||
uint32_t magic;
|
||||
uint64_t revision;
|
||||
uint8_t structVersion;
|
||||
uint8_t structSize; //incl this header
|
||||
#define SETTINGS_STRUCT_VERSION 0x01
|
||||
|
||||
#define DEFAULT_SETTING_FASTBOOT 0
|
||||
#define DEFAULT_SETTING_RFWAKE 0
|
||||
#define DEFAULT_SETTING_TAGROAMING 0
|
||||
#define DEFAULT_SETTING_SCANFORAP 1
|
||||
#define DEFAULT_SETTING_LOWBATSYMBOL 1
|
||||
#define DEFAULT_SETTING_NORFSYMBOL 1
|
||||
|
||||
struct tagsettings {
|
||||
uint8_t settingsVer; // the version of the struct as written to the infopage
|
||||
uint8_t enableFastBoot; // default 0; if set, it will skip splashscreen
|
||||
uint8_t enableRFWake; // default 0; if set, it will enable RF wake. This will add about ~0.9µA idle power consumption
|
||||
uint8_t enableTagRoaming; // default 0; if set, the tag will scan for an accesspoint every few check-ins. This will increase power consumption quite a bit
|
||||
uint8_t enableScanForAPAfterTimeout; // default 1; if a the tag failed to check in, after a few attempts it will try to find a an AP on other channels
|
||||
uint8_t enableLowBatSymbol; // default 1; tag will show 'low battery' icon on screen if the battery is depleted
|
||||
uint8_t enableNoRFSymbol; // default 1; tag will show 'no signal' icon on screen if it failed to check in for a longer period of time
|
||||
uint8_t fastBootCapabilities; // holds the byte with 'capabilities' as detected during a normal tag boot; allows the tag to skip detecting buttons and NFC chip
|
||||
uint8_t customMode; // default 0; if anything else, tag will bootup in a different 'mode'
|
||||
uint16_t batLowVoltage; // Low battery threshold voltage (2450 for 2.45v). defaults to BATTERY_VOLTAGE_MINIMUM from powermgt.h
|
||||
uint16_t minimumCheckInTime; // defaults to BASE_INTERVAL from powermgt.h
|
||||
uint8_t fixedChannel; // default 0; if set to a valid channel number, the tag will stick to that channel
|
||||
} __attribute__((packed));
|
||||
|
||||
enum SettingsThingType {
|
||||
SettingsThingTypeNone,
|
||||
SettingsThingTypeImage,
|
||||
SettingsThingTypeUpdate,
|
||||
};
|
||||
extern __attribute__((section(".aonshadow")))struct tagsettings tagSettings;
|
||||
|
||||
#define SETTING_CHANNEL_OFFSET 11
|
||||
|
||||
struct Settings { //V1
|
||||
struct SettingsHeader hdr;
|
||||
|
||||
//master address
|
||||
uint8_t masterMac[8];
|
||||
|
||||
//encryption things
|
||||
uint32_t encrKey[4];
|
||||
uint32_t nextIV;
|
||||
|
||||
//checkin tracking
|
||||
uint32_t checkinDelay; //space between checkins, in msec
|
||||
uint32_t retryDelay;
|
||||
uint16_t failedCheckinsTillBlank; //how many fails till we go blank
|
||||
uint16_t failedCheckinsTillDissoc; //how many fails till we dissociate
|
||||
uint16_t numFailedCheckins;
|
||||
|
||||
//state
|
||||
uint8_t lastRxedLQI;
|
||||
uint8_t isPaired : 1;
|
||||
uint8_t channel : 4; //minus SETTING_CHANNEL_OFFSET
|
||||
uint8_t reserved : 3;
|
||||
|
||||
uint16_t prevDlProgress;
|
||||
|
||||
int8_t lastRxedRSSI;
|
||||
uint32_t helperInit;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SETTINGS_CURRENT SETTINGS_VER_3
|
||||
|
||||
|
||||
void settingsRead(struct Settings* settings);
|
||||
void settingsWrite(struct Settings* settings);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
void loadDefaultSettings();
|
||||
void writeSettings();
|
||||
void loadSettings();
|
||||
void loadSettingsFromBuffer(uint8_t* p);
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
extern uint8_t mSelfMac[];
|
||||
extern uint8_t currentChannel;
|
||||
extern __attribute__((section(".aonshadow"))) uint8_t mSelfMac[];
|
||||
extern __attribute__((section(".aonshadow"))) volatile uint8_t currentChannel;
|
||||
extern __attribute__((section(".aonshadow"))) struct blockRequest curBlock; // used by the block-requester, contains the next request that we'll send
|
||||
extern __attribute__((section(".aonshadow"))) struct AvailDataInfo curDataInfo; // last 'AvailDataInfo' we received from the AP // __attribute__((section(".aon")))
|
||||
|
||||
|
||||
extern uint8_t APmac[];
|
||||
|
||||
extern uint8_t curImgSlot;
|
||||
extern __attribute__((section(".aonshadow"))) uint8_t curImgSlot;
|
||||
|
||||
extern void setupRadio(void);
|
||||
extern void killRadio(void);
|
||||
|
||||
181
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/userinterface.c
Normal file
181
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/userinterface.c
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "userinterface.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitmaps.h"
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "epd.h"
|
||||
#include "font.h"
|
||||
#include "powermgt.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "syncedproto.h" // for APmac / Channel
|
||||
#include "timer.h"
|
||||
|
||||
const uint16_t fwVersion = FW_VERSION;
|
||||
const char fwVersionSuffix[] = FW_VERSION_SUFFIX;
|
||||
|
||||
extern uint8_t capabilities;
|
||||
|
||||
bool __attribute__((section(".aonshadow"))) lowBatteryShown = false;
|
||||
bool __attribute__((section(".aonshadow"))) noAPShown = false;
|
||||
|
||||
void addCapabilities() {
|
||||
// if (capabilities) epdpr("Options: ");
|
||||
if (capabilities & CAPABILITY_HAS_NFC) {
|
||||
// epdpr("-NFC");
|
||||
if (capabilities & CAPABILITY_NFC_WAKE) {
|
||||
// epdpr("+WAKE");
|
||||
} else {
|
||||
// epdpr(" ");
|
||||
}
|
||||
}
|
||||
if (capabilities & CAPABILITY_HAS_WAKE_BUTTON) {
|
||||
// epdpr("-WAKE BUTTON");
|
||||
}
|
||||
}
|
||||
|
||||
void addOverlay() {
|
||||
if ((currentChannel == 0) && (tagSettings.enableNoRFSymbol)) {
|
||||
// loadRawBitmap(ant, SCREEN_WIDTH - 24, 6, EPD_COLOR_BLACK);
|
||||
// loadRawBitmap(cross, SCREEN_WIDTH - 16, 13, EPD_COLOR_RED);
|
||||
noAPShown = true;
|
||||
} else {
|
||||
noAPShown = false;
|
||||
}
|
||||
if ((batteryVoltage < tagSettings.batLowVoltage) && (tagSettings.enableLowBatSymbol)) {
|
||||
// loadRawBitmap(battery, SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, EPD_COLOR_BLACK);
|
||||
lowBatteryShown = true;
|
||||
} else {
|
||||
lowBatteryShown = false;
|
||||
}
|
||||
}
|
||||
|
||||
void afterFlashScreenSaver() {
|
||||
// selectLUT(EPD_LUT_DEFAULT);
|
||||
// clearScreen();
|
||||
|
||||
#if (SCREEN_WIDTH == 400) // 4.2"
|
||||
epdPrintBegin(3, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("OpenEPaperLink");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
// drawWithSleep();
|
||||
}
|
||||
|
||||
void showSplashScreen() {
|
||||
// selectLUT(EPD_LUT_NO_REPEATS);
|
||||
// clearScreen();
|
||||
#if (SCREEN_WIDTH == 400) // 4.2"
|
||||
epdPrintBegin(3, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Starting");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(2, 252, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
addCapabilities();
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(3, 268, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs42v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(3, 284, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
epdpr("MAC: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
epdpr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
epdpr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
epdpr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
loadRawBitmap(oepli, 136, 22, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(cloud, 136, 10, EPD_COLOR_RED);
|
||||
|
||||
uint8_t __xdata buffer[17];
|
||||
spr(buffer, "%02X%02X", mSelfMac[7], mSelfMac[6]);
|
||||
spr(buffer + 4, "%02X%02X", mSelfMac[5], mSelfMac[4]);
|
||||
spr(buffer + 8, "%02X%02X", mSelfMac[3], mSelfMac[2]);
|
||||
spr(buffer + 12, "%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
printBarcode(buffer, 392, 264);
|
||||
printBarcode(buffer, 384, 264);
|
||||
|
||||
#endif
|
||||
// drawWithSleep();
|
||||
}
|
||||
|
||||
void showApplyUpdate() {
|
||||
// selectLUT(1);
|
||||
// clearScreen();
|
||||
#if (SCREEN_WIDTH == 400)
|
||||
epdPrintBegin(136, 134, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
#endif
|
||||
|
||||
// epdpr("Updating!");
|
||||
// epdPrintEnd();
|
||||
// drawNoWait();
|
||||
}
|
||||
|
||||
void showAPFound() {
|
||||
|
||||
init_epd();
|
||||
fillWindow(0, 0, 640, 384, 1);
|
||||
epdPrintf(10, 10, 1, "OpenEPaperLink");
|
||||
epdPrintf(10, 40, 1, "AP Found at channel %d", currentChannel);
|
||||
epdPrintf(10, 60, 1, "AP MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
|
||||
|
||||
epdPrintf(10, 330, 1, "Battery: %d.%dV", batteryVoltage / 1000, batteryVoltage % 1000);
|
||||
epdPrintf(10, 350, 1, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
|
||||
epd_refresh_and_sleep();
|
||||
}
|
||||
|
||||
void showNoAP() {
|
||||
init_epd();
|
||||
fillWindow(0, 0, 640, 384, 1);
|
||||
epdPrintf(10, 10, 1, "OpenEPaperLink ");
|
||||
epdPrintf(10, 40, 1, "No AP found... We'll try again in a little while though!");
|
||||
epdPrintf(10, 350, 1, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
|
||||
|
||||
epd_refresh_and_sleep();
|
||||
}
|
||||
|
||||
void showLongTermSleep() {
|
||||
// selectLUT(EPD_LUT_NO_REPEATS);
|
||||
// clearScreen();
|
||||
|
||||
// epdPrintBegin(2, SCREEN_HEIGHT - 16, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
// epdpr("zZ");
|
||||
// epdPrintEnd();
|
||||
|
||||
addOverlay();
|
||||
// drawWithSleep();
|
||||
}
|
||||
void showNoEEPROM() {
|
||||
// selectLUT(EPD_LUT_NO_REPEATS);
|
||||
// clearScreen();
|
||||
#if (SCREEN_WIDTH == 400) // 4.2"
|
||||
epdPrintBegin(50, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("EEPROM FAILED :(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 176, 126, EPD_COLOR_RED);
|
||||
epdPrintBegin(100, 284, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Sleeping forever :'(");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
// drawWithSleep();
|
||||
}
|
||||
|
||||
void showNoMAC() {
|
||||
// selectLUT(EPD_LUT_NO_REPEATS);
|
||||
// clearScreen();
|
||||
#if (SCREEN_WIDTH == 400) // 4.2"
|
||||
epdPrintBegin(100, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("NO MAC SET :(");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(failed, 176, 126, EPD_COLOR_RED);
|
||||
epdPrintBegin(100, 284, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Sleeping forever :'(");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
// drawWithSleep();
|
||||
}
|
||||
22
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/userinterface.h
Normal file
22
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/userinterface.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef _UI_H_
|
||||
#define _UI_H_
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void addOverlay();
|
||||
|
||||
void afterFlashScreenSaver();
|
||||
void showSplashScreen();
|
||||
void showApplyUpdate();
|
||||
void showAPFound();
|
||||
void showNoAP();
|
||||
void showLongTermSleep();
|
||||
void showNoEEPROM();
|
||||
void showNoMAC();
|
||||
|
||||
extern const uint16_t fwVersion;
|
||||
extern const char fwVersionSuffix[];
|
||||
extern __attribute__((section(".aon"))) bool lowBatteryShown;
|
||||
extern __attribute__((section(".aon"))) bool noAPShown;
|
||||
|
||||
#endif
|
||||
@@ -1,213 +1,185 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "eeprom.h"
|
||||
#include "timer.h"
|
||||
#include "mz100.h"
|
||||
#include "util.h"
|
||||
#include "mz100_flash.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
//#include <stdio.h>
|
||||
#include "printf.h"
|
||||
|
||||
#include "eeprom.h"
|
||||
#include "mz100.h"
|
||||
#include "mz100_adc.h"
|
||||
#include "mz100_flash.h"
|
||||
#include "mz100_wdt.h"
|
||||
#include "timer.h"
|
||||
|
||||
void wdt10s()
|
||||
{
|
||||
void wdt10s() {
|
||||
WDT_RestartCounter();
|
||||
}
|
||||
void wdt30s()
|
||||
{
|
||||
void wdt30s() {
|
||||
WDT_RestartCounter();
|
||||
}
|
||||
void wdt60s()
|
||||
{
|
||||
void wdt60s() {
|
||||
WDT_RestartCounter();
|
||||
}
|
||||
|
||||
void delay(int cnt)
|
||||
{
|
||||
volatile unsigned int i;
|
||||
for (i = 107 * cnt; i; --i)
|
||||
;
|
||||
void delay(int cnt) {
|
||||
volatile unsigned int i;
|
||||
for (i = 107 * cnt; i; --i)
|
||||
;
|
||||
}
|
||||
|
||||
void delay_us(unsigned int result)
|
||||
{
|
||||
volatile unsigned int i;
|
||||
void delay_us(unsigned int result) {
|
||||
volatile unsigned int i;
|
||||
|
||||
for (i = 0; i < result; ++i)
|
||||
;
|
||||
for (i = 0; i < result; ++i)
|
||||
;
|
||||
}
|
||||
|
||||
uint16_t crc16(uint16_t cur_crc, uint8_t data)
|
||||
{
|
||||
cur_crc ^= data;
|
||||
for (uint8_t i = 8; i > 0; i--)
|
||||
{
|
||||
if ((cur_crc & 0x001) != 0)
|
||||
{
|
||||
cur_crc >>= 1;
|
||||
cur_crc ^= 0x8005; // poly
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_crc >>= 1;
|
||||
}
|
||||
}
|
||||
return cur_crc;
|
||||
uint16_t crc16(uint16_t cur_crc, uint8_t data) {
|
||||
cur_crc ^= data;
|
||||
for (uint8_t i = 8; i > 0; i--) {
|
||||
if ((cur_crc & 0x001) != 0) {
|
||||
cur_crc >>= 1;
|
||||
cur_crc ^= 0x8005; // poly
|
||||
} else {
|
||||
cur_crc >>= 1;
|
||||
}
|
||||
}
|
||||
return cur_crc;
|
||||
}
|
||||
|
||||
uint32_t measureTemp(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
ADC_CFG_Type adc_config;
|
||||
adc_config.adcResolution = ADC_RESOLUTION_14BIT;
|
||||
adc_config.adcVrefSource = ADC_VREF_INTERNAL; // 1.2V
|
||||
adc_config.adcGainSel = ADC_GAIN_1;
|
||||
adc_config.adcClockDivider = ADC_CLOCK_DIVIDER_4;
|
||||
adc_config.adcBiasMode = ADC_BIAS_FULL;
|
||||
uint32_t measureTemp(void) {
|
||||
uint32_t result = 0;
|
||||
ADC_CFG_Type adc_config;
|
||||
adc_config.adcResolution = ADC_RESOLUTION_14BIT;
|
||||
adc_config.adcVrefSource = ADC_VREF_INTERNAL; // 1.2V
|
||||
adc_config.adcGainSel = ADC_GAIN_1;
|
||||
adc_config.adcClockDivider = ADC_CLOCK_DIVIDER_4;
|
||||
adc_config.adcBiasMode = ADC_BIAS_FULL;
|
||||
|
||||
ADC_Reset();
|
||||
ADC_ModeSelect(ADC_MODE_TSENSOR);
|
||||
ADC_TSensorConfig(ADC_TEMPP, ADC_SENSOR_INTERNAL);
|
||||
ADC_Init(&adc_config);
|
||||
ADC_Enable();
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
}
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
result += (ADC_GetConversionResult() - 458) / 1.7;
|
||||
}
|
||||
result /= 128;
|
||||
printf("Temp: %iC\r\n", result);
|
||||
return result;
|
||||
ADC_Reset();
|
||||
ADC_ModeSelect(ADC_MODE_TSENSOR);
|
||||
ADC_TSensorConfig(ADC_TEMPP, ADC_SENSOR_INTERNAL);
|
||||
ADC_Init(&adc_config);
|
||||
ADC_Enable();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
}
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
result += (ADC_GetConversionResult() - 458) / 1.7;
|
||||
}
|
||||
result /= 128;
|
||||
printf("Temp: %iC\r\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t measureBattery(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
ADC_CFG_Type adc_config;
|
||||
adc_config.adcResolution = ADC_RESOLUTION_16BIT;
|
||||
adc_config.adcVrefSource = ADC_VREF_VCAU; // 1.8V
|
||||
adc_config.adcGainSel = ADC_GAIN_1; // range 0 - 1.8V
|
||||
adc_config.adcClockDivider = ADC_CLOCK_DIVIDER_4;
|
||||
adc_config.adcBiasMode = ADC_BIAS_FULL;
|
||||
uint32_t measureBattery(void) {
|
||||
uint32_t result = 0;
|
||||
ADC_CFG_Type adc_config;
|
||||
adc_config.adcResolution = ADC_RESOLUTION_16BIT;
|
||||
adc_config.adcVrefSource = ADC_VREF_VCAU; // 1.8V
|
||||
adc_config.adcGainSel = ADC_GAIN_1; // range 0 - 1.8V
|
||||
adc_config.adcClockDivider = ADC_CLOCK_DIVIDER_4;
|
||||
adc_config.adcBiasMode = ADC_BIAS_FULL;
|
||||
|
||||
ADC_Reset();
|
||||
ADC_ModeSelect(ADC_MODE_ADC);
|
||||
ADC_ChannelConfig(ADC_VBATS); // 0.33 of Actual Voltage
|
||||
ADC_Init(&adc_config);
|
||||
ADC_Enable();
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
}
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
result += ADC_GetConversionResult() * 5940 / 32768;
|
||||
}
|
||||
result /= 128;
|
||||
printf("Voltage: %imV\r\n", result);
|
||||
return result;
|
||||
ADC_Reset();
|
||||
ADC_ModeSelect(ADC_MODE_ADC);
|
||||
ADC_ChannelConfig(ADC_VBATS); // 0.33 of Actual Voltage
|
||||
ADC_Init(&adc_config);
|
||||
ADC_Enable();
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
}
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ADC_ConversionStart();
|
||||
ADC_IntClr(ADC_RDY);
|
||||
while (!ADC_GetStatus(ADC_STATUS_RDY))
|
||||
;
|
||||
ADC_ConversionStop();
|
||||
result += ADC_GetConversionResult() * 5940 / 32768;
|
||||
}
|
||||
result /= 128;
|
||||
printf("Voltage: %imV\r\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void qspiEraseRange(uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint64_t time;
|
||||
// round starting address down
|
||||
if (addr % EEPROM_PAGE_SIZE)
|
||||
{
|
||||
len += addr % EEPROM_PAGE_SIZE;
|
||||
addr = addr / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
|
||||
}
|
||||
void qspiEraseRange(uint32_t addr, uint32_t len) {
|
||||
uint64_t time;
|
||||
// round starting address down
|
||||
if (addr % EEPROM_PAGE_SIZE) {
|
||||
len += addr % EEPROM_PAGE_SIZE;
|
||||
addr = addr / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
// round length up
|
||||
len = (len + EEPROM_PAGE_SIZE - 1) / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
|
||||
// round length up
|
||||
len = (len + EEPROM_PAGE_SIZE - 1) / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
|
||||
|
||||
while (len)
|
||||
{
|
||||
while (len) {
|
||||
uint32_t now;
|
||||
bool ok;
|
||||
|
||||
uint32_t now;
|
||||
bool ok;
|
||||
WDT_RestartCounter();
|
||||
if (!(addr % 0x10000) && len >= 0x10000) {
|
||||
ok = FLASH_Block64KErase(addr / 0x10000);
|
||||
now = 0x10000;
|
||||
} else if (!(addr % 0x8000) && len >= 0x8000) {
|
||||
ok = FLASH_Block32KErase(addr / 0x8000);
|
||||
now = 0x8000;
|
||||
} else {
|
||||
ok = FLASH_SectorErase(addr / 0x1000);
|
||||
now = 0x1000;
|
||||
}
|
||||
|
||||
WDT_RestartCounter();
|
||||
if (!(addr % 0x10000) && len >= 0x10000)
|
||||
{
|
||||
ok = FLASH_Block64KErase(addr / 0x10000);
|
||||
now = 0x10000;
|
||||
}
|
||||
else if (!(addr % 0x8000) && len >= 0x8000)
|
||||
{
|
||||
ok = FLASH_Block32KErase(addr / 0x8000);
|
||||
now = 0x8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = FLASH_SectorErase(addr / 0x1000);
|
||||
now = 0x1000;
|
||||
}
|
||||
if (!ok)
|
||||
printf("ERZ fail at 0x%08x + %u\r\n", addr, now);
|
||||
|
||||
if (!ok)
|
||||
printf("ERZ fail at 0x%08x + %u\r\n", addr, now);
|
||||
|
||||
addr += now;
|
||||
len -= now;
|
||||
if (len)
|
||||
{
|
||||
// let the caps recharge
|
||||
time = timerGet();
|
||||
while (timerGet() - time < TIMER_TICKS_PER_SEC / 10)
|
||||
;
|
||||
}
|
||||
}
|
||||
WDT_RestartCounter();
|
||||
addr += now;
|
||||
len -= now;
|
||||
if (len) {
|
||||
// let the caps recharge
|
||||
time = timerGet();
|
||||
while (timerGet() - time < TIMER_TICKS_PER_SEC / 10)
|
||||
;
|
||||
}
|
||||
}
|
||||
WDT_RestartCounter();
|
||||
}
|
||||
|
||||
bool eepromWrite(uint32_t addr, const void *srcP, uint16_t len)
|
||||
{
|
||||
FLASH_Write(false, addr, srcP, len);
|
||||
return true;
|
||||
bool eepromWrite(uint32_t addr, const void *srcP, uint16_t len) {
|
||||
FLASH_Write(false, addr, (void*)srcP, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eepromErase(uint32_t addr, uint16_t nSec)
|
||||
{
|
||||
qspiEraseRange(addr, nSec);
|
||||
return true;
|
||||
bool eepromErase(uint32_t addr, uint16_t nSec) {
|
||||
qspiEraseRange(addr, nSec);
|
||||
return true;
|
||||
}
|
||||
|
||||
void eepromRead(uint32_t addr, void *dstP, uint16_t len)
|
||||
{
|
||||
uint8_t *dst = (uint8_t *)dstP;
|
||||
FLASH_Read(0, addr, dst, len);
|
||||
void eepromRead(uint32_t addr, void *dstP, uint16_t len) {
|
||||
uint8_t *dst = (uint8_t *)dstP;
|
||||
FLASH_Read(0, addr, dst, len);
|
||||
}
|
||||
uint32_t eepromGetSize(void)
|
||||
{
|
||||
return EEPROM_IMG_LEN;
|
||||
uint32_t eepromGetSize(void) {
|
||||
return EEPROM_IMG_LEN;
|
||||
}
|
||||
|
||||
void radioShutdown(void)
|
||||
{
|
||||
// i have no idea what these do, determined by writing random registers and watching the current drawn
|
||||
*(volatile uint32_t *)0x4C000000 = 0;
|
||||
*(volatile uint32_t *)0x4C010000 = 0;
|
||||
*(volatile uint32_t *)0x4C010004 = 0x10000000;
|
||||
void radioShutdown(void) {
|
||||
// i have no idea what these do, determined by writing random registers and watching the current drawn
|
||||
*(volatile uint32_t *)0x4C000000 = 0;
|
||||
*(volatile uint32_t *)0x4C010000 = 0;
|
||||
*(volatile uint32_t *)0x4C010004 = 0x10000000;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
#include "zigbee.h"
|
||||
#include "printf.h"
|
||||
|
||||
volatile uint8_t calibration_irq_ocoured = 0;
|
||||
volatile uint8_t zigbee_tx_done = 0;
|
||||
@@ -145,24 +146,29 @@ void fill_rx_regs()
|
||||
;
|
||||
}
|
||||
|
||||
void sub_1021E6()
|
||||
void load_calib()
|
||||
{
|
||||
int v0;
|
||||
unsigned int v1;
|
||||
unsigned int i;
|
||||
|
||||
v0 = (*(volatile unsigned int *)0x4C01000C);
|
||||
v1 = get_register(0x130004);
|
||||
v1 = zigbeeCalibData.len;
|
||||
(*(volatile unsigned int *)0x4C010000) |= 4u;
|
||||
while (((*(volatile unsigned int *)0x4C010008) & 0x1000000) == 0)
|
||||
;
|
||||
for (i = 0; i < v1; ++i)
|
||||
set_register(v0 + 4 * i + 0x4C014000, *(uint32_t *)(4 * i + 0x130008));
|
||||
set_register(v0 + 4 * i + 0x4C014000, zigbeeCalibData.data[i]);
|
||||
(*(volatile unsigned int *)0x4C010000) &= ~4u;
|
||||
while (((*(volatile unsigned int *)0x4C010008) & 0x1000000) != 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// It is from 0x130000 up to 0x1301000 But you can only use 0x130404 up to the 0x1301000
|
||||
|
||||
|
||||
void save_calib_in_ram()
|
||||
{
|
||||
int v0;
|
||||
@@ -171,14 +177,14 @@ void save_calib_in_ram()
|
||||
|
||||
v0 = (*(volatile unsigned int *)0x4C01000C) + 0x4C014000;
|
||||
v1 = ((unsigned int)(uint8_t)((*(volatile unsigned int *)0x4C010008) >> 2) + 3) >> 2;
|
||||
set_register(0x130000u, 0x464C4147);
|
||||
set_register(0x130004u, v1);
|
||||
zigbeeCalibData.isValid = true;
|
||||
(*(volatile unsigned int *)0x4C01001C) = -5;
|
||||
(*(volatile unsigned int *)0x4C010000) |= 2u;
|
||||
while (((*(volatile unsigned int *)0x4C010008) & 0x1000000) == 0)
|
||||
;
|
||||
for (i = 0; i < v1; ++i)
|
||||
set_register(4 * i + 0x130008, *(uint32_t *)(v0 + 4 * i));
|
||||
for (i = 0; i < v1; ++i){
|
||||
zigbeeCalibData.data[i] = *(uint32_t *)(v0 + 4 * i);
|
||||
}
|
||||
(*(volatile unsigned int *)0x4C010000) &= ~2u;
|
||||
while (((*(volatile unsigned int *)0x4C010008) & 0x1000000) != 0)
|
||||
;
|
||||
@@ -189,12 +195,12 @@ int inner_calibration()
|
||||
int is_in_ram;
|
||||
|
||||
(*(volatile unsigned int *)0x4C010000) |= 0x20u;
|
||||
if (get_register(0x130000) == 0x464C4147)
|
||||
if(zigbeeCalibData.isValid)
|
||||
{
|
||||
is_in_ram = 1;
|
||||
(*(volatile unsigned int *)0x4C010000) |= 8u;
|
||||
(*(volatile unsigned int *)0x4C010000) &= ~0x10u;
|
||||
sub_1021E6();
|
||||
load_calib();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
|
||||
extern uint8_t channelList[6];
|
||||
|
||||
@@ -10,4 +11,11 @@ uint8_t Zigbee_tx_buffer(uint8_t *tx_buffer, int len);
|
||||
void radioInit();
|
||||
void radioSetChannel(uint8_t channel);
|
||||
void radioRxEnable(uint8_t channel);
|
||||
void radioRxFlush();
|
||||
void radioRxFlush();
|
||||
|
||||
struct zigbeeCalibDataStruct {
|
||||
uint16_t len;
|
||||
bool isValid;
|
||||
uint32_t data[30];
|
||||
};
|
||||
extern __attribute__((section(".aon"))) volatile struct zigbeeCalibDataStruct zigbeeCalibData;
|
||||
|
||||
4
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/.gitignore
vendored
Normal file
4
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
build
|
||||
*.axf
|
||||
# Allow
|
||||
!*.bin
|
||||
6
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/CMakeLists.txt
Normal file
6
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(OpenEPaperLink_esp32_C6)
|
||||
Binary file not shown.
1
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/flash.bat
Normal file
1
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/flash.bat
Normal file
@@ -0,0 +1 @@
|
||||
idf.py -p COM21 flash monitor
|
||||
@@ -0,0 +1,7 @@
|
||||
idf_component_register( SRCS
|
||||
SRCS "utils.c"
|
||||
SRCS "second_uart.c"
|
||||
SRCS "radio.c"
|
||||
SRCS "led.c"
|
||||
SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
26
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/led.c
Normal file
26
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/led.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "led.h"
|
||||
#include "proto.h"
|
||||
|
||||
void init_led()
|
||||
{
|
||||
gpio_config_t led1 = {};
|
||||
led1.intr_type = GPIO_INTR_DISABLE;
|
||||
led1.mode = GPIO_MODE_OUTPUT;
|
||||
led1.pin_bit_mask = ((1ULL<<LED1) | (1ULL<<LED2));
|
||||
led1.pull_down_en = 0;
|
||||
led1.pull_up_en = 0;
|
||||
gpio_config(&led1);
|
||||
}
|
||||
|
||||
void led_set(int nr, bool state)
|
||||
{
|
||||
gpio_set_level(nr, state);
|
||||
}
|
||||
4
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/led.h
Normal file
4
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/led.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void init_led();
|
||||
void led_set(int nr, bool state);
|
||||
715
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.c
Normal file
715
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.c
Normal file
@@ -0,0 +1,715 @@
|
||||
// Ported to ESP32-C6 By ATC1441(ATCnetz.de) for OpenEPaperLink at ~08.2023
|
||||
|
||||
#include "main.h"
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_ieee802154.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "second_uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc\lp_uart_reg.h"
|
||||
#include "utils.h"
|
||||
#include "led.h"
|
||||
|
||||
static const char *TAG = "MAIN";
|
||||
|
||||
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
||||
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define HW_TYPE 0xFF
|
||||
|
||||
#define MAX_PENDING_MACS 250
|
||||
#define HOUSEKEEPING_INTERVAL 60UL
|
||||
|
||||
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
||||
|
||||
// VERSION GOES HERE!
|
||||
uint16_t version = 0x0017;
|
||||
|
||||
#define RAW_PKT_PADDING 2
|
||||
|
||||
uint8_t radiotxbuffer[128];
|
||||
uint8_t radiorxbuffer[128];
|
||||
|
||||
static uint32_t housekeepingTimer;
|
||||
|
||||
struct blockRequest requestedData = {0}; // holds which data was requested by the tag
|
||||
|
||||
uint8_t dstMac[8]; // target for the block transfer
|
||||
uint16_t dstPan; //
|
||||
|
||||
static uint32_t blockStartTimer = 0; // reference that holds when the AP sends the next block
|
||||
uint32_t nextBlockAttempt = 0; // reference time for when the AP can request a new block from the ESP32
|
||||
uint8_t seq = 0; // holds current sequence number for transmission
|
||||
uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE + 5]; // block transfer buffer
|
||||
uint8_t lastAckMac[8] = {0};
|
||||
|
||||
// these variables hold the current mac were talking to
|
||||
#define CONCURRENT_REQUEST_DELAY 1200UL
|
||||
uint32_t lastBlockRequest = 0;
|
||||
uint8_t lastBlockMac[8];
|
||||
|
||||
uint8_t curChannel = 11;
|
||||
uint8_t curPower = 10;
|
||||
|
||||
uint8_t curPendingData = 0;
|
||||
uint8_t curNoUpdate = 0;
|
||||
|
||||
void sendXferCompleteAck(uint8_t *dst);
|
||||
void sendCancelXfer(uint8_t *dst);
|
||||
void espNotifyAPInfo();
|
||||
|
||||
// tools
|
||||
void addCRC(void *p, uint8_t len) {
|
||||
uint8_t total = 0;
|
||||
for (uint8_t c = 1; c < len; c++) {
|
||||
total += ((uint8_t *) p)[c];
|
||||
}
|
||||
((uint8_t *) p)[0] = total;
|
||||
}
|
||||
bool checkCRC(void *p, uint8_t len) {
|
||||
uint8_t total = 0;
|
||||
for (uint8_t c = 1; c < len; c++) {
|
||||
total += ((uint8_t *) p)[c];
|
||||
}
|
||||
return ((uint8_t *) p)[0] == total;
|
||||
}
|
||||
|
||||
uint8_t getPacketType(void *buffer) {
|
||||
struct MacFcs *fcs = buffer;
|
||||
if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) {
|
||||
// broadcast frame
|
||||
uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameBcast)];
|
||||
return type;
|
||||
} else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) {
|
||||
// normal frame
|
||||
uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameNormal)];
|
||||
return type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint8_t getBlockDataLength() {
|
||||
uint8_t partNo = 0;
|
||||
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) {
|
||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
||||
partNo++;
|
||||
}
|
||||
}
|
||||
return partNo;
|
||||
}
|
||||
|
||||
// pendingdata slot stuff
|
||||
int8_t findSlotForMac(const uint8_t *mac) {
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||
if (memcmp(mac, ((uint8_t *) &(pendingDataArr[c].targetMac)), 8) == 0) {
|
||||
if (pendingDataArr[c].attemptsLeft != 0) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int8_t findFreeSlot() {
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||
if (pendingDataArr[c].attemptsLeft == 0) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int8_t findSlotForVer(const uint8_t *ver) {
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||
if (memcmp(ver, ((uint8_t *) &(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) {
|
||||
if (pendingDataArr[c].attemptsLeft != 0) return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void deleteAllPendingDataForVer(const uint8_t *ver) {
|
||||
int8_t slot = -1;
|
||||
do {
|
||||
slot = findSlotForVer(ver);
|
||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
||||
} while (slot != -1);
|
||||
}
|
||||
void deleteAllPendingDataForMac(const uint8_t *mac) {
|
||||
int8_t slot = -1;
|
||||
do {
|
||||
slot = findSlotForMac(mac);
|
||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
||||
} while (slot != -1);
|
||||
}
|
||||
|
||||
void countSlots() {
|
||||
curPendingData = 0;
|
||||
curNoUpdate = 0;
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||
if (pendingDataArr[c].attemptsLeft != 0) {
|
||||
if (pendingDataArr[c].availdatainfo.dataType != 0) {
|
||||
curPendingData++;
|
||||
} else {
|
||||
curNoUpdate++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processing serial data
|
||||
#define ZBS_RX_WAIT_HEADER 0
|
||||
#define ZBS_RX_WAIT_SDA 1 // send data avail
|
||||
#define ZBS_RX_WAIT_CANCEL 2 // cancel traffic for mac
|
||||
#define ZBS_RX_WAIT_SCP 3 // set channel power
|
||||
#define ZBS_RX_WAIT_BLOCKDATA 4
|
||||
|
||||
bool isSame(uint8_t *in1, char *in2, int len) {
|
||||
bool flag = 1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (in1[i] != in2[i]) flag = 0;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
int blockPosition = 0;
|
||||
void processSerial(uint8_t lastchar) {
|
||||
static uint8_t cmdbuffer[4];
|
||||
static uint8_t RXState = 0;
|
||||
static uint8_t serialbuffer[48];
|
||||
static uint8_t *serialbufferp;
|
||||
static uint8_t bytesRemain = 0;
|
||||
static uint32_t lastSerial = 0;
|
||||
static uint32_t blockStartTime = 0;
|
||||
if ((RXState != ZBS_RX_WAIT_HEADER) && ((getMillis() - lastSerial) > 1000)) {
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
ESP_LOGI(TAG, "UART Timeout");
|
||||
}
|
||||
lastSerial = getMillis();
|
||||
switch (RXState) {
|
||||
case ZBS_RX_WAIT_HEADER:
|
||||
// shift characters in
|
||||
for (uint8_t c = 0; c < 3; c++) {
|
||||
cmdbuffer[c] = cmdbuffer[c + 1];
|
||||
}
|
||||
cmdbuffer[3] = lastchar;
|
||||
|
||||
if (isSame(cmdbuffer + 1, ">D>", 3)) {
|
||||
pr("ACK>\n");
|
||||
blockStartTime = getMillis();
|
||||
ESP_LOGI(TAG, "Starting BlkData");
|
||||
blockPosition = 0;
|
||||
RXState = ZBS_RX_WAIT_BLOCKDATA;
|
||||
}
|
||||
|
||||
if (isSame(cmdbuffer, "SDA>", 4)) {
|
||||
ESP_LOGI(TAG, "SDA In");
|
||||
RXState = ZBS_RX_WAIT_SDA;
|
||||
bytesRemain = sizeof(struct pendingData);
|
||||
serialbufferp = serialbuffer;
|
||||
break;
|
||||
}
|
||||
if (isSame(cmdbuffer, "CXD>", 4)) {
|
||||
ESP_LOGI(TAG, "CXD In");
|
||||
RXState = ZBS_RX_WAIT_CANCEL;
|
||||
bytesRemain = sizeof(struct pendingData);
|
||||
serialbufferp = serialbuffer;
|
||||
break;
|
||||
}
|
||||
if (isSame(cmdbuffer, "SCP>", 4)) {
|
||||
ESP_LOGI(TAG, "SCP In");
|
||||
RXState = ZBS_RX_WAIT_SCP;
|
||||
bytesRemain = sizeof(struct espSetChannelPower);
|
||||
serialbufferp = serialbuffer;
|
||||
break;
|
||||
}
|
||||
if (isSame(cmdbuffer, "NFO?", 4)) {
|
||||
pr("ACK>");
|
||||
ESP_LOGI(TAG, "NFO? In");
|
||||
espNotifyAPInfo();
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
if (isSame(cmdbuffer, "RDY?", 4)) {
|
||||
pr("ACK>");
|
||||
ESP_LOGI(TAG, "RDY? In");
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
if (isSame(cmdbuffer, "RSET", 4)) {
|
||||
pr("ACK>");
|
||||
ESP_LOGI(TAG, "RSET In");
|
||||
delay(100);
|
||||
// TODO RESET US HERE
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_BLOCKDATA:
|
||||
blockbuffer[blockPosition++] = 0xAA ^ lastchar;
|
||||
if (blockPosition >= 4100) {
|
||||
ESP_LOGI(TAG, "Blockdata fully received %lu", getMillis() - blockStartTime);
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZBS_RX_WAIT_SDA:
|
||||
*serialbufferp = lastchar;
|
||||
serialbufferp++;
|
||||
bytesRemain--;
|
||||
if (bytesRemain == 0) {
|
||||
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
|
||||
struct pendingData *pd = (struct pendingData *) serialbuffer;
|
||||
int8_t slot = findSlotForMac(pd->targetMac);
|
||||
if (slot == -1) slot = findFreeSlot();
|
||||
if (slot != -1) {
|
||||
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
|
||||
pr("ACK>\n");
|
||||
} else {
|
||||
pr("NOQ>\n");
|
||||
}
|
||||
} else {
|
||||
pr("NOK>\n");
|
||||
}
|
||||
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_CANCEL:
|
||||
*serialbufferp = lastchar;
|
||||
serialbufferp++;
|
||||
bytesRemain--;
|
||||
if (bytesRemain == 0) {
|
||||
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
|
||||
struct pendingData *pd = (struct pendingData *) serialbuffer;
|
||||
// deleteAllPendingDataForVer((uint8_t *)&pd->availdatainfo.dataVer);
|
||||
deleteAllPendingDataForMac((uint8_t *) &pd->targetMac);
|
||||
pr("ACK>\n");
|
||||
} else {
|
||||
pr("NOK>\n");
|
||||
}
|
||||
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_SCP:
|
||||
*serialbufferp = lastchar;
|
||||
serialbufferp++;
|
||||
bytesRemain--;
|
||||
if (bytesRemain == 0) {
|
||||
if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower))) {
|
||||
struct espSetChannelPower *scp = (struct espSetChannelPower *) serialbuffer;
|
||||
for (uint8_t c = 0; c < sizeof(channelList); c++) {
|
||||
if (channelList[c] == scp->channel) goto SCPchannelFound;
|
||||
}
|
||||
goto SCPfailed;
|
||||
SCPchannelFound:
|
||||
curChannel = scp->channel;
|
||||
curPower = scp->power;
|
||||
radioSetChannel(scp->channel);
|
||||
radioSetTxPower(scp->power);
|
||||
pr("ACK>\n");
|
||||
} else {
|
||||
SCPfailed:
|
||||
pr("NOK>\n");
|
||||
}
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sending data to the ESP
|
||||
void espBlockRequest(const struct blockRequest *br, uint8_t *src) {
|
||||
struct espBlockRequest *ebr = (struct espBlockRequest *) blockbuffer;
|
||||
uartTx('R');
|
||||
uartTx('Q');
|
||||
uartTx('B');
|
||||
uartTx('>');
|
||||
memcpy(&(ebr->ver), &(br->ver), 8);
|
||||
memcpy(&(ebr->src), src, 8);
|
||||
ebr->blockId = br->blockId;
|
||||
addCRC(ebr, sizeof(struct espBlockRequest));
|
||||
for (uint8_t c = 0; c < sizeof(struct espBlockRequest); c++) {
|
||||
uartTx(((uint8_t *) ebr)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyAvailDataReq(const struct AvailDataReq *adr, const uint8_t *src) {
|
||||
uartTx('A');
|
||||
uartTx('D');
|
||||
uartTx('R');
|
||||
uartTx('>');
|
||||
|
||||
struct espAvailDataReq eadr = {0};
|
||||
memcpy((void *) eadr.src, (void *) src, 8);
|
||||
memcpy((void *) &eadr.adr, (void *) adr, sizeof(struct AvailDataReq));
|
||||
addCRC(&eadr, sizeof(struct espAvailDataReq));
|
||||
for (uint8_t c = 0; c < sizeof(struct espAvailDataReq); c++) {
|
||||
uartTx(((uint8_t *) &eadr)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyXferComplete(const uint8_t *src) {
|
||||
struct espXferComplete exfc;
|
||||
memcpy(&exfc.src, src, 8);
|
||||
uartTx('X');
|
||||
uartTx('F');
|
||||
uartTx('C');
|
||||
uartTx('>');
|
||||
addCRC(&exfc, sizeof(exfc));
|
||||
for (uint8_t c = 0; c < sizeof(exfc); c++) {
|
||||
uartTx(((uint8_t *) &exfc)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyTimeOut(const uint8_t *src) {
|
||||
struct espXferComplete exfc;
|
||||
memcpy(&exfc.src, src, 8);
|
||||
uartTx('X');
|
||||
uartTx('T');
|
||||
uartTx('O');
|
||||
uartTx('>');
|
||||
addCRC(&exfc, sizeof(exfc));
|
||||
for (uint8_t c = 0; c < sizeof(exfc); c++) {
|
||||
uartTx(((uint8_t *) &exfc)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyAPInfo() {
|
||||
pr("TYP>%02X\n", HW_TYPE);
|
||||
pr("VER>%04X\n", version);
|
||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
||||
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
|
||||
pr("ZCH>%02X\n", curChannel);
|
||||
pr("ZPW>%02X\n", curPower);
|
||||
countSlots();
|
||||
pr("PEN>%02X\n", curPendingData);
|
||||
pr("NOP>%02X\n", curNoUpdate);
|
||||
}
|
||||
|
||||
// process data from tag
|
||||
void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
|
||||
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer;
|
||||
struct blockRequest *blockReq = (struct blockRequest *) (buffer + sizeof(struct MacFrameNormal) + 1);
|
||||
if (!checkCRC(blockReq, sizeof(struct blockRequest))) return;
|
||||
|
||||
// check if we're already talking to this mac
|
||||
if (memcmp(rxHeader->src, lastBlockMac, 8) == 0) {
|
||||
lastBlockRequest = getMillis();
|
||||
} else {
|
||||
// we weren't talking to this mac, see if there was a transfer in progress from another mac, recently
|
||||
if ((getMillis() - lastBlockRequest) > CONCURRENT_REQUEST_DELAY) {
|
||||
// mark this mac as the new current mac we're talking to
|
||||
memcpy((void *) lastBlockMac, (void *) rxHeader->src, 8);
|
||||
lastBlockRequest = getMillis();
|
||||
} else {
|
||||
// we're talking to another mac, let this mac know we can't accomodate another request right now
|
||||
pr("BUSY!\n");
|
||||
sendCancelXfer(rxHeader->src);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have data for this mac
|
||||
if (findSlotForMac(rxHeader->src) == -1) {
|
||||
// no data for this mac, politely tell it to fuck off
|
||||
sendCancelXfer(rxHeader->src);
|
||||
return;
|
||||
}
|
||||
|
||||
bool requestDataDownload = false;
|
||||
if ((blockReq->blockId != requestedData.blockId) || (blockReq->ver != requestedData.ver)) {
|
||||
// requested block isn't already in the buffer
|
||||
requestDataDownload = true;
|
||||
} else {
|
||||
// requested block is already in the buffer
|
||||
if (forceBlockDownload) {
|
||||
if ((getMillis() - nextBlockAttempt) > 380) {
|
||||
requestDataDownload = true;
|
||||
pr("FORCED\n");
|
||||
} else {
|
||||
pr("IGNORED\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy blockrequest into requested data
|
||||
memcpy(&requestedData, blockReq, sizeof(struct blockRequest));
|
||||
|
||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
||||
struct blockRequestAck *blockRequestAck = (struct blockRequestAck *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct blockRequestAck) + RAW_PKT_PADDING;
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST_ACK;
|
||||
|
||||
if (blockStartTimer == 0) {
|
||||
if (requestDataDownload) {
|
||||
// check if we need to download the first block; we need to give the ESP32 some additional time to cache the file
|
||||
if (blockReq->blockId == 0) {
|
||||
blockRequestAck->pleaseWaitMs = 450;
|
||||
} else {
|
||||
blockRequestAck->pleaseWaitMs = 450;
|
||||
}
|
||||
} else {
|
||||
// block is already in buffer
|
||||
blockRequestAck->pleaseWaitMs = 50;
|
||||
}
|
||||
} else {
|
||||
blockRequestAck->pleaseWaitMs = 50;
|
||||
}
|
||||
blockStartTimer = getMillis() + blockRequestAck->pleaseWaitMs;
|
||||
|
||||
memcpy(txHeader->src, mSelfMac, 8);
|
||||
memcpy(txHeader->dst, rxHeader->src, 8);
|
||||
|
||||
txHeader->pan = rxHeader->pan;
|
||||
txHeader->fcs.frameType = 1;
|
||||
txHeader->fcs.panIdCompressed = 1;
|
||||
txHeader->fcs.destAddrType = 3;
|
||||
txHeader->fcs.srcAddrType = 3;
|
||||
txHeader->seq = seq++;
|
||||
|
||||
addCRC((void *) blockRequestAck, sizeof(struct blockRequestAck));
|
||||
|
||||
radioTx(radiotxbuffer);
|
||||
|
||||
// save the target for the blockdata
|
||||
memcpy(dstMac, rxHeader->src, 8);
|
||||
dstPan = rxHeader->pan;
|
||||
|
||||
if (requestDataDownload) {
|
||||
blockPosition = 0;
|
||||
espBlockRequest(&requestedData, rxHeader->src);
|
||||
nextBlockAttempt = getMillis();
|
||||
}
|
||||
}
|
||||
|
||||
void processAvailDataReq(uint8_t *buffer) {
|
||||
struct MacFrameBcast *rxHeader = (struct MacFrameBcast *) buffer;
|
||||
struct AvailDataReq *availDataReq = (struct AvailDataReq *) (buffer + sizeof(struct MacFrameBcast) + 1);
|
||||
|
||||
if (!checkCRC(availDataReq, sizeof(struct AvailDataReq))) return;
|
||||
|
||||
// prepare tx buffer to send a response
|
||||
memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct AvailDataInfo) + 2); // 120);
|
||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
||||
struct AvailDataInfo *availDataInfo = (struct AvailDataInfo *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct AvailDataInfo) + RAW_PKT_PADDING;
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_AVAIL_DATA_INFO;
|
||||
|
||||
// check to see if we have data available for this mac
|
||||
bool haveData = false;
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||
if (pendingDataArr[c].attemptsLeft) {
|
||||
if (memcmp(pendingDataArr[c].targetMac, rxHeader->src, 8) == 0) {
|
||||
haveData = true;
|
||||
memcpy((void *) availDataInfo, &(pendingDataArr[c].availdatainfo), sizeof(struct AvailDataInfo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// couldn't find data for this mac
|
||||
if (!haveData) availDataInfo->dataType = DATATYPE_NOUPDATE;
|
||||
|
||||
memcpy(txHeader->src, mSelfMac, 8);
|
||||
memcpy(txHeader->dst, rxHeader->src, 8);
|
||||
txHeader->pan = rxHeader->dstPan;
|
||||
txHeader->fcs.frameType = 1;
|
||||
txHeader->fcs.panIdCompressed = 1;
|
||||
txHeader->fcs.destAddrType = 3;
|
||||
txHeader->fcs.srcAddrType = 3;
|
||||
txHeader->seq = seq++;
|
||||
addCRC(availDataInfo, sizeof(struct AvailDataInfo));
|
||||
radioTx(radiotxbuffer);
|
||||
memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet
|
||||
espNotifyAvailDataReq(availDataReq, rxHeader->src);
|
||||
}
|
||||
void processXferComplete(uint8_t *buffer) {
|
||||
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer;
|
||||
sendXferCompleteAck(rxHeader->src);
|
||||
if (memcmp(lastAckMac, rxHeader->src, 8) != 0) {
|
||||
memcpy((void *) lastAckMac, (void *) rxHeader->src, 8);
|
||||
espNotifyXferComplete(rxHeader->src);
|
||||
int8_t slot = findSlotForMac(rxHeader->src);
|
||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// send block data to the tag
|
||||
void sendPart(uint8_t partNo) {
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
||||
struct blockPart *blockPart = (struct blockPart *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PART;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, dstMac, 8);
|
||||
blockPart->blockId = requestedData.blockId;
|
||||
blockPart->blockPart = partNo;
|
||||
memcpy(&(blockPart->data), blockbuffer + (partNo * BLOCK_PART_DATA_SIZE), BLOCK_PART_DATA_SIZE);
|
||||
addCRC(blockPart, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE);
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = dstPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
void sendBlockData() {
|
||||
if (getBlockDataLength() == 0) {
|
||||
pr("Invalid block request received, 0 parts..\n");
|
||||
requestedData.requestedParts[0] |= 0x01;
|
||||
}
|
||||
uint8_t partNo = 0;
|
||||
while (partNo < BLOCK_MAX_PARTS) {
|
||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++) {
|
||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
||||
sendPart(c);
|
||||
partNo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void sendXferCompleteAck(uint8_t *dst) {
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_XFER_COMPLETE_ACK;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, dst, 8);
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = dstPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
void sendCancelXfer(uint8_t *dst) {
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_CANCEL_XFER;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, dst, 8);
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = dstPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
void sendPong(void *buf) {
|
||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *) buf;
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG;
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curChannel;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
||||
radiotxbuffer[2] = 0xCC; // normal frame
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = rxframe->srcPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
init_nvs();
|
||||
init_led();
|
||||
init_second_uart();
|
||||
|
||||
esp_event_loop_create_default();
|
||||
|
||||
radio_init();
|
||||
|
||||
requestedData.blockId = 0xFF;
|
||||
// clear the array with pending information
|
||||
memset(pendingDataArr, 0, sizeof(pendingDataArr));
|
||||
|
||||
radioSetChannel(curChannel);
|
||||
radioSetTxPower(10);
|
||||
|
||||
pr("RES>\n");
|
||||
pr("RDY>\n");
|
||||
|
||||
housekeepingTimer = getMillis();
|
||||
while (1) {
|
||||
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
|
||||
int8_t ret = commsRxUnencrypted(radiorxbuffer);
|
||||
if (ret > 1) {
|
||||
led_set(LED1, 1);
|
||||
// received a packet, lets see what it is
|
||||
switch (getPacketType(radiorxbuffer)) {
|
||||
case PKT_AVAIL_DATA_REQ:
|
||||
if (ret == 28) {
|
||||
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0,
|
||||
sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2);
|
||||
} else if (ret == 40) {
|
||||
// new version of the AvailDataReq struct
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
}
|
||||
break;
|
||||
case PKT_BLOCK_REQUEST:
|
||||
processBlockRequest(radiorxbuffer, 1);
|
||||
break;
|
||||
case PKT_BLOCK_PARTIAL_REQUEST:
|
||||
processBlockRequest(radiorxbuffer, 0);
|
||||
break;
|
||||
case PKT_XFER_COMPLETE:
|
||||
processXferComplete(radiorxbuffer);
|
||||
break;
|
||||
case PKT_PING:
|
||||
sendPong(radiorxbuffer);
|
||||
break;
|
||||
case PKT_AVAIL_DATA_SHORTREQ:
|
||||
// a short AvailDataReq is basically a very short (1 byte payload) packet that requires little preparation on the tx side, for optimal
|
||||
// battery use bytes of the struct are set 0, so it passes the checksum test, and the ESP32 can detect that no interesting payload is
|
||||
// sent
|
||||
if (ret == 18) {
|
||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2);
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr("t=%02X\n", getPacketType(radiorxbuffer));
|
||||
break;
|
||||
}
|
||||
led_set(LED1, 0);
|
||||
}
|
||||
uint8_t curr_char;
|
||||
while (getRxCharSecond(&curr_char)) processSerial(curr_char);
|
||||
|
||||
if (blockStartTimer) {
|
||||
// BUG: uint32 overflowing; this will break every once in a while. Don't know how to fix this other than ugly global variables
|
||||
if (getMillis() > blockStartTimer) {
|
||||
sendBlockData();
|
||||
blockStartTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) {
|
||||
if (pendingDataArr[cCount].attemptsLeft == 1) {
|
||||
if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) {
|
||||
espNotifyTimeOut(pendingDataArr[cCount].targetMac);
|
||||
}
|
||||
pendingDataArr[cCount].attemptsLeft = 0;
|
||||
} else if (pendingDataArr[cCount].attemptsLeft > 1) {
|
||||
pendingDataArr[cCount].attemptsLeft--;
|
||||
if (pendingDataArr[cCount].availdatainfo.nextCheckIn) pendingDataArr[cCount].availdatainfo.nextCheckIn--;
|
||||
}
|
||||
}
|
||||
housekeepingTimer = getMillis();
|
||||
}
|
||||
}
|
||||
1
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.h
Normal file
1
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.h
Normal file
@@ -0,0 +1 @@
|
||||
#pragma once
|
||||
176
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/proto.h
Normal file
176
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/proto.h
Normal file
@@ -0,0 +1,176 @@
|
||||
#ifndef _PROTO_H_
|
||||
#define _PROTO_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#define LED1 22
|
||||
#define LED2 23
|
||||
|
||||
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
||||
|
||||
#define RADIO_MAX_PACKET_LEN (125) // useful payload, not including the crc
|
||||
|
||||
#define ADDR_MODE_NONE (0)
|
||||
#define ADDR_MODE_SHORT (2)
|
||||
#define ADDR_MODE_LONG (3)
|
||||
|
||||
#define FRAME_TYPE_BEACON (0)
|
||||
#define FRAME_TYPE_DATA (1)
|
||||
#define FRAME_TYPE_ACK (2)
|
||||
#define FRAME_TYPE_MAC_CMD (3)
|
||||
|
||||
#define SHORT_MAC_UNUSED (0x10000000UL) // for radioRxFilterCfg's myShortMac
|
||||
|
||||
struct MacFcs {
|
||||
uint8_t frameType : 3;
|
||||
uint8_t secure : 1;
|
||||
uint8_t framePending : 1;
|
||||
uint8_t ackReqd : 1;
|
||||
uint8_t panIdCompressed : 1;
|
||||
uint8_t rfu1 : 1;
|
||||
uint8_t rfu2 : 2;
|
||||
uint8_t destAddrType : 2;
|
||||
uint8_t frameVer : 2;
|
||||
uint8_t srcAddrType : 2;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct MacFrameFromMaster {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint16_t from;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct MacFrameNormal {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint8_t src[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct MacFrameBcast {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t dstPan;
|
||||
uint16_t dstAddr;
|
||||
uint16_t srcPan;
|
||||
uint8_t src[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
#define PKT_AVAIL_DATA_SHORTREQ 0xE3
|
||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
||||
#define PKT_AVAIL_DATA_INFO 0xE6
|
||||
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
|
||||
#define PKT_BLOCK_REQUEST_ACK 0xE9
|
||||
#define PKT_BLOCK_REQUEST 0xE4
|
||||
#define PKT_BLOCK_PART 0xE8
|
||||
#define PKT_XFER_COMPLETE 0xEA
|
||||
#define PKT_XFER_COMPLETE_ACK 0xEB
|
||||
#define PKT_CANCEL_XFER 0xEC
|
||||
#define PKT_PING 0xED
|
||||
#define PKT_PONG 0xEE
|
||||
|
||||
struct AvailDataReq {
|
||||
uint8_t checksum;
|
||||
uint8_t lastPacketLQI;
|
||||
int8_t lastPacketRSSI;
|
||||
int8_t temperature;
|
||||
uint16_t batteryMv;
|
||||
uint8_t hwType;
|
||||
uint8_t wakeupReason;
|
||||
uint8_t capabilities;
|
||||
uint16_t tagSoftwareVersion;
|
||||
uint8_t currentChannel;
|
||||
uint8_t customMode;
|
||||
uint8_t reserved[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct oldAvailDataReq {
|
||||
uint8_t checksum;
|
||||
uint8_t lastPacketLQI;
|
||||
int8_t lastPacketRSSI;
|
||||
int8_t temperature;
|
||||
uint16_t batteryMv;
|
||||
uint8_t hwType;
|
||||
uint8_t wakeupReason;
|
||||
uint8_t capabilities;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
uint64_t dataVer; // MD5 of potential traffic
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType;
|
||||
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
|
||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct pendingData {
|
||||
struct AvailDataInfo availdatainfo;
|
||||
uint16_t attemptsLeft;
|
||||
uint8_t targetMac[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct blockPart {
|
||||
uint8_t checksum;
|
||||
uint8_t blockId;
|
||||
uint8_t blockPart;
|
||||
uint8_t data[];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct blockData {
|
||||
uint16_t size;
|
||||
uint16_t checksum;
|
||||
uint8_t data[];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct burstMacData {
|
||||
uint16_t offset;
|
||||
uint8_t targetMac[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
#define BLOCK_PART_DATA_SIZE 99
|
||||
#define BLOCK_MAX_PARTS 42
|
||||
#define BLOCK_DATA_SIZE 4096UL
|
||||
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
|
||||
#define BLOCK_REQ_PARTS_BYTES 6
|
||||
|
||||
struct blockRequest {
|
||||
uint8_t checksum;
|
||||
uint64_t ver;
|
||||
uint8_t blockId;
|
||||
uint8_t type;
|
||||
uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct blockRequestAck {
|
||||
uint8_t checksum;
|
||||
uint16_t pleaseWaitMs;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct espBlockRequest {
|
||||
uint8_t checksum;
|
||||
uint64_t ver;
|
||||
uint8_t blockId;
|
||||
uint8_t src[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct espXferComplete {
|
||||
uint8_t checksum;
|
||||
uint8_t src[8];
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct espAvailDataReq {
|
||||
uint8_t checksum;
|
||||
uint8_t src[8];
|
||||
struct AvailDataReq adr;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct espSetChannelPower {
|
||||
uint8_t checksum;
|
||||
uint8_t channel;
|
||||
uint8_t power;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
#endif
|
||||
95
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.c
Normal file
95
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_ieee802154.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "main.h"
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc\lp_uart_reg.h"
|
||||
#include "radio.h"
|
||||
#include "utils.h"
|
||||
#include "led.h"
|
||||
|
||||
static const char *TAG = "RADIO";
|
||||
|
||||
uint8_t mSelfMac[8];
|
||||
volatile uint8_t isInTransmit = 0;
|
||||
QueueHandle_t packet_bufer = NULL;
|
||||
|
||||
void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) {
|
||||
ESP_EARLY_LOGI(TAG, "RX <- : %d", frame[0]);
|
||||
BaseType_t xHigherPriorityTaskWoken ;
|
||||
static uint8_t inner_rxPKT[130];
|
||||
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
|
||||
xQueueSendFromISR(packet_bufer, (void *) &inner_rxPKT, &xHigherPriorityTaskWoken );
|
||||
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
|
||||
isInTransmit = 0;
|
||||
ESP_EARLY_LOGE(TAG, "TX Err: %d", error);
|
||||
}
|
||||
|
||||
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
|
||||
isInTransmit = 0;
|
||||
ESP_EARLY_LOGI(TAG, "TX -> : %d", frame[0]);
|
||||
}
|
||||
|
||||
void radio_init()
|
||||
{
|
||||
packet_bufer = xQueueCreate(32, 130);
|
||||
esp_ieee802154_enable();
|
||||
radioSetChannel(11);
|
||||
esp_ieee802154_set_panid(PROTO_PAN_ID);
|
||||
esp_ieee802154_set_promiscuous(false); // Filter for our mac and PAN
|
||||
esp_ieee802154_set_coordinator(false);
|
||||
esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE);
|
||||
esp_read_mac(mSelfMac, ESP_MAC_IEEE802154);
|
||||
esp_ieee802154_set_extended_address(mSelfMac);
|
||||
esp_ieee802154_set_short_address(0xFFFE);
|
||||
esp_ieee802154_set_rx_when_idle(true);
|
||||
esp_ieee802154_receive();
|
||||
}
|
||||
|
||||
uint32_t lastZbTx = 0;
|
||||
bool radioTx(uint8_t *packet)
|
||||
{
|
||||
static uint8_t txPKT[130];
|
||||
led_set(LED2, 1);
|
||||
while (isInTransmit) {
|
||||
}
|
||||
while (getMillis() - lastZbTx < 6) {
|
||||
}
|
||||
memcpy(txPKT, packet, packet[0]);
|
||||
isInTransmit = 1;
|
||||
lastZbTx = getMillis();
|
||||
esp_ieee802154_transmit(txPKT, false);
|
||||
led_set(LED2, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void radioSetChannel(uint8_t ch) { esp_ieee802154_set_channel(ch); }
|
||||
|
||||
void radioSetTxPower(uint8_t power) {}
|
||||
|
||||
int8_t commsRxUnencrypted(uint8_t *data) {
|
||||
static uint8_t inner_rxPKT_out[130];
|
||||
if (xQueueReceive(packet_bufer, (void *) &inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1);
|
||||
return inner_rxPKT_out[0] - 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
9
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.h
Normal file
9
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
extern uint8_t mSelfMac[8];
|
||||
|
||||
void radio_init();
|
||||
bool radioTx(uint8_t *packet);
|
||||
void radioSetChannel(uint8_t ch);
|
||||
void radioSetTxPower(uint8_t power);
|
||||
int8_t commsRxUnencrypted(uint8_t *data);
|
||||
260
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/second_uart.c
Normal file
260
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/second_uart.c
Normal file
@@ -0,0 +1,260 @@
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_ieee802154.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "main.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc\lp_uart_reg.h"
|
||||
|
||||
static const char *TAG = "SECOND_UART";
|
||||
|
||||
#define BUF_SIZE (1024)
|
||||
#define RD_BUF_SIZE (BUF_SIZE)
|
||||
static QueueHandle_t uart0_queue;
|
||||
|
||||
#define MAX_BUFF_POS 8000
|
||||
volatile int curr_buff_pos = 0;
|
||||
volatile int worked_buff_pos = 0;
|
||||
volatile uint8_t buff_pos[MAX_BUFF_POS + 5];
|
||||
|
||||
|
||||
|
||||
static void uart_event_task(void *pvParameters);
|
||||
void init_second_uart() {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(1, 3, 2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL);
|
||||
}
|
||||
|
||||
void uartTx(uint8_t data) { uart_write_bytes(1, (const char *) &data, 1); }
|
||||
|
||||
|
||||
bool getRxCharSecond(uint8_t *newChar) {
|
||||
if (curr_buff_pos != worked_buff_pos) {
|
||||
*newChar = buff_pos[worked_buff_pos];
|
||||
worked_buff_pos++;
|
||||
worked_buff_pos %= MAX_BUFF_POS;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void uart_event_task(void *pvParameters) {
|
||||
uart_event_t event;
|
||||
uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE);
|
||||
for (;;) {
|
||||
if (xQueueReceive(uart0_queue, (void *) &event, (TickType_t) portMAX_DELAY)) {
|
||||
bzero(dtmp, RD_BUF_SIZE);
|
||||
switch (event.type) {
|
||||
case UART_DATA:
|
||||
uart_read_bytes(1, dtmp, event.size, portMAX_DELAY);
|
||||
for (int i = 0; i < event.size; i++) {
|
||||
buff_pos[curr_buff_pos] = dtmp[i];
|
||||
curr_buff_pos++;
|
||||
curr_buff_pos %= MAX_BUFF_POS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "uart event type: %d", event.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(dtmp);
|
||||
dtmp = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void printchar(char **str, int c) {
|
||||
if (str) {
|
||||
**str = c;
|
||||
++(*str);
|
||||
} else {
|
||||
uart_write_bytes(1, (const char *) &c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#define PAD_RIGHT 1
|
||||
#define PAD_ZERO 2
|
||||
|
||||
static int prints(char **out, const char *string, int width, int pad) {
|
||||
register int pc = 0, padchar = ' ';
|
||||
|
||||
if (width > 0) {
|
||||
register int len = 0;
|
||||
register const char *ptr;
|
||||
for (ptr = string; *ptr; ++ptr) ++len;
|
||||
if (len >= width)
|
||||
width = 0;
|
||||
else
|
||||
width -= len;
|
||||
if (pad & PAD_ZERO) padchar = '0';
|
||||
}
|
||||
if (!(pad & PAD_RIGHT)) {
|
||||
for (; width > 0; --width) {
|
||||
printchar(out, padchar);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
for (; *string; ++string) {
|
||||
printchar(out, *string);
|
||||
++pc;
|
||||
}
|
||||
for (; width > 0; --width) {
|
||||
printchar(out, padchar);
|
||||
++pc;
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/* the following should be enough for 32 bit int */
|
||||
#define PRINT_BUF_LEN 12
|
||||
|
||||
static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase) {
|
||||
char print_buf[PRINT_BUF_LEN];
|
||||
register char *s;
|
||||
register int t, neg = 0, pc = 0;
|
||||
register unsigned int u = i;
|
||||
|
||||
if (i == 0) {
|
||||
print_buf[0] = '0';
|
||||
print_buf[1] = '\0';
|
||||
return prints(out, print_buf, width, pad);
|
||||
}
|
||||
|
||||
if (sg && b == 10 && i < 0) {
|
||||
neg = 1;
|
||||
u = -i;
|
||||
}
|
||||
|
||||
s = print_buf + PRINT_BUF_LEN - 1;
|
||||
*s = '\0';
|
||||
|
||||
while (u) {
|
||||
t = u % b;
|
||||
if (t >= 10) t += letbase - '0' - 10;
|
||||
*--s = t + '0';
|
||||
u /= b;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if (width && (pad & PAD_ZERO)) {
|
||||
printchar(out, '-');
|
||||
++pc;
|
||||
--width;
|
||||
} else {
|
||||
*--s = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return pc + prints(out, s, width, pad);
|
||||
}
|
||||
|
||||
static int print(char **out, const char *format, va_list args) {
|
||||
register int width, pad;
|
||||
register int pc = 0;
|
||||
char scr[2];
|
||||
|
||||
for (; *format != 0; ++format) {
|
||||
if (*format == '%') {
|
||||
++format;
|
||||
width = pad = 0;
|
||||
if (*format == '\0') break;
|
||||
if (*format == '%') goto out;
|
||||
if (*format == '-') {
|
||||
++format;
|
||||
pad = PAD_RIGHT;
|
||||
}
|
||||
while (*format == '0') {
|
||||
++format;
|
||||
pad |= PAD_ZERO;
|
||||
}
|
||||
for (; *format >= '0' && *format <= '9'; ++format) {
|
||||
width *= 10;
|
||||
width += *format - '0';
|
||||
}
|
||||
if (*format == 's') {
|
||||
register char *s = (char *) va_arg(args, int);
|
||||
pc += prints(out, s ? s : "(null)", width, pad);
|
||||
continue;
|
||||
}
|
||||
if (*format == 'd') {
|
||||
pc += printi(out, va_arg(args, int), 10, 1, width, pad, 'a');
|
||||
continue;
|
||||
}
|
||||
if (*format == 'x') {
|
||||
pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'a');
|
||||
continue;
|
||||
}
|
||||
if (*format == 'X') {
|
||||
pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'A');
|
||||
continue;
|
||||
}
|
||||
if (*format == 'u') {
|
||||
pc += printi(out, va_arg(args, int), 10, 0, width, pad, 'a');
|
||||
continue;
|
||||
}
|
||||
if (*format == 'c') {
|
||||
/* char are converted to int then pushed on the stack */
|
||||
scr[0] = (char) va_arg(args, int);
|
||||
scr[1] = '\0';
|
||||
pc += prints(out, scr, width, pad);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
out:
|
||||
printchar(out, *format);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
if (out) **out = '\0';
|
||||
va_end(args);
|
||||
return pc;
|
||||
}
|
||||
|
||||
int u_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
print(0, format, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int u_sprintf(char *out, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
return print(&out, format, args);
|
||||
}
|
||||
|
||||
void u_array_printf(unsigned char *data, unsigned int len) {
|
||||
u_printf("{");
|
||||
for (int i = 0; i < len; ++i) {
|
||||
u_printf("%X%s", data[i], i < (len) -1 ? ":" : " ");
|
||||
}
|
||||
u_printf("}\n");
|
||||
}
|
||||
14
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/second_uart.h
Normal file
14
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/second_uart.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
void init_second_uart();
|
||||
|
||||
void uartTx(uint8_t data);
|
||||
bool getRxCharSecond(uint8_t *newChar);
|
||||
|
||||
int u_printf(const char *fmt, ...);
|
||||
int u_sprintf(char *s, const char *fmt, ...);
|
||||
void u_array_printf(unsigned char *data, unsigned int len);
|
||||
|
||||
#define pr u_printf
|
||||
#define sprf u_sprintf
|
||||
#define array_prf u_array_printf
|
||||
36
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/utils.c
Normal file
36
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/utils.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_ieee802154.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "main.h"
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc\lp_uart_reg.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }
|
||||
|
||||
uint32_t getMillis() { return (uint32_t) (esp_timer_get_time() / 1000); }
|
||||
|
||||
void init_nvs()
|
||||
{
|
||||
// Initialize NVS
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( ret );
|
||||
}
|
||||
5
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/utils.h
Normal file
5
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/utils.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void delay(int ms);
|
||||
uint32_t getMillis();
|
||||
void init_nvs();
|
||||
1825
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig
Normal file
1825
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig
Normal file
File diff suppressed because it is too large
Load Diff
9
ARM_Tag_FW/cc2531_OEPL/Makefile
Normal file
9
ARM_Tag_FW/cc2531_OEPL/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
CONTIKI_PROJECT = cc2531_OEPL
|
||||
|
||||
DEFINES+=MODELS_CONF_CC2531_USB_STICK=1 CC2530_RF_LOW_POWER_RX=0
|
||||
|
||||
all: $(CONTIKI_PROJECT)
|
||||
|
||||
CONTIKI = ./contiki
|
||||
CONTIKI_WITH_RIME = 1
|
||||
include $(CONTIKI)/Makefile.include
|
||||
1
ARM_Tag_FW/cc2531_OEPL/Makefile.target
Normal file
1
ARM_Tag_FW/cc2531_OEPL/Makefile.target
Normal file
@@ -0,0 +1 @@
|
||||
TARGET = cc2530dk
|
||||
3
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/.gitignore
vendored
Normal file
3
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
__pycache__
|
||||
/.idea
|
||||
/cache
|
||||
@@ -0,0 +1,3 @@
|
||||
This codebase is copied from here: https://github.com/Westwoodlabs/WAMP2023-Badge/tree/main/OpenEPaperLink-PyStation
|
||||
|
||||
All Credit belongs to the creator
|
||||
69
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/c_util.py
Normal file
69
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/c_util.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import ctypes
|
||||
|
||||
"""
|
||||
helpers to interact with c-struct based data, which we transfer with the AP
|
||||
"""
|
||||
|
||||
|
||||
def c_format(value):
|
||||
"""
|
||||
internal formatting helper for ctypes-values.
|
||||
most importantly renders array-contents as lists or hex (if the data is in bytes)
|
||||
"""
|
||||
if isinstance(value, ctypes.Array):
|
||||
if value._type_ == ctypes.c_byte or value._type_ == ctypes.c_ubyte:
|
||||
return bytes(value).hex()
|
||||
else:
|
||||
return [str(v) for v in value]
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
|
||||
def c_pretty(inst):
|
||||
"""
|
||||
decorator for ctypes.Structure classes, which adds automatic pretty-printing
|
||||
"""
|
||||
def __repr__(self) -> str:
|
||||
values = ", ".join(f"{name}={c_format(value)}" for name, value in self._asdict().items())
|
||||
return f"<{self.__class__.__name__}: {values}>"
|
||||
|
||||
def _asdict(self) -> dict:
|
||||
return {field[0]: getattr(self, field[0]) for field in self._fields_}
|
||||
|
||||
inst.__repr__ = __repr__
|
||||
inst._asdict = _asdict
|
||||
return inst
|
||||
|
||||
|
||||
def hex_reverse_bytes(val, delimiter=":"):
|
||||
"""
|
||||
reverses (by copy) the given bytearray and encodes it as colon-delimited hex.
|
||||
this is mostly used to pretty-print tag MAC addresses, which are transferred in reverse
|
||||
"""
|
||||
reversed = bytes(val)[::-1]
|
||||
return reversed.hex() if delimiter is None else reversed.hex(delimiter)
|
||||
|
||||
|
||||
def hex_bytes(val, delimiter=None):
|
||||
"""
|
||||
encodes the given bytes / bytes-convertable into a (optionally delimited) hex-string
|
||||
"""
|
||||
return bytes(val).hex() if delimiter is None else bytes(val).hex(delimiter)
|
||||
|
||||
|
||||
def try_decode(buffer, prefix, typ):
|
||||
"""
|
||||
tries to decode the given c-struct (typ) from the given buffer,
|
||||
if the buffer starts with the given prefix.
|
||||
also returns an indicator, whether the buffer might be decodable to this
|
||||
type, if the buffer gets more contents / longer.
|
||||
"""
|
||||
if len(buffer) < len(prefix):
|
||||
may_match = buffer == prefix[:len(buffer)]
|
||||
return may_match, None
|
||||
may_match = buffer[:len(prefix)] == prefix
|
||||
if may_match and len(buffer) >= len(prefix) + ctypes.sizeof(typ):
|
||||
val = typ.from_buffer_copy(buffer, len(prefix))
|
||||
buffer[:ctypes.sizeof(typ) + len(prefix)] = b''
|
||||
return True, val
|
||||
return may_match, None
|
||||
42
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/db.py
Normal file
42
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/db.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import json
|
||||
import os
|
||||
from json import JSONDecodeError
|
||||
from typing import Callable, Any, List
|
||||
|
||||
"""
|
||||
a stupid, trivial and probably suboptimal database implementation,
|
||||
that we use to preserve some runtime-information about tags
|
||||
"""
|
||||
|
||||
|
||||
class TagDb:
|
||||
def __init__(self):
|
||||
self.tags = {}
|
||||
self.listeners: List[Callable[[dict], Any]] = []
|
||||
|
||||
def get_tag(self, mac):
|
||||
if mac not in self.tags:
|
||||
self.tags[mac] = {}
|
||||
return self.tags[mac]
|
||||
|
||||
def save(self):
|
||||
os.makedirs('cache', exist_ok=True)
|
||||
with open('cache/tagdb.json', 'wt') as f:
|
||||
json.dump(self.tags, f, indent=4)
|
||||
|
||||
def load(self):
|
||||
if os.path.exists("cache/tagdb.json"):
|
||||
try:
|
||||
with open("cache/tagdb.json", 'rt') as f:
|
||||
self.tags = json.load(f)
|
||||
for listener in self.listeners:
|
||||
listener(self.tags)
|
||||
except JSONDecodeError:
|
||||
print("tagdb.json is invalid. ignoring")
|
||||
|
||||
def notify_change(self, tag_key):
|
||||
for listener in self.listeners:
|
||||
listener({tag_key: self.tags[tag_key]})
|
||||
|
||||
def on_update(self, listener: Callable[[dict], Any]):
|
||||
self.listeners.append(listener)
|
||||
274
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/main.py
Normal file
274
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/main.py
Normal file
@@ -0,0 +1,274 @@
|
||||
import time
|
||||
|
||||
import serial
|
||||
import ctypes
|
||||
import hashlib
|
||||
import typing
|
||||
import logging
|
||||
from db import TagDb
|
||||
from pic_fs import PicFS
|
||||
from time import sleep
|
||||
from c_util import hex_reverse_bytes, hex_bytes
|
||||
from proto_def import AvailableDataRequest, AvailDataInfo, BlockRequest, BlockHeader, XferComplete
|
||||
|
||||
|
||||
BLOCK_SIZE = 4096
|
||||
T = typing.TypeVar('T')
|
||||
|
||||
ser = serial.Serial("COM26", 115200, timeout=0.1)
|
||||
ser.flushInput()
|
||||
|
||||
start = 0
|
||||
arr = bytearray(BLOCK_SIZE)
|
||||
arrIn = bytearray(BLOCK_SIZE)
|
||||
rx_state = 0
|
||||
last_rx_millis = 0
|
||||
bytesRemain = 0
|
||||
byteInCount = 0
|
||||
class Logic:
|
||||
db = TagDb()
|
||||
pic = PicFS()
|
||||
def __init__(self):
|
||||
self.log = logging.getLogger("logic")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
def cmpare(self, array, string):
|
||||
if array == string:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def parseUart(self, cha):
|
||||
global rx_state
|
||||
global last_rx_millis
|
||||
global arr
|
||||
global arrIn
|
||||
global bytesRemain
|
||||
global byteInCount
|
||||
|
||||
if round(time.time()*1000) - last_rx_millis > 25:
|
||||
rx_state = 0
|
||||
last_rx_millis = round(time.time()*1000)
|
||||
if rx_state == 0: #ZBS_RX_WAIT_HEADER
|
||||
arr[0] = arr[1]
|
||||
arr[1] = arr[2]
|
||||
arr[2] = arr[3]
|
||||
arr[3] = cha
|
||||
if self.cmpare(arr[0:4], b"ADR>"):
|
||||
rx_state = 1 #ZBS_RX_WAIT_SDA
|
||||
bytesRemain = 30
|
||||
byteInCount = 0
|
||||
elif self.cmpare(arr[0:4], b"RQB>"):
|
||||
rx_state = 2 #ZBS_RX_WAIT_RQB
|
||||
bytesRemain = 18
|
||||
byteInCount = 0
|
||||
elif self.cmpare(arr[0:4], b"XFC>"):
|
||||
rx_state = 3 #ZBS_RX_WAIT_XFC
|
||||
bytesRemain = 9
|
||||
byteInCount = 0
|
||||
elif self.cmpare(arr[0:4], b"ACK>"):
|
||||
print("ACKed")
|
||||
rx_state = 0 #ZBS_RX_WAIT_HEADER
|
||||
elif rx_state == 1: #ZBS_RX_WAIT_SDA
|
||||
arrIn[byteInCount] = cha
|
||||
byteInCount = byteInCount + 1
|
||||
bytesRemain = bytesRemain-1
|
||||
if bytesRemain == 0:
|
||||
rx_state = 0 #ZBS_RX_WAIT_HEADER
|
||||
data_request = AvailableDataRequest.from_buffer_copy(arrIn)
|
||||
self.handle_adr(data_request);
|
||||
elif rx_state == 2: #ZBS_RX_WAIT_RQB
|
||||
arrIn[byteInCount] = cha
|
||||
byteInCount = byteInCount + 1
|
||||
bytesRemain = bytesRemain-1
|
||||
if bytesRemain == 0:
|
||||
rx_state = 0 #ZBS_RX_WAIT_HEADER
|
||||
block_request = BlockRequest.from_buffer_copy(arrIn)
|
||||
self.handle_rqb(block_request);
|
||||
elif rx_state == 3: #ZBS_RX_WAIT_XFC
|
||||
arrIn[byteInCount] = cha
|
||||
byteInCount = byteInCount + 1
|
||||
bytesRemain = bytesRemain-1
|
||||
if bytesRemain == 0:
|
||||
rx_state = 0 #ZBS_RX_WAIT_HEADER
|
||||
xfer_request = XferComplete.from_buffer_copy(arrIn)
|
||||
self.handle_xfc(xfer_request);
|
||||
|
||||
|
||||
|
||||
def main_loop(self):
|
||||
global start
|
||||
while True:
|
||||
b = ser.read(1)
|
||||
if len(b):
|
||||
self.parseUart(b[0])
|
||||
|
||||
def handle_adr(self, adr: AvailableDataRequest):
|
||||
data_type = 0;
|
||||
"""
|
||||
handles an AvailableDataRequest, which is issued by the AP
|
||||
whenever a tag checks-in with the AP. The tag provides some
|
||||
useful data - which we store.
|
||||
we then check, if there is new data available for the tag -
|
||||
hence the method name. if so, we generate an AvailDataInfo,
|
||||
which the AP will deliver to the tag on its next check-in
|
||||
"""
|
||||
self.log.debug(f"{adr}")
|
||||
pretty_mac = hex_reverse_bytes(adr.sourceMac)
|
||||
self.log.info(f"Checkin from MAC {pretty_mac}")
|
||||
# lookup the tag in the DB, might create it, if it's new
|
||||
tag = self.db.get_tag(pretty_mac)
|
||||
tag['lastCheckin'] = int(time.time())
|
||||
if adr.lastPacketLQI != 0:
|
||||
tag['lastPacketLQI'] = adr.lastPacketLQI
|
||||
if adr.lastPacketRSSI != 0:
|
||||
tag['lastPacketRSSI'] = adr.lastPacketRSSI
|
||||
if adr.temperature != 0:
|
||||
tag['temperature'] = adr.temperature
|
||||
if adr.batteryMv != 0:
|
||||
tag['batteryMv'] = adr.batteryMv
|
||||
tag['hwType'] = adr.hwType
|
||||
|
||||
mac = hex_reverse_bytes(adr.sourceMac, None)
|
||||
if self.pic.has_image(mac + ".bin"):
|
||||
# type 0x03 firmware update
|
||||
data_type = 0x03
|
||||
data = self.pic.get_image(mac + ".bin", data_type)
|
||||
elif self.pic.has_image(mac + ".png"):
|
||||
# we just assume, the picture and tag are bi-color (black and red)
|
||||
# type 0x20 would be "just black"
|
||||
data_type = 0x21
|
||||
data = self.pic.get_image(mac + ".png", data_type)
|
||||
else:
|
||||
self.log.info(f"No image found for {pretty_mac}")
|
||||
return
|
||||
|
||||
# the tag and AP firmware uses a 64-bit "version" to check, whether
|
||||
# it has an up-to date image. we currently just use half of a MD5-hash
|
||||
# of a picture to generate a new value, if the picture data changes.
|
||||
md5 = hashlib.md5(data).digest()
|
||||
data_version = hex_bytes(md5[:8])
|
||||
|
||||
# out tag-db knows (caches) which imageVersion was last acknowledged (XFC-command)
|
||||
# by the tag / AP. if the tags current image version is identical to our local image version,
|
||||
# the tag is up-to-date
|
||||
if 'imageVersion' not in tag or tag['imageVersion'] != data_version:
|
||||
tag['pendingVersion'] = data_version
|
||||
|
||||
sda = AvailDataInfo(
|
||||
checksum=0,
|
||||
dataVer=(ctypes.c_ubyte * 8).from_buffer_copy(md5[:8]),
|
||||
dataSize=len(data),
|
||||
dataType=data_type,
|
||||
# the tag firmware know multiple "LUT"s (whatever that means).
|
||||
# it seems to be related to the updating of the epaper contents.
|
||||
# EPD_LUT_DEFAULT 0
|
||||
# EPD_LUT_NO_REPEATS 1
|
||||
# EPD_LUT_FAST_NO_REDS 2
|
||||
# EPD_LUT_FAST 3
|
||||
dataTypeArgument=1,
|
||||
nextCheckIn=0, # default taken from ESP firmware
|
||||
attemptsLeft=60 * 24, # default taken from ESP firmware
|
||||
targetMac=adr.sourceMac,
|
||||
)
|
||||
# OpenEPaper checksums seem to be quite literal "checksums" even though they call them CRCs
|
||||
# in their firmware. they're just 8- or 16-bit integers, which overflow while adding.
|
||||
# we recreate this native overflow behaviour by MOD-0x100-ing them
|
||||
sda.checksum = sum(bytes(sda)[1:]) % 0x100
|
||||
self.log.info(f"Tag needs new data. sending {sda}")
|
||||
ser.write(b'SDA>')
|
||||
ser.write(bytes(sda))
|
||||
else:
|
||||
self.log.info("Tag image is up to date")
|
||||
self.db.notify_change(pretty_mac)
|
||||
# persist our database changes
|
||||
# NOTE: this is stupid, simple and lazy database implementation,
|
||||
# but sufficient for now. we can change to something fancy later.
|
||||
self.db.save()
|
||||
|
||||
def handle_rqb(self, rqb: BlockRequest):
|
||||
"""
|
||||
Handles a BlockRequest, which is issued by the AP when it needs data
|
||||
to transfer to a tag. data is split-up into blocks of 4096 bytes, prefixed
|
||||
with a header and sent with a special encoding (XORd with 0xAA) - only god
|
||||
knows why, as this only makes sense, if the receiver can recover timing info
|
||||
from the signal (maybe?)
|
||||
"""
|
||||
data_type = 0
|
||||
filename = ""
|
||||
self.log.debug(f"{rqb}")
|
||||
self.log.info(f"Got RQB for MAC {hex_reverse_bytes(rqb.srcMac)}")
|
||||
mac = hex_reverse_bytes(rqb.srcMac, None)
|
||||
if self.pic.has_image(mac + ".bin"):
|
||||
data_type = 0x03
|
||||
filename = mac + ".bin"
|
||||
cancel = False
|
||||
elif self.pic.has_image(mac + ".png"):
|
||||
data_type = 0x21
|
||||
filename = mac + ".png"
|
||||
cancel = False
|
||||
else:
|
||||
self.log.warning(f"No image found for {hex_reverse_bytes(rqb.srcMac)}")
|
||||
cancel = True
|
||||
|
||||
if cancel:
|
||||
# cancel block request
|
||||
self.log.info("Sending: cancel block request")
|
||||
cxd = AvailDataInfo(targetMac=rqb.srcMac)
|
||||
cxd.checksum = sum(bytes(cxd)[1:]) & 0x100
|
||||
ser.write(b'CXD>')
|
||||
ser.write(bytes(cxd))
|
||||
else:
|
||||
# we just assume, that the data is black-and-red (0x21) - see handle_adr()
|
||||
data = self.pic.get_image(filename, data_type)
|
||||
offset = rqb.blockId * BLOCK_SIZE
|
||||
length = min(len(data) - offset, BLOCK_SIZE)
|
||||
self.log.info(f"Transmitting block {rqb.blockId} of length {length}")
|
||||
transmit_data = data[offset:offset + length]
|
||||
self.log.debug(f"Block bytes: {transmit_data.hex()}")
|
||||
header = bytes(BlockHeader(
|
||||
length=length,
|
||||
# see handle_adr() for checksum-foo
|
||||
checksum=sum(transmit_data) % 0x10000
|
||||
))
|
||||
ser.write(b'>D>')
|
||||
# waiting for a little bit, but not too long, seems to be required for successful transmission.
|
||||
# this may be due to the fact, that serial-command processing and the below bulk-transfer are
|
||||
# separate processes, as the below bulk-transfer is implemented as a kind of interrupt-driven DMA
|
||||
# in the AP.
|
||||
sleep(.05)
|
||||
# the AP-firmware XORs the data back on retrieval
|
||||
ser.write(bytes(b ^ 0xAA for b in header))
|
||||
ser.write(bytes(b ^ 0xAA for b in transmit_data))
|
||||
# the AP-firmware expects bulk-transfers to always be 4100 bytes (due to the DMA mechanism)
|
||||
# thus we need to fill the block with junk (0xFF when unXORd in this case)
|
||||
ser.write(bytes([0xAA] * (BLOCK_SIZE - length)))
|
||||
|
||||
def handle_xfc(self, val: XferComplete):
|
||||
"""
|
||||
handles a XFC (transfer-complete) message, which is issued by the AP,
|
||||
when it "knows" that a tag has fully received the data, announced by a previous
|
||||
AvailDataInfo. this may happen without any actual data-transfer - e.g. if the
|
||||
tag has fetched the data from EPROM
|
||||
"""
|
||||
pretty_mac = hex_reverse_bytes(val.srcMac)
|
||||
mac = hex_reverse_bytes(val.srcMac, None)
|
||||
self.log.info(f"Got XFC for Mac {pretty_mac}")
|
||||
tag = self.db.get_tag(pretty_mac)
|
||||
if 'pendingVersion' not in tag:
|
||||
# should not happen but also is uncritical
|
||||
self.log.warning("WARNING: pendingVersion not found on XFC")
|
||||
else:
|
||||
# persist fact, that the tags imageVersion now is identical to its pendingVersion
|
||||
tag['imageVersion'] = tag['pendingVersion']
|
||||
if self.pic.has_image(mac + ".bin"):
|
||||
self.pic.remove_image(mac + ".bin")
|
||||
self.db.notify_change(pretty_mac)
|
||||
self.db.save()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
Logic().main_loop()
|
||||
86
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/pic_fs.py
Normal file
86
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/pic_fs.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from PIL import Image
|
||||
from bitarray import bitarray
|
||||
import os
|
||||
|
||||
"""
|
||||
helper for loading pictures from the filesystem.
|
||||
"""
|
||||
|
||||
|
||||
class PicFS:
|
||||
def __init__(self):
|
||||
# caches preload and -converted image-data for faster retrieval
|
||||
# this is actually quite critical, as RQB (AP BlockRequests) must
|
||||
# be responded to very timely (within a couple dozen milliseconds)
|
||||
self.data_cache = {}
|
||||
|
||||
def _get_path(self, image_path):
|
||||
# TODO: make picture path better / configurable
|
||||
return "cache/" + image_path
|
||||
|
||||
def has_image(self, image_path):
|
||||
return os.path.exists(self._get_path(image_path))
|
||||
|
||||
def get_image(self, image_path, data_type):
|
||||
"""
|
||||
gets the given image from cache (if present)
|
||||
or loads it otherwise.
|
||||
TODO: add a mechanism to dispose of stale entries,
|
||||
as they accumulate memory indefinitely right now
|
||||
"""
|
||||
mtime = os.path.getmtime(self._get_path(image_path))
|
||||
key = (image_path, data_type, mtime)
|
||||
if key in self.data_cache:
|
||||
return self.data_cache[key]
|
||||
data = self.load_image(image_path, data_type)
|
||||
self.data_cache[key] = data
|
||||
return data
|
||||
|
||||
def remove_image(self, image_path):
|
||||
"""
|
||||
removes the given image from cache (if present)
|
||||
"""
|
||||
for key in list(self.data_cache.keys()):
|
||||
if key[0] == image_path:
|
||||
del self.data_cache[key]
|
||||
os.remove(self._get_path(image_path))
|
||||
|
||||
def load_image(self, image_path, data_type):
|
||||
if data_type == 0x20:
|
||||
# just black
|
||||
colors = [(0x00, 0x00, 0x00)]
|
||||
elif data_type == 0x21:
|
||||
colors = [(0x00, 0x00, 0x00), (0xFF, 0x00, 0x00)]
|
||||
elif data_type == 0x03:
|
||||
# firmware update
|
||||
colors = []
|
||||
else:
|
||||
raise "no such data_type " + str(data_type)
|
||||
|
||||
if data_type == 0x03:
|
||||
with open(self._get_path(image_path), 'rb') as file:
|
||||
return bytearray(file.read())
|
||||
else:
|
||||
|
||||
image = Image.open(self._get_path(image_path))
|
||||
width, height = image.size
|
||||
pixel_colors = bitarray()
|
||||
|
||||
# the tag picture format is:
|
||||
# - one full frame per color
|
||||
# - each frame consist of $height columns of $with pixels
|
||||
# Note: so the image is rotated by 90-deg
|
||||
# - each column (line from src image) is transferred in reverse
|
||||
# - each pixel is one bit (the epaper only knows "WHITE" (0) or "COLOR" (1))
|
||||
# due to the below algorithm, all colors, except for exact matches of the defined
|
||||
# colors, are ignored (remain white)
|
||||
for c in colors: # one frame per color
|
||||
for x in range(width - 1, -1, -1): # transfer lines (columns in output) in reverse
|
||||
for y in range(height):
|
||||
pixel = image.getpixel((x, y))
|
||||
is_similar = abs(pixel[0] - c[0]) < 128 \
|
||||
and abs(pixel[1] - c[1]) < 128 \
|
||||
and abs(pixel[2] - c[2]) < 128
|
||||
# each pixel is on bit (True or False)
|
||||
pixel_colors.append(is_similar)
|
||||
return pixel_colors.tobytes() # bitarray handles packing of 8-booleans to one byte
|
||||
68
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/proto_def.py
Normal file
68
ARM_Tag_FW/cc2531_OEPL/OpenEPaperLink-PyStation/proto_def.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import ctypes
|
||||
|
||||
from c_util import c_pretty
|
||||
|
||||
"""
|
||||
c-structures are copies from AP firmware.
|
||||
used for serial communication.
|
||||
"""
|
||||
|
||||
|
||||
@c_pretty
|
||||
class AvailableDataRequest(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('outerChecksum', ctypes.c_uint8),
|
||||
('sourceMac', ctypes.c_uint8 * 8),
|
||||
('innerChecksum', ctypes.c_uint8),
|
||||
('lastPacketLQI', ctypes.c_uint8),
|
||||
('lastPacketRSSI', ctypes.c_int8),
|
||||
('temperature', ctypes.c_int8),
|
||||
('batteryMv', ctypes.c_uint16),
|
||||
('hwType', ctypes.c_uint8),
|
||||
('wakeupReason', ctypes.c_uint8),
|
||||
)
|
||||
|
||||
|
||||
@c_pretty
|
||||
class AvailDataInfo(ctypes.Structure):
|
||||
_pack_ = 1
|
||||
_fields_ = (
|
||||
('checksum', ctypes.c_uint8),
|
||||
('dataVer', ctypes.c_uint8 * 8), # MD5 (first half) of potential traffic
|
||||
('dataSize', ctypes.c_uint32),
|
||||
('dataType', ctypes.c_uint8), # allows for 16 different datatypes
|
||||
# extra specification or instruction for the tag (LUT to be used for drawing image)
|
||||
('dataTypeArgument', ctypes.c_uint8),
|
||||
('nextCheckIn', ctypes.c_uint16), # when should the tag check-in again? Measured in minutes
|
||||
('attemptsLeft', ctypes.c_uint16),
|
||||
('targetMac', ctypes.c_uint8 * 8),
|
||||
)
|
||||
|
||||
|
||||
@c_pretty
|
||||
class BlockRequest(ctypes.Structure):
|
||||
_pack_ = 1
|
||||
_fields_ = (
|
||||
('checksum', ctypes.c_uint8),
|
||||
('dataVer', ctypes.c_uint8 * 8), # MD5 (first half) of potential traffic
|
||||
('blockId', ctypes.c_uint8),
|
||||
('srcMac', ctypes.c_uint8 * 8),
|
||||
)
|
||||
|
||||
|
||||
@c_pretty
|
||||
class BlockHeader(ctypes.Structure):
|
||||
_pack_ = 1
|
||||
_fields_ = (
|
||||
('length', ctypes.c_uint16),
|
||||
('checksum', ctypes.c_uint16),
|
||||
)
|
||||
|
||||
|
||||
@c_pretty
|
||||
class XferComplete(ctypes.Structure):
|
||||
_pack_ = 1
|
||||
_fields_ = (
|
||||
('checksum', ctypes.c_uint8),
|
||||
('srcMac', ctypes.c_uint8 * 8),
|
||||
)
|
||||
931
ARM_Tag_FW/cc2531_OEPL/cc2531_OEPL.c
Normal file
931
ARM_Tag_FW/cc2531_OEPL/cc2531_OEPL.c
Normal file
@@ -0,0 +1,931 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "contiki.h"
|
||||
#include "net/packetbuf.h"
|
||||
#include "debug.h"
|
||||
#include "lib/ringbuf.h"
|
||||
#include "contiki-conf.h"
|
||||
#include "dev/io-arch.h"
|
||||
#include "net/netstack.h"
|
||||
#include "proto.h"
|
||||
|
||||
static struct etimer et;
|
||||
#define BUFSIZE 128
|
||||
uint8_t cmd_buf[BUFSIZE];
|
||||
static struct ringbuf rxbuf;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
||||
|
||||
void radioTx1(uint8_t *buff)
|
||||
{
|
||||
NETSTACK_RADIO.send((uint8_t *)&buff[1], buff[0] - 2);
|
||||
}
|
||||
|
||||
void radioTx(uint8_t *buff)
|
||||
{
|
||||
clock_delay_usec(500);
|
||||
NETSTACK_RADIO.send((uint8_t *)&buff[1], buff[0] - 2);
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define bool uint8_t
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define HW_TYPE 0xFF
|
||||
|
||||
#define MAX_PENDING_MACS 6
|
||||
#define HOUSEKEEPING_INTERVAL 60UL
|
||||
|
||||
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
||||
|
||||
// VERSION GOES HERE!
|
||||
uint16_t version = 0x0017;
|
||||
|
||||
#define RAW_PKT_PADDING 2
|
||||
|
||||
uint8_t radiotxbuffer[128];
|
||||
uint8_t radiorxbuffer[128];
|
||||
|
||||
uint8_t mSelfMac[8];
|
||||
|
||||
struct blockRequest requestedData = {0}; // holds which data was requested by the tag
|
||||
|
||||
uint8_t dstMac[8]; // target for the block transfer
|
||||
uint16_t dstPan; //
|
||||
|
||||
static uint32_t blockStartTimer = 0; // reference that holds when the AP sends the next block
|
||||
// extern bool __idata serialBypassActive; // if the serial bypass is disabled, saves bytes straight to the block buffer
|
||||
uint32_t nextBlockAttempt = 0; // reference time for when the AP can request a new block from the ESP32
|
||||
uint8_t seq = 0; // holds current sequence number for transmission
|
||||
uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE + 5]; // block transfer buffer
|
||||
uint8_t lastAckMac[8] = {0};
|
||||
|
||||
uint8_t *blockXferBuffer = blockbuffer;
|
||||
|
||||
// these variables hold the current mac were talking to
|
||||
#define CONCURRENT_REQUEST_DELAY (1200UL / 8)
|
||||
uint32_t lastBlockRequest = 0;
|
||||
uint8_t lastBlockMac[8];
|
||||
|
||||
uint8_t curChannel = 11;
|
||||
uint8_t curPower = 10;
|
||||
|
||||
uint8_t curPendingData = 0;
|
||||
uint8_t curNoUpdate = 0;
|
||||
|
||||
void sendXferCompleteAck(uint8_t *dst);
|
||||
void sendCancelXfer(uint8_t *dst);
|
||||
void espNotifyAPInfo();
|
||||
|
||||
// tools
|
||||
void addCRC(void *p, uint8_t len)
|
||||
{
|
||||
uint8_t total = 0;
|
||||
for (uint8_t c = 1; c < len; c++)
|
||||
{
|
||||
total += ((uint8_t *)p)[c];
|
||||
}
|
||||
((uint8_t *)p)[0] = total;
|
||||
}
|
||||
bool checkCRC(void *p, uint8_t len)
|
||||
{
|
||||
uint8_t total = 0;
|
||||
for (uint8_t c = 1; c < len; c++)
|
||||
{
|
||||
total += ((uint8_t *)p)[c];
|
||||
}
|
||||
return ((uint8_t *)p)[0] == total;
|
||||
}
|
||||
|
||||
uint8_t getPacketType(void *buffer)
|
||||
{
|
||||
struct MacFcs *fcs = buffer;
|
||||
if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0))
|
||||
{
|
||||
// broadcast frame
|
||||
uint8_t type = ((uint8_t *)buffer)[sizeof(struct MacFrameBcast)];
|
||||
return type;
|
||||
}
|
||||
else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1))
|
||||
{
|
||||
// normal frame
|
||||
uint8_t type = ((uint8_t *)buffer)[sizeof(struct MacFrameNormal)];
|
||||
return type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint8_t getBlockDataLength()
|
||||
{
|
||||
uint8_t partNo = 0;
|
||||
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++)
|
||||
{
|
||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8)))
|
||||
{
|
||||
partNo++;
|
||||
}
|
||||
}
|
||||
return partNo;
|
||||
}
|
||||
|
||||
// pendingdata slot stuff
|
||||
int8_t findSlotForMac(const uint8_t *mac)
|
||||
{
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++)
|
||||
{
|
||||
// if (u64_isEq((uint64_t *)mac, (uint64_t *)&(pendingDataArr[c].targetMac))) { // this costs 1 sloc :(
|
||||
if (memcmp(mac, ((uint8_t *)&(pendingDataArr[c].targetMac)), 8) == 0)
|
||||
{
|
||||
if (pendingDataArr[c].attemptsLeft != 0)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int8_t findFreeSlot()
|
||||
{
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++)
|
||||
{
|
||||
if (pendingDataArr[c].attemptsLeft == 0)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int8_t findSlotForVer(const uint8_t *ver)
|
||||
{
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++)
|
||||
{
|
||||
// if (u64_isEq((uint64_t *)ver, (uint64_t *)&(pendingDataArr[c].availdatainfo.dataVer))) {
|
||||
if (memcmp(ver, ((uint8_t *)&(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0)
|
||||
{
|
||||
if (pendingDataArr[c].attemptsLeft != 0)
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void deleteAllPendingDataForVer(const uint8_t *ver)
|
||||
{
|
||||
int8_t slot = -1;
|
||||
do
|
||||
{
|
||||
slot = findSlotForVer(ver);
|
||||
if (slot != -1)
|
||||
pendingDataArr[slot].attemptsLeft = 0;
|
||||
} while (slot != -1);
|
||||
}
|
||||
void deleteAllPendingDataForMac(const uint8_t *mac)
|
||||
{
|
||||
int8_t slot = -1;
|
||||
do
|
||||
{
|
||||
slot = findSlotForMac(mac);
|
||||
if (slot != -1)
|
||||
pendingDataArr[slot].attemptsLeft = 0;
|
||||
} while (slot != -1);
|
||||
}
|
||||
|
||||
void countSlots()
|
||||
{
|
||||
curPendingData = 0;
|
||||
curNoUpdate = 0;
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++)
|
||||
{
|
||||
if (pendingDataArr[c].attemptsLeft != 0)
|
||||
{
|
||||
if (pendingDataArr[c].availdatainfo.dataType != 0)
|
||||
{
|
||||
curPendingData++;
|
||||
}
|
||||
else
|
||||
{
|
||||
curNoUpdate++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processing serial data
|
||||
#define ZBS_RX_WAIT_HEADER 0
|
||||
#define ZBS_RX_WAIT_SDA 1 // send data avail
|
||||
#define ZBS_RX_WAIT_CANCEL 2 // cancel traffic for mac
|
||||
#define ZBS_RX_WAIT_SCP 3 // set channel power
|
||||
|
||||
#define ZBS_RX_WAIT_BLOCKDATA 4
|
||||
|
||||
int blockPosition = 0;
|
||||
void processSerial(uint8_t lastchar)
|
||||
{
|
||||
static uint8_t cmdbuffer[4];
|
||||
static uint8_t RXState = 0;
|
||||
static uint8_t serialbuffer[48];
|
||||
static uint8_t *serialbufferp;
|
||||
static uint8_t bytesRemain = 0;
|
||||
|
||||
static uint32_t lastSerial = 0;
|
||||
if ((clock_time() - lastSerial) > (800 / 8))
|
||||
{
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
lastSerial = clock_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
lastSerial = clock_time();
|
||||
}
|
||||
// uartTx(lastchar); echo
|
||||
switch (RXState)
|
||||
{
|
||||
case ZBS_RX_WAIT_HEADER:
|
||||
// shift characters in
|
||||
for (uint8_t c = 0; c < 3; c++)
|
||||
{
|
||||
cmdbuffer[c] = cmdbuffer[c + 1];
|
||||
}
|
||||
cmdbuffer[3] = lastchar;
|
||||
|
||||
if (strncmp(cmdbuffer + 1, ">D>", 3) == 0)
|
||||
{
|
||||
putstring("ACK>\n");
|
||||
blockPosition = 0;
|
||||
RXState = ZBS_RX_WAIT_BLOCKDATA;
|
||||
}
|
||||
|
||||
if (strncmp(cmdbuffer, "SDA>", 4) == 0)
|
||||
{
|
||||
RXState = ZBS_RX_WAIT_SDA;
|
||||
bytesRemain = sizeof(struct pendingData);
|
||||
serialbufferp = serialbuffer;
|
||||
break;
|
||||
}
|
||||
if (strncmp(cmdbuffer, "CXD>", 4) == 0)
|
||||
{
|
||||
RXState = ZBS_RX_WAIT_CANCEL;
|
||||
bytesRemain = sizeof(struct pendingData);
|
||||
serialbufferp = serialbuffer;
|
||||
break;
|
||||
}
|
||||
if (strncmp(cmdbuffer, "SCP>", 4) == 0)
|
||||
{
|
||||
RXState = ZBS_RX_WAIT_SCP;
|
||||
bytesRemain = sizeof(struct espSetChannelPower);
|
||||
serialbufferp = serialbuffer;
|
||||
break;
|
||||
}
|
||||
if (strncmp(cmdbuffer, "NFO?", 4) == 0)
|
||||
{
|
||||
putstring("ACK>");
|
||||
espNotifyAPInfo();
|
||||
}
|
||||
if (strncmp(cmdbuffer, "RDY?", 4) == 0)
|
||||
{
|
||||
putstring("ACK>");
|
||||
}
|
||||
if (strncmp(cmdbuffer, "RSET", 4) == 0)
|
||||
{
|
||||
putstring("ACK>");
|
||||
// timerDelay(100);
|
||||
/*CFGPAGE = 4;
|
||||
WDTCONF = 0x80;
|
||||
WDTENA = 1;
|
||||
WDTRSTVALH = 0xff;
|
||||
WDTRSTVALM = 0xff;
|
||||
WDTRSTVALL = 0xff;
|
||||
while(1);*/
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_BLOCKDATA:
|
||||
blockbuffer[blockPosition++] = 0xAA ^ lastchar;
|
||||
if (blockPosition >= 4100)
|
||||
{
|
||||
putstring("ACK>");
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZBS_RX_WAIT_SDA:
|
||||
*serialbufferp = lastchar;
|
||||
serialbufferp++;
|
||||
bytesRemain--;
|
||||
if (bytesRemain == 0)
|
||||
{
|
||||
if (checkCRC(serialbuffer, sizeof(struct pendingData)))
|
||||
{
|
||||
struct pendingData *pd = (struct pendingData *)serialbuffer;
|
||||
int8_t slot = findSlotForMac(pd->targetMac);
|
||||
if (slot == -1)
|
||||
slot = findFreeSlot();
|
||||
if (slot != -1)
|
||||
{
|
||||
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
|
||||
putstring("ACK>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
putstring("NOQ>\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
putstring("NOK>\n");
|
||||
}
|
||||
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_CANCEL:
|
||||
*serialbufferp = lastchar;
|
||||
serialbufferp++;
|
||||
bytesRemain--;
|
||||
if (bytesRemain == 0)
|
||||
{
|
||||
if (checkCRC(serialbuffer, sizeof(struct pendingData)))
|
||||
{
|
||||
struct pendingData *pd = (struct pendingData *)serialbuffer;
|
||||
// deleteAllPendingDataForVer((uint8_t *)&pd->availdatainfo.dataVer);
|
||||
deleteAllPendingDataForMac((uint8_t *)&pd->targetMac);
|
||||
putstring("ACK>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
putstring("NOK>\n");
|
||||
}
|
||||
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_SCP:
|
||||
*serialbufferp = lastchar;
|
||||
serialbufferp++;
|
||||
bytesRemain--;
|
||||
if (bytesRemain == 0)
|
||||
{
|
||||
if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower)))
|
||||
{
|
||||
struct espSetChannelPower *scp = (struct espSetChannelPower *)serialbuffer;
|
||||
for (uint8_t c = 0; c < sizeof(channelList); c++)
|
||||
{
|
||||
if (channelList[c] == scp->channel)
|
||||
goto SCPchannelFound;
|
||||
}
|
||||
goto SCPfailed;
|
||||
SCPchannelFound:
|
||||
curChannel = scp->channel;
|
||||
curPower = scp->power;
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scp->channel);
|
||||
// NETSTACK_RADIO.set_value(RADIO_PARAM_TXPOWER, scp->power);
|
||||
putstring("ACK>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
SCPfailed:
|
||||
putstring("NOK>\n");
|
||||
}
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sending data to the ESP
|
||||
void espBlockRequest(const struct blockRequest *br, uint8_t *src)
|
||||
{
|
||||
struct espBlockRequest *ebr = (struct espBlockRequest *)blockbuffer;
|
||||
putchar('R');
|
||||
putchar('Q');
|
||||
putchar('B');
|
||||
putchar('>');
|
||||
memcpy(&(ebr->ver), &(br->ver), 8);
|
||||
memcpy(&(ebr->src), src, 8);
|
||||
ebr->blockId = br->blockId;
|
||||
addCRC(ebr, sizeof(struct espBlockRequest));
|
||||
for (uint8_t c = 0; c < sizeof(struct espBlockRequest); c++)
|
||||
{
|
||||
putchar(((uint8_t *)ebr)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyAvailDataReq(const struct AvailDataReq *adr, const uint8_t *src)
|
||||
{
|
||||
putchar('A');
|
||||
putchar('D');
|
||||
putchar('R');
|
||||
putchar('>');
|
||||
|
||||
struct espAvailDataReq eadr = {0};
|
||||
memcpy((void *)eadr.src, (void *)src, 8);
|
||||
memcpy((void *)&eadr.adr, (void *)adr, sizeof(struct AvailDataReq));
|
||||
addCRC(&eadr, sizeof(struct espAvailDataReq));
|
||||
for (uint8_t c = 0; c < sizeof(struct espAvailDataReq); c++)
|
||||
{
|
||||
putchar(((uint8_t *)eadr)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyXferComplete(const uint8_t *src)
|
||||
{
|
||||
struct espXferComplete exfc;
|
||||
memcpy(&exfc.src, src, 8);
|
||||
putchar('X');
|
||||
putchar('F');
|
||||
putchar('C');
|
||||
putchar('>');
|
||||
addCRC(&exfc, sizeof(exfc));
|
||||
for (uint8_t c = 0; c < sizeof(exfc); c++)
|
||||
{
|
||||
putchar(((uint8_t *)exfc)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyTimeOut(const uint8_t *src)
|
||||
{
|
||||
struct espXferComplete exfc;
|
||||
memcpy(&exfc.src, src, 8);
|
||||
putchar('X');
|
||||
putchar('T');
|
||||
putchar('O');
|
||||
putchar('>');
|
||||
addCRC(&exfc, sizeof(exfc));
|
||||
for (uint8_t c = 0; c < sizeof(exfc); c++)
|
||||
{
|
||||
putchar(((uint8_t *)exfc)[c]);
|
||||
}
|
||||
}
|
||||
void espNotifyAPInfo()
|
||||
{
|
||||
putstring("TYP>");
|
||||
puthex(HW_TYPE);
|
||||
putchar('\n');
|
||||
|
||||
putstring("VER>");
|
||||
puthex(version >> 8);
|
||||
puthex(version & 0xFF);
|
||||
putchar('\n');
|
||||
|
||||
putstring("MAC>");
|
||||
puthex(mSelfMac[0]);
|
||||
puthex(mSelfMac[1]);
|
||||
puthex(mSelfMac[2]);
|
||||
puthex(mSelfMac[3]);
|
||||
puthex(mSelfMac[4]);
|
||||
puthex(mSelfMac[5]);
|
||||
puthex(mSelfMac[6]);
|
||||
puthex(mSelfMac[7]);
|
||||
putchar('\n');
|
||||
|
||||
putstring("ZCH>");
|
||||
puthex(curChannel);
|
||||
putchar('\n');
|
||||
putstring("ZPW>");
|
||||
puthex(curPower);
|
||||
putchar('\n');
|
||||
|
||||
countSlots();
|
||||
|
||||
putstring("PEN>");
|
||||
puthex(curPendingData);
|
||||
putchar('\n');
|
||||
|
||||
putstring("NOP>");
|
||||
puthex(curNoUpdate);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
// process data from tag
|
||||
void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload)
|
||||
{
|
||||
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer;
|
||||
struct blockRequest *blockReq = (struct blockRequest *)(buffer + sizeof(struct MacFrameNormal) + 1);
|
||||
if (!checkCRC(blockReq, sizeof(struct blockRequest)))
|
||||
return;
|
||||
|
||||
// check if we're already talking to this mac
|
||||
if (memcmp(rxHeader->src, lastBlockMac, 8) == 0)
|
||||
{
|
||||
lastBlockRequest = clock_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we weren't talking to this mac, see if there was a transfer in progress from another mac, recently
|
||||
if ((clock_time() - lastBlockRequest) > CONCURRENT_REQUEST_DELAY)
|
||||
{
|
||||
// mark this mac as the new current mac we're talking to
|
||||
memcpy((void *)lastBlockMac, (void *)rxHeader->src, 8);
|
||||
lastBlockRequest = clock_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're talking to another mac, let this mac know we can't accomodate another request right now
|
||||
putstring("BUSY!\n");
|
||||
sendCancelXfer(rxHeader->src);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have data for this mac
|
||||
if (findSlotForMac(rxHeader->src) == -1)
|
||||
{
|
||||
// no data for this mac, politely tell it to fuck off
|
||||
sendCancelXfer(rxHeader->src);
|
||||
return;
|
||||
}
|
||||
|
||||
bool requestDataDownload = false;
|
||||
if ((blockReq->blockId != requestedData.blockId) || (!memcmp((const uint64_t *)&blockReq->ver, (const uint64_t *)&requestedData.ver, 8)))
|
||||
{
|
||||
// requested block isn't already in the buffer
|
||||
requestDataDownload = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// requested block is already in the buffer
|
||||
if (forceBlockDownload)
|
||||
{
|
||||
if ((clock_time() - nextBlockAttempt) > (400 / 8))
|
||||
{
|
||||
requestDataDownload = true;
|
||||
putstring("FORCED\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
putstring("IGNORED\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy blockrequest into requested data
|
||||
memcpy(&requestedData, blockReq, sizeof(struct blockRequest));
|
||||
|
||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
struct blockRequestAck *blockRequestAck = (struct blockRequestAck *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct blockRequestAck) + RAW_PKT_PADDING;
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST_ACK;
|
||||
|
||||
if (blockStartTimer == 0)
|
||||
{
|
||||
if (requestDataDownload)
|
||||
{
|
||||
// check if we need to download the first block; we need to give the ESP32 some additional time to cache the file
|
||||
if (blockReq->blockId == 0)
|
||||
{
|
||||
blockRequestAck->pleaseWaitMs = 600;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockRequestAck->pleaseWaitMs = 600;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// block is already in buffer
|
||||
blockRequestAck->pleaseWaitMs = 600;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
blockRequestAck->pleaseWaitMs = 600;
|
||||
}
|
||||
blockStartTimer = clock_time() + (blockRequestAck->pleaseWaitMs / 8);
|
||||
|
||||
memcpy(txHeader->src, mSelfMac, 8);
|
||||
memcpy(txHeader->dst, rxHeader->src, 8);
|
||||
|
||||
txHeader->pan = rxHeader->pan;
|
||||
txHeader->fcs.frameType = 1;
|
||||
txHeader->fcs.panIdCompressed = 1;
|
||||
txHeader->fcs.destAddrType = 3;
|
||||
txHeader->fcs.srcAddrType = 3;
|
||||
txHeader->seq = seq++;
|
||||
|
||||
addCRC((void *)blockRequestAck, sizeof(struct blockRequestAck));
|
||||
|
||||
radioTx(radiotxbuffer);
|
||||
|
||||
// save the target for the blockdata
|
||||
memcpy(dstMac, rxHeader->src, 8);
|
||||
dstPan = rxHeader->pan;
|
||||
|
||||
if (requestDataDownload)
|
||||
{
|
||||
// serialBypassActive = false;
|
||||
espBlockRequest(&requestedData, rxHeader->src);
|
||||
nextBlockAttempt = clock_time();
|
||||
}
|
||||
}
|
||||
void processAvailDataReq(uint8_t *buffer)
|
||||
{
|
||||
struct MacFrameBcast *rxHeader = (struct MacFrameBcast *)buffer;
|
||||
struct AvailDataReq *availDataReq = (struct AvailDataReq *)(buffer + sizeof(struct MacFrameBcast) + 1);
|
||||
|
||||
if (!checkCRC(availDataReq, sizeof(struct AvailDataReq)))
|
||||
return;
|
||||
|
||||
// prepare tx buffer to send a response
|
||||
memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct AvailDataInfo) + 2); // 120);
|
||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
struct AvailDataInfo *availDataInfo = (struct AvailDataInfo *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct AvailDataInfo) + RAW_PKT_PADDING;
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_AVAIL_DATA_INFO;
|
||||
|
||||
// check to see if we have data available for this mac
|
||||
bool haveData = false;
|
||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++)
|
||||
{
|
||||
if (pendingDataArr[c].attemptsLeft)
|
||||
{
|
||||
if (memcmp(pendingDataArr[c].targetMac, rxHeader->src, 8) == 0)
|
||||
{
|
||||
haveData = true;
|
||||
memcpy((void *)availDataInfo, &(pendingDataArr[c].availdatainfo), sizeof(struct AvailDataInfo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// couldn't find data for this mac
|
||||
if (!haveData)
|
||||
availDataInfo->dataType = DATATYPE_NOUPDATE;
|
||||
|
||||
memcpy(txHeader->src, mSelfMac, 8);
|
||||
memcpy(txHeader->dst, rxHeader->src, 8);
|
||||
txHeader->pan = rxHeader->dstPan;
|
||||
txHeader->fcs.frameType = 1;
|
||||
txHeader->fcs.panIdCompressed = 1;
|
||||
txHeader->fcs.destAddrType = 3;
|
||||
txHeader->fcs.srcAddrType = 3;
|
||||
txHeader->seq = seq++;
|
||||
addCRC(availDataInfo, sizeof(struct AvailDataInfo));
|
||||
radioTx(radiotxbuffer);
|
||||
memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet
|
||||
espNotifyAvailDataReq(availDataReq, rxHeader->src);
|
||||
}
|
||||
void processXferComplete(uint8_t *buffer)
|
||||
{
|
||||
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *)buffer;
|
||||
sendXferCompleteAck(rxHeader->src);
|
||||
if (memcmp(lastAckMac, rxHeader->src, 8) != 0)
|
||||
{
|
||||
memcpy((void *)lastAckMac, (void *)rxHeader->src, 8);
|
||||
espNotifyXferComplete(rxHeader->src);
|
||||
int8_t slot = findSlotForMac(rxHeader->src);
|
||||
if (slot != -1)
|
||||
pendingDataArr[slot].attemptsLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// send block data to the tag
|
||||
void sendPart(uint8_t partNo)
|
||||
{
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
struct blockPart *blockPart = (struct blockPart *)(radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PART;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, dstMac, 8);
|
||||
blockPart->blockId = requestedData.blockId;
|
||||
blockPart->blockPart = partNo;
|
||||
memcpy(&(blockPart->data), blockbuffer + (partNo * BLOCK_PART_DATA_SIZE), BLOCK_PART_DATA_SIZE);
|
||||
addCRC(blockPart, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE);
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = dstPan;
|
||||
radioTx1(radiotxbuffer);
|
||||
}
|
||||
void sendBlockData()
|
||||
{
|
||||
if (getBlockDataLength() == 0)
|
||||
{
|
||||
putstring("Invalid block request received, 0 parts..\n");
|
||||
requestedData.requestedParts[0] |= 0x01;
|
||||
}
|
||||
uint8_t partNo = 0;
|
||||
while (partNo < BLOCK_MAX_PARTS)
|
||||
{
|
||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++)
|
||||
{
|
||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8)))
|
||||
{
|
||||
sendPart(c);
|
||||
partNo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void sendXferCompleteAck(uint8_t *dst)
|
||||
{
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_XFER_COMPLETE_ACK;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, dst, 8);
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = dstPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
void sendCancelXfer(uint8_t *dst)
|
||||
{
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_CANCEL_XFER;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, dst, 8);
|
||||
frameHeader->fcs.frameType = 1;
|
||||
frameHeader->fcs.panIdCompressed = 1;
|
||||
frameHeader->fcs.destAddrType = 3;
|
||||
frameHeader->fcs.srcAddrType = 3;
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = dstPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
void sendPong(void *buf)
|
||||
{
|
||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buf;
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG;
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curChannel;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
||||
radiotxbuffer[2] = 0xCC; // normal frame
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = rxframe->srcPan;
|
||||
radioTx(radiotxbuffer);
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void process_incoming_data(void)
|
||||
{
|
||||
int c = 0;
|
||||
uint8_t byte_in;
|
||||
c = ringbuf_get(&rxbuf);
|
||||
while (c != -1)
|
||||
{
|
||||
byte_in = (uint8_t)c;
|
||||
processSerial(byte_in);
|
||||
c = ringbuf_get(&rxbuf);
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS(cc2531_usb_demo_process, "cc2531 USB Demo process");
|
||||
PROCESS(cc2531_RF, "cc2531 RF");
|
||||
AUTOSTART_PROCESSES(&cc2531_usb_demo_process, &cc2531_RF);
|
||||
|
||||
static int char_in(unsigned char c)
|
||||
{
|
||||
ringbuf_put(&rxbuf, c);
|
||||
process_poll(&cc2531_usb_demo_process);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PROCESS_THREAD(cc2531_RF, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
uint16_t short_addr;
|
||||
short_addr = mSelfMac[7];
|
||||
short_addr |= mSelfMac[6] << 8;
|
||||
|
||||
NETSTACK_RADIO.off();
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, PROTO_PAN_ID);
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr);
|
||||
NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, mSelfMac, 8);
|
||||
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, 0); // RADIO_RX_MODE_ADDRESS_FILTER);
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, 11);
|
||||
NETSTACK_RADIO.on();
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (NETSTACK_RADIO.pending_packet())
|
||||
{
|
||||
int len = NETSTACK_RADIO.read(radiorxbuffer, 128);
|
||||
if (len)
|
||||
{
|
||||
/*putstring("RX: ");
|
||||
for(int i = 0;i<len;i++){
|
||||
puthex(radiorxbuffer[i]);
|
||||
}
|
||||
putchar('\n');*/
|
||||
// received a packet, lets see what it is
|
||||
switch (getPacketType(radiorxbuffer))
|
||||
{
|
||||
case PKT_AVAIL_DATA_REQ:
|
||||
if (len == 28)
|
||||
{
|
||||
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0, sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2);
|
||||
}
|
||||
else if (len == 40)
|
||||
{
|
||||
// new version of the AvailDataReq struct
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
}
|
||||
break;
|
||||
case PKT_BLOCK_REQUEST:
|
||||
processBlockRequest(radiorxbuffer, 1);
|
||||
break;
|
||||
case PKT_BLOCK_PARTIAL_REQUEST:
|
||||
processBlockRequest(radiorxbuffer, 0);
|
||||
break;
|
||||
case PKT_XFER_COMPLETE:
|
||||
processXferComplete(radiorxbuffer);
|
||||
break;
|
||||
case PKT_PING:
|
||||
sendPong(radiorxbuffer);
|
||||
break;
|
||||
case PKT_AVAIL_DATA_SHORTREQ:
|
||||
// a short AvailDataReq is basically a very short (1 byte payload) packet that requires little preparation on the tx side, for optimal battery use
|
||||
// bytes of the struct are set 0, so it passes the checksum test, and the ESP32 can detect that no interesting payload is sent
|
||||
if (len == 18)
|
||||
{
|
||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2);
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
putstring("t=");
|
||||
puthex(getPacketType(radiorxbuffer));
|
||||
putchar('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (blockStartTimer)
|
||||
{
|
||||
// BUG: uint32 overflowing; this will break every once in a while. Don't know how to fix this other than ugly global variables
|
||||
if (clock_time() > blockStartTimer)
|
||||
{
|
||||
sendBlockData();
|
||||
blockStartTimer = 0;
|
||||
}
|
||||
}
|
||||
PROCESS_PAUSE();
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
|
||||
PROCESS_THREAD(cc2531_usb_demo_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
ringbuf_init(&rxbuf, cmd_buf, sizeof(cmd_buf));
|
||||
io_arch_set_input(&char_in);
|
||||
etimer_set(&et, CLOCK_SECOND * HOUSEKEEPING_INTERVAL);
|
||||
|
||||
unsigned char *macp = &X_IEEE_ADDR;
|
||||
requestedData.blockId = 0xFF;
|
||||
for (uint8_t c = 0; c < 8; c++)
|
||||
{
|
||||
mSelfMac[c] = *macp;
|
||||
macp++;
|
||||
}
|
||||
memset(pendingDataArr, 0, sizeof(pendingDataArr));
|
||||
|
||||
putstring("RES>\n");
|
||||
putstring("RDY>\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
PROCESS_YIELD();
|
||||
if (ev == PROCESS_EVENT_POLL)
|
||||
{
|
||||
process_incoming_data();
|
||||
}
|
||||
else if (ev == PROCESS_EVENT_TIMER)
|
||||
{
|
||||
putstring("Housekeepin\r\n");
|
||||
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++)
|
||||
{
|
||||
if (pendingDataArr[cCount].attemptsLeft == 1)
|
||||
{
|
||||
if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE)
|
||||
{
|
||||
espNotifyTimeOut(pendingDataArr[cCount].targetMac);
|
||||
}
|
||||
pendingDataArr[cCount].attemptsLeft = 0;
|
||||
}
|
||||
else if (pendingDataArr[cCount].attemptsLeft > 1)
|
||||
{
|
||||
pendingDataArr[cCount].attemptsLeft--;
|
||||
if (pendingDataArr[cCount].availdatainfo.nextCheckIn)
|
||||
pendingDataArr[cCount].availdatainfo.nextCheckIn--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
4110
ARM_Tag_FW/cc2531_OEPL/cc2531_OEPL_beta.hex
Normal file
4110
ARM_Tag_FW/cc2531_OEPL/cc2531_OEPL_beta.hex
Normal file
File diff suppressed because it is too large
Load Diff
14
ARM_Tag_FW/cc2531_OEPL/contiki/.gitattributes
vendored
Normal file
14
ARM_Tag_FW/cc2531_OEPL/contiki/.gitattributes
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto whitespace=trailing-space
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.c text
|
||||
*.h text
|
||||
*.java text
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.ihex binary
|
||||
*.s37 binary
|
||||
131
ARM_Tag_FW/cc2531_OEPL/contiki/.gitignore
vendored
Normal file
131
ARM_Tag_FW/cc2531_OEPL/contiki/.gitignore
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
*.a
|
||||
*.bin
|
||||
*.map
|
||||
*.png
|
||||
*.log
|
||||
*.elf
|
||||
*.zip
|
||||
*.d
|
||||
*.ihex
|
||||
*.pyc
|
||||
*.redbee-econotag
|
||||
*.econotag
|
||||
*.native
|
||||
*.z1
|
||||
*.minimal-net
|
||||
*.sky
|
||||
*.wismote
|
||||
*.esb
|
||||
*.avr-raven
|
||||
*.exp5438
|
||||
*.mbxxx
|
||||
*.win32
|
||||
*.apple2enh
|
||||
*.atarixl
|
||||
*.c128
|
||||
*.c64
|
||||
*.cc2538dk
|
||||
*.zoul
|
||||
*.jn516x
|
||||
*.srf06-cc26xx
|
||||
*.ev-aducrf101mkxz
|
||||
*.report
|
||||
summary
|
||||
*.summary
|
||||
*.runerr
|
||||
*.runlog
|
||||
*.faillog
|
||||
*.orig
|
||||
*~
|
||||
.DS_Store
|
||||
obj_*
|
||||
symbols.*
|
||||
Makefile.target
|
||||
doc/html
|
||||
doc/latex
|
||||
patches-*
|
||||
tools/tunslip
|
||||
tools/tunslip6
|
||||
build
|
||||
tools/coffee-manager/build/
|
||||
tools/cooja/dist/
|
||||
tools/collect-view/build/
|
||||
tools/collect-view/dist/
|
||||
COOJA.testlog
|
||||
tools/cooja/apps/mrm/lib/
|
||||
tools/cooja/apps/mspsim/lib/
|
||||
tools/cooja/apps/powertracker/lib/
|
||||
tools/cooja/apps/serial_socket/lib/
|
||||
tools/coffee-manager/coffee.jar
|
||||
tools/cooja/apps/avrora/lib/cooja_avrora.jar
|
||||
tools/cooja/apps/collect-view/cooja-collect-view.jar
|
||||
|
||||
# sdcc build artifacts
|
||||
contiki-cc2530dk.lib
|
||||
*.ihx
|
||||
*.hex
|
||||
*.mem
|
||||
*.lk
|
||||
*.omf
|
||||
*.cdb
|
||||
*.banks
|
||||
*.cc2530dk
|
||||
|
||||
# VC++ build artifacts
|
||||
*.exp
|
||||
*.ilk
|
||||
*.lib
|
||||
*.pdb
|
||||
*.prg
|
||||
*.dsc
|
||||
|
||||
#cc65 build artifacts
|
||||
*.s
|
||||
*.eth
|
||||
*.dsk
|
||||
*.po
|
||||
*.atr
|
||||
*.d64
|
||||
*.d71
|
||||
*.d81
|
||||
|
||||
# Cooja Build Artifacts
|
||||
*.cooja
|
||||
|
||||
#regression tests artifacts
|
||||
*.testlog
|
||||
*.log.prog
|
||||
regression-tests/[0-9][0-9]-*/report
|
||||
regression-tests/[0-9][0-9]-*/org/
|
||||
|
||||
# rl78 build artifacts
|
||||
*.eval-adf7xxxmb4z
|
||||
*.eval-adf7xxxmb4z.srec
|
||||
|
||||
# cscope files
|
||||
cscope.*
|
||||
|
||||
# vim swap files
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# x86 UEFI files
|
||||
cpu/x86/uefi/Makefile.uefi
|
||||
cpu/x86/uefi/edk2
|
||||
|
||||
# galileo bsp files
|
||||
platform/galileo/bsp/libc/Makefile.libc
|
||||
platform/galileo/bsp/libc/i586-elf/
|
||||
platform/galileo/bsp/libc/newlib-2.2.0-1*
|
||||
platform/galileo/bsp/grub/src/
|
||||
platform/galileo/bsp/grub/bin/
|
||||
|
||||
# galileo build and debug artefacts
|
||||
*.galileo
|
||||
*.galileo.dll
|
||||
*.galileo.efi
|
||||
LOG_OPENOCD
|
||||
|
||||
# nRF52 build artifacts
|
||||
*.jlink
|
||||
*.nrf52dk
|
||||
19
ARM_Tag_FW/cc2531_OEPL/contiki/.gitmodules
vendored
Normal file
19
ARM_Tag_FW/cc2531_OEPL/contiki/.gitmodules
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
[submodule "tools/mspsim"]
|
||||
path = tools/mspsim
|
||||
url = https://github.com/contiki-os/mspsim.git
|
||||
[submodule "tools/cc2538-bsl"]
|
||||
path = tools/cc2538-bsl
|
||||
url = https://github.com/JelmerT/cc2538-bsl.git
|
||||
[submodule "cpu/cc26xx-cc13xx/lib/cc26xxware"]
|
||||
path = cpu/cc26xx-cc13xx/lib/cc26xxware
|
||||
url = https://github.com/contiki-os/cc26xxware.git
|
||||
[submodule "cpu/cc26xx-cc13xx/lib/cc13xxware"]
|
||||
path = cpu/cc26xx-cc13xx/lib/cc13xxware
|
||||
url = https://github.com/contiki-os/cc13xxware.git
|
||||
[submodule "platform/stm32nucleo-spirit1/stm32cube-lib"]
|
||||
path = platform/stm32nucleo-spirit1/stm32cube-lib
|
||||
url = https://github.com/STclab/stm32nucleo-spirit1-lib
|
||||
|
||||
[submodule "tools/sensniff"]
|
||||
path = tools/sensniff
|
||||
url = https://github.com/g-oikonomou/sensniff.git
|
||||
165
ARM_Tag_FW/cc2531_OEPL/contiki/.travis.yml
Normal file
165
ARM_Tag_FW/cc2531_OEPL/contiki/.travis.yml
Normal file
@@ -0,0 +1,165 @@
|
||||
# Workaround for the issue found in the stable image promoted on Dec 1, 2016.
|
||||
# See https://github.com/travis-ci/travis-ci/issues/6928#issuecomment-264227708
|
||||
group: deprecated
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
language: c #NOTE: this will set CC=gcc which might cause trouble
|
||||
before_script:
|
||||
- WGET="travis_retry wget --continue --tries=20 --waitretry=10 --retry-connrefused --no-dns-cache --timeout 300"
|
||||
- sudo apt-get -qq update
|
||||
|
||||
## Support building a binary that is identical to the CI
|
||||
- echo -n "Contiki will be compiled with RELSTR=" ; git --git-dir .git describe --tags --always
|
||||
|
||||
## Install doxygen
|
||||
- if [ ${BUILD_CATEGORY:-0} = doxygen ] ; then
|
||||
sudo add-apt-repository ppa:libreoffice/libreoffice-4-4 -y && sudo apt-get -qq update &&
|
||||
sudo apt-get --no-install-suggests --no-install-recommends -qq install doxygen &&
|
||||
doxygen --version ;
|
||||
fi
|
||||
|
||||
## Install msp430 toolchain
|
||||
- sudo apt-get -qq install lib32z1
|
||||
- $WGET http://simonduq.github.io/resources/mspgcc-4.7.2-compiled.tar.bz2 &&
|
||||
tar xjf mspgcc*.tar.bz2 -C /tmp/ &&
|
||||
sudo cp -f -r /tmp/msp430/* /usr/local/ &&
|
||||
rm -rf /tmp/msp430 mspgcc*.tar.bz2 &&
|
||||
msp430-gcc --version
|
||||
|
||||
## Install avr toolchain
|
||||
- $WGET http://atiselsts.github.io/resources/avr-gcc-4.9.2-compiled.tar.bz2 &&
|
||||
tar xjf avr-gcc*.tar.bz2 -C /tmp/ &&
|
||||
sudo cp -f -r /tmp/avr-gcc/* /usr/local/ &&
|
||||
rm -rf /tmp/avr-gcc avr-gcc*.tar.bz2 &&
|
||||
avr-gcc --version
|
||||
|
||||
## Install 32-bit compatibility libraries
|
||||
- sudo apt-get -qq install libc6:i386 libgcc1:i386 gcc-4.6-base:i386
|
||||
libstdc++5:i386 libstdc++6:i386
|
||||
|
||||
## Install old APCS ARM toolchain for mc1233x and mbxxx
|
||||
- if [ ${BUILD_ARCH:-0} = arm-apcs ] ; then
|
||||
$WGET https://raw.githubusercontent.com/wiki/malvira/libmc1322x/files/arm-2008q3-66-arm-none-eabi-i686-pc-linux-gnu.tar.bz2 &&
|
||||
tar xjf arm-2008q3*.tar.bz2 -C /tmp/ &&
|
||||
sudo cp -f -r /tmp/arm-2008q3/* /usr/ &&
|
||||
rm -rf /tmp/arm-2008q3 arm-2008q3*.tar.bz2 &&
|
||||
sudo apt-get -qq install libconfig-dev uuid-dev libqrencode-dev &&
|
||||
arm-none-eabi-gcc --version ;
|
||||
fi
|
||||
|
||||
## Install mainline ARM toolchain and srecord.
|
||||
- if [ ${BUILD_ARCH:-0} = arm-aapcs ] ; then
|
||||
sudo apt-get -qq install srecord &&
|
||||
$WGET https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 &&
|
||||
tar xjf gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 -C /tmp/ &&
|
||||
sudo cp -f -r /tmp/gcc-arm-none-eabi-5_2-2015q4/* /usr/local/ &&
|
||||
rm -rf /tmp/gcc-arm-none-eabi-* gcc-arm-none-eabi-*-linux.tar.bz2 &&
|
||||
arm-none-eabi-gcc --version ;
|
||||
fi
|
||||
|
||||
## Install RL78 GCC toolchain
|
||||
- sudo apt-get install libncurses5:i386 zlib1g:i386
|
||||
- $WGET http://adamdunkels.github.io/contiki-fork/gnurl78-v13.02-elf_1-2_i386.deb &&
|
||||
sudo dpkg -i gnurl78*.deb
|
||||
|
||||
## Install SDCC from a purpose-built bundle
|
||||
- if [ ${BUILD_ARCH:-0} = 8051 ] ; then
|
||||
$WGET https://raw.githubusercontent.com/wiki/g-oikonomou/contiki-sensinode/files/sdcc.tar.gz &&
|
||||
tar xzf sdcc.tar.gz -C /tmp/ &&
|
||||
sudo cp -f -r /tmp/sdcc/* /usr/local/ &&
|
||||
rm -rf /tmp/sdcc sdcc.tar.gz &&
|
||||
sdcc --version &&
|
||||
sudo apt-get -qq install srecord ;
|
||||
fi
|
||||
|
||||
## Clone and build cc65 when testing 6502 ports
|
||||
- if [ ${BUILD_ARCH:-0} = 6502 ] ; then
|
||||
git clone https://github.com/cc65/cc65 /tmp/cc65 &&
|
||||
make -C /tmp/cc65 bin apple2enh atarixl c64 c128 &&
|
||||
sudo make -C /tmp/cc65 avail &&
|
||||
cc65 --version ;
|
||||
fi
|
||||
|
||||
## Install NXP toolchain
|
||||
- if [ ${BUILD_ARCH:-0} = jn516x ] ; then
|
||||
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 &&
|
||||
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 &&
|
||||
$WGET http://simonduq.github.io/resources/jn516x-sdk-4163.tar.bz2 &&
|
||||
mkdir /tmp/jn516x-sdk /tmp/ba-elf-gcc &&
|
||||
tar xjf jn516x-sdk-*.tar.bz2 -C /tmp/jn516x-sdk &&
|
||||
tar xjf ba-elf-gcc-*part1.tar.bz2 -C /tmp/ba-elf-gcc &&
|
||||
tar xjf ba-elf-gcc-*part2.tar.bz2 -C /tmp/ba-elf-gcc &&
|
||||
sudo cp -f -r /tmp/jn516x-sdk /usr/ &&
|
||||
sudo cp -f -r /tmp/ba-elf-gcc /usr/ &&
|
||||
export PATH=/usr/ba-elf-gcc/bin:$PATH &&
|
||||
rm -rf /tmp/ba-elf-gcc* /tmp/jn516x-sdk* &&
|
||||
ba-elf-gcc --version ;
|
||||
fi
|
||||
|
||||
## Install mainline ARM toolchain and download nRF52 SDK
|
||||
- if [ ${BUILD_ARCH:-0} = nrf52dk ] ; then
|
||||
sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa &&
|
||||
sudo apt-get -qq update &&
|
||||
sudo apt-get -qq install gcc-arm-embedded srecord &&
|
||||
arm-none-eabi-gcc --version &&
|
||||
$WGET https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip &&
|
||||
mkdir /tmp/nrf52-sdk &&
|
||||
unzip nrf5_iot_sdk_3288530.zip -d /tmp/nrf52-sdk &&
|
||||
export NRF52_SDK_ROOT=/tmp/nrf52-sdk ;
|
||||
fi
|
||||
|
||||
## Compile cooja.jar only when it's going to be needed
|
||||
- if [ ${BUILD_CATEGORY:-sim} = sim ] ; then
|
||||
java -version &&
|
||||
ant -q -f tools/cooja/build.xml jar &&
|
||||
sudo java -Xshare:dump -version ;
|
||||
fi
|
||||
|
||||
script:
|
||||
## regression-tests/Makefile handles most of generic logic
|
||||
- "make -C regression-tests/??-$BUILD_TYPE RUNALL=true summary"
|
||||
|
||||
after_script:
|
||||
## Print cooja test logs
|
||||
- "[ ${BUILD_CATEGORY:-sim} = sim ] && tail regression-tests/??-$BUILD_TYPE/*.testlog"
|
||||
## Print a basic summary
|
||||
- "echo 'Summary:'; cat regression-tests/??-$BUILD_TYPE/summary"
|
||||
- "FAILS=`grep -c ' FAIL ' regression-tests/??-$BUILD_TYPE/summary`"
|
||||
## This will detect whether the build should pass or fail
|
||||
- "test $FAILS -eq 0; exit $?"
|
||||
|
||||
|
||||
env:
|
||||
## This magically kick-off parallel jobs for each of the for the sets
|
||||
## of environment variable defined below
|
||||
- BUILD_TYPE='doxygen' BUILD_CATEGORY='doxygen'
|
||||
- BUILD_TYPE='compile-base' BUILD_CATEGORY='compile'
|
||||
- BUILD_TYPE='compile-tools' BUILD_CATEGORY='compile'
|
||||
- BUILD_TYPE='collect'
|
||||
- BUILD_TYPE='collect-lossy'
|
||||
- BUILD_TYPE='rpl'
|
||||
- BUILD_TYPE='rpl-non-storing'
|
||||
- BUILD_TYPE='large-rpl'
|
||||
- BUILD_TYPE='rime'
|
||||
- BUILD_TYPE='ipv6'
|
||||
- BUILD_TYPE='ip64' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='hello-world'
|
||||
- BUILD_TYPE='base'
|
||||
# XXX: netperf disabled b/c it's flaky
|
||||
# - BUILD_TYPE='netperf' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='shell'
|
||||
- BUILD_TYPE='elfloader'
|
||||
# Tests under the ipv4 dir are individually disabled. Thus the entire job can be off
|
||||
# - BUILD_TYPE='ipv4'
|
||||
- BUILD_TYPE='ipv6-apps'
|
||||
- BUILD_TYPE='compile-8051-ports' BUILD_CATEGORY='compile' BUILD_ARCH='8051'
|
||||
- BUILD_TYPE='compile-arm-apcs-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-apcs'
|
||||
- BUILD_TYPE='compile-6502-ports' BUILD_CATEGORY='compile' BUILD_ARCH='6502'
|
||||
- BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-aapcs'
|
||||
- BUILD_TYPE='compile-nxp-ports' BUILD_CATEGORY='compile' BUILD_ARCH='jn516x'
|
||||
- BUILD_TYPE='compile-nrf52-ports' BUILD_CATEGORY='compile' BUILD_ARCH='nrf52dk'
|
||||
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='compile-avr' BUILD_CATEGORY='compile' BUILD_ARCH='avr-rss2'
|
||||
- BUILD_TYPE='ieee802154'
|
||||
278
ARM_Tag_FW/cc2531_OEPL/contiki/CONTRIBUTING.md
Normal file
278
ARM_Tag_FW/cc2531_OEPL/contiki/CONTRIBUTING.md
Normal file
@@ -0,0 +1,278 @@
|
||||
Code Contributions
|
||||
==================
|
||||
|
||||
Do you have a new cool feature that you'd like to contribute to
|
||||
Contiki? Or a fix for a bug? Great! The Contiki project loves code
|
||||
contributions, improvements, and bugfixes, but we require that they
|
||||
follow a set of guidelines and that they are contributed in a specific
|
||||
way.
|
||||
|
||||
Additional rules apply for contributions of a new hardware platform.
|
||||
|
||||
General Advice
|
||||
--------------
|
||||
|
||||
The chance of getting your pull request accepted increases considerably
|
||||
if you adhere to the following rules in addition to the aforementioned
|
||||
formatting and naming standards:
|
||||
|
||||
* Ensure that all contributed files have a valid copyright statement
|
||||
and an open-source license.
|
||||
* Do not bundle commits that are unrelated to each other -- create
|
||||
separate pull requests instead.
|
||||
* Adhere to ISO C99 in all C language source files. Exceptions are
|
||||
allowed for those platform-dependent source files that rely on the
|
||||
extensions of a specific set of compilers.
|
||||
* Clean up the commit history. "git rebase -i" is useful for this purpose.
|
||||
* Do not include executable binary files, because they are usually
|
||||
rejected for security reasons. Instead, provide instructions for how
|
||||
to compile the file, so that a trusted member of the merge team can
|
||||
commit it.
|
||||
* Write a descriptive pull request message. Explain the advantages and
|
||||
disadvantages of your proposed changes.
|
||||
* Before starting to work on a major contribution, discuss your idea
|
||||
with experienced Contiki programmers (e.g., on the contiki-developers
|
||||
mailing list) to avoid wasting time on things that have no chance of
|
||||
getting merged into Contiki.
|
||||
|
||||
Source code that goes into the mainline Contiki repository must be of
|
||||
interest to a large part of the Contiki community. It must be
|
||||
well-tested and the merge team must have confidence that the code can
|
||||
be maintained over a longer period. See below for more details
|
||||
pertaining to platform contributions.
|
||||
|
||||
Contributions that have been made in research projects, and typically
|
||||
do not get maintained thereafter, are better suited for inclusion in
|
||||
the Contiki projects repository.
|
||||
|
||||
Structuring Commits
|
||||
-------------------
|
||||
|
||||
* Write descriptive commit messages. They don't have to be very long,
|
||||
but you should mention what the commit achieves. Commit messages
|
||||
like "modified foo/bar.c" are not helpful, should not be used, and
|
||||
are likely to result in you having to re-write them.
|
||||
* Please do not add / remove irrelevant new line markers. Don't remove
|
||||
the new line marker at the EOF.
|
||||
* Please, make sure that your patch doesn't add lines with trailing
|
||||
whitespaces. If you run uncrustify as discussed above, this should
|
||||
get taken care of for you automatically.
|
||||
* More generally speaking, make sure that each commit in your history
|
||||
only includes changes necessary to implement whatever it is the
|
||||
commit is trying to achieve. All changes should be mentioned in the
|
||||
commit message.
|
||||
|
||||
Code Formatting
|
||||
---------------
|
||||
|
||||
We require that all code contributed to the Contiki tree follows the
|
||||
same code formatting as the existing Contiki code. We are very strict
|
||||
on this.
|
||||
|
||||
Code must be formatted according to
|
||||
[contiki/doc/code-style.c](https://github.com/contiki-os/contiki/blob/master/doc/code-style.c).
|
||||
|
||||
The Contiki source tree contains scripts to assist with correct code formatting
|
||||
and we recommend [Uncrustify](http://uncrustify.sourceforge.net/) as the
|
||||
preferred auto formatter. Everything is under
|
||||
[tools/code-style](https://github.com/contiki-os/contiki/tree/master/tools/code-style).
|
||||
|
||||
If you wish, you can format all changed resources in your working tree
|
||||
automatically if the
|
||||
[tools/code-style/uncrustify-changed.sh](https://github.com/contiki-os/contiki/blob/master/tools/code-style/uncrustify-changed.sh)
|
||||
script is added as a [Git pre-commit
|
||||
hook](http://git-scm.com/book/en/Customizing-Git-Git-Hooks) to your Git
|
||||
configuration.
|
||||
|
||||
Here are some examples of what you can do:
|
||||
* To check a file's style without changing the file on disk, you can run this:
|
||||
`./tools/code-style/uncrustify-check-style.sh <path-to-file>`
|
||||
This script will only accept a single file as its argument.
|
||||
|
||||
* To auto format a file (and change it on disk) you can run this:
|
||||
`./tools/code-style/uncrustify-fix-style.sh <path-to-file>`
|
||||
|
||||
* `uncrustify-fix-style.sh` will accept a space-delimited list of files as its argument. Thus, you can auto-format an entire directory by running something like this:
|
||||
``./tools/code-style/uncrustify-fix-style.sh `find cpu/cc2538 -type f -name "*.[ch]"` ``
|
||||
|
||||
This is _not_ a silver bullet and developer intervention is still required. Below are some examples of code which will get misformatted by uncrustify:
|
||||
* Math symbol following a cast to a typedef
|
||||
```
|
||||
a = (uint8_t) ~P0_1; /* Cast to a typedef. Space gets added here (incorrect) */
|
||||
a = (int)~P0_1; /* Cast to a known type. Space gets removed (correct) */
|
||||
a = (uint8_t)P0_1; /* Variable directly after the cast. Space gets removed (correct) */
|
||||
```
|
||||
|
||||
* `while(<condition>);` will become `while(<condition>) ;` (space incorrectly added after closing paren)
|
||||
|
||||
* `asm("wfi");` becomes `asm ("wfi");`: A space gets added before the opening paren, because the `asm` keyword stops this from getting interpreted as a normal function call / macro invocation. This is only a problem with `asm`. For instance, `foo("bar");` gets formatted correctly.
|
||||
|
||||
Naming
|
||||
------
|
||||
|
||||
We require that all code contributed to the Contiki tree follow the
|
||||
Contiki source code naming standard:
|
||||
|
||||
* File names are composed of lower-case characters and dashes. Like
|
||||
this: simple-udp.c
|
||||
* Variable and function names are composed of lower-case characters
|
||||
and underscores. Like this: simple_udp_send();
|
||||
* Variable and function names that are visible outside of their module
|
||||
must begin with the name of the module. Like this:
|
||||
simple_udp_send(), which is in the simple-udp module, declared in
|
||||
simple-udp.h, and implemented in simple-udp.c.
|
||||
* C macros are composed of upper-case characters and underscores. Like
|
||||
this: PROCESS_THREAD().
|
||||
* Configuration definitions begin with the module name and CONF_. Like
|
||||
this: PROCESS_CONF_NUMEVENTS.
|
||||
|
||||
How to Contribute Code
|
||||
----------------------
|
||||
|
||||
When your code is formatted according to the Contiki code style and
|
||||
follows the Contiki naming standard, it is time to send it to the
|
||||
Contiki maintainers to look at!
|
||||
|
||||
All code contributions to Contiki are submitted as [Github pull
|
||||
requests](https://help.github.com/articles/using-pull-requests). Pull
|
||||
requests will be reviewed and accepted according to the guidelines
|
||||
found in the next section.
|
||||
|
||||
The basic guidelines to to start a Pull-Request:
|
||||
* Create a new branch for your modifications. This branch should be based on the latest contiki master branch.
|
||||
* If you already added the commits to another branch you can [cherry-pick](http://git-scm.com/docs/git-cherry-pick) them onto your new branch.
|
||||
* Push the new branch to github.
|
||||
* Raise the new Pull Requests on this new branch. Raising a Pull Request for the master branch is almost always a bad idea.
|
||||
* If changes are requested do not close the pull request but rewrite your history. [Details about rewriting your history](http://git-scm.com/book/en/Git-Tools-Rewriting-History)
|
||||
* You now force-push the changes to github. The pull-request is automatically updated.
|
||||
|
||||
In Git terminology this is equivalent to:
|
||||
* Make sure you have the original contiki repo as origin.
|
||||
```bash
|
||||
$ git remote -v
|
||||
contiki-orig https://github.com/contiki-os/contiki.git
|
||||
```
|
||||
* If not add it
|
||||
```bash
|
||||
$ git remote add contiki-orig https://github.com/contiki-os/contiki.git
|
||||
```
|
||||
* Make sure you have the latest version of your remotes
|
||||
```bash
|
||||
$ git remote update
|
||||
```
|
||||
* Create a new branch "my_new_feature" based on the latest contiki master branch
|
||||
```bash
|
||||
$ git checkout contiki-orig/master -b my_new_feature
|
||||
```
|
||||
* Add your work. For example by cherry-picking your changes from another branch.
|
||||
```bash
|
||||
$ git cherry-pick <HASH OF COMMIT>
|
||||
```
|
||||
* Push to _your_ github repository
|
||||
```bash
|
||||
$ git push origin my_new_feature
|
||||
```
|
||||
* Make a Pull Request for that branch
|
||||
* Rewrite your history if requested
|
||||
```bash
|
||||
$ git rebase -i contiki-orig/master
|
||||
```
|
||||
* As rewriting your history can break things you must force-push the changes. **Warning**: Force-pushing normally is dangerous and you might break things. Make sure you are never force-pushing branches other people are supposed to work with.
|
||||
```bash
|
||||
$ git push origin my_new_feature -f
|
||||
```
|
||||
* NOTE: To avoid all the pain of selectively picking commits, rebasing and force-pushing - begin your development with a branch OTHER THAN your master branch, and push changes to that branch after any local commits.
|
||||
|
||||
Pull Request Merging Policy
|
||||
---------------------------
|
||||
|
||||
Pull requests (PRs) are reviewed by the [merge team](https://github.com/orgs/contiki-os/people).
|
||||
Generally, PRs require two "+1" before they can be merged by someone on the merge team.
|
||||
The since Contiki 3.0, the merging policy is the following:
|
||||
* The PR receives **one "-1"** from a merge team member (along with specific feedback). The PR is closed. A "-1" must be accompanied with a clear explanation why the PR will not be considered for inclusion.
|
||||
* The PR receives **two "+1"** from merge team members. The PR is merged.
|
||||
* The PR was inactive for **two months**. A team member may either:
|
||||
* Comment "Is there any interest for this PR? Is there any work pending on it? If not I will close it in **one month**." Back to initial state in case of activity, close otherwise.
|
||||
* Comment "I approve this PR. If nobody disapproves within **one month**, I will merge it." Back to initial state in case of activity, merge otherwise.
|
||||
|
||||
There is an exception to the rule.
|
||||
Code that requires esoteric expertise such as some applications, platforms or tools can be merged after a single "+1" from its domain expert.
|
||||
|
||||
Travis / Regression testing
|
||||
---------------------------
|
||||
|
||||
[Travis](https://travis-ci.org/) is a service that runs regression
|
||||
tests. If you make a pull-request for Contiki this is automatically
|
||||
forwarded to Travis and regression tests are run. A box with
|
||||
information about the state of you pull request should show up after a
|
||||
minute or two.
|
||||
|
||||
If the test fails it is likely that something is wrong with your
|
||||
code. Please look carefully at the log. It might also be that some
|
||||
package on the testing VM was updated and causes the build to fail. If
|
||||
you are sure that is is not your code causing the tests to fail start
|
||||
a new issue describing the problem. Also note this in your pull
|
||||
request.
|
||||
|
||||
You can also register at [Travis](https://travis-ci.org/) for
|
||||
free. Once you activated your Contiki repository, every push will be
|
||||
tested at Travis. The configuration is part of the contiki repository
|
||||
and testing will therefore work out-of-the-box. At Travis you then get
|
||||
an overview of the state of each of your branches.
|
||||
|
||||
New Platforms
|
||||
-------------
|
||||
A new hardware port will be considered for inclusion in mainline Contiki
|
||||
if it satisfies the following rules:
|
||||
|
||||
* There must be at least one person willing and committed to maintain it.
|
||||
They may but do not have to be the people who wrote the code. Similarly,
|
||||
they may but do not have to be affiliated with the hardware manufacturer.
|
||||
In the first instance, code maintenance would mean keeping the port up to
|
||||
speed by submitting pull requests as Contiki moves forward. In the longer
|
||||
term, people who maintain a reasonable level of commitment and who demonstrate
|
||||
that they know what they're doing may be invited to become repo collaborators.
|
||||
* The hardware must be commercially available and of interest to a wide audience.
|
||||
In other words, ports for bespoke hardware built for e.g. a specific project /
|
||||
a single customer / niche markets are more suitable for a Contiki fork.
|
||||
* The code must strictly adhere to the Contiki code style, as discussed above.
|
||||
* The new files must have a clear copyright notice and license header. Contiki's
|
||||
preferred software license is the
|
||||
[3-clause BSD](http://opensource.org/licenses/BSD-3-Clause).
|
||||
Other licenses may also be considered
|
||||
as long as they are compatible with the 3-clause BSD (e.g. the Apache 2.0 license).
|
||||
Conversely, code distributed under GPL cannot be considered. The same applies to
|
||||
bespoke licenses, such as those allowing use or redistribution only together with
|
||||
certain kinds of hardware.
|
||||
* The port must demonstrate a certain degree of completeness and maturity. Common sense
|
||||
applies here.
|
||||
* The port must be accompanied by examples demonstrating basic functionality. This could
|
||||
be a set of examples under `examples/<new-hardware-port>` and/or documentation of
|
||||
which existing examples are meant to work.
|
||||
* The port must provide compile regression tests by extending the existing travis
|
||||
integration testing framework. Again, we can't specify explicitly
|
||||
what those tests should be, but something more interesting than hello-world is expected.
|
||||
* The work must be documented. The documentation could be README.md files
|
||||
under the platform / cpu / example dirs or wiki pages. Doxygen comments are
|
||||
also encouraged. The documentation should include:
|
||||
* A getting started guide, including a list of tools required to use the platform
|
||||
(e.g. toolchain, software to program the device), where to get them from and brief notes
|
||||
how to install them (can simply be a list of links to external guides)
|
||||
* A list of things which will work off the shelf
|
||||
* A list of things which are not meant to work, if any
|
||||
* Additional reading resources (e.g. datasheets, hardware user guides, web resources)
|
||||
* A ToDo list, if applicable.
|
||||
* It must be possible to use the port using free software. We do not discourage the
|
||||
use of commercial software (e.g. support for a commercial toolchain), quite the opposite.
|
||||
However, we will insist on the existence of a free alternative for everything.
|
||||
|
||||
After the port has been accepted, things meant to work off the shelf should
|
||||
keep working off the shelf as Contiki moves forward.
|
||||
|
||||
We appreciate that, for many people, contributing to Contiki is a spare time
|
||||
activity and our expectations from port maintainers take this into
|
||||
consideration. All we ask from maintainers is to comment on and address
|
||||
relevant pull requests at a reasonable frequency and to make sure travis keeps
|
||||
passing. In other words, we just want platforms to stay healthy over time and
|
||||
to thus avoid becoming very broken / obsolete.
|
||||
|
||||
38
ARM_Tag_FW/cc2531_OEPL/contiki/LICENSE
Normal file
38
ARM_Tag_FW/cc2531_OEPL/contiki/LICENSE
Normal file
@@ -0,0 +1,38 @@
|
||||
Contiki is licensed under the 3-clause BSD license. This license gives
|
||||
everyone the right to use and distribute the code, either in binary or
|
||||
source code format, as long as the copyright license is retained in
|
||||
the source code.
|
||||
|
||||
The copyright for different parts of the code is held by different
|
||||
people and organizations, but the code is licensed under the same type
|
||||
of license. The license text is:
|
||||
|
||||
* Copyright (c) (Year), (Name of copyright holder)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
304
ARM_Tag_FW/cc2531_OEPL/contiki/Makefile.include
Normal file
304
ARM_Tag_FW/cc2531_OEPL/contiki/Makefile.include
Normal file
@@ -0,0 +1,304 @@
|
||||
# -*- makefile -*-
|
||||
|
||||
ifndef CONTIKI
|
||||
${error CONTIKI not defined! You must specify where Contiki resides}
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),)
|
||||
-include Makefile.target
|
||||
ifeq ($(TARGET),)
|
||||
${info TARGET not defined, using target 'native'}
|
||||
TARGET=native
|
||||
else
|
||||
${info using saved target '$(TARGET)'}
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(DEFINES),)
|
||||
-include Makefile.$(TARGET).defines
|
||||
ifneq ($(DEFINES),)
|
||||
${info using saved defines '$(DEFINES)'}
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef HOST_OS
|
||||
ifeq ($(OS),Windows_NT)
|
||||
## TODO: detect more specific Windows set-ups,
|
||||
## e.g. CygWin, MingW, VisualC, Watcom, Interix
|
||||
HOST_OS := Windows
|
||||
else
|
||||
HOST_OS := $(shell uname)
|
||||
endif
|
||||
endif
|
||||
|
||||
#More debug information when running in CI
|
||||
ifdef CI
|
||||
ifeq ($(CI),true)
|
||||
V = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
usage:
|
||||
@echo "make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]"
|
||||
|
||||
targets:
|
||||
@ls -1 $(CONTIKI)/platform $(TARGETDIRS) | grep -v CVS
|
||||
|
||||
savetarget:
|
||||
-@rm -f Makefile.target
|
||||
@echo "saving Makefile.target"
|
||||
@echo >Makefile.target "TARGET = $(TARGET)"
|
||||
|
||||
savedefines:
|
||||
-@rm -f Makefile.$(TARGET).defines
|
||||
@echo "saving Makefile.$(TARGET).defines"
|
||||
@echo >Makefile.$(TARGET).defines "DEFINES = $(DEFINES)"
|
||||
|
||||
OBJECTDIR = obj_$(TARGET)
|
||||
|
||||
LOWERCASE = -abcdefghijklmnopqrstuvwxyz
|
||||
UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}}
|
||||
CFLAGS += -DCONTIKI=1 -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1
|
||||
|
||||
MODULES += core/sys core/dev core/lib
|
||||
|
||||
# Include IPv6, IPv4, and/or Rime
|
||||
|
||||
HAS_STACK = 0
|
||||
ifeq ($(CONTIKI_WITH_IPV4),1)
|
||||
HAS_STACK = 1
|
||||
CFLAGS += -DNETSTACK_CONF_WITH_IPV4=1
|
||||
MODULES += core/net/ipv4 core/net/ip
|
||||
endif
|
||||
|
||||
ifeq ($(CONTIKI_WITH_RIME),1)
|
||||
HAS_STACK = 1
|
||||
CFLAGS += -DNETSTACK_CONF_WITH_RIME=1
|
||||
MODULES += core/net/rime
|
||||
endif
|
||||
|
||||
# Make IPv6 the default stack
|
||||
ifeq ($(HAS_STACK),0)
|
||||
ifneq ($(CONTIKI_WITH_IPV6),0)
|
||||
CONTIKI_WITH_IPV6 = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONTIKI_WITH_IPV6),1)
|
||||
CFLAGS += -DNETSTACK_CONF_WITH_IPV6=1
|
||||
ifneq ($(CONTIKI_WITH_RPL),0)
|
||||
CONTIKI_WITH_RPL = 1
|
||||
endif
|
||||
MODULES += core/net/ipv6 core/net/ip
|
||||
endif
|
||||
|
||||
ifeq ($(CONTIKI_WITH_RPL),1)
|
||||
CFLAGS += -DUIP_CONF_IPV6_RPL=1
|
||||
MODULES += core/net/rpl
|
||||
else
|
||||
CFLAGS += -DUIP_CONF_IPV6_RPL=0
|
||||
endif
|
||||
|
||||
CONTIKI_SOURCEFILES += $(CONTIKIFILES)
|
||||
|
||||
CONTIKIDIRS += ${addprefix $(CONTIKI)/core/,dev lib net net/llsec net/mac net/rime \
|
||||
net/rpl sys cfs ctk lib/ctk loader . }
|
||||
|
||||
oname = ${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}
|
||||
|
||||
CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}}
|
||||
|
||||
PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFILES)}}
|
||||
|
||||
# Provide way to create $(OBJECTDIR) if it has been removed by make clean
|
||||
$(OBJECTDIR):
|
||||
mkdir $@
|
||||
|
||||
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
||||
|
||||
### Include application makefiles
|
||||
|
||||
ifdef APPS
|
||||
APPDS = ${wildcard ${foreach DIR, $(APPDIRS), ${addprefix $(DIR)/, $(APPS)}}} \
|
||||
${wildcard ${addprefix $(CONTIKI)/apps/, $(APPS)} \
|
||||
${addprefix $(CONTIKI)/platform/$(TARGET)/apps/, $(APPS)} \
|
||||
$(APPS)}
|
||||
APPINCLUDES = ${foreach APP, $(APPS), ${wildcard ${foreach DIR, $(APPDS), $(DIR)/Makefile.$(APP)}}}
|
||||
-include $(APPINCLUDES)
|
||||
APP_SOURCES = ${foreach APP, $(APPS), $($(APP)_src)}
|
||||
DSC_SOURCES = ${foreach APP, $(APPS), $($(APP)_dsc)}
|
||||
CONTIKI_SOURCEFILES += $(APP_SOURCES) $(DSC_SOURCES)
|
||||
endif
|
||||
|
||||
### Include target makefile (TODO Unsafe?)
|
||||
|
||||
target_makefile := $(wildcard $(CONTIKI)/platform/$(TARGET)/Makefile.$(TARGET) ${foreach TDIR, $(TARGETDIRS), $(TDIR)/$(TARGET)/Makefile.$(TARGET)})
|
||||
|
||||
# Check if the target makefile exists, and create the object directory if necessary.
|
||||
ifeq ($(strip $(target_makefile)),)
|
||||
${error The target platform "$(TARGET)" does not exist (maybe it was misspelled?)}
|
||||
else
|
||||
ifneq (1, ${words $(target_makefile)})
|
||||
${error More than one TARGET Makefile found: $(target_makefile)}
|
||||
endif
|
||||
include $(target_makefile)
|
||||
endif
|
||||
|
||||
ifdef MODULES
|
||||
UNIQUEMODULES = $(call uniq,$(MODULES))
|
||||
MODULEDIRS = ${wildcard ${addprefix $(CONTIKI)/, $(UNIQUEMODULES)}}
|
||||
MODULES_SOURCES = ${foreach d, $(MODULEDIRS), ${subst ${d}/,,${wildcard $(d)/*.c}}}
|
||||
CONTIKI_SOURCEFILES += $(MODULES_SOURCES)
|
||||
APPDS += $(MODULEDIRS)
|
||||
endif
|
||||
|
||||
### Verbosity control. Use make V=1 to get verbose builds.
|
||||
|
||||
ifeq ($(V),1)
|
||||
TRACE_CC =
|
||||
TRACE_LD =
|
||||
TRACE_AR =
|
||||
TRACE_AS =
|
||||
Q=
|
||||
else
|
||||
TRACE_CC = @echo " CC " $<
|
||||
TRACE_LD = @echo " LD " $@
|
||||
TRACE_AR = @echo " AR " $@
|
||||
TRACE_AS = @echo " AS " $<
|
||||
Q=@
|
||||
endif
|
||||
|
||||
### Forward comma-separated list of arbitrary defines to the compiler
|
||||
|
||||
COMMA := ,
|
||||
CFLAGS += ${addprefix -D,${subst $(COMMA), ,$(DEFINES)}}
|
||||
|
||||
### Setup directory search path for source and header files
|
||||
|
||||
CONTIKI_TARGET_DIRS_CONCAT = ${addprefix ${dir $(target_makefile)}, \
|
||||
$(CONTIKI_TARGET_DIRS)}
|
||||
CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \
|
||||
$(CONTIKI_CPU_DIRS)}
|
||||
|
||||
SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
|
||||
$(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(APPDS) $(EXTERNALDIRS) ${dir $(target_makefile)}
|
||||
|
||||
vpath %.c $(SOURCEDIRS)
|
||||
vpath %.S $(SOURCEDIRS)
|
||||
|
||||
CFLAGS += ${addprefix -I,$(SOURCEDIRS) $(CONTIKI)}
|
||||
|
||||
### Check for a git repo and pass version if found
|
||||
### git.exe in Windows cmd shells may require no stderr redirection
|
||||
ifndef RELSTR
|
||||
RELSTR:=${shell git --git-dir ${CONTIKI}/.git describe --tags --always}
|
||||
endif
|
||||
|
||||
ifneq ($(RELSTR),)
|
||||
CFLAGS += -DCONTIKI_VERSION_STRING=\"Contiki-$(RELSTR)\"
|
||||
endif
|
||||
|
||||
### Automatic dependency generation
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include ${addprefix $(OBJECTDIR)/,$(CONTIKI_SOURCEFILES:.c=.d) \
|
||||
$(PROJECT_SOURCEFILES:.c=.d)}
|
||||
endif
|
||||
|
||||
### See http://make.paulandlesley.org/autodep.html#advanced
|
||||
|
||||
define FINALIZE_DEPENDENCY
|
||||
cp $(@:.o=.d) $(@:.o=.$$$$); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.$$$$) >> $(@:.o=.d); \
|
||||
rm -f $(@:.o=.$$$$)
|
||||
endef
|
||||
|
||||
clean:
|
||||
-rm -f *~ *core core *.srec \
|
||||
*.lst *.map \
|
||||
*.cprg *.bin *.data contiki*.a *.firmware core-labels.S *.ihex *.ini \
|
||||
*.ce *.co
|
||||
rm -rf $(CLEAN)
|
||||
-rm -rf $(OBJECTDIR)
|
||||
|
||||
distclean: clean
|
||||
-rm -f ${addsuffix .$(TARGET),$(CONTIKI_PROJECT)}
|
||||
|
||||
-include $(CONTIKI)/platform/$(TARGET)/Makefile.customrules-$(TARGET)
|
||||
|
||||
ifndef CUSTOM_RULE_C_TO_CE
|
||||
%.ce: %.c
|
||||
$(TRACE_CC)
|
||||
$(Q)$(CC) $(CFLAGS) -DAUTOSTART_ENABLE -c $< -o $@
|
||||
$(STRIP) --strip-unneeded -g -x $@
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_C_TO_OBJECTDIR_O
|
||||
$(OBJECTDIR)/%.o: %.c | $(OBJECTDIR)
|
||||
$(TRACE_CC)
|
||||
$(Q)$(CC) $(CFLAGS) -MMD -c $< -o $@
|
||||
@$(FINALIZE_DEPENDENCY)
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_S_TO_OBJECTDIR_O
|
||||
$(OBJECTDIR)/%.o: %.S | $(OBJECTDIR)
|
||||
$(TRACE_AS)
|
||||
$(Q)$(AS) $(ASFLAGS) -o $@ $<
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_C_TO_O
|
||||
%.o: %.c
|
||||
$(TRACE_CC)
|
||||
$(Q)$(CC) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
|
||||
|
||||
ifndef CUSTOM_RULE_C_TO_CO
|
||||
%.co: %.c
|
||||
$(TRACE_CC)
|
||||
$(Q)$(CC) $(CFLAGS) -DAUTOSTART_ENABLE -c $< -o $@
|
||||
endif
|
||||
|
||||
ifndef AROPTS
|
||||
AROPTS = rcf
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_ALLOBJS_TO_TARGETLIB
|
||||
contiki-$(TARGET).a: $(CONTIKI_OBJECTFILES)
|
||||
$(TRACE_AR)
|
||||
$(Q)$(AR) $(AROPTS) $@ $^
|
||||
endif
|
||||
|
||||
ifndef LD
|
||||
LD = $(CC)
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_LINK
|
||||
%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a
|
||||
$(TRACE_LD)
|
||||
$(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \
|
||||
${filter %.a,$^} $(TARGET_LIBFILES) -o $@
|
||||
endif
|
||||
|
||||
%.ramprof: %.$(TARGET)
|
||||
$(NM) -S -td --size-sort $< | grep -i " [abdrw] " | cut -d' ' -f2,4
|
||||
|
||||
%.flashprof: %.$(TARGET)
|
||||
$(NM) -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4
|
||||
|
||||
# Don't treat %.$(TARGET) as an intermediate file because it is
|
||||
# in fact the primary target.
|
||||
.PRECIOUS: %.$(TARGET)
|
||||
|
||||
# Cancel the predefined implict rule for compiling and linking
|
||||
# a single C source into a binary to force GNU make to consider
|
||||
# the match-anything rule below instead.
|
||||
%: %.c
|
||||
|
||||
# Match-anything pattern rule to allow the project makefiles to
|
||||
# abstract from the actual binary name. It needs to contain some
|
||||
# command in order to be a rule, not just a prerequisite.
|
||||
%: %.$(TARGET)
|
||||
@
|
||||
92
ARM_Tag_FW/cc2531_OEPL/contiki/README-BUILDING.md
Normal file
92
ARM_Tag_FW/cc2531_OEPL/contiki/README-BUILDING.md
Normal file
@@ -0,0 +1,92 @@
|
||||
The Contiki build system
|
||||
========================
|
||||
|
||||
The Contiki build system is designed to make it easy to compile Contiki
|
||||
applications for different hardware platforms or into a simulation platform by
|
||||
simply supplying different parameters to the make command, without having to
|
||||
edit makefiles or modify the application code.
|
||||
|
||||
The file example project in examples/hello-world/ shows how the Contiki build
|
||||
system works. The hello-world.c application can be built into a complete
|
||||
Contiki system by running make in the examples/hello-world/ directory. Running
|
||||
make without parameters will build a Contiki system using the native target.
|
||||
The native target is a special Contiki platform that builds an entire Contiki
|
||||
system as a program that runs on the development system. After compiling the
|
||||
application for the native target it is possible to run the Contiki system with
|
||||
the application by running the file hello-world.native. To compile the
|
||||
application and a Contiki system for the ESB platform the command make
|
||||
TARGET=esb is used. This produces a hello-world.esb file that can be loaded
|
||||
into an ESB board.
|
||||
|
||||
To compile the hello-world application into a stand-alone executable that can
|
||||
be loaded into a running Contiki system, the command make hello-world.ce is
|
||||
used. To build an executable file for the ESB platform, make TARGET=esb
|
||||
hello-world.ce is run.
|
||||
|
||||
To avoid having to type TARGET= every time make is run, it is possible to run
|
||||
make TARGET=esb savetarget to save the selected target as the default target
|
||||
platform for subsequent invocations of make. A file called Makefile.target
|
||||
containing the currently saved target is saved in the project's directory.
|
||||
|
||||
Beside TARGET= there's DEFINES= which allows to set arbitrary variables for the
|
||||
C preprocessor in form of a comma-separated list. Again it is possible to avoid
|
||||
having to re-type i.e. DEFINES=MYTRACE,MYVALUE=4711 by running make TARGET=esb
|
||||
DEFINES=MYTRACE,MYVALUE=4711 savedefines. A file called Makefile.esb.defines is
|
||||
saved in the project's directory containing the currently saved defines for the
|
||||
ESB platform.
|
||||
|
||||
Makefiles used in the Contiki build system The Contiki build system is composed
|
||||
of a number of Makefiles. These are:
|
||||
|
||||
* Makefile: the project's makefile, located in the project directory.
|
||||
|
||||
* Makefile.include: the system-wide Contiki makefile, located in the root of
|
||||
the Contiki source tree.
|
||||
|
||||
* Makefile.$(TARGET) (where $(TARGET) is the name of the platform that is
|
||||
currently being built): rules for the specific platform, located in the
|
||||
platform's subdirectory in the platform/ directory.
|
||||
|
||||
* Makefile.$(CPU) (where $(CPU) is the name of the CPU or microcontroller
|
||||
architecture used on the platform for which Contiki is built): rules for the
|
||||
CPU architecture, located in the CPU architecture's subdirectory in the cpu/
|
||||
directory.
|
||||
|
||||
* Makefile.$(APP) (where $(APP) is the name of an application in the apps/
|
||||
directory): rules for applications in the apps/ directories. Each application
|
||||
has its own makefile.
|
||||
|
||||
The Makefile in the project's directory is intentionally simple. It specifies
|
||||
where the Contiki source code resides in the system and includes the
|
||||
system-wide Makefile, Makefile.include. The project's makefile can also define
|
||||
in the APPS variable a list of applications from the apps/ directory that
|
||||
should be included in the Contiki system. The Makefile used in the hello-world
|
||||
example project looks like this:
|
||||
|
||||
CONTIKI_PROJECT = hello-world
|
||||
all: $(CONTIKI_PROJECT)
|
||||
|
||||
CONTIKI = ../..
|
||||
include $(CONTIKI)/Makefile.include
|
||||
|
||||
First, the location of the Contiki source code tree is given by defining the
|
||||
CONTIKI variable. Next, the name of the application is defined. Finally, the
|
||||
system-wide Makefile.include is included.
|
||||
|
||||
The Makefile.include contains definitions of the C files of the core Contiki
|
||||
system. Makefile.include always reside in the root of the Contiki source tree.
|
||||
When make is run, Makefile.include includes the Makefile.$(TARGET) as well as
|
||||
all makefiles for the applications in the APPS list (which is specified by the
|
||||
project's Makefile).
|
||||
|
||||
Makefile.$(TARGET), which is located in the platform/$(TARGET)/ directory,
|
||||
contains the list of C files that the platform adds to the Contiki system. This
|
||||
list is defined by the CONTIKI_TARGET_SOURCEFILES variable. The
|
||||
Makefile.$(TARGET) also includes the Makefile.$(CPU) from the cpu/$(CPU)/
|
||||
directory.
|
||||
|
||||
The Makefile.$(CPU) typically contains definitions for the C compiler used for
|
||||
the particular CPU. If multiple C compilers are used, the Makefile.$(CPU) can
|
||||
either contain a conditional expression that allows different C compilers to be
|
||||
defined, or it can be completely overridden by the platform specific makefile
|
||||
Makefile.$(TARGET).
|
||||
220
ARM_Tag_FW/cc2531_OEPL/contiki/README-EXAMPLES.md
Normal file
220
ARM_Tag_FW/cc2531_OEPL/contiki/README-EXAMPLES.md
Normal file
@@ -0,0 +1,220 @@
|
||||
Contiki Examples
|
||||
================
|
||||
|
||||
The examples/ directory contains a few examples that will help you get
|
||||
started with Contiki.
|
||||
|
||||
To run the example programs, you need either to be running Linux or FreeBSD (or
|
||||
any other UNIX-type system), or install Cygwin if you are running Microsoft
|
||||
Windows [http://cygwin.com](http://cygwin.com). As a minimum you will need to
|
||||
have the gcc C compiler installed. To run the examples in the 'netsim' target,
|
||||
you need to have GTK 1.x development libraries installed. These are usually
|
||||
called 'gtk-devel', 'libgtk1-devel' or similar in your Linux software
|
||||
installation programs.
|
||||
|
||||
compile-platforms/
|
||||
------------------
|
||||
|
||||
A test script that compiles Contiki for a number of platforms and reports any
|
||||
errors found during the build.
|
||||
|
||||
email/
|
||||
------
|
||||
|
||||
An email program supporting SMTP. It can be compiled and run in the 'win32'
|
||||
target by typing the following commands:
|
||||
|
||||
cd examples/email
|
||||
make
|
||||
./email-client.win32
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/win32/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well.
|
||||
|
||||
esb/
|
||||
----
|
||||
|
||||
A set of demo applications for the ESB board.
|
||||
|
||||
ftp/
|
||||
----
|
||||
|
||||
An FTP client supporting download. It can be compiled and run in the 'win32'
|
||||
target by typing the following commands:
|
||||
|
||||
cd examples/ftp
|
||||
make
|
||||
./ftp-client.win32
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/win32/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well.
|
||||
|
||||
hello-world/
|
||||
------------
|
||||
|
||||
A really simple Contiki program that shows how to write Contiki programs. To
|
||||
compile and test the program, go into the hello-world directory:
|
||||
|
||||
cd examples/hello-world
|
||||
|
||||
Run the 'make' command.
|
||||
|
||||
make
|
||||
|
||||
This will compile the hello-world program in the 'native' target. This causes
|
||||
the entire Contiki operating system and the hello-world application to be
|
||||
compiled into a single program that can be run by typing the following command:
|
||||
|
||||
./hello-world.native
|
||||
|
||||
This will print out the following text:
|
||||
|
||||
Contiki initiated, now starting process scheduling
|
||||
Hello, world
|
||||
|
||||
The program will then appear to hang, and must be stopped by pressing the C key
|
||||
while holding down the Control key.
|
||||
|
||||
irc/
|
||||
----
|
||||
|
||||
An IRC client. It can be compiled and run in the 'win32' target by
|
||||
typing the following commands:
|
||||
|
||||
cd examples/irc
|
||||
make
|
||||
./irc-client.win32
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/win32/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well.
|
||||
|
||||
multi-threading/
|
||||
----------------
|
||||
|
||||
A quite simple demonstration of the Contiki multi-threading library
|
||||
employing two worker threads each running a recursive function. It
|
||||
can be compiled and run in the 'native' target by typing the
|
||||
following commands:
|
||||
|
||||
cd examples/multi-threading
|
||||
make
|
||||
./multi-threading.native
|
||||
|
||||
rime/
|
||||
-----
|
||||
|
||||
Contains a set of examples on how to use the Rime communications
|
||||
stack. To run those examples in the 'netsim' target (a very simple
|
||||
Contiki network simulator), compile the programs with:
|
||||
|
||||
make TARGET=netsim
|
||||
|
||||
You will need to have GTK 1.x development libraries installed.
|
||||
|
||||
Run the different programs:
|
||||
|
||||
./test-abc.netsim
|
||||
./test-meshroute.netsim
|
||||
./test-rudolph0.netsim
|
||||
./test-rudolph1.netsim
|
||||
./test-treeroute.netsim
|
||||
./test-trickle.netsim
|
||||
|
||||
Most of the examples requires you to click with the middle mouse
|
||||
button on one of the simulated nodes for something to happen.
|
||||
|
||||
sky/
|
||||
----
|
||||
|
||||
Examples inteded for running on the Tmote Sky board. To compile those, you need
|
||||
to have msp430-gcc (the gcc C compiler for the MSP430 microcontroller)
|
||||
installed.
|
||||
|
||||
The follwing programs are included:
|
||||
|
||||
- blink.c A simple program that blinks the on-board LEDs
|
||||
- sky-collect.c Collects sensor data and energy profile values to a sink.
|
||||
Press the "user" button on the Tmote Sky that is connected to the PC to make
|
||||
the node a sink.
|
||||
- test-button.c Toggles the LEDs when the button is pressed.
|
||||
- test-cfs.c Tests the 1 mb flash memory of the Tmote Sky
|
||||
|
||||
telnet-server/
|
||||
--------------
|
||||
|
||||
A simple TCP telnet server with a simple command shell. It can be
|
||||
compiled and run in the 'minimal-net' target by typing the following
|
||||
commands:
|
||||
|
||||
cd examples/telnet-server
|
||||
make
|
||||
./telnet-server.minimal-net
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/minimal-net/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well if you are running
|
||||
Microsoft Windows.
|
||||
|
||||
webbrowser/
|
||||
-----------
|
||||
|
||||
A text mode web browser supporting links and forms. It can be compiled
|
||||
and run in the 'win32' target by typing the following commands:
|
||||
|
||||
cd examples/webbrowser
|
||||
make
|
||||
./webbrowser.win32
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/win32/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well.
|
||||
|
||||
webserver/
|
||||
----------
|
||||
|
||||
A web server supporting dynamic content creation using "scripts" which
|
||||
are actually compiled-in C-functions. It can be compiled and run in the
|
||||
'minimal-net' target by typing the following commands:
|
||||
|
||||
cd examples/webserver
|
||||
make
|
||||
./webserver-example.minimal-net
|
||||
|
||||
As an alternative to the static and dynamic compiled-in content the web
|
||||
server can instead support "external" static-only content loaded from
|
||||
any storage supported by the 'Contiki File System' (CFS) interface. To
|
||||
compile it in the 'minimal-net' target and have it load files from disk
|
||||
use the following command:
|
||||
|
||||
make HTTPD-CFS=1
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/minimal-net/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well if you are running
|
||||
Microsoft Windows.
|
||||
|
||||
wget/
|
||||
-----
|
||||
|
||||
A command line program that retrieves files from web servers and saves them
|
||||
using the 'Contiki File System' (CFS). It can be compiled and run in the
|
||||
'minimal-net' target by typing the following commands:
|
||||
|
||||
cd examples/wget
|
||||
make
|
||||
./wget.minimal-net
|
||||
|
||||
Most likely you'll have to adjust the TCP/IP values set in main() in
|
||||
platform/minimal-net/contiki-main.c to match your needs.
|
||||
|
||||
Please consult cpu/native/net/README-WPCAP.md as well if you are running
|
||||
Microsoft Windows.
|
||||
19
ARM_Tag_FW/cc2531_OEPL/contiki/README.md
Normal file
19
ARM_Tag_FW/cc2531_OEPL/contiki/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
The Contiki Operating System
|
||||
============================
|
||||
|
||||
[](https://travis-ci.org/contiki-os/contiki/branches)
|
||||
|
||||
Contiki is an open source operating system that runs on tiny low-power
|
||||
microcontrollers and makes it possible to develop applications that
|
||||
make efficient use of the hardware while providing standardized
|
||||
low-power wireless communication for a range of hardware platforms.
|
||||
|
||||
Contiki is used in numerous commercial and non-commercial systems,
|
||||
such as city sound monitoring, street lights, networked electrical
|
||||
power meters, industrial monitoring, radiation monitoring,
|
||||
construction site monitoring, alarm systems, remote house monitoring,
|
||||
and so on.
|
||||
|
||||
For more information, see the Contiki website:
|
||||
|
||||
[http://contiki-os.org](http://contiki-os.org)
|
||||
2
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/Makefile.about
Normal file
2
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/Makefile.about
Normal file
@@ -0,0 +1,2 @@
|
||||
about_src = about.c
|
||||
about_dsc = about-dsc.c
|
||||
72
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/about-dsc.c
Normal file
72
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/about-dsc.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Adam Dunkels.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki desktop environment
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sys/dsc.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if CTK_CONF_ICON_BITMAPS
|
||||
static unsigned char abouticon_bitmap[3*3*8] = {
|
||||
0x00, 0x7f, 0x43, 0x4c, 0x58, 0x53, 0x60, 0x6f,
|
||||
0x00, 0xff, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0xfe, 0xc2, 0x32, 0x1a, 0xca, 0x06, 0xf6,
|
||||
|
||||
0x40, 0x5f, 0x40, 0x5f, 0x40, 0x5f, 0x40, 0x4f,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xfc, 0x01, 0xf3,
|
||||
0x02, 0xfa, 0x02, 0x82, 0x3e, 0xfe, 0xfe, 0xfe,
|
||||
|
||||
0x60, 0x67, 0x50, 0x59, 0x4c, 0x43, 0x7f, 0x00,
|
||||
0x07, 0xe7, 0x0f, 0xef, 0x0f, 0x0f, 0xff, 0x00,
|
||||
0x8e, 0x06, 0x06, 0x06, 0x8e, 0xfe, 0xfe, 0x00
|
||||
};
|
||||
#endif /* CTK_CONF_ICON_BITMAPS */
|
||||
|
||||
#if CTK_CONF_ICON_TEXTMAPS
|
||||
static char abouticon_textmap[9] = {
|
||||
' ', ' ', 'c',
|
||||
' ', '?', ' ',
|
||||
'.', ' ', ' '
|
||||
};
|
||||
#endif /* CTK_CONF_ICON_TEXTMAPS */
|
||||
|
||||
#if CTK_CONF_ICONS
|
||||
static struct ctk_icon about_icon =
|
||||
{CTK_ICON("About Contiki", abouticon_bitmap, abouticon_textmap)};
|
||||
#endif /* CTK_CONF_ICONS */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
DSC(about_dsc,
|
||||
"About Contiki",
|
||||
"about.prg",
|
||||
about_process,
|
||||
&about_icon);
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
41
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/about-dsc.h
Normal file
41
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/about-dsc.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Adam Dunkels.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki desktop environment
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef ABOUT_DSC_H_
|
||||
#define ABOUT_DSC_H_
|
||||
|
||||
#include "sys/dsc.h"
|
||||
|
||||
DSC_HEADER(about_dsc);
|
||||
|
||||
#endif /* ABOUT_DSC_H_ */
|
||||
129
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/about.c
Normal file
129
ARM_Tag_FW/cc2531_OEPL/contiki/apps/about/about.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Adam Dunkels.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki desktop environment
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "contiki.h"
|
||||
#include "ctk/ctk.h"
|
||||
#include "lib/petsciiconv.h"
|
||||
|
||||
static struct ctk_window aboutdialog;
|
||||
static struct ctk_label aboutlabel1 =
|
||||
{CTK_LABEL(2, 0, 28, 1, "The Contiki Operating System")};
|
||||
static struct ctk_label aboutlabel2 =
|
||||
{CTK_LABEL(3, 2, 28, 1, "A modern, Internet-enabled")};
|
||||
static struct ctk_label aboutlabel3 =
|
||||
{CTK_LABEL(6, 3, 20, 1, "operating system and")};
|
||||
static struct ctk_label aboutlabel4 =
|
||||
{CTK_LABEL(6, 4, 20, 1, "desktop environment.")};
|
||||
|
||||
static char abouturl_petscii[] = "http://www.sics.se/~adam/contiki/";
|
||||
static char abouturl_ascii[40];
|
||||
static struct ctk_hyperlink abouturl =
|
||||
{CTK_HYPERLINK(0, 6, 32, "http://www.sics.se/~adam/contiki/",
|
||||
abouturl_ascii)};
|
||||
static struct ctk_button aboutclose =
|
||||
{CTK_BUTTON(12, 8, 5, "Close")};
|
||||
|
||||
|
||||
PROCESS(about_process, "About Contiki");
|
||||
|
||||
AUTOSTART_PROCESSES(&about_process);
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void
|
||||
about_quit(void)
|
||||
{
|
||||
ctk_dialog_close();
|
||||
process_exit(&about_process);
|
||||
LOADER_UNLOAD();
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(about_process, ev, data)
|
||||
{
|
||||
unsigned char width;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
width = ctk_desktop_width(NULL);
|
||||
|
||||
strcpy(abouturl_ascii, abouturl_petscii);
|
||||
petsciiconv_toascii(abouturl_ascii, sizeof(abouturl_ascii));
|
||||
|
||||
if(width > 34) {
|
||||
ctk_dialog_new(&aboutdialog, 32, 9);
|
||||
} else {
|
||||
ctk_dialog_new(&aboutdialog, width - 2, 9);
|
||||
}
|
||||
CTK_WIDGET_ADD(&aboutdialog, &aboutlabel1);
|
||||
CTK_WIDGET_ADD(&aboutdialog, &aboutlabel2);
|
||||
CTK_WIDGET_ADD(&aboutdialog, &aboutlabel3);
|
||||
CTK_WIDGET_ADD(&aboutdialog, &aboutlabel4);
|
||||
if(width > 34) {
|
||||
CTK_WIDGET_ADD(&aboutdialog, &abouturl);
|
||||
CTK_WIDGET_SET_FLAG(&abouturl, CTK_WIDGET_FLAG_MONOSPACE);
|
||||
} else {
|
||||
CTK_WIDGET_SET_XPOS(&aboutlabel1, 0);
|
||||
CTK_WIDGET_SET_XPOS(&aboutlabel2, 0);
|
||||
CTK_WIDGET_SET_XPOS(&aboutlabel3, 0);
|
||||
CTK_WIDGET_SET_XPOS(&aboutlabel4, 0);
|
||||
|
||||
CTK_WIDGET_SET_XPOS(&aboutclose, 0);
|
||||
}
|
||||
CTK_WIDGET_ADD(&aboutdialog, &aboutclose);
|
||||
CTK_WIDGET_FOCUS(&aboutdialog, &aboutclose);
|
||||
|
||||
ctk_dialog_open(&aboutdialog);
|
||||
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
if(ev == PROCESS_EVENT_EXIT) {
|
||||
about_quit();
|
||||
PROCESS_EXIT();
|
||||
} else if(ev == ctk_signal_button_activate) {
|
||||
if(data == (process_data_t)&aboutclose) {
|
||||
about_quit();
|
||||
PROCESS_EXIT();
|
||||
}
|
||||
} else if(ev == ctk_signal_hyperlink_activate) {
|
||||
if((struct ctk_widget *)data == (struct ctk_widget *)&abouturl) {
|
||||
about_quit();
|
||||
PROCESS_EXIT();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,4 @@
|
||||
antelope_src = antelope.c aql-adt.c aql-exec.c aql-lexer.c aql-parser.c \
|
||||
index.c index-inline.c index-maxheap.c lvm.c relation.c \
|
||||
result.c storage-cfs.c
|
||||
antelope_dsc =
|
||||
160
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/antelope.c
Normal file
160
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/antelope.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Main functions for Antelope, a DBMS for sensor devices.
|
||||
*
|
||||
* Antelope is described and evaluated in the paper A Database in
|
||||
* Every Sensor, N. Tsiftes and A. Dunkels, in Proceedings of
|
||||
* ACM SenSys 2011.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "antelope.h"
|
||||
|
||||
static db_output_function_t output = printf;
|
||||
|
||||
void
|
||||
db_init(void)
|
||||
{
|
||||
relation_init();
|
||||
index_init();
|
||||
}
|
||||
|
||||
void
|
||||
db_set_output_function(db_output_function_t f)
|
||||
{
|
||||
output = f;
|
||||
}
|
||||
|
||||
const char *
|
||||
db_get_result_message(db_result_t code)
|
||||
{
|
||||
switch(code) {
|
||||
case DB_FINISHED:
|
||||
return "Iteration finished";
|
||||
case DB_OK:
|
||||
return "Operation succeeded";
|
||||
case DB_LIMIT_ERROR:
|
||||
return "Limit reached";
|
||||
case DB_ALLOCATION_ERROR:
|
||||
return "Allocation error";
|
||||
case DB_STORAGE_ERROR:
|
||||
return "Storage error";
|
||||
case DB_PARSING_ERROR:
|
||||
return "Parsing error";
|
||||
case DB_NAME_ERROR:
|
||||
return "Invalid name";
|
||||
case DB_RELATIONAL_ERROR:
|
||||
return "Semantic error";
|
||||
case DB_TYPE_ERROR:
|
||||
return "Type error";
|
||||
case DB_IMPLEMENTATION_ERROR:
|
||||
return "Implementation error";
|
||||
case DB_INDEX_ERROR:
|
||||
return "Index error";
|
||||
case DB_BUSY_ERROR:
|
||||
return "Busy with processing";
|
||||
case DB_INCONSISTENCY_ERROR:
|
||||
return "Inconsistent handle";
|
||||
case DB_ARGUMENT_ERROR:
|
||||
return "Invalid argument";
|
||||
default:
|
||||
return "Unknown result code";
|
||||
};
|
||||
}
|
||||
|
||||
db_result_t
|
||||
db_print_header(db_handle_t *handle)
|
||||
{
|
||||
int column;
|
||||
attribute_t *attr;
|
||||
|
||||
output("[relation = %s, attributes = (", handle->result_rel->name);
|
||||
attr = list_head(handle->result_rel->attributes);
|
||||
for(column = 0; column < handle->ncolumns; column++) {
|
||||
if(attr == NULL) {
|
||||
return DB_IMPLEMENTATION_ERROR;
|
||||
} else if(attr->flags & ATTRIBUTE_FLAG_NO_STORE) {
|
||||
continue;
|
||||
}
|
||||
output("%s%s", column > 0 ? ", " : "", attr->name);
|
||||
attr = attr->next;
|
||||
}
|
||||
output(")]\n");
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
db_print_tuple(db_handle_t *handle)
|
||||
{
|
||||
int column;
|
||||
attribute_value_t value;
|
||||
db_result_t result;
|
||||
|
||||
output("Row %lu:\t", (unsigned long)handle->current_row);
|
||||
|
||||
for(column = 0; column < handle->ncolumns; column++) {
|
||||
result = db_get_value(&value, handle, column);
|
||||
if(DB_ERROR(result)) {
|
||||
output("Unable to get the value for row %lu, column %u: %s\n",
|
||||
(unsigned long)handle->current_row, column,
|
||||
db_get_result_message(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
switch(value.domain) {
|
||||
case DOMAIN_STRING:
|
||||
output("\"%s\"\t", VALUE_STRING(&value));
|
||||
break;
|
||||
case DOMAIN_INT:
|
||||
output("%d\t", (int)VALUE_INT(&value));
|
||||
break;
|
||||
case DOMAIN_LONG:
|
||||
output("%ld\t", (long)VALUE_LONG(&value));
|
||||
break;
|
||||
default:
|
||||
output("\nUnrecognized domain: %d\n", value.domain);
|
||||
return DB_IMPLEMENTATION_ERROR;
|
||||
}
|
||||
}
|
||||
output("\n");
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
db_processing(db_handle_t *handle)
|
||||
{
|
||||
return handle->flags & DB_HANDLE_FLAG_PROCESSING;
|
||||
}
|
||||
53
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/antelope.h
Normal file
53
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/antelope.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Declarations of the main Antelope functions.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include "db-types.h"
|
||||
#include "result.h"
|
||||
#include "aql.h"
|
||||
|
||||
typedef int (*db_output_function_t)(const char *, ...);
|
||||
|
||||
void db_init(void);
|
||||
void db_set_output_function(db_output_function_t f);
|
||||
const char *db_get_result_message(db_result_t code);
|
||||
db_result_t db_print_header(db_handle_t *handle);
|
||||
db_result_t db_print_tuple(db_handle_t *handle);
|
||||
int db_processing(db_handle_t *handle);
|
||||
|
||||
#endif /* DB_H */
|
||||
149
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-adt.c
Normal file
149
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-adt.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Utilities for building the internal representation of an AQL command.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "aql.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
static unsigned char char_buf[DB_MAX_CHAR_SIZE_PER_ROW];
|
||||
static uint8_t next_free_offset;
|
||||
|
||||
static aql_attribute_t *
|
||||
get_attribute(aql_adt_t *adt, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < AQL_ATTRIBUTE_COUNT(adt); i++) {
|
||||
if(strcmp(adt->attributes[i].name, name) == 0) {
|
||||
return &adt->attributes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
save_char(unsigned char *ptr, size_t length)
|
||||
{
|
||||
unsigned char *start_ptr;
|
||||
|
||||
if(length + next_free_offset > DB_MAX_CHAR_SIZE_PER_ROW) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
start_ptr = char_buf + next_free_offset;
|
||||
memcpy(start_ptr, ptr, length);
|
||||
next_free_offset += length;
|
||||
|
||||
return start_ptr;
|
||||
}
|
||||
|
||||
void
|
||||
aql_clear(aql_adt_t *adt)
|
||||
{
|
||||
char_buf[0] = 0;
|
||||
next_free_offset = 0;
|
||||
|
||||
adt->optype = AQL_TYPE_NONE;
|
||||
adt->relation_count = 0;
|
||||
adt->attribute_count = 0;
|
||||
adt->value_count = 0;
|
||||
adt->flags = 0;
|
||||
memset(adt->aggregators, 0, sizeof(adt->aggregators));
|
||||
}
|
||||
|
||||
db_result_t
|
||||
aql_add_attribute(aql_adt_t *adt, char *name, domain_t domain,
|
||||
unsigned element_size, int processed_only)
|
||||
{
|
||||
aql_attribute_t *attr;
|
||||
|
||||
if(adt->attribute_count == AQL_ATTRIBUTE_LIMIT) {
|
||||
return DB_LIMIT_ERROR;
|
||||
}
|
||||
|
||||
if(processed_only && get_attribute(adt, name)) {
|
||||
/* No need to have multiple instances of attributes that are only
|
||||
used for processing in the PLE. */
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
attr = &adt->attributes[adt->attribute_count++];
|
||||
|
||||
if(strlen(name) + 1 > sizeof(attr->name)) {
|
||||
return DB_LIMIT_ERROR;
|
||||
}
|
||||
|
||||
strcpy(attr->name, name);
|
||||
attr->domain = domain;
|
||||
attr->element_size = element_size;
|
||||
attr->flags = processed_only ? ATTRIBUTE_FLAG_NO_STORE : 0;
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
aql_add_value(aql_adt_t *adt, domain_t domain, void *value_ptr)
|
||||
{
|
||||
attribute_value_t *value;
|
||||
|
||||
if(adt->value_count == AQL_ATTRIBUTE_LIMIT) {
|
||||
return DB_LIMIT_ERROR;
|
||||
}
|
||||
|
||||
value = &adt->values[adt->value_count++];
|
||||
value->domain = domain;
|
||||
|
||||
switch(domain) {
|
||||
case DOMAIN_INT:
|
||||
VALUE_LONG(value) = *(long *)value_ptr;
|
||||
break;
|
||||
case DOMAIN_STRING:
|
||||
VALUE_STRING(value) = save_char(value_ptr, strlen(value_ptr) + 1);
|
||||
if(VALUE_STRING(value) != NULL) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return DB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
240
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-exec.c
Normal file
240
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-exec.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Query execution functions for AQL.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#include "index.h"
|
||||
#include "relation.h"
|
||||
#include "result.h"
|
||||
#include "aql.h"
|
||||
|
||||
static aql_adt_t adt;
|
||||
|
||||
static void
|
||||
clear_handle(db_handle_t *handle)
|
||||
{
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
handle->result_rel = NULL;
|
||||
handle->left_rel = NULL;
|
||||
handle->right_rel = NULL;
|
||||
handle->join_rel = NULL;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
aql_execute(db_handle_t *handle, aql_adt_t *adt)
|
||||
{
|
||||
uint8_t optype;
|
||||
int first_rel_arg;
|
||||
db_result_t result;
|
||||
relation_t *rel;
|
||||
aql_attribute_t *attr;
|
||||
attribute_t *relattr;
|
||||
|
||||
optype = AQL_GET_TYPE(adt);
|
||||
if(optype == AQL_TYPE_NONE) {
|
||||
/* No-ops always succeed. These can be generated by
|
||||
empty lines or comments in the query language. */
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
/* If the ASSIGN flag is set, the first relation in the array is
|
||||
the desired result relation. */
|
||||
first_rel_arg = !!(adt->flags & AQL_FLAG_ASSIGN);
|
||||
|
||||
if(optype != AQL_TYPE_CREATE_RELATION &&
|
||||
optype != AQL_TYPE_REMOVE_RELATION &&
|
||||
optype != AQL_TYPE_JOIN) {
|
||||
rel = relation_load(adt->relations[first_rel_arg]);
|
||||
if(rel == NULL) {
|
||||
return DB_NAME_ERROR;
|
||||
}
|
||||
} else {
|
||||
rel = NULL;
|
||||
}
|
||||
|
||||
result = DB_RELATIONAL_ERROR;
|
||||
switch(optype) {
|
||||
case AQL_TYPE_CREATE_ATTRIBUTE:
|
||||
attr = &adt->attributes[0];
|
||||
if(relation_attribute_add(rel, DB_STORAGE, attr->name, attr->domain,
|
||||
attr->element_size) != NULL) {
|
||||
result = DB_OK;
|
||||
}
|
||||
break;
|
||||
case AQL_TYPE_CREATE_INDEX:
|
||||
relattr = relation_attribute_get(rel, adt->attributes[0].name);
|
||||
if(relattr == NULL) {
|
||||
result = DB_NAME_ERROR;
|
||||
break;
|
||||
}
|
||||
result = index_create(AQL_GET_INDEX_TYPE(adt), rel, relattr);
|
||||
break;
|
||||
case AQL_TYPE_CREATE_RELATION:
|
||||
if(relation_create(adt->relations[0], DB_STORAGE) != NULL) {
|
||||
result = DB_OK;
|
||||
}
|
||||
break;
|
||||
case AQL_TYPE_REMOVE_ATTRIBUTE:
|
||||
result = relation_attribute_remove(rel, adt->attributes[0].name);
|
||||
break;
|
||||
case AQL_TYPE_REMOVE_INDEX:
|
||||
relattr = relation_attribute_get(rel, adt->attributes[0].name);
|
||||
if(relattr != NULL) {
|
||||
if(relattr->index != NULL) {
|
||||
result = index_destroy(relattr->index);
|
||||
} else {
|
||||
result = DB_OK;
|
||||
}
|
||||
} else {
|
||||
result = DB_NAME_ERROR;
|
||||
}
|
||||
break;
|
||||
case AQL_TYPE_REMOVE_RELATION:
|
||||
result = relation_remove(adt->relations[0], 1);
|
||||
break;
|
||||
#if DB_FEATURE_REMOVE
|
||||
case AQL_TYPE_REMOVE_TUPLES:
|
||||
/* Overwrite the attribute array with a full copy of the original
|
||||
relation's attributes. */
|
||||
adt->attribute_count = 0;
|
||||
for(relattr = list_head(rel->attributes);
|
||||
relattr != NULL;
|
||||
relattr = relattr->next) {
|
||||
AQL_ADD_ATTRIBUTE(adt, relattr->name, DOMAIN_UNSPECIFIED, 0);
|
||||
}
|
||||
AQL_SET_FLAG(adt, AQL_FLAG_INVERSE_LOGIC);
|
||||
#endif /* DB_FEATURE_REMOVE */
|
||||
case AQL_TYPE_SELECT:
|
||||
if(handle == NULL) {
|
||||
result = DB_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
result = relation_select(handle, rel, adt);
|
||||
break;
|
||||
case AQL_TYPE_INSERT:
|
||||
result = relation_insert(rel, adt->values);
|
||||
break;
|
||||
#if DB_FEATURE_JOIN
|
||||
case AQL_TYPE_JOIN:
|
||||
if(handle == NULL) {
|
||||
result = DB_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
handle->left_rel = relation_load(adt->relations[first_rel_arg]);
|
||||
if(handle->left_rel == NULL) {
|
||||
break;
|
||||
}
|
||||
handle->right_rel = relation_load(adt->relations[first_rel_arg + 1]);
|
||||
if(handle->right_rel == NULL) {
|
||||
relation_release(handle->left_rel);
|
||||
break;
|
||||
}
|
||||
result = relation_join(handle, adt);
|
||||
break;
|
||||
#endif /* DB_FEATURE_JOIN */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(rel != NULL) {
|
||||
if(handle == NULL || !(handle->flags & DB_HANDLE_FLAG_PROCESSING)) {
|
||||
relation_release(rel);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
db_query(db_handle_t *handle, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char query_string[AQL_MAX_QUERY_LENGTH];
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(query_string, sizeof(query_string), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if(handle != NULL) {
|
||||
clear_handle(handle);
|
||||
}
|
||||
|
||||
if(AQL_ERROR(aql_parse(&adt, query_string))) {
|
||||
return DB_PARSING_ERROR;
|
||||
}
|
||||
|
||||
/*aql_optimize(&adt);*/
|
||||
|
||||
return aql_execute(handle, &adt);
|
||||
}
|
||||
|
||||
db_result_t
|
||||
db_process(db_handle_t *handle)
|
||||
{
|
||||
uint8_t optype;
|
||||
|
||||
optype = ((aql_adt_t *)handle->adt)->optype;
|
||||
|
||||
switch(optype) {
|
||||
#if DB_FEATURE_REMOVE
|
||||
case AQL_TYPE_REMOVE_TUPLES:
|
||||
return relation_process_remove(handle);
|
||||
break;
|
||||
#endif
|
||||
case AQL_TYPE_SELECT:
|
||||
return relation_process_select(handle);
|
||||
break;
|
||||
#if DB_FEATURE_JOIN
|
||||
case AQL_TYPE_JOIN:
|
||||
return relation_process_join(handle);
|
||||
#endif /* DB_FEATURE_JOIN */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PRINTF("DB: Invalid operation type: %d\n", optype);
|
||||
|
||||
return DB_INCONSISTENCY_ERROR;
|
||||
}
|
||||
274
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-lexer.c
Normal file
274
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-lexer.c
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Lexical analyzer for AQL, the Antelope Query Language.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include "aql.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct keyword {
|
||||
char *string;
|
||||
token_t token;
|
||||
};
|
||||
|
||||
/* The keywords are arranged primarily by length and
|
||||
secondarily by expected lookup frequency. */
|
||||
static const struct keyword keywords[] = {
|
||||
{";", END},
|
||||
{"(", LEFT_PAREN},
|
||||
{")", RIGHT_PAREN},
|
||||
{",", COMMA},
|
||||
{"=", EQUAL},
|
||||
{">", GT},
|
||||
{"<", LT},
|
||||
{".", DOT},
|
||||
{"+", ADD},
|
||||
{"-", SUB},
|
||||
{"*", MUL},
|
||||
{"/", DIV},
|
||||
{"#", COMMENT},
|
||||
|
||||
{">=", GEQ},
|
||||
{"<=", LEQ},
|
||||
{"<>", NOT_EQUAL},
|
||||
{"<-", ASSIGN},
|
||||
{"OR", OR},
|
||||
{"IS", IS},
|
||||
{"ON", ON},
|
||||
{"IN", IN},
|
||||
|
||||
{"AND", AND},
|
||||
{"NOT", NOT},
|
||||
{"SUM", SUM},
|
||||
{"MAX", MAX},
|
||||
{"MIN", MIN},
|
||||
{"INT", INT},
|
||||
|
||||
{"INTO", INTO},
|
||||
{"FROM", FROM},
|
||||
{"MEAN", MEAN},
|
||||
{"JOIN", JOIN},
|
||||
{"LONG", LONG},
|
||||
{"TYPE", TYPE},
|
||||
|
||||
{"WHERE", WHERE},
|
||||
{"COUNT", COUNT},
|
||||
{"INDEX", INDEX},
|
||||
|
||||
{"INSERT", INSERT},
|
||||
{"SELECT", SELECT},
|
||||
{"REMOVE", REMOVE},
|
||||
{"CREATE", CREATE},
|
||||
{"MEDIAN", MEDIAN},
|
||||
{"DOMAIN", DOMAIN},
|
||||
{"STRING", STRING},
|
||||
{"INLINE", INLINE},
|
||||
|
||||
{"PROJECT", PROJECT},
|
||||
{"MAXHEAP", MAXHEAP},
|
||||
{"MEMHASH", MEMHASH},
|
||||
|
||||
{"RELATION", RELATION},
|
||||
|
||||
{"ATTRIBUTE", ATTRIBUTE}
|
||||
};
|
||||
|
||||
/* Provides a pointer to the first keyword of a specific length. */
|
||||
static const int8_t skip_hint[] = {0, 13, 21, 27, 33, 36, 44, 47, 48};
|
||||
|
||||
static char separators[] = "#.;,() \t\n";
|
||||
|
||||
int
|
||||
lexer_start(lexer_t *lexer, char *input, token_t *token, value_t *value)
|
||||
{
|
||||
lexer->input = input;
|
||||
lexer->prev_pos = input;
|
||||
lexer->token = token;
|
||||
lexer->value = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static token_t
|
||||
get_token_id(const char *string, const size_t length)
|
||||
{
|
||||
int start, end;
|
||||
int i;
|
||||
|
||||
if(sizeof(skip_hint) < length || length < 1) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
|
||||
start = skip_hint[length - 1];
|
||||
if(sizeof(skip_hint) == length) {
|
||||
end = sizeof(keywords) / sizeof(keywords[0]);
|
||||
} else {
|
||||
end = skip_hint[length];
|
||||
}
|
||||
|
||||
for(i = start; i < end; i++) {
|
||||
if(strncasecmp(keywords[i].string, string, length) == 0) {
|
||||
return keywords[i].token;
|
||||
}
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
next_real(lexer_t *lexer, const char *s)
|
||||
{
|
||||
char *end;
|
||||
long long_value;
|
||||
#if DB_FEATURE_FLOATS
|
||||
float float_value;
|
||||
#endif /* DB_FEATURE_FLOATS */
|
||||
|
||||
errno = 0;
|
||||
long_value = strtol(s, &end, 10);
|
||||
|
||||
#if DB_FEATURE_FLOATS
|
||||
if(*end == '.') {
|
||||
/* Process a float value. */
|
||||
float_value = strtof(s, &end);
|
||||
if(float_value == 0 && s == end) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(lexer->value, &float_value, sizeof(float_value));
|
||||
*lexer->token = FLOAT_VALUE;
|
||||
lexer->input = end;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* DB_FEATURE_FLOATS */
|
||||
|
||||
/* Process an integer value. */
|
||||
if(long_value == 0 && errno != 0) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(lexer->value, &long_value, sizeof(long_value));
|
||||
*lexer->token = INTEGER_VALUE;
|
||||
lexer->input = end;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
next_string(lexer_t *lexer, const char *s)
|
||||
{
|
||||
char *end;
|
||||
size_t length;
|
||||
|
||||
end = strchr(s, '\'');
|
||||
if(end == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = end - s;
|
||||
*lexer->token = STRING_VALUE;
|
||||
lexer->input = end + 1; /* Skip the closing delimiter. */
|
||||
|
||||
memcpy(lexer->value, s, length);
|
||||
(*lexer->value)[length] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
next_token(lexer_t *lexer, const char *s)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
length = strcspn(s, separators);
|
||||
if(length == 0) {
|
||||
/* We encountered a separator, so we try to get a token of
|
||||
precisely 1 byte. */
|
||||
length = 1;
|
||||
}
|
||||
|
||||
*lexer->token = get_token_id(s, length);
|
||||
lexer->input = s + length;
|
||||
if(*lexer->token != NONE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The input did not constitute a valid token,
|
||||
so we regard it as an identifier. */
|
||||
|
||||
*lexer->token = IDENTIFIER;
|
||||
|
||||
memcpy(lexer->value, s, length);
|
||||
(*lexer->value)[length] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lexer_next(lexer_t *lexer)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
*lexer->token = NONE;
|
||||
s = lexer->input;
|
||||
s += strspn(s, " \t\n");
|
||||
lexer->prev_pos = s;
|
||||
|
||||
switch(*s) {
|
||||
case '\'':
|
||||
/* Process the string that follows the delimiter. */
|
||||
return next_string(lexer, s + 1);
|
||||
case '\0':
|
||||
return 0;
|
||||
default:
|
||||
if(isdigit((int)*s) || (*s == '-' && isdigit((int)s[1]))) {
|
||||
return next_real(lexer, s);
|
||||
}
|
||||
|
||||
/* Process a token. */
|
||||
return next_token(lexer, s);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lexer_rewind(lexer_t *lexer)
|
||||
{
|
||||
lexer->input = lexer->prev_pos;
|
||||
}
|
||||
856
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-parser.c
Normal file
856
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql-parser.c
Normal file
@@ -0,0 +1,856 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* A recursive parser for AQL, the Antelope Query Language.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include "attribute.h"
|
||||
#include "db-options.h"
|
||||
#include "index.h"
|
||||
#include "aql.h"
|
||||
#include "lvm.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "debug.h"
|
||||
|
||||
#if DEBUG
|
||||
static char error_message[DB_ERROR_BUF_SIZE];
|
||||
static int error_line;
|
||||
static const char *error_function;
|
||||
#define RETURN(value) \
|
||||
do { \
|
||||
if(error_message[0] == '\0') { \
|
||||
strncpy(error_message, lexer->input, sizeof(error_message) - 1); \
|
||||
error_line = __LINE__; \
|
||||
error_function = __func__; \
|
||||
} \
|
||||
} while(0); \
|
||||
return (value)
|
||||
#define RESET_ERROR() \
|
||||
do { \
|
||||
error_message[0] = '\0'; \
|
||||
error_line = 0; \
|
||||
error_function = NULL; \
|
||||
} while(0)
|
||||
#else
|
||||
#define RETURN(value) return (value)
|
||||
#define RESET_ERROR()
|
||||
#endif
|
||||
#define PARSER(name) \
|
||||
static aql_status_t \
|
||||
parse_##name(lexer_t *lexer)
|
||||
#define PARSER_ARG(name, arg) \
|
||||
static aql_status_t \
|
||||
parse_##name(lexer_t *lexer, arg)
|
||||
#define PARSER_TOKEN(name) \
|
||||
static token_t \
|
||||
parse_##name(lexer_t *lexer)
|
||||
#define PARSE(name) \
|
||||
!AQL_ERROR(parse_##name(lexer))
|
||||
#define PARSE_TOKEN(name) \
|
||||
parse_##name(lexer)
|
||||
|
||||
#define NEXT lexer_next(lexer)
|
||||
#define REWIND lexer_rewind(lexer); RESET_ERROR()
|
||||
#define TOKEN *lexer->token
|
||||
#define VALUE *lexer->value
|
||||
|
||||
#define CONSUME(token) \
|
||||
do { \
|
||||
NEXT; \
|
||||
if(TOKEN != (token)) { \
|
||||
RETURN(SYNTAX_ERROR); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* The parsing of AQL results in this aql_adt_t object. */
|
||||
static aql_adt_t *adt;
|
||||
|
||||
/* Conditional statements are compiled into VM bytecode, which is stored in
|
||||
an instance of the LogicVM. */
|
||||
static lvm_instance_t p;
|
||||
static unsigned char vmcode[DB_VM_BYTECODE_SIZE];
|
||||
|
||||
/* Parsing functions for AQL. */
|
||||
PARSER_TOKEN(cmp)
|
||||
{
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case EQUAL:
|
||||
case NOT_EQUAL:
|
||||
case GT:
|
||||
case LT:
|
||||
case GEQ:
|
||||
case LEQ:
|
||||
return TOKEN;
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
PARSER_TOKEN(op)
|
||||
{
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case ADD:
|
||||
case SUB:
|
||||
case MUL:
|
||||
case DIV:
|
||||
case RIGHT_PAREN:
|
||||
return TOKEN;
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
PARSER_TOKEN(aggregator)
|
||||
{
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case COUNT:
|
||||
case SUM:
|
||||
case MEAN:
|
||||
case MEDIAN:
|
||||
case MAX:
|
||||
case MIN:
|
||||
return TOKEN;
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
PARSER(attributes)
|
||||
{
|
||||
token_t token;
|
||||
aql_aggregator_t function;
|
||||
|
||||
token = PARSE_TOKEN(aggregator);
|
||||
if(token != NONE) {
|
||||
switch(TOKEN) {
|
||||
case COUNT:
|
||||
function = AQL_COUNT;
|
||||
break;
|
||||
case SUM:
|
||||
function = AQL_SUM;
|
||||
break;
|
||||
case MEAN:
|
||||
function = AQL_MEAN;
|
||||
break;
|
||||
case MEDIAN:
|
||||
function = AQL_MEDIAN;
|
||||
break;
|
||||
case MAX:
|
||||
function = AQL_MAX;
|
||||
break;
|
||||
case MIN:
|
||||
function = AQL_MIN;
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
AQL_SET_FLAG(adt, AQL_FLAG_AGGREGATE);
|
||||
|
||||
PRINTF("aggregator: %d\n", TOKEN);
|
||||
|
||||
/* Parse the attribute to aggregate. */
|
||||
CONSUME(LEFT_PAREN);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
AQL_ADD_AGGREGATE(adt, function, VALUE);
|
||||
PRINTF("aggregated attribute: %s\n", VALUE);
|
||||
|
||||
CONSUME(RIGHT_PAREN);
|
||||
goto check_more_attributes;
|
||||
} else {
|
||||
REWIND;
|
||||
}
|
||||
|
||||
/* Plain identifier. */
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
|
||||
|
||||
check_more_attributes:
|
||||
NEXT;
|
||||
if(TOKEN == COMMA) {
|
||||
if(!PARSE(attributes)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
} else {
|
||||
REWIND;
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(relations)
|
||||
{
|
||||
/* Parse comma-separated identifiers for relations. */
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
NEXT;
|
||||
if(TOKEN == COMMA) {
|
||||
if(!PARSE(relations)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
} else {
|
||||
REWIND;
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(values)
|
||||
{
|
||||
/* Parse comma-separated attribute values. */
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case STRING_VALUE:
|
||||
AQL_ADD_VALUE(adt, DOMAIN_STRING, VALUE);
|
||||
break;
|
||||
case INTEGER_VALUE:
|
||||
AQL_ADD_VALUE(adt, DOMAIN_INT, VALUE);
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
NEXT;
|
||||
if(TOKEN == COMMA) {
|
||||
return PARSE(values);
|
||||
} else {
|
||||
REWIND;
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(operand)
|
||||
{
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case IDENTIFIER:
|
||||
lvm_register_variable(VALUE, LVM_LONG);
|
||||
lvm_set_variable(&p, VALUE);
|
||||
AQL_ADD_PROCESSING_ATTRIBUTE(adt, VALUE);
|
||||
break;
|
||||
case STRING_VALUE:
|
||||
break;
|
||||
case FLOAT_VALUE:
|
||||
break;
|
||||
case INTEGER_VALUE:
|
||||
lvm_set_long(&p, *(long *)lexer->value);
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(expr)
|
||||
{
|
||||
token_t token;
|
||||
size_t saved_end;
|
||||
operator_t op;
|
||||
|
||||
saved_end = lvm_get_end(&p);
|
||||
|
||||
NEXT;
|
||||
if(TOKEN == LEFT_PAREN) {
|
||||
if(!PARSE(expr)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
CONSUME(RIGHT_PAREN);
|
||||
} else {
|
||||
REWIND;
|
||||
if(!PARSE(operand)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
while(1) {
|
||||
token = PARSE_TOKEN(op);
|
||||
if(token == NONE) {
|
||||
saved_end = lvm_get_end(&p);
|
||||
REWIND;
|
||||
break;
|
||||
} else if (token == RIGHT_PAREN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!PARSE(operand) && !PARSE(expr)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
saved_end = lvm_shift_for_operator(&p, saved_end);
|
||||
|
||||
switch(token) {
|
||||
case ADD:
|
||||
op = LVM_ADD;
|
||||
break;
|
||||
case SUB:
|
||||
op = LVM_SUB;
|
||||
break;
|
||||
case MUL:
|
||||
op = LVM_MUL;
|
||||
break;
|
||||
case DIV:
|
||||
op = LVM_DIV;
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
lvm_set_op(&p, op);
|
||||
lvm_set_end(&p, saved_end);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
PARSER(comparison)
|
||||
{
|
||||
token_t token;
|
||||
size_t saved_end;
|
||||
operator_t rel;
|
||||
|
||||
saved_end = lvm_jump_to_operand(&p);
|
||||
|
||||
if(!PARSE(expr)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
saved_end = lvm_set_end(&p, saved_end);
|
||||
|
||||
token = PARSE_TOKEN(cmp);
|
||||
if(token == NONE) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
switch(token) {
|
||||
case GT:
|
||||
rel = LVM_GE;
|
||||
break;
|
||||
case GEQ:
|
||||
rel = LVM_GEQ;
|
||||
break;
|
||||
case LT:
|
||||
rel = LVM_LE;
|
||||
break;
|
||||
case LEQ:
|
||||
rel = LVM_LEQ;
|
||||
break;
|
||||
case EQUAL:
|
||||
rel = LVM_EQ;
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
rel = LVM_NEQ;
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
lvm_set_relation(&p, rel);
|
||||
lvm_set_end(&p, saved_end);
|
||||
|
||||
if(!PARSE(expr)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(where)
|
||||
{
|
||||
int r;
|
||||
operator_t connective;
|
||||
size_t saved_end;
|
||||
|
||||
if(!PARSE(comparison)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
saved_end = 0;
|
||||
|
||||
/* The WHERE clause can consist of multiple prepositions. */
|
||||
for(;;) {
|
||||
NEXT;
|
||||
if(TOKEN != AND && TOKEN != OR) {
|
||||
REWIND;
|
||||
break;
|
||||
}
|
||||
|
||||
connective = TOKEN == AND ? LVM_AND : LVM_OR;
|
||||
|
||||
saved_end = lvm_shift_for_operator(&p, saved_end);
|
||||
lvm_set_relation(&p, connective);
|
||||
lvm_set_end(&p, saved_end);
|
||||
|
||||
NEXT;
|
||||
if(TOKEN == LEFT_PAREN) {
|
||||
r = PARSE(where);
|
||||
if(!r) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
CONSUME(RIGHT_PAREN);
|
||||
} else {
|
||||
REWIND;
|
||||
r = PARSE(comparison);
|
||||
if(!r) {
|
||||
RETURN(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lvm_print_code(&p);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
PARSER(join)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_JOIN);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
PRINTF("Left relation: %s\n", VALUE);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
CONSUME(COMMA);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
PRINTF("Right relation: %s\n", VALUE);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
CONSUME(ON);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
PRINTF("Join on attribute %s\n", VALUE);
|
||||
AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
|
||||
|
||||
CONSUME(PROJECT);
|
||||
|
||||
/* projection attributes... */
|
||||
if(!PARSE(attributes)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
CONSUME(END);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(select)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_SELECT);
|
||||
|
||||
/* projection attributes... */
|
||||
if(!PARSE(attributes)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
CONSUME(FROM);
|
||||
if(!PARSE(relations)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
NEXT;
|
||||
if(TOKEN == WHERE) {
|
||||
lvm_reset(&p, vmcode, sizeof(vmcode));
|
||||
|
||||
if(!PARSE(where)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
AQL_SET_CONDITION(adt, &p);
|
||||
} else {
|
||||
REWIND;
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
CONSUME(END);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
PARSER(insert)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_INSERT);
|
||||
|
||||
CONSUME(LEFT_PAREN);
|
||||
|
||||
if(!PARSE(values)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
CONSUME(RIGHT_PAREN);
|
||||
CONSUME(INTO);
|
||||
|
||||
if(!PARSE(relations)) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(remove_attribute)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_ATTRIBUTE);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
CONSUME(DOT);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
PRINTF("Removing the index for the attribute %s\n", VALUE);
|
||||
AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
#if DB_FEATURE_REMOVE
|
||||
PARSER(remove_from)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_TUPLES);
|
||||
|
||||
/* Use a temporary persistent relation to assign the query result to. */
|
||||
AQL_SET_FLAG(adt, AQL_FLAG_ASSIGN);
|
||||
AQL_ADD_RELATION(adt, REMOVE_RELATION);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
CONSUME(WHERE);
|
||||
|
||||
lvm_reset(&p, vmcode, sizeof(vmcode));
|
||||
AQL_SET_CONDITION(adt, &p);
|
||||
|
||||
return PARSE(where);
|
||||
|
||||
}
|
||||
#endif /* DB_FEATURE_REMOVE */
|
||||
|
||||
PARSER(remove_index)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_INDEX);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
CONSUME(DOT);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
PRINTF("remove index: %s\n", VALUE);
|
||||
AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(remove_relation)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_RELATION);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
PRINTF("remove relation: %s\n", VALUE);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(remove)
|
||||
{
|
||||
aql_status_t r;
|
||||
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case ATTRIBUTE:
|
||||
r = PARSE(remove_attribute);
|
||||
break;
|
||||
#if DB_FEATURE_REMOVE
|
||||
case FROM:
|
||||
r = PARSE(remove_from);
|
||||
break;
|
||||
#endif
|
||||
case INDEX:
|
||||
r = PARSE(remove_index);
|
||||
break;
|
||||
case RELATION:
|
||||
r = PARSE(remove_relation);
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
if(!r) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
CONSUME(END);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER_TOKEN(index_type)
|
||||
{
|
||||
index_type_t type;
|
||||
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case INLINE:
|
||||
type = INDEX_INLINE;
|
||||
break;
|
||||
case MAXHEAP:
|
||||
type = INDEX_MAXHEAP;
|
||||
break;
|
||||
case MEMHASH:
|
||||
type = INDEX_MEMHASH;
|
||||
break;
|
||||
default:
|
||||
return NONE;
|
||||
};
|
||||
|
||||
AQL_SET_INDEX_TYPE(adt, type);
|
||||
return TOKEN;
|
||||
}
|
||||
|
||||
PARSER(create_index)
|
||||
{
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_CREATE_INDEX);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
CONSUME(DOT);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
PRINTF("Creating an index for the attribute %s\n", VALUE);
|
||||
AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
|
||||
|
||||
CONSUME(TYPE);
|
||||
|
||||
if(PARSE_TOKEN(index_type) == NONE) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(create_relation)
|
||||
{
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_CREATE_RELATION);
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER_ARG(domain, char *name)
|
||||
{
|
||||
domain_t domain;
|
||||
unsigned element_size;
|
||||
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case STRING:
|
||||
domain = DOMAIN_STRING;
|
||||
|
||||
/* Parse the amount of characters for this domain. */
|
||||
CONSUME(LEFT_PAREN);
|
||||
CONSUME(INTEGER_VALUE);
|
||||
element_size = *(long *)lexer->value;
|
||||
CONSUME(RIGHT_PAREN);
|
||||
|
||||
break;
|
||||
case LONG:
|
||||
domain = DOMAIN_LONG;
|
||||
element_size = 4;
|
||||
break;
|
||||
case INT:
|
||||
domain = DOMAIN_INT;
|
||||
element_size = 2;
|
||||
break;
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
|
||||
AQL_ADD_ATTRIBUTE(adt, name, domain, element_size);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
PARSER(create_attributes)
|
||||
{
|
||||
aql_status_t r;
|
||||
char name[ATTRIBUTE_NAME_LENGTH];
|
||||
|
||||
AQL_SET_TYPE(adt, AQL_TYPE_CREATE_ATTRIBUTE);
|
||||
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
strncpy(name, VALUE, sizeof(name) - 1);
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
|
||||
CONSUME(DOMAIN);
|
||||
|
||||
r = parse_domain(lexer, name);
|
||||
if(AQL_ERROR(r)) {
|
||||
RETURN(r);
|
||||
}
|
||||
|
||||
CONSUME(IN);
|
||||
CONSUME(IDENTIFIER);
|
||||
|
||||
AQL_ADD_RELATION(adt, VALUE);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
PARSER(create)
|
||||
{
|
||||
aql_status_t r;
|
||||
|
||||
NEXT;
|
||||
switch(TOKEN) {
|
||||
case ATTRIBUTE:
|
||||
r = PARSE(create_attributes);
|
||||
break;
|
||||
case INDEX:
|
||||
r = PARSE(create_index);
|
||||
break;
|
||||
case RELATION:
|
||||
r = PARSE(create_relation);
|
||||
break;
|
||||
default:
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
if(!r) {
|
||||
RETURN(SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
CONSUME(END);
|
||||
|
||||
RETURN(OK);
|
||||
}
|
||||
|
||||
aql_status_t
|
||||
aql_parse(aql_adt_t *external_adt, char *input_string)
|
||||
{
|
||||
lexer_t lex;
|
||||
token_t token = NONE;
|
||||
value_t value;
|
||||
aql_status_t result;
|
||||
|
||||
RESET_ERROR();
|
||||
|
||||
PRINTF("Parsing \"%s\"\n", input_string);
|
||||
|
||||
adt = external_adt;
|
||||
AQL_CLEAR(adt);
|
||||
AQL_SET_CONDITION(adt, NULL);
|
||||
|
||||
lexer_start(&lex, input_string, &token, &value);
|
||||
|
||||
result = lexer_next(&lex);
|
||||
if(!AQL_ERROR(result)) {
|
||||
switch(token) {
|
||||
case IDENTIFIER:
|
||||
PRINTF("Assign the result to relation %s\n", *lex.value);
|
||||
AQL_ADD_RELATION(adt, *lex.value);
|
||||
AQL_SET_FLAG(adt, AQL_FLAG_ASSIGN);
|
||||
if(AQL_ERROR(lexer_next(&lex))) {
|
||||
result = SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
if(*lex.token != ASSIGN) {
|
||||
result = SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
if(AQL_ERROR(lexer_next(&lex))) {
|
||||
result = SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
switch(*lex.token) {
|
||||
case SELECT:
|
||||
result = parse_select(&lex);
|
||||
break;
|
||||
case JOIN:
|
||||
result = parse_join(&lex);
|
||||
break;
|
||||
default:
|
||||
result = SYNTAX_ERROR;
|
||||
}
|
||||
break;
|
||||
case JOIN:
|
||||
result = parse_join(&lex);
|
||||
break;
|
||||
case CREATE:
|
||||
result = parse_create(&lex);
|
||||
break;
|
||||
case REMOVE:
|
||||
result = parse_remove(&lex);
|
||||
break;
|
||||
case INSERT:
|
||||
result = parse_insert(&lex);
|
||||
break;
|
||||
case SELECT:
|
||||
result = parse_select(&lex);
|
||||
break;
|
||||
case NONE:
|
||||
case COMMENT:
|
||||
result = OK;
|
||||
case END:
|
||||
break;
|
||||
default:
|
||||
result = SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(AQL_ERROR(result)) {
|
||||
PRINTF("Error in function %s, line %d: input \"%s\"\n",
|
||||
error_function, error_line, error_message);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
221
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql.h
Normal file
221
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/aql.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Definitions and declarations for AQL, the Antelope Query Language.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef AQL_H
|
||||
#define AQL_H
|
||||
|
||||
#include "db-options.h"
|
||||
#include "index.h"
|
||||
#include "relation.h"
|
||||
#include "result.h"
|
||||
|
||||
enum aql_status {
|
||||
OK = 2,
|
||||
SYNTAX_ERROR = 3,
|
||||
INVALID_TOKEN = 9,
|
||||
PLE_ERROR = 12
|
||||
};
|
||||
typedef enum aql_status aql_status_t;
|
||||
#define AQL_ERROR(x) ((x) >= 3)
|
||||
|
||||
enum token {
|
||||
END = 0,
|
||||
LEFT_PAREN = 1,
|
||||
RIGHT_PAREN = 2,
|
||||
COMMA = 3,
|
||||
EQUAL = 4,
|
||||
GT = 5,
|
||||
LT = 6,
|
||||
DOT = 7,
|
||||
ADD = 8,
|
||||
SUB = 9,
|
||||
MUL = 10,
|
||||
DIV = 11,
|
||||
COMMENT = 12,
|
||||
GEQ = 13,
|
||||
LEQ = 14,
|
||||
NOT_EQUAL = 15,
|
||||
ASSIGN = 16,
|
||||
OR = 17,
|
||||
IS = 18,
|
||||
ON = 19,
|
||||
IN = 20,
|
||||
AND = 21,
|
||||
NOT = 22,
|
||||
SUM = 23,
|
||||
MAX = 24,
|
||||
MIN = 25,
|
||||
INT = 26,
|
||||
INTO = 27,
|
||||
FROM = 28,
|
||||
MEAN = 29,
|
||||
JOIN = 30,
|
||||
LONG = 31,
|
||||
TYPE = 32,
|
||||
WHERE = 33,
|
||||
COUNT = 34,
|
||||
INDEX = 35,
|
||||
INSERT = 36,
|
||||
SELECT = 37,
|
||||
REMOVE = 38,
|
||||
CREATE = 39,
|
||||
MEDIAN = 40,
|
||||
DOMAIN = 41,
|
||||
STRING = 42,
|
||||
INLINE = 43,
|
||||
PROJECT = 44,
|
||||
MAXHEAP = 45,
|
||||
MEMHASH = 46,
|
||||
RELATION = 47,
|
||||
ATTRIBUTE = 48,
|
||||
|
||||
INTEGER_VALUE = 251,
|
||||
FLOAT_VALUE = 252,
|
||||
STRING_VALUE = 253,
|
||||
IDENTIFIER = 254,
|
||||
NONE = 255
|
||||
};
|
||||
|
||||
typedef enum token token_t;
|
||||
|
||||
typedef char value_t[DB_MAX_ELEMENT_SIZE];
|
||||
|
||||
struct lexer {
|
||||
const char *input;
|
||||
const char *prev_pos;
|
||||
token_t *token;
|
||||
value_t *value;
|
||||
};
|
||||
|
||||
typedef struct lexer lexer_t;
|
||||
|
||||
enum aql_aggregator {
|
||||
AQL_NONE = 0,
|
||||
AQL_COUNT = 1,
|
||||
AQL_SUM = 2,
|
||||
AQL_MIN = 3,
|
||||
AQL_MAX = 4,
|
||||
AQL_MEAN = 5,
|
||||
AQL_MEDIAN = 6
|
||||
};
|
||||
|
||||
typedef enum aql_aggregator aql_aggregator_t;
|
||||
|
||||
struct aql_attribute {
|
||||
domain_t domain;
|
||||
uint8_t element_size;
|
||||
uint8_t flags;
|
||||
char name[ATTRIBUTE_NAME_LENGTH + 1];
|
||||
};
|
||||
typedef struct aql_attribute aql_attribute_t;
|
||||
|
||||
struct aql_adt {
|
||||
char relations[AQL_RELATION_LIMIT][RELATION_NAME_LENGTH + 1];
|
||||
aql_attribute_t attributes[AQL_ATTRIBUTE_LIMIT];
|
||||
aql_aggregator_t aggregators[AQL_ATTRIBUTE_LIMIT];
|
||||
attribute_value_t values[AQL_ATTRIBUTE_LIMIT];
|
||||
index_type_t index_type;
|
||||
uint8_t relation_count;
|
||||
uint8_t attribute_count;
|
||||
uint8_t value_count;
|
||||
uint8_t optype;
|
||||
uint8_t flags;
|
||||
void *lvm_instance;
|
||||
};
|
||||
typedef struct aql_adt aql_adt_t;
|
||||
|
||||
#define AQL_TYPE_NONE 0
|
||||
#define AQL_TYPE_SELECT 1
|
||||
#define AQL_TYPE_INSERT 2
|
||||
#define AQL_TYPE_UPDATE 3
|
||||
#define AQL_TYPE_DROP 4
|
||||
#define AQL_TYPE_DELETE 5
|
||||
#define AQL_TYPE_RENAME 6
|
||||
#define AQL_TYPE_CREATE_ATTRIBUTE 7
|
||||
#define AQL_TYPE_CREATE_INDEX 8
|
||||
#define AQL_TYPE_CREATE_RELATION 9
|
||||
#define AQL_TYPE_REMOVE_ATTRIBUTE 10
|
||||
#define AQL_TYPE_REMOVE_INDEX 11
|
||||
#define AQL_TYPE_REMOVE_RELATION 12
|
||||
#define AQL_TYPE_REMOVE_TUPLES 13
|
||||
#define AQL_TYPE_JOIN 14
|
||||
|
||||
#define AQL_FLAG_AGGREGATE 1
|
||||
#define AQL_FLAG_ASSIGN 2
|
||||
#define AQL_FLAG_INVERSE_LOGIC 4
|
||||
|
||||
#define AQL_CLEAR(adt) aql_clear(adt)
|
||||
#define AQL_SET_TYPE(adt, type) (((adt))->optype = (type))
|
||||
#define AQL_GET_TYPE(adt) ((adt)->optype)
|
||||
#define AQL_SET_INDEX_TYPE(adt, type) ((adt)->index_type = (type))
|
||||
#define AQL_GET_INDEX_TYPE(adt) ((adt)->index_type)
|
||||
|
||||
#define AQL_SET_FLAG(adt, flag) (((adt)->flags) |= (flag))
|
||||
#define AQL_GET_FLAGS(adt) ((adt)->flags)
|
||||
#define AQL_ADD_RELATION(adt, rel) \
|
||||
strcpy((adt)->relations[(adt)->relation_count++], (rel))
|
||||
#define AQL_RELATION_COUNT(adt) ((adt)->relation_count)
|
||||
#define AQL_ADD_ATTRIBUTE(adt, attr, dom, size) \
|
||||
aql_add_attribute(adt, attr, dom, size, 0)
|
||||
#define AQL_ADD_PROCESSING_ATTRIBUTE(adt, attr) \
|
||||
aql_add_attribute((adt), (attr), DOMAIN_UNSPECIFIED, 0, 1)
|
||||
#define AQL_ADD_AGGREGATE(adt, function, attr) \
|
||||
do { \
|
||||
(adt)->aggregators[(adt)->attribute_count] = (function); \
|
||||
aql_add_attribute((adt), (attr), DOMAIN_UNSPECIFIED, 0, 0); \
|
||||
} while(0)
|
||||
#define AQL_ATTRIBUTE_COUNT(adt) ((adt)->attribute_count)
|
||||
#define AQL_SET_CONDITION(adt, cond) ((adt)->lvm_instance = (cond))
|
||||
#define AQL_ADD_VALUE(adt, domain, value) \
|
||||
aql_add_value((adt), (domain), (value))
|
||||
|
||||
int lexer_start(lexer_t *, char *, token_t *, value_t *);
|
||||
int lexer_next(lexer_t *);
|
||||
void lexer_rewind(lexer_t *);
|
||||
|
||||
void aql_clear(aql_adt_t *adt);
|
||||
aql_status_t aql_parse(aql_adt_t *adt, char *query_string);
|
||||
db_result_t aql_add_attribute(aql_adt_t *adt, char *name,
|
||||
domain_t domain, unsigned element_size,
|
||||
int processed_only);
|
||||
db_result_t aql_add_value(aql_adt_t *adt, domain_t domain, void *value);
|
||||
db_result_t db_query(db_handle_t *handle, const char *format, ...);
|
||||
db_result_t db_process(db_handle_t *handle);
|
||||
|
||||
#endif /* !AQL_H */
|
||||
89
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/attribute.h
Normal file
89
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/attribute.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Definitions for attributes.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef ATTRIBUTE_H
|
||||
#define ATTRIBUTE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lib/list.h"
|
||||
|
||||
#include "db-options.h"
|
||||
|
||||
typedef enum {
|
||||
DOMAIN_UNSPECIFIED = 0,
|
||||
DOMAIN_INT = 1,
|
||||
DOMAIN_LONG = 2,
|
||||
DOMAIN_STRING = 3,
|
||||
DOMAIN_FLOAT = 4
|
||||
} domain_t;
|
||||
|
||||
#define ATTRIBUTE_FLAG_NO_STORE 0x1
|
||||
#define ATTRIBUTE_FLAG_INVALID 0x2
|
||||
#define ATTRIBUTE_FLAG_PRIMARY_KEY 0x4
|
||||
#define ATTRIBUTE_FLAG_UNIQUE 0x8
|
||||
|
||||
struct attribute {
|
||||
struct attribute *next;
|
||||
void *index;
|
||||
long aggregation_value;
|
||||
uint8_t aggregator;
|
||||
uint8_t domain;
|
||||
uint8_t element_size;
|
||||
uint8_t flags;
|
||||
char name[ATTRIBUTE_NAME_LENGTH + 1];
|
||||
};
|
||||
|
||||
typedef struct attribute attribute_t;
|
||||
typedef uint8_t attribute_id_t;
|
||||
|
||||
struct attribute_value {
|
||||
union {
|
||||
int int_value;
|
||||
long long_value;
|
||||
unsigned char *string_value;
|
||||
} u;
|
||||
domain_t domain;
|
||||
};
|
||||
|
||||
typedef struct attribute_value attribute_value_t;
|
||||
|
||||
#define VALUE_LONG(value) (value)->u.long_value
|
||||
#define VALUE_INT(value) (value)->u.int_value
|
||||
#define VALUE_STRING(value) (value)->u.string_value
|
||||
|
||||
#endif /* ATTRIBUTES_H */
|
||||
231
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/db-options.h
Normal file
231
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/db-options.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Database configuration options.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef DB_OPTIONS_H
|
||||
#define DB_OPTIONS_H
|
||||
|
||||
#include "contiki-conf.h"
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Optional Antelope features. Include only what is needed
|
||||
in order to save space. */
|
||||
|
||||
/* Support join operations on relations. */
|
||||
#ifndef DB_FEATURE_JOIN
|
||||
#define DB_FEATURE_JOIN 1
|
||||
#endif /* DB_FEATURE_JOIN */
|
||||
|
||||
/* Support tuple removals. */
|
||||
#ifndef DB_FEATURE_REMOVE
|
||||
#define DB_FEATURE_REMOVE 1
|
||||
#endif /* DB_FEATURE_REMOVE */
|
||||
|
||||
/* Support floating-point values in attributes. */
|
||||
#ifndef DB_FEATURE_FLOATS
|
||||
#define DB_FEATURE_FLOATS 0
|
||||
#endif /* DB_FEATURE_FLOATS */
|
||||
|
||||
/* Optimize storage access for the Coffee file system. */
|
||||
#ifndef DB_FEATURE_COFFEE
|
||||
#define DB_FEATURE_COFFEE 1
|
||||
#endif /* DB_FEATURE_COFFEE */
|
||||
|
||||
/* Enable basic data integrity checks. */
|
||||
#ifndef DB_FEATURE_INTEGRITY
|
||||
#define DB_FEATURE_INTEGRITY 0
|
||||
#endif /* DB_FEATURE_INTEGRITY */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Configuration parameters that may be trimmed to save space. */
|
||||
|
||||
/* The size of the error message buffer used by the parser. */
|
||||
#ifndef DB_ERROR_BUF_SIZE
|
||||
#define DB_ERROR_BUF_SIZE 50
|
||||
#endif /* DB_ERROR_BUF_SIZE */
|
||||
|
||||
/* The maximum number of indexes in use by all relations loaded in memory. */
|
||||
#ifndef DB_INDEX_POOL_SIZE
|
||||
#define DB_INDEX_POOL_SIZE 3
|
||||
#endif /* DB_INDEX_POOL_SIZE */
|
||||
|
||||
/* The maximum number of relations loaded in memory. */
|
||||
#ifndef DB_RELATION_POOL_SIZE
|
||||
#define DB_RELATION_POOL_SIZE 5
|
||||
#endif /* DB_RELATION_POOL_SIZE */
|
||||
|
||||
/* The maximum number of attributes loaded in memory. */
|
||||
#ifndef DB_ATTRIBUTE_POOL_SIZE
|
||||
#define DB_ATTRIBUTE_POOL_SIZE 16
|
||||
#endif /* DB_ATTRIBUTE_POOL_SIZE */
|
||||
|
||||
/* The maximum number of attributes in a relation. */
|
||||
#ifndef DB_MAX_ATTRIBUTES_PER_RELATION
|
||||
#define DB_MAX_ATTRIBUTES_PER_RELATION 6
|
||||
#endif /* DB_MAX_ATTRIBUTES_PER_RELATION */
|
||||
|
||||
/* The maximum physical storage size on an attribute value. */
|
||||
#ifndef DB_MAX_ELEMENT_SIZE
|
||||
#define DB_MAX_ELEMENT_SIZE 16
|
||||
#endif /* DB_MAX_ELEMENT_SIZE */
|
||||
|
||||
|
||||
/* The maximum size of the LVM bytecode compiled from a
|
||||
single database query. */
|
||||
#ifndef DB_VM_BYTECODE_SIZE
|
||||
#define DB_VM_BYTECODE_SIZE 128
|
||||
#endif /* DB_VM_BYTECODE_SIZE */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Language options. */
|
||||
|
||||
/* The maximum length of a database query in AQL text format. */
|
||||
#ifndef AQL_MAX_QUERY_LENGTH
|
||||
#define AQL_MAX_QUERY_LENGTH 128
|
||||
#endif /* AQL_MAX_QUERY_LENGTH */
|
||||
|
||||
#ifndef AQL_MAX_VALUE_LENGTH
|
||||
#define AQL_MAX_VALUE_LENGTH DB_MAX_ELEMENT_SIZE
|
||||
#endif /* AQL_MAX_VALUE_LENGTH */
|
||||
|
||||
/* The maximum number of relations used in a single query. */
|
||||
#ifndef AQL_RELATION_LIMIT
|
||||
#define AQL_RELATION_LIMIT 3
|
||||
#endif /* AQL_RELATION_LIMIT */
|
||||
|
||||
/* The maximum number of attributes used in a single query. */
|
||||
#ifndef AQL_ATTRIBUTE_LIMIT
|
||||
#define AQL_ATTRIBUTE_LIMIT 5
|
||||
#endif /* AQL_ATTRIBUTE_LIMIT */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Physical storage options. Changing these options might cause
|
||||
* compatibility problems if the database files are moved between
|
||||
* different installations of Antelope.
|
||||
*/
|
||||
|
||||
/* The default relation file size to reserve when using Coffee. */
|
||||
#ifndef DB_COFFEE_RESERVE_SIZE
|
||||
#define DB_COFFEE_RESERVE_SIZE (128 * 1024UL)
|
||||
#endif /* DB_COFFEE_RESERVE_SIZE */
|
||||
|
||||
/* The maximum size of the physical storage of a tuple (labelled a "row"
|
||||
in Antelope's terminology. */
|
||||
#ifndef DB_MAX_CHAR_SIZE_PER_ROW
|
||||
#define DB_MAX_CHAR_SIZE_PER_ROW 64
|
||||
#endif /* DB_MAX_CHAR_SIZE_PER_ROW */
|
||||
|
||||
/* The maximum file name length to use for creating various database file. */
|
||||
#ifndef DB_MAX_FILENAME_LENGTH
|
||||
#define DB_MAX_FILENAME_LENGTH 16
|
||||
#endif /* DB_MAX_FILENAME_LENGTH */
|
||||
|
||||
/* The maximum length of an attribute name. */
|
||||
#ifndef ATTRIBUTE_NAME_LENGTH
|
||||
#define ATTRIBUTE_NAME_LENGTH 12
|
||||
#endif /* ATTRIBUTE_NAME_LENGTH */
|
||||
|
||||
/* The maximum length on a relation name. */
|
||||
#ifndef RELATION_NAME_LENGTH
|
||||
#define RELATION_NAME_LENGTH 10
|
||||
#endif /* RELATION_NAME_LENGTH */
|
||||
|
||||
/* The name of the intermediate "result" relation file, which is used
|
||||
for presenting the result of a query to a user. */
|
||||
#ifndef RESULT_RELATION
|
||||
#define RESULT_RELATION "db-result"
|
||||
#endif /* RESULT_RELATION */
|
||||
|
||||
/* The name of the relation used for processing a REMOVE query. */
|
||||
#ifndef REMOVE_RELATION
|
||||
#define REMOVE_RELATION "db-remove"
|
||||
#endif /* REMOVE_RELATION */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Index options. */
|
||||
|
||||
#ifndef DB_INDEX_COST
|
||||
#define DB_INDEX_COST 64
|
||||
#endif /* DB_INDEX_COST */
|
||||
|
||||
/* The maximum number of hash table indexes. */
|
||||
#ifndef DB_MEMHASH_INDEX_LIMIT
|
||||
#define DB_MEMHASH_INDEX_LIMIT 1
|
||||
#endif /* DB_MEMHASH_INDEX_LIMIT */
|
||||
|
||||
/* The default hash table index size. */
|
||||
#ifndef DB_MEMHASH_TABLE_SIZE
|
||||
#define DB_MEMHASH_TABLE_SIZE 61
|
||||
#endif /* DB_MEMHASH_TABLE_SIZE */
|
||||
|
||||
/* The maximum number of Maxheap indexes. */
|
||||
#ifndef DB_HEAP_INDEX_LIMIT
|
||||
#define DB_HEAP_INDEX_LIMIT 1
|
||||
#endif /* DB_HEAP_INDEX_LIMIT */
|
||||
|
||||
/* The maximum number of buckets cached in the MaxHeap index. */
|
||||
#ifndef DB_HEAP_CACHE_LIMIT
|
||||
#define DB_HEAP_CACHE_LIMIT 1
|
||||
#endif /* DB_HEAP_CACHE_LIMIT */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* LVM options. */
|
||||
|
||||
/* The maximum length of a variable in LVM. This value should preferably
|
||||
be identical to the maximum attribute name length. */
|
||||
#ifndef LVM_MAX_NAME_LENGTH
|
||||
#define LVM_MAX_NAME_LENGTH ATTRIBUTE_NAME_LENGTH
|
||||
#endif /* LVM_MAX_NAME_LENGTH */
|
||||
|
||||
/* The maximum variable identifier number in the LVM. The default
|
||||
value corresponds to the highest attribute ID. */
|
||||
#ifndef LVM_MAX_VARIABLE_ID
|
||||
#define LVM_MAX_VARIABLE_ID AQL_ATTRIBUTE_LIMIT - 1
|
||||
#endif /* LVM_MAX_VARIABLE_ID */
|
||||
|
||||
/* Specify whether floats should be used or not inside the LVM. */
|
||||
#ifndef LVM_USE_FLOATS
|
||||
#define LVM_USE_FLOATS DB_FEATURE_FLOATS
|
||||
#endif /* LVM_USE_FLOATS */
|
||||
|
||||
|
||||
#endif /* !DB_OPTIONS_H */
|
||||
64
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/db-types.h
Normal file
64
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/db-types.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* .
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef DB_TYPES_H
|
||||
#define DB_TYPES_H
|
||||
|
||||
enum db_result {
|
||||
DB_FINISHED = 3,
|
||||
DB_GOT_ROW = 2,
|
||||
DB_OK = 1,
|
||||
DB_LIMIT_ERROR = -1,
|
||||
DB_ALLOCATION_ERROR = -2,
|
||||
DB_STORAGE_ERROR = -3,
|
||||
DB_PARSING_ERROR = -4,
|
||||
DB_NAME_ERROR = -5,
|
||||
DB_RELATIONAL_ERROR = -6,
|
||||
DB_TYPE_ERROR = -7,
|
||||
DB_IMPLEMENTATION_ERROR = -8,
|
||||
DB_INDEX_ERROR = -9,
|
||||
DB_BUSY_ERROR = -10,
|
||||
DB_INCONSISTENCY_ERROR = -11,
|
||||
DB_ARGUMENT_ERROR = -12
|
||||
};
|
||||
|
||||
typedef enum db_result db_result_t;
|
||||
typedef int db_storage_id_t;
|
||||
|
||||
#define DB_ERROR(result_code) ((result_code) < DB_OK)
|
||||
#define DB_SUCCESS(result_code) !DB_ERROR(result_code)
|
||||
|
||||
#endif /* !DB_TYPES_H */
|
||||
63
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/debug.h
Normal file
63
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/debug.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* A set of debugging macros.
|
||||
*
|
||||
* \author Nicolas Tsiftes <nvt@sics.se>
|
||||
* Niclas Finne <nfi@sics.se>
|
||||
* Joakim Eriksson <joakime@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef UIP_DEBUG_H
|
||||
#define UIP_DEBUG_H
|
||||
|
||||
#define DEBUG_NONE 0
|
||||
#define DEBUG_PRINT 1
|
||||
#define DEBUG_ANNOTATE 2
|
||||
#define DEBUG_FULL DEBUG_ANNOTATE | DEBUG_PRINT
|
||||
|
||||
#if (DEBUG) & DEBUG_ANNOTATE
|
||||
#include <stdio.h>
|
||||
#define ANNOTATE(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define ANNOTATE(...)
|
||||
#endif /* (DEBUG) & DEBUG_ANNOTATE */
|
||||
|
||||
#if (DEBUG) & DEBUG_PRINT
|
||||
#include <stdio.h>
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif /* (DEBUG) & DEBUG_PRINT */
|
||||
|
||||
#endif
|
||||
227
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index-inline.c
Normal file
227
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index-inline.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* A binary search index for attributes that are constrained to be
|
||||
* monotonically increasing, which is a rather common pattern for
|
||||
* time series or keys. Since this index has no storage overhead,
|
||||
* it does not wear out the flash memory nor does it occupy any
|
||||
* space. Furthermore, unlike B+-trees, it has a O(1) memory
|
||||
* footprint in relation to the number of data items.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "index.h"
|
||||
#include "relation.h"
|
||||
#include "result.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
struct search_handle {
|
||||
index_t *index;
|
||||
tuple_id_t start_row;
|
||||
tuple_id_t end_row;
|
||||
};
|
||||
|
||||
struct search_handle handle;
|
||||
|
||||
static db_result_t null_op(index_t *);
|
||||
static db_result_t insert(index_t *, attribute_value_t *, tuple_id_t);
|
||||
static db_result_t delete(index_t *, attribute_value_t *);
|
||||
static tuple_id_t get_next(index_iterator_t *);
|
||||
|
||||
/*
|
||||
* The create, destroy, load, release, insert, and delete operations
|
||||
* of the index API always succeed because the index does not store
|
||||
* items separately from the row file. The four former operations share
|
||||
* the same signature, and are thus implemented by the null_op function
|
||||
* to save space.
|
||||
*/
|
||||
index_api_t index_inline = {
|
||||
INDEX_INLINE,
|
||||
INDEX_API_EXTERNAL | INDEX_API_COMPLETE | INDEX_API_RANGE_QUERIES,
|
||||
null_op,
|
||||
null_op,
|
||||
null_op,
|
||||
null_op,
|
||||
insert,
|
||||
delete,
|
||||
get_next
|
||||
};
|
||||
|
||||
static attribute_value_t *
|
||||
get_value(tuple_id_t *index, relation_t *rel, attribute_t *attr)
|
||||
{
|
||||
unsigned char row[rel->row_length];
|
||||
static attribute_value_t value;
|
||||
|
||||
if(DB_ERROR(storage_get_row(rel, index, row))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(DB_ERROR(relation_get_value(rel, attr, row, &value))) {
|
||||
PRINTF("DB: Unable to retrieve a value from tuple %ld\n", (long)(*index));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &value;
|
||||
}
|
||||
|
||||
static tuple_id_t
|
||||
binary_search(index_iterator_t *index_iterator,
|
||||
attribute_value_t *target_value,
|
||||
int exact_match)
|
||||
{
|
||||
relation_t *rel;
|
||||
attribute_t *attr;
|
||||
attribute_value_t *cmp_value;
|
||||
tuple_id_t min;
|
||||
tuple_id_t max;
|
||||
tuple_id_t center;
|
||||
|
||||
rel = index_iterator->index->rel;
|
||||
attr = index_iterator->index->attr;
|
||||
|
||||
max = relation_cardinality(rel);
|
||||
if(max == INVALID_TUPLE) {
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
max--;
|
||||
min = 0;
|
||||
|
||||
do {
|
||||
center = min + ((max - min) / 2);
|
||||
|
||||
cmp_value = get_value(¢er, rel, attr);
|
||||
if(cmp_value == NULL) {
|
||||
PRINTF("DB: Failed to get the center value, index = %ld\n",
|
||||
(long)center);
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
if(db_value_to_long(target_value) > db_value_to_long(cmp_value)) {
|
||||
min = center + 1;
|
||||
} else {
|
||||
max = center - 1;
|
||||
}
|
||||
} while(min <= max &&
|
||||
db_value_to_long(target_value) != db_value_to_long(cmp_value));
|
||||
|
||||
if(exact_match &&
|
||||
db_value_to_long(target_value) != db_value_to_long(cmp_value)) {
|
||||
PRINTF("DB: Could not find value %ld in the inline index\n",
|
||||
db_value_to_long(target_value));
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
return center;
|
||||
}
|
||||
|
||||
static tuple_id_t
|
||||
range_search(index_iterator_t *index_iterator,
|
||||
tuple_id_t *start, tuple_id_t *end)
|
||||
{
|
||||
attribute_value_t *low_target;
|
||||
attribute_value_t *high_target;
|
||||
int exact_match;
|
||||
|
||||
low_target = &index_iterator->min_value;
|
||||
high_target = &index_iterator->max_value;
|
||||
|
||||
PRINTF("DB: Search index for value range (%ld, %ld)\n",
|
||||
db_value_to_long(low_target), db_value_to_long(high_target));
|
||||
|
||||
exact_match = db_value_to_long(low_target) == db_value_to_long(high_target);
|
||||
|
||||
/* Optimize later so that the other search uses the result
|
||||
from the first one. */
|
||||
*start = binary_search(index_iterator, low_target, exact_match);
|
||||
if(*start == INVALID_TUPLE) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
*end = binary_search(index_iterator, high_target, exact_match);
|
||||
if(*end == INVALID_TUPLE) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
null_op(index_t *index)
|
||||
{
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
insert(index_t *index, attribute_value_t *value, tuple_id_t tuple_id)
|
||||
{
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
delete(index_t *index, attribute_value_t *value)
|
||||
{
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static tuple_id_t
|
||||
get_next(index_iterator_t *iterator)
|
||||
{
|
||||
static tuple_id_t cached_start;
|
||||
static tuple_id_t cached_end;
|
||||
|
||||
if(iterator->next_item_no == 0) {
|
||||
/*
|
||||
* We conduct the actual index search when the caller attempts to
|
||||
* access the first item in the iteration. The first and last tuple
|
||||
* id:s of the result get cached for subsequent iterations.
|
||||
*/
|
||||
if(DB_ERROR(range_search(iterator, &cached_start, &cached_end))) {
|
||||
cached_start = 0;
|
||||
cached_end = 0;
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
PRINTF("DB: Cached the tuple range (%ld,%ld)\n",
|
||||
(long)cached_start, (long)cached_end);
|
||||
++iterator->next_item_no;
|
||||
return cached_start;
|
||||
} else if(cached_start + iterator->next_item_no <= cached_end) {
|
||||
return cached_start + iterator->next_item_no++;
|
||||
}
|
||||
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
750
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index-maxheap.c
Normal file
750
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index-maxheap.c
Normal file
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* MaxHeap - A binary maximum heap index for flash memory.
|
||||
*
|
||||
* The idea behind the MaxHeap index is to write entries sequentially
|
||||
* into small buckets, which are indexed in a binary maximum heap.
|
||||
* Although sequential writes make the entries unsorted within a
|
||||
* bucket, the time to load and scan a single bucket is small. The
|
||||
* sequential write is important for flash memories, which are
|
||||
* unable to handle multiple rewrites of the same page without doing
|
||||
* an expensive erase operation between the rewrites.
|
||||
*
|
||||
* Each bucket specifies a range (a,b) of values that it accepts.
|
||||
* Once a bucket fills up, two buckets are created with the ranges
|
||||
* (a,mean) and (mean+1, b), respectively. The entries from the
|
||||
* original bucket are then copied into the appropriate new bucket
|
||||
* before the old bucket gets deleted.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cfs/cfs.h"
|
||||
#include "cfs/cfs-coffee.h"
|
||||
#include "lib/memb.h"
|
||||
#include "lib/random.h"
|
||||
|
||||
#include "db-options.h"
|
||||
#include "index.h"
|
||||
#include "result.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#define BRANCH_FACTOR 2
|
||||
#define BUCKET_SIZE 128
|
||||
#define NODE_LIMIT 511
|
||||
#define NODE_DEPTH 9
|
||||
|
||||
#if (1 << NODE_DEPTH) != (NODE_LIMIT + 1)
|
||||
#error "NODE_DEPTH is set incorrectly."
|
||||
#endif
|
||||
|
||||
#define EMPTY_NODE(node) ((node)->min == 0 && (node)->max == 0)
|
||||
#define EMPTY_PAIR(pair) ((pair)->key == 0 && (pair)->value == 0)
|
||||
|
||||
typedef uint16_t maxheap_key_t;
|
||||
typedef uint16_t maxheap_value_t;
|
||||
|
||||
#define KEY_MIN 0
|
||||
#define KEY_MAX 65535
|
||||
|
||||
struct heap_node {
|
||||
maxheap_key_t min;
|
||||
maxheap_key_t max;
|
||||
};
|
||||
typedef struct heap_node heap_node_t;
|
||||
|
||||
struct key_value_pair {
|
||||
maxheap_key_t key;
|
||||
maxheap_value_t value;
|
||||
};
|
||||
|
||||
struct bucket {
|
||||
struct key_value_pair pairs[BUCKET_SIZE];
|
||||
};
|
||||
typedef struct bucket bucket_t;
|
||||
|
||||
struct heap {
|
||||
db_storage_id_t heap_storage;
|
||||
db_storage_id_t bucket_storage;
|
||||
/* Remember where the next free slot for each bucket is located. */
|
||||
uint8_t next_free_slot[NODE_LIMIT];
|
||||
};
|
||||
typedef struct heap heap_t;
|
||||
|
||||
struct bucket_cache {
|
||||
heap_t *heap;
|
||||
uint16_t bucket_id;
|
||||
bucket_t bucket;
|
||||
};
|
||||
|
||||
/* Keep a cache of buckets read from storage. */
|
||||
static struct bucket_cache bucket_cache[DB_HEAP_CACHE_LIMIT];
|
||||
MEMB(heaps, heap_t, DB_HEAP_INDEX_LIMIT);
|
||||
|
||||
static struct bucket_cache *get_cache(heap_t *, int);
|
||||
static struct bucket_cache *get_cache_free(void);
|
||||
static void invalidate_cache(void);
|
||||
static maxheap_key_t transform_key(maxheap_key_t);
|
||||
static int heap_read(heap_t *, int, heap_node_t *);
|
||||
static int heap_write(heap_t *, int, heap_node_t *);
|
||||
static int heap_insert(heap_t *, maxheap_key_t, maxheap_key_t);
|
||||
static int heap_find(heap_t *, maxheap_key_t key, int *iterator);
|
||||
#if HEAP_DEBUG
|
||||
static void heap_print(heap_t *);
|
||||
#endif
|
||||
static int bucket_read(heap_t *, int, bucket_t *);
|
||||
static struct bucket_cache *bucket_load(heap_t *, int);
|
||||
static int bucket_append(heap_t *, int, struct key_value_pair *);
|
||||
static int bucket_split(heap_t *, int);
|
||||
|
||||
static db_result_t create(index_t *);
|
||||
static db_result_t destroy(index_t *);
|
||||
static db_result_t load(index_t *);
|
||||
static db_result_t release(index_t *);
|
||||
static db_result_t insert(index_t *, attribute_value_t *, tuple_id_t);
|
||||
static db_result_t delete(index_t *, attribute_value_t *);
|
||||
static tuple_id_t get_next(index_iterator_t *);
|
||||
|
||||
index_api_t index_maxheap = {
|
||||
INDEX_MAXHEAP,
|
||||
INDEX_API_EXTERNAL,
|
||||
create,
|
||||
destroy,
|
||||
load,
|
||||
release,
|
||||
insert,
|
||||
delete,
|
||||
get_next
|
||||
};
|
||||
|
||||
static struct bucket_cache *
|
||||
get_cache(heap_t *heap, int bucket_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < DB_HEAP_CACHE_LIMIT; i++) {
|
||||
if(bucket_cache[i].heap == heap && bucket_cache[i].bucket_id == bucket_id) {
|
||||
return &bucket_cache[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct bucket_cache *
|
||||
get_cache_free(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < DB_HEAP_CACHE_LIMIT; i++) {
|
||||
if(bucket_cache[i].heap == NULL) {
|
||||
return &bucket_cache[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
invalidate_cache(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < DB_HEAP_CACHE_LIMIT; i++) {
|
||||
if(bucket_cache[i].heap != NULL) {
|
||||
bucket_cache[i].heap = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static maxheap_key_t
|
||||
transform_key(maxheap_key_t key)
|
||||
{
|
||||
random_init(key);
|
||||
return random_rand();
|
||||
}
|
||||
|
||||
static int
|
||||
heap_read(heap_t *heap, int bucket_id, heap_node_t *node)
|
||||
{
|
||||
if(DB_ERROR(storage_read(heap->heap_storage, node,
|
||||
DB_MAX_FILENAME_LENGTH + (unsigned long)bucket_id * sizeof(*node), sizeof(*node)))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
heap_write(heap_t *heap, int bucket_id, heap_node_t *node)
|
||||
{
|
||||
if(DB_ERROR(storage_write(heap->heap_storage, node,
|
||||
DB_MAX_FILENAME_LENGTH + (unsigned long)bucket_id * sizeof(*node), sizeof(*node)))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
heap_insert(heap_t *heap, maxheap_key_t min, maxheap_key_t max)
|
||||
{
|
||||
int i;
|
||||
heap_node_t node;
|
||||
|
||||
PRINTF("DB: Insert node (%ld,%ld) into the heap\n", (long)min, (long)max);
|
||||
|
||||
if(min > max) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < NODE_LIMIT;) {
|
||||
if(heap_read(heap, i, &node) == 0) {
|
||||
PRINTF("DB: Failed to read heap node %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EMPTY_NODE(&node)) {
|
||||
node.min = min;
|
||||
node.max = max;
|
||||
if(heap_write(heap, i, &node) == 0) {
|
||||
PRINTF("DB: Failed to write heap node %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
} else if(node.min <= min && max <= node.max) {
|
||||
i = BRANCH_FACTOR * i + 1;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF("DB: No more nodes available\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
heap_find(heap_t *heap, maxheap_key_t key, int *iterator)
|
||||
{
|
||||
maxheap_key_t hashed_key;
|
||||
int i;
|
||||
int first_child;
|
||||
static heap_node_t node;
|
||||
|
||||
hashed_key = transform_key(key);
|
||||
|
||||
for(i = *iterator; i < NODE_LIMIT;) {
|
||||
if(heap_read(heap, i, &node) == 0) {
|
||||
break;
|
||||
}
|
||||
if(EMPTY_NODE(&node)) {
|
||||
break;
|
||||
} else if(node.min <= hashed_key && hashed_key <= node.max) {
|
||||
first_child = BRANCH_FACTOR * i + 1;
|
||||
|
||||
if(first_child >= NODE_LIMIT) {
|
||||
break;
|
||||
}
|
||||
*iterator = first_child;
|
||||
return i;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if HEAP_DEBUG
|
||||
static void
|
||||
heap_print(heap_t *heap)
|
||||
{
|
||||
int level_count;
|
||||
int branch_count;
|
||||
int branch_amount;
|
||||
int i, j;
|
||||
heap_node_t node;
|
||||
|
||||
level_count = 0;
|
||||
branch_count = 0;
|
||||
branch_amount = BRANCH_FACTOR;
|
||||
|
||||
for(i = 0;; i++) {
|
||||
if(heap_read(heap, i, &node) == 0 || EMPTY_NODE(&node)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(j = 0; j < level_count; j++) {
|
||||
PRINTF("\t");
|
||||
}
|
||||
PRINTF("(%ld,%ld)\n", (long)node.min, (long)node.max);
|
||||
if(level_count == 0) {
|
||||
level_count++;
|
||||
} else if(branch_count + 1 == branch_amount) {
|
||||
level_count++;
|
||||
branch_count = 0;
|
||||
branch_amount = branch_amount * BRANCH_FACTOR;
|
||||
} else {
|
||||
branch_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HEAP_DEBUG */
|
||||
|
||||
static int
|
||||
bucket_read(heap_t *heap, int bucket_id, bucket_t *bucket)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if(heap->next_free_slot[bucket_id] == 0) {
|
||||
size = BUCKET_SIZE;
|
||||
} else {
|
||||
size = heap->next_free_slot[bucket_id];
|
||||
}
|
||||
|
||||
size *= sizeof(struct key_value_pair);
|
||||
|
||||
if(DB_ERROR(storage_read(heap->bucket_storage, bucket,
|
||||
(unsigned long)bucket_id * sizeof(*bucket), size))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct bucket_cache *
|
||||
bucket_load(heap_t *heap, int bucket_id)
|
||||
{
|
||||
int i;
|
||||
struct bucket_cache *cache;
|
||||
|
||||
cache = get_cache(heap, bucket_id);
|
||||
if(cache != NULL) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
cache = get_cache_free();
|
||||
if(cache == NULL) {
|
||||
invalidate_cache();
|
||||
cache = get_cache_free();
|
||||
if(cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(bucket_read(heap, bucket_id, &cache->bucket) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache->heap = heap;
|
||||
cache->bucket_id = bucket_id;
|
||||
|
||||
if(heap->next_free_slot[bucket_id] == 0) {
|
||||
for(i = 0; i < BUCKET_SIZE; i++) {
|
||||
if(EMPTY_PAIR(&cache->bucket.pairs[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
heap->next_free_slot[bucket_id] = i;
|
||||
}
|
||||
|
||||
PRINTF("DB: Loaded bucket %d, the next free slot is %u\n", bucket_id,
|
||||
(unsigned)heap->next_free_slot[bucket_id]);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static int
|
||||
bucket_append(heap_t *heap, int bucket_id, struct key_value_pair *pair)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
if(heap->next_free_slot[bucket_id] >= BUCKET_SIZE) {
|
||||
PRINTF("DB: Invalid write attempt to the full bucket %d\n", bucket_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = (unsigned long)bucket_id * sizeof(bucket_t);
|
||||
offset += heap->next_free_slot[bucket_id] * sizeof(struct key_value_pair);
|
||||
|
||||
if(DB_ERROR(storage_write(heap->bucket_storage, pair, offset, sizeof(*pair)))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
heap->next_free_slot[bucket_id]++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
bucket_split(heap_t *heap, int bucket_id)
|
||||
{
|
||||
heap_node_t node;
|
||||
maxheap_key_t mean;
|
||||
int small_bucket_index;
|
||||
int large_bucket_index;
|
||||
|
||||
if(heap_read(heap, bucket_id, &node) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mean = node.min + ((node.max - node.min) / 2);
|
||||
|
||||
PRINTF("DB: Split bucket %d (%ld, %ld) at mean value %ld\n", bucket_id,
|
||||
(long)node.min, (long)node.max, (long)mean);
|
||||
|
||||
small_bucket_index = heap_insert(heap, node.min, mean);
|
||||
if(small_bucket_index < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
large_bucket_index = heap_insert(heap, mean + 1, node.max);
|
||||
if(large_bucket_index < 0) {
|
||||
/*heap_remove(small_bucket);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
insert_item(heap_t *heap, maxheap_key_t key, maxheap_value_t value)
|
||||
{
|
||||
int heap_iterator;
|
||||
int bucket_id, last_good_bucket_id;
|
||||
struct key_value_pair pair;
|
||||
|
||||
for(heap_iterator = 0, last_good_bucket_id = -1;;) {
|
||||
bucket_id = heap_find(heap, key, &heap_iterator);
|
||||
if(bucket_id < 0) {
|
||||
break;
|
||||
}
|
||||
last_good_bucket_id = bucket_id;
|
||||
}
|
||||
bucket_id = last_good_bucket_id;
|
||||
|
||||
if(bucket_id < 0) {
|
||||
PRINTF("DB: No bucket for key %ld\n", (long)key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pair.key = key;
|
||||
pair.value = value;
|
||||
|
||||
if(heap->next_free_slot[bucket_id] == BUCKET_SIZE) {
|
||||
PRINTF("DB: Bucket %d is full\n", bucket_id);
|
||||
if(bucket_split(heap, bucket_id) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Select one of the newly created buckets. */
|
||||
bucket_id = heap_find(heap, key, &heap_iterator);
|
||||
if(bucket_id < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(bucket_append(heap, bucket_id, &pair) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRINTF("DB: Inserted key %ld (hash %ld) into the heap at bucket_id %d\n",
|
||||
(long)key, (long)transform_key(key), bucket_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
create(index_t *index)
|
||||
{
|
||||
char heap_filename[DB_MAX_FILENAME_LENGTH];
|
||||
char bucket_filename[DB_MAX_FILENAME_LENGTH];
|
||||
char *filename;
|
||||
db_result_t result;
|
||||
heap_t *heap;
|
||||
|
||||
heap = NULL;
|
||||
filename = NULL;
|
||||
bucket_filename[0] = '\0';
|
||||
|
||||
/* Generate the heap file, which is the main index file that is
|
||||
referenced from the metadata of the relation. */
|
||||
filename = storage_generate_file("heap",
|
||||
(unsigned long)NODE_LIMIT * sizeof(heap_node_t));
|
||||
if(filename == NULL) {
|
||||
PRINTF("DB: Failed to generate a heap file\n");
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
memcpy(index->descriptor_file, filename,
|
||||
sizeof(index->descriptor_file));
|
||||
|
||||
PRINTF("DB: Generated the heap file \"%s\" using %lu bytes of space\n",
|
||||
index->descriptor_file, (unsigned long)NODE_LIMIT * sizeof(heap_node_t));
|
||||
|
||||
index->opaque_data = heap = memb_alloc(&heaps);
|
||||
if(heap == NULL) {
|
||||
PRINTF("DB: Failed to allocate a heap\n");
|
||||
result = DB_ALLOCATION_ERROR;
|
||||
goto end;
|
||||
}
|
||||
heap->heap_storage = -1;
|
||||
heap->bucket_storage = -1;
|
||||
|
||||
/* Generate the bucket file, which stores the (key, value) pairs. */
|
||||
filename = storage_generate_file("bucket",
|
||||
(unsigned long)NODE_LIMIT * sizeof(bucket_t));
|
||||
if(filename == NULL) {
|
||||
PRINTF("DB: Failed to generate a bucket file\n");
|
||||
result = DB_INDEX_ERROR;
|
||||
goto end;
|
||||
}
|
||||
memcpy(bucket_filename, filename, sizeof(bucket_filename));
|
||||
|
||||
PRINTF("DB: Generated the bucket file \"%s\" using %lu bytes of space\n",
|
||||
bucket_filename, (unsigned long)NODE_LIMIT * sizeof(bucket_t));
|
||||
|
||||
/* Initialize the heap. */
|
||||
memset(&heap->next_free_slot, 0, sizeof(heap->next_free_slot));
|
||||
|
||||
heap->heap_storage = storage_open(index->descriptor_file);
|
||||
heap->bucket_storage = storage_open(bucket_filename);
|
||||
if(heap->heap_storage < 0 || heap->bucket_storage < 0) {
|
||||
result = DB_STORAGE_ERROR;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(DB_ERROR(storage_write(heap->heap_storage, &bucket_filename, 0,
|
||||
sizeof(bucket_filename)))) {
|
||||
result = DB_STORAGE_ERROR;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(heap_insert(heap, KEY_MIN, KEY_MAX) < 0) {
|
||||
PRINTF("DB: Heap insertion error\n");
|
||||
result = DB_INDEX_ERROR;
|
||||
goto end;
|
||||
}
|
||||
|
||||
PRINTF("DB: Created a heap index\n");
|
||||
result = DB_OK;
|
||||
|
||||
end:
|
||||
if(result != DB_OK) {
|
||||
if(heap != NULL) {
|
||||
storage_close(heap->bucket_storage);
|
||||
storage_close(heap->heap_storage);
|
||||
memb_free(&heaps, heap);
|
||||
}
|
||||
if(index->descriptor_file[0] != '\0') {
|
||||
cfs_remove(heap_filename);
|
||||
index->descriptor_file[0] = '\0';
|
||||
}
|
||||
if(bucket_filename[0] != '\0') {
|
||||
cfs_remove(bucket_filename);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
destroy(index_t *index)
|
||||
{
|
||||
release(index);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
load(index_t *index)
|
||||
{
|
||||
heap_t *heap;
|
||||
db_storage_id_t fd;
|
||||
char bucket_file[DB_MAX_FILENAME_LENGTH];
|
||||
|
||||
index->opaque_data = heap = memb_alloc(&heaps);
|
||||
if(heap == NULL) {
|
||||
PRINTF("DB: Failed to allocate a heap\n");
|
||||
return DB_ALLOCATION_ERROR;
|
||||
}
|
||||
|
||||
fd = storage_open(index->descriptor_file);
|
||||
if(fd < 0) {
|
||||
return DB_STORAGE_ERROR;
|
||||
}
|
||||
|
||||
if(storage_read(fd, bucket_file, 0, sizeof(bucket_file)) !=
|
||||
sizeof(bucket_file)) {
|
||||
storage_close(fd);
|
||||
return DB_STORAGE_ERROR;
|
||||
}
|
||||
|
||||
storage_close(fd);
|
||||
|
||||
heap->heap_storage = storage_open(index->descriptor_file);
|
||||
heap->bucket_storage = storage_open(bucket_file);
|
||||
|
||||
memset(&heap->next_free_slot, 0, sizeof(heap->next_free_slot));
|
||||
|
||||
PRINTF("DB: Loaded max-heap index from file %s and bucket file %s\n",
|
||||
index->descriptor_file, bucket_file);
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
release(index_t *index)
|
||||
{
|
||||
heap_t *heap;
|
||||
|
||||
heap = index->opaque_data;
|
||||
|
||||
storage_close(heap->bucket_storage);
|
||||
storage_close(heap->heap_storage);
|
||||
memb_free(&heaps, index->opaque_data);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
insert(index_t *index, attribute_value_t *key, tuple_id_t value)
|
||||
{
|
||||
heap_t *heap;
|
||||
long long_key;
|
||||
|
||||
heap = (heap_t *)index->opaque_data;
|
||||
|
||||
long_key = db_value_to_long(key);
|
||||
|
||||
if(insert_item(heap, (maxheap_key_t)long_key,
|
||||
(maxheap_value_t)value) == 0) {
|
||||
PRINTF("DB: Failed to insert key %ld into a max-heap index\n", long_key);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
delete(index_t *index, attribute_value_t *value)
|
||||
{
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
static tuple_id_t
|
||||
get_next(index_iterator_t *iterator)
|
||||
{
|
||||
struct iteration_cache {
|
||||
index_iterator_t *index_iterator;
|
||||
int heap_iterator;
|
||||
tuple_id_t found_items;
|
||||
uint8_t start;
|
||||
int visited_buckets[NODE_DEPTH];
|
||||
int end;
|
||||
};
|
||||
static struct iteration_cache cache;
|
||||
heap_t *heap;
|
||||
maxheap_key_t key;
|
||||
int bucket_id;
|
||||
int tmp_heap_iterator;
|
||||
int i;
|
||||
struct bucket_cache *bcache;
|
||||
uint8_t next_free_slot;
|
||||
|
||||
heap = (heap_t *)iterator->index->opaque_data;
|
||||
key = *(maxheap_key_t *)&iterator->min_value;
|
||||
|
||||
if(cache.index_iterator != iterator || iterator->next_item_no == 0) {
|
||||
/* Initialize the cache for a new search. */
|
||||
cache.end = NODE_DEPTH - 1;
|
||||
cache.found_items = cache.start = 0;
|
||||
cache.index_iterator = iterator;
|
||||
|
||||
/* Find the downward path through the heap consisting of all nodes
|
||||
that could possibly contain the key. */
|
||||
for(i = tmp_heap_iterator = 0; i < NODE_DEPTH; i++) {
|
||||
cache.visited_buckets[i] = heap_find(heap, key, &tmp_heap_iterator);
|
||||
if(cache.visited_buckets[i] < 0) {
|
||||
cache.end = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cache.heap_iterator = cache.end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for the key in each heap node, starting from the bottom
|
||||
* of the heap. Because the bottom nodes contain are very narrow
|
||||
* range of keys, there is a much higher chance that the key will be
|
||||
* there rather than at the top.
|
||||
*/
|
||||
for(; cache.heap_iterator >= 0; cache.heap_iterator--) {
|
||||
bucket_id = cache.visited_buckets[cache.heap_iterator];
|
||||
|
||||
PRINTF("DB: Find key %lu in bucket %d\n", (unsigned long)key, bucket_id);
|
||||
|
||||
if((bcache = bucket_load(heap, bucket_id)) == NULL) {
|
||||
PRINTF("DB: Failed to load bucket %d\n", bucket_id);
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
/* Because keys are stored in an unsorted order in the bucket, we
|
||||
* need to search the bucket sequentially. */
|
||||
next_free_slot = heap->next_free_slot[bucket_id];
|
||||
for(i = cache.start; i < next_free_slot; i++) {
|
||||
if(bcache->bucket.pairs[i].key == key) {
|
||||
if(cache.found_items++ == iterator->next_item_no) {
|
||||
iterator->next_item_no++;
|
||||
cache.start = i + 1;
|
||||
PRINTF("DB: Found key %ld with value %lu\n", (long)key,
|
||||
(unsigned long)bcache->bucket.pairs[i].value);
|
||||
return (tuple_id_t)bcache->bucket.pairs[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(VALUE_INT(&iterator->min_value) == VALUE_INT(&iterator->max_value)) {
|
||||
PRINTF("DB: Could not find key %ld in the index\n", (long)key);
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
iterator->next_item_no = 0;
|
||||
VALUE_INT(&iterator->min_value)++;
|
||||
|
||||
return get_next(iterator);
|
||||
}
|
||||
194
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index-memhash.c
Normal file
194
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index-memhash.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* A memory-resident hash map used as a DB index.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/memb.h"
|
||||
|
||||
#include "db-options.h"
|
||||
#include "index.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
static db_result_t create(index_t *);
|
||||
static db_result_t destroy(index_t *);
|
||||
static db_result_t load(index_t *);
|
||||
static db_result_t release(index_t *);
|
||||
static db_result_t insert(index_t *, attribute_value_t *, tuple_id_t);
|
||||
static db_result_t delete(index_t *, attribute_value_t *);
|
||||
static tuple_id_t get_next(index_iterator_t *);
|
||||
|
||||
index_api_t index_memhash = {
|
||||
INDEX_MEMHASH,
|
||||
INDEX_API_INTERNAL,
|
||||
create,
|
||||
destroy,
|
||||
load,
|
||||
release,
|
||||
insert,
|
||||
delete,
|
||||
get_next
|
||||
};
|
||||
|
||||
struct hash_item {
|
||||
tuple_id_t tuple_id;
|
||||
attribute_value_t value;
|
||||
};
|
||||
typedef struct hash_item hash_item_t;
|
||||
|
||||
typedef hash_item_t hash_map_t[DB_MEMHASH_TABLE_SIZE];
|
||||
|
||||
MEMB(hash_map_memb, hash_map_t, DB_MEMHASH_INDEX_LIMIT);
|
||||
|
||||
static unsigned
|
||||
calculate_hash(attribute_value_t *value)
|
||||
{
|
||||
unsigned char *cp, *end;
|
||||
unsigned hash_value;
|
||||
|
||||
cp = (unsigned char *)value;
|
||||
end = cp + sizeof(*value);
|
||||
hash_value = 0;
|
||||
|
||||
while(cp < end) {
|
||||
hash_value = hash_value * 33 + *cp++;
|
||||
}
|
||||
|
||||
return hash_value % DB_MEMHASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
create(index_t *index)
|
||||
{
|
||||
int i;
|
||||
hash_map_t *hash_map;
|
||||
|
||||
PRINTF("Creating a memory-resident hash map index\n");
|
||||
|
||||
hash_map = memb_alloc(&hash_map_memb);
|
||||
if(hash_map == NULL) {
|
||||
return DB_ALLOCATION_ERROR;
|
||||
}
|
||||
|
||||
for(i = 0; i < DB_MEMHASH_TABLE_SIZE; i++) {
|
||||
hash_map[i]->tuple_id = INVALID_TUPLE;
|
||||
}
|
||||
|
||||
index->opaque_data = hash_map;
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
destroy(index_t *index)
|
||||
{
|
||||
memb_free(&hash_map_memb, index->opaque_data);
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
load(index_t *index)
|
||||
{
|
||||
return create(index);
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
release(index_t *index)
|
||||
{
|
||||
return destroy(index);
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
insert(index_t *index, attribute_value_t *value, tuple_id_t tuple_id)
|
||||
{
|
||||
hash_map_t *hash_map;
|
||||
uint16_t hash_value;
|
||||
|
||||
hash_map = index->opaque_data;
|
||||
|
||||
hash_value = calculate_hash(value);
|
||||
hash_map[hash_value]->tuple_id = tuple_id;
|
||||
hash_map[hash_value]->value = *value;
|
||||
|
||||
PRINTF("DB: Inserted value %ld into the hash table\n", VALUE_LONG(value));
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static db_result_t
|
||||
delete(index_t *index, attribute_value_t *value)
|
||||
{
|
||||
hash_map_t *hash_map;
|
||||
uint16_t hash_value;
|
||||
|
||||
hash_map = index->opaque_data;
|
||||
|
||||
hash_value = calculate_hash(value);
|
||||
if(memcmp(&hash_map[hash_value]->value, value, sizeof(*value)) != 0) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
hash_map[hash_value]->tuple_id = INVALID_TUPLE;
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
static tuple_id_t
|
||||
get_next(index_iterator_t *iterator)
|
||||
{
|
||||
hash_map_t *hash_map;
|
||||
uint16_t hash_value;
|
||||
|
||||
if(iterator->next_item_no == 1) {
|
||||
/* The memhash supports only unique values at the moment. */
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
hash_map = iterator->index->opaque_data;
|
||||
|
||||
hash_value = calculate_hash(&iterator->min_value);
|
||||
if(memcmp(&hash_map[hash_value]->value, &iterator->min_value, sizeof(iterator->min_value)) != 0) {
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
iterator->next_item_no++;
|
||||
|
||||
PRINTF("DB: Found value %ld in the hash table\n",
|
||||
VALUE_LONG(&iterator->min_value));
|
||||
|
||||
return hash_map[hash_value]->tuple_id;
|
||||
}
|
||||
433
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index.c
Normal file
433
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This component forwards index calls using the generic index
|
||||
* API to specific implementations.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "lib/memb.h"
|
||||
#include "lib/list.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#include "antelope.h"
|
||||
#include "attribute.h"
|
||||
#include "db-options.h"
|
||||
#include "index.h"
|
||||
#include "storage.h"
|
||||
|
||||
static index_api_t *index_components[] = {&index_inline,
|
||||
&index_maxheap};
|
||||
|
||||
LIST(indices);
|
||||
MEMB(index_memb, index_t, DB_INDEX_POOL_SIZE);
|
||||
|
||||
static process_event_t load_request_event;
|
||||
PROCESS(db_indexer, "DB Indexer");
|
||||
|
||||
static index_api_t *
|
||||
find_index_api(index_type_t index_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(index_components) / sizeof(index_components[0]); i++) {
|
||||
if(index_components[i]->type == index_type) {
|
||||
return index_components[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
index_init(void)
|
||||
{
|
||||
list_init(indices);
|
||||
memb_init(&index_memb);
|
||||
process_start(&db_indexer, NULL);
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_create(index_type_t index_type, relation_t *rel, attribute_t *attr)
|
||||
{
|
||||
tuple_id_t cardinality;
|
||||
index_t *index;
|
||||
index_api_t *api;
|
||||
|
||||
cardinality = relation_cardinality(rel);
|
||||
if(cardinality == INVALID_TUPLE) {
|
||||
return DB_STORAGE_ERROR;
|
||||
}
|
||||
|
||||
if(attr->domain != DOMAIN_INT && attr->domain != DOMAIN_LONG) {
|
||||
PRINTF("DB: Cannot create an index for a non-number attribute!\n");
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
api = find_index_api(index_type);
|
||||
if(api == NULL) {
|
||||
PRINTF("DB: No API for index type %d\n", (int)index_type);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
if(attr->index != NULL) {
|
||||
/* Refuse to overwrite the old index. */
|
||||
PRINTF("DB: The attribute %s is already indexed\n", attr->name);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
index = memb_alloc(&index_memb);
|
||||
if(index == NULL) {
|
||||
PRINTF("DB: Failed to allocate an index\n");
|
||||
return DB_ALLOCATION_ERROR;
|
||||
}
|
||||
|
||||
index->rel = rel;
|
||||
index->attr = attr;
|
||||
index->api = api;
|
||||
index->flags = 0;
|
||||
index->opaque_data = NULL;
|
||||
index->descriptor_file[0] = '\0';
|
||||
index->type = index_type;
|
||||
|
||||
if(DB_ERROR(api->create(index))) {
|
||||
memb_free(&index_memb, index);
|
||||
PRINTF("DB: Index-specific creation failed for attribute %s\n", attr->name);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
attr->index = index;
|
||||
list_push(indices, index);
|
||||
|
||||
if(index->descriptor_file[0] != '\0' &&
|
||||
DB_ERROR(storage_put_index(index))) {
|
||||
api->destroy(index);
|
||||
memb_free(&index_memb, index);
|
||||
PRINTF("DB: Failed to store index data in file \"%s\"\n",
|
||||
index->descriptor_file);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
if(!(api->flags & INDEX_API_INLINE) && cardinality > 0) {
|
||||
PRINTF("DB: Created an index for an old relation; issuing a load request\n");
|
||||
index->flags = INDEX_LOAD_NEEDED;
|
||||
process_post(&db_indexer, load_request_event, NULL);
|
||||
} else {
|
||||
/* Inline indexes (i.e., those using the existing storage of the relation)
|
||||
do not need to be reloaded after restarting the system. */
|
||||
PRINTF("DB: Index created for attribute %s\n", attr->name);
|
||||
index->flags |= INDEX_READY;
|
||||
}
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_destroy(index_t *index)
|
||||
{
|
||||
if(DB_ERROR(index_release(index)) ||
|
||||
DB_ERROR(index->api->destroy(index))) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_load(relation_t *rel, attribute_t *attr)
|
||||
{
|
||||
index_t *index;
|
||||
index_api_t *api;
|
||||
|
||||
PRINTF("DB: Attempting to load an index over %s.%s\n", rel->name, attr->name);
|
||||
|
||||
index = memb_alloc(&index_memb);
|
||||
if(index == NULL) {
|
||||
PRINTF("DB: No more index objects available\n");
|
||||
return DB_ALLOCATION_ERROR;
|
||||
}
|
||||
|
||||
if(DB_ERROR(storage_get_index(index, rel, attr))) {
|
||||
PRINTF("DB: Failed load an index descriptor from storage\n");
|
||||
memb_free(&index_memb, index);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
index->rel = rel;
|
||||
index->attr = attr;
|
||||
index->opaque_data = NULL;
|
||||
|
||||
api = find_index_api(index->type);
|
||||
if(api == NULL) {
|
||||
PRINTF("DB: No API for index type %d\n", index->type);
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
index->api = api;
|
||||
|
||||
if(DB_ERROR(api->load(index))) {
|
||||
PRINTF("DB: Index-specific load failed\n");
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
list_push(indices, index);
|
||||
attr->index = index;
|
||||
index->flags = INDEX_READY;
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_release(index_t *index)
|
||||
{
|
||||
if(DB_ERROR(index->api->release(index))) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
index->attr->index = NULL;
|
||||
list_remove(indices, index);
|
||||
memb_free(&index_memb, index);
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_insert(index_t *index, attribute_value_t *value,
|
||||
tuple_id_t tuple_id)
|
||||
{
|
||||
return index->api->insert(index, value, tuple_id);
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_delete(index_t *index, attribute_value_t *value)
|
||||
{
|
||||
if(index->flags != INDEX_READY) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
return index->api->delete(index, value);
|
||||
}
|
||||
|
||||
db_result_t
|
||||
index_get_iterator(index_iterator_t *iterator, index_t *index,
|
||||
attribute_value_t *min_value,
|
||||
attribute_value_t *max_value)
|
||||
{
|
||||
tuple_id_t cardinality;
|
||||
unsigned long range;
|
||||
unsigned long max_range;
|
||||
long max;
|
||||
long min;
|
||||
|
||||
cardinality = relation_cardinality(index->rel);
|
||||
if(cardinality == INVALID_TUPLE) {
|
||||
return DB_STORAGE_ERROR;
|
||||
}
|
||||
|
||||
if(index->flags != INDEX_READY) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
|
||||
min = db_value_to_long(min_value);
|
||||
max = db_value_to_long(max_value);
|
||||
|
||||
range = (unsigned long)max - min;
|
||||
if(range > 0) {
|
||||
/*
|
||||
* Index structures that do not have a natural ability to handle
|
||||
* range queries (e.g., a hash index) can nevertheless emulate them.
|
||||
*
|
||||
* The range query emulation attempts to look up the key for each
|
||||
* value in the search range. If the search range is sparse, this
|
||||
* iteration will incur a considerable overhead per found key.
|
||||
*
|
||||
* Hence, the emulation is preferable when an external module wants
|
||||
* to iterate over a narrow range of keys, for which the total
|
||||
* search cost is smaller than that of an iteration over all tuples
|
||||
* in the relation.
|
||||
*/
|
||||
if(!(index->api->flags & INDEX_API_RANGE_QUERIES)) {
|
||||
PRINTF("DB: Range query requested for an index that does not support it\n");
|
||||
max_range = cardinality / DB_INDEX_COST;
|
||||
if(range > max_range) {
|
||||
return DB_INDEX_ERROR;
|
||||
}
|
||||
PRINTF("DB: Using the index anyway because the range is small enough (%lu <= %lu)\n",
|
||||
range, max_range);
|
||||
}
|
||||
}
|
||||
|
||||
iterator->index = index;
|
||||
iterator->min_value = *min_value;
|
||||
iterator->max_value = *max_value;
|
||||
iterator->next_item_no = 0;
|
||||
|
||||
PRINTF("DB: Acquired an index iterator for %s.%s over the range (%ld,%ld)\n",
|
||||
index->rel->name, index->attr->name,
|
||||
min_value->u.long_value, max_value->u.long_value);
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
tuple_id_t
|
||||
index_get_next(index_iterator_t *iterator)
|
||||
{
|
||||
long min;
|
||||
long max;
|
||||
|
||||
if(iterator->index == NULL) {
|
||||
/* This attribute is not indexed. */
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
|
||||
if((iterator->index->attr->flags & ATTRIBUTE_FLAG_UNIQUE) &&
|
||||
iterator->next_item_no == 1) {
|
||||
min = db_value_to_long(&iterator->min_value);
|
||||
max = db_value_to_long(&iterator->max_value);
|
||||
if(min == max) {
|
||||
/*
|
||||
* We stop if this is an equivalence search on an attribute
|
||||
* whose values are unique, and we already found one item.
|
||||
*/
|
||||
PRINTF("DB: Equivalence search finished\n");
|
||||
return INVALID_TUPLE;
|
||||
}
|
||||
}
|
||||
|
||||
return iterator->index->api->get_next(iterator);
|
||||
}
|
||||
|
||||
int
|
||||
index_exists(attribute_t *attr)
|
||||
{
|
||||
index_t *index;
|
||||
|
||||
index = (index_t *)attr->index;
|
||||
if(index == NULL || index->flags != INDEX_READY) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static index_t *
|
||||
get_next_index_to_load(void)
|
||||
{
|
||||
index_t *index;
|
||||
|
||||
for(index = list_head(indices); index != NULL; index = index->next) {
|
||||
if(index->flags & INDEX_LOAD_NEEDED) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PROCESS_THREAD(db_indexer, ev, data)
|
||||
{
|
||||
static index_t *index;
|
||||
static db_handle_t handle;
|
||||
static tuple_id_t row;
|
||||
db_result_t result;
|
||||
attribute_value_t value;
|
||||
int column;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
load_request_event = process_alloc_event();
|
||||
|
||||
for(;;) {
|
||||
PROCESS_WAIT_EVENT_UNTIL(ev == load_request_event);
|
||||
|
||||
index = get_next_index_to_load();
|
||||
if(index == NULL) {
|
||||
PRINTF("DB: Request to load an index, but no index is set to be loaded\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
PRINTF("DB: Loading the index for %s.%s...\n",
|
||||
index->rel->name, index->attr->name);
|
||||
|
||||
/* Project the values of the indexed attribute from all tuples in
|
||||
the relation, and insert them into the index again. */
|
||||
if(DB_ERROR(db_query(&handle, "SELECT %s FROM %s;", index->attr->name, index->rel->name))) {
|
||||
index->flags |= INDEX_LOAD_ERROR;
|
||||
index->flags &= ~INDEX_LOAD_NEEDED;
|
||||
continue;
|
||||
}
|
||||
|
||||
for(;; row++) {
|
||||
PROCESS_PAUSE();
|
||||
|
||||
result = db_process(&handle);
|
||||
if(DB_ERROR(result)) {
|
||||
PRINTF("DB: Index loading failed while processing: %s\n",
|
||||
db_get_result_message(result));
|
||||
index->flags |= INDEX_LOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
if(result == DB_FINISHED) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(column = 0; column < handle.ncolumns; column++) {
|
||||
if(DB_ERROR(db_get_value(&value, &handle, column))) {
|
||||
index->flags |= INDEX_LOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(DB_ERROR(index_insert(index, &value, row))) {
|
||||
index->flags |= INDEX_LOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF("DB: Loaded %lu rows into the index\n",
|
||||
(unsigned long)handle.current_row);
|
||||
|
||||
cleanup:
|
||||
if(index->flags & INDEX_LOAD_ERROR) {
|
||||
PRINTF("DB: Failed to load the index for %s.%s\n",
|
||||
index->rel->name, index->attr->name);
|
||||
}
|
||||
index->flags &= ~INDEX_LOAD_NEEDED;
|
||||
index->flags |= INDEX_READY;
|
||||
db_free(&handle);
|
||||
}
|
||||
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
113
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index.h
Normal file
113
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/index.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* .
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef INDEX_H
|
||||
#define INDEX_H
|
||||
|
||||
#include "relation.h"
|
||||
|
||||
typedef enum {
|
||||
INDEX_NONE = 0,
|
||||
INDEX_INLINE = 1,
|
||||
INDEX_MEMHASH = 2,
|
||||
INDEX_MAXHEAP = 3
|
||||
} index_type_t;
|
||||
|
||||
#define INDEX_READY 0x00
|
||||
#define INDEX_LOAD_NEEDED 0x01
|
||||
#define INDEX_LOAD_ERROR 0x02
|
||||
|
||||
#define INDEX_API_INTERNAL 0x01
|
||||
#define INDEX_API_EXTERNAL 0x02
|
||||
#define INDEX_API_INLINE 0x04
|
||||
#define INDEX_API_COMPLETE 0x08
|
||||
#define INDEX_API_RANGE_QUERIES 0x10
|
||||
|
||||
struct index_api;
|
||||
|
||||
struct index {
|
||||
struct index *next;
|
||||
char descriptor_file[DB_MAX_FILENAME_LENGTH];
|
||||
relation_t *rel;
|
||||
attribute_t *attr;
|
||||
struct index_api *api;
|
||||
void *opaque_data;
|
||||
index_type_t type;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
typedef struct index index_t;
|
||||
|
||||
struct index_iterator {
|
||||
index_t *index;
|
||||
attribute_value_t min_value;
|
||||
attribute_value_t max_value;
|
||||
tuple_id_t next_item_no;
|
||||
tuple_id_t found_items;
|
||||
};
|
||||
typedef struct index_iterator index_iterator_t;
|
||||
|
||||
struct index_api {
|
||||
index_type_t type;
|
||||
uint8_t flags;
|
||||
db_result_t (*create)(index_t *);
|
||||
db_result_t (*destroy)(index_t *);
|
||||
db_result_t (*load)(index_t *);
|
||||
db_result_t (*release)(index_t *);
|
||||
db_result_t (*insert)(index_t *, attribute_value_t *, tuple_id_t);
|
||||
db_result_t (*delete)(index_t *, attribute_value_t *);
|
||||
tuple_id_t (*get_next)(index_iterator_t *);
|
||||
};
|
||||
|
||||
typedef struct index_api index_api_t;
|
||||
|
||||
extern index_api_t index_inline;
|
||||
extern index_api_t index_maxheap;
|
||||
extern index_api_t index_memhash;
|
||||
|
||||
void index_init(void);
|
||||
db_result_t index_create(index_type_t, relation_t *, attribute_t *);
|
||||
db_result_t index_destroy(index_t *);
|
||||
db_result_t index_load(relation_t *, attribute_t *);
|
||||
db_result_t index_release(index_t *);
|
||||
db_result_t index_insert(index_t *, attribute_value_t *, tuple_id_t);
|
||||
db_result_t index_delete(index_t *, attribute_value_t *);
|
||||
db_result_t index_get_iterator(index_iterator_t *, index_t *,
|
||||
attribute_value_t *, attribute_value_t *);
|
||||
tuple_id_t index_get_next(index_iterator_t *);
|
||||
int index_exists(attribute_t *);
|
||||
|
||||
#endif /* !INDEX_H */
|
||||
973
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/lvm.c
Normal file
973
ARM_Tag_FW/cc2531_OEPL/contiki/apps/antelope/lvm.c
Normal file
@@ -0,0 +1,973 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Swedish Institute of Computer Science
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Logic engine used for quickly evaluating data constraints in relations.
|
||||
* \author
|
||||
* Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aql.h"
|
||||
#include "lvm.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* The logic engine determines whether a logical predicate is true for
|
||||
* each tuple in a relation. It uses a stack-based execution model of
|
||||
* operations that are arranged in prefix (Polish) notation.
|
||||
*/
|
||||
|
||||
/* Default option values. */
|
||||
#ifndef LVM_MAX_NAME_LENGTH
|
||||
#define LVM_MAX_NAME_LENGTH 16
|
||||
#endif
|
||||
|
||||
#ifndef LVM_MAX_VARIABLE_ID
|
||||
#define LVM_MAX_VARIABLE_ID 8
|
||||
#endif
|
||||
|
||||
#ifndef LVM_USE_FLOATS
|
||||
#define LVM_USE_FLOATS 0
|
||||
#endif
|
||||
|
||||
#define IS_CONNECTIVE(op) ((op) & LVM_CONNECTIVE)
|
||||
|
||||
struct variable {
|
||||
operand_type_t type;
|
||||
operand_value_t value;
|
||||
char name[LVM_MAX_NAME_LENGTH + 1];
|
||||
};
|
||||
typedef struct variable variable_t;
|
||||
|
||||
struct derivation {
|
||||
operand_value_t max;
|
||||
operand_value_t min;
|
||||
uint8_t derived;
|
||||
};
|
||||
typedef struct derivation derivation_t;
|
||||
|
||||
/* Registered variables for a LVM expression. Their values may be
|
||||
changed between executions of the expression. */
|
||||
static variable_t variables[LVM_MAX_VARIABLE_ID - 1];
|
||||
|
||||
/* Range derivations of variables that are used for index searches. */
|
||||
static derivation_t derivations[LVM_MAX_VARIABLE_ID - 1];
|
||||
|
||||
#if DEBUG
|
||||
static void
|
||||
print_derivations(derivation_t *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < LVM_MAX_VARIABLE_ID; i++) {
|
||||
if(d[i].derived) {
|
||||
printf("%s is constrained to (%ld,%ld)\n", variables[i].name,
|
||||
d[i].min.l, d[i].max.l);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
static variable_id_t
|
||||
lookup(char *name)
|
||||
{
|
||||
variable_t *var;
|
||||
|
||||
for(var = variables; var <= &variables[LVM_MAX_VARIABLE_ID - 1] && var->name[0] != '\0'; var++) {
|
||||
if(strcmp(var->name, name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (variable_id_t)(var - &variables[0]);
|
||||
}
|
||||
|
||||
static operator_t *
|
||||
get_operator(lvm_instance_t *p)
|
||||
{
|
||||
operator_t *operator;
|
||||
|
||||
operator = (operator_t *)&p->code[p->ip];
|
||||
p->ip += sizeof(operator_t);
|
||||
return operator;
|
||||
}
|
||||
|
||||
static void
|
||||
get_operand(lvm_instance_t *p, operand_t *operand)
|
||||
{
|
||||
memcpy(operand, &p->code[p->ip], sizeof(*operand));
|
||||
p->ip += sizeof(*operand);
|
||||
}
|
||||
|
||||
static node_type_t
|
||||
get_type(lvm_instance_t *p)
|
||||
{
|
||||
node_type_t node_type;
|
||||
|
||||
node_type = *(node_type_t *)(p->code + p->ip);
|
||||
p->ip += sizeof(node_type);
|
||||
|
||||
return node_type;
|
||||
}
|
||||
|
||||
static long
|
||||
operand_to_long(operand_t *operand)
|
||||
{
|
||||
switch(operand->type) {
|
||||
case LVM_LONG:
|
||||
return operand->value.l;
|
||||
#if LVM_USE_FLOATS
|
||||
case LVM_FLOAT:
|
||||
return (long)operand->value.f;
|
||||
break;
|
||||
#endif /* LVM_USE_FLOATS */
|
||||
case LVM_VARIABLE:
|
||||
return variables[operand->value.id].value.l;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static lvm_status_t
|
||||
eval_expr(lvm_instance_t *p, operator_t op, operand_t *result)
|
||||
{
|
||||
int i;
|
||||
node_type_t type;
|
||||
operator_t *operator;
|
||||
operand_t operand[2];
|
||||
long value[2];
|
||||
long result_value;
|
||||
lvm_status_t r;
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
type = get_type(p);
|
||||
switch(type) {
|
||||
case LVM_ARITH_OP:
|
||||
operator = get_operator(p);
|
||||
r = eval_expr(p, *operator, &operand[i]);
|
||||
if(LVM_ERROR(r)) {
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
case LVM_OPERAND:
|
||||
get_operand(p, &operand[i]);
|
||||
break;
|
||||
default:
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
value[i] = operand_to_long(&operand[i]);
|
||||
}
|
||||
|
||||
switch(op) {
|
||||
case LVM_ADD:
|
||||
result_value = value[0] + value[1];
|
||||
break;
|
||||
case LVM_SUB:
|
||||
result_value = value[0] - value[1];
|
||||
break;
|
||||
case LVM_MUL:
|
||||
result_value = value[0] * value[1];
|
||||
break;
|
||||
case LVM_DIV:
|
||||
if(value[1] == 0) {
|
||||
return MATH_ERROR;
|
||||
}
|
||||
result_value = value[0] / value[1];
|
||||
break;
|
||||
default:
|
||||
return EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
result->type = LVM_LONG;
|
||||
result->value.l = result_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
eval_logic(lvm_instance_t *p, operator_t *op)
|
||||
{
|
||||
int i;
|
||||
int r;
|
||||
operand_t operand;
|
||||
long result[2];
|
||||
node_type_t type;
|
||||
operator_t *operator;
|
||||
long l1, l2;
|
||||
int logic_result[2];
|
||||
unsigned arguments;
|
||||
|
||||
if(IS_CONNECTIVE(*op)) {
|
||||
arguments = *op == LVM_NOT ? 1 : 2;
|
||||
for(i = 0; i < arguments; i++) {
|
||||
type = get_type(p);
|
||||
if(type != LVM_CMP_OP) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
operator = get_operator(p);
|
||||
logic_result[i] = eval_logic(p, operator);
|
||||
if(LVM_ERROR(logic_result[i])) {
|
||||
return logic_result[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(*op == LVM_NOT) {
|
||||
return !logic_result[0];
|
||||
} else if(*op == LVM_AND) {
|
||||
return logic_result[0] == TRUE && logic_result[1] == TRUE;
|
||||
} else {
|
||||
return logic_result[0] == TRUE || logic_result[1] == TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
type = get_type(p);
|
||||
switch(type) {
|
||||
case LVM_ARITH_OP:
|
||||
operator = get_operator(p);
|
||||
r = eval_expr(p, *operator, &operand);
|
||||
if(LVM_ERROR(r)) {
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
case LVM_OPERAND:
|
||||
get_operand(p, &operand);
|
||||
break;
|
||||
default:
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
result[i] = operand_to_long(&operand);
|
||||
}
|
||||
|
||||
l1 = result[0];
|
||||
l2 = result[1];
|
||||
PRINTF("Result1: %ld\nResult2: %ld\n", l1, l2);
|
||||
|
||||
switch(*op) {
|
||||
case LVM_EQ:
|
||||
return l1 == l2;
|
||||
case LVM_NEQ:
|
||||
return l1 != l2;
|
||||
case LVM_GE:
|
||||
return l1 > l2;
|
||||
case LVM_GEQ:
|
||||
return l1 >= l2;
|
||||
case LVM_LE:
|
||||
return l1 < l2;
|
||||
case LVM_LEQ:
|
||||
return l1 <= l2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
lvm_reset(lvm_instance_t *p, unsigned char *code, lvm_ip_t size)
|
||||
{
|
||||
memset(code, 0, size);
|
||||
p->code = code;
|
||||
p->size = size;
|
||||
p->end = 0;
|
||||
p->ip = 0;
|
||||
p->error = 0;
|
||||
|
||||
memset(variables, 0, sizeof(variables));
|
||||
memset(derivations, 0, sizeof(derivations));
|
||||
}
|
||||
|
||||
lvm_ip_t
|
||||
lvm_jump_to_operand(lvm_instance_t *p)
|
||||
{
|
||||
lvm_ip_t old_end;
|
||||
|
||||
old_end = p->end;
|
||||
p->end += sizeof(operator_t) + sizeof(node_type_t);
|
||||
if(p->end >= p->size) {
|
||||
p->error = __LINE__;
|
||||
p->end = old_end;
|
||||
}
|
||||
|
||||
return old_end;
|
||||
}
|
||||
|
||||
lvm_ip_t
|
||||
lvm_shift_for_operator(lvm_instance_t *p, lvm_ip_t end)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
lvm_ip_t old_end;
|
||||
|
||||
old_end = p->end;
|
||||
|
||||
if(p->end + sizeof(operator_t) > p->size || end >= old_end) {
|
||||
p->error = __LINE__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = p->code + end;
|
||||
|
||||
memmove(ptr + sizeof(operator_t) + sizeof(node_type_t), ptr, old_end - end);
|
||||
p->end = end;
|
||||
|
||||
return old_end + sizeof(operator_t) + sizeof(node_type_t);
|
||||
}
|
||||
|
||||
lvm_ip_t
|
||||
lvm_get_end(lvm_instance_t *p)
|
||||
{
|
||||
return p->end;
|
||||
}
|
||||
|
||||
lvm_ip_t
|
||||
lvm_set_end(lvm_instance_t *p, lvm_ip_t end)
|
||||
{
|
||||
lvm_ip_t old_end;
|
||||
|
||||
if(end >= p->size) {
|
||||
p->error = __LINE__;
|
||||
return p->end;
|
||||
}
|
||||
|
||||
old_end = p->end;
|
||||
p->end = end;
|
||||
|
||||
return old_end;
|
||||
}
|
||||
|
||||
void
|
||||
lvm_set_type(lvm_instance_t *p, node_type_t type)
|
||||
{
|
||||
*(node_type_t *)(p->code + p->end) = type;
|
||||
p->end += sizeof(type);
|
||||
}
|
||||
|
||||
lvm_status_t
|
||||
lvm_execute(lvm_instance_t *p)
|
||||
{
|
||||
node_type_t type;
|
||||
operator_t *operator;
|
||||
lvm_status_t status;
|
||||
|
||||
p->ip = 0;
|
||||
status = EXECUTION_ERROR;
|
||||
type = get_type(p);
|
||||
switch(type) {
|
||||
case LVM_CMP_OP:
|
||||
operator = get_operator(p);
|
||||
status = eval_logic(p, operator);
|
||||
if(!LVM_ERROR(status)) {
|
||||
PRINTF("The statement is %s\n", status == TRUE ? "true" : "false");
|
||||
} else {
|
||||
PRINTF("Execution error: %d\n", (int)status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PRINTF("Error: The code must start with a relational operator\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
lvm_set_op(lvm_instance_t *p, operator_t op)
|
||||
{
|
||||
lvm_set_type(p, LVM_ARITH_OP);
|
||||
memcpy(&p->code[p->end], &op, sizeof(op));
|
||||
p->end += sizeof(op);
|
||||
}
|
||||
|
||||
void
|
||||
lvm_set_relation(lvm_instance_t *p, operator_t op)
|
||||
{
|
||||
lvm_set_type(p, LVM_CMP_OP);
|
||||
memcpy(&p->code[p->end], &op, sizeof(op));
|
||||
p->end += sizeof(op);
|
||||
}
|
||||
|
||||
void
|
||||
lvm_set_operand(lvm_instance_t *p, operand_t *op)
|
||||
{
|
||||
lvm_set_type(p, LVM_OPERAND);
|
||||
memcpy(&p->code[p->end], op, sizeof(*op));
|
||||
p->end += sizeof(*op);
|
||||
}
|
||||
|
||||
void
|
||||
lvm_set_long(lvm_instance_t *p, long l)
|
||||
{
|
||||
operand_t op;
|
||||
|
||||
op.type = LVM_LONG;
|
||||
op.value.l = l;
|
||||
|
||||
lvm_set_operand(p, &op);
|
||||
}
|
||||
|
||||
lvm_status_t
|
||||
lvm_register_variable(char *name, operand_type_t type)
|
||||
{
|
||||
variable_id_t id;
|
||||
variable_t *var;
|
||||
|
||||
id = lookup(name);
|
||||
if(id == LVM_MAX_VARIABLE_ID) {
|
||||
return VARIABLE_LIMIT_REACHED;
|
||||
}
|
||||
|
||||
var = &variables[id];
|
||||
if(var->name[0] == '\0') {
|
||||
strncpy(var->name, name, sizeof(var->name) - 1);
|
||||
var->name[sizeof(var->name) - 1] = '\0';
|
||||
var->type = type;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
lvm_status_t
|
||||
lvm_set_variable_value(char *name, operand_value_t value)
|
||||
{
|
||||
variable_id_t id;
|
||||
|
||||
id = lookup(name);
|
||||
if(id == LVM_MAX_VARIABLE_ID) {
|
||||
return INVALID_IDENTIFIER;
|
||||
}
|
||||
variables[id].value = value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
lvm_set_variable(lvm_instance_t *p, char *name)
|
||||
{
|
||||
operand_t op;
|
||||
variable_id_t id;
|
||||
|
||||
id = lookup(name);
|
||||
if(id < LVM_MAX_VARIABLE_ID) {
|
||||
PRINTF("var id = %d\n", id);
|
||||
op.type = LVM_VARIABLE;
|
||||
op.value.id = id;
|
||||
lvm_set_operand(p, &op);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lvm_clone(lvm_instance_t *dst, lvm_instance_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static void
|
||||
create_intersection(derivation_t *result, derivation_t *d1, derivation_t *d2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < LVM_MAX_VARIABLE_ID; i++) {
|
||||
if(!d1[i].derived && !d2[i].derived) {
|
||||
continue;
|
||||
} else if(d1[i].derived && !d2[i].derived) {
|
||||
result[i].min.l = d1[i].min.l;
|
||||
result[i].max.l = d1[i].max.l;
|
||||
} else if(!d1[i].derived && d2[i].derived) {
|
||||
result[i].min.l = d2[i].min.l;
|
||||
result[i].max.l = d2[i].max.l;
|
||||
} else {
|
||||
/* Both derivations have been made; create an
|
||||
intersection of the ranges. */
|
||||
if(d1[i].min.l > d2[i].min.l) {
|
||||
result[i].min.l = d1[i].min.l;
|
||||
} else {
|
||||
result[i].min.l = d2[i].min.l;
|
||||
}
|
||||
|
||||
if(d1[i].max.l < d2[i].max.l) {
|
||||
result[i].max.l = d1[i].max.l;
|
||||
} else {
|
||||
result[i].max.l = d2[i].max.l;
|
||||
}
|
||||
}
|
||||
result[i].derived = 1;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
PRINTF("Created an intersection of D1 and D2\n");
|
||||
PRINTF("D1: \n");
|
||||
print_derivations(d1);
|
||||
PRINTF("D2: \n");
|
||||
print_derivations(d2);
|
||||
PRINTF("Result: \n");
|
||||
print_derivations(result);
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
static void
|
||||
create_union(derivation_t *result, derivation_t *d1, derivation_t *d2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < LVM_MAX_VARIABLE_ID; i++) {
|
||||
if(!d1[i].derived && !d2[i].derived) {
|
||||
continue;
|
||||
} else if(d1[i].derived && !d2[i].derived) {
|
||||
result[i].min.l = d1[i].min.l;
|
||||
result[i].max.l = d1[i].max.l;
|
||||
} else if(!d1[i].derived && d2[i].derived) {
|
||||
result[i].min.l = d2[i].min.l;
|
||||
result[i].max.l = d2[i].max.l;
|
||||
} else {
|
||||
/* Both derivations have been made; create a
|
||||
union of the ranges. */
|
||||
if(d1[i].min.l > d2[i].min.l) {
|
||||
result[i].min.l = d2[i].min.l;
|
||||
} else {
|
||||
result[i].min.l = d1[i].min.l;
|
||||
}
|
||||
|
||||
if(d1[i].max.l < d2[i].max.l) {
|
||||
result[i].max.l = d2[i].max.l;
|
||||
} else {
|
||||
result[i].max.l = d1[i].max.l;
|
||||
}
|
||||
}
|
||||
result[i].derived = 1;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
PRINTF("Created a union of D1 and D2\n");
|
||||
PRINTF("D1: \n");
|
||||
print_derivations(d1);
|
||||
PRINTF("D2: \n");
|
||||
print_derivations(d2);
|
||||
PRINTF("Result: \n");
|
||||
print_derivations(result);
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
static int
|
||||
derive_relation(lvm_instance_t *p, derivation_t *local_derivations)
|
||||
{
|
||||
operator_t *operator;
|
||||
node_type_t type;
|
||||
operand_t operand[2];
|
||||
int i;
|
||||
int variable_id;
|
||||
operand_value_t *value;
|
||||
derivation_t *derivation;
|
||||
|
||||
type = get_type(p);
|
||||
operator = get_operator(p);
|
||||
|
||||
if(IS_CONNECTIVE(*operator)) {
|
||||
derivation_t d1[LVM_MAX_VARIABLE_ID];
|
||||
derivation_t d2[LVM_MAX_VARIABLE_ID];
|
||||
|
||||
if(*operator != LVM_AND && *operator != LVM_OR) {
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
|
||||
PRINTF("Attempting to infer ranges from a logical connective\n");
|
||||
|
||||
memset(d1, 0, sizeof(d1));
|
||||
memset(d2, 0, sizeof(d2));
|
||||
|
||||
if(LVM_ERROR(derive_relation(p, d1)) ||
|
||||
LVM_ERROR(derive_relation(p, d2))) {
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
|
||||
if(*operator == LVM_AND) {
|
||||
create_intersection(local_derivations, d1, d2);
|
||||
} else if(*operator == LVM_OR) {
|
||||
create_union(local_derivations, d1, d2);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
type = get_type(p);
|
||||
switch(type) {
|
||||
case LVM_OPERAND:
|
||||
get_operand(p, &operand[i]);
|
||||
break;
|
||||
default:
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(operand[0].type == LVM_VARIABLE && operand[1].type == LVM_VARIABLE) {
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
|
||||
/* Determine which of the operands that is the variable. */
|
||||
if(operand[0].type == LVM_VARIABLE) {
|
||||
if(operand[1].type == LVM_VARIABLE) {
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
variable_id = operand[0].value.id;
|
||||
value = &operand[1].value;
|
||||
} else {
|
||||
variable_id = operand[1].value.id;
|
||||
value = &operand[0].value;
|
||||
}
|
||||
|
||||
if(variable_id >= LVM_MAX_VARIABLE_ID) {
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
|
||||
PRINTF("variable id %d, value %ld\n", variable_id, *(long *)value);
|
||||
|
||||
derivation = local_derivations + variable_id;
|
||||
/* Default values. */
|
||||
derivation->max.l = LONG_MAX;
|
||||
derivation->min.l = LONG_MIN;
|
||||
|
||||
switch(*operator) {
|
||||
case LVM_EQ:
|
||||
derivation->max = *value;
|
||||
derivation->min = *value;
|
||||
break;
|
||||
case LVM_GE:
|
||||
derivation->min.l = value->l + 1;
|
||||
break;
|
||||
case LVM_GEQ:
|
||||
derivation->min.l = value->l;
|
||||
break;
|
||||
case LVM_LE:
|
||||
derivation->max.l = value->l - 1;
|
||||
break;
|
||||
case LVM_LEQ:
|
||||
derivation->max.l = value->l;
|
||||
break;
|
||||
default:
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
|
||||
derivation->derived = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
lvm_status_t
|
||||
lvm_derive(lvm_instance_t *p)
|
||||
{
|
||||
return derive_relation(p, derivations);
|
||||
}
|
||||
|
||||
lvm_status_t
|
||||
lvm_get_derived_range(lvm_instance_t *p, char *name,
|
||||
operand_value_t *min, operand_value_t *max)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < LVM_MAX_VARIABLE_ID; i++) {
|
||||
if(strcmp(name, variables[i].name) == 0) {
|
||||
if(derivations[i].derived) {
|
||||
*min = derivations[i].min;
|
||||
*max = derivations[i].max;
|
||||
return TRUE;
|
||||
}
|
||||
return DERIVATION_ERROR;
|
||||
}
|
||||
}
|
||||
return INVALID_IDENTIFIER;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static lvm_ip_t
|
||||
print_operator(lvm_instance_t *p, lvm_ip_t index)
|
||||
{
|
||||
operator_t operator;
|
||||
struct operator_map {
|
||||
operator_t op;
|
||||
char *representation;
|
||||
};
|
||||
struct operator_map operator_map[] = {
|
||||
{LVM_ADD, "+"},
|
||||
{LVM_SUB, "-"},
|
||||
{LVM_MUL, "*"},
|
||||
{LVM_DIV, "/"},
|
||||
{LVM_GE, ">"},
|
||||
{LVM_GEQ, ">="},
|
||||
{LVM_LE, "<"},
|
||||
{LVM_LEQ, "<="},
|
||||
{LVM_EQ, "="},
|
||||
{LVM_NEQ, "<>"},
|
||||
{LVM_AND, "/\\"},
|
||||
{LVM_OR, "\\/"},
|
||||
{LVM_NOT, "!"}
|
||||
};
|
||||
int i;
|
||||
|
||||
memcpy(&operator, p->code + index, sizeof(operator));
|
||||
|
||||
for(i = 0; i < sizeof(operator_map) / sizeof(operator_map[0]); i++) {
|
||||
if(operator_map[i].op == operator) {
|
||||
PRINTF("%s ", operator_map[i].representation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index + sizeof(operator_t);
|
||||
}
|
||||
|
||||
static lvm_ip_t
|
||||
print_operand(lvm_instance_t *p, lvm_ip_t index)
|
||||
{
|
||||
operand_t operand;
|
||||
|
||||
memcpy(&operand, p->code + index, sizeof(operand));
|
||||
|
||||
switch(operand.type) {
|
||||
case LVM_VARIABLE:
|
||||
if(operand.value.id >= LVM_MAX_VARIABLE_ID || variables[operand.value.id].name == NULL) {
|
||||
PRINTF("var(id:%d):?? ", operand.value.id);
|
||||
} else {
|
||||
PRINTF("var(%s):%ld ", variables[operand.value.id].name,
|
||||
variables[operand.value.id].value.l);
|
||||
}
|
||||
break;
|
||||
case LVM_LONG:
|
||||
PRINTF("long:%ld ", operand.value.l);
|
||||
break;
|
||||
default:
|
||||
PRINTF("?? ");
|
||||
break;
|
||||
}
|
||||
|
||||
return index + sizeof(operand_t);
|
||||
}
|
||||
|
||||
static lvm_ip_t
|
||||
print_relation(lvm_instance_t *p, lvm_ip_t index)
|
||||
{
|
||||
/* Relational operators are stored as ordinary operators. */
|
||||
return print_operator(p, index);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
void
|
||||
lvm_print_code(lvm_instance_t *p)
|
||||
{
|
||||
#if DEBUG
|
||||
lvm_ip_t ip;
|
||||
|
||||
PRINTF("Code: ");
|
||||
|
||||
for(ip = 0; ip < p->end;) {
|
||||
switch(*(node_type_t *)(p->code + ip)) {
|
||||
case LVM_CMP_OP:
|
||||
ip = print_relation(p, ip + sizeof(node_type_t));
|
||||
break;
|
||||
case LVM_ARITH_OP:
|
||||
ip = print_operator(p, ip + sizeof(node_type_t));
|
||||
break;
|
||||
case LVM_OPERAND:
|
||||
ip = print_operand(p, ip + sizeof(node_type_t));
|
||||
break;
|
||||
default:
|
||||
PRINTF("Invalid opcode: 0x%x ", p->code[ip]);
|
||||
ip = p->end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
lvm_print_derivations(lvm_instance_t *p)
|
||||
{
|
||||
#if DEBUG
|
||||
print_derivations(derivations);
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
lvm_instance_t p;
|
||||
unsigned char code[256];
|
||||
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
|
||||
lvm_register_variable("z", LVM_LONG);
|
||||
lvm_set_variable_value("z", (operand_value_t)15L);
|
||||
|
||||
lvm_register_variable("y", LVM_LONG);
|
||||
lvm_set_variable_value("y", (operand_value_t)109L);
|
||||
|
||||
/* Infix: 109 = y /\ 20 > 70 - (6 + z * 3) => 109 = 109 /\ 20 > 19 => true */
|
||||
lvm_set_relation(&p, LVM_AND);
|
||||
lvm_set_relation(&p, LVM_EQ);
|
||||
lvm_set_long(&p, 109);
|
||||
lvm_set_variable(&p, "y");
|
||||
lvm_set_relation(&p, LVM_GE);
|
||||
lvm_set_long(&p, 20);
|
||||
lvm_set_op(&p, LVM_SUB);
|
||||
lvm_set_long(&p, 70);
|
||||
lvm_set_op(&p, LVM_ADD);
|
||||
lvm_set_long(&p, 6);
|
||||
lvm_set_op(&p, LVM_MUL);
|
||||
lvm_set_variable(&p, "z");
|
||||
lvm_set_long(&p, 3);
|
||||
|
||||
lvm_print_code(&p);
|
||||
|
||||
lvm_execute(&p);
|
||||
|
||||
/* Infix: !(9999 + 1 < -1 + 10001) => !(10000 < 10000) => true */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_set_relation(&p, LVM_NOT);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_op(&p, LVM_ADD);
|
||||
lvm_set_long(&p, 9999);
|
||||
lvm_set_long(&p, 1);
|
||||
lvm_set_op(&p, LVM_ADD);
|
||||
lvm_set_long(&p, -1);
|
||||
lvm_set_long(&p, 10001);
|
||||
|
||||
lvm_print_code(&p);
|
||||
|
||||
lvm_execute(&p);
|
||||
|
||||
/* Derivation tests */
|
||||
|
||||
/* Infix: a = 5 => a:(5,5) */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_register_variable("a", LVM_LONG);
|
||||
lvm_set_relation(&p, LVM_EQ);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 5);
|
||||
|
||||
lvm_derive(&p);
|
||||
lvm_print_derivations(&p);
|
||||
|
||||
/* Infix: a < 10 => a:(-oo,9) */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_register_variable("a", LVM_LONG);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 10);
|
||||
|
||||
lvm_derive(&p);
|
||||
lvm_print_derivations(&p);
|
||||
|
||||
/* Infix: a < 100 /\ 10 < a => a:(11,99) */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_register_variable("a", LVM_LONG);
|
||||
lvm_set_relation(&p, LVM_AND);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 100);
|
||||
lvm_set_relation(&p, LVM_GE);
|
||||
lvm_set_long(&p, 10);
|
||||
lvm_set_variable(&p, "a");
|
||||
|
||||
lvm_derive(&p);
|
||||
lvm_print_derivations(&p);
|
||||
|
||||
/* Infix: a < 100 /\ b > 100 => a:(-oo,99), b:(101,oo) */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_register_variable("a", LVM_LONG);
|
||||
lvm_register_variable("b", LVM_LONG);
|
||||
lvm_set_relation(&p, LVM_AND);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 100);
|
||||
lvm_set_relation(&p, LVM_GE);
|
||||
lvm_set_variable(&p, "b");
|
||||
lvm_set_long(&p, 100);
|
||||
|
||||
lvm_derive(&p);
|
||||
lvm_print_derivations(&p);
|
||||
|
||||
/* Infix: a < 100 \/ a < 1000 \/ a < 1902 => a:(-oo,1901) */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_register_variable("a", LVM_LONG);
|
||||
lvm_set_relation(&p, LVM_OR);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 100);
|
||||
lvm_set_relation(&p, LVM_OR);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_long(&p, 1000);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 1902);
|
||||
|
||||
lvm_derive(&p);
|
||||
lvm_print_derivations(&p);
|
||||
|
||||
/* Infix: (a < 100 /\ a < 90 /\ a > 80 /\ a < 105) \/ b > 10000 =>
|
||||
a:(81,89), b:(10001:oo) */
|
||||
lvm_reset(&p, code, sizeof(code));
|
||||
lvm_register_variable("a", LVM_LONG);
|
||||
lvm_register_variable("b", LVM_LONG);
|
||||
|
||||
lvm_set_relation(&p, LVM_OR);
|
||||
lvm_set_relation(&p, LVM_GE);
|
||||
lvm_set_variable(&p, "b");
|
||||
lvm_set_long(&p, 10000);
|
||||
|
||||
lvm_set_relation(&p, LVM_AND);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 100);
|
||||
lvm_set_relation(&p, LVM_AND);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 90);
|
||||
lvm_set_relation(&p, LVM_AND);
|
||||
lvm_set_relation(&p, LVM_GE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 80);
|
||||
lvm_set_relation(&p, LVM_LE);
|
||||
lvm_set_variable(&p, "a");
|
||||
lvm_set_long(&p, 105);
|
||||
|
||||
lvm_derive(&p);
|
||||
lvm_print_derivations(&p);
|
||||
|
||||
printf("Done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user