mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-23 02:06:10 +01:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33f77b2192 | ||
|
|
e079c30c54 | ||
|
|
eba9f54454 | ||
|
|
a0a39e98cd | ||
|
|
2144bd58f9 | ||
|
|
fdd87779d7 | ||
|
|
44514e24d1 | ||
|
|
8857ecb669 | ||
|
|
1871f53b5a | ||
|
|
1de47b1133 | ||
|
|
2e38e9f218 | ||
|
|
a48511145c | ||
|
|
ae87ac1960 | ||
|
|
d84a5f6e75 | ||
|
|
f4025fb18f | ||
|
|
9d4e31b01b | ||
|
|
5950c5df4a | ||
|
|
691b64d192 | ||
|
|
573ba8c424 | ||
|
|
511fa3e5dd | ||
|
|
cc3128d22a | ||
|
|
78e097738a | ||
|
|
534c52cebf | ||
|
|
8cf6d01098 | ||
|
|
aadbe7652e | ||
|
|
7735612a16 | ||
|
|
c22de350f6 | ||
|
|
95d5aac01a | ||
|
|
7a31db91ba | ||
|
|
344ded01ac | ||
|
|
4747669df8 | ||
|
|
a532c7c190 | ||
|
|
a6772c6fae | ||
|
|
6ec580d267 | ||
|
|
7805ab2b46 | ||
|
|
e6401f6840 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -63,7 +63,7 @@ jobs:
|
||||
# run: |
|
||||
# cd ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/
|
||||
# dir build
|
||||
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_C6.bin
|
||||
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_H2.bin
|
||||
# cp merged-firmware.bin ../../espbinaries/OpenEPaperLink_esp32_H2.bin
|
||||
|
||||
# - name: Zip web files
|
||||
|
||||
@@ -13,6 +13,9 @@ menu "OEPL Hardware config"
|
||||
config OEPL_HARDWARE_PROFILE_CUSTOM
|
||||
bool "Custom"
|
||||
|
||||
config OEPL_HARDWARE_PROFILE_LILYGO
|
||||
bool "LILYGO-AP"
|
||||
|
||||
endchoice
|
||||
|
||||
config OEPL_HARDWARE_UART_TX
|
||||
@@ -40,6 +43,7 @@ menu "OEPL Hardware config"
|
||||
default 18 if IDF_TARGET_ESP32C2
|
||||
default 19 if IDF_TARGET_ESP32C3
|
||||
default 30 if IDF_TARGET_ESP32C6
|
||||
default 30 if IDF_TARGET_ESP32H2
|
||||
|
||||
config MISO_GPIO
|
||||
int "CC1101 MISO GPIO"
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include "radio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "second_uart.h"
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#endif
|
||||
#include "soc/uart_struct.h"
|
||||
#include "utils.h"
|
||||
#include <esp_mac.h>
|
||||
@@ -42,7 +44,7 @@ const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
||||
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
||||
|
||||
// VERSION GOES HERE!
|
||||
uint16_t version = 0x001d;
|
||||
uint16_t version = 0x001e;
|
||||
|
||||
#define RAW_PKT_PADDING 2
|
||||
|
||||
@@ -752,7 +754,11 @@ void app_main(void) {
|
||||
|
||||
pr("RES>");
|
||||
pr("RDY>");
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
ESP_LOGI(TAG, "C6 ready!");
|
||||
#else
|
||||
ESP_LOGI(TAG, "H2 ready!");
|
||||
#endif
|
||||
|
||||
housekeepingTimer = getMillis();
|
||||
while (1) {
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define LED1 22
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
#define LED2 23
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#define LED2 25
|
||||
#endif
|
||||
|
||||
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
||||
#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include "sdkconfig.h"
|
||||
// if you get an error about soc/lp_uart_reg.h not being found,
|
||||
// you didn't choose the right build target. :-)
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#endif
|
||||
#include "soc/uart_struct.h"
|
||||
#include "utils.h"
|
||||
#include <esp_mac.h>
|
||||
@@ -39,7 +41,9 @@ void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *fr
|
||||
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
|
||||
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
|
||||
esp_ieee802154_receive_sfd_done();
|
||||
if(esp_ieee802154_receive_handle_done(frame)) {
|
||||
ESP_EARLY_LOGI(TAG, "esp_ieee802154_receive_handle_done() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
|
||||
@@ -50,7 +54,7 @@ void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_erro
|
||||
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]);
|
||||
esp_ieee802154_receive_sfd_done();
|
||||
esp_ieee802154_receive_handle_done(ack);
|
||||
}
|
||||
static bool zigbee_is_enabled = false;
|
||||
void radio_init(uint8_t ch) {
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "soc/lp_uart_reg.h"
|
||||
static const char *TAG = "SECOND_UART";
|
||||
#endif
|
||||
#include "second_uart.h"
|
||||
|
||||
static const char *TAG = "SECOND_UART";
|
||||
|
||||
#define BUF_SIZE (1024)
|
||||
#define RD_BUF_SIZE (BUF_SIZE)
|
||||
|
||||
@@ -13,8 +13,11 @@ void uart_printf(const char *format, ...);
|
||||
#define pr uart_printf
|
||||
|
||||
#if defined(CONFIG_OEPL_HARDWARE_PROFILE_DEFAULT)
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 3
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 2
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 3
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 2
|
||||
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_LILYGO)
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 24
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 23
|
||||
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_POE_AP)
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 5
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 18
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#endif
|
||||
#include "nvs_flash.h"
|
||||
|
||||
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(OpenEPaperLink_esp32_C6)
|
||||
project(OpenEPaperLink_esp32_H2)
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
idf_component_register( SRCS
|
||||
SRCS "utils.c"
|
||||
SRCS "second_uart.c"
|
||||
SRCS "radio.c"
|
||||
SRCS "SubGigRadio.c"
|
||||
SRCS "cc1101_radio.c"
|
||||
SRCS "led.c"
|
||||
SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
SRC_DIRS "../../OpenEPaperLink_esp32_C6_AP/main"
|
||||
INCLUDE_DIRS "../../OpenEPaperLink_esp32_C6_AP/main")
|
||||
|
||||
@@ -13,6 +13,9 @@ menu "OEPL Hardware config"
|
||||
config OEPL_HARDWARE_PROFILE_CUSTOM
|
||||
bool "Custom"
|
||||
|
||||
config OEPL_HARDWARE_PROFILE_LILYGO
|
||||
bool "LILYGO-AP"
|
||||
|
||||
endchoice
|
||||
|
||||
config OEPL_HARDWARE_UART_TX
|
||||
|
||||
@@ -1,562 +0,0 @@
|
||||
#include "sdkconfig.h"
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <driver/spi_master.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "radio.h"
|
||||
#include "proto.h"
|
||||
#include "cc1101_radio.h"
|
||||
#include "SubGigRadio.h"
|
||||
|
||||
void DumpHex(void *AdrIn,int Len);
|
||||
|
||||
#define LOGE(format, ... ) \
|
||||
printf("%s#%d: " format,__FUNCTION__,__LINE__,## __VA_ARGS__)
|
||||
|
||||
#if 0
|
||||
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
||||
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
||||
#define LOG_HEX(x,y) DumpHex(x,y)
|
||||
#else
|
||||
#define LOG(format, ... )
|
||||
#define LOG_RAW(format, ... )
|
||||
#define LOG_HEX(x,y)
|
||||
#endif
|
||||
|
||||
|
||||
// SPI Stuff
|
||||
#if CONFIG_SPI2_HOST
|
||||
#define HOST_ID SPI2_HOST
|
||||
#elif CONFIG_SPI3_HOST
|
||||
#define HOST_ID SPI3_HOST
|
||||
#endif
|
||||
|
||||
// Address Config = No address check
|
||||
// Base Frequency = xxx.xxx
|
||||
// CRC Enable = false
|
||||
// Carrier Frequency = 915.000000
|
||||
// Channel Number = 0
|
||||
// Channel Spacing = 199.951172
|
||||
// Data Rate = 1.19948
|
||||
// Deviation = 5.157471
|
||||
// Device Address = 0
|
||||
// Manchester Enable = false
|
||||
// Modulated = false
|
||||
// Modulation Format = ASK/OOK
|
||||
// PA Ramping = false
|
||||
// Packet Length = 255
|
||||
// Packet Length Mode = Reserved
|
||||
// Preamble Count = 4
|
||||
// RX Filter BW = 58.035714
|
||||
// Sync Word Qualifier Mode = No preamble/sync
|
||||
// TX Power = 10
|
||||
// Whitening = false
|
||||
// Rf settings for CC1110
|
||||
const RfSetting gCW[] = {
|
||||
{CC1101_PKTCTRL0,0x22}, // PKTCTRL0: Packet Automation Control
|
||||
{CC1101_FSCTRL1,0x06}, // FSCTRL1: Frequency Synthesizer Control
|
||||
{CC1101_MDMCFG4,0xF5}, // MDMCFG4: Modem configuration
|
||||
{CC1101_MDMCFG3,0x83}, // MDMCFG3: Modem Configuration
|
||||
{CC1101_MDMCFG2,0xb0}, // MDMCFG2: Modem Configuration
|
||||
{CC1101_DEVIATN,0x15}, // DEVIATN: Modem Deviation Setting
|
||||
{CC1101_MCSM0,0x18}, // MCSM0: Main Radio Control State Machine Configuration
|
||||
{CC1101_FOCCFG,0x17}, // FOCCFG: Frequency Offset Compensation Configuration
|
||||
{CC1101_FSCAL3,0xE9}, // FSCAL3: Frequency Synthesizer Calibration
|
||||
{CC1101_FSCAL2,0x2A}, // FSCAL2: Frequency Synthesizer Calibration
|
||||
{CC1101_FSCAL1,0x00}, // FSCAL1: Frequency Synthesizer Calibration
|
||||
{CC1101_FSCAL0,0x1F}, // FSCAL0: Frequency Synthesizer Calibration
|
||||
{CC1101_TEST1,0x31}, // TEST1: Various Test Settings
|
||||
{CC1101_TEST0,0x09}, // TEST0: Various Test Settings
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
|
||||
// Set Base Frequency to 865.999634
|
||||
const RfSetting g866Mhz[] = {
|
||||
{CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte
|
||||
{CC1101_FREQ1,0x4e}, // FREQ1: Frequency Control Word, Middle Byte
|
||||
{CC1101_FREQ0,0xc4}, // FREQ0: Frequency Control Word, Low Byte
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
// Set Base Frequency to 863.999756
|
||||
const RfSetting g864Mhz[] = {
|
||||
{CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte
|
||||
{CC1101_FREQ1,0x3b}, // FREQ1: Frequency Control Word, Middle Byte
|
||||
{CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
// Set Base Frequency to 902.999756
|
||||
const RfSetting g903Mhz[] = {
|
||||
{CC1101_FREQ2,0x22}, // FREQ2: Frequency Control Word, High Byte
|
||||
{CC1101_FREQ1,0xbb}, // FREQ1: Frequency Control Word, Middle Byte
|
||||
{CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
|
||||
// Seet Base Frequency to 915.000000
|
||||
const RfSetting g915Mhz[] = {
|
||||
{CC1101_FREQ2,0x23}, // FREQ2: Frequency Control Word, High Byte
|
||||
{CC1101_FREQ1,0x31}, // FREQ1: Frequency Control Word, Middle Byte
|
||||
{CC1101_FREQ0,0x3B}, // FREQ0: Frequency Control Word, Low Byte
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
// Address Config = No address check
|
||||
// Base Frequency = 901.934937 (adjusted to compensate for the crappy crystal on the CC1101 board)
|
||||
// CRC Enable = true
|
||||
// Carrier Frequency = 901.934937
|
||||
// Channel Number = 0
|
||||
// Channel Spacing = 199.951172
|
||||
// Data Rate = 38.3835
|
||||
// Deviation = 20.629883
|
||||
// Device Address = ff
|
||||
// Manchester Enable = false
|
||||
// Modulated = true
|
||||
// Modulation Format = GFSK
|
||||
// PA Ramping = false
|
||||
// Packet Length = 61
|
||||
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
|
||||
// Preamble Count = 4
|
||||
// RX Filter BW = 101.562500
|
||||
// Sync Word Qualifier Mode = 30/32 sync word bits detected
|
||||
// TX Power = 10
|
||||
// Whitening = false
|
||||
// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@},"
|
||||
const RfSetting gIDF_Basic[] = {
|
||||
{CC1101_SYNC1,0xC7},
|
||||
{CC1101_SYNC0,0x0A},
|
||||
{CC1101_PKTLEN,0x3D},
|
||||
{CC1101_PKTCTRL0,0x05},
|
||||
{CC1101_ADDR,0xFF},
|
||||
{CC1101_FSCTRL1,0x08},
|
||||
{CC1101_FREQ2,0x22},
|
||||
{CC1101_FREQ1,0xB1},
|
||||
{CC1101_FREQ0,0x3B},
|
||||
{CC1101_MDMCFG4,0xCA},
|
||||
{CC1101_MDMCFG3,0x83},
|
||||
{CC1101_MDMCFG2,0x93},
|
||||
{CC1101_DEVIATN,0x35},
|
||||
// {CC1101_MCSM0,0x18}, FS_AUTOCAL = 1, PO_TIMEOUT = 2
|
||||
{CC1101_MCSM0,0x18},
|
||||
{CC1101_FOCCFG,0x16},
|
||||
{CC1101_AGCCTRL2,0x43},
|
||||
{CC1101_FSCAL3,0xEF},
|
||||
{CC1101_FSCAL2,0x2D},
|
||||
{CC1101_FSCAL1,0x25},
|
||||
{CC1101_FSCAL0,0x1F},
|
||||
{CC1101_TEST2,0x81},
|
||||
{CC1101_TEST1,0x35},
|
||||
{CC1101_TEST0,0x09},
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
// RF configuration from Dimitry's orginal code
|
||||
// Address Config = No address check
|
||||
// Base Frequency = 902.999756
|
||||
// CRC Autoflush = false
|
||||
// CRC Enable = true
|
||||
// Carrier Frequency = 902.999756
|
||||
// Channel Number = 0
|
||||
// Channel Spacing = 335.632324
|
||||
// Data Format = Normal mode
|
||||
// Data Rate = 249.939
|
||||
// Deviation = 165.039063
|
||||
// Device Address = 22
|
||||
// Manchester Enable = false
|
||||
// Modulated = true
|
||||
// Modulation Format = GFSK
|
||||
// PA Ramping = false
|
||||
// Packet Length = 255
|
||||
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
|
||||
// Preamble Count = 24
|
||||
// RX Filter BW = 650.000000
|
||||
// Sync Word Qualifier Mode = 30/32 sync word bits detected
|
||||
// TX Power = 0
|
||||
// Whitening = true
|
||||
// Rf settings for CC1101
|
||||
// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@},"
|
||||
const RfSetting gDmitry915[] = {
|
||||
{CC1101_FREQ2,0x22},
|
||||
{CC1101_FREQ1,0xBB},
|
||||
{CC1101_FREQ0,0x13},
|
||||
{CC1101_MDMCFG4,0x1D},
|
||||
{CC1101_MDMCFG3,0x3B},
|
||||
{CC1101_MDMCFG2,0x13},
|
||||
{CC1101_MDMCFG1,0x73},
|
||||
{CC1101_MDMCFG0,0xA7},
|
||||
{CC1101_DEVIATN,0x65},
|
||||
{CC1101_MCSM0,0x18},
|
||||
{CC1101_FOCCFG,0x1E},
|
||||
{CC1101_BSCFG,0x1C},
|
||||
{CC1101_AGCCTRL2,0xC7},
|
||||
{CC1101_AGCCTRL1,0x00},
|
||||
{CC1101_AGCCTRL0,0xB0},
|
||||
{CC1101_FREND1,0xB6},
|
||||
{CC1101_FSCAL3,0xEA},
|
||||
{CC1101_FSCAL2,0x2A},
|
||||
{CC1101_FSCAL1,0x00},
|
||||
{CC1101_FSCAL0,0x1F},
|
||||
{CC1101_TEST0,0x09},
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
SubGigData gSubGigData;
|
||||
|
||||
int CheckSubGigState(void);
|
||||
void SubGig_CC1101_reset(void);
|
||||
void SubGig_CC1101_SetConfig(const RfSetting *pConfig);
|
||||
|
||||
static void IRAM_ATTR gpio_isr_handler(void *arg)
|
||||
{
|
||||
gSubGigData.RxAvailable = true;
|
||||
}
|
||||
|
||||
// return SUBGIG_ERR_NONE aka ESP_OK aka 0 if CC1101 is detected and all is good
|
||||
SubGigErr SubGig_radio_init(uint8_t ch)
|
||||
{
|
||||
esp_err_t Err;
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = 5000000, // SPI clock is 5 MHz!
|
||||
.queue_size = 7,
|
||||
.mode = 0, // SPI mode 0
|
||||
.spics_io_num = -1, // we will use manual CS control
|
||||
.flags = SPI_DEVICE_NO_DUMMY
|
||||
};
|
||||
gpio_config_t io_conf = {
|
||||
.intr_type = GPIO_INTR_NEGEDGE, // GPIO interrupt type : falling edge
|
||||
//bit mask of the pins
|
||||
.pin_bit_mask = 1ULL<<CONFIG_GDO0_GPIO,
|
||||
//set as input mode
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
//enable pull-up mode
|
||||
.pull_up_en = 1,
|
||||
.pull_down_en = 0
|
||||
};
|
||||
int ErrLine = 0;
|
||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
||||
|
||||
do {
|
||||
gpio_reset_pin(CONFIG_CSN_GPIO);
|
||||
gpio_set_direction(CONFIG_CSN_GPIO, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(CONFIG_CSN_GPIO, 1);
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.sclk_io_num = CONFIG_SCK_GPIO,
|
||||
.mosi_io_num = CONFIG_MOSI_GPIO,
|
||||
.miso_io_num = CONFIG_MISO_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1
|
||||
};
|
||||
|
||||
if((Err = spi_bus_initialize(HOST_ID,&buscfg,SPI_DMA_CH_AUTO)) != 0) {
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
|
||||
if((Err = spi_bus_add_device(HOST_ID,&devcfg,&gSpiHndl)) != 0) {
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
|
||||
// Configure GDO0, interrupt on falling edge
|
||||
if((Err = gpio_config(&io_conf)) != 0) {
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
|
||||
// Configure GDO2, interrupts disabled
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.pin_bit_mask = 1ULL<<CONFIG_GDO2_GPIO;
|
||||
if((Err = gpio_config(&io_conf)) != 0) {
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
|
||||
// install gpio isr service
|
||||
if((Err = gpio_install_isr_service(0)) != 0) {
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
//hook isr handler for specific gpio pin
|
||||
Err = gpio_isr_handler_add(CONFIG_GDO0_GPIO,gpio_isr_handler,
|
||||
(void*) CONFIG_GDO0_GPIO);
|
||||
if(Err != 0) {
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
// Check Chip ID
|
||||
if(!CC1101_Present()) {
|
||||
Ret = SUBGIG_CC1101_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
gSubGigData.Present = true;
|
||||
SubGig_CC1101_reset();
|
||||
CC1101_SetConfig(NULL);
|
||||
SubGig_CC1101_SetConfig(gDmitry915);
|
||||
#if 0
|
||||
CC1101_DumpRegs();
|
||||
#endif
|
||||
if(ch != 0) {
|
||||
SubGig_radioSetChannel(ch);
|
||||
}
|
||||
// good to go!
|
||||
} while(false);
|
||||
|
||||
if(ErrLine != 0) {
|
||||
LOG("%s#%d: failed %d\n",__FUNCTION__,ErrLine,Err);
|
||||
if(Err == 0) {
|
||||
Ret = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
SubGigErr SubGig_radioSetChannel(uint8_t ch)
|
||||
{
|
||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
||||
|
||||
RfSetting SetChannr[2] = {
|
||||
{CC1101_CHANNR,0},
|
||||
{0xff,0} // end of table
|
||||
};
|
||||
|
||||
do {
|
||||
if(!gSubGigData.Enabled && gSubGigData.Present && ch != 0) {
|
||||
gSubGigData.Enabled = true;
|
||||
LOG("SubGhz enabled\n");
|
||||
}
|
||||
if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
if(ch == 0) {
|
||||
// Disable SubGhz
|
||||
LOG("SubGhz disabled\n");
|
||||
gSubGigData.Enabled = false;
|
||||
break;
|
||||
}
|
||||
LOG("Set channel %d\n",ch);
|
||||
|
||||
if(ch >= FIRST_866_CHAN && ch < FIRST_866_CHAN + NUM_866_CHANNELS) {
|
||||
// Base Frequency = 863.999756
|
||||
// total channels 6 (0 -> 5) (CHANNR 0 -> 15)
|
||||
// Channel 100 / CHANNR 0: 863.999756
|
||||
// Channel 101 / CHANNR 3: 865.006 Mhz
|
||||
// Channel 102 / CHANNR 6: 866.014 Mhz
|
||||
// Channel 103 / CHANNR 9: 867.020 Mhz
|
||||
// Channel 104 / CHANNR 12: 868.027 Mhz
|
||||
// Channel 105 / CHANNR 15: 869.034 Mhz
|
||||
SubGig_CC1101_SetConfig(g864Mhz);
|
||||
SetChannr[0].Value = (ch - FIRST_866_CHAN) * 3;
|
||||
}
|
||||
else {
|
||||
// Base Frequency = 902.999756
|
||||
// Dmitry's orginal code used 25 channels in 915 Mhz
|
||||
// We don't want to have to scan that many so for OEPL we'll just use 6
|
||||
// to match 866.
|
||||
// Channel 200 / CHANNR 0: 903.000 Mhz
|
||||
// Channel 201 / CHANNR 12: 907.027 Mhz
|
||||
// Channel 202 / CHANNR 24: 911.054 Mhz
|
||||
// Channel 203 / CHANNR 24: 915.083 Mhz
|
||||
// Channel 204 / CHANNR 48: 919.110 Mhz
|
||||
// Channel 205 / CHANNR 60: 923.138 Mhz
|
||||
SubGig_CC1101_SetConfig(g903Mhz);
|
||||
|
||||
if(ch >= FIRST_915_CHAN && ch < FIRST_915_CHAN + NUM_915_CHANNELS) {
|
||||
SetChannr[0].Value = (ch - FIRST_915_CHAN) * 12;
|
||||
}
|
||||
else {
|
||||
Ret = SUBGIG_INVALID_CHANNEL;
|
||||
SetChannr[0].Value = 0; // default to the first channel on 915
|
||||
}
|
||||
}
|
||||
SubGig_CC1101_SetConfig(SetChannr);
|
||||
CC1101_setRxState();
|
||||
} while(false);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
SubGigErr SubGig_radioTx(uint8_t *packet)
|
||||
{
|
||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
||||
|
||||
do {
|
||||
if(gSubGigData.FreqTest) {
|
||||
break;
|
||||
}
|
||||
if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(packet[0] < 3 || packet[0] > RADIO_MAX_PACKET_LEN + RAW_PKT_PADDING) {
|
||||
Ret = SUBGIG_TX_BAD_LEN;
|
||||
break;
|
||||
}
|
||||
|
||||
// All packets seem to be padded by RAW_PKT_PADDING (2 bytes)
|
||||
// Remove the padding before sending so the length is correct when received
|
||||
packet[0] -= RAW_PKT_PADDING;
|
||||
LOG("Sending %d byte subgig frame:\n",packet[0]);
|
||||
LOG_HEX(&packet[1],packet[0]);
|
||||
if(CC1101_Tx(packet)) {
|
||||
Ret = SUBGIG_TX_FAILED;
|
||||
}
|
||||
// Clear RxAvailable, in TX GDO0 deasserts on TX FIFO underflows
|
||||
gSubGigData.RxAvailable = false;
|
||||
// restore original len just in case anyone cares
|
||||
packet[0] += RAW_PKT_PADDING;
|
||||
} while(false);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// returns packet size in bytes data in data
|
||||
int8_t SubGig_commsRxUnencrypted(uint8_t *data)
|
||||
{
|
||||
int RxBytes;
|
||||
int8_t Ret = 0;
|
||||
|
||||
do {
|
||||
if(CheckSubGigState() != SUBGIG_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(gSubGigData.FreqTest) {
|
||||
break;
|
||||
}
|
||||
CC1101_logState();
|
||||
|
||||
if(!gSubGigData.RxAvailable && gpio_get_level(CONFIG_GDO0_GPIO) == 1) {
|
||||
// Did we miss an interrupt?
|
||||
if(gpio_get_level(CONFIG_GDO0_GPIO) == 1) {
|
||||
// Yup!
|
||||
LOGE("SubGhz lost interrupt\n");
|
||||
gSubGigData.RxAvailable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(gSubGigData.RxAvailable){
|
||||
gSubGigData.RxAvailable = false;
|
||||
RxBytes = CC1101_Rx(data,128,NULL,NULL);
|
||||
|
||||
if(RxBytes >= 2) {
|
||||
// NB: RxBytes includes the CRC, deduct it
|
||||
Ret = (uint8_t) RxBytes - 2;
|
||||
LOG("Received %d byte subgig frame:\n",Ret);
|
||||
LOG_HEX(data,Ret);
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
int CheckSubGigState()
|
||||
{
|
||||
int Err = SUBGIG_ERR_NONE;
|
||||
|
||||
if(!gSubGigData.Present) {
|
||||
Err = SUBGIG_CC1101_NOT_FOUND;
|
||||
}
|
||||
else if(!gSubGigData.Initialized) {
|
||||
Err = SUBGIG_NOT_INITIALIZED;
|
||||
}
|
||||
else if(!gSubGigData.Enabled) {
|
||||
Err = SUBGIG_NOT_ENABLED;
|
||||
}
|
||||
|
||||
if(Err != SUBGIG_ERR_NONE) {
|
||||
LOG("CheckSubGigState: returing %d\n",Err);
|
||||
}
|
||||
|
||||
return Err;
|
||||
}
|
||||
|
||||
SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart)
|
||||
{
|
||||
SubGigErr Err = SUBGIG_ERR_NONE;
|
||||
#if 0
|
||||
uint8_t TxData = 0; // len = 0
|
||||
|
||||
do {
|
||||
if((Err = CheckSubGigState()) != SUBGIG_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
if(bStart) {
|
||||
LOG_RAW("Starting %sMhz Freq test\n",b866Mhz ? "866" : "915");
|
||||
SubGig_CC1101_reset();
|
||||
SubGig_CC1101_SetConfig(gCW);
|
||||
SubGig_CC1101_SetConfig(b866Mhz ? g866Mhz : g915Mhz);
|
||||
CC1101_cmdStrobe(CC1101_SIDLE);
|
||||
CC1101_cmdStrobe(CC1101_SFTX); // flush Tx Fifo
|
||||
CC1101_cmdStrobe(CC1101_STX);
|
||||
gRfState = RFSTATE_TX;
|
||||
gSubGigData.FreqTest = true;
|
||||
}
|
||||
else {
|
||||
LOG_RAW("Ending Freq test\n");
|
||||
gSubGigData.FreqTest = false;
|
||||
SubGig_CC1101_reset();
|
||||
SubGig_CC1101_SetConfig(gSubGigData.pConfig);
|
||||
}
|
||||
} while(false);
|
||||
#endif
|
||||
return Err;
|
||||
}
|
||||
|
||||
void SubGig_CC1101_reset()
|
||||
{
|
||||
gSubGigData.Initialized = false;
|
||||
gSubGigData.FixedRegsSet = false;
|
||||
CC1101_reset();
|
||||
}
|
||||
|
||||
void SubGig_CC1101_SetConfig(const RfSetting *pConfig)
|
||||
{
|
||||
CC1101_SetConfig(pConfig);
|
||||
gSubGigData.Initialized = true;
|
||||
}
|
||||
|
||||
void DumpHex(void *AdrIn,int Len)
|
||||
{
|
||||
unsigned char *Adr = (unsigned char *) AdrIn;
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
while(i < Len) {
|
||||
for(j = 0; j < 16; j++) {
|
||||
if((i + j) == Len) {
|
||||
break;
|
||||
}
|
||||
LOG_RAW("%02x ",Adr[i+j]);
|
||||
}
|
||||
|
||||
LOG_RAW(" ");
|
||||
for(j = 0; j < 16; j++) {
|
||||
if((i + j) == Len) {
|
||||
break;
|
||||
}
|
||||
if(isprint(Adr[i+j])) {
|
||||
LOG_RAW("%c",Adr[i+j]);
|
||||
}
|
||||
else {
|
||||
LOG_RAW(".");
|
||||
}
|
||||
}
|
||||
i += 16;
|
||||
LOG_RAW("\n");
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef _SUBGIG_RADIO_H_
|
||||
#define _SUBGIG_RADIO_H_
|
||||
|
||||
//sub-GHz 866 Mhz channels start at 100
|
||||
#define FIRST_866_CHAN (100)
|
||||
#define NUM_866_CHANNELS (6)
|
||||
|
||||
//sub-GHz 915 Mhz channels start at 200
|
||||
#define FIRST_915_CHAN (200)
|
||||
#define NUM_915_CHANNELS (6)
|
||||
|
||||
typedef enum {
|
||||
SUBGIG_ERR_NONE,
|
||||
SUBGIG_CC1101_NOT_FOUND,
|
||||
SUBGIG_NOT_INITIALIZED,
|
||||
SUBGIG_NOT_ENABLED,
|
||||
SUBGIG_TX_FAILED,
|
||||
SUBGIG_TX_BAD_LEN,
|
||||
SUBGIG_INVALID_CHANNEL,
|
||||
} SubGigErr;
|
||||
|
||||
typedef struct {
|
||||
uint8_t Present:1;
|
||||
uint8_t Enabled:1;
|
||||
uint8_t FreqTest:1;
|
||||
uint8_t RxAvailable:1;
|
||||
uint8_t Initialized:1;
|
||||
uint8_t FixedRegsSet:1;
|
||||
} SubGigData;
|
||||
|
||||
extern SubGigData gSubGigData;
|
||||
|
||||
SubGigErr SubGig_radio_init(uint8_t ch);
|
||||
SubGigErr SubGig_radioTx(uint8_t *packet);
|
||||
SubGigErr SubGig_radioSetChannel(uint8_t ch);
|
||||
int8_t SubGig_commsRxUnencrypted(uint8_t *data);
|
||||
SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart);
|
||||
|
||||
#endif // _SUBGIG_RADIO_H_
|
||||
|
||||
@@ -1,790 +0,0 @@
|
||||
// Large portions of this code was copied from:
|
||||
// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 panStamp <contact@panstamp.com>
|
||||
* Copyright (c) 2016 Tyler Sommer <contact@tylersommer.pro>
|
||||
*
|
||||
* This file is part of the CC1101 project.
|
||||
*
|
||||
* CC1101 is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* CC1101 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CC1101; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA
|
||||
*
|
||||
* Author: Daniel Berenguer
|
||||
* Creation date: 03/03/2011
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include "proto.h"
|
||||
#include "cc1101_radio.h"
|
||||
#include "radio.h"
|
||||
|
||||
#define ENABLE_LOGGING 0
|
||||
|
||||
// LOGA - generic logging, always enabled
|
||||
#define LOGA(format, ... ) printf(format,## __VA_ARGS__)
|
||||
// LOGE - error logging, always enabled
|
||||
#define LOGE(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
||||
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
||||
#else
|
||||
#define LOG(format, ... )
|
||||
#define LOG_RAW(format, ... )
|
||||
#endif
|
||||
|
||||
#define ENABLE_VERBOSE_LOGGING 0
|
||||
|
||||
#if ENABLE_VERBOSE_LOGGING
|
||||
#define LOGV(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
||||
#define LOGV_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
||||
#else
|
||||
#define LOGV(format, ... )
|
||||
#define LOGB_RAW(format, ... )
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <driver/spi_master.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* RF STATES
|
||||
*/
|
||||
enum RFSTATE {
|
||||
RFSTATE_IDLE = 0,
|
||||
RFSTATE_RX,
|
||||
RFSTATE_TX
|
||||
};
|
||||
|
||||
/**
|
||||
* Type of transfers
|
||||
*/
|
||||
#define WRITE_BURST 0x40
|
||||
#define READ_SINGLE 0x80
|
||||
#define READ_BURST 0xC0
|
||||
|
||||
/**
|
||||
* Type of register
|
||||
*/
|
||||
#define CC1101_CONFIG_REGISTER READ_SINGLE
|
||||
#define CC1101_STATUS_REGISTER READ_BURST
|
||||
|
||||
/**
|
||||
* PATABLE & FIFO's
|
||||
*/
|
||||
#define CC1101_PATABLE 0x3E // PATABLE address
|
||||
#define CC1101_TXFIFO 0x3F // TX FIFO address
|
||||
#define CC1101_RXFIFO 0x3F // RX FIFO address
|
||||
|
||||
/**
|
||||
* Command strobes
|
||||
*/
|
||||
#define CC1101_SRES 0x30 // Reset CC1101 chip
|
||||
#define CC1101_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA):
|
||||
// Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround).
|
||||
#define CC1101_SXOFF 0x32 // Turn off crystal oscillator
|
||||
#define CC1101_SCAL 0x33 // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without
|
||||
// setting manual calibration mode (MCSM0.FS_AUTOCAL=0)
|
||||
#define CC1101_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1
|
||||
#define CC1101_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1.
|
||||
// If in RX state and CCA is enabled: Only go to TX if channel is clear
|
||||
#define CC1101_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable
|
||||
#define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if
|
||||
// WORCTRL.RC_PD=0
|
||||
#define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high
|
||||
#define CC1101_SFRX 0x3A // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states
|
||||
#define CC1101_SFTX 0x3B // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states
|
||||
#define CC1101_SWORRST 0x3C // Reset real time clock to Event1 value
|
||||
#define CC1101_SNOP 0x3D // No operation. May be used to get access to the chip status byte
|
||||
|
||||
#define CC1101_STATE_SLEEP 0x00
|
||||
#define CC1101_STATE_IDLE 0x01
|
||||
#define CC1101_STATE_XOFF 0x02
|
||||
#define CC1101_STATE_VCOON_MC 0x03
|
||||
#define CC1101_STATE_REGON_MC 0x04
|
||||
#define CC1101_STATE_MANCAL 0x05
|
||||
#define CC1101_STATE_VCOON 0x06
|
||||
#define CC1101_STATE_REGON 0x07
|
||||
#define CC1101_STATE_STARTCAL 0x08
|
||||
#define CC1101_STATE_BWBOOST 0x09
|
||||
#define CC1101_STATE_FS_LOCK 0x0A
|
||||
#define CC1101_STATE_IFADCON 0x0B
|
||||
#define CC1101_STATE_ENDCAL 0x0C
|
||||
#define CC1101_STATE_RX 0x0D
|
||||
#define CC1101_STATE_RX_END 0x0E
|
||||
#define CC1101_STATE_RX_RST 0x0F
|
||||
#define CC1101_STATE_TXRX_SWITCH 0x10
|
||||
#define CC1101_STATE_RXFIFO_OVERFLOW 0x11
|
||||
#define CC1101_STATE_FSTXON 0x12
|
||||
#define CC1101_STATE_TX 0x13
|
||||
#define CC1101_STATE_TX_END 0x14
|
||||
#define CC1101_STATE_RXTX_SWITCH 0x15
|
||||
#define CC1101_STATE_TXFIFO_UNDERFLOW 0x16
|
||||
|
||||
// Masks for first byte read from RXFIFO
|
||||
#define CC1101_NUM_RXBYTES_MASK 0x7f
|
||||
#define CC1101_RXFIFO_OVERFLOW_MASK 0x80
|
||||
|
||||
// Masks for last byte read from RXFIFO
|
||||
#define CC1101_LQI_MASK 0x7f
|
||||
#define CC1101_CRC_OK_MASK 0x80
|
||||
|
||||
// IOCFG2 GDO2: high when TX FIFO at or above the TX FIFO threshold
|
||||
#define CC1101_DEFVAL_IOCFG2 0x02
|
||||
|
||||
// IOCFG1 GDO1: High impedance (3-state)
|
||||
#define CC1101_DEFVAL_IOCFG1 0x2E
|
||||
|
||||
// GDO0 goes high when sync word has been sent / received, and
|
||||
// goes low at the end of the packet.
|
||||
// In TX mode the pin will go low if the TX FIFO underflows.
|
||||
#define CC1101_DEFVAL_IOCFG0 0x06
|
||||
|
||||
// Threshold = 32 bytes (1/2 of FIFO len)
|
||||
#define CC1101_DEFVAL_FIFOTHR 0x07
|
||||
#define CC1101_DEFVAL_RCCTRL1 0x41
|
||||
#define CC1101_DEFVAL_RCCTRL0 0x00
|
||||
#define CC1101_DEFVAL_AGCTEST 0x3F
|
||||
#define CC1101_DEFVAL_MCSM1 0x20
|
||||
#define CC1101_DEFVAL_WORCTRL 0xFB
|
||||
#define CC1101_DEFVAL_FSCTRL0 0
|
||||
|
||||
#define CC1101_DEFVAL_PATABLE 0xc0 // full power
|
||||
|
||||
RfSetting gFixedConfig[] = {
|
||||
{CC1101_IOCFG2,CC1101_DEFVAL_IOCFG2},
|
||||
{CC1101_IOCFG1,CC1101_DEFVAL_IOCFG1},
|
||||
{CC1101_IOCFG0,CC1101_DEFVAL_IOCFG0},
|
||||
{CC1101_FIFOTHR,CC1101_DEFVAL_FIFOTHR},
|
||||
{CC1101_FSCTRL0,CC1101_DEFVAL_FSCTRL0},
|
||||
{CC1101_RCCTRL1,CC1101_DEFVAL_RCCTRL1},
|
||||
{CC1101_RCCTRL0,CC1101_DEFVAL_RCCTRL0},
|
||||
{CC1101_MCSM1,CC1101_DEFVAL_MCSM1},
|
||||
{CC1101_WORCTRL,CC1101_DEFVAL_WORCTRL},
|
||||
{0xff,0},
|
||||
};
|
||||
|
||||
void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len);
|
||||
void CC1101_cmdStrobe(uint8_t cmd);
|
||||
void CC1101_wakeUp(void);
|
||||
uint8_t CC1101_readReg(uint8_t regAddr, uint8_t regType);
|
||||
void CC1101_writeReg(uint8_t regAddr, uint8_t value);
|
||||
void CC1101_setTxState(void);
|
||||
|
||||
void setIdleState(void);
|
||||
|
||||
spi_device_handle_t gSpiHndl;
|
||||
|
||||
#define readConfigReg(regAddr) CC1101_readReg(regAddr, CC1101_CONFIG_REGISTER)
|
||||
#define readStatusReg(regAddr) CC1101_readReg(regAddr, CC1101_STATUS_REGISTER)
|
||||
#define flushRxFifo() CC1101_cmdStrobe(CC1101_SFRX)
|
||||
#define flushTxFifo() CC1101_cmdStrobe(CC1101_SFTX)
|
||||
|
||||
const char *RegNamesCC1101[] = {
|
||||
"IOCFG2", // 0x00 GDO2 output pin configuration
|
||||
"IOCFG1", // 0x01 GDO1 output pin configuration
|
||||
"IOCFG0", // 0x02 GDO0 output pin configuration
|
||||
"FIFOTHR", // 0x03 RX FIFO and TX FIFO thresholds
|
||||
"SYNC1", // 0x04 Sync word, high INT8U
|
||||
"SYNC0", // 0x05 Sync word, low INT8U
|
||||
"PKTLEN", // 0x06 Packet length
|
||||
"PKTCTRL1", // 0x07 Packet automation control
|
||||
"PKTCTRL0", // 0x08 Packet automation control
|
||||
"ADDR", // 0x09 Device address
|
||||
"CHANNR", // 0x0A Channel number
|
||||
"FSCTRL1", // 0x0B Frequency synthesizer control
|
||||
"FSCTRL0", // 0x0C Frequency synthesizer control
|
||||
"FREQ2", // 0x0D Frequency control word, high INT8U
|
||||
"FREQ1", // 0x0E Frequency control word, middle INT8U
|
||||
"FREQ0", // 0x0F Frequency control word, low INT8U
|
||||
"MDMCFG4", // 0x10 Modem configuration
|
||||
"MDMCFG3", // 0x11 Modem configuration
|
||||
"MDMCFG2", // 0x12 Modem configuration
|
||||
"MDMCFG1", // 0x13 Modem configuration
|
||||
"MDMCFG0", // 0x14 Modem configuration
|
||||
"DEVIATN", // 0x15 Modem deviation setting
|
||||
"MCSM2", // 0x16 Main Radio Control State Machine configuration
|
||||
"MCSM1", // 0x17 Main Radio Control State Machine configuration
|
||||
"MCSM0", // 0x18 Main Radio Control State Machine configuration
|
||||
"FOCCFG", // 0x19 Frequency Offset Compensation configuration
|
||||
"BSCFG", // 0x1A Bit Synchronization configuration
|
||||
"AGCCTRL2", // 0x1B AGC control
|
||||
"AGCCTRL1", // 0x1C AGC control
|
||||
"AGCCTRL0", // 0x1D AGC control
|
||||
"WOREVT1", // 0x1E High INT8U Event 0 timeout
|
||||
"WOREVT0", // 0x1F Low INT8U Event 0 timeout
|
||||
"WORCTRL", // 0x20 Wake On Radio control
|
||||
"FREND1", // 0x21 Front end RX configuration
|
||||
"FREND0", // 0x22 Front end TX configuration
|
||||
"FSCAL3", // 0x23 Frequency synthesizer calibration
|
||||
"FSCAL2", // 0x24 Frequency synthesizer calibration
|
||||
"FSCAL1", // 0x25 Frequency synthesizer calibration
|
||||
"FSCAL0", // 0x26 Frequency synthesizer calibration
|
||||
"RCCTRL1", // 0x27 RC oscillator configuration
|
||||
"RCCTRL0", // 0x28 RC oscillator configuration
|
||||
"FSTEST", // 0x29 Frequency synthesizer calibration control
|
||||
"PTEST", // 0x2A Production test
|
||||
"AGCTEST", // 0x2B AGC test
|
||||
"TEST2", // 0x2C Various test settings
|
||||
"TEST1", // 0x2D Various test settings
|
||||
"TEST0", // 0x2E Various test settings
|
||||
"0x2f", // 0x2f
|
||||
//CC1101 Strobe commands
|
||||
"SRES", // 0x30 Reset chip.
|
||||
"SFSTXON", // 0x31 Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
|
||||
"SXOFF", // 0x32 Turn off crystal oscillator.
|
||||
"SCAL", // 0x33 Calibrate frequency synthesizer and turn it off
|
||||
"SRX", // 0x34 Enable RX. Perform calibration first if coming from IDLE and
|
||||
"STX", // 0x35 In IDLE state: Enable TX. Perform calibration first if
|
||||
"SIDLE", // 0x36 Exit RX / TX, turn off frequency synthesizer and exit
|
||||
"SAFC", // 0x37 Perform AFC adjustment of the frequency synthesizer
|
||||
"SWOR", // 0x38 Start automatic RX polling sequence (Wake-on-Radio)
|
||||
"SPWD", // 0x39 Enter power down mode when CSn goes high.
|
||||
"SFRX", // 0x3A Flush the RX FIFO buffer.
|
||||
"SFTX", // 0x3B Flush the TX FIFO buffer.
|
||||
"SWORRST", // 0x3C Reset real time clock.
|
||||
"SNOP", // 0x3D No operation. May be used to pad strobe commands to two
|
||||
"PATABLE" // 0x3E
|
||||
};
|
||||
|
||||
|
||||
// SPI Stuff
|
||||
#if CONFIG_SPI2_HOST
|
||||
#define HOST_ID SPI2_HOST
|
||||
#elif CONFIG_SPI3_HOST
|
||||
#define HOST_ID SPI3_HOST
|
||||
#endif
|
||||
|
||||
/*
|
||||
* RF state
|
||||
*/
|
||||
static uint8_t gRfState;
|
||||
|
||||
#define cc1101_Select() gpio_set_level(CONFIG_CSN_GPIO, LOW)
|
||||
#define cc1101_Deselect() gpio_set_level(CONFIG_CSN_GPIO, HIGH)
|
||||
#define wait_Miso() while(gpio_get_level(CONFIG_MISO_GPIO)>0)
|
||||
#define getGDO0state() gpio_get_level(CONFIG_GDO0_GPIO)
|
||||
#define wait_GDO0_high() while(!getGDO0state())
|
||||
#define wait_GDO0_low() while(getGDO0state())
|
||||
#define getGDO2state() gpio_get_level(CONFIG_GDO2_GPIO)
|
||||
#define wait_GDO2_low() while(getGDO2state())
|
||||
|
||||
/**
|
||||
* Arduino Macros
|
||||
*/
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
|
||||
#define delayMicroseconds(us) esp_rom_delay_us(us)
|
||||
#define LOW 0
|
||||
#define HIGH 1
|
||||
|
||||
int32_t gFreqErrSum;
|
||||
uint8_t gFreqErrSumCount;
|
||||
int8_t gFreqCorrection;
|
||||
|
||||
bool spi_write_byte(uint8_t* Dataout,size_t DataLength)
|
||||
{
|
||||
spi_transaction_t SPITransaction;
|
||||
|
||||
if(DataLength > 0) {
|
||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
||||
SPITransaction.length = DataLength * 8;
|
||||
SPITransaction.tx_buffer = Dataout;
|
||||
SPITransaction.rx_buffer = NULL;
|
||||
spi_device_transmit(gSpiHndl,&SPITransaction);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spi_read_byte(uint8_t* Datain,uint8_t* Dataout,size_t DataLength)
|
||||
{
|
||||
spi_transaction_t SPITransaction;
|
||||
|
||||
if(DataLength > 0) {
|
||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
||||
SPITransaction.length = DataLength * 8;
|
||||
SPITransaction.tx_buffer = Dataout;
|
||||
SPITransaction.rx_buffer = Datain;
|
||||
spi_device_transmit(gSpiHndl,&SPITransaction);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t spi_transfer(uint8_t address)
|
||||
{
|
||||
uint8_t datain[1];
|
||||
uint8_t dataout[1];
|
||||
dataout[0] = address;
|
||||
//spi_write_byte(dev, dataout, 1 );
|
||||
//spi_read_byte(datain, dataout, 1 );
|
||||
|
||||
spi_transaction_t SPITransaction;
|
||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
||||
SPITransaction.length = 8;
|
||||
SPITransaction.tx_buffer = dataout;
|
||||
SPITransaction.rx_buffer = datain;
|
||||
spi_device_transmit(gSpiHndl,&SPITransaction);
|
||||
|
||||
return datain[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* CC1101_wakeUp
|
||||
*
|
||||
* Wake up CC1101 from Power Down state
|
||||
*/
|
||||
void CC1101_wakeUp(void)
|
||||
{
|
||||
cc1101_Select();
|
||||
wait_Miso();
|
||||
cc1101_Deselect();
|
||||
}
|
||||
|
||||
/**
|
||||
* CC1101_writeReg
|
||||
*
|
||||
* Write single register into the CC1101 IC via SPI
|
||||
*
|
||||
* @param regAddr Register address
|
||||
* @param value Value to be writen
|
||||
*/
|
||||
void CC1101_writeReg(uint8_t regAddr, uint8_t value)
|
||||
{
|
||||
if(regAddr < 0x3f) {
|
||||
LOGV("0x%x -> %s(0x%x)\n",value,RegNamesCC1101[regAddr],regAddr);
|
||||
}
|
||||
else {
|
||||
LOGV("0x%x -> 0x%x\n",value,regAddr);
|
||||
}
|
||||
cc1101_Select(); // Select CC1101
|
||||
wait_Miso(); // Wait until MISO goes low
|
||||
spi_transfer(regAddr); // Send register address
|
||||
spi_transfer(value); // Send value
|
||||
cc1101_Deselect(); // Deselect CC1101
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CC1101_cmdStrobe
|
||||
*
|
||||
* Send command strobe to the CC1101 IC via SPI
|
||||
*
|
||||
* @param cmd Command strobe
|
||||
*/
|
||||
void CC1101_cmdStrobe(uint8_t cmd)
|
||||
{
|
||||
cc1101_Select();
|
||||
wait_Miso();
|
||||
spi_transfer(cmd);
|
||||
cc1101_Deselect();
|
||||
}
|
||||
|
||||
/**
|
||||
* CC1101_readReg
|
||||
*
|
||||
* Read CC1101 register via SPI
|
||||
*
|
||||
* @param regAddr Register address
|
||||
* @param regType Type of register: CONFIG_REGISTER or STATUS_REGISTER
|
||||
*
|
||||
* Return:
|
||||
* Data uint8_t returned by the CC1101 IC
|
||||
*/
|
||||
uint8_t CC1101_readReg(uint8_t regAddr,uint8_t regType)
|
||||
{
|
||||
uint8_t addr, val;
|
||||
|
||||
addr = regAddr | regType;
|
||||
cc1101_Select();
|
||||
wait_Miso();
|
||||
spi_transfer(addr);
|
||||
val = spi_transfer(0x00); // Read result
|
||||
cc1101_Deselect();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* CC1101_readBurstReg
|
||||
*
|
||||
* Read burst data from CC1101 via SPI
|
||||
*
|
||||
* @param buffer Buffer where to copy the result to
|
||||
* @param regAddr Register address
|
||||
* @param len Data length
|
||||
*/
|
||||
void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len)
|
||||
{
|
||||
uint8_t addr, i;
|
||||
|
||||
addr = regAddr | READ_BURST;
|
||||
cc1101_Select();
|
||||
wait_Miso();
|
||||
spi_transfer(addr); // Send register address
|
||||
for(i = 0; i < len; i++) {
|
||||
buffer[i] = spi_transfer(0x00); // Read result uint8_t by uint8_t
|
||||
}
|
||||
cc1101_Deselect();
|
||||
}
|
||||
|
||||
/**
|
||||
* reset
|
||||
*
|
||||
* Reset CC1101
|
||||
*/
|
||||
void CC1101_reset(void)
|
||||
{
|
||||
// See sectin 19.1.2 of the CC1101 spec sheet for reasons for the following
|
||||
cc1101_Deselect();
|
||||
delayMicroseconds(5);
|
||||
cc1101_Select();
|
||||
delayMicroseconds(10);
|
||||
cc1101_Deselect();
|
||||
delayMicroseconds(41);
|
||||
cc1101_Select();
|
||||
|
||||
// Wait until MISO goes low indicating XOSC stable
|
||||
wait_Miso();
|
||||
spi_transfer(CC1101_SRES); // Send reset command strobe
|
||||
wait_Miso();
|
||||
cc1101_Deselect();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CC1101_setRxState
|
||||
*
|
||||
* Enter Rx state
|
||||
*/
|
||||
void CC1101_setRxState(void)
|
||||
{
|
||||
CC1101_cmdStrobe(CC1101_SRX);
|
||||
gRfState = RFSTATE_RX;
|
||||
}
|
||||
|
||||
/**
|
||||
* CC1101_setTxState
|
||||
*
|
||||
* Enter Tx state
|
||||
*/
|
||||
void CC1101_setTxState(void)
|
||||
{
|
||||
CC1101_cmdStrobe(CC1101_STX);
|
||||
gRfState = RFSTATE_TX;
|
||||
}
|
||||
|
||||
|
||||
void CC1101_DumpRegs()
|
||||
{
|
||||
#if ENABLE_LOGGING
|
||||
uint8_t regAddr;
|
||||
uint8_t value;
|
||||
|
||||
LOG("\n");
|
||||
for(regAddr = 0; regAddr < 0x2f; regAddr++) {
|
||||
value = CC1101_readReg(regAddr,READ_SINGLE);
|
||||
LOG("%02x %s: 0x%02X\n",regAddr,RegNamesCC1101[regAddr],value);
|
||||
}
|
||||
|
||||
#if 0
|
||||
for(regAddr = 0; regAddr < 0x2f; regAddr++) {
|
||||
value = CC1101_readReg(regAddr,READ_SINGLE);
|
||||
LOG("<Register><Name>%s</Name><Value>0x%02X</Value></Register>\n",RegNamesCC1101[regAddr],value);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool CC1101_Tx(uint8_t *TxData)
|
||||
{
|
||||
bool Ret = false;
|
||||
int ErrLine = 0;
|
||||
spi_transaction_t SPITransaction;
|
||||
uint8_t BytesSent = 0;
|
||||
uint8_t Bytes2Send;
|
||||
uint8_t len;
|
||||
uint8_t CanSend;
|
||||
esp_err_t Err;
|
||||
|
||||
do {
|
||||
// The first byte in the buffer is the number of data bytes to send,
|
||||
// we also need to send the first byte
|
||||
len = 1 + *TxData;
|
||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
||||
SPITransaction.tx_buffer = TxData;
|
||||
|
||||
setIdleState();
|
||||
flushTxFifo();
|
||||
|
||||
while(BytesSent < len) {
|
||||
Bytes2Send = len - BytesSent;
|
||||
if(BytesSent == 0) {
|
||||
// First chunk, the FIFO is empty and can take 64 bytes
|
||||
if(Bytes2Send > 64) {
|
||||
Bytes2Send = 64;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not the first chunk, we can only send FIFO_THRESHOLD bytes
|
||||
// and only when GDO2 says we can
|
||||
if(getGDO2state()) {
|
||||
wait_GDO2_low();
|
||||
}
|
||||
CanSend = readStatusReg(CC1101_TXBYTES);
|
||||
if(CanSend & 0x80) {
|
||||
LOGE("TX FIFO underflow, BytesSent %d\n",BytesSent);
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
CanSend = 64 - CanSend;
|
||||
if(CanSend == 0) {
|
||||
LOGE("CanSend == 0, GDO2 problem\n");
|
||||
ErrLine = __LINE__;
|
||||
break;
|
||||
}
|
||||
|
||||
if(Bytes2Send > CanSend) {
|
||||
Bytes2Send = CanSend;
|
||||
}
|
||||
}
|
||||
SPITransaction.length = Bytes2Send * 8;
|
||||
SPITransaction.rxlength = 0;
|
||||
cc1101_Select();
|
||||
wait_Miso();
|
||||
spi_transfer(CC1101_TXFIFO | WRITE_BURST);
|
||||
if((Err = spi_device_transmit(gSpiHndl,&SPITransaction)) != ESP_OK) {
|
||||
ErrLine = __LINE__;
|
||||
LOGE("spi_device_transmit failed %d\n",Err);
|
||||
break;
|
||||
}
|
||||
cc1101_Deselect();
|
||||
// LOG("Sending %d bytes\n",Bytes2Send);
|
||||
if(BytesSent == 0) {
|
||||
// some or all of the tx data has been written to the FIFO,
|
||||
// start transmitting
|
||||
// LOG("Start tx\n");
|
||||
CC1101_setTxState();
|
||||
// Wait for the sync word to be transmitted
|
||||
wait_GDO0_high();
|
||||
}
|
||||
SPITransaction.tx_buffer += Bytes2Send;
|
||||
BytesSent += Bytes2Send;
|
||||
}
|
||||
|
||||
// Wait until the end of the TxData transmission
|
||||
wait_GDO0_low();
|
||||
Ret = true;
|
||||
} while(false);
|
||||
|
||||
setIdleState();
|
||||
CC1101_setRxState();
|
||||
|
||||
if(ErrLine != 0) {
|
||||
LOGE("%s#%d: failure\n",__FUNCTION__,ErrLine);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// Called when GDO0 goes low, i.e. end of packet.
|
||||
// Everything has been received.
|
||||
// NB: this means the entire packet must fit in the FIFO so maximum
|
||||
// message length is 64 bytes.
|
||||
int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi)
|
||||
{
|
||||
uint8_t rxBytes = readStatusReg(CC1101_RXBYTES);
|
||||
uint8_t Rssi;
|
||||
uint8_t Lqi;
|
||||
int Ret;
|
||||
int8_t FreqErr;
|
||||
int8_t FreqCorrection;
|
||||
|
||||
// Any data waiting to be read and no overflow?
|
||||
do {
|
||||
if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) {
|
||||
LOGE("RxFifo overflow\n");
|
||||
Ret = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
if(rxBytes < 2) {
|
||||
// should have at least 2 bytes, packet len and one byte of data
|
||||
LOGE("Internal error, rxBytes = %d\n",rxBytes);
|
||||
Ret = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get packet length
|
||||
Ret = readConfigReg(CC1101_RXFIFO);
|
||||
if(Ret > RxBufLen) {
|
||||
// Toss the data
|
||||
LOGE("RxBuf too small %d < %d\n",RxBufLen,Ret);
|
||||
Ret = -1;
|
||||
break;
|
||||
}
|
||||
// Read the data
|
||||
CC1101_readBurstReg(RxBuf,CC1101_RXFIFO,Ret);
|
||||
// Read RSSI
|
||||
Rssi = readConfigReg(CC1101_RXFIFO);
|
||||
// Read LQI and CRC_OK
|
||||
Lqi = readConfigReg(CC1101_RXFIFO);
|
||||
if(!(Lqi & CC1101_CRC_OK_MASK)) {
|
||||
// Crc error, ignore the packet
|
||||
LOG("Ignoring %d byte packet, CRC error\n",Ret);
|
||||
Ret = 0;
|
||||
break;
|
||||
}
|
||||
// CRC is valid
|
||||
if(pRssi != NULL) {
|
||||
*pRssi = Rssi;
|
||||
}
|
||||
if(pLqi != NULL) {
|
||||
*pLqi = Lqi & CC1101_LQI_MASK;
|
||||
}
|
||||
FreqErr = (int8_t) CC1101_readReg(CC1101_FREQEST,CC1101_STATUS_REGISTER);
|
||||
if(FreqErr != 0 && gFreqErrSumCount < 255) {
|
||||
gFreqErrSum += FreqErr + gFreqCorrection;
|
||||
gFreqErrSumCount++;
|
||||
FreqCorrection = (int8_t) (gFreqErrSum / gFreqErrSumCount);
|
||||
if(gFreqCorrection != FreqCorrection) {
|
||||
LOGA("FreqCorrection %d -> %d\n",gFreqCorrection,FreqCorrection);
|
||||
gFreqCorrection = FreqCorrection;
|
||||
CC1101_writeReg(CC1101_FSCTRL0,gFreqCorrection);
|
||||
}
|
||||
if(gFreqErrSumCount == 255) {
|
||||
LOGA("Final FreqCorrection %d\n",gFreqCorrection);
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
setIdleState();
|
||||
flushRxFifo();
|
||||
CC1101_setRxState();
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
bool CC1101_Present()
|
||||
{
|
||||
bool Ret = false;
|
||||
uint8_t PartNum = CC1101_readReg(CC1101_PARTNUM, CC1101_STATUS_REGISTER);
|
||||
uint8_t ChipVersion = CC1101_readReg(CC1101_VERSION, CC1101_STATUS_REGISTER);
|
||||
|
||||
if(PartNum == 0 && (ChipVersion == 20 || ChipVersion == 4)) {
|
||||
LOGA("CC1101 detected\n");
|
||||
Ret = true;
|
||||
}
|
||||
else {
|
||||
if(PartNum != 0) {
|
||||
LOGA("Invalid PartNum 0x%x\n",PartNum);
|
||||
}
|
||||
else {
|
||||
LOGA("Invalid or unsupported ChipVersion 0x%x\n",ChipVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
void CC1101_SetConfig(const RfSetting *pConfig)
|
||||
{
|
||||
int i;
|
||||
uint8_t RegWasSet[CC1101_TEST0 + 1];
|
||||
uint8_t Reg;
|
||||
|
||||
memset(RegWasSet,0,sizeof(RegWasSet));
|
||||
setIdleState();
|
||||
|
||||
if(pConfig == NULL) {
|
||||
// Just set the fixed registers
|
||||
LOG("Setting fixed registers\n");
|
||||
for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) {
|
||||
CC1101_writeReg(Reg,gFixedConfig[i].Value);
|
||||
}
|
||||
// Set TX power
|
||||
CC1101_writeReg(CC1101_PATABLE,CC1101_DEFVAL_PATABLE);
|
||||
}
|
||||
else {
|
||||
for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) {
|
||||
RegWasSet[Reg] = 1;
|
||||
}
|
||||
|
||||
while((Reg = pConfig->Reg) != 0xff) {
|
||||
if(RegWasSet[Reg] == 1) {
|
||||
LOG("%s value ignored\n",RegNamesCC1101[Reg]);
|
||||
}
|
||||
else {
|
||||
if(RegWasSet[Reg] == 2) {
|
||||
LOG("%s value set before\n",RegNamesCC1101[Reg]);
|
||||
}
|
||||
CC1101_writeReg(pConfig->Reg,pConfig->Value);
|
||||
RegWasSet[Reg] = 2;
|
||||
}
|
||||
pConfig++;
|
||||
}
|
||||
#if 0
|
||||
for(Reg = 0; Reg <= CC1101_TEST0; Reg++) {
|
||||
if(RegWasSet[Reg] == 0) {
|
||||
LOG("%s value not set\n",RegNamesCC1101[Reg]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setIdleState()
|
||||
{
|
||||
uint8_t MarcState;
|
||||
CC1101_cmdStrobe(CC1101_SIDLE);
|
||||
// Wait for it
|
||||
do {
|
||||
MarcState = readStatusReg(CC1101_MARCSTATE);
|
||||
} while(MarcState != CC1101_STATE_IDLE);
|
||||
}
|
||||
|
||||
|
||||
void CC1101_logState()
|
||||
{
|
||||
static uint8_t LastMarcState = 0xff;
|
||||
uint8_t MarcState;
|
||||
|
||||
MarcState = readStatusReg(CC1101_MARCSTATE);
|
||||
if(LastMarcState != MarcState) {
|
||||
LOG("MarcState 0x%x -> 0x%x\n",LastMarcState,MarcState);
|
||||
LastMarcState = MarcState;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
// Large portions of this code was copied from:
|
||||
// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 panStamp <contact@panstamp.com>
|
||||
* Copyright (c) 2016 Tyler Sommer <contact@tylersommer.pro>
|
||||
*
|
||||
* This file is part of the CC1101 project.
|
||||
*
|
||||
* CC1101 is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* CC1101 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CC1101; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA
|
||||
*
|
||||
* Author: Daniel Berenguer
|
||||
* Creation date: 03/03/2011
|
||||
*/
|
||||
|
||||
#ifndef __CC1101_RADIO_H_
|
||||
#define __CC1101_RADIO_H_
|
||||
|
||||
/**
|
||||
* CC1101 configuration registers
|
||||
*/
|
||||
#define CC1101_IOCFG2 0x00 // GDO2 Output Pin Configuration
|
||||
#define CC1101_IOCFG1 0x01 // GDO1 Output Pin Configuration
|
||||
#define CC1101_IOCFG0 0x02 // GDO0 Output Pin Configuration
|
||||
#define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO Thresholds
|
||||
#define CC1101_SYNC1 0x04 // Sync Word, High Byte
|
||||
#define CC1101_SYNC0 0x05 // Sync Word, Low Byte
|
||||
#define CC1101_PKTLEN 0x06 // Packet Length
|
||||
#define CC1101_PKTCTRL1 0x07 // Packet Automation Control
|
||||
#define CC1101_PKTCTRL0 0x08 // Packet Automation Control
|
||||
#define CC1101_ADDR 0x09 // Device Address
|
||||
#define CC1101_CHANNR 0x0A // Channel Number
|
||||
#define CC1101_FSCTRL1 0x0B // Frequency Synthesizer Control
|
||||
#define CC1101_FSCTRL0 0x0C // Frequency Synthesizer Control
|
||||
#define CC1101_FREQ2 0x0D // Frequency Control Word, High Byte
|
||||
#define CC1101_FREQ1 0x0E // Frequency Control Word, Middle Byte
|
||||
#define CC1101_FREQ0 0x0F // Frequency Control Word, Low Byte
|
||||
#define CC1101_MDMCFG4 0x10 // Modem Configuration
|
||||
#define CC1101_MDMCFG3 0x11 // Modem Configuration
|
||||
#define CC1101_MDMCFG2 0x12 // Modem Configuration
|
||||
#define CC1101_MDMCFG1 0x13 // Modem Configuration
|
||||
#define CC1101_MDMCFG0 0x14 // Modem Configuration
|
||||
#define CC1101_DEVIATN 0x15 // Modem Deviation Setting
|
||||
#define CC1101_MCSM2 0x16 // Main Radio Control State Machine Configuration
|
||||
#define CC1101_MCSM1 0x17 // Main Radio Control State Machine Configuration
|
||||
#define CC1101_MCSM0 0x18 // Main Radio Control State Machine Configuration
|
||||
#define CC1101_FOCCFG 0x19 // Frequency Offset Compensation Configuration
|
||||
#define CC1101_BSCFG 0x1A // Bit Synchronization Configuration
|
||||
#define CC1101_AGCCTRL2 0x1B // AGC Control
|
||||
#define CC1101_AGCCTRL1 0x1C // AGC Control
|
||||
#define CC1101_AGCCTRL0 0x1D // AGC Control
|
||||
#define CC1101_WOREVT1 0x1E // High Byte Event0 Timeout
|
||||
#define CC1101_WOREVT0 0x1F // Low Byte Event0 Timeout
|
||||
#define CC1101_WORCTRL 0x20 // Wake On Radio Control
|
||||
#define CC1101_FREND1 0x21 // Front End RX Configuration
|
||||
#define CC1101_FREND0 0x22 // Front End TX Configuration
|
||||
#define CC1101_FSCAL3 0x23 // Frequency Synthesizer Calibration
|
||||
#define CC1101_FSCAL2 0x24 // Frequency Synthesizer Calibration
|
||||
#define CC1101_FSCAL1 0x25 // Frequency Synthesizer Calibration
|
||||
#define CC1101_FSCAL0 0x26 // Frequency Synthesizer Calibration
|
||||
#define CC1101_RCCTRL1 0x27 // RC Oscillator Configuration
|
||||
#define CC1101_RCCTRL0 0x28 // RC Oscillator Configuration
|
||||
#define CC1101_FSTEST 0x29 // Frequency Synthesizer Calibration Control
|
||||
#define CC1101_PTEST 0x2A // Production Test
|
||||
#define CC1101_AGCTEST 0x2B // AGC Test
|
||||
#define CC1101_TEST2 0x2C // Various Test Settings
|
||||
#define CC1101_TEST1 0x2D // Various Test Settings
|
||||
#define CC1101_TEST0 0x2E // Various Test Settings
|
||||
|
||||
/**
|
||||
* Status registers
|
||||
*/
|
||||
#define CC1101_PARTNUM 0x30 // Chip ID
|
||||
#define CC1101_VERSION 0x31 // Chip ID
|
||||
#define CC1101_FREQEST 0x32 // Frequency Offset Estimate from Demodulator
|
||||
#define CC1101_LQI 0x33 // Demodulator Estimate for Link Quality
|
||||
#define CC1101_RSSI 0x34 // Received Signal Strength Indication
|
||||
#define CC1101_MARCSTATE 0x35 // Main Radio Control State Machine State
|
||||
#define CC1101_WORTIME1 0x36 // High Byte of WOR Time
|
||||
#define CC1101_WORTIME0 0x37 // Low Byte of WOR Time
|
||||
#define CC1101_PKTSTATUS 0x38 // Current GDOx Status and Packet Status
|
||||
#define CC1101_VCO_VC_DAC 0x39 // Current Setting from PLL Calibration Module
|
||||
#define CC1101_TXBYTES 0x3A // Underflow and Number of Bytes
|
||||
#define CC1101_RXBYTES 0x3B // Overflow and Number of Bytes
|
||||
#define CC1101_RCCTRL1_STATUS 0x3C // Last RC Oscillator Calibration Result
|
||||
#define CC1101_RCCTRL0_STATUS 0x3D // Last RC Oscillator Calibration Result
|
||||
|
||||
typedef struct {
|
||||
uint16_t Reg;
|
||||
uint8_t Value;
|
||||
} RfSetting;
|
||||
|
||||
extern spi_device_handle_t gSpiHndl;
|
||||
|
||||
void CC1101_SetConfig(const RfSetting *pConfig);
|
||||
int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi);
|
||||
bool CC1101_Tx(uint8_t *TxData);
|
||||
bool CC1101_Present(void);
|
||||
void CC1101_DumpRegs(void);
|
||||
void CC1101_reset(void);
|
||||
void CC1101_logState(void);
|
||||
void CC1101_setRxState(void);
|
||||
|
||||
#endif // __CC1101_RADIO_H_
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "led.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "proto.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NUM_LEDS 2
|
||||
|
||||
const gpio_num_t led_pins[NUM_LEDS] = {LED1, LED2};
|
||||
TimerHandle_t led_timers[NUM_LEDS] = {0};
|
||||
|
||||
void led_timer_callback(TimerHandle_t xTimer) {
|
||||
int led_index = (int)pvTimerGetTimerID(xTimer);
|
||||
if (led_index >= 0 && led_index < NUM_LEDS) {
|
||||
gpio_set_level(led_pins[led_index], 0);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
led_timers[i] = xTimerCreate("led_timer", pdMS_TO_TICKS(50), pdFALSE, (void *)i, led_timer_callback);
|
||||
}
|
||||
}
|
||||
|
||||
void led_flash(int nr) {
|
||||
gpio_set_level(led_pins[nr], 1);
|
||||
if (nr >= 0 && nr < NUM_LEDS) {
|
||||
xTimerStart(led_timers[nr], 0);
|
||||
}
|
||||
}
|
||||
|
||||
void led_set(int nr, bool state) {
|
||||
gpio_set_level(nr, state);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
void init_led();
|
||||
void led_set(int nr, bool state);
|
||||
void led_flash(int nr);
|
||||
@@ -1,833 +0,0 @@
|
||||
// Ported to ESP32-H2 By ATC1441(ATCnetz.de) for OpenEPaperLink at ~08.2023
|
||||
|
||||
#include "main.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 "led.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "second_uart.h"
|
||||
//#include "soc/lp_uart_reg.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "utils.h"
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "SubGigRadio.h"
|
||||
|
||||
|
||||
static const char *TAG = "MAIN";
|
||||
|
||||
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
||||
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define HW_TYPE 0xC6
|
||||
|
||||
#define MAX_PENDING_MACS 250
|
||||
#define HOUSEKEEPING_INTERVAL 60UL
|
||||
|
||||
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
||||
|
||||
// VERSION GOES HERE!
|
||||
uint16_t version = 0x001d;
|
||||
|
||||
#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 lastTagReturn[8];
|
||||
|
||||
#define NO_SUBGHZ_CHANNEL 255
|
||||
uint8_t curSubGhzChannel;
|
||||
uint8_t curChannel = 25;
|
||||
uint8_t curPower = 10;
|
||||
|
||||
uint8_t curPendingData = 0;
|
||||
uint8_t curNoUpdate = 0;
|
||||
|
||||
bool highspeedSerial = false;
|
||||
|
||||
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>");
|
||||
blockStartTime = getMillis();
|
||||
ESP_LOGI(TAG, "Starting BlkData, %lu ms after request", blockStartTime - nextBlockAttempt );
|
||||
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;
|
||||
}
|
||||
if (isSame(cmdbuffer, "HSPD", 4)) {
|
||||
pr("ACK>");
|
||||
ESP_LOGI(TAG, "HSPD In, switching to 2000000");
|
||||
delay(100);
|
||||
uart_switch_speed(2000000);
|
||||
delay(100);
|
||||
highspeedSerial = true;
|
||||
pr("ACK>");
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
break;
|
||||
case ZBS_RX_WAIT_BLOCKDATA:
|
||||
blockbuffer[blockPosition++] = 0xAA ^ lastchar;
|
||||
if (blockPosition >= 4100) {
|
||||
ESP_LOGI(TAG, "Blockdata fully received in %lu ms, %lu ms after the request", getMillis() - blockStartTime, getMillis() - nextBlockAttempt);
|
||||
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>");
|
||||
} else {
|
||||
pr("NOQ>");
|
||||
}
|
||||
} else {
|
||||
pr("NOK>");
|
||||
}
|
||||
|
||||
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;
|
||||
deleteAllPendingDataForMac((uint8_t *) &pd->targetMac);
|
||||
pr("ACK>");
|
||||
} else {
|
||||
pr("NOK>");
|
||||
}
|
||||
|
||||
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;
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
if(curSubGhzChannel != scp->subghzchannel
|
||||
&& curSubGhzChannel != NO_SUBGHZ_CHANNEL)
|
||||
{
|
||||
curSubGhzChannel = scp->subghzchannel;
|
||||
ESP_LOGI(TAG,"Set SubGhz channel: %d",curSubGhzChannel);
|
||||
SubGig_radioSetChannel(scp->subghzchannel);
|
||||
if(scp->channel == 0) {
|
||||
// Not setting 802.15.4 channel
|
||||
goto SCPchannelFound;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (uint8_t c = 0; c < sizeof(channelList); c++) {
|
||||
if (channelList[c] == scp->channel) goto SCPchannelFound;
|
||||
}
|
||||
goto SCPfailed;
|
||||
SCPchannelFound:
|
||||
pr("ACK>");
|
||||
if (curChannel != scp->channel) {
|
||||
radioSetChannel(scp->channel);
|
||||
curChannel = scp->channel;
|
||||
}
|
||||
curPower = scp->power;
|
||||
radioSetTxPower(scp->power);
|
||||
ESP_LOGI(TAG, "Set channel: %d power: %d", curChannel, curPower);
|
||||
} else {
|
||||
SCPfailed:
|
||||
pr("NOK>");
|
||||
}
|
||||
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", HW_TYPE);
|
||||
pr("VER>%04X", 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", mSelfMac[6], mSelfMac[7]);
|
||||
pr("ZCH>%02X", curChannel);
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
pr("SCH>%03d",curSubGhzChannel);
|
||||
#endif
|
||||
pr("ZPW>%02X", curPower);
|
||||
countSlots();
|
||||
pr("PEN>%02X", curPendingData);
|
||||
pr("NOP>%02X", curNoUpdate);
|
||||
}
|
||||
|
||||
void espNotifyTagReturnData(uint8_t *src, uint8_t len) {
|
||||
struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me
|
||||
struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer;
|
||||
|
||||
if (memcmp((void *) & trd->dataVer, lastTagReturn, 8) == 0) {
|
||||
return;
|
||||
} else {
|
||||
memcpy(lastTagReturn, &trd->dataVer, 8);
|
||||
}
|
||||
|
||||
memcpy(etrd->src, src, 8);
|
||||
etrd->len = len;
|
||||
memcpy(&etrd->returnData, trd, len);
|
||||
addCRC(etrd, len + 10);
|
||||
|
||||
uartTx('T');
|
||||
uartTx('R');
|
||||
uartTx('D');
|
||||
uartTx('>');
|
||||
for (uint8_t c = 0; c < len + 10; c++) {
|
||||
uartTx(((uint8_t *)etrd)[c]);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (highspeedSerial == true) {
|
||||
blockRequestAck->pleaseWaitMs = 140;
|
||||
} else {
|
||||
blockRequestAck->pleaseWaitMs = 550;
|
||||
}
|
||||
} else {
|
||||
// block is already in buffer
|
||||
blockRequestAck->pleaseWaitMs = 30;
|
||||
}
|
||||
} else {
|
||||
blockRequestAck->pleaseWaitMs = 30;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void processTagReturnData(uint8_t *buffer, uint8_t len) {
|
||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer;
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
|
||||
if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) {
|
||||
return;
|
||||
}
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 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);
|
||||
|
||||
espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1));
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
pr("Sending parts:");
|
||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS); c++) {
|
||||
if (c % 10 == 0) pr(" ");
|
||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
||||
pr("X");
|
||||
} else {
|
||||
pr(".");
|
||||
}
|
||||
}
|
||||
pr("\n");
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
if(dstPan == PROTO_PAN_ID_SUBGHZ) {
|
||||
// Don't send BLOCK_MAX_PARTS for subgig, it requests what it
|
||||
// can handle with its limited RAM
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
if(rxframe->srcPan == PROTO_PAN_ID_SUBGHZ) {
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curSubGhzChannel;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
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) {
|
||||
esp_event_loop_create_default();
|
||||
|
||||
init_nvs();
|
||||
init_led();
|
||||
init_second_uart();
|
||||
|
||||
requestedData.blockId = 0xFF;
|
||||
// clear the array with pending information
|
||||
memset(pendingDataArr, 0, sizeof(pendingDataArr));
|
||||
|
||||
radio_init(curChannel);
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
if(SubGig_radio_init(curSubGhzChannel)) {
|
||||
// Ether we don't have a cc1101 or it's not working
|
||||
curSubGhzChannel = NO_SUBGHZ_CHANNEL;
|
||||
ESP_LOGI(TAG,"CC1101 NOT detected.");
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(TAG,"CC1101 detected.");
|
||||
}
|
||||
#endif
|
||||
radioSetTxPower(10);
|
||||
|
||||
pr("RES>");
|
||||
pr("RDY>");
|
||||
ESP_LOGI(TAG, "H2 ready!");
|
||||
|
||||
housekeepingTimer = getMillis();
|
||||
while (1) {
|
||||
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
|
||||
int8_t ret = commsRxUnencrypted(radiorxbuffer);
|
||||
if (ret > 1) {
|
||||
led_flash(0);
|
||||
// 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
|
||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0,
|
||||
sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2);
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
} 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;
|
||||
case PKT_TAG_RETURN_DATA:
|
||||
processTagReturnData(radiorxbuffer, ret);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer));
|
||||
break;
|
||||
}
|
||||
} else if (blockStartTimer == 0) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
uint8_t curr_char;
|
||||
while (getRxCharSecond(&curr_char)) processSerial(curr_char);
|
||||
|
||||
if (blockStartTimer) {
|
||||
if (getMillis() > blockStartTimer) {
|
||||
sendBlockData();
|
||||
blockStartTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(&lastTagReturn, 0, 8);
|
||||
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 +0,0 @@
|
||||
#pragma once
|
||||
@@ -1,194 +0,0 @@
|
||||
#ifndef _PROTO_H_
|
||||
#define _PROTO_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#define LED1 22
|
||||
#define LED2 25
|
||||
|
||||
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
||||
#define PROTO_PAN_ID_SUBGHZ (0x1337) // 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_TAG_RETURN_DATA 0xE1
|
||||
#define PKT_TAG_RETURN_DATA_ACK 0xE2
|
||||
#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)));
|
||||
|
||||
#define TAG_RETURN_DATA_SIZE 90
|
||||
|
||||
struct tagReturnData {
|
||||
uint8_t checksum;
|
||||
uint8_t partId;
|
||||
uint64_t dataVer;
|
||||
uint8_t dataType;
|
||||
uint8_t data[TAG_RETURN_DATA_SIZE];
|
||||
} __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;
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
uint8_t subghzchannel;
|
||||
#endif
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
struct espTagReturnData {
|
||||
uint8_t checksum;
|
||||
uint8_t src[8];
|
||||
uint8_t len;
|
||||
struct tagReturnData returnData;
|
||||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
#endif
|
||||
@@ -1,150 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include "radio.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 "led.h"
|
||||
#include "main.h"
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
// if you get an error about soc/lp_uart_reg.h not being found,
|
||||
// you didn't choose the right build target. :-)
|
||||
//#include "soc/lp_uart_reg.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "utils.h"
|
||||
#include <esp_mac.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "SubGigRadio.h"
|
||||
|
||||
|
||||
static const char *TAG = "RADIO";
|
||||
|
||||
uint8_t mSelfMac[8];
|
||||
volatile uint8_t isInTransmit = 0;
|
||||
QueueHandle_t packet_buffer = 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_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
|
||||
esp_ieee802154_receive_sfd_done();
|
||||
}
|
||||
|
||||
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]);
|
||||
esp_ieee802154_receive_sfd_done();
|
||||
}
|
||||
static bool zigbee_is_enabled = false;
|
||||
void radio_init(uint8_t ch) {
|
||||
if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130);
|
||||
|
||||
// this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works
|
||||
if(zigbee_is_enabled)
|
||||
{
|
||||
zigbee_is_enabled = false;
|
||||
esp_ieee802154_disable();
|
||||
}
|
||||
zigbee_is_enabled = true;
|
||||
esp_ieee802154_enable();
|
||||
esp_ieee802154_set_channel(ch);
|
||||
// esp_ieee802154_set_txpower(int8_t power);
|
||||
esp_ieee802154_set_panid(PROTO_PAN_ID);
|
||||
esp_ieee802154_set_promiscuous(false);
|
||||
esp_ieee802154_set_coordinator(false);
|
||||
esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE);
|
||||
|
||||
// esp_ieee802154_set_extended_address needs the MAC in reversed byte order
|
||||
esp_read_mac(mSelfMac, ESP_MAC_IEEE802154);
|
||||
uint8_t eui64_rev[8] = {0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
eui64_rev[7 - i] = mSelfMac[i];
|
||||
}
|
||||
esp_ieee802154_set_extended_address(eui64_rev);
|
||||
esp_ieee802154_get_extended_address(mSelfMac);
|
||||
|
||||
esp_ieee802154_set_short_address(0xFFFE);
|
||||
esp_ieee802154_set_rx_when_idle(true);
|
||||
esp_ieee802154_receive();
|
||||
|
||||
led_flash(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(0);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(0);
|
||||
|
||||
ESP_LOGI(TAG, "Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x",
|
||||
esp_ieee802154_get_panid(), esp_ieee802154_get_channel(),
|
||||
mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3],
|
||||
mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7],
|
||||
esp_ieee802154_get_short_address());
|
||||
}
|
||||
|
||||
// uint32_t lastZbTx = 0;
|
||||
bool radioTx(uint8_t *packet) {
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
// The subghz driver uses DMA
|
||||
static DMA_ATTR uint8_t txPKT[130];
|
||||
#else
|
||||
static uint8_t txPKT[130];
|
||||
#endif
|
||||
led_flash(1);
|
||||
// while (getMillis() - lastZbTx < 6) {
|
||||
// }
|
||||
// lastZbTx = getMillis();
|
||||
memcpy(txPKT, packet, packet[0]);
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (packet + 1);
|
||||
|
||||
if(txHeader->pan == PROTO_PAN_ID_SUBGHZ) {
|
||||
return SubGig_radioTx(packet);
|
||||
}
|
||||
#endif
|
||||
while (isInTransmit) {
|
||||
}
|
||||
isInTransmit = 1;
|
||||
esp_ieee802154_transmit(txPKT, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void radioSetChannel(uint8_t ch) {
|
||||
radio_init(ch);
|
||||
}
|
||||
|
||||
void radioSetTxPower(uint8_t power) {}
|
||||
|
||||
int8_t commsRxUnencrypted(uint8_t *data) {
|
||||
static uint8_t inner_rxPKT_out[130];
|
||||
if (xQueueReceive(packet_buffer, (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;
|
||||
}
|
||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
||||
if(gSubGigData.Enabled) {
|
||||
int8_t Ret = SubGig_commsRxUnencrypted(data);
|
||||
if(Ret > 0) {
|
||||
return Ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define RAW_PKT_PADDING 2
|
||||
extern uint8_t mSelfMac[8];
|
||||
|
||||
void radio_init(uint8_t ch);
|
||||
bool radioTx(uint8_t *packet);
|
||||
void radioSetChannel(uint8_t ch);
|
||||
void radioSetTxPower(uint8_t power);
|
||||
int8_t commsRxUnencrypted(uint8_t *data);
|
||||
|
||||
#ifdef SUBGIG_SUPPORT
|
||||
void SubGig_radio_init(uint8_t ch);
|
||||
bool SubGig_radioTx(uint8_t *packet);
|
||||
void SubGig_radioSetChannel(uint8_t ch);
|
||||
void SubGig_radioSetTxPower(uint8_t power);
|
||||
int8_t SubGig_commsRxUnencrypted(uint8_t *data);
|
||||
#endif
|
||||
@@ -1,116 +0,0 @@
|
||||
#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"
|
||||
#include "second_uart.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, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL);
|
||||
}
|
||||
|
||||
void uart_switch_speed(int baudrate) {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = baudrate,
|
||||
.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_param_config(1, &uart_config));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void uart_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char buffer[128];
|
||||
int len = vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
if (len > 0) {
|
||||
uart_write_bytes(1, buffer, len);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void init_second_uart();
|
||||
void uart_switch_speed(int baudrate);
|
||||
|
||||
void uartTx(uint8_t data);
|
||||
bool getRxCharSecond(uint8_t *newChar);
|
||||
|
||||
void uart_printf(const char *format, ...);
|
||||
|
||||
#define pr uart_printf
|
||||
|
||||
|
||||
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 24
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 23
|
||||
@@ -1,36 +0,0 @@
|
||||
#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 );
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void delay(int ms);
|
||||
uint32_t getMillis();
|
||||
void init_nvs();
|
||||
@@ -1,8 +1,16 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32h2"
|
||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_OEPL_HARDWARE_PROFILE_LILYGO=y
|
||||
CONFIG_OEPL_SUBGIG_SUPPORT=y
|
||||
CONFIG_MISO_GPIO=25
|
||||
CONFIG_SCK_GPIO=3
|
||||
CONFIG_MOSI_GPIO=11
|
||||
CONFIG_CSN_GPIO=8
|
||||
CONFIG_GDO0_GPIO=2
|
||||
CONFIG_GDO2_GPIO=22
|
||||
|
||||
@@ -10,54 +10,6 @@
|
||||
"/www/painter.js",
|
||||
"/www/setup.html",
|
||||
"/www/setup.js",
|
||||
"/www/upload-demo.html",
|
||||
"/fonts/weathericons30.vlw",
|
||||
"/fonts/weathericons70.vlw",
|
||||
"/fonts/weathericons78.vlw",
|
||||
"/fonts/calibrib120.vlw",
|
||||
"/fonts/calibrib150.vlw",
|
||||
"/fonts/calibrib50.vlw",
|
||||
"/fonts/calibrib60.vlw",
|
||||
"/fonts/BellCent10.vlw",
|
||||
"/tagtypes/00.json",
|
||||
"/tagtypes/01.json",
|
||||
"/tagtypes/02.json",
|
||||
"/tagtypes/05.json",
|
||||
"/tagtypes/11.json",
|
||||
"/tagtypes/21.json",
|
||||
"/tagtypes/22.json",
|
||||
"/tagtypes/26.json",
|
||||
"/tagtypes/27.json",
|
||||
"/tagtypes/2E.json",
|
||||
"/tagtypes/2F.json",
|
||||
"/tagtypes/30.json",
|
||||
"/tagtypes/31.json",
|
||||
"/tagtypes/32.json",
|
||||
"/tagtypes/33.json",
|
||||
"/tagtypes/34.json",
|
||||
"/tagtypes/35.json",
|
||||
"/tagtypes/36.json",
|
||||
"/tagtypes/40.json",
|
||||
"/tagtypes/41.json",
|
||||
"/tagtypes/42.json",
|
||||
"/tagtypes/43.json",
|
||||
"/tagtypes/55.json",
|
||||
"/tagtypes/60.json",
|
||||
"/tagtypes/61.json",
|
||||
"/tagtypes/62.json",
|
||||
"/tagtypes/80.json",
|
||||
"/tagtypes/81.json",
|
||||
"/tagtypes/82.json",
|
||||
"/tagtypes/83.json",
|
||||
"/tagtypes/B0.json",
|
||||
"/tagtypes/B1.json",
|
||||
"/tagtypes/B2.json",
|
||||
"/tagtypes/B3.json",
|
||||
"/tagtypes/B5.json",
|
||||
"/tagtypes/BD.json",
|
||||
"/tagtypes/BE.json",
|
||||
"/tagtypes/E0.json",
|
||||
"/tagtypes/E1.json",
|
||||
"/tagtypes/F0.json"
|
||||
"/www/upload-demo.html"
|
||||
]
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/www/g5decoder.js.gz
Normal file
BIN
ESP32_AP-Flasher/data/www/g5decoder.js.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,5 +6,6 @@ uint8_t gicToOEPLtype(uint8_t gicType);
|
||||
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice);
|
||||
bool BLE_is_image_pending(uint8_t address[8]);
|
||||
uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len);
|
||||
uint32_t get_ATC_BLE_OEPL_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len, uint8_t* dataType, uint8_t* dataTypeArgument, uint16_t* nextCheckIn);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@ struct imgParam {
|
||||
uint8_t preloadlut;
|
||||
|
||||
uint8_t zlib;
|
||||
uint8_t g5;
|
||||
};
|
||||
|
||||
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams);
|
||||
|
||||
@@ -93,6 +93,7 @@ struct HwType {
|
||||
uint8_t bpp;
|
||||
uint8_t shortlut;
|
||||
uint8_t zlib;
|
||||
uint8_t g5;
|
||||
uint16_t highlightColor;
|
||||
std::vector<Color> colortable;
|
||||
};
|
||||
|
||||
@@ -307,6 +307,7 @@ build_flags =
|
||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||
-D HAS_SUBGHZ
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||
board_build.flash_mode=qio
|
||||
@@ -413,6 +414,57 @@ board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 16777216
|
||||
board_upload.maximum_ram_size = 327680
|
||||
board_upload.flash_size = 16MB
|
||||
; ----------------------------------------------------------------------------------------
|
||||
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||
; ----------------------------------------------------------------------------------------
|
||||
[env:ESP32_S3_SIMPLE_AP]
|
||||
board = esp32-s3-devkitc-1
|
||||
board_build.partitions = large_spiffs_16MB.csv
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D HAS_BLE_WRITER
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT
|
||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||
-D POWER_NO_SOFT_POWER
|
||||
-D BOARD_HAS_PSRAM
|
||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
-D FLASHER_AP_SS=-1
|
||||
-D FLASHER_AP_CLK=-1
|
||||
-D FLASHER_AP_MOSI=-1
|
||||
-D FLASHER_AP_MISO=-1
|
||||
-D FLASHER_AP_RESET=41
|
||||
-D FLASHER_AP_POWER={-1}
|
||||
-D FLASHER_AP_TEST=-1
|
||||
-D FLASHER_AP_TXD=2
|
||||
-D FLASHER_AP_RXD=1
|
||||
-D FLASHER_DEBUG_TXD=12
|
||||
-D FLASHER_DEBUG_RXD=11
|
||||
-D FLASHER_DEBUG_PROG=40
|
||||
-D FLASHER_LED=38
|
||||
-D HAS_RGB_LED
|
||||
-D FLASHER_RGB_LED=48
|
||||
-D MD5_ENABLED=1
|
||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||
-D C6_OTA_FLASHING
|
||||
-D HAS_SUBGHZ
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||
board_build.flash_mode=qio
|
||||
board_build.arduino.memory_type = qio_opi
|
||||
board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 16777216
|
||||
board_upload.maximum_ram_size = 327680
|
||||
board_upload.flash_size = 16MB
|
||||
|
||||
; ----------------------------------------------------------------------------------------
|
||||
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||
|
||||
@@ -64,6 +64,16 @@ uint8_t gicToOEPLtype(uint8_t gicType) {
|
||||
}
|
||||
}
|
||||
|
||||
struct BleAdvDataStruct {
|
||||
uint16_t manu_id; // 0x1337 for us
|
||||
uint8_t version;
|
||||
uint16_t hw_type;
|
||||
uint16_t fw_version;
|
||||
uint16_t capabilities;
|
||||
uint16_t battery_mv;
|
||||
uint8_t counter;
|
||||
} __packed;
|
||||
|
||||
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
||||
Serial.print("BLE Advertised Device found: ");
|
||||
Serial.println(advertisedDevice.toString().c_str());
|
||||
@@ -103,10 +113,46 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
||||
theAdvData.src[7] = manuData[6];
|
||||
theAdvData.adr.batteryMv = manuData[3] * 100;
|
||||
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
|
||||
theAdvData.adr.lastPacketLQI = advertisedDevice.getRSSI();
|
||||
theAdvData.adr.hwType = gicToOEPLtype(manuData[2]);
|
||||
theAdvData.adr.tagSoftwareVersion = manuData[4] << 8 | manuData[5];
|
||||
theAdvData.adr.capabilities = 0x00;
|
||||
|
||||
processDataReq(&theAdvData, true);
|
||||
return true;
|
||||
} else if (manuDatalen >= sizeof(BleAdvDataStruct) && manuData[0] == 0x37 && manuData[1] == 0x13) { // Lets check for a Gicisky E-Paper display
|
||||
Serial.printf("ATC BLE OEPL Detected\r\n");
|
||||
struct espAvailDataReq theAdvData;
|
||||
struct BleAdvDataStruct inAdvData;
|
||||
|
||||
memset((uint8_t*)&theAdvData, 0x00, sizeof(espAvailDataReq));
|
||||
memcpy(&inAdvData, manuData, sizeof(BleAdvDataStruct));
|
||||
/*Serial.printf("manu_id %04X\r\n", inAdvData.manu_id);
|
||||
Serial.printf("version %04X\r\n", inAdvData.version);
|
||||
Serial.printf("hw_type %04X\r\n", inAdvData.hw_type);
|
||||
Serial.printf("fw_version %04X\r\n", inAdvData.fw_version);
|
||||
Serial.printf("capabilities %04X\r\n", inAdvData.capabilities);
|
||||
Serial.printf("battery_mv %u\r\n", inAdvData.battery_mv);
|
||||
Serial.printf("counter %u\r\n", inAdvData.counter);*/
|
||||
if (inAdvData.version != 1) {
|
||||
printf("Version currently not supported!\r\n");
|
||||
return false;
|
||||
}
|
||||
uint8_t macReversed[6];
|
||||
memcpy(&macReversed, (uint8_t*)advertisedDevice.getAddress().getNative(), 6);
|
||||
theAdvData.src[0] = macReversed[5];
|
||||
theAdvData.src[1] = macReversed[4];
|
||||
theAdvData.src[2] = macReversed[3];
|
||||
theAdvData.src[3] = macReversed[2];
|
||||
theAdvData.src[4] = macReversed[1];
|
||||
theAdvData.src[5] = macReversed[0];
|
||||
theAdvData.src[6] = manuData[0]; // We use this do find out what type of display we got for compression^^
|
||||
theAdvData.src[7] = manuData[1];
|
||||
theAdvData.adr.batteryMv = inAdvData.battery_mv;
|
||||
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
|
||||
theAdvData.adr.hwType = inAdvData.hw_type & 0xff;
|
||||
theAdvData.adr.tagSoftwareVersion = inAdvData.fw_version;
|
||||
theAdvData.adr.capabilities = inAdvData.capabilities & 0xff;
|
||||
processDataReq(&theAdvData, true);
|
||||
return true;
|
||||
}
|
||||
@@ -133,7 +179,6 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
||||
theAdvData.adr.hwType = ATC_MI_THERMOMETER;
|
||||
theAdvData.adr.tagSoftwareVersion = 0x00;
|
||||
theAdvData.adr.capabilities = 0x00;
|
||||
|
||||
processDataReq(&theAdvData, true);
|
||||
Serial.printf("We got an ATC_MiThermometer via BLE\r\n");
|
||||
return true;
|
||||
@@ -150,6 +195,14 @@ bool BLE_is_image_pending(uint8_t address[8]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* taginfo = tagDB.at(c);
|
||||
if (taginfo->pendingCount > 0 && taginfo->version == 0 && (taginfo->mac[7] == 0x13) && (taginfo->mac[6] == 0x37)) {
|
||||
memcpy(address, taginfo->mac, 8);
|
||||
Serial.printf("ATC BLE OEPL data Waiting\r\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -374,4 +427,37 @@ uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len) {
|
||||
return len_compressed;
|
||||
}
|
||||
|
||||
uint32_t get_ATC_BLE_OEPL_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len, uint8_t* dataType, uint8_t* dataTypeArgument, uint16_t* nextCheckIn) {
|
||||
uint32_t t = millis();
|
||||
PendingItem* queueItem = getQueueItem(address, 0);
|
||||
if (queueItem == nullptr) {
|
||||
prepareCancelPending(address);
|
||||
Serial.printf("blockrequest: couldn't find taginfo %02X%02X%02X%02X%02X%02X%02X%02X\r\n", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
|
||||
return 0;
|
||||
}
|
||||
if (queueItem->data == nullptr) {
|
||||
fs::File file = contentFS->open(queueItem->filename);
|
||||
if (!file) {
|
||||
Serial.print("No current file. " + String(queueItem->filename) + " Canceling request\r\n");
|
||||
prepareCancelPending(address);
|
||||
return 0;
|
||||
}
|
||||
queueItem->data = getDataForFile(file);
|
||||
Serial.println("Reading file " + String(queueItem->filename) + " in " + String(millis() - t) + "ms");
|
||||
file.close();
|
||||
}
|
||||
if (queueItem->len > max_len) {
|
||||
Serial.print("The upload is too big better cencel it\r\n");
|
||||
prepareCancelPending(address);
|
||||
return 0;
|
||||
}
|
||||
*dataType = queueItem->pendingdata.availdatainfo.dataType;
|
||||
*dataTypeArgument = queueItem->pendingdata.availdatainfo.dataTypeArgument;
|
||||
*nextCheckIn = queueItem->pendingdata.availdatainfo.nextCheckIn;
|
||||
uint32_t len_compressed = queueItem->len;
|
||||
memcpy(buffer, queueItem->data, queueItem->len);
|
||||
Serial.print("Data is prepared Len: " + String(queueItem->len) + "\r\n");
|
||||
return queueItem->len;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifdef HAS_BLE_WRITER
|
||||
#include <Arduino.h>
|
||||
#include <MD5Builder.h>
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "ble_filter.h"
|
||||
@@ -7,12 +8,13 @@
|
||||
|
||||
#define INTERVAL_BLE_SCANNING_SECONDS 60
|
||||
#define INTERVAL_HANDLE_PENDING_SECONDS 10
|
||||
#define BUFFER_MAX_SIZE_COMPRESSING 100000
|
||||
#define BUFFER_MAX_SIZE_COMPRESSING 135000
|
||||
|
||||
#define BLE_MAIN_STATE_IDLE 0
|
||||
#define BLE_MAIN_STATE_PREPARE 1
|
||||
#define BLE_MAIN_STATE_CONNECT 2
|
||||
#define BLE_MAIN_STATE_UPLOAD 3
|
||||
#define BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD 4
|
||||
|
||||
int ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
uint32_t last_ble_scan = 0;
|
||||
@@ -23,9 +25,25 @@ uint32_t last_ble_scan = 0;
|
||||
#define BLE_UPLOAD_STATE_UPLOAD 5
|
||||
int BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||
|
||||
#define BLE_CMD_ACK_CMD 99
|
||||
#define BLE_CMD_AVAILDATA 100
|
||||
#define BLE_CMD_BLK_DATA 101
|
||||
#define BLE_CMD_ERR_BLKPRT 196
|
||||
#define BLE_CMD_ACK_BLKPRT 197
|
||||
#define BLE_CMD_REQ 198
|
||||
#define BLE_CMD_ACK 199
|
||||
#define BLE_CMD_ACK_IS_SHOWN 200
|
||||
#define BLE_CMD_ACK_FW_UPDATED 201
|
||||
|
||||
struct AvailDataInfo BLEavaildatainfo = {0};
|
||||
struct blockRequest BLEblkRequst = {0};
|
||||
|
||||
bool BLE_connected = false;
|
||||
bool BLE_new_notify = false;
|
||||
|
||||
static BLEUUID ATC_BLE_OEPL_ServiceUUID((uint16_t)0x1337);
|
||||
static BLEUUID ATC_BLE_OEPL_CtrlUUID((uint16_t)0x1337);
|
||||
|
||||
static BLEUUID gicServiceUUID((uint16_t)0xfef0);
|
||||
static BLEUUID gicCtrlUUID((uint16_t)0xfef1);
|
||||
static BLEUUID gicImgUUID((uint16_t)0xfef2);
|
||||
@@ -33,20 +51,21 @@ static BLEUUID gicImgUUID((uint16_t)0xfef2);
|
||||
BLERemoteCharacteristic* ctrlChar;
|
||||
BLERemoteCharacteristic* imgChar;
|
||||
BLEAdvertisedDevice* myDevice;
|
||||
|
||||
BLEClient* pClient;
|
||||
|
||||
uint8_t BLE_notify_buffer[255] = {0};
|
||||
uint8_t BLE_notify_buffer[256] = {0};
|
||||
|
||||
uint32_t curr_part = 0;
|
||||
uint8_t BLE_buff[255];
|
||||
uint32_t BLE_err_counter = 0;
|
||||
uint32_t BLE_curr_part = 0;
|
||||
uint32_t BLE_max_block_parts = 0;
|
||||
uint8_t BLE_mini_buff[256];
|
||||
|
||||
uint32_t BLE_last_notify = 0;
|
||||
uint32_t BLE_last_pending_check = 0;
|
||||
uint8_t BLE_curr_address[8] = {0};
|
||||
|
||||
uint32_t compressed_len = 0;
|
||||
uint8_t* buffer;
|
||||
uint32_t BLE_compressed_len = 0;
|
||||
uint8_t* BLE_image_buffer;
|
||||
|
||||
static void notifyCallback(
|
||||
BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||
@@ -81,7 +100,13 @@ class MyClientCallback : public BLEClientCallbacks {
|
||||
}
|
||||
};
|
||||
|
||||
bool BLE_connect(uint8_t addr[8]) {
|
||||
enum BLE_CONNECTION_TYPE {
|
||||
BLE_TYPE_GICISKY = 0,
|
||||
BLE_TYPE_ATC_BLE_OEPL
|
||||
};
|
||||
|
||||
bool BLE_connect(uint8_t addr[8], BLE_CONNECTION_TYPE conn_type) {
|
||||
BLE_err_counter = 0;
|
||||
uint8_t temp_Address[] = {addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]};
|
||||
Serial.printf("BLE Connecting to: %02X:%02X:%02X:%02X:%02X:%02X\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
|
||||
pClient = BLEDevice::createClient();
|
||||
@@ -92,25 +117,27 @@ bool BLE_connect(uint8_t addr[8]) {
|
||||
return false;
|
||||
}
|
||||
uint32_t timeStart = millis();
|
||||
while (millis() - timeStart <= 5000) {// We wait for a few seconds as otherwise the connection might not be ready!
|
||||
while (millis() - timeStart <= 5000) { // We wait for a few seconds as otherwise the connection might not be ready!
|
||||
delay(100);
|
||||
}
|
||||
if (!BLE_connected)
|
||||
return false;
|
||||
Serial.printf("BLE starting to get service\r\n");
|
||||
BLERemoteService* pRemoteService = pClient->getService(gicServiceUUID);
|
||||
BLERemoteService* pRemoteService = pClient->getService((conn_type == BLE_TYPE_GICISKY) ? gicServiceUUID : ATC_BLE_OEPL_ServiceUUID);
|
||||
if (pRemoteService == nullptr) {
|
||||
Serial.printf("BLE Service failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
|
||||
if (imgChar == nullptr) {
|
||||
Serial.printf("BLE IMG Char failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
if (conn_type == BLE_TYPE_GICISKY) {
|
||||
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
|
||||
if (imgChar == nullptr) {
|
||||
Serial.printf("BLE IMG Char failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ctrlChar = pRemoteService->getCharacteristic(gicCtrlUUID);
|
||||
ctrlChar = pRemoteService->getCharacteristic((conn_type == BLE_TYPE_GICISKY) ? gicCtrlUUID : ATC_BLE_OEPL_CtrlUUID);
|
||||
if (ctrlChar == nullptr) {
|
||||
Serial.printf("BLE ctrl Char failed\r\n");
|
||||
pClient->disconnect();
|
||||
@@ -147,6 +174,49 @@ void BLE_startScan(uint32_t timeout) {
|
||||
pBLEScan->start(timeout, false);
|
||||
}
|
||||
|
||||
#define BLOCK_DATA_SIZE_BLE 4096
|
||||
#define BLOCK_PART_DATA_SIZE_BLE 230
|
||||
uint8_t tempBlockBuffer[BLOCK_DATA_SIZE_BLE + 4];
|
||||
uint8_t tempPacketBuffer[2 + 3 + BLOCK_PART_DATA_SIZE_BLE];
|
||||
void ATC_BLE_OEPL_PrepareBlk(uint8_t indexBlockId) {
|
||||
if (BLE_image_buffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
uint32_t bufferPosition = (BLOCK_DATA_SIZE_BLE * indexBlockId);
|
||||
uint32_t lenNow = BLOCK_DATA_SIZE_BLE;
|
||||
uint16_t crcCalc = 0;
|
||||
if ((BLE_compressed_len - bufferPosition) < BLOCK_DATA_SIZE_BLE)
|
||||
lenNow = (BLE_compressed_len - bufferPosition);
|
||||
tempBlockBuffer[0] = lenNow & 0xff;
|
||||
tempBlockBuffer[1] = (lenNow >> 8) & 0xff;
|
||||
for (uint16_t c = 0; c < lenNow; c++) {
|
||||
tempBlockBuffer[4 + c] = BLE_image_buffer[c + bufferPosition];
|
||||
crcCalc += tempBlockBuffer[4 + c];
|
||||
}
|
||||
tempBlockBuffer[2] = crcCalc & 0xff;
|
||||
tempBlockBuffer[3] = (crcCalc >> 8) & 0xff;
|
||||
BLE_max_block_parts = (4 + lenNow) / BLOCK_PART_DATA_SIZE_BLE;
|
||||
if ((4 + lenNow) % BLOCK_PART_DATA_SIZE_BLE)
|
||||
BLE_max_block_parts++;
|
||||
Serial.println("Preparing block: " + String(indexBlockId) + " BuffPos: " + String(bufferPosition) + " LenNow: " + String(lenNow) + " MaxBLEparts: " + String(BLE_max_block_parts));
|
||||
BLE_curr_part = 0;
|
||||
}
|
||||
|
||||
void ATC_BLE_OEPL_SendPart(uint8_t indexBlockId, uint8_t indexPkt) {
|
||||
uint8_t crcCalc = indexBlockId + indexPkt;
|
||||
for (uint16_t c = 0; c < BLOCK_PART_DATA_SIZE_BLE; c++) {
|
||||
tempPacketBuffer[5 + c] = tempBlockBuffer[c + (BLOCK_PART_DATA_SIZE_BLE * indexPkt)];
|
||||
crcCalc += tempPacketBuffer[5 + c];
|
||||
}
|
||||
tempPacketBuffer[0] = 0x00;
|
||||
tempPacketBuffer[1] = 0x65;
|
||||
tempPacketBuffer[2] = crcCalc;
|
||||
tempPacketBuffer[3] = indexBlockId;
|
||||
tempPacketBuffer[4] = indexPkt;
|
||||
Serial.println("BLE Sending packet Len " + String(sizeof(tempPacketBuffer)));
|
||||
ctrlChar->writeValue(tempPacketBuffer, sizeof(tempPacketBuffer), true);
|
||||
}
|
||||
|
||||
void BLETask(void* parameter) {
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
Serial.println("BLE task started");
|
||||
@@ -162,25 +232,79 @@ void BLETask(void* parameter) {
|
||||
}
|
||||
if (millis() - BLE_last_pending_check >= (INTERVAL_HANDLE_PENDING_SECONDS * 1000)) {
|
||||
if (BLE_is_image_pending(BLE_curr_address)) {
|
||||
delay(4000); // We better wait here, since the pending image needs to be created first
|
||||
Serial.println("BLE Image is pending");
|
||||
// Here we create the compressed buffer
|
||||
buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
||||
if (buffer == nullptr) {
|
||||
Serial.println("BLE Could not create buffer!");
|
||||
compressed_len = 0;
|
||||
} else {
|
||||
compressed_len = compress_image(BLE_curr_address, buffer, BUFFER_MAX_SIZE_COMPRESSING);
|
||||
Serial.printf("BLE Compressed Length: %i\r\n", compressed_len);
|
||||
// then we connect to BLE to send the compressed data
|
||||
if (compressed_len && BLE_connect(BLE_curr_address)) {
|
||||
curr_part = 0;
|
||||
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
||||
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||
ble_main_state = BLE_MAIN_STATE_UPLOAD;
|
||||
BLE_new_notify = true; // trigger the upload here
|
||||
Serial.println("BLE Image is pending but we wait a bit");
|
||||
delay(5000); // We better wait here, since the pending image needs to be created first
|
||||
if (BLE_curr_address[7] == 0x13 && BLE_curr_address[6] == 0x37) { // This is an ATC BLE OEPL display
|
||||
// Here we create the compressed buffer
|
||||
BLE_image_buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
||||
if (BLE_image_buffer == nullptr) {
|
||||
Serial.println("BLE Could not create buffer!");
|
||||
BLE_compressed_len = 0;
|
||||
} else {
|
||||
free(buffer);
|
||||
uint8_t dataType = 0x00;
|
||||
uint8_t dataTypeArgument = 0x00;
|
||||
uint16_t nextCheckin = 0x00;
|
||||
BLE_compressed_len = get_ATC_BLE_OEPL_image(BLE_curr_address, BLE_image_buffer, BUFFER_MAX_SIZE_COMPRESSING, &dataType, &dataTypeArgument, &nextCheckin);
|
||||
Serial.printf("BLE data Length: %i\r\n", BLE_compressed_len);
|
||||
// then we connect to BLE to send the compressed data
|
||||
if (BLE_compressed_len && BLE_connect(BLE_curr_address, BLE_TYPE_ATC_BLE_OEPL)) {
|
||||
BLE_err_counter = 0;
|
||||
BLE_curr_part = 0;
|
||||
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
||||
|
||||
uint8_t md5bytes[16];
|
||||
MD5Builder md5;
|
||||
md5.begin();
|
||||
md5.add(BLE_image_buffer, BLE_compressed_len);
|
||||
md5.calculate();
|
||||
md5.getBytes(md5bytes);
|
||||
|
||||
BLEavaildatainfo.dataType = dataType;
|
||||
BLEavaildatainfo.dataVer = *((uint64_t*)md5bytes);
|
||||
BLEavaildatainfo.dataSize = BLE_compressed_len;
|
||||
BLEavaildatainfo.dataTypeArgument = dataTypeArgument;
|
||||
BLEavaildatainfo.nextCheckIn = nextCheckin;
|
||||
BLEavaildatainfo.checksum = 0;
|
||||
for (uint16_t c = 1; c < sizeof(struct AvailDataInfo); c++) {
|
||||
BLEavaildatainfo.checksum += (uint8_t)((uint8_t*)&BLEavaildatainfo)[c];
|
||||
}
|
||||
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||
ble_main_state = BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD;
|
||||
BLE_new_notify = true; // trigger the upload here
|
||||
} else {
|
||||
free(BLE_image_buffer);
|
||||
if (BLE_err_counter++ >= 5) { // 5 Retries for a BLE Connection
|
||||
struct espXferComplete reportStruct;
|
||||
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||
processXferComplete(&reportStruct, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // This is a Gicisky display
|
||||
// Here we create the compressed buffer
|
||||
BLE_image_buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
||||
if (BLE_image_buffer == nullptr) {
|
||||
Serial.println("BLE Could not create buffer!");
|
||||
BLE_compressed_len = 0;
|
||||
} else {
|
||||
BLE_compressed_len = compress_image(BLE_curr_address, BLE_image_buffer, BUFFER_MAX_SIZE_COMPRESSING);
|
||||
Serial.printf("BLE Compressed Length: %i\r\n", BLE_compressed_len);
|
||||
// then we connect to BLE to send the compressed data
|
||||
if (BLE_compressed_len && BLE_connect(BLE_curr_address, BLE_TYPE_GICISKY)) {
|
||||
BLE_err_counter = 0;
|
||||
BLE_curr_part = 0;
|
||||
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
||||
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||
ble_main_state = BLE_MAIN_STATE_UPLOAD;
|
||||
BLE_new_notify = true; // trigger the upload here
|
||||
} else {
|
||||
free(BLE_image_buffer);
|
||||
if (BLE_err_counter++ >= 5) { // 5 Retries for a BLE Connection
|
||||
struct espXferComplete reportStruct;
|
||||
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||
processXferComplete(&reportStruct, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BLE_last_pending_check = millis();
|
||||
@@ -196,25 +320,25 @@ void BLETask(void* parameter) {
|
||||
switch (BLE_upload_state) {
|
||||
default:
|
||||
case BLE_UPLOAD_STATE_INIT:
|
||||
BLE_buff[0] = 1;
|
||||
ctrlChar->writeValue(BLE_buff, 1);
|
||||
BLE_mini_buff[0] = 1;
|
||||
ctrlChar->writeValue(BLE_mini_buff, 1);
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_SIZE:
|
||||
BLE_buff[0] = 0x02;
|
||||
BLE_buff[1] = compressed_len & 0xff;
|
||||
BLE_buff[2] = (compressed_len >> 8) & 0xff;
|
||||
BLE_buff[3] = (compressed_len >> 16) & 0xff;
|
||||
BLE_buff[4] = (compressed_len >> 24) & 0xff;
|
||||
BLE_buff[5] = 0x00;
|
||||
ctrlChar->writeValue(BLE_buff, 6);
|
||||
BLE_mini_buff[0] = 0x02;
|
||||
BLE_mini_buff[1] = BLE_compressed_len & 0xff;
|
||||
BLE_mini_buff[2] = (BLE_compressed_len >> 8) & 0xff;
|
||||
BLE_mini_buff[3] = (BLE_compressed_len >> 16) & 0xff;
|
||||
BLE_mini_buff[4] = (BLE_compressed_len >> 24) & 0xff;
|
||||
BLE_mini_buff[5] = 0x00;
|
||||
ctrlChar->writeValue(BLE_mini_buff, 6);
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_START:
|
||||
BLE_buff[0] = 0x03;
|
||||
ctrlChar->writeValue(BLE_buff, 1);
|
||||
BLE_mini_buff[0] = 0x03;
|
||||
ctrlChar->writeValue(BLE_mini_buff, 1);
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_UPLOAD:
|
||||
if (BLE_notify_buffer[2] == 0x08) {
|
||||
free(buffer);
|
||||
free(BLE_image_buffer);
|
||||
pClient->disconnect();
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
@@ -222,35 +346,103 @@ void BLETask(void* parameter) {
|
||||
struct espXferComplete reportStruct;
|
||||
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||
processXferComplete(&reportStruct, true);
|
||||
curr_part = 0;
|
||||
BLE_err_counter = 0;
|
||||
BLE_curr_part = 0;
|
||||
} else {
|
||||
uint32_t req_curr_part = (BLE_notify_buffer[6] << 24) | (BLE_notify_buffer[5] << 24) | (BLE_notify_buffer[4] << 24) | BLE_notify_buffer[3];
|
||||
if (req_curr_part != curr_part) {
|
||||
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, curr_part);
|
||||
free(buffer);
|
||||
if (req_curr_part != BLE_curr_part) {
|
||||
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, BLE_curr_part);
|
||||
free(BLE_image_buffer);
|
||||
pClient->disconnect();
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
}
|
||||
uint32_t curr_len = 240;
|
||||
if (compressed_len - (curr_part * 240) < 240)
|
||||
curr_len = compressed_len - (curr_part * 240);
|
||||
BLE_buff[0] = curr_part & 0xff;
|
||||
BLE_buff[1] = (curr_part >> 8) & 0xff;
|
||||
BLE_buff[2] = (curr_part >> 16) & 0xff;
|
||||
BLE_buff[3] = (curr_part >> 24) & 0xff;
|
||||
memcpy((uint8_t*)&BLE_buff[4], (uint8_t*)&buffer[curr_part * 240], curr_len);
|
||||
imgChar->writeValue(BLE_buff, curr_len + 4);
|
||||
Serial.printf("BLE sending part: %i\r\n", curr_part);
|
||||
curr_part++;
|
||||
if (BLE_compressed_len - (BLE_curr_part * 240) < 240)
|
||||
curr_len = BLE_compressed_len - (BLE_curr_part * 240);
|
||||
BLE_mini_buff[0] = BLE_curr_part & 0xff;
|
||||
BLE_mini_buff[1] = (BLE_curr_part >> 8) & 0xff;
|
||||
BLE_mini_buff[2] = (BLE_curr_part >> 16) & 0xff;
|
||||
BLE_mini_buff[3] = (BLE_curr_part >> 24) & 0xff;
|
||||
memcpy((uint8_t*)&BLE_mini_buff[4], (uint8_t*)&BLE_image_buffer[BLE_curr_part * 240], curr_len);
|
||||
imgChar->writeValue(BLE_mini_buff, curr_len + 4);
|
||||
Serial.printf("BLE sending part: %i\r\n", BLE_curr_part);
|
||||
BLE_curr_part++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
|
||||
Serial.println("BLE err going back to IDLE");
|
||||
free(buffer);
|
||||
free(BLE_image_buffer);
|
||||
pClient->disconnect();
|
||||
BLE_err_counter = 0;
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD: {
|
||||
if (BLE_connected && BLE_new_notify) {
|
||||
BLE_new_notify = false;
|
||||
BLE_last_notify = millis();
|
||||
switch (BLE_upload_state) {
|
||||
default:
|
||||
case BLE_UPLOAD_STATE_INIT:
|
||||
BLE_mini_buff[0] = 0x00;
|
||||
BLE_mini_buff[1] = 0x64;
|
||||
memcpy((uint8_t*)&BLE_mini_buff[2], &BLEavaildatainfo, sizeof(struct AvailDataInfo));
|
||||
ctrlChar->writeValue(BLE_mini_buff, sizeof(struct AvailDataInfo) + 2);
|
||||
BLE_upload_state = BLE_UPLOAD_STATE_UPLOAD;
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_UPLOAD: {
|
||||
uint8_t notifyLen = BLE_notify_buffer[0];
|
||||
uint16_t notifyCMD = (BLE_notify_buffer[1] << 8) | BLE_notify_buffer[2];
|
||||
Serial.println("BLE CMD " + String(notifyCMD));
|
||||
switch (notifyCMD) {
|
||||
case BLE_CMD_REQ:
|
||||
if (notifyLen == (sizeof(struct blockRequest) + 2)) {
|
||||
Serial.println("We got a request for a BLK");
|
||||
memcpy(&BLEblkRequst, &BLE_notify_buffer[3], sizeof(struct blockRequest));
|
||||
BLE_curr_part = 0;
|
||||
ATC_BLE_OEPL_PrepareBlk(BLEblkRequst.blockId);
|
||||
ATC_BLE_OEPL_SendPart(BLEblkRequst.blockId, BLE_curr_part);
|
||||
}
|
||||
break;
|
||||
case BLE_CMD_ACK_BLKPRT:
|
||||
BLE_curr_part++;
|
||||
BLE_err_counter = 0;
|
||||
case BLE_CMD_ERR_BLKPRT:
|
||||
if (BLE_curr_part <= BLE_max_block_parts && BLE_err_counter++ < 15) {
|
||||
ATC_BLE_OEPL_SendPart(BLEblkRequst.blockId, BLE_curr_part);
|
||||
break;
|
||||
} // FALLTROUGH!!! We cancel the upload if we land here since we dont have so many parts of a block!
|
||||
case BLE_CMD_ACK:
|
||||
case BLE_CMD_ACK_IS_SHOWN:
|
||||
case BLE_CMD_ACK_FW_UPDATED:
|
||||
Serial.println("BLE Upload done");
|
||||
free(BLE_image_buffer);
|
||||
pClient->disconnect();
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
// Done and the image is refreshing now
|
||||
struct espXferComplete reportStruct;
|
||||
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||
processXferComplete(&reportStruct, true);
|
||||
BLE_err_counter = 0;
|
||||
BLE_max_block_parts = 0;
|
||||
BLE_curr_part = 0;
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} else {
|
||||
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
|
||||
Serial.println("BLE err going back to IDLE");
|
||||
free(BLE_image_buffer);
|
||||
pClient->disconnect();
|
||||
BLE_err_counter = 0;
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
}
|
||||
|
||||
@@ -222,6 +222,15 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
|
||||
} else {
|
||||
imageParams.zlib = 0;
|
||||
}
|
||||
#ifdef SAVE_SPACE
|
||||
imageParams.g5 = 0;
|
||||
#else
|
||||
if (hwdata.g5 != 0 && taginfo->tagSoftwareVersion >= hwdata.g5) {
|
||||
imageParams.g5 = 1;
|
||||
} else {
|
||||
imageParams.g5 = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
imageParams.lut = EPD_LUT_NO_REPEATS;
|
||||
if (taginfo->lut == 2) imageParams.lut = EPD_LUT_FAST_NO_REDS;
|
||||
@@ -277,9 +286,18 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
|
||||
imageParams.lut = EPD_LUT_DEFAULT;
|
||||
}
|
||||
|
||||
if (imageParams.zlib) {
|
||||
if (imageParams.bpp == 3) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_3BPP;
|
||||
Serial.println("datatype: DATATYPE_IMG_RAW_3BPP");
|
||||
} else if (imageParams.bpp == 4) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_4BPP;
|
||||
Serial.println("datatype: DATATYPE_IMG_RAW_4BPP");
|
||||
} else if (imageParams.zlib) {
|
||||
imageParams.dataType = DATATYPE_IMG_ZLIB;
|
||||
Serial.println("datatype: DATATYPE_IMG_ZLIB");
|
||||
} else if (imageParams.g5) {
|
||||
imageParams.dataType = DATATYPE_IMG_G5;
|
||||
Serial.println("datatype: DATATYPE_IMG_G5");
|
||||
} else if (imageParams.hasRed) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
|
||||
Serial.println("datatype: DATATYPE_IMG_RAW_2BPP");
|
||||
@@ -437,13 +455,6 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
|
||||
taginfo->nextupdate = 3216153600;
|
||||
prepareNFCReq(mac, cfgobj["url"].as<const char *>());
|
||||
break;
|
||||
|
||||
case 15: // send gray LUT
|
||||
|
||||
taginfo->nextupdate = 3216153600;
|
||||
prepareLUTreq(mac, cfgobj["bytes"]);
|
||||
taginfo->hasCustomLUT = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONTENT_BUIENRADAR
|
||||
@@ -557,9 +568,18 @@ bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin,
|
||||
imageParams.lut = EPD_LUT_DEFAULT;
|
||||
}
|
||||
|
||||
if (imageParams.zlib) {
|
||||
if (imageParams.bpp == 3) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_3BPP;
|
||||
Serial.println("datatype: DATATYPE_IMG_RAW_3BPP");
|
||||
} else if (imageParams.bpp == 4) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_4BPP;
|
||||
Serial.println("datatype: DATATYPE_IMG_RAW_4BPP");
|
||||
} else if (imageParams.zlib) {
|
||||
imageParams.dataType = DATATYPE_IMG_ZLIB;
|
||||
Serial.println("datatype: DATATYPE_IMG_ZLIB");
|
||||
} else if (imageParams.g5) {
|
||||
imageParams.dataType = DATATYPE_IMG_G5;
|
||||
Serial.println("datatype: DATATYPE_IMG_G5");
|
||||
} else if (imageParams.hasRed) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
|
||||
Serial.println("datatype: DATATYPE_IMG_RAW_2BPP");
|
||||
@@ -681,7 +701,7 @@ void drawTextBox(TFT_eSprite &spr, String &content, int16_t &posx, int16_t &posy
|
||||
switch (processFontPath(font)) {
|
||||
case 2: {
|
||||
// truetype
|
||||
Serial.println("truetype font not implemented for drawStringBox");
|
||||
Serial.println("truetype font not implemented for drawTextBox");
|
||||
} break;
|
||||
case 3: {
|
||||
// vlw bitmap font
|
||||
@@ -990,19 +1010,19 @@ void drawForecast(String &filename, JsonObject &cfgobj, const tagRecord *taginfo
|
||||
}
|
||||
|
||||
if (loc["rain"]) {
|
||||
if (cfgobj["units"] == "0") {
|
||||
const int8_t rain = round(daily["precipitation_sum"][dag].as<double>());
|
||||
if (rain > 0) {
|
||||
drawString(spr, String(rain) + "mm", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (rain > 10 ? imageParams.highlightColor : TFT_BLACK));
|
||||
}
|
||||
} else {
|
||||
double fRain = daily["precipitation_sum"][dag].as<double>();
|
||||
fRain = round(fRain*100.0) / 100.0;
|
||||
if (fRain > 0.0) {
|
||||
// inch, display if > .01 inches
|
||||
drawString(spr, String(fRain) + "in", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (fRain > 0.5 ? imageParams.highlightColor : TFT_BLACK));
|
||||
}
|
||||
}
|
||||
if (cfgobj["units"] == "0") {
|
||||
const int8_t rain = round(daily["precipitation_sum"][dag].as<double>());
|
||||
if (rain > 0) {
|
||||
drawString(spr, String(rain) + "mm", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (rain > 10 ? imageParams.highlightColor : TFT_BLACK));
|
||||
}
|
||||
} else {
|
||||
double fRain = daily["precipitation_sum"][dag].as<double>();
|
||||
fRain = round(fRain * 100.0) / 100.0;
|
||||
if (fRain > 0.0) {
|
||||
// inch, display if > .01 inches
|
||||
drawString(spr, String(fRain) + "in", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (fRain > 0.5 ? imageParams.highlightColor : TFT_BLACK));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawString(spr, String(tmin) + " ", dag * column1 + day[0].as<int>(), day[4], day[2], TR_DATUM, (tmin < 0 ? imageParams.highlightColor : TFT_BLACK));
|
||||
@@ -1211,7 +1231,7 @@ bool getCalFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
|
||||
int temp = imageParams.height;
|
||||
imageParams.height = imageParams.width;
|
||||
imageParams.width = temp;
|
||||
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer%2);
|
||||
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer % 2);
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
} else {
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
@@ -1439,18 +1459,32 @@ bool getCalFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
|
||||
|
||||
#ifdef CONTENT_DAYAHEAD
|
||||
uint16_t getPercentileColor(const double *prices, int numPrices, double price, HwType hwdata) {
|
||||
double percentile = 100.0;
|
||||
int colorIndex = 3;
|
||||
const char *colors[] = {"black", "darkgray", "pink", "red"};
|
||||
if (hwdata.highlightColor == 3) {
|
||||
// yellow
|
||||
colors[2] = "brown";
|
||||
colors[3] = "yellow";
|
||||
}
|
||||
const int numColors = sizeof(colors) / sizeof(colors[0]);
|
||||
const char *colorsDefault[] = {"black", "darkgray", "pink", "red"};
|
||||
const double boundariesDefault[] = {40.0, 80.0, 90.0};
|
||||
|
||||
const double boundaries[] = {40.0, 80.0, 90.0};
|
||||
const int numBoundaries = sizeof(boundaries) / sizeof(boundaries[0]);
|
||||
const char *colors3bpp[] = {"blue", "green", "yellow", "orange", "red"};
|
||||
const double boundaries3bpp[] = {20.0, 50.0, 70.0, 90.0};
|
||||
|
||||
const char **colors;
|
||||
const double *boundaries;
|
||||
int numColors, numBoundaries;
|
||||
|
||||
if (hwdata.bpp == 3 || hwdata.bpp == 4) {
|
||||
colors = colors3bpp;
|
||||
boundaries = boundaries3bpp;
|
||||
numColors = sizeof(colors3bpp) / sizeof(colors3bpp[0]);
|
||||
numBoundaries = sizeof(boundaries3bpp) / sizeof(boundaries3bpp[0]);
|
||||
} else {
|
||||
colors = colorsDefault;
|
||||
boundaries = boundariesDefault;
|
||||
numColors = sizeof(colorsDefault) / sizeof(colorsDefault[0]);
|
||||
numBoundaries = sizeof(boundariesDefault) / sizeof(boundariesDefault[0]);
|
||||
if (hwdata.highlightColor == 3) {
|
||||
colors[2] = "brown";
|
||||
colors[3] = "yellow";
|
||||
}
|
||||
}
|
||||
int colorIndex = numColors - 1;
|
||||
|
||||
for (int i = 0; i < numBoundaries; i++) {
|
||||
if (price < prices[int(numPrices * boundaries[i] / 100.0)]) {
|
||||
@@ -1622,7 +1656,7 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo,
|
||||
spr.fillTriangle(barX + i * barwidth, 15 + arrowY,
|
||||
barX + i * barwidth + barwidth - 1, 15 + arrowY,
|
||||
barX + i * barwidth + (barwidth - 1) / 2, 15 + barwidth + arrowY, imageParams.highlightColor);
|
||||
spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth + arrowY, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), getColor("pink"));
|
||||
spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth + arrowY, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), TFT_BLACK);
|
||||
pricenow = price;
|
||||
}
|
||||
}
|
||||
@@ -1809,14 +1843,18 @@ void drawTimestamp(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, im
|
||||
drawString(spr, "Well done!", spr.width() / 2, 90, "calibrib30.vlw", TC_DATUM, TFT_BLACK);
|
||||
spr2buffer(spr, filename2, imageParams);
|
||||
|
||||
if (imageParams.zlib) imageParams.dataType = DATATYPE_IMG_ZLIB;
|
||||
if (imageParams.zlib) {
|
||||
imageParams.dataType = DATATYPE_IMG_ZLIB;
|
||||
} else if (imageParams.g5) {
|
||||
imageParams.dataType = DATATYPE_IMG_G5;
|
||||
}
|
||||
|
||||
struct imageDataTypeArgStruct arg = {0};
|
||||
arg.preloadImage = 1;
|
||||
arg.specialType = 17; // button 2
|
||||
arg.lut = 0;
|
||||
|
||||
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000 );
|
||||
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000);
|
||||
|
||||
spr.fillRect(0, 0, spr.width(), spr.height(), TFT_WHITE);
|
||||
|
||||
@@ -1828,7 +1866,7 @@ void drawTimestamp(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, im
|
||||
arg.preloadImage = 1;
|
||||
arg.specialType = 16; // button 1
|
||||
arg.lut = 0;
|
||||
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000 );
|
||||
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000);
|
||||
|
||||
cfgobj["#init"] = "1";
|
||||
}
|
||||
@@ -2165,7 +2203,7 @@ void rotateBuffer(uint8_t rotation, uint8_t ¤tOrientation, TFT_eSprite &sp
|
||||
initSprite(spr, sprCpy.width(), sprCpy.height(), imageParams);
|
||||
sprCpy.pushToSprite(&spr, 0, 0);
|
||||
sprCpy.deleteSprite();
|
||||
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer%2);
|
||||
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer % 2);
|
||||
}
|
||||
currentOrientation = rotation;
|
||||
}
|
||||
@@ -2217,6 +2255,9 @@ uint16_t getColor(const String &color) {
|
||||
if (color == "5" || color == "darkgray") return TFT_DARKGREY;
|
||||
if (color == "6" || color == "pink") return 0xFBCF;
|
||||
if (color == "7" || color == "brown") return 0x8400;
|
||||
if (color == "8" || color == "green") return TFT_GREEN;
|
||||
if (color == "9" || color == "blue") return TFT_BLUE;
|
||||
if (color == "10" || color == "orange") return 0xFBE0;
|
||||
uint16_t r, g, b;
|
||||
if (color.length() == 7 && color[0] == '#' &&
|
||||
sscanf(color.c_str(), "#%2hx%2hx%2hx", &r, &g, &b) == 3) {
|
||||
@@ -2315,20 +2356,6 @@ void prepareNFCReq(const uint8_t *dst, const char *url) {
|
||||
len = 1 + len;
|
||||
prepareDataAvail(data, len, DATATYPE_NFC_RAW_CONTENT, dst);
|
||||
}
|
||||
|
||||
void prepareLUTreq(const uint8_t *dst, const String &input) {
|
||||
constexpr const char *delimiters = ", \t";
|
||||
constexpr const int maxValues = 76;
|
||||
uint8_t waveform[maxValues];
|
||||
char *ptr = strtok(const_cast<char *>(input.c_str()), delimiters);
|
||||
int i = 0;
|
||||
while (ptr != nullptr && i < maxValues) {
|
||||
waveform[i++] = static_cast<uint8_t>(strtol(ptr, nullptr, 16));
|
||||
ptr = strtok(nullptr, delimiters);
|
||||
}
|
||||
const size_t waveformLen = sizeof(waveform);
|
||||
prepareDataAvail(waveform, waveformLen, DATATYPE_CUSTOM_LUT_OTA, dst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONTENT_TAGCFG
|
||||
|
||||
203
ESP32_AP-Flasher/src/g5/Group5.h
Normal file
203
ESP32_AP-Flasher/src/g5/Group5.h
Normal file
@@ -0,0 +1,203 @@
|
||||
#ifndef __GROUP5__
|
||||
#define __GROUP5__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
//
|
||||
// Group5 1-bit image compression library
|
||||
// Written by Larry Bank
|
||||
// Copyright (c) 2024 BitBank Software, Inc.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file ./LICENSE.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// ./APL.txt.
|
||||
//
|
||||
// The name "Group5" is derived from the CCITT Group4 standard
|
||||
// This code is based on a lot of the good ideas from CCITT T.6
|
||||
// for FAX image compression, but modified to work in a very
|
||||
// constrained environment. The Huffman tables for horizontal
|
||||
// mode have been replaced with a simple 2-bit flag followed by
|
||||
// short or long counts of a fixed length. The short codes are
|
||||
// always 3 bits (run lengths 0-7) and the long codes are the
|
||||
// number of bits needed to encode the width of the image.
|
||||
// For example, if a 320 pixel wide image is being compressed,
|
||||
// the longest horizontal run needed is 320, which requires 9
|
||||
// bits to encode. The 2 prefix bits have the following meaning:
|
||||
// 00 = short, short (3+3 bits)
|
||||
// 01 = short, long (3+N bits)
|
||||
// 10 = long, short (N+3 bits)
|
||||
// 11 = long, long (N+N bits)
|
||||
// The rest of the code works identically to Group4 2D FAX
|
||||
//
|
||||
// Caution - this is the maximum number of color changes per line
|
||||
// The default value is set low to work embedded systems with little RAM
|
||||
// for font compression, this is plenty since each line of a character should have
|
||||
// a maximum of 7 color changes
|
||||
// You can define this in your compiler macros to override the default vlaue
|
||||
//
|
||||
|
||||
|
||||
#define MAX_IMAGE_FLIPS 640
|
||||
|
||||
#ifndef MAX_IMAGE_FLIPS
|
||||
#ifdef __AVR__
|
||||
#define MAX_IMAGE_FLIPS 32
|
||||
#else
|
||||
#define MAX_IMAGE_FLIPS 512
|
||||
#endif // __AVR__
|
||||
#endif
|
||||
// Horizontal prefix bits
|
||||
enum {
|
||||
HORIZ_SHORT_SHORT=0,
|
||||
HORIZ_SHORT_LONG,
|
||||
HORIZ_LONG_SHORT,
|
||||
HORIZ_LONG_LONG
|
||||
};
|
||||
|
||||
// Return code for encoder and decoder
|
||||
enum {
|
||||
G5_SUCCESS = 0,
|
||||
G5_INVALID_PARAMETER,
|
||||
G5_DECODE_ERROR,
|
||||
G5_UNSUPPORTED_FEATURE,
|
||||
G5_ENCODE_COMPLETE,
|
||||
G5_DECODE_COMPLETE,
|
||||
G5_NOT_INITIALIZED,
|
||||
G5_DATA_OVERFLOW,
|
||||
G5_MAX_FLIPS_EXCEEDED
|
||||
};
|
||||
//
|
||||
// Decoder state
|
||||
//
|
||||
typedef struct g5_dec_image_tag
|
||||
{
|
||||
int iWidth, iHeight; // image size
|
||||
int iError;
|
||||
int y; // last y value drawn
|
||||
int iVLCSize;
|
||||
int iHLen; // length of 'long' horizontal codes for this image
|
||||
int iPitch; // width in bytes of output buffer
|
||||
uint32_t u32Accum; // fractional scaling accumulator
|
||||
uint32_t ulBitOff, ulBits; // vlc decode variables
|
||||
uint8_t *pSrc, *pBuf; // starting & current buffer pointer
|
||||
int16_t *pCur, *pRef; // current state of current vs reference flips
|
||||
int16_t CurFlips[MAX_IMAGE_FLIPS];
|
||||
int16_t RefFlips[MAX_IMAGE_FLIPS];
|
||||
} G5DECIMAGE;
|
||||
|
||||
// Due to unaligned memory causing an exception, we have to do these macros the slow way
|
||||
#ifdef __AVR__
|
||||
// assume PROGMEM as the source of data
|
||||
inline uint32_t TIFFMOTOLONG(uint8_t *p)
|
||||
{
|
||||
uint32_t u32 = pgm_read_dword(p);
|
||||
return __builtin_bswap32(u32);
|
||||
}
|
||||
#else
|
||||
#define TIFFMOTOLONG(p) (((uint32_t)(*p)<<24UL) + ((uint32_t)(*(p+1))<<16UL) + ((uint32_t)(*(p+2))<<8UL) + (uint32_t)(*(p+3)))
|
||||
#endif // __AVR__
|
||||
|
||||
#define TOP_BIT 0x80000000
|
||||
#define MAX_VALUE 0xffffffff
|
||||
// Must be a 32-bit target processor
|
||||
#define REGISTER_WIDTH 32
|
||||
#define BIGUINT uint32_t
|
||||
|
||||
//
|
||||
// G5 Encoder
|
||||
//
|
||||
|
||||
typedef struct pil_buffered_bits
|
||||
{
|
||||
unsigned char *pBuf; // buffer pointer
|
||||
uint32_t ulBits; // buffered bits
|
||||
uint32_t ulBitOff; // current bit offset
|
||||
uint32_t ulDataSize; // available data
|
||||
} BUFFERED_BITS;
|
||||
|
||||
//
|
||||
// Encoder state
|
||||
//
|
||||
typedef struct g5_enc_image_tag
|
||||
{
|
||||
int iWidth, iHeight; // image size
|
||||
int iError;
|
||||
int y; // last y encoded
|
||||
int iOutSize;
|
||||
int iDataSize; // generated output size
|
||||
uint8_t *pOutBuf;
|
||||
int16_t *pCur, *pRef; // pointers to swap current and reference lines
|
||||
BUFFERED_BITS bb;
|
||||
int16_t CurFlips[MAX_IMAGE_FLIPS];
|
||||
int16_t RefFlips[MAX_IMAGE_FLIPS];
|
||||
} G5ENCIMAGE;
|
||||
|
||||
// 16-bit marker at the start of a BB_FONT file
|
||||
// (BitBank FontFile)
|
||||
#define BB_FONT_MARKER 0xBBFF
|
||||
// 16-bit marker at the start of a BB_BITMAP file
|
||||
// (BitBank BitmapFile)
|
||||
#define BB_BITMAP_MARKER 0xBBBF
|
||||
|
||||
// Font info per character (glyph)
|
||||
typedef struct {
|
||||
uint16_t bitmapOffset; // Offset to compressed bitmap data for this glyph (starting from the end of the BB_GLYPH[] array)
|
||||
uint8_t width; // bitmap width in pixels
|
||||
uint8_t xAdvance; // total width in pixels (bitmap + padding)
|
||||
uint16_t height; // bitmap height in pixels
|
||||
int16_t xOffset; // left padding to upper left corner
|
||||
int16_t yOffset; // padding from baseline to upper left corner (usually negative)
|
||||
} BB_GLYPH;
|
||||
|
||||
// This structure is stored at the beginning of a BB_FONT file
|
||||
typedef struct {
|
||||
uint16_t u16Marker; // 16-bit Marker defining a BB_FONT file
|
||||
uint16_t first; // first char (ASCII value)
|
||||
uint16_t last; // last char (ASCII value)
|
||||
uint16_t height; // total height of font
|
||||
uint32_t rotation; // store this as 32-bits to not have a struct packing problem
|
||||
BB_GLYPH glyphs[]; // Array of glyphs (one for each char)
|
||||
} BB_FONT;
|
||||
|
||||
// This structure defines the start of a compressed bitmap file
|
||||
typedef struct {
|
||||
uint16_t u16Marker; // 16-bit marker defining a BB_BITMAP file
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t size; // compressed data size (not including this 8-byte header)
|
||||
} BB_BITMAP;
|
||||
|
||||
#ifdef __cplusplus
|
||||
//
|
||||
// The G5 classes wrap portable C code which does the actual work
|
||||
//
|
||||
class G5ENCODER
|
||||
{
|
||||
public:
|
||||
int init(int iWidth, int iHeight, uint8_t *pOut, int iOutSize);
|
||||
int encodeLine(uint8_t *pPixels);
|
||||
int size();
|
||||
|
||||
private:
|
||||
G5ENCIMAGE _g5enc;
|
||||
};
|
||||
class G5DECODER
|
||||
{
|
||||
public:
|
||||
int init(int iWidth, int iHeight, uint8_t *pData, int iDataSize);
|
||||
int decodeLine(uint8_t *pOut);
|
||||
|
||||
private:
|
||||
G5DECIMAGE _g5dec;
|
||||
};
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // __GROUP5__
|
||||
338
ESP32_AP-Flasher/src/g5/g5dec.inl
Normal file
338
ESP32_AP-Flasher/src/g5/g5dec.inl
Normal file
@@ -0,0 +1,338 @@
|
||||
//
|
||||
// Group5
|
||||
// A 1-bpp image decoder
|
||||
//
|
||||
// Written by Larry Bank
|
||||
// Copyright (c) 2024 BitBank Software, Inc.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file ./LICENSE.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// ./APL.txt.
|
||||
#include "Group5.h"
|
||||
|
||||
/*
|
||||
The code tree that follows has: bit_length, decode routine
|
||||
These codes are for Group 4 (MMR) decoding
|
||||
|
||||
01 = vertneg1, 11h = vert1, 20h = horiz, 30h = pass, 12h = vert2
|
||||
02 = vertneg2, 13h = vert3, 03 = vertneg3, 90h = trash
|
||||
*/
|
||||
|
||||
static const uint8_t code_table[128] =
|
||||
{0x90, 0, 0x40, 0, /* trash, uncompr mode - codes 0 and 1 */
|
||||
3, 7, /* V(-3) pos = 2 */
|
||||
0x13, 7, /* V(3) pos = 3 */
|
||||
2, 6, 2, 6, /* V(-2) pos = 4,5 */
|
||||
0x12, 6, 0x12, 6, /* V(2) pos = 6,7 */
|
||||
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4, /* pass pos = 8->F */
|
||||
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4,
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, /* horiz pos = 10->1F */
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||
/* V(-1) pos = 20->2F */
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3, /* V(1) pos = 30->3F */
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3};
|
||||
|
||||
static int g5_decode_init(G5DECIMAGE *pImage, int iWidth, int iHeight, uint8_t *pData, int iDataSize)
|
||||
{
|
||||
if (pImage == NULL || iWidth < 1 || iHeight < 1 || pData == NULL || iDataSize < 1)
|
||||
return G5_INVALID_PARAMETER;
|
||||
|
||||
pImage->iVLCSize = iDataSize;
|
||||
pImage->pSrc = pData;
|
||||
pImage->ulBitOff = 0;
|
||||
pImage->y = 0;
|
||||
pImage->ulBits = TIFFMOTOLONG(pData); // preload the first 32 bits of data
|
||||
pImage->iWidth = iWidth;
|
||||
pImage->iHeight = iHeight;
|
||||
return G5_SUCCESS;
|
||||
|
||||
} /* g5_decode_init() */
|
||||
|
||||
static void G5DrawLine(G5DECIMAGE *pPage, int16_t *pCurFlips, uint8_t *pOut)
|
||||
{
|
||||
int x, len, run;
|
||||
uint8_t lBit, rBit, *p;
|
||||
int iStart = 0, xright = pPage->iWidth;
|
||||
uint8_t *pDest;
|
||||
|
||||
iStart = 0;
|
||||
|
||||
pDest = pOut;
|
||||
len = (xright+7)>>3; // number of bytes to generate
|
||||
for (x=0; x<len; x++) {
|
||||
pOut[x] = 0xff; // start with white and only draw the black runs
|
||||
}
|
||||
x = 0;
|
||||
while (x < xright) { // while the scaled x is within the window bounds
|
||||
x = *pCurFlips++; // black starting point
|
||||
run = *pCurFlips++ - x; // get the black run
|
||||
x -= iStart;
|
||||
if (x >= xright || run == 0)
|
||||
break;
|
||||
if ((x + run) > 0) { /* If the run is visible, draw it */
|
||||
if (x < 0) {
|
||||
run += x; /* draw only visible part of run */
|
||||
x = 0;
|
||||
}
|
||||
if ((x + run) > xright) { /* Don't let it go off right edge */
|
||||
run = xright - x;
|
||||
}
|
||||
/* Draw this run */
|
||||
lBit = 0xff << (8 - (x & 7));
|
||||
rBit = 0xff >> ((x + run) & 7);
|
||||
len = ((x+run)>>3) - (x >> 3);
|
||||
p = &pDest[x >> 3];
|
||||
if (len == 0) {
|
||||
lBit |= rBit;
|
||||
*p &= lBit;
|
||||
} else {
|
||||
*p++ &= lBit;
|
||||
while (len > 1) {
|
||||
*p++ = 0;
|
||||
len--;
|
||||
}
|
||||
*p = rBit;
|
||||
}
|
||||
} // visible run
|
||||
} /* while drawing line */
|
||||
} /* G5DrawLine() */
|
||||
//
|
||||
// Initialize internal structures to decode the image
|
||||
//
|
||||
static void Decode_Begin(G5DECIMAGE *pPage)
|
||||
{
|
||||
int i, xsize;
|
||||
int16_t *CurFlips, *RefFlips;
|
||||
|
||||
xsize = pPage->iWidth;
|
||||
|
||||
RefFlips = pPage->RefFlips;
|
||||
CurFlips = pPage->CurFlips;
|
||||
|
||||
/* Seed the current and reference line with XSIZE for V(0) codes */
|
||||
for (i=0; i<MAX_IMAGE_FLIPS-2; i++) {
|
||||
RefFlips[i] = xsize;
|
||||
CurFlips[i] = xsize;
|
||||
}
|
||||
/* Prefill both current and reference lines with 7fff to prevent it from
|
||||
walking off the end if the data gets bunged and the current X is > XSIZE
|
||||
3-16-94 */
|
||||
CurFlips[i] = RefFlips[i] = 0x7fff;
|
||||
CurFlips[i+1] = RefFlips[i+1] = 0x7fff;
|
||||
|
||||
pPage->pCur = CurFlips;
|
||||
pPage->pRef = RefFlips;
|
||||
pPage->pBuf = pPage->pSrc;
|
||||
pPage->ulBits = TIFFMOTOLONG(pPage->pSrc); // load 32 bits to start
|
||||
pPage->ulBitOff = 0;
|
||||
// Calculate the number of bits needed for a long horizontal code
|
||||
#ifdef __AVR__
|
||||
pPage->iHLen = 16 - __builtin_clz(pPage->iWidth);
|
||||
#else
|
||||
pPage->iHLen = 32 - __builtin_clz(pPage->iWidth);
|
||||
#endif
|
||||
} /* Decode_Begin() */
|
||||
//
|
||||
// Decode a single line of G5 data (private function)
|
||||
//
|
||||
static int DecodeLine(G5DECIMAGE *pPage)
|
||||
{
|
||||
signed int a0, a0_p, b1;
|
||||
int16_t *pCur, *pRef, *RefFlips, *CurFlips;
|
||||
int xsize, tot_run=0, tot_run1 = 0;
|
||||
int32_t sCode;
|
||||
uint32_t lBits;
|
||||
uint32_t ulBits, ulBitOff;
|
||||
uint8_t *pBuf/*, *pBufEnd*/;
|
||||
uint32_t u32HMask, u32HLen; // horizontal code mask and length
|
||||
|
||||
pCur = CurFlips = pPage->pCur;
|
||||
pRef = RefFlips = pPage->pRef;
|
||||
ulBits = pPage->ulBits;
|
||||
ulBitOff = pPage->ulBitOff;
|
||||
pBuf = pPage->pBuf;
|
||||
// pBufEnd = &pPage->pSrc[pPage->iVLCSize];
|
||||
u32HLen = pPage->iHLen;
|
||||
u32HMask = (1 << u32HLen) - 1;
|
||||
a0 = -1;
|
||||
xsize = pPage->iWidth;
|
||||
|
||||
while (a0 < xsize) { /* Decode this line */
|
||||
if (ulBitOff > (REGISTER_WIDTH-8)) { // need at least 7 unused bits
|
||||
pBuf += (ulBitOff >> 3);
|
||||
ulBitOff &= 7;
|
||||
ulBits = TIFFMOTOLONG(pBuf);
|
||||
}
|
||||
if ((int32_t)(ulBits << ulBitOff) < 0) { /* V(0) code is the most frequent case (1 bit) */
|
||||
a0 = *pRef++;
|
||||
ulBitOff++; // length = 1 bit
|
||||
*pCur++ = a0;
|
||||
} else { /* Slower method for the less frequence codes */
|
||||
lBits = (ulBits >> ((REGISTER_WIDTH - 8) - ulBitOff)) & 0xfe; /* Only the first 7 bits are useful */
|
||||
sCode = code_table[lBits]; /* Get the code type as an 8-bit value */
|
||||
ulBitOff += code_table[lBits+1]; /* Get the code length */
|
||||
switch (sCode) {
|
||||
case 1: /* V(-1) */
|
||||
case 2: /* V(-2) */
|
||||
case 3: /* V(-3) */
|
||||
a0 = *pRef - sCode; /* A0 = B1 - x */
|
||||
*pCur++ = a0;
|
||||
if (pRef == RefFlips) {
|
||||
pRef += 2;
|
||||
}
|
||||
pRef--;
|
||||
while (a0 >= *pRef) {
|
||||
pRef += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11: /* V(1) */
|
||||
case 0x12: /* V(2) */
|
||||
case 0x13: /* V(3) */
|
||||
a0 = *pRef++; /* A0 = B1 */
|
||||
b1 = a0;
|
||||
a0 += sCode & 7; /* A0 = B1 + x */
|
||||
if (b1 != xsize && a0 < xsize) {
|
||||
while (a0 >= *pRef) {
|
||||
pRef += 2;
|
||||
}
|
||||
}
|
||||
if (a0 > xsize) {
|
||||
a0 = xsize;
|
||||
}
|
||||
*pCur++ = a0;
|
||||
break;
|
||||
|
||||
case 0x20: /* Horizontal codes */
|
||||
if (ulBitOff > (REGISTER_WIDTH-16)) { // need at least 16 unused bits
|
||||
pBuf += (ulBitOff >> 3);
|
||||
ulBitOff &= 7;
|
||||
ulBits = TIFFMOTOLONG(pBuf);
|
||||
}
|
||||
a0_p = a0;
|
||||
if (a0 < 0) {
|
||||
a0_p = 0;
|
||||
}
|
||||
lBits = (ulBits >> ((REGISTER_WIDTH - 2) - ulBitOff)) & 0x3; // get 2-bit prefix for code type
|
||||
// There are 4 possible horizontal cases: short/short, short/long, long/short, long/long
|
||||
// These are encoded in a 2-bit prefix code, followed by 3 bits for short or N bits for long code
|
||||
// N is the log base 2 of the image width (e.g. 320 pixels requires 9 bits)
|
||||
ulBitOff += 2;
|
||||
switch (lBits) {
|
||||
case HORIZ_SHORT_SHORT:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||
ulBitOff += 3;
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||
ulBitOff += 3;
|
||||
break;
|
||||
case HORIZ_SHORT_LONG:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||
ulBitOff += 3;
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||
ulBitOff += u32HLen;
|
||||
break;
|
||||
case HORIZ_LONG_SHORT:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||
ulBitOff += u32HLen;
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||
ulBitOff += 3;
|
||||
break;
|
||||
case HORIZ_LONG_LONG:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||
ulBitOff += u32HLen;
|
||||
if (ulBitOff > (REGISTER_WIDTH-16)) { // need at least 16 unused bits
|
||||
pBuf += (ulBitOff >> 3);
|
||||
ulBitOff &= 7;
|
||||
ulBits = TIFFMOTOLONG(pBuf);
|
||||
}
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||
ulBitOff += u32HLen;
|
||||
break;
|
||||
} // switch on lBits
|
||||
a0 = a0_p + tot_run;
|
||||
*pCur++ = a0;
|
||||
a0 += tot_run1;
|
||||
if (a0 < xsize) {
|
||||
while (a0 >= *pRef) {
|
||||
pRef += 2;
|
||||
}
|
||||
}
|
||||
*pCur++ = a0;
|
||||
break;
|
||||
|
||||
case 0x30: /* Pass code */
|
||||
pRef++; /* A0 = B2, iRef+=2 */
|
||||
a0 = *pRef++;
|
||||
break;
|
||||
|
||||
default: /* ERROR */
|
||||
pPage->iError = G5_DECODE_ERROR;
|
||||
goto pilreadg5z;
|
||||
} /* switch */
|
||||
} /* Slow climb */
|
||||
}
|
||||
/*--- Convert flips data into run lengths ---*/
|
||||
*pCur++ = xsize; /* Terminate the line properly */
|
||||
*pCur++ = xsize;
|
||||
pilreadg5z:
|
||||
// Save the current VLC decoder state
|
||||
pPage->ulBits = ulBits;
|
||||
pPage->ulBitOff = ulBitOff;
|
||||
pPage->pBuf = pBuf;
|
||||
return pPage->iError;
|
||||
} /* DecodeLine() */
|
||||
//
|
||||
// Decompress the VLC data
|
||||
//
|
||||
static int g5_decode_line(G5DECIMAGE *pPage, uint8_t *pOut)
|
||||
{
|
||||
int rc;
|
||||
uint8_t *pBufEnd;
|
||||
int16_t *t1;
|
||||
|
||||
if (pPage == NULL || pOut == NULL)
|
||||
return G5_INVALID_PARAMETER;
|
||||
if (pPage->y >= pPage->iHeight)
|
||||
return G5_DECODE_COMPLETE;
|
||||
|
||||
pPage->iError = G5_SUCCESS;
|
||||
|
||||
if (pPage->y == 0) { // first time through
|
||||
Decode_Begin(pPage);
|
||||
}
|
||||
pBufEnd = &pPage->pSrc[pPage->iVLCSize];
|
||||
|
||||
if (pPage->pBuf >= pBufEnd) { // read past the end, error
|
||||
pPage->iError = G5_DECODE_ERROR;
|
||||
return G5_DECODE_ERROR;
|
||||
}
|
||||
rc = DecodeLine(pPage);
|
||||
if (rc == G5_SUCCESS) {
|
||||
// Draw the current line
|
||||
G5DrawLine(pPage, pPage->pCur, pOut);
|
||||
/*--- Swap current and reference lines ---*/
|
||||
t1 = pPage->pRef;
|
||||
pPage->pRef = pPage->pCur;
|
||||
pPage->pCur = t1;
|
||||
pPage->y++;
|
||||
if (pPage->y >= pPage->iHeight) {
|
||||
pPage->iError = G5_DECODE_COMPLETE;
|
||||
}
|
||||
} else {
|
||||
pPage->iError = rc;
|
||||
}
|
||||
return pPage->iError;
|
||||
} /* Decode() */
|
||||
|
||||
305
ESP32_AP-Flasher/src/g5/g5enc.inl
Normal file
305
ESP32_AP-Flasher/src/g5/g5enc.inl
Normal file
@@ -0,0 +1,305 @@
|
||||
//
|
||||
// G5 Encoder
|
||||
// A 1-bpp image encoding library
|
||||
//
|
||||
// Written by Larry Bank
|
||||
// Copyright (c) 2024 BitBank Software, Inc.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file ./LICENSE.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// ./APL.txt.
|
||||
#include "Group5.h"
|
||||
|
||||
/* Number of consecutive 1 bits in a byte from MSB to LSB */
|
||||
static uint8_t bitcount[256] =
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0-15 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16-31 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 32-47 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 48-63 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 64-79 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80-95 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 96-111 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 112-127 */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 128-143 */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 144-159 */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 160-175 */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 176-191 */
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 192-207 */
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 208-223 */
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, /* 224-239 */
|
||||
4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,8}; /* 240-255 */
|
||||
|
||||
/* Table of vertical codes for G5 encoding */
|
||||
/* code followed by length, starting with v(-3) */
|
||||
static const uint8_t vtable[14] =
|
||||
{3,7, /* V(-3) = 0000011 */
|
||||
3,6, /* V(-2) = 000011 */
|
||||
3,3, /* V(-1) = 011 */
|
||||
1,1, /* V(0) = 1 */
|
||||
2,3, /* V(1) = 010 */
|
||||
2,6, /* V(2) = 000010 */
|
||||
2,7}; /* V(3) = 0000010 */
|
||||
|
||||
|
||||
static void G5ENCInsertCode(BUFFERED_BITS *bb, BIGUINT ulCode, int iLen)
|
||||
{
|
||||
if ((bb->ulBitOff + iLen) > REGISTER_WIDTH) { // need to write data
|
||||
bb->ulBits |= (ulCode >> (bb->ulBitOff + iLen - REGISTER_WIDTH)); // partial bits on first word
|
||||
*(BIGUINT *)bb->pBuf = __builtin_bswap32(bb->ulBits);
|
||||
bb->pBuf += sizeof(BIGUINT);
|
||||
bb->ulBits = ulCode << ((REGISTER_WIDTH*2) - (bb->ulBitOff + iLen));
|
||||
bb->ulBitOff += iLen - REGISTER_WIDTH;
|
||||
} else {
|
||||
bb->ulBits |= (ulCode << (REGISTER_WIDTH - bb->ulBitOff - iLen));
|
||||
bb->ulBitOff += iLen;
|
||||
}
|
||||
} /* G5ENCInsertCode() */
|
||||
//
|
||||
// Flush any buffered bits to the output
|
||||
//
|
||||
static void G5ENCFlushBits(BUFFERED_BITS *bb)
|
||||
{
|
||||
while (bb->ulBitOff >= 8)
|
||||
{
|
||||
*bb->pBuf++ = (unsigned char) (bb->ulBits >> (REGISTER_WIDTH - 8));
|
||||
bb->ulBits <<= 8;
|
||||
bb->ulBitOff -= 8;
|
||||
}
|
||||
*bb->pBuf++ = (unsigned char) (bb->ulBits >> (REGISTER_WIDTH - 8));
|
||||
bb->ulBitOff = 0;
|
||||
bb->ulBits = 0;
|
||||
} /* G5ENCFlushBits() */
|
||||
//
|
||||
// Initialize the compressor
|
||||
// This must be called before adding data to the output
|
||||
//
|
||||
int g5_encode_init(G5ENCIMAGE *pImage, int iWidth, int iHeight, uint8_t *pOut, int iOutSize)
|
||||
{
|
||||
int iError = G5_SUCCESS;
|
||||
|
||||
if (pImage == NULL || iHeight <= 0)
|
||||
return G5_INVALID_PARAMETER;
|
||||
pImage->iWidth = iWidth; // image size
|
||||
pImage->iHeight = iHeight;
|
||||
pImage->pCur = pImage->CurFlips;
|
||||
pImage->pRef = pImage->RefFlips;
|
||||
pImage->pOutBuf = pOut; // optional output buffer
|
||||
pImage->iOutSize = iOutSize; // output buffer pre-allocated size
|
||||
pImage->iDataSize = 0; // no data yet
|
||||
pImage->y = 0;
|
||||
for (int i=0; i<MAX_IMAGE_FLIPS; i++) {
|
||||
pImage->RefFlips[i] = iWidth;
|
||||
pImage->CurFlips[i] = iWidth;
|
||||
}
|
||||
pImage->bb.pBuf = pImage->pOutBuf;
|
||||
pImage->bb.ulBits = 0;
|
||||
pImage->bb.ulBitOff = 0;
|
||||
pImage->iError = iError;
|
||||
return iError;
|
||||
} /* g5_encode_init() */
|
||||
//
|
||||
// Internal function to convert uncompressed 1-bit per pixel data
|
||||
// into the run-end data needed to feed the G5 encoder
|
||||
//
|
||||
static int G5ENCEncodeLine(unsigned char *buf, int xsize, int16_t *pDest)
|
||||
{
|
||||
int iCount, xborder;
|
||||
uint8_t i, c;
|
||||
int8_t cBits;
|
||||
int iLen;
|
||||
int16_t x;
|
||||
int16_t *pLimit = pDest + (MAX_IMAGE_FLIPS-4);
|
||||
|
||||
xborder = xsize;
|
||||
iCount = (xsize + 7) >> 3; /* Number of bytes per line */
|
||||
cBits = 8;
|
||||
iLen = 0; /* Current run length */
|
||||
x = 0;
|
||||
|
||||
c = *buf++; /* Get the first byte to start */
|
||||
iCount--;
|
||||
while (iCount >=0) {
|
||||
if (pDest >= pLimit) return G5_MAX_FLIPS_EXCEEDED;
|
||||
i = bitcount[c]; /* Get the number of consecutive bits */
|
||||
iLen += i; /* Add this length to total run length */
|
||||
c <<= i;
|
||||
cBits -= i; /* Minus the number in a byte */
|
||||
if (cBits <= 0)
|
||||
{
|
||||
iLen += cBits; /* Adjust length */
|
||||
cBits = 8;
|
||||
c = *buf++; /* Get another data byte */
|
||||
iCount--;
|
||||
continue; /* Keep doing white until color change */
|
||||
}
|
||||
c = ~c; /* flip color to count black pixels */
|
||||
/* Store the white run length */
|
||||
xborder -= iLen;
|
||||
if (xborder < 0)
|
||||
{
|
||||
iLen += xborder; /* Make sure run length is not past end */
|
||||
break;
|
||||
}
|
||||
x += iLen;
|
||||
*pDest++ = x;
|
||||
iLen = 0;
|
||||
doblack:
|
||||
i = bitcount[c]; /* Get consecutive bits */
|
||||
iLen += i; /* Add to total run length */
|
||||
c <<= i;
|
||||
cBits -= i;
|
||||
if (cBits <= 0)
|
||||
{
|
||||
iLen += cBits; /* Adjust length */
|
||||
cBits = 8;
|
||||
c = *buf++; /* Get another data byte */
|
||||
c = ~c; /* Flip color to find black */
|
||||
iCount--;
|
||||
if (iCount < 0)
|
||||
break;
|
||||
goto doblack;
|
||||
}
|
||||
/* Store the black run length */
|
||||
c = ~c; /* Flip color again to find white pixels */
|
||||
xborder -= iLen;
|
||||
if (xborder < 0)
|
||||
{
|
||||
iLen += xborder; /* Make sure run length is not past end */
|
||||
break;
|
||||
}
|
||||
x += iLen;
|
||||
*pDest++ = x;
|
||||
iLen = 0;
|
||||
} /* while */
|
||||
|
||||
x += iLen;
|
||||
if (pDest >= pLimit) return G5_MAX_FLIPS_EXCEEDED;
|
||||
*pDest++ = x;
|
||||
*pDest++ = x; // Store a few more XSIZE to end the line
|
||||
*pDest++ = x; // so that the compressor doesn't go past
|
||||
*pDest++ = x; // the end of the line
|
||||
return G5_SUCCESS;
|
||||
} /* G5ENCEncodeLine() */
|
||||
//
|
||||
// Compress a line of pixels and add it to the output
|
||||
// the input format is expected to be MSB (most significant bit) first
|
||||
// for example, pixel 0 is in byte 0 at bit 7 (0x80)
|
||||
// Returns G5ENC_SUCCESS for each line if all is well and G5ENC_IMAGE_COMPLETE
|
||||
// for the last line
|
||||
//
|
||||
int g5_encode_encodeLine(G5ENCIMAGE *pImage, uint8_t *pPixels)
|
||||
{
|
||||
int16_t a0, a0_c, b2, a1;
|
||||
int dx, run1, run2;
|
||||
int xsize, iErr, iHighWater;
|
||||
int iCur, iRef, iLen;
|
||||
int iHLen; // number of bits for long horizontal codes
|
||||
int16_t *CurFlips, *RefFlips;
|
||||
BUFFERED_BITS bb;
|
||||
|
||||
if (pImage == NULL || pPixels == NULL)
|
||||
return G5_INVALID_PARAMETER;
|
||||
iHighWater = pImage->iOutSize - 32;
|
||||
iHLen = 32 - __builtin_clz(pImage->iWidth);
|
||||
memcpy(&bb, &pImage->bb, sizeof(BUFFERED_BITS)); // keep local copy
|
||||
CurFlips = pImage->pCur;
|
||||
RefFlips = pImage->pRef;
|
||||
xsize = pImage->iWidth; /* For performance reasons */
|
||||
|
||||
// Convert the incoming line of pixels into run-end data
|
||||
iErr = G5ENCEncodeLine(pPixels, pImage->iWidth, CurFlips);
|
||||
if (iErr != G5_SUCCESS) return iErr; // exceeded the maximum number of color changes
|
||||
/* Encode this line as G5 */
|
||||
a0 = a0_c = 0;
|
||||
iCur = iRef = 0;
|
||||
while (a0 < xsize) {
|
||||
b2 = RefFlips[iRef+1];
|
||||
a1 = CurFlips[iCur];
|
||||
if (b2 < a1) { /* Is b2 to the left of a1? */
|
||||
/* yes, do pass mode */
|
||||
a0 = b2;
|
||||
iRef += 2;
|
||||
G5ENCInsertCode(&bb, 1, 4); /* Pass code = 0001 */
|
||||
} else { /* Try vertical and horizontal mode */
|
||||
dx = RefFlips[iRef] - a1; /* b1 - a1 */
|
||||
if (dx > 3 || dx < -3) { /* Horizontal mode */
|
||||
G5ENCInsertCode(&bb, 1, 3); /* Horizontal code = 001 */
|
||||
run1 = CurFlips[iCur] - a0;
|
||||
run2 = CurFlips[iCur+1] - CurFlips[iCur];
|
||||
if (run1 < 8) {
|
||||
if (run2 < 8) { // short, short
|
||||
G5ENCInsertCode(&bb, HORIZ_SHORT_SHORT, 2); /* short, short = 00 */
|
||||
G5ENCInsertCode(&bb, run1, 3);
|
||||
G5ENCInsertCode(&bb, run2, 3);
|
||||
} else { // short, long
|
||||
G5ENCInsertCode(&bb, HORIZ_SHORT_LONG, 2); /* short, long = 01 */
|
||||
G5ENCInsertCode(&bb, run1, 3);
|
||||
G5ENCInsertCode(&bb, run2, iHLen);
|
||||
}
|
||||
} else { // first run is long
|
||||
if (run2 < 8) { // long, short
|
||||
G5ENCInsertCode(&bb, HORIZ_LONG_SHORT, 2); /* long, short = 10 */
|
||||
G5ENCInsertCode(&bb, run1, iHLen);
|
||||
G5ENCInsertCode(&bb, run2, 3);
|
||||
} else { // long, long
|
||||
G5ENCInsertCode(&bb, HORIZ_LONG_LONG, 2); /* long, long = 11 */
|
||||
G5ENCInsertCode(&bb, run1, iHLen);
|
||||
G5ENCInsertCode(&bb, run2, iHLen);
|
||||
}
|
||||
}
|
||||
a0 = CurFlips[iCur+1]; /* a0 = a2 */
|
||||
if (a0 != xsize) {
|
||||
iCur += 2; /* Skip two color flips */
|
||||
while (RefFlips[iRef] != xsize && RefFlips[iRef] <= a0) {
|
||||
iRef += 2;
|
||||
}
|
||||
}
|
||||
} else { /* Vertical mode */
|
||||
dx = (dx + 3) * 2; /* Convert to index table */
|
||||
G5ENCInsertCode(&bb, vtable[dx], vtable[dx+1]);
|
||||
a0 = a1;
|
||||
a0_c = 1-a0_c;
|
||||
if (a0 != xsize) {
|
||||
if (iRef != 0) {
|
||||
iRef -= 2;
|
||||
}
|
||||
iRef++; /* Skip a color change in cur and ref */
|
||||
iCur++;
|
||||
while (RefFlips[iRef] <= a0 && RefFlips[iRef] != xsize) {
|
||||
iRef += 2;
|
||||
}
|
||||
}
|
||||
} /* vertical mode */
|
||||
} /* horiz/vert mode */
|
||||
} /* while x < xsize */
|
||||
iLen = (int)(bb.pBuf-pImage->pOutBuf);
|
||||
if (iLen >= iHighWater) { // not enough space
|
||||
pImage->iError = iErr = G5_DATA_OVERFLOW; // we don't have a better error
|
||||
return iErr;
|
||||
}
|
||||
if (pImage->y == pImage->iHeight-1) { // last line of image
|
||||
G5ENCFlushBits(&bb); // output the final buffered bits
|
||||
// wrap up final output
|
||||
pImage->iDataSize = (int)(bb.pBuf-pImage->pOutBuf);
|
||||
iErr = G5_ENCODE_COMPLETE;
|
||||
}
|
||||
pImage->pCur = RefFlips; // swap current and reference lines
|
||||
pImage->pRef = CurFlips;
|
||||
pImage->y++;
|
||||
memcpy(&pImage->bb, &bb, sizeof(bb));
|
||||
return iErr;
|
||||
} /* g5_encode_encodeLine() */
|
||||
//
|
||||
// Returns the number of bytes of G5 created by the encoder
|
||||
//
|
||||
int g5_encode_getOutSize(G5ENCIMAGE *pImage)
|
||||
{
|
||||
int iSize = 0;
|
||||
if (pImage != NULL)
|
||||
iSize = pImage->iDataSize;
|
||||
return iSize;
|
||||
} /* g5_encode_getOutSize() */
|
||||
@@ -15,6 +15,12 @@
|
||||
#include "ips_display.h"
|
||||
#endif
|
||||
|
||||
#include "commstructs.h"
|
||||
#ifndef SAVE_SPACE
|
||||
#include "g5/Group5.h"
|
||||
#include "g5/g5enc.inl"
|
||||
#endif
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
@@ -80,12 +86,11 @@ uint32_t colorDistance(Color &c1, Color &c2, Error &e1) {
|
||||
}
|
||||
|
||||
void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t buffer_size, bool is_red) {
|
||||
|
||||
uint8_t rotate = imageParams.rotate;
|
||||
long bufw = spr.width(), bufh = spr.height();
|
||||
|
||||
if (imageParams.rotatebuffer % 2) {
|
||||
//turn the image 90 or 270
|
||||
// turn the image 90 or 270
|
||||
rotate = (rotate + 3) % 4;
|
||||
rotate = (rotate + (imageParams.rotatebuffer - 1)) % 4;
|
||||
bufw = spr.height();
|
||||
@@ -112,6 +117,7 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
||||
{12, 5, 14, 6},
|
||||
{3, 11, 1, 8},
|
||||
{15, 7, 13, 4}};
|
||||
size_t bitOffset = 0;
|
||||
|
||||
memset(error_bufferold, 0, bufw * sizeof(Error));
|
||||
for (uint16_t y = 0; y < bufh; y++) {
|
||||
@@ -134,10 +140,10 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
||||
|
||||
if (imageParams.dither == 2) {
|
||||
// Ordered dithering
|
||||
uint8_t ditherValue = ditherMatrix[y % 4][x % 4];
|
||||
error_bufferold[x].r = (ditherValue << 4) - 120; // * 256 / 16 - 128 + 8
|
||||
error_bufferold[x].g = (ditherValue << 4) - 120;
|
||||
error_bufferold[x].b = (ditherValue << 4) - 120;
|
||||
uint8_t ditherValue = ditherMatrix[y % 4][x % 4] << (imageParams.bpp >= 3 ? 2 : 4);
|
||||
error_bufferold[x].r = ditherValue - (imageParams.bpp >= 3 ? 30 : 120); // * 256 / 16 - 128 + 8
|
||||
error_bufferold[x].g = ditherValue - (imageParams.bpp >= 3 ? 30 : 120);
|
||||
error_bufferold[x].b = ditherValue - (imageParams.bpp >= 3 ? 30 : 120);
|
||||
}
|
||||
|
||||
int best_color_index = 0;
|
||||
@@ -151,24 +157,40 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
||||
best_color_index = i;
|
||||
}
|
||||
}
|
||||
uint8_t bitIndex = 7 - (x % 8);
|
||||
uint32_t byteIndex = (y * bufw + x) / 8;
|
||||
|
||||
// this looks a bit ugly, but it's performing better than shorter notations
|
||||
switch (best_color_index) {
|
||||
case 1:
|
||||
if (!is_red)
|
||||
if (imageParams.bpp == 3 || imageParams.bpp == 4) {
|
||||
size_t byteIndex = bitOffset / 8;
|
||||
uint8_t bitIndex = bitOffset % 8;
|
||||
|
||||
if (bitIndex + imageParams.bpp <= 8) {
|
||||
buffer[byteIndex] |= best_color_index << (8 - bitIndex - imageParams.bpp);
|
||||
} else {
|
||||
uint8_t highPart = best_color_index >> (bitIndex + imageParams.bpp - 8);
|
||||
uint8_t lowPart = best_color_index & ((1 << (bitIndex + imageParams.bpp - 8)) - 1);
|
||||
buffer[byteIndex] |= highPart;
|
||||
buffer[byteIndex + 1] |= lowPart << (8 - (bitIndex + imageParams.bpp - 8));
|
||||
}
|
||||
bitOffset += imageParams.bpp;
|
||||
} else {
|
||||
uint8_t bitIndex = 7 - (x % 8);
|
||||
uint32_t byteIndex = (y * bufw + x) / 8;
|
||||
|
||||
// this looks a bit ugly, but it's performing better than shorter notations
|
||||
switch (best_color_index) {
|
||||
case 1:
|
||||
if (!is_red)
|
||||
buffer[byteIndex] |= (1 << bitIndex);
|
||||
break;
|
||||
case 2:
|
||||
imageParams.hasRed = true;
|
||||
if (is_red)
|
||||
buffer[byteIndex] |= (1 << bitIndex);
|
||||
break;
|
||||
case 3:
|
||||
imageParams.hasRed = true;
|
||||
buffer[byteIndex] |= (1 << bitIndex);
|
||||
break;
|
||||
case 2:
|
||||
imageParams.hasRed = true;
|
||||
if (is_red)
|
||||
buffer[byteIndex] |= (1 << bitIndex);
|
||||
break;
|
||||
case 3:
|
||||
imageParams.hasRed = true;
|
||||
buffer[byteIndex] |= (1 << bitIndex);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (imageParams.dither == 1) {
|
||||
@@ -226,7 +248,10 @@ size_t prepareHeader(uint8_t headerbuf[], uint16_t bufw, uint16_t bufh, imgParam
|
||||
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
|
||||
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
|
||||
|
||||
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||
if (imageParams.bpp == 3 || imageParams.bpp == 4) {
|
||||
totalbytes = buffer_size * imageParams.bpp + headersize;
|
||||
headerbuf[5] = imageParams.bpp;
|
||||
} else if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||
totalbytes = buffer_size * 2 + headersize;
|
||||
headerbuf[5] = 2;
|
||||
} else {
|
||||
@@ -266,6 +291,32 @@ void rewriteHeader(File &f_out) {
|
||||
f_out.write(flg);
|
||||
}
|
||||
|
||||
#ifndef SAVE_SPACE
|
||||
uint8_t *g5Compress(uint16_t width, uint16_t height, uint8_t *buffer, uint16_t buffersize, uint16_t &outBufferSize) {
|
||||
G5ENCIMAGE g5enc;
|
||||
int rc;
|
||||
uint8_t *outbuffer = (uint8_t *)ps_malloc(buffersize + 16384);
|
||||
if (outbuffer == NULL) {
|
||||
Serial.println("Failed to allocate the output buffer for the G5 encoder");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rc = g5_encode_init(&g5enc, width, height, outbuffer, buffersize + 16384);
|
||||
for (int y = 0; y < height && rc == G5_SUCCESS; y++) {
|
||||
rc = g5_encode_encodeLine(&g5enc, buffer);
|
||||
buffer += (width / 8);
|
||||
}
|
||||
if (rc == G5_ENCODE_COMPLETE) {
|
||||
outBufferSize = g5_encode_getOutSize(&g5enc);
|
||||
} else {
|
||||
printf("Encode failed! rc=%d\n", rc);
|
||||
free(outbuffer);
|
||||
return nullptr;
|
||||
}
|
||||
return outbuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
long t = millis();
|
||||
|
||||
@@ -274,11 +325,11 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
if (fileout == "direct") {
|
||||
if (tftOverride == false) {
|
||||
TFT_eSprite spr2 = TFT_eSprite(&tft2);
|
||||
#ifdef ST7735_NANO_TLSR
|
||||
#ifdef ST7735_NANO_TLSR
|
||||
tft2.setRotation(1);
|
||||
#else
|
||||
#else
|
||||
tft2.setRotation(YellowSense == 1 ? 1 : 3);
|
||||
#endif
|
||||
#endif
|
||||
spr2.createSprite(spr.width(), spr.height());
|
||||
spr2.setColorDepth(spr.getColorDepth());
|
||||
|
||||
@@ -287,20 +338,19 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
size_t dataSize = spr.width() * spr.height() * (spr.getColorDepth() / 8);
|
||||
memcpy(spriteData2, spriteData, dataSize);
|
||||
|
||||
#ifdef HAS_LILYGO_TPANEL
|
||||
if (spr.getColorDepth() == 16)
|
||||
{
|
||||
long dy = spr.height();
|
||||
long dx = spr.width();
|
||||
|
||||
uint16_t* data = static_cast<uint16_t*>(const_cast<void*>(spriteData2));
|
||||
#ifdef HAS_LILYGO_TPANEL
|
||||
if (spr.getColorDepth() == 16) {
|
||||
long dy = spr.height();
|
||||
long dx = spr.width();
|
||||
|
||||
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData2, dx, dy);
|
||||
spr2.deleteSprite();
|
||||
}
|
||||
#else
|
||||
uint16_t *data = static_cast<uint16_t *>(const_cast<void *>(spriteData2));
|
||||
|
||||
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData2, dx, dy);
|
||||
spr2.deleteSprite();
|
||||
}
|
||||
#else
|
||||
spr2.pushSprite(0, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -319,6 +369,7 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
#else
|
||||
uint8_t *buffer = (uint8_t *)malloc(buffer_size);
|
||||
imageParams.zlib = 0;
|
||||
imageParams.g5 = 0;
|
||||
#endif
|
||||
if (!buffer) {
|
||||
Serial.println("Failed to allocate buffer");
|
||||
@@ -359,6 +410,70 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
free(comp);
|
||||
|
||||
rewriteHeader(f_out);
|
||||
#ifndef SAVE_SPACE
|
||||
} else if (imageParams.g5) {
|
||||
// handling for G5-compressed image data
|
||||
|
||||
uint8_t headerbuf[6];
|
||||
prepareHeader(headerbuf, bufw, bufh, imageParams, buffer_size);
|
||||
f_out.write(headerbuf, sizeof(headerbuf));
|
||||
|
||||
uint16_t height = imageParams.height; // spr.height();
|
||||
uint16_t width = imageParams.width;
|
||||
spr.width();
|
||||
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||
uint8_t *newbuffer = (uint8_t *)ps_realloc(buffer, 2 * buffer_size);
|
||||
if (newbuffer == NULL) {
|
||||
Serial.println("Failed to allocate larger buffer for 2bpp G5");
|
||||
free(buffer);
|
||||
f_out.close();
|
||||
xSemaphoreGive(fsMutex);
|
||||
return;
|
||||
}
|
||||
buffer = newbuffer;
|
||||
spr2color(spr, imageParams, buffer + buffer_size, buffer_size, true);
|
||||
buffer_size *= 2;
|
||||
// double the height, to do two layers sequentially
|
||||
if (imageParams.rotatebuffer % 2) {
|
||||
width *= 2;
|
||||
} else {
|
||||
height *= 2;
|
||||
}
|
||||
|
||||
}
|
||||
uint16_t outbufferSize = 0;
|
||||
uint8_t *outBuffer;
|
||||
bool compressionSuccessful = true;
|
||||
if (imageParams.rotatebuffer % 2) {
|
||||
outBuffer = g5Compress(height, width, buffer, buffer_size, outbufferSize);
|
||||
} else {
|
||||
outBuffer = g5Compress(width, height, buffer, buffer_size, outbufferSize);
|
||||
}
|
||||
if (outBuffer == NULL) {
|
||||
Serial.println("Failed to compress G5");
|
||||
compressionSuccessful = false;
|
||||
} else {
|
||||
printf("Compressed %d to %d bytes\n", buffer_size, outbufferSize);
|
||||
if (outbufferSize > buffer_size) {
|
||||
printf("That wasn't very useful, falling back to raw\n");
|
||||
compressionSuccessful = false;
|
||||
f_out.seek(0);
|
||||
} else {
|
||||
f_out.write(outBuffer, outbufferSize);
|
||||
}
|
||||
free(outBuffer);
|
||||
}
|
||||
if (!compressionSuccessful) {
|
||||
// if we failed to compress the image, or the resulting image was larger than a raw file, fallback
|
||||
imageParams.g5 = false;
|
||||
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
|
||||
} else {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_1BPP;
|
||||
}
|
||||
f_out.write(buffer, buffer_size);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
f_out.write(buffer, buffer_size);
|
||||
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||
@@ -370,6 +485,24 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
free(buffer);
|
||||
} break;
|
||||
|
||||
case 3:
|
||||
case 4: {
|
||||
long bufw = spr.width(), bufh = spr.height();
|
||||
size_t buffer_size = (bufw * bufh) / 8 * imageParams.bpp;
|
||||
uint8_t *buffer = (uint8_t *)ps_malloc(buffer_size);
|
||||
if (!buffer) {
|
||||
Serial.println("Failed to allocate buffer");
|
||||
util::printLargestFreeBlock();
|
||||
f_out.close();
|
||||
xSemaphoreGive(fsMutex);
|
||||
return;
|
||||
}
|
||||
spr2color(spr, imageParams, buffer, buffer_size, false);
|
||||
f_out.write(buffer, buffer_size);
|
||||
|
||||
free(buffer);
|
||||
} break;
|
||||
|
||||
case 16: {
|
||||
size_t spriteDataSize = (spr.getColorDepth() == 1) ? (spr.width() * spr.height() / 8) : ((spr.getColorDepth() == 8) ? (spr.width() * spr.height()) : ((spr.getColorDepth() == 16) ? (spr.width() * spr.height() * 2) : 0));
|
||||
f_out.write((const uint8_t *)spr.getPointer(), spriteDataSize);
|
||||
|
||||
@@ -273,7 +273,9 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
case DATATYPE_IMG_DIFF:
|
||||
case DATATYPE_IMG_ZLIB:
|
||||
case DATATYPE_IMG_RAW_1BPP:
|
||||
case DATATYPE_IMG_RAW_2BPP: {
|
||||
case DATATYPE_IMG_RAW_2BPP:
|
||||
case DATATYPE_IMG_G5:
|
||||
case DATATYPE_IMG_RAW_3BPP: {
|
||||
char hexmac[17];
|
||||
mac2hex(pending->targetMac, hexmac);
|
||||
String filename = "/current/" + String(hexmac) + "_" + String(millis() % 1000000) + ".pending";
|
||||
@@ -445,7 +447,7 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
|
||||
contentFS->remove(dst_path);
|
||||
}
|
||||
if (contentFS->exists(queueItem->filename)) {
|
||||
if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
|
||||
if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_3BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_G5 || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
|
||||
contentFS->rename(queueItem->filename, String(dst_path));
|
||||
} else {
|
||||
if (queueItem->pendingdata.availdatainfo.dataType != DATATYPE_FW_UPDATE) contentFS->remove(queueItem->filename);
|
||||
@@ -966,7 +968,7 @@ bool queueDataAvail(struct pendingData* pending, bool local) {
|
||||
}
|
||||
newPending.len = taginfo->len;
|
||||
|
||||
if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
|
||||
if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_3BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB || pending->availdatainfo.dataType == DATATYPE_IMG_G5) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
|
||||
// in case of an image (no preload), remove already queued images
|
||||
pendingQueue.erase(std::remove_if(pendingQueue.begin(), pendingQueue.end(),
|
||||
[pending](const PendingItem& item) {
|
||||
|
||||
@@ -334,9 +334,9 @@ void initAPconfig() {
|
||||
config.sleepTime2 = APconfig.containsKey("sleeptime2") ? APconfig["sleeptime2"] : 0;
|
||||
config.ble = APconfig.containsKey("ble") ? APconfig["ble"] : 0;
|
||||
config.discovery = APconfig.containsKey("discovery") ? APconfig["discovery"] : 0;
|
||||
#ifdef BLE_ONLY
|
||||
#ifdef BLE_ONLY
|
||||
config.ble = true;
|
||||
#endif
|
||||
#endif
|
||||
// default wifi power 8.5 dbM
|
||||
// see https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.h#L111
|
||||
config.wifiPower = APconfig.containsKey("wifipower") ? APconfig["wifipower"] : 34;
|
||||
@@ -395,6 +395,7 @@ HwType getHwType(const uint8_t id) {
|
||||
filter["bpp"] = true;
|
||||
filter["shortlut"] = true;
|
||||
filter["zlib_compression"] = true;
|
||||
filter["g5_compression"] = true;
|
||||
filter["highlight_color"] = true;
|
||||
filter["colortable"] = true;
|
||||
StaticJsonDocument<1000> doc;
|
||||
@@ -416,6 +417,11 @@ HwType getHwType(const uint8_t id) {
|
||||
} else {
|
||||
hwType.zlib = 0;
|
||||
}
|
||||
if (doc.containsKey("g5_compression")) {
|
||||
hwType.g5 = strtol(doc["g5_compression"], nullptr, 16);
|
||||
} else {
|
||||
hwType.g5 = 0;
|
||||
}
|
||||
hwType.highlightColor = doc.containsKey("highlight_color") ? doc["highlight_color"].as<uint16_t>() : 2;
|
||||
JsonObject colorTable = doc["colortable"];
|
||||
for (auto kv : colorTable) {
|
||||
|
||||
@@ -593,21 +593,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "Send custom LUT",
|
||||
"desc": "EXPERIMENTAL. Don't use. YOU RISK DAMAGING YOUR SCREEN.",
|
||||
"capabilities": 4,
|
||||
"properties": [ "savespace" ],
|
||||
"param": [
|
||||
{
|
||||
"key": "bytes",
|
||||
"name": "bytes",
|
||||
"desc": "76 bytes, formatted as 0x00,0x00,...",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "Send Command",
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
|
||||
const canvas = $('#previewimg');
|
||||
canvas.style.display = 'block';
|
||||
fetch(path)
|
||||
fetch(path + "?r=" + Math.random())
|
||||
.then(response => response.arrayBuffer())
|
||||
.then(buffer => {
|
||||
|
||||
@@ -433,6 +433,16 @@
|
||||
if (tagTypes[hwtype].zlib > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].zlib) {
|
||||
data = window.opener.processZlib(data);
|
||||
}
|
||||
if (data.length > 0 && tagTypes[hwtype].g5 > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].g5) {
|
||||
const headerSize = data[0];
|
||||
let bufw = (data[2] << 8) | data[1];
|
||||
let bufh = (data[4] << 8) | data[3];
|
||||
if ((bufw == tagTypes[hwtype].width || bufw == tagTypes[hwtype].height) && (bufh == tagTypes[hwtype].width || bufh == tagTypes[hwtype].height) && (data[5] <= 3)) {
|
||||
// valid header for g5 compression
|
||||
if (data[5] == 2) bufh *= 2;
|
||||
data = window.opener.processG5(data.subarray(headerSize), bufw, bufh);
|
||||
}
|
||||
}
|
||||
|
||||
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
|
||||
if (tagTypes[hwtype].rotatebuffer%2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
||||
@@ -452,7 +462,27 @@
|
||||
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
|
||||
imageData.data[i * 4 + 3] = 255;
|
||||
}
|
||||
} else if (tagTypes[hwtype].bpp == 3) {
|
||||
const colorTable = tagTypes[hwtype].colortable;
|
||||
|
||||
let pixelIndex = 0;
|
||||
for (let i = 0; i < data.length; i += 3) {
|
||||
for (let j = 0; j < 8; j++) {
|
||||
let bitPos = j * 3;
|
||||
let bytePos = Math.floor(bitPos / 8);
|
||||
let bitOffset = bitPos % 8;
|
||||
let pixelValue = (data[i + bytePos] >> (5 - bitOffset)) & 0x07;
|
||||
if (bitOffset > 5) {
|
||||
pixelValue = ((data[i + bytePos] & (0xFF >> bitOffset)) << (bitOffset - 5)) |
|
||||
(data[i + bytePos + 1] >> (13 - bitOffset));
|
||||
}
|
||||
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
|
||||
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
|
||||
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
|
||||
imageData.data[pixelIndex * 4 + 3] = 255;
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
|
||||
|
||||
377
ESP32_AP-Flasher/wwwroot/g5decoder.js
Normal file
377
ESP32_AP-Flasher/wwwroot/g5decoder.js
Normal file
@@ -0,0 +1,377 @@
|
||||
//
|
||||
// Group5
|
||||
// A 1-bpp image decoder
|
||||
//
|
||||
// Written by Larry Bank
|
||||
// Copyright (c) 2024 BitBank Software, Inc.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file ./LICENSE.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// ./APL.txt.
|
||||
|
||||
// Converted from C to Javascript by Nic Limper
|
||||
|
||||
// Define constants
|
||||
const MAX_IMAGE_FLIPS = 640;
|
||||
|
||||
// Horizontal prefix bits
|
||||
const HORIZ_SHORT_SHORT = 0;
|
||||
const HORIZ_SHORT_LONG = 1;
|
||||
const HORIZ_LONG_SHORT = 2;
|
||||
const HORIZ_LONG_LONG = 3;
|
||||
|
||||
// Return code for encoder and decoder
|
||||
const G5_SUCCESS = 0;
|
||||
const G5_INVALID_PARAMETER = 1;
|
||||
const G5_DECODE_ERROR = 2;
|
||||
const G5_UNSUPPORTED_FEATURE = 3;
|
||||
const G5_ENCODE_COMPLETE = 4;
|
||||
const G5_DECODE_COMPLETE = 5;
|
||||
const G5_NOT_INITIALIZED = 6;
|
||||
const G5_DATA_OVERFLOW = 7;
|
||||
const G5_MAX_FLIPS_EXCEEDED = 8;
|
||||
|
||||
// Utility function equivalent to the TIFFMOTOLONG macro
|
||||
function TIFFMOTOLONG(p, ix) {
|
||||
let value = 0;
|
||||
if (ix < p.length) value |= p[ix] << 24;
|
||||
if (ix + 1 < p.length) value |= p[ix + 1] << 16;
|
||||
if (ix + 2 < p.length) value |= p[ix + 2] << 8;
|
||||
if (ix + 3 < p.length) value |= p[ix + 3];
|
||||
return value;
|
||||
}
|
||||
|
||||
// Constants for bit manipulation
|
||||
const REGISTER_WIDTH = 32; // Must align with a 32-bit system in C++
|
||||
|
||||
/*
|
||||
The code tree that follows has: bit_length, decode routine
|
||||
These codes are for Group 4 (MMR) decoding
|
||||
|
||||
01 = vertneg1, 11h = vert1, 20h = horiz, 30h = pass, 12h = vert2
|
||||
02 = vertneg2, 13h = vert3, 03 = vertneg3, 90h = trash
|
||||
*/
|
||||
|
||||
const code_table = [
|
||||
0x90, 0, 0x40, 0, // trash, uncompressed mode - codes 0 and 1
|
||||
3, 7, // V(-3) pos = 2
|
||||
0x13, 7, // V(3) pos = 3
|
||||
2, 6, 2, 6, // V(-2) pos = 4,5
|
||||
0x12, 6, 0x12, 6, // V(2) pos = 6,7
|
||||
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4, // pass pos = 8->F
|
||||
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4,
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, // horiz pos = 10->1F
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, // V(-1) pos = 20->2F
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 1, 3,
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3, // V(1) pos = 30->3F
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3
|
||||
];
|
||||
|
||||
class G5DECIMAGE {
|
||||
constructor() {
|
||||
this.iWidth = 0;
|
||||
this.iHeight = 0;
|
||||
this.iError = 0;
|
||||
this.y = 0;
|
||||
this.iVLCSize = 0;
|
||||
this.iHLen = 0;
|
||||
this.iPitch = 0;
|
||||
this.u32Accum = 0;
|
||||
this.ulBitOff = 0;
|
||||
this.ulBits = 0;
|
||||
this.pSrc = null; // Input buffer
|
||||
this.pBuf = null; // Current buffer index
|
||||
this.pBufIndex = 0;
|
||||
this.pCur = new Int16Array(MAX_IMAGE_FLIPS); // Current state
|
||||
this.pRef = new Int16Array(MAX_IMAGE_FLIPS); // Reference state
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//static int g5_decode_init(G5DECIMAGE *pImage, int iWidth, int iHeight, uint8_t *pData, int iDataSize)
|
||||
function g5_decode_init(pImage, iWidth, iHeight, pData, iDataSize) {
|
||||
if (
|
||||
pImage == null ||
|
||||
iWidth < 1 ||
|
||||
iHeight < 1 ||
|
||||
pData == null ||
|
||||
iDataSize < 1
|
||||
) {
|
||||
return G5_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pImage.iVLCSize = iDataSize;
|
||||
pImage.pSrc = pData;
|
||||
pImage.ulBitOff = 0;
|
||||
pImage.y = 0;
|
||||
pImage.ulBits = TIFFMOTOLONG(pData, 0); // Preload the first 32 bits of data
|
||||
pImage.iWidth = iWidth;
|
||||
pImage.iHeight = iHeight;
|
||||
|
||||
return G5_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//static void G5DrawLine(G5DECIMAGE *pPage, int16_t *pCurFlips, uint8_t *pOut)
|
||||
function G5DrawLine(pPage, pCurFlips, pOut) {
|
||||
const xright = pPage.iWidth;
|
||||
let pCurIndex = 0;
|
||||
|
||||
// Initialize output to white (0xff)
|
||||
const len = (xright + 7) >> 3; // Number of bytes to generate
|
||||
pOut.fill(0xff, 0, len);
|
||||
|
||||
let x = 0;
|
||||
while (x < xright) { // While the scaled x is within the window bounds
|
||||
const startX = pCurFlips[pCurIndex++]; // Black starting point
|
||||
const run = pCurFlips[pCurIndex++] - startX; // Get the black run
|
||||
|
||||
if (startX >= xright || run <= 0) break;
|
||||
|
||||
// Calculate visible run
|
||||
let visibleX = Math.max(0, startX);
|
||||
let visibleRun = Math.min(xright, startX + run) - visibleX;
|
||||
|
||||
if (visibleRun > 0) {
|
||||
const startByte = visibleX >> 3;
|
||||
const endByte = (visibleX + visibleRun) >> 3;
|
||||
|
||||
const lBit = (0xff << (8 - (visibleX & 7))) & 0xff; // Left bitmask based on the starting x position
|
||||
const rBit = 0xff >> ((visibleX + visibleRun) & 7); // Right bitmask based on the ending x position
|
||||
|
||||
if (endByte == startByte) {
|
||||
// If the run fits in a single byte, combine left and right bit masks
|
||||
pOut[startByte] &= (lBit | rBit);
|
||||
} else {
|
||||
// Mask the left-most byte
|
||||
pOut[startByte] &= lBit;
|
||||
|
||||
// Set intermediate bytes to 0
|
||||
for (let i = startByte + 1; i < endByte; i++) {
|
||||
pOut[i] = 0x00;
|
||||
}
|
||||
|
||||
// Mask the right-most byte if it's not fully aligned
|
||||
pOut[endByte] &= rBit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Initialize internal structures to decode the image
|
||||
//
|
||||
function Decode_Begin(pPage) {
|
||||
const xsize = pPage.iWidth;
|
||||
|
||||
// Seed the current and reference lines with xsize for V(0) codes
|
||||
for (let i = 0; i < MAX_IMAGE_FLIPS - 2; i++) {
|
||||
pPage.pRef[i] = xsize;
|
||||
pPage.pCur[i] = xsize;
|
||||
}
|
||||
|
||||
// Prefill both current and reference lines with 0x7fff to prevent walking off the end
|
||||
// if the data gets bunged and the current X is > XSIZE
|
||||
pPage.pCur[MAX_IMAGE_FLIPS - 2] = pPage.pRef[MAX_IMAGE_FLIPS - 2] = 0x7fff;
|
||||
pPage.pCur[MAX_IMAGE_FLIPS - 1] = pPage.pRef[MAX_IMAGE_FLIPS - 1] = 0x7fff;
|
||||
|
||||
pPage.pBuf = pPage.pSrc; // Start buffer
|
||||
pPage.pBufIndex = 0;
|
||||
|
||||
// Load 32 bits to start (use a helper function to interpret bytes as a 32-bit integer)
|
||||
pPage.ulBits = TIFFMOTOLONG(pPage.pSrc, 0);
|
||||
pPage.ulBitOff = 0;
|
||||
|
||||
// Calculate the number of bits needed for a long horizontal code
|
||||
pPage.iHLen = 32 - Math.clz32(pPage.iWidth); // clz32 counts leading zeroes in JavaScript
|
||||
}
|
||||
|
||||
|
||||
// Decode a single line of G5 data
|
||||
//
|
||||
function DecodeLine(pPage) {
|
||||
let a0 = -1;
|
||||
let a0_p, b1;
|
||||
let pCurIndex = 0, pRefIndex = 0;
|
||||
const pCur = pPage.pCur;
|
||||
const pRef = pPage.pRef;
|
||||
let ulBits = pPage.ulBits;
|
||||
let ulBitOff = pPage.ulBitOff;
|
||||
let pBufIndex = pPage.pBufIndex;
|
||||
const pBuf = pPage.pBuf;
|
||||
const xsize = pPage.iWidth;
|
||||
const u32HLen = pPage.iHLen;
|
||||
const u32HMask = (1 << u32HLen) - 1;
|
||||
let tot_run, tot_run1;
|
||||
|
||||
while (a0 < xsize) {
|
||||
if (ulBitOff > (REGISTER_WIDTH - 8)) {
|
||||
pBufIndex += (ulBitOff >> 3);
|
||||
ulBitOff &= 7;
|
||||
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
|
||||
}
|
||||
|
||||
if (((ulBits << ulBitOff) & 0x80000000) !== 0) {
|
||||
a0 = pRef[pRefIndex++];
|
||||
pCur[pCurIndex++] = a0;
|
||||
ulBitOff++;
|
||||
} else {
|
||||
const lBits = (ulBits >> (REGISTER_WIDTH - 8 - ulBitOff)) & 0xfe;
|
||||
const sCode = code_table[lBits];
|
||||
ulBitOff += code_table[lBits + 1];
|
||||
switch (sCode) {
|
||||
case 1: case 2: case 3: // V(-1), V(-2), V(-3)
|
||||
a0 = pRef[pRefIndex] - sCode; // A0 = B1 - x
|
||||
pCur[pCurIndex++] = a0;
|
||||
if (pRefIndex == 0) {
|
||||
pRefIndex += 2;
|
||||
}
|
||||
pRefIndex--;
|
||||
while (a0 >= pRef[pRefIndex]) {
|
||||
pRefIndex += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11: case 0x12: case 0x13: // V(1), V(2), V(3)
|
||||
a0 = pRef[pRefIndex++];
|
||||
b1 = a0;
|
||||
a0 += sCode & 7;
|
||||
if (b1 !== xsize && a0 < xsize) {
|
||||
while (a0 >= pRef[pRefIndex]) {
|
||||
pRefIndex += 2;
|
||||
}
|
||||
}
|
||||
if (a0 > xsize) {
|
||||
a0 = xsize;
|
||||
}
|
||||
pCur[pCurIndex++] = a0;
|
||||
break;
|
||||
|
||||
case 0x20: // Horizontal codes
|
||||
if (ulBitOff > (REGISTER_WIDTH - 16)) {
|
||||
pBufIndex += (ulBitOff >> 3);
|
||||
ulBitOff &= 7;
|
||||
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
|
||||
}
|
||||
|
||||
a0_p = Math.max(0, a0);
|
||||
const lBits = (ulBits >> ((REGISTER_WIDTH - 2) - ulBitOff)) & 0x3;
|
||||
ulBitOff += 2;
|
||||
|
||||
switch (lBits) {
|
||||
case HORIZ_SHORT_SHORT:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||
ulBitOff += 3;
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||
ulBitOff += 3;
|
||||
break;
|
||||
|
||||
case HORIZ_SHORT_LONG:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||
ulBitOff += 3;
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||
ulBitOff += u32HLen;
|
||||
break;
|
||||
|
||||
case HORIZ_LONG_SHORT:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||
ulBitOff += u32HLen;
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||
ulBitOff += 3;
|
||||
break;
|
||||
|
||||
case HORIZ_LONG_LONG:
|
||||
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||
ulBitOff += u32HLen;
|
||||
if (ulBitOff > (REGISTER_WIDTH - 16)) {
|
||||
pBufIndex += (ulBitOff >> 3);
|
||||
ulBitOff &= 7;
|
||||
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
|
||||
}
|
||||
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||
ulBitOff += u32HLen;
|
||||
break;
|
||||
}
|
||||
a0 = a0_p + tot_run;
|
||||
pCur[pCurIndex++] = a0;
|
||||
a0 += tot_run1;
|
||||
|
||||
if (a0 < xsize) {
|
||||
while (a0 >= pRef[pRefIndex]) {
|
||||
pRefIndex += 2;
|
||||
}
|
||||
}
|
||||
pCur[pCurIndex++] = a0;
|
||||
break;
|
||||
|
||||
case 0x30: // Pass code
|
||||
pRefIndex++;
|
||||
a0 = pRef[pRefIndex++];
|
||||
break;
|
||||
|
||||
default: // ERROR
|
||||
pPage.iError = G5_DECODE_ERROR;
|
||||
return pPage.iError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pCur[pCurIndex++] = xsize;
|
||||
pCur[pCurIndex++] = xsize;
|
||||
|
||||
pPage.ulBits = ulBits;
|
||||
pPage.ulBitOff = ulBitOff;
|
||||
pPage.pBufIndex = pBufIndex;
|
||||
|
||||
return pPage.iError;
|
||||
}
|
||||
|
||||
|
||||
function processG5(data, width, height) {
|
||||
try {
|
||||
let decoder = new G5DECIMAGE();
|
||||
let initResult = g5_decode_init(decoder, width, height, data, data.length);
|
||||
|
||||
if (initResult !== G5_SUCCESS) {
|
||||
throw new Error("Initialization failed with code: " + initResult);
|
||||
}
|
||||
|
||||
Decode_Begin(decoder);
|
||||
|
||||
let outputBuffer = new Uint8Array(height * ((width + 7) >> 3)); // Adjust for byte alignment
|
||||
|
||||
for (let y = 0; y < height; y++) {
|
||||
let lineBuffer = outputBuffer.subarray(y * ((width + 7) >> 3), (y + 1) * ((width + 7) >> 3));
|
||||
decoder.y = y;
|
||||
let decodeResult = DecodeLine(decoder);
|
||||
|
||||
if (decodeResult !== G5_SUCCESS) {
|
||||
console.log("Decoding error on line " + y + ": " + decoder.iError);
|
||||
}
|
||||
|
||||
G5DrawLine(decoder, decoder.pCur, lineBuffer);
|
||||
const temp = decoder.pRef;
|
||||
decoder.pRef = decoder.pCur;
|
||||
decoder.pCur = temp;
|
||||
}
|
||||
|
||||
return outputBuffer;
|
||||
} catch (error) {
|
||||
console.error("Error during G5 decoding:", error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||
|
||||
<title>Open EPaper Link Access Point</title>
|
||||
<script src="main.js" defer></script>
|
||||
<link rel="stylesheet" href="main.css" type="text/css" />
|
||||
<script src="main.js?2.74" defer></script>
|
||||
<script src="g5decoder.js?2.74"></script>
|
||||
<link rel="stylesheet" href="main.css?2.74" type="text/css" />
|
||||
<!--<link rel="icon" type="image/vnd.icon" href="favicon.ico">-->
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
|
||||
|
||||
@@ -1207,6 +1207,16 @@ function drawCanvas(buffer, canvas, hwtype, tagmac, doRotate) {
|
||||
if (data.length > 0 && tagTypes[hwtype].zlib > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].zlib) {
|
||||
data = processZlib(data);
|
||||
}
|
||||
if (data.length > 0 && tagTypes[hwtype].g5 > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].g5) {
|
||||
const headerSize = data[0];
|
||||
let bufw = (data[2] << 8) | data[1];
|
||||
let bufh = (data[4] << 8) | data[3];
|
||||
if ((bufw == tagTypes[hwtype].width || bufw == tagTypes[hwtype].height) && (bufh == tagTypes[hwtype].width || bufh == tagTypes[hwtype].height) && (data[5] <= 3)) {
|
||||
// valid header for g5 compression
|
||||
if (data[5] == 2) bufh *= 2;
|
||||
data = processG5(data.subarray(headerSize), bufw, bufh);
|
||||
}
|
||||
}
|
||||
|
||||
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
|
||||
if (tagTypes[hwtype].rotatebuffer % 2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
||||
@@ -1243,6 +1253,28 @@ function drawCanvas(buffer, canvas, hwtype, tagmac, doRotate) {
|
||||
imageData.data[i * 4 + 3] = 255;
|
||||
}
|
||||
|
||||
} else if (tagTypes[hwtype].bpp == 3) {
|
||||
const colorTable = tagTypes[hwtype].colortable;
|
||||
|
||||
let pixelIndex = 0;
|
||||
for (let i = 0; i < data.length; i += 3) {
|
||||
for (let j = 0; j < 8; j++) {
|
||||
let bitPos = j * 3;
|
||||
let bytePos = Math.floor(bitPos / 8);
|
||||
let bitOffset = bitPos % 8;
|
||||
let pixelValue = (data[i + bytePos] >> (5 - bitOffset)) & 0x07;
|
||||
if (bitOffset > 5) {
|
||||
pixelValue = ((data[i + bytePos] & (0xFF >> bitOffset)) << (bitOffset - 5)) |
|
||||
(data[i + bytePos + 1] >> (13 - bitOffset));
|
||||
}
|
||||
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
|
||||
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
|
||||
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
|
||||
imageData.data[pixelIndex * 4 + 3] = 255;
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
|
||||
@@ -1499,6 +1531,7 @@ async function getTagtype(hwtype) {
|
||||
contentids: Object.values(jsonData.contentids ?? []),
|
||||
options: Object.values(jsonData.options ?? []),
|
||||
zlib: parseInt(jsonData.zlib_compression || "0", 16),
|
||||
g5: parseInt(jsonData.g5_compression || "0", 16),
|
||||
shortlut: parseInt(jsonData.shortlut),
|
||||
busy: false,
|
||||
usetemplate: parseInt(jsonData.usetemplate || "0", 10)
|
||||
@@ -1746,7 +1779,7 @@ function populateAPCard(msg) {
|
||||
|
||||
function populateAPInfo(apip) {
|
||||
let apid = apip.replace(/\./g, "-");
|
||||
fetch('sysinfo')
|
||||
fetch('http://' + apip + '/sysinfo')
|
||||
.then(response => {
|
||||
if (response.status != 200) {
|
||||
$('#ap' + apid + ' .apswversion').innerHTML = "Error fetching sysinfo: " + response.status;
|
||||
@@ -1895,11 +1928,12 @@ function showPreview(previewWindow, element) {
|
||||
console.log('refresh ' + element.mac);
|
||||
previewWindow.pending = element.pending;
|
||||
previewWindow.hash = "";
|
||||
let cachetag = Date.now();
|
||||
|
||||
if (element.isexternal && element.contentMode == 12) {
|
||||
imageSrc = 'http://' + tagDB[element.mac].apip + '/getdata?mac=' + element.mac + '&md5=0000000000000000';
|
||||
imageSrc = 'http://' + tagDB[element.mac].apip + '/getdata?mac=' + element.mac + '&md5=0000000000000000&c=' + cachetag;
|
||||
} else {
|
||||
imageSrc = '/getdata?mac=' + element.mac + '&md5=0000000000000000';
|
||||
imageSrc = '/getdata?mac=' + element.mac + '&md5=0000000000000000&c=' + cachetag;
|
||||
}
|
||||
|
||||
} else if (element.hash != previewWindow.hash) {
|
||||
@@ -1924,4 +1958,4 @@ function showPreview(previewWindow, element) {
|
||||
console.error('fetch preview image error:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,16 +56,17 @@ export async function initUpdate() {
|
||||
.then(([sdata, rdata]) => {
|
||||
|
||||
if (sdata.env) {
|
||||
let matchtest = '';
|
||||
if (sdata.buildversion != filesystemversion && filesystemversion != "custom" && sdata.buildversion != "custom") matchtest = " <- not matching!"
|
||||
print(`env: ${sdata.env}`);
|
||||
print(`current env: ${sdata.env}`);
|
||||
print(`build date: ${formatEpoch(sdata.buildtime)}`);
|
||||
print(`esp32 version: ${sdata.buildversion}`);
|
||||
print(`filesystem version: ${filesystemversion}` + matchtest);
|
||||
print(`filesystem version: ${filesystemversion}`);
|
||||
print(`psram size: ${sdata.psramsize}`);
|
||||
print(`flash size: ${sdata.flashsize}`);
|
||||
print("--------------------------", "gray");
|
||||
env = sdata.env;
|
||||
env = apConfig.env || sdata.env;
|
||||
if (sdata.env != env) {
|
||||
print(`Warning: you selected a build environment ${env} which is\ndifferent than the currently used ${sdata.env}.\nOnly update the firmware with a mismatched build environment if\nyou know what you're doing.`, "yellow");
|
||||
}
|
||||
currentVer = sdata.buildversion;
|
||||
currentBuildtime = sdata.buildtime;
|
||||
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
|
||||
@@ -96,9 +97,9 @@ export async function initUpdate() {
|
||||
} else {
|
||||
const release = releaseDetails[0];
|
||||
if (release?.tag_name) {
|
||||
if (release.tag_name == currentVer) {
|
||||
if (normalizeVersion(release.tag_name) === normalizeVersion(currentVer)) {
|
||||
easyupdate.innerHTML = `Version ${currentVer}. You are up to date`;
|
||||
} else if (release.date < formatEpoch(currentBuildtime)) {
|
||||
} else if (release.date < formatEpoch(currentBuildtime - 30 * 60)) {
|
||||
easyupdate.innerHTML = `Your version is newer than the latest release date.<br>Are you the developer? :-)`;
|
||||
} else {
|
||||
easyupdate.innerHTML = `An update from version ${currentVer} to version ${release.tag_name} is available.<button onclick="otamodule.updateAll('${release.bin_url}','${release.file_url}','${release.tag_name}')">Update now!</button>`;
|
||||
@@ -637,3 +638,7 @@ async function fetchAndCheckTagtypes(cleanup) {
|
||||
print("Error: " + error, "red");
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeVersion(version) {
|
||||
return version.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
binaries/Tag/SOL_M2_154_SSD_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_154_SSD_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOL_M2_22_SSD_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_22_SSD_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOL_M2_26_SSD_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_26_SSD_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOL_M2_29_SSD_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_29_SSD_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOL_M2_29_UC_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_29_UC_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOL_M2_42_SSD_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_42_SSD_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOL_M2_42_UC_0029.bin
Normal file
BIN
binaries/Tag/SOL_M2_42_UC_0029.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/chroma29_full_0010.bin
Normal file
BIN
binaries/Tag/chroma29_full_0010.bin
Normal file
Binary file not shown.
996
binaries/Tag/chroma29_full_0010.hex
Normal file
996
binaries/Tag/chroma29_full_0010.hex
Normal file
@@ -0,0 +1,996 @@
|
||||
:040000000200833245
|
||||
:01000B0032C2
|
||||
:0100130032BA
|
||||
:01001B0032B2
|
||||
:0100230032AA
|
||||
:03002B00024A4343
|
||||
:01003300329A
|
||||
:01003B003292
|
||||
:0300430002500563
|
||||
:03004B0002496007
|
||||
:01005300327A
|
||||
:01005B003272
|
||||
:01006300326A
|
||||
:01006B003262
|
||||
:01007300325A
|
||||
:03007B00025B4CD9
|
||||
:0300FA0002007E83
|
||||
:03007E0002050672
|
||||
:2000FD00E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FBA6
|
||||
:20011D00004380040022AF8290F090E4F090F091F08F061FEE60767E0090F95AE0FDBD024E
|
||||
:20013D000BEE9062AF93FDBDC800405990F95AE0FDBD010BEE9062AF93FDBDC8005046EEA9
|
||||
:20015D0024AFFCE43462FD8C828D83E493F582C007C006C005C004121C5EE582D004D0057E
|
||||
:20017D00D006D007601F90F090E0FB90F0BFE0FAC3EB9A501090F090EAF08C828D83E4930B
|
||||
:20019D00FC90F091F00EBE0C005086808C90F091E0FFE06013BFC800400890F95A7402F030
|
||||
:2001BD00800690F95A7401F090F091E0F5822290F0EDE0FEA3E0FFC3742C9E74019F40099F
|
||||
:2001DD0090F0E3E0700330015E300A0920020690F0C6E0700930031E90F0C7E0601890FC37
|
||||
:2001FD0063E0FFBFFF02800B7824E4F28F821227818003123CFA121E2AAD82AE83AFF09064
|
||||
:20021D00F092EDF0EEA3F0EFA3F0ED4E602D90F0EDE4F0A3F010010090F0E3E06002D2013A
|
||||
:20023D0090F0E3E4F08014121F15AD82AE83AFF090F092EDF0EEA3F0EFA3F01218BE90F037
|
||||
:20025D0092E0FDA3E0FEA3E0FFED4E700990F0E1E4F0A3F08059740F2DFAE43EFB8F048AD6
|
||||
:20027D00828B838CF012628FFAA312628FFB90F0E1EAF0EBA3F0740D2DFAE43EFB8F048A1C
|
||||
:20029D00828B838CF012628F60168D828E838FF0123156E582701890F0E1E4F0A3F0800F3E
|
||||
:2002BD0074C0C0E07462C0E0125A4615811581121909AE82AF8390F0EDE0FCA3E0FD90F01A
|
||||
:2002DD00EDEE2CF0EF3DA3F0BE580CBF020990F0C5E06003C2002290FA5BE0600E90FA5BDB
|
||||
:2002FD00E4F0900064E4F5F002180990F0E1E0FEA3E0FF4E603BEF30E71F8E048F055305E0
|
||||
:20031D007F7877ECF2ED08F2E408F208F29003E8E4F5F0125F410218097877EEF2EF08F2E4
|
||||
:20033D00E408F208F290EA60E4F5F0125F41021809121909AE82AF837877EEF2EF08F2E41E
|
||||
:20035D0008F208F29003E8E4F5F0125F4102180990F0CEE0FF600D8F82121C5EE58290F94C
|
||||
:20037D0059F0800C758202120123E58290F959F090F959E0700920030690F0C7E0701430E4
|
||||
:20039D000A0920020690F0C6E0700890F0E4E0FFBF233690FC63E0FFBFFF02801A758202EB
|
||||
:2003BD00123E9AE582702290FC63E0FF7824E4F28F82122781801290F0E4E0FFBF2300403B
|
||||
:2003DD0005123E3B8003123DF890F959E0604890F0E4E4F090F0CEE0700F7582041217C46F
|
||||
:2003FD001214C77582041217FD90F0E374FDF09000281217A1121909AE82AF837877EEF227
|
||||
:20041D00EF08F2E408F208F29003E8E4F5F0125F41121809D20022758201121884AC82AD60
|
||||
:20043D0083AEF0FF7877ECF2ED08F2EE08F2EF08F29003E8E4F5F0125F41021809E582FF7B
|
||||
:20045D0024FA50030204EEEF2F2F90046B7302495C02047D0204940204C40204EE0204D003
|
||||
:20047D0074CBC0E07462C0E0125A4615811581C20090F959E4F02290F959E0FE74D8C0E0E6
|
||||
:20049D007462C0E0125A4615811581758204C0061217C41213811214C77582041217FDD0B9
|
||||
:2004BD000690F959EEF022123A19900000E4F5F002180974E8C0E07462C0E0125A4615819C
|
||||
:2004DD0015817582041217C412276D7582040217FD7E00C007C00674F8C0E07462C0E0122B
|
||||
:2004FD005A46E58124FCF581227582011217C475820F124C9E90FAB2E0FEA3E0FF7423C047
|
||||
:20051D00E08E828F831248A615817404C0E01243EFAC82AD83158190F0E5ECF0EDA3F09085
|
||||
:20053D0062BBE493C0E0740193C0E09062BDE493C0E0740193C0E0740293C0E0740AC0E08D
|
||||
:20055D007463C0E0125A46E58124F9F58112531B1219A212195A90F0E374FCF0AEBE530602
|
||||
:20057D00187F00BE1009BF000690F0E374FEF0301B0C123E94900000E4F5F01218097436F5
|
||||
:20059D00C0E074FCC0E0E4C0E07439C0E07463C0E0125A46E58124FBF58112374E900190E1
|
||||
:2005BD00E4F5F01218097582041217C41213F312373590F0C2E060117441C0E07463C0E045
|
||||
:2005DD00125A4615811581801B7452C0E07463C0E0125A4615811581123AC8902710E4F516
|
||||
:2005FD00F012180990F959E0FFE0601F8F82121C5EE5827025745FC0E07463C0E0125A4666
|
||||
:20061D001581158190F959E4F0800F747DC0E07463C0E0125A461581158190F959E0700331
|
||||
:20063D0012036D90F959E06007123CFAD2008005123DF8C2007582041217C41214C7300045
|
||||
:20065D00067E287F0080047E587F028E828F831217A130000A7C887D137E007F0080087CBC
|
||||
:1E067D00C07DD47E017F008C828D838EF0EF1218093000051201CC80F812036D80F311
|
||||
:2062AF00C864C965CA66CB67CC68CD6910008F63804E6F207570646174650A00434D445F8A
|
||||
:2062CF00444F5F5343414E0A0052657365742073657474696E67730A0045726173696E6727
|
||||
:2062EF0020696D616765730A00436D6420307825782069676E6F7265640A000A2573204F53
|
||||
:20630F0045504C2076253034782C20636F6D70696C656420417567202037203230323420A1
|
||||
:20632F0030393A32353A33320A004D41432025730A00446F696E67206661737420626F6FE9
|
||||
:20634F00740A004E6F726D616C20626F6F740A004E6F20415020666F756E64206F6E20732F
|
||||
:20636F0061766564206368616E6E656C0A004E6F207361766564206368616E6E656C0A0078
|
||||
:09638F004368726F6D6132390040
|
||||
:017671000117
|
||||
:20069B00E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB02
|
||||
:2006BB00004380040022AC82AD83AEF0FF00C2A00075820312435C8E8212435C8D82124309
|
||||
:2006DB005C8C8202435CC007C006C005C004C003C002C001C000AC82AD83AEF0FFE5812453
|
||||
:2006FB00F5F8860208860300C2A00075820312435C8E8212435C8D8212435C8C8212435C8C
|
||||
:20071B008A068B07E58124F3F886040886058C028D031CBCFF011DEA4B6015758200124301
|
||||
:20073B005CAB828E828F83EBF0A3AE82AF8380DE00D2A000D000D001D002D003D004D00554
|
||||
:20075B00D006D00722AF8200C2A0008F8212435C00D2A0002200C2A00075820512435C7542
|
||||
:20077B00820012435CE58220E0F500D2A00022AC82AD83AEF0FF7803E2FA08E2FBC007C07D
|
||||
:20079B0006C005C004C003C002120770758206120760D002D003D004D005D006D00700C26E
|
||||
:2007BB00A00075820212435C8E8212435C8D8212435C8C8212435C8A068B077805E2FC080F
|
||||
:2007DB00E2FD8C028D031CBCFF011DEA4B60128E828F83E0FBA3AE82AF838B8212435C8025
|
||||
:2007FB00E100D2A000221207707582B9120760C20C227582AB12076075F034D5F0FDD20C73
|
||||
:20081B0022C007C006C005C004C003C002C001C000C082C083C0F0C0E005810581E5812414
|
||||
:20083B00EFF88605088604E58124EDF8E608467003020915C005C004E58124F9F8860208CF
|
||||
:20085B007B00E58124FDF8E4C39AF674019B08F6E58124FDF8E58124EBF9C3E79609E70819
|
||||
:20087B0096D004D005500EE58124EDF8A98119E6F708E609F77803EDF2EC08F2A881187949
|
||||
:20089B0005E6F308E609F3E58124FBF886820886830886F008E6C007C006C005C004C0039A
|
||||
:2008BB00C002C001C000C02512078AD025D000D001D002D003D004D005D006D007A8811880
|
||||
:2008DB008602088603E4FEFFE58124FBF8EA26F6EB0836F6EE0836F6EF0836F6A88118E6F5
|
||||
:2008FB002DFD08E63CFCE58124EDF8A98119E6C397F608E60997F6020842E58124FAF581DB
|
||||
:20091B00D000D001D002D003D004D005D006D00722C007C006C005C004C003C002C001C0E2
|
||||
:20093B0000C082C083C0F0C0E0E58124FDF88602088603EA7005EB540F6006758200020A19
|
||||
:20095B002FE58124F1F8E608467003020A2C758206C007C006C005C004C003C002C001C0E2
|
||||
:20097B0000C025120760D025D000D001D002D003D004D005D006D00700C2A000E58124F190
|
||||
:20099B00F8860208860375822012435CE58124FDF80808868212435CE58124FDF80886828C
|
||||
:2009BB0012435CE58124FDF8868212435C00D2A000C007C006C005C004C003C002C001C0A5
|
||||
:2009DB0000C025120770D025D000D001D002D003D004D005D006D0077401C0E09010001236
|
||||
:2009FB0043EFAC82AD83AEF0FF1581E58124FDF8EC26F6ED0836F6EE0836F6EF0836F61A12
|
||||
:200A1B00BAFF011BE58124F1F8A60208A60302095C758201E58124FCF581D000D001D0024C
|
||||
:0B0A3B00D003D004D005D006D0072265
|
||||
:200A4600E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB53
|
||||
:200A6600004380040022C007C006C005C004AF82AE83ADF0FC90F0BBEFF0EEA3F0EDA3F05B
|
||||
:200A8600ECA3F0C202C203D208758204C007C006C005C004C003C002C001C000C025121749
|
||||
:200AA600C4D025D000D001D002D003D004D005D006D00790F0BBE0FCA3E0FDA3E0FEA3E040
|
||||
:200AC600FF7416C0E0E4C0E074F3C0E074F0C0E08C828D838EF0EF1206E1E58124FCF581D8
|
||||
:200AE60090F0BBE0FCA3E0FDA3E0FEA3E0FF90F0BB74162CF0E43DA3F0E43EA3F0E43FA346
|
||||
:200B0600F090F103E0FFBF2004C207806A90F103E0FFBF2104D207805E90F103E0FF7E0007
|
||||
:200B2600C007C0067480C0E07469C0E0125A46E58124FCF58190FA6E7416F0E4A3F090F0FA
|
||||
:200B4600F375F000C007C006C005C004C003C002C001C000C025121B11D025758204C02523
|
||||
:200B66001217FDD025D000D001D002D003D004D005D006D0078051C221C007C006C005C0F2
|
||||
:200B860004C003C002C001C000C025125C75D025C025120BD7D025D221C025125C75D0250A
|
||||
:200BA600C025120BD7D025758204C0251217FDD025C025125CB9D025D000D001D002D0031F
|
||||
:200BC600D004D005D006D007D004D005D006D007227F807E0090F0ABE4F0A3F090F0A5F01D
|
||||
:200BE600A3F05390FD007D00200803020C6A30211D20071A74A0C0E07404C0E0E4C0E090CD
|
||||
:200C0600F0F3124598158115811581020CBAC00590F0BBE0FAA3E0FBA3E0FCA3E0FD74A007
|
||||
:200C2600C0E07404C0E074F3C0E074F0C0E08A828B838CF0ED1206E1E58124FCF58190F0F3
|
||||
:200C4600BBE0FAA3E0FBA3E0FCA3E0FD90F0BB74A02AF074043BA3F0E43CA3F0E43DA3F066
|
||||
:200C6600D005805074A0C0E07404C0E0E4C0E090F0F31245981581158115817B4A7C00C054
|
||||
:200C860007C006C005C004C0037807E2F58208E2F583120081D003D004D005D006D00790AF
|
||||
:200CA600F0A5E02401F0A3E03400F01BBBFF011CEB4C70CB7B007C00EF60503021238E02FF
|
||||
:200CC600EA2AFEEB24F3F582EC34F0F583E0FAEF5A7003430601EF30E02B8E82125CAB8048
|
||||
:200CE600248E02EA2A25E0FEEB24F3F582EC34F0F583E0FAEF5A6003430603EF5411600597
|
||||
:200D06008E82125CABEFC313FF80AD7F800BBB00010CC3EB94A0EC9404409D90F0ABE0FB98
|
||||
:200D2600A3E0FC744A2BFBE43CFC90F0ABEBF0ECA3F00DBD04005003020BEEE58620E0FB27
|
||||
:200D4600004390020022AE82AF83C202C203C208D207C2217807EEF2EF08F2125C75120BDD
|
||||
:200D6600D7D221125C75120BD7025CB9C007C006C005C004C003C002C001C000AD82AE8339
|
||||
:200D8600AFF0A204202101B3505090F09FE0F508A3E0F50974012DFAE43EFB8F048A828B13
|
||||
:200DA600838CF012628FFA780CF2E408F2850882850983C007C006C005C004C003C002C062
|
||||
:200DC60001C000121003E582D000D001D002D003D004D005D006D0076003020FA98D828E6A
|
||||
:200DE600838FF0780912628FF290F0A1E0F508A3E0F5097809E2F50A750B00780EE50AF2AD
|
||||
:200E0600E50B08F2850882850983C007C006C005C004C003C002C001C00012107AD000D06A
|
||||
:200E260001D002D003D00490F0ADE0F508A3E0F50990F0B1E0FBA3E0FCEBC39508F582EC6E
|
||||
:200E46009509F5837875E50AF2E50B08F2C002C001C000125F21AB82AC83D000D001D0021A
|
||||
:200E6600D005D006D007ECC423CBC423541F6BCB541FCB6BCBFC90F0B7EBF0ECA3F0740245
|
||||
:200E86002BFBE43CFCEB2DFDEC3EFE90F0A7E0FBA3E0FCEB5407700A7809E2540770030259
|
||||
:200EA6000F5D5303078BF005F07B80E4FC3392D28008A2D2EC13FCEB13FBD5F0F5780AEB6A
|
||||
:200EC600F2780B7480F28D828E838FF012628FFA74012DF50CE43EF50D8F0E7809E2F50A4F
|
||||
:200EE600AC0A150AEC7003020FA9780BE25A6025C00290F0B5E0FAA3E0FCEA24F3FAEC344F
|
||||
:200F0600F0FC8A828C83E0FB780AE242038A828C83EBF0D002780BE2C313F2780BE270195D
|
||||
:200F2600850C82850D83850EF012628FFAA385820C85830D780B7480F2780AE2C313F2782B
|
||||
:200F46000AE2709C780A7480F290F0B5E02401F0A3E03400F080897809E2604790F0B5E032
|
||||
:200F6600FBA3E0FCEB24F3FBEC34F0FC8B828C83E0F50C8D828E838FF012628FFAA3AD827D
|
||||
:200F8600AE83E50C42028B828C83EAF090F0B5E02401F0A3E03400F07809E2FC780924F822
|
||||
:200FA600F280B4D000D001D002D003D004D005D006D0072290F0A7E0FEA3E0C423CEC42323
|
||||
:200FC600541F6ECE541FCE6ECE30E40244E0FF90F0ABE0FCA3E0FD90F0B1E0FAA3E0FBEAAC
|
||||
:200FE600C39CFCEB9DC454F0CCC4CC6CCC54F0CC6CFD90F0B5EC2EF0ED3FA3F022AE82AFF4
|
||||
:201006008390F095EEF0EFA3F090F0AFEEF0EFA3F07427C39EFE74019FFF90F0A9EEF0EF40
|
||||
:20102600A3F090F0A5E0FCA3E0FD90F0B1ECF0EDA3F0C3EE9CEF64808DF063F08095F040D4
|
||||
:201046002F780CE22CFC08E23DFDC3EE9CEF9D501F780CD3E29EF4B3FEB308E29FF4FF0EA8
|
||||
:20106600BE00010F90F0ADEEF0EFA3F07582002275820122AE82AF8390F0A7EEF0EFA3F0F3
|
||||
:20108600780E90F097E22EF008E23FA3F0120FBA75820022C007C006C005C004C003C00262
|
||||
:2010A600C001C000AC82AD83AEF0FF058105810581BF2000502C8F82C007C006C005C0049A
|
||||
:2010C600C003C002C001C000C0251242A7D025D000D001D002D003D004D005D006D0070291
|
||||
:2010E60013447E00EF24E0FFEE34FFFEEF2FFFEE33FEEF2498F582EE3463F583E493FEA391
|
||||
:20110600E493FF90F0B7EEF0EFA3F0EFC4540FFE90F0B3F0300507EE2EFE90F0B3F090F08C
|
||||
:2011260099E0FEA3E0FF90F0B9EEF0EFA3F090F0B3E0FDFB3395E0FC0BBB00010CEB2EFB81
|
||||
:20114600EC3FFC90F099EBF0ECA3F0A204202101B3504190F0B9E0FEA3E0FF780CEDF2EDDA
|
||||
:201166003395E008F28E828F83C007C006C005C004C003C002C001C000C025121003E58218
|
||||
:20118600D025D000D001D002D003D004D005D006D007600302134490F09BE0FEA3E0FF90F1
|
||||
:2011A600F0B4E0FD780EF2ED3395E008F28E828F83C007C006C005C004C003C002C001C063
|
||||
:2011C60000C02512107AD025D000D001D002D003D004D005D006D00790F0B7E0FEA3E0FF60
|
||||
:2011E60053070F90F0B7EEF0EFA3F0A8811818760008768090F0A7E0FCA3E05304078CF0BC
|
||||
:2012060005F07C80E4FD3392D28008A2D2ED13FDEC13FCD5F0F5A881A60490F0B3E0FD903E
|
||||
:20122600F0ADE0FAA3E0FB90F0A5E0FCA3E0FFECC39AFAEF9BFBED3395E0FFEDC39AFAEFA1
|
||||
:201246009BFB1ABAFF011B90F0B9EAF0EBA3F030050FEBC313CA13CAFB90F0B9EAF0EBA32A
|
||||
:20126600F090F0B9E0FEA3E0FF90F0B7E0FCA3E0FD90F0B7EE2CF0EF3DA3F090F0B7E0FE37
|
||||
:20128600A3E0FFEE2EFEEF33FFEE2458F582EF3464F583E493FEA3E493FF90F0B9E4F0A36D
|
||||
:2012A600F090F0B9E0FCA3E0FD90F0B4E0FB3395E0FAC3EC9BED9A4003021344A88118182C
|
||||
:2012C600E65EFC08E65FFD4C602190F0B5E0FCA3E0FDEC24F3FCED34F0FD8C828D83E0FB1A
|
||||
:2012E600A881E642038C828D83EBF030051A90F0B9E0FCA3E0FDEC30E01AA88118E618C39F
|
||||
:2013060013C613C608F6800CA88118E618C313C613C608F6A881E6C313F6A881E6701090DF
|
||||
:20132600F0B5E02401F0A3E03400F0A881768090F0B9E02401F0A3E03400F00212A7158121
|
||||
:1513460015811581D000D001D002D003D004D005D006D00722A8
|
||||
:206398000070071008500D9016601CA026A03010316037603D7044904D204F605520578020
|
||||
:2063B8005F7066706D6073507880805085708C7093709A70A120A320A570AC80B470BB70B6
|
||||
:2063D800C2A0CCA0D670DD80E570EC70F370FA8002710971105115811D7124812C7133813E
|
||||
:2063F8003B7142814A7151715891617168A172A17CA186A1908198519D81A551AA81B2A1F2
|
||||
:20641800BC21BE71C571CC71D371DA71E181E971F071F741FB51007207420B9214721B724A
|
||||
:2064380022722972306236623C724362499252A25C8264A26E8276627C127D6283A28D728C
|
||||
:206458000000000000000000000000000000D87F0078000000000000007880009804E005DC
|
||||
:20647800801E9864E005801E80648004183808640842FCFF8841F040083810442044C04489
|
||||
:2064980000397002880C881088207040E0001001083A08468845C84C3838180068008001E2
|
||||
:2064B8000078E00718180C300420024002400240024004200C301818E00700100018000F1F
|
||||
:2064D8000072000F001800104000400040004000F807400040004000400019001E00800045
|
||||
:2064F800800080008000800080001800180002000C003000C0000003000C00300040C00F88
|
||||
:2065180030300840084008403030C00F082008200820F87F0800080008001860284048408D
|
||||
:2065380088400843083C0840084208420842F03DC0004003400440184020F87F40004000A3
|
||||
:20655800087C084408441042E041E00F10320844084408441042E00100401840E040004351
|
||||
:20657800004C00500060F038084508420842084590456038001E0821884088408840302154
|
||||
:20659800C01F1806180619061E06C000C0002001200110021002080420012001200120010F
|
||||
:2065B800200120012001200108041002100220012001C000C00000700040D8400041004202
|
||||
:2065D80000640038C00F30181820C84728486850D851E03F2000200008007000C001400E72
|
||||
:2065F8004018400C4003C00030000800F81F08110811081108118812700CC003300C1008FC
|
||||
:2066180008100810081008100818F81F08100810081008101008E007F81F8810881088108D
|
||||
:20663800881088100810F81F801080108010801080100010C003300C100808100810881024
|
||||
:206658008810F818F81F80008000800080008000F81F081008100810F81F08100810081025
|
||||
:206678000800081008100810F01FF81F0001800140022004200810100800F81F080008002D
|
||||
:206698000800080008000800F81F001C8007E00060008003001CF81FF81F0008000680016C
|
||||
:2066B80060001000F81FE007100808100810081008101008E007F81F801080108010801086
|
||||
:2066D8000011000EE00710080810081008100C101208E207F81F80108010C0102011100EC7
|
||||
:2066F8000800180E0812081108118810901070180010001000100010F81F001000100010C1
|
||||
:206718000010E01F18000800080008001000E01F0010000C8003600018001800E000000301
|
||||
:20673800000C00100018C0073800F0000007800370003800C0070018081010082004400277
|
||||
:206758008001800140022004100808100010000800060001F8000001000200040008001053
|
||||
:2067780018102810481088100811081208140818FE7F024002400240024000400030000C41
|
||||
:206798000003C00030000C0002000240024002400240FE7F2000C0000007001C0070000EDA
|
||||
:2067B800C0012000040004000400040004000400040004000400040000800040300048047C
|
||||
:2067D800880488049004F8030800F87F10020804080408041006E001E00110020804080443
|
||||
:2067F800080408040804E00118020804080408041002F87FE0019002880488048804880412
|
||||
:20681800880300040004F83F00240044004400440044E00119020904090409041202FC0728
|
||||
:20683800F87F00010002000400040004F803000400040064F8670100010401040164FE671F
|
||||
:20685800F87F8000C0002001200210020804004000400040F87FF807000200040004F803CD
|
||||
:20687800000200040004F803F80700030002000400040004F803E0011002080408040804D9
|
||||
:206898001002E001FF0710020804080408041006E001E00118020804080408041002FF0783
|
||||
:2068B800F8070001000200040004000718038804880448044804300400040004F01F08048D
|
||||
:2068D800080408040804F0070800080008001000F807000480036000180008003000C00067
|
||||
:2068F800000300040006E001180070008003800170001800E0010006080410022001C00098
|
||||
:20691800C00020011002080401040103C10062001C001800600080000003000408041804F1
|
||||
:20693800280448048804080508060804800080007C3F024002400240FE7F02400240024050
|
||||
:206958007C3F80008000C000000100010001800080004000400040008001F8010803080450
|
||||
:20697800080808040803F80164617461547970652030782578206E6F7420737570706F7204
|
||||
:056998007465640A00B3
|
||||
:20135B00E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB35
|
||||
:20137B0000438004002290F0C17401F090F0C2E4F090F0C3F090F0C4F090F0C5F090F0C6CB
|
||||
:20139B0004F090F0C7F090F0C9E4F090F0C8F090F0CC7428F0E4A3F090F0CEF090F0CA7467
|
||||
:2013BB0028F0740AA3F090F959E4F090F95AF022AD82AE8312628FFCBC011C7BC17CF08BD3
|
||||
:2013DB00828C83740EC0E0C005C0061246301581158115810214C7227480C0E0E4C0E074DF
|
||||
:2013FB00A2C0E074FDC0E0906000E4F5F01206E1E58124FCF581740EC0E07414C0E074FE15
|
||||
:20141B00C0E090F0C112463015811581158190FDA2E0FCA3E0FDA3E0FEA3E0FFBCA513BDC7
|
||||
:20143B005A10BEBA0DBFAB0A90FDA6E0FFBF0102803590FDA2E0FCA3E0FDA3E0FEA3E0FF17
|
||||
:20145B0090FDA6E0FB7A00C004C005C006C007C003C002749DC0E07469C0E0125A46E58108
|
||||
:20147B0024F8F58102138190FDA7E090F959F090FDA8E090F95AF074CBC0E07469C0E012ED
|
||||
:20149B005A461581158112161990FDA2E4F004C0E0E4C0E074A2C0E074FDC0E0906000E45E
|
||||
:2014BB00F5F012081CE58124FCF581227480C0E0E4C0E074A2C0E074FDC0E0906000E4F530
|
||||
:2014DB00F01206E1E58124FCF58190FDA2E0FCA3E0FDA3E0FEA3E0FFBCA53EBD5A3BBEBA15
|
||||
:2014FB0038BFAB35788574C1F274F008F2E408F27888740EF2E408F290FE1475F0001261CE
|
||||
:20151B0010E5828583F045F0700F90FDA7E0FF90F959E0FEEFB506012290FE21E0FF90F0DF
|
||||
:20153B00CEE0FEEFB50602803EEE603BBE6400502390FE21E0FF7D00C007C00574DDC0E0D4
|
||||
:20155B007469C0E0125A46E58124FCF58190F0CEE4F08013BEC800400890F95A7402F080F9
|
||||
:20157B000690F95A7401F07480C0E0E4C0E0C0E090FDA2124598158115811581740EC0E048
|
||||
:20159B0074C1C0E074F0C0E090FE1412463015811581158190FDA274A5F0F4A3F074BAA3DB
|
||||
:2015BB00F0C4A3F090FDA67401F090F959E090FDA7F090F95AE090FDA8F07401C0E0E4C0AA
|
||||
:2015DB00E0906000E4F5F012092C158115817480C0E0E4C0E074A2C0E074FDC0E090600015
|
||||
:2015FB00E4F5F012081CE58124FCF58174F6C0E07469C0E0125A461581158102161990F0BF
|
||||
:20161B00C5E0FF7E00C007C0067407C0E0746AC0E0125A46E58124FCF58190F0CEE0FF7E0E
|
||||
:20163B0000C007C0067420C0E0746AC0E0125A46E58124FCF58190F0CAE0FEA3E0FFC00632
|
||||
:20165B00C0077433C0E0746AC0E0125A46E58124FCF58190F0C2E0FF7E00C007C00674474E
|
||||
:20167B00C0E0746AC0E0125A46E58124FCF58190F959E0FF7E00C007C006745CC0E0746A69
|
||||
:0C169B00C0E0125A46E58124FCF58122D3
|
||||
:20699D004C6F616465642064656661756C74732073657474696E67735665722030782578F6
|
||||
:2069BD00204D61676963203078256C780A004C6F616465642073657474696E67733A0A00C0
|
||||
:2069DD0049676E6F7265642066697865644368616E6E656C2025640A0053617665642073B0
|
||||
:2069FD00657474696E67733A0A0020205363616E2041667465722054696D656F7574202515
|
||||
:206A1D00640A00202066697865644368616E6E656C2025640A0020206261744C6F77566FC1
|
||||
:206A3D006C746167652025640A002020656E61626C6546617374426F6F742025640A0020DD
|
||||
:0D6A5D00204C6173742063682025640A00DA
|
||||
:2016A700E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FBE6
|
||||
:2016C70000438004002275F10175805875FDDD75F33875904075FE6E75F4E875A00175FF76
|
||||
:2016E70001227401C0E0E4C0E0900000E4F5F012092C158115817414C0E0E4C0E0746AC011
|
||||
:20170700E0746AC0E090F0F31245F6E58124FCF5817414C0E0E4C0E074F3C0E074F0C0E0F1
|
||||
:20172700900000E4F5F012081CE58124FCF58122C00775E40075FC0075F70075FE0290F9FA
|
||||
:2017470053E0FF54F06002800DD291758F0075F60075FD008012758F8175F62F75FD8175C0
|
||||
:14176700FE2F53807E5390D075F30075F40075F500D0072209
|
||||
:146A6A005612098501084A41000000000904EC0212045A0A19
|
||||
:027FFE00706AA7
|
||||
:20177B00E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB11
|
||||
:20179B00004380040022AE82AF837D00BD08005017ED75F002A424CFF58274F035F0F583D7
|
||||
:2017BB00EEF0EFA3F00D80E422E582FF30E025125657C0071249C9D2AF1216CD12435812A1
|
||||
:2017DB004E6FD00775820A124EAE90F959E0FEF582124DFAEF30E209124385200C0302089E
|
||||
:2017FB000D22E58230E206300C0302080122AF82AE83ADF0FC90F0EFEFF0EEA3F0EDA3F06A
|
||||
:20181B00ECA3F090F0EFE0FCA3E0FDA3E0FEA3E0FFC004C005C006C007747EC0E0746AC01A
|
||||
:20183B00E0125A46E58124FAF581300C16758204C007C006C005C0041217FDD004D005D0FF
|
||||
:20185B0006D007C007C006C005C004125C62D004D005D006D0071217378C828D838EF0EF69
|
||||
:20187B00124A517582010217C4E582FF601090F0E4E0FFBFFF00500690F0E4EF04F090F0D7
|
||||
:20189B00E4E0FFBF18005007900E10E4F5F022BF24005007901C20E4F5F02290518075F0EC
|
||||
:2018BB0001E42290F0E0E07875F2E408F2900230125F217862740EF2E408F2125D4AAE82A0
|
||||
:2018DB00AF8374282EFEE43FFF90F0DFE054077D0025E0FCED33FDEC24CFF582ED34F0F540
|
||||
:2018FB0083EEF0EFA3F090F0DFE02401F0227E007F007D00BD0800501DED75F002A424CFDD
|
||||
:20191B00F58274F035F0F583E0FBA3E0FCEB2EFEEC3FFF0D80DEEFC423CEC423541F6ECEF4
|
||||
:20193B00541FCE6ECEFF90F0CCE0FCA3E0FDC3EE9CEF9D50058C828D83228E828F83229026
|
||||
:20195B00FAB4E0FF3395E0FEC007C0067493C0E0746AC0E0125A46E58124FCF58190F0BF9A
|
||||
:20197B00E0FF7E0090F0C0E0FD3395E0FCC007C006C005C004749EC0E0746AC0E0125A4636
|
||||
:20199B00E58124FAF5812275820E124C9E124CCA75820F124C9E90FAB2E0FEA3E0FF7423B2
|
||||
:2019BB00C0E08E828F831248A615817404C0E01243EFAC82AD83158190F0EBECF0EDA3F09D
|
||||
:2019DB00C20A90F0CAE0FEA3E0FFC3EC9EED9F5004D20A803A90F0E7E0FCA3E0FD4C601331
|
||||
:2019FB00C3EC9EED9F500C90F0EBECF0EDA3F0D20A801C90F0E9E0FCA3E0FD4C6011C3EC27
|
||||
:201A1B009EED9F500A90F0EBECF0EDA3F0D20A90F0E9E0C0E0A3E0C0E090F0E7E0C0E0A3EE
|
||||
:201A3B00E0C0E090F0EBE0C0E0A3E0C0E090F0E5E0C0E0A3E0C0E074AFC0E0746AC0E012A2
|
||||
:091A5B005A46E58124F6F58122CA
|
||||
:206A7E00536C656570696E6720666F7220256C64206D730A0054656D7020256420430A008F
|
||||
:206A9E00525353492025642C204C51492025640A00426174745620426F6F742025642C207F
|
||||
:1A6ABE006E6F772025642C2054782025642C207570646174652025640A007E
|
||||
:0500DC00781074FFF232
|
||||
:201A6400E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB25
|
||||
:201A8400004380040022121AE0E582600790F96CE0F58222121AAAE582600790F970E0F59F
|
||||
:201AA40082227582002290F95BE05407FFBF012890F95CE003035403FFBF031C90F95CE09B
|
||||
:201AC40023235403FFBF031090F95BE023235401FFBF0104758201227582002290F95BE07B
|
||||
:201AE4005407FFBF012390F95CE003035403FFBF021790F95CE023235403FFBF030B90F9F5
|
||||
:201B04005BE020E6047582012275820022AFF0AE83E58290FA70F0EEA3F0EFA3F090FA702B
|
||||
:201B2400E0FDA3E0FEA3E0FF90FA6EE0FBA3E0FC79007A00C3E99BEA9C5052E94A6016E97B
|
||||
:201B4400540F6002800F74D8C0E0746AC0E0125A4615811581C003C004E92DF8EA3EFB8F9E
|
||||
:201B64000488828B838CF012628FF87C00C000C00474DAC0E0746AC0E0125A46E58124FC2A
|
||||
:201B8400F58109B900010AD004D00380A774D8C0E0746AC0E0125A461581158122AFF0AE79
|
||||
:201BA40083E5827812F2EE08F2EF08F27815E4F27B017811C3E2F5F0EB95F050227812E2AA
|
||||
:201BC400FA08E2FC08E2FFEB2AFAE43CFC8A828C838FF012628FFA7815E22AF20B80D37815
|
||||
:201BE40012E2FD08E2FE08E2FF8D828E838FF012628FFD7815E2B50503D38001C3E433F531
|
||||
:201C04008222AFF0AE83E5827817F2EE08F2EF08F2781AE4F27B017816C3E2F5F0EB95F027
|
||||
:201C240050227817E2FA08E2FC08E2FFEB2AFAE43CFC8A828C838FF012628FFA781AE22A94
|
||||
:201C4400F20B80D37817E2FD08E2FE08E2FF8D828E838FF0781AE2025F06E5812404F58173
|
||||
:201C6400AF82C218C007125098D0078F82124DFAC00712514DD218125098D0077E01EE2490
|
||||
:201C8400FC5003021D8890F9DB7414F0C007C00612379590F9ED74EDF090F9DB124F94D013
|
||||
:201CA40006D007124981AA82AB83ACF0FD90FA7374A62AF0740E3BA3F0E43CA3F0E43DA37C
|
||||
:201CC400F0C006124981AA82AB83ACF0FD90FA73E58124FCF8E0F6A3E008F6A3E008F6A385
|
||||
:201CE400E008F6E58124FCF8C3EA96EB0896EC0896ED0896D0064003021D84C007C0061248
|
||||
:201D040050AAAD82D006D007C374818DF063F08095F050AD90F971E0FDB507A5C007C0069A
|
||||
:201D2400121A8AAD82D006D007BDEE95C007C006121AAAE582D006D00760867408C0E074E0
|
||||
:201D440068C0E074F9C0E090F94612463015811581158190F95EE0FCA3E0FD90F94EECF05B
|
||||
:201D6400EDA3F08F047D00C004C00574E0C0E0746AC0E0125A46E58124FCF5818F82802075
|
||||
:201D84000E021C828F057E00C005C00674EAC0E0746AC0E0125A46E58124FCF581758200D3
|
||||
:201DA400E58124FCF5812290F9DB742AF012379590F9ED74E5F090F9F47482F090F0E3E0CC
|
||||
:201DC40090F9F5F090F0C0E090F9F0F090F0BFE090F9EFF090FAB4E090F9F1F090F0EBE0AE
|
||||
:201DE400FEA3E0FF90F9F2EEF0EFA3F090F9F6E4F09062BB93FE740193FF90F9F7EEF0EF9F
|
||||
:201E0400A3F090F959E090F9F9F090F0C9E090F9FAF078167415F290F9EE75F000121C0642
|
||||
:201E240090F9DB024F94D2181250981219A212195A7F00781BE4F2781BE2B40E00400302BB
|
||||
:201E44001F08C007121DABD007124981AA82AB83ACF0FD74882AF52674133BF527E43CF5DC
|
||||
:201E640028E43DF529C007124981AC82AD83AEF0FFC3EC9526ED9527EE9528EF9529D00717
|
||||
:201E84004003021EFBC0071250AAAE82D007C374818EF063F08095F050CBC007121A8AAE32
|
||||
:201EA40082D007BEE6BF78117411F290F97175F000C007121BA1E582D00760A97408C0E00B
|
||||
:201EC4007468C0E074F9C0E090F94612463015811581158190F95E75F00012628FFDA3125B
|
||||
:201EE400628FFE90F94EEDF0EEA3F090F0E0EFF090F97175F00022781BE22401F2781BE2F9
|
||||
:201F0400FF021E3B90F0E0740EF090000075F00022D2181250987F00781CE4F2781CE2B483
|
||||
:201F24000E004003021FFC90F9DB7414F090F9ED74E3F0C00712379590F9DB124F94D007C1
|
||||
:201F4400124981AA82AB83ACF0FD74882AF52A74133BF52BE43CF52CE43DF52DC0071249E1
|
||||
:201F640081AC82AD83AEF0FFC3EC952AED952BEE952CEF952DD0075072C0071250AAAE82CA
|
||||
:201F8400D007C374818EF063F08095F050CEC007121A8AAE82D007BEE6C278117411F29040
|
||||
:201FA400F97175F000C007121BA1E582D00760AC7408C0E07468C0E074F9C0E090F94612E9
|
||||
:201FC400463015811581158190F95E75F00012628FFDA312628FFE90F94EEDF0EEA3F09010
|
||||
:201FE400F0E0EFF090F97175F00022781CE22401F2781CE2FF021F2090F0E0740EF0900008
|
||||
:202004000075F00022AFF0AE83E582781DF2EE08F2EF08F2781DE22402FA08E23400FB08EE
|
||||
:20202400E2FC8A828B838CF012628FF52E852E2F75300090FA5CE0F531AE317F00E52FC35A
|
||||
:202044009EFEE5309FFF7875EEF2EF08F2900063C004C003C002125F21AE82AF83D002D0A5
|
||||
:2020640003D0048E2F8F3090FA77E52FF0E530A3F0781DE22401FD08E23400FE08E2FF8D31
|
||||
:20208400828E838FF012628FFD90F91FE0FFEDB50702800122E52E24D5500122C3E52E956B
|
||||
:2020A400315001227463252FFEE43530FFC374239E74089F500122781DE2FD08E2FE08E23B
|
||||
:2020C400FF78117466F28D828E838FF0C004C003C002121BA1E582D002D003D0047003029D
|
||||
:2020E400217D781DE22403FD08E23400FE08E28D2F8E3090FA77E0FEA3E0FFEE24F3FEEFD0
|
||||
:2021040034F0FF8E828F837463C0E0E4C0E0C02FC0301245F6E58124FCF5818A828B838CAD
|
||||
:20212400F012628FFA7F00788A7408F2E408F28A828F83C007C0021261CAAD82AE83D002CB
|
||||
:20214400D007ED2421FDEE34F9FE5302078AF005F07401800225E0D5F0FBF4FA8D828E83C7
|
||||
:20216400E052028D828E83EAF074F7C0E0746AC0E0125A46158115812274F9C0E0746AC0F9
|
||||
:20218400E0125A461581158122AF82AE83ADF0FC7820EFF2EE08F2ED08F2EC08F290FA5C4C
|
||||
:2021A400E0FB7A0090F91FE0FF7E00C003C002C007C006740AC0E0746BC0E0125A46E581FA
|
||||
:2021C40024FAF581D21812509812498185823285833385F034F53578207977E22414F308C3
|
||||
:2021E400E2340009F308E2340009F308E2340009F3900019E4F5F0125F41AA82AB83AEF079
|
||||
:20220400FFEA2532F532EB3533F533EE3534F534EF3535F535124981AA82AB83AEF0FFC33F
|
||||
:20222400EA9532EB9533EE9534EF9535503C1250AAAF82C374818FF063F08095F050D61236
|
||||
:202244001A8AAF82BFE8CE90F97175F0001220097F00EF2421FDE434F9FE8D828E83E07067
|
||||
:20226400060FBF060040EBBF06AB74D8C0E0746AC0E0125A4615811581C218125098025176
|
||||
:202284004D90F972E4F0A3F090F97175F00022742AC0E0E4C0E0C0E090F9DB1245981581BF
|
||||
:2022A4001581158190F9DB742AF090F940E0600890F9F174E4F0800690F9F174E7F0740862
|
||||
:2022C400C0E07450C0E074F9C0E090F9E91246301581158115817408C0E07446C0E074F94A
|
||||
:2022E400C0E090F9E112463015811581158190F9DCE054F84401F090F9DCE054C74440F0EC
|
||||
:2023040090F9DDE0440C54CF44C0F090F958E0FF04F090F9DEEFF090F94EE0FEA3E0FF904B
|
||||
:20232400F9DFEEF0EFA3F07DF27EF98D828E837411C0E07416C0E074F9C0E01246301581E1
|
||||
:20234400158115817DF27EF97F0078167411F28D828E838FF0121C0690F9DB024F94E58161
|
||||
:202364002404F581D21812509812514D7F00BF1E004003022445C007122293D007124981DC
|
||||
:20238400AB82AC83ADF0FE90FA7974642BF0749F3CA3F0740B3DA3F0E43EA3F0C00712503D
|
||||
:2023A400AAAE82D007C374818EF063F08095F05051C007121A8AAE82D007BEE8028028BEA7
|
||||
:2023C400E9028005BEEC33802978117403F290F97175F000C007121BA1E582D007602390CC
|
||||
:2023E400F97175F0008063122285AC82AD83AEF0805890000075F000805090000075F000E0
|
||||
:202404008048C007124981C8E58124FCC8A68208A68308A6F008F690FA79E0FAA3E0FDA342
|
||||
:20242400E0FEA3E0FFE58124FCF8C3E69A08E69D08E69E08E69FD00750030223A00F0223B0
|
||||
:2024440072122285AD82AE83AFF0E58124FCF58122741BC0E0E4C0E0C0E090F9DB1245988A
|
||||
:2024640015811581158190F9DB7419F090F9F174EAF07408C0E07450C0E074F9C0E090F9D7
|
||||
:20248400E91246301581158115817408C0E07446C0E074F9C0E090F9E11246301581158164
|
||||
:2024A400158190F9DCE054F84401F090F9DCE054C74440F090F9DDE0440C54CF44C0F090AB
|
||||
:2024C400F94EE0FEA3E0FF90F9DFEEF0EFA3F090F958E0FF04F090F9DEEFF090F9DB024FDA
|
||||
:2024E40094D2181250987F00BF1000506CC007122455D00712498185823A85833B85F03C1C
|
||||
:20250400F53D12498185823685833785F038F539E536C3953AFAE537953BFCE538953CFDD8
|
||||
:20252400E539953DFEC3EA94A6EC940EED9400EE94005022C0071250AAAE82D007C374812D
|
||||
:202544008EF063F08095F050B9C007121A8AAE82D007BEEBAD220F808F22AF82E4FDCD5429
|
||||
:2025640003A2E0CD13CD13A2E0CD13CD13CDFCEF0303543F4DFDEF030354C0FE7F0074013A
|
||||
:202584002DFDE43C8F828E838DF022AD82AE83AFF07C007B00BB0400400302261EC0048B9F
|
||||
:2025A40082C007C006C005C00312255EA882A983AAF0FCD003D005D006D0077416C0E0E49C
|
||||
:2025C400C0E074F3C0E074F0C0E0888289838AF0EC1206E1E58124FCF5817464C0E074FCF3
|
||||
:2025E400C0E090F0FB12490315811581920ED004300E218D008E018F027408C0E0C000C016
|
||||
:202604000190F0F31245C4158115811581920E50038C82220B8B040225997582FF22AF829F
|
||||
:202624005307F87E007D00BD040040030226AAC0068D82C007C00512255EAA82AB83ACF087
|
||||
:20264400FED005D0077416C0E0E4C0E074F3C0E074F0C0E08A828B838CF0EE1206E1E58130
|
||||
:2026640024FCF5817464C0E074FCC0E090F0FB124903158115819228D006302823C00690D2
|
||||
:20268400F108E0FC5304F87B008F027E00ECB50206EBB506028004D0068005D0068E822250
|
||||
:2026A4000D8D0602262B7582FF2212255EAC82AD83AEF0FF7416C0E0E4C0E074F3C0E07452
|
||||
:2026C400F0C0E08C828D838EF0EF1206E1E58124FCF58190F108E0F58222AF828F060EEE22
|
||||
:2026E40024FB50027E00EEB507038E82228E82C007C00612255EAA82AB83ACF0FDD006D03D
|
||||
:20270400077416C0E0E4C0E074F3C0E074F0C0E08A828B838CF0ED1206E1E58124FCF5817D
|
||||
:202724007464C0E074FCC0E090F0FB12490315811581922850A890F108E0FD5305F87C0024
|
||||
:20274400BD789BBC00988E822212255EAC82AD83AEF0FF7404C0E0E4C0E08C828D838EF057
|
||||
:20276400EF12092C15811581227F00BF0400500C8F82C00712274DD0070F80EF22AF828F9E
|
||||
:20278400057E00C005C0067419C0E0746BC0E0125A46E58124FCF5818F8212255E020A6CAF
|
||||
:2027A4007825E4F208F208F208F27B00BB040040030228438B82C00312255E85823E858318
|
||||
:2027C4003F85F040F541D0037416C0E0E4C0E074F3C0E074F0C0E0853E82853F838540F0FE
|
||||
:2027E400E5411206E1E58124FCF5817464C0E074FCC0E090F0FB12490315811581920F503C
|
||||
:202804003AC00390F104E0FAA3E0FBA3E0FEA3E0FF7825C3E29A08E29B08E29E08E29FD095
|
||||
:2028240003501890F1047825E0F2A3E008F2A3E008F2A3E008F290F945EBF00B0227B078B9
|
||||
:2028440025E2F58208E2F58308E2F5F008E222AF82AE83D21090F91FE0FD7C007B007A007F
|
||||
:202864008C44EBC454F0C544C4C5446544C54454F0C5446544F545EDC4540F4544F544ED16
|
||||
:20288400C454F0F543754200300D17782FE542F27470254308F2E4354408F2E4354508F234
|
||||
:2028A40080497810E2F582C007C00612255E85824685834785F048F549D006D00774162555
|
||||
:2028C40046F546E43547F547E43548F548E43549F549782FE5462542F2E547354308F2E5EB
|
||||
:2028E40048354408F2E549354508F290FA807405F090FA5CE4F090F94004F07829EFF20803
|
||||
:20290400EEF27406C0E0E4C0E0C0E090F92112459815811581158190FA80E0FB14F0EB70F6
|
||||
:2029240003022C961010030229E57829E2FA08E2FB8A828B8378627463F2E408F2125D4AE3
|
||||
:20294400AA8290FA7DEAF07829E2FB08E2FF8B828F8378837463F2E408F2C00212608DE598
|
||||
:20296400828583F0D00245F0600690FA7DEA04F090FA7DE024EA500690FA7D7415F090FA32
|
||||
:202984005CE0FB7A0090FA7DE0FFC3EA9F50528B067F00788A7408F2E408F28E828F83C06E
|
||||
:2029A40007C006C003C0021261CAAC82AD83D002D003D006D007EC2421FCED34F9FD530637
|
||||
:2029C400078EF005F07401800225E0D5F0FBFE8C828D83E0FF42068C828D83EEF00B0A80E9
|
||||
:2029E400A4122362AA82AB83AFF0EA4B7003F582220ABA00010B8A828B838FF012628FFEF4
|
||||
:202A0400A312628FFF4E60428E048F05C3EC9423ED9400501A7877EEF2EF08F2E408F20808
|
||||
:202A2400F2900019E4F5F0125F411249E2801BEC24F6FCED34FFFD7F007E008C828D838FDB
|
||||
:202A4400F0EE121809D218125098900122E4F5F012218D78337401F290FA5CE0FF7E00905C
|
||||
:202A6400FA7DE0FDC3EE9D505E8F047D00788A7408F2E408F28C828D83C007C006C005C074
|
||||
:202A8400041261CAAA82AB83D004D005D006D007EA2421F582EB34F9F5835304078CF0052C
|
||||
:202AA400F07C017D008006EC2CFCED33FDD5F0F7E0FB7A005204EA5205EC4D60067833E49B
|
||||
:202AC400F280040F0E80987833E27003022C5B90FA7DE07875F2E408F2900063125F21AEE7
|
||||
:202AE40082AF83782DEEF2EF08F290FA8174F3F074F0A3F0E4A3F090FA5CE0704B90F0F3EC
|
||||
:202B0400E0FCA3E0FD7829ECF208EDF290F0F5E0FCA3E0FD782BECF208EDF290FA7EE4F0DA
|
||||
:202B2400A3F0782DE2FC08E2FDEC24FCFCED34FFFD782DECF2ED08F290FA81740424F3F07B
|
||||
:202B4400E434F0A3F0E4A3F07829E2FC08E2FD782DC3E2F5F0EC95F008E2F5F0ED95F050C8
|
||||
:202B64000A7829792DE2F308E209F37829E2FC08E2FD782DD3E29CF4B3FCB308E29DF4FD1B
|
||||
:202B84007829ECF208EDF27582041217C490FA81E0F546A3E0F547A3E0F548AA46AF4778E0
|
||||
:202BA4002DE2C0E008E2C0E0C002C007782FE2F58208E2F58308E2F5F008E212081CE58198
|
||||
:202BC40024FCF5817582041217FD782DE2FA08E2FD7E007F00782FE22AF208E23DF208E22D
|
||||
:202BE4003EF208E23FF2AD46AE47AF48782DE2F54608E2F547AA46AC47154674FFB5460211
|
||||
:202C04001547EA4C60368D828E838FF012628FFCA3AD82AE838C4275430090FA7EE0FAA3DC
|
||||
:202C2400E0FC8A4A8C4BAB42AC43EB254AFBEC354BFC90FA7EEBF0ECA3F080B990FA7DE0EE
|
||||
:202C4400FF90FA5CE02FF07829E2FE08E2FF4E60067833E4F2D21090F940E4F07833E27071
|
||||
:202C64000302291B782BE2FE08E2FF90FA7EE0FCA3E0FDEEB50406EFB5050280117433C0E7
|
||||
:202C8400E0746BC0E0125A461581158180047582012275820022AFF0AE83E58290FA88F003
|
||||
:202CA400EEA3F0EFA3F090FA88E0FDA3E0FEA3E00DBD00010E8D828E837408C0E07430C0A1
|
||||
:202CC400E074F9C0E01245C41581158115819211501490F938E0FCA3E0FDA3E0FEA3E0FFFF
|
||||
:202CE400EC4D4E4F707490F91FE4F090FA88E0FDA3E0FEA3E0FF74012DFAE43EFBC002C06D
|
||||
:202D04000390F9171244C615811581740D2DFAE43EFB8F048A828B838CF012628FFA90F950
|
||||
:202D240020F07411C0E0C005C00690F92F1246301581158115817408C0E0E4C0E09070002D
|
||||
:202D4400E4F5F012092C1581158190F938E0FEA3E0FF90FA86EEF0EFA3F090F938E0FCA362
|
||||
:202D6400E0FDA3E0FEA3E0FFEC4D4E4F7003022DF3C3E49C74109DE49EE49F500B90FA8432
|
||||
:202D8400E4F07410A3F0800890FA84ECF0EDA3F0D20D90FA84E0FEA3E0FF8E828F831228A9
|
||||
:202DA40053E582604690F91FE0FF0F90F91FEFF090F938E0FCA3E0FDA3E0FEA3E0FF90FAE8
|
||||
:202DC40084E0FAA3E0FB8A008B01E4FAFBECC398FCED99FDEE9AFEEF9BFF90F938ECF0EDC5
|
||||
:202DE400A3F0EEA3F0EFA3F0022D5E7582002275820122AFF0AE83E58290FA8DF0EEA3F0BA
|
||||
:202E0400EFA3F090FA8DE0FDA3E0FEA3E0FF74012DFAE43EFB8F048A828B837408C0E0743F
|
||||
:202E240030C0E074F9C0E01245C41581158115819212504090F93DE0FC740E2DFDE43EFE32
|
||||
:202E44008D828E838FF012628FFDECB5052690F938E0FCA3E0FDA3E0FEA3E0FFEC4D4E4F0D
|
||||
:202E64006012744BC0E0746BC0E0125A46158115810230017582041217C490F9457834E0AB
|
||||
:202E8400F290FA8DE0FCA3E0FDA3E0FE740E2CFAE43DFB8E078A828B838FF012628FFA5405
|
||||
:202EA400FC60317834E2FB7F00C003C007745EC0E0746BC0E0125A46E58124FCF58190FAC6
|
||||
:202EC4006E7411F0E4A3F08C828D838EF0121B117834E4F290F945E02401F0FFBF04004073
|
||||
:202EE4000590F945E4F090F945E0FF7834E2B507197582041217FD7482C0E0746BC0E012CF
|
||||
:202F04005A4615811581758201228F8212255EAC82AD83AEF0FF7416C0E0E4C0E074F3C051
|
||||
:202F2400E074F0C0E08C828D838EF0EF1206E1E58124FCF5817464C0E074FCC0E090F0FB26
|
||||
:202F4400124903158115819212500890F108E054F8708190F945E0FF7810F28F8212255E74
|
||||
:202F6400AC82AD83AEF0FF7404C0E0E4C0E08C828D838EF0EF12092C1581158175820412AB
|
||||
:202F840017FD7810E2FE7F00C006C007748CC0E0746BC0E0125A46E58124FCF58190F91F30
|
||||
:202FA400E4F090FA8DE0FDA3E0FEA3E0FF74012DFAE43EFBC002C00390F9171244C61581B2
|
||||
:202FC4001581740D2DFAE43EFB8F048A828B838CF012628FFA90F920F07411C0E0C005C029
|
||||
:202FE4000690F92F12463015811581158190F938E0FEA3E0FF90FA8BEEF0EFA3F090F9386E
|
||||
:20300400E0FCA3E0FDA3E0FEA3E0FFEC4D4E4F7003023098C3E49C74109DE49EE49F500B76
|
||||
:2030240090FA84E4F07410A3F0800890FA84ECF0EDA3F090FA84E0FEA3E0FF8E828F8312FF
|
||||
:203044002853E582604A90F91FE0FF0F90F91FEFF090F938E0F54CA3E0F54DA3E0F54EA3B3
|
||||
:20306400E0F54F90FA84E0FAA3E0FBE4FEFFE54CC39AFAE54D9BFBE54E9EFEE54F9FFF9060
|
||||
:20308400F938EAF0EBA3F0EEA3F0EFA3F0023001758200227582041217C47430C0E074F9BB
|
||||
:2030A400C0E090F0F31244C61581158190F0FB7421F07447A3F0744DA3F07447A3F090F938
|
||||
:2030C40041E02401F0A3E03400F0A3E03400F0A3E03400F090F941E0FCA3E0FDA3E0FEA377
|
||||
:2030E400E0FF90F104ECF0EDA3F0EEA3F0EFA3F090FA8BE0FEA3E0FF7D007C0090F0FFEE2E
|
||||
:20310400F0EFA3F0EDA3F0ECA3F090F93CE090F103F090F93DE090F108F07810E2F582120F
|
||||
:20312400255EAC82AD83AEF0FF7416C0E0E4C0E074F3C0E074F0C0E08C828D838EF0EF12B7
|
||||
:20314400081CE58124FCF5817582041217FD75820122AFF0AE83E58290FA91F0EEA3F0EF5E
|
||||
:20316400A3F0C20D90FA91E0F553A3E0F554A3E0F555740D2553FAE43554FBAC558A828B1A
|
||||
:20318400838CF012628FFCBC02028024BC03030234DEBC10028019BC20028014BC210280BB
|
||||
:2031A4000FBCA8030233D1BCAF030234BE02355390FA91E0FFA3E0FEA3E0FD75509075518D
|
||||
:2031C400FA755200740E2FF553E43EF5548D558553828554838555F012628FFB855082858A
|
||||
:2031E40051838552F0125F0690FA90E020E2030232B5758204C007C006C0051217C4D005C2
|
||||
:20320400D006D00790FA90E0C423541FFB603CBB0F02806C8553828554838555F012628FD7
|
||||
:20322400F582C007C006C005122622AB82D005D006D007BBFF0280488B82C007C006C005D5
|
||||
:2032440012274DD005D006D007803574012FF553E43EF5548D558553828554838555F0C034
|
||||
:2032640007C006C00512258FAB82D005D006D007BBFF02800B1224E578357401F20233CBCD
|
||||
:20328400758204C007C006C0051217FDD005D006D0078F828E838DF0122DF7E582600B127C
|
||||
:2032A40024E578357401F20233CB7835E4F20233CB74012FF553E43EF5548D558553508584
|
||||
:2032C40054518555528550828551837408C0E07427C0E074F9C0E01245C415811581158128
|
||||
:2032E4009213500B1224E578357401F20233CB758204C007C006C0051217C485538285542E
|
||||
:20330400838555F012258FAC82758204C0041217FDD004D005D006D007BCFF028051C007D8
|
||||
:20332400C006C005C0041224E5D004D005D006D0078F538E548D55AA53AB547411C0E0C042
|
||||
:2033440002C00390F92F12463015811581158190F938E4F0A3F0A3F0A3F090FC63ECF090F9
|
||||
:20336400FA90E054037824F28C82122781803D749AC0E0746BC0E0125A46158115818F8259
|
||||
:203384008E838DF0122DF7E582601B1224E57810E2FB90FC63F090FA90E054037824F28BBA
|
||||
:2033A4008212278180067835E4F2801B90F930E0FAA3E0FBC002C00390F9271244C6158131
|
||||
:2033C400158178357401F27835E2F5822290F938E0FAA3E0FBA3E0FEA3E0FFEA4B4E4F70B9
|
||||
:2033E4002F74012553FDE43554FEAF558D828E837408C0E07430C0E074F9C0E01245C41584
|
||||
:203404008115811581921350071224E57582012290F91FE4F090FA91E0F550A3E0F551A3A2
|
||||
:20342400E0F55274012550FAE43551FBC002C00390F9171244C615811581740D2550FDE4D4
|
||||
:203444003551FEAF528D828E838FF012628F90F920F0AD50AE517411C0E0C005C00690F973
|
||||
:203464002F12463015811581158174092550FDE43551FEAF528D828E838FF012628FFDA335
|
||||
:2034840012628FFE8D828E83122853E582602790F938E4F0A3F0A3F0A3F07582041217C456
|
||||
:2034A40090F0F775F0001213CB7582041217FD1224E575820122758200221224E5740E250B
|
||||
:2034C40053FDE43554FEAF558D828E838FF012628FF58212045A758201227582041217C49E
|
||||
:2034E4008553828554838555F0122C9AE582605B1224E57582041217C412356E300D111236
|
||||
:203504003B03907019E4F5F01206C1125616805674A2C0E0746BC0E0125A461581158175D2
|
||||
:2035240082041217FD90FA5B7401F090F0E374E0F0123B7C7408C0E0E4C0E0C0E090F92731
|
||||
:20354400124598158115811581801B758200227F00C004C00774BFC0E0746BC0E0125A46F4
|
||||
:20356400E58124FCF58175820022783AE4F208F208F208F2C20D7419C0E0E4C0E074A2C066
|
||||
:20358400E074FDC0E0907000E4F5F01206E1E58124FCF58178367419F2747008F2E408F28F
|
||||
:2035A40008F29062BD93FD740193FE7402937406C0E0C005C00690FDAB1245C4158115819B
|
||||
:2035C40015819214500790F08F7405F0229062BDE493FD740193FE7402937409C0E0C005A6
|
||||
:2035E400C00690FDAB1245C41581158115819214500790F08F7402F02290FDAAE0FFBF0182
|
||||
:2036040002800790F08F7401F02290FDA8E0FEA3E0FFC3E49E74809F500790F08F7403F04D
|
||||
:203624002290FDA8E0FEA3E0FF4E70030236E190FDA8E0FEA3E0FFC374239E74089F5004F9
|
||||
:203644007E237F08C006C00774F3C0E074F0C0E07836E2F58208E2F58308E2F5F008E21272
|
||||
:2036640006E1E58124FCF58190FA9474F3F074F0A3F0E4A3F090FA97EEF0EFA3F0783AE26B
|
||||
:20368400F58208E2F58308E2F5F008E2C007C0061237BA783AC0E0E582F2E58308F2E5F022
|
||||
:2036A40008F2D0E008F2D006D0078E028F037C007D007836E22AF208E23BF208E23CF208B7
|
||||
:2036C400E23DF290FDA8E0FCA3E0FDECC39EFEED9FFF90FDA8EEF0EFA3F002362590FDA24D
|
||||
:2036E400E0FCA3E0FDA3E0FEA3E0FF783AE2B5041108E2B5050C08E2B5060708E2B5070205
|
||||
:20370400800790F08F7404F02290FDA6E0FEA3E0FF90F08DEEF0EFA3F0C006C00774DFC0E5
|
||||
:20372400E0746BC0E0125A46E58124FCF581D20D221227A4AC82AD83AEF0FF90F941ECF0F9
|
||||
:20374400EDA3F0EEA3F0EFA3F0227408C0E07450C0E074F9C0E090FA66124630158115818F
|
||||
:20376400158190FA5DE054F84421F090FA5EE054F344C8F090FA607437F07413A3F090FA13
|
||||
:203784006274FFF0A3F090FA647437F07413A3F0227411C0E0745DC0E074FAC0E090F9DCFF
|
||||
:2037A40012463015811581158190F958E0FF04F090F9DEEFF022AC82AD83AEF0FF783EEC02
|
||||
:2037C400F4F2EDF408F2EEF408F2EFF408F290FA94E0F55EA3E0F55FA3E0F56090FA97E06A
|
||||
:2037E400F55AA3E0F55B855A5C855B5D155A74FFB55A02155BE55C455D70030238B8855E9D
|
||||
:2038040082855F838560F012628FFEA385825E85835F8E047D007E007B00783EE26CF20870
|
||||
:20382400E26DF208E26EF208E26BF27846E4F208F27846C3E2940808E26480948050A778D4
|
||||
:203844003EE25401FA08E25400FB08E25400FC08E25400FE7842C3E49AF2E49B08F2E49C60
|
||||
:2038640008F2E49E08F27841E2C313F56418E213F56318E213F56218E213F5617842E254E8
|
||||
:2038840020FC08E25483FD08E254B8FE08E254EDFA783EEC6561F2ED656208F2EE6563086B
|
||||
:2038A400F2EA656408F27846E22401F208E23400F2023835783EE2F4FB08E2F4FC08E2F4F0
|
||||
:0B38C400FD08E2F48B828C838DF02263
|
||||
:206AD8000A002530327820004150206F6E2025640A004E6F204150206F6E2025640A002EE8
|
||||
:206AF80000636865636B435243206661696C65640A00524551202564207061727420256408
|
||||
:206B18000044726177696E6720696D61676520696E20736C6F742025640A00626C6B206623
|
||||
:206B380061696C65642076616C69646174696F6E210A0072657374617274696E6720696D8F
|
||||
:206B58006720646C0A004368616E67696E67207374617274696E67536C6F742066726F6D9B
|
||||
:206B780020256420746F20300A004E6F20736C6F74730A006E657720646C20746F202564F5
|
||||
:206B98000A00646C20696D670A004F544120696D6167652076616C69646174696F6E2066C4
|
||||
:206BB80061696C65640A00646174615479706520307825782069676E6F7265640A00436856
|
||||
:206BD800726F6D613239004F54412076616C6964617465642C207570646174696E67207495
|
||||
:0F6BF8006F2076657273696F6E202530780A0002
|
||||
:05767200FF21474D4718
|
||||
:2038CF00E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB9C
|
||||
:2038EF0000438004002290F09B7438F0E4A3F030050990F09B7430F0E4A3F02290F959E05A
|
||||
:20390F00704590F0C7E0603FC20490F09F7410F0C4A3F090F0A17406F0E4A3F09071D9751C
|
||||
:20392F00F080120D72D20490F09F7418F07401A3F090F0A1740DF0E4A3F09071FB75F08014
|
||||
:20394F00120D72D2038002C203300A2690F0C6E06020C20490F09F7410F0C4A3F090F0A1D4
|
||||
:20396F007470F0E4A3F090720575F080120D72D20222C20222123EBD742CC0E07472C0E0C1
|
||||
:20398F0012416C15811581743FC0E07472C0E012416C1581158190F09BE0FEA3E0FF740872
|
||||
:2039AF002EFEE43FFF90F09BEEF0EFA3F07452C0E07472C0E012416C158115817475C0E0CF
|
||||
:2039CF007472C0E012416C158115817497C0E07472C0E012416C1581158190F09BE0FEA3AF
|
||||
:2039EF00E0FF74082EFEE43FFF90F09BEEF0EFA3F090F09DE4F0A3F07427C0E07472C0E04F
|
||||
:203A0F0012416C15811581023A39758205123E9AE58260012274B5C0E07472C0E0125A4666
|
||||
:203A2F0015811581903984020D4C7436C0E074FCC0E0E4C0E074C1C0E07472C0E012416CAB
|
||||
:203A4F00E58124FBF581229062BBE493C0E0740193C0E074CDC0E07472C0E012416CE58142
|
||||
:203A6F0024FCF58122123EBD123ED974DCC0E07472C0E012416C15811581123A5690F0E5E1
|
||||
:203A8F00E0C0E0A3E0C0E074EDC0E07472C0E012416CE58124FCF58190FAB4E0FF3395E06D
|
||||
:203AAF00FEC007C00674FBC0E07472C0E012416CE58124FCF581023A39758201123E9AE5E0
|
||||
:203ACF00826001221219A2903A74020D4C123EBD123ED9C2051238F590F08DE0C0E0A3E020
|
||||
:203AEF00C0E0740EC0E07473C0E012416CE58124FCF58122903ADC020D4C123EBD123ED95A
|
||||
:203B0F00D2057424C0E07473C0E012416C15811581D20490F08FE0FFBF02028018BF040231
|
||||
:203B2F008023BF05307435C0E07473C0E012416C15811581227444C0E07473C0E012416C64
|
||||
:203B4F0015811581227455C0E07473C0E012416C15811581227E00C007C0067460C0E07418
|
||||
:203B6F0073C0E012416CE58124FCF58122903B09020D4C123EBD123ED9746FC0E07473C0B7
|
||||
:203B8F00E012416C158115817487C0E07473C0E012416C1581158190F09BE0FEA3E0FF9033
|
||||
:203BAF00F0A1EEF0EFA3F090F94CE0FF7E0090F94DE0FD7C00C007C006C005C00474A0C0BA
|
||||
:203BCF00E07473C0E012416CE58124FAF58190F94AE0FF7E0090F94BE0FD7C00C007C006CC
|
||||
:203BEF00C005C00474B2C0E07473C0E012416CE58124FAF58190F948E0FF7E0090F949E047
|
||||
:203C0F00FD7C00C007C006C005C00474B2C0E07473C0E012416CE58124FAF58190F946E051
|
||||
:203C2F00FF7E0090F947E0FD7C00C007C006C005C00474B2C0E07473C0E012416CE5812423
|
||||
:203C4F00FAF58190F099E0FEA3E0FF8E02EFFB3395E0FCFD7428C39AF50F74019BF510E45B
|
||||
:203C6F009CF511E49DF512906F2DE493FDE4FC3395E0FBFAE50FC39DFDE5109CFCE5119B7F
|
||||
:203C8F00FBE5129AFA78647402F2E408F208F208F28D828C838BF0EAC007C006125D95AABB
|
||||
:203CAF0082AB83D006D00790F09FEA2EF0EB3FA3F090F0BFE0FF7E0090F0C0E0FD3395E053
|
||||
:203CCF00FC90F959E0FB7A00C007C006C005C004C003C00274BBC0E07473C0E012416CE50D
|
||||
:203CEF008124F8F581123F5A023A56758203123E9AE5826001221219A2903B82020D4C1210
|
||||
:203D0F003EBD123ED974D5C0E07473C0E012416C1581158174E8C0E07473C0E012416C15BE
|
||||
:203D2F0081158190F099E0FEA3E0FF90FA99EEF0EFA3F090F09BE0FEA3E0FF90F0A1EEF0E7
|
||||
:203D4F00EFA3F074FDC0E07473C0E012416C1581158190FA99E0FEA3E0FF8E02EFFB33958A
|
||||
:203D6F00E0FCFD74F0C39AFAE49BFBE49CFCE49DFD78647402F2E408F208F208F28A828B7F
|
||||
:203D8F00838CF0EDC007C006125D95AA82AB83D006D007EA2EFEEB3FFF90F09FEEF0EFA3C2
|
||||
:203DAF00F0EE5407601574075EFC7D00EEC39CFEEF9DFF90F09FEEF0EFA3F0906F2D75F00E
|
||||
:203DCF0080120D7290F0A1E0FEA3E0FF74082EFEE43FFF90F0A1EEF0EFA3F0D2049070B76A
|
||||
:203DEF0075F080120D7202390B758204123E9AE582600122903D0E020D4C123EBD123ED9BD
|
||||
:203E0F0090F09BE0FEA3E0FF74102EFEE43FFF90F09BEEF0EFA3F07411C0E07474C0E0120C
|
||||
:203E2F00416C15811581123F5A02390B758205123E9AE582600122903E09020D4C123EBD9A
|
||||
:203E4F00123ED97421C0E07474C0E012416C158115817435C0E07474C0E012416C15811547
|
||||
:203E6F008190F09F747CF0E4A3F090F09BE0FEA3E0FF90F0A1EEF0EFA3F0D2049070B7753E
|
||||
:203E8F00F080020D72903E4C020D4CE582C40354F8F582122622AF82BFFF02800D7824E464
|
||||
:203EAF00F28F821227817582012275820022C206C204C20590F099E4F0A3F090F09DF0A37E
|
||||
:203ECF00F090F09BF0A3F0C20922D20490F0A1E4F0A3F0906DAA93FF7E007428C39FFF74D2
|
||||
:203EEF00019EFE90F09FEFF0EEA3F0906DA975F080120D72C204906C08E493FF7E0090F03D
|
||||
:203F0F009FE0FCA3E0FDECC39FFFED9EFE90F09FEFF0EEA3F0906C0775F080120D72906ECB
|
||||
:203F2F006CE493FF7E0090F09FE0FCA3E0FDECC39FFFED9EFE90F09FEFF0EEA3F0D20490DC
|
||||
:203F4F006E6B75F080120D72C2042290F0E9E0FEA3E0FF4E601190F0E7E0FCA3E0FDC3EE1F
|
||||
:203F6F009CEF9D5002800890F0E7E0FEA3E0FFC006C007744FC0E07474C0E012416CE581CC
|
||||
:053F8F0024FCF5812275
|
||||
:206C0700801AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000E3
|
||||
:206C270000000000000000000000000000000000000000000000000000000000000000004D
|
||||
:206C47000000000000000000000000000000000000001C000000001F9F800000000038702B
|
||||
:206C670001C07F000000001F9FC000000000387001C07F000000001F9FE000000000387021
|
||||
:206C870001C0F7800000001C1CE000000000380001C0E3800000001C1CE0000000003800F1
|
||||
:206CA70001C0E39DC1C7701F9CE773B871D03873B9C7E39FE3E7F81F9FEFF3FCF9F03873E7
|
||||
:206CC700FDCEE39FE777F81F9FCFF3FDDDF03873FDDCE39CE7F7381C1F8E739DFDC0387366
|
||||
:206CE7009DF8E39CE7F7381C1C0E739DFDC038739DF8F79CE707381C1C0E739DC1C03873D5
|
||||
:206D07009DDC7F1FE7F7381F9C0FF3FDFDC03F739DDC7F1FE3E7381F9C0FF3FCF9C03F73D9
|
||||
:206D27009DCE1E1DC1C7381F9C0773B871C03F739DC7001C00000000000003800000000013
|
||||
:206D47000000001C0000000000000380000000000000001C000000000000038000000000EE
|
||||
:206D67000000001C000000000000038000000000000000000000000000000000000000006D
|
||||
:206D8700000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFA
|
||||
:206DA700FFFF800C000882A2AB55BFFFFFFF7DB4622800000010101176FF7BFFFF7FB7A9A1
|
||||
:206DC70055505100002922966FF7BFFFFFFFEAE622AA08000002542ABF3F7FFFFFFFFD59BF
|
||||
:206DE700B4102000002423B5B5DFFFFFFFFFF6AE48551000008890546AEFFFFFFFFFFBF51A
|
||||
:206E0700A382000000012DA3B3FFFFFFFFFFF6BE4E5209000490020D55DFFFFFFFFFFDDDBD
|
||||
:206E270068A9001000490CFBAB6FFFFFFFFFFEEB955A002000129122BFDFFFFFFFFFFFF579
|
||||
:206E4700658140400028127DEFFFFFFFFFFFFFEFAB28000000420A9775FFFFFFFFFFFFF71A
|
||||
:206E67004AC20400800C0008029CDFFFFFFFFFFFFF6A6A8D002000044D72AAFFFFFFFFFF07
|
||||
:206E8700FFD5D57480000240128EDFFDFFFFFFFFFFAEAA0A11200020525FF57FFFFFFFFFC1
|
||||
:206EA700FF7294AA240000010AAB6F77FFFFFFFFFDAF545488000004804D95EBFFFFFFFF37
|
||||
:206EC7005B58B5514000000808A6B3F77FFFFFFFFFAD4AA0100000029641DCAEFFFFFFFFD1
|
||||
:206EE700FDBFEA4802000000093EAB75EFFFFFFFFFD4B121080000000AC35DFF7FFFFFFFF6
|
||||
:206F0700EFEF444A64800000A152A6EFEFFFFFFFD6CAF5101800000002154BD5DFFFFFF7DE
|
||||
:206F2700EBD4D88500003838000000000000000000000000000000000000000000000000BE
|
||||
:206F47000000000000000000000000000000000007C00000000001FFF0000000000FFFF075
|
||||
:206F6700000000007FFFF000000001FFFFF000000007FFFFC00000001FFF80000000007FCB
|
||||
:206F8700F80000000000FFE00000000001FF000000000007FE00000000000FF80000000007
|
||||
:206FA700001FE000000000003FC00003E000007F80007FF00000FE0003FFF00001FC000F7F
|
||||
:206FC700FFF00001F8003FFFF00003F800FFFF800007F001FFE000000FE003FF0000000F44
|
||||
:206FE700C00FF80000001F801FF00000001F803FC00000003F003F800000003F007F0000BB
|
||||
:2070070000007E00FE0007E0007E01FC001FF000FC01F8007FF000FC03F001FFF000F8033E
|
||||
:20702700F003FFF001F807E007FF0001F807E00FF00001F00FC01FE00001F00FC03F800064
|
||||
:2070470003F00F803F000003F01F807E000003E01F807E000003E01F00FC01E003E01F0077
|
||||
:20706700FC07F803E01F00F80FFC03E03F00F80FFC03E03F01F81FFE03E03F01F81FFE0371
|
||||
:20708700E03F01F81FFE03C03E01F01FFE01C01E00F00FFC00000000000FFC0000000000C0
|
||||
:2070A70007F8000000000001E000000000000000303000001FF800000000FFFF0000000371
|
||||
:2070C700FFFFE000000FFFFFF000003FFFFFFC00007FF00FFE0000FF8001FF0001FE00009B
|
||||
:2070E7007F8003F800001FC007F000003FE00FE000007FF00FC00000FFF01F800001FFF8E7
|
||||
:207107001F000003FFF83F000007FEFC3E00000FFC7C7E00001FF87E7C00003FF03E7C00D2
|
||||
:20712700007FE03EFC0000FFC03FF80001FF801FF80003FF001FF80007FE001FF8000FFCE2
|
||||
:20714700001FF8001FF8001FF8003FF0001FF8007FE0001FF800FFC0001FFC01FF80003F8E
|
||||
:207167007C03FF00003E7C07FE00003E7E0FFC00007E3E1FF800007C3F3FF00000FC3F7F8D
|
||||
:20718700E00000FC1FFFC00001F80FFF800003F00FFF000007F007FE00000FE003FC0000BC
|
||||
:2071A7001FC001FE00007F8000FF8001FF00007FF00FFE00003FFFFFFC00000FFFFFF000BA
|
||||
:2071C7000003FFFFE0000000FFFF000000001FF800001010000000000000000000007C0016
|
||||
:2071E7008200000038004407007903811C0103810079000708080063773E1C3E77631010E9
|
||||
:20720700000003C00FF0081008100810081008100810081008100BD00BD008100FF0000018
|
||||
:207227000A000A0A0009084F70656E4550617065724C696E6B0A08006F70656E6570617051
|
||||
:2072470065726C696E6B2E64650A0049276D0920666173742061736C656570202E202E2097
|
||||
:207267002E20746F2077616B65206D653A000A52656D6F7665206261747465726965732C5B
|
||||
:207287002073686F727420626174746572790A00636F6E74616374732C207265696E736541
|
||||
:2072A7007274206261747465726965732E004465657020736C6565700A00546167204D4145
|
||||
:2072C700433A202573004368726F6D613239207625303458005374617274696E67202E207C
|
||||
:2072E7002E202E0A0A000A564261743A202564206D560A0054656D70657261747572653AE8
|
||||
:20730700202564430A0A000C466C617368696E67207625303478202E202E202E000C4F54FE
|
||||
:2073270041204641494C4544203A280A0A000C4E6F74204F544120696D616765000C577271
|
||||
:207347006F6E67204F544120696D616765000C435243206572726F72000C4572726F722057
|
||||
:20736700436F64652025640057616974696E6720666F722064617461202E202E202E0A00FA
|
||||
:207387000A466F756E642074686520666F6C6C6F77696E672041503A000A4150204D414317
|
||||
:2073A7003A202530325825303258002530325825303258000A43683A2025642052535349F7
|
||||
:2073C7003A202564204C51493A2025640A00084E6F20415020666F756E64203A280A080A80
|
||||
:2073E700005765276C6C2074727920616761696E20696E2061000A6C6974746C652077681D
|
||||
:20740700696C65202E202E202E00087A7A5A5A5A202E202E202E0A080A000C454550524FAA
|
||||
:207427004D204641494C4544203A280A0A000C536C656570696E6720666F72657665722021
|
||||
:157447002E202E202E0A0A00564261743A202564206D560A0015
|
||||
:203F9400C007C006C005C004C00390FAA2E0600302408890FAA3E0FF24FB5003024085EFC7
|
||||
:203FB4002F2F903FBA73023FC9023FE702406802407F02408590FAA0744BF0E4A3F090FA55
|
||||
:203FD400A2740BF090FAA37401F090FAA47468F002408890FA9D1248B0E582FF6045EF2417
|
||||
:203FF400E0FFBF600040027F1F90FAA5E0FE0E90FAA5EEF0C0078E821243DAAD82AE83152C
|
||||
:204014008190FAA4E0FC7B002DFDEB3EFE8D828E837467C0E01248ABAE82158190FAA4EEB3
|
||||
:20403400F0800B90FAA37402F090FAA4E0FFEF75F002A4245CF582747435F0F583E493FE66
|
||||
:20405400A3E493FF90FAA0EEF0EFA3F090FAA2740BF0802090FAA37403F090FAA074E3F069
|
||||
:20407400741AA3F090FAA203F0800990FAA37404F0C3802D90FAA0E0FEA3E0FFEE5401246D
|
||||
:20409400FFE433FDEFC313CE13CEFF90FAA0EEF0EFA3F090FAA2E0FF1F90FAA2EFF0ED24B6
|
||||
:0C40B400FFD003D004D005D006D00722B6
|
||||
:20745C009B01B3013303C90089019101990019013101930013012301CD01D90199039D0113
|
||||
:20747C00B90139037302D30193033B017301B7039701A7012703370167016702DB001B0345
|
||||
:20749C006303C500D10011038D00B10031028B00A3002302ED008D03B103DD001D0371035A
|
||||
:2074BC0077038B03A303BB003B02BB03D70017034703B7003702C702F70213028F02650054
|
||||
:2074DC00850169000903A10121034D000D01590019026101610243025300EF024301F1027B
|
||||
:2074FC00E501E901C9033D01790179022F014F014F02DB037B036F03F500C503D103BD00B4
|
||||
:0E751C003D02AF002F02DD03BD03D703AF0316
|
||||
:2040C000C007C006C005C004C001C000AC82AD83AEF0FFBF20005031BF0A0302415F8F826F
|
||||
:2040E000C007C006C005C004C003C002C001C000C0251242A7D025D000D001D002D003D0B9
|
||||
:2041000004D005D006D00780567E00EF24E0FFEE34FFFEEF2FFFEE33FEEF2498F582EE3434
|
||||
:2041200063F583E493A3E493C4540FFE90F0B3EEF0300507EE2EFE90F0B3F090F0B3E0FF52
|
||||
:204140003395E0FE0FBF00010E90F099E0FCA3E0FDEF2CFFEE3DFE90F099EFF0EEA3F0D0DB
|
||||
:2041600000D001D004D005D006D00722C007C006C005C004C003C001C000E58124F6FFC05D
|
||||
:2041800007C006C005C004C003C002C001C000C02512425AD025D000D001D002D003D00421
|
||||
:2041A000D005D006D007E58124F6F886050886068D828E83E493FCBC0C7290F099E4F0A389
|
||||
:2041C000F0C007C005C006C0E0C0E09040C01256F5E58124FBF58190F099E0FDA3E0FE33CB
|
||||
:2041E00095E0FCFB7428C39DFD74019EFEE49CFCE49BFB78647402F2E408F208F208F28DB0
|
||||
:20420000828E838CF0EBC007C002C001C000C025125D95AB82AC83ADF0FED025D000D00124
|
||||
:20422000D002D00790F099EBF0ECA3F0C007E58124F5F8E6C0E008E6C0E0E4C0E0C0E0905C
|
||||
:20424000109A1256F5E58124FBF581D000D001D003D004D005D006D00722300625300506DA
|
||||
:204260007E147F0080047E0A7F0090F0B4EEF03005067E207F0080047E107F0090F0B3EE86
|
||||
:20428000F0223005067E207F0080047E107F0090F0B4EEF03005067E147F0080047E0A7F3A
|
||||
:2042A0000090F0B3EEF022AF82BF08028018BF0902804EBF0A028013BF0B028055BF0C01D6
|
||||
:2042C00022BF0D568038B20502425A12425A90F0B4E0FE3395E0FD90F09BE0FBA3E0FCEEC5
|
||||
:2042E0002BFEED3CFD90F09BEEF0EDA3F090F09DE0FDA3E0FE90F099EDF0EEA3F022B2042C
|
||||
:204300002290F099E0FDA3E0FE90F09DEDF0EEA3F02290F09DE4F0A3F0227E00C007C006B6
|
||||
:12432000742AC0E07475C0E0125A46E58124FCF58122F4
|
||||
:15752A00496E76616C69642063686172203078253032780A00F6
|
||||
:20433200E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB2E
|
||||
:2043520000438004002275FB02228582F9E5F830E1FB53F8FDE5F820E0FB85F9822253F35D
|
||||
:20437200C775FA2275FC0C75F8C043F4C043F102D20B2253F1FD53F43F75FA0075FC3175B0
|
||||
:08439200F84043F338C20B228E
|
||||
:20439A00858283D0F0D0E0D082C082C0E0C0F022C00074FB2581F8E5828682088683088628
|
||||
:2043BA00F0D0002275F008C58213C58233D5F0F7C58222E583A2E713F583E58213F582220C
|
||||
:2043DA00D083D0E0D0F0C0F0C0E0C083E582A4F58285F08322C000E58124FDF8E6F88582AD
|
||||
:2043FA00F0A4F582E8A8F08583F0A428F583E5F03400F5F0E4D00022C000C001C0E0C0F047
|
||||
:20441A0074FA2581F88600E58288F0A4F582A9F0E58388F0A429F583E5F03400F9D0E088FE
|
||||
:20443A00F0A429C5F03400F9D0E0C0F088F0A429D0F0D001D00022C000C001C002E58124CE
|
||||
:20445A00FBF8E6F918E6F88582F0A4C0E0AAF0E58388F0A42AF8E5F03400FAE98582F0A478
|
||||
:20447A0028C0E0E5F03AFA74003400F8E98583F0A42AFAE5F0388AF0D083D082D002D00139
|
||||
:20449A00D00022D0E0D0F0C000C001C002C0F0C0E074F82581F9E7F809E7F922D002D00175
|
||||
:2044BA00D00022C9C583C9C8C582C82212449D75F0081244BDE0A31244BDF0A3D5F0F302C7
|
||||
:2044DA0044B612449D75F0081244BDE493A31244BDF0A3D5F0F20244B612449DC375F008BF
|
||||
:2044FA001244BDE0A3F5021244BDE03AF0A3D5F0EF0244B612449D75F0081244BDE0A3F5BA
|
||||
:20451A00021244BDE05AF0A3D5F0EF0244B612449DC375F0081244BDE0A3F5021244BDE04C
|
||||
:20453A009AF0A3D5F0EF0244B612449DC375F0081244BDE0A3F5021244BDE0A39AD5F0F0EF
|
||||
:20455A000244B612449D75F0081244BDE0A3F5021244BDE0A36A7007D5F0EED30244B6C39C
|
||||
:20457A000244B6C8C0E075F008E038F0A3D5F0F9D00022D3E402457DC374FF02457DC000C0
|
||||
:20459A00C00174FA2581F8E6F5F0088601496015088600E8F0A374FF25F0F5F074FF39F505
|
||||
:2045BA000145F070EED001D00022C000C001C00274F92581F9E7D3601CF5F0098700098700
|
||||
:2045DA0001C3E0F502A31244BDE0A31244BD6A7004D5F0EED3D002D001D00022C000C00160
|
||||
:2045FA00C00274F82581F9E7F5F00987024A601F0987000987011244BDE0A31244BDF0A350
|
||||
:20461A0074FF25F0F5F074FF3AF50245F070E7D002D001D00022C000C001C00274F92581F8
|
||||
:20463A00F9E76015F5F00987000987011244BDE0A31244BDF0A3D5F0F3D002D001D000227C
|
||||
:20465A00C083C082E06003A380FAC3E582D0F095F0F582E583D0F095F0F58322C003C002A9
|
||||
:20467A00C001C000C0E0C0F0C083C082A98174F62581F886F018860075020175030075829D
|
||||
:20469A0011A2F74014C3E833F8E5F033F5F0C3EA33FAEB33FB058280E8E4C003C002C0E054
|
||||
:2046BA00C0E0AA81C0F0C000C0E0C0E0A881C0E0C0E0C0E0C0E0AB81C000C001C375830450
|
||||
:2046DA0086F018E71995F0D583F6D001D000402BC000C001C375830486F018E795F0F71909
|
||||
:2046FA00D583F585020085030175830486F018E745F0F719D583F5D001D00074FC28F8C34C
|
||||
:20471A0075830408E613F6D583F9C00074FC2AF8C375830408E613F6D583F9D000D5829823
|
||||
:20473A0020D508D082D083D0F0D00074F42581F58130D508D082D083D0F0D000E8D000D0DF
|
||||
:20475A0001D002D00322C2D5024676D2D5024676C003C002C001C000C0E0C0F0C083C082E2
|
||||
:20477A00A98174F62581F886F07401758219A2F7400A23C5F023C5F0058280F2C0E0E4C022
|
||||
:20479A00E0C0E0C0E0AA81C0F0C0E0C0E0C0E0A881C0E0C0E0C0E0C0E0AB81C000C001C30B
|
||||
:2047BA0075830486F018E71995F0D583F6D001D000402BC000C001C375830486F018E7952C
|
||||
:2047DA00F0F719D583F585020085030175830486F018E745F0F719D583F5D001D00074FC4E
|
||||
:2047FA0028F8C375830408E613F6D583F9C00074FC2AF8C375830408E613F6D583F9D0004F
|
||||
:20481A00D58298D082D083D0F0D00074F42581F581E8D000D001D002D00322C006C005C03B
|
||||
:20483A0004C003C002C001C00074F72581F886F074017C09A2F7400923C5F023C5F00C80BD
|
||||
:20485A00F3FBE4FAA9F0F88582F0FDFEC3E58298E583994011C3E58298F582E58399F58329
|
||||
:20487A00EA4DFDEB4EFEC3E913F9E813F8C3EB13FBEA13FADCD620D5048D828E83D000D0EA
|
||||
:20489A0001D002D003D004D005D00622C2D5024835D2D5024835E0C0E02401F0A3E0C0E0C3
|
||||
:2048BA003400F0A3E0D083D0826014B4600AC000A882E2D000F582224009E493F58222E092
|
||||
:2048DA00F58222C000A882E6D000F5822212449D75F004D31244BDE0FA3400F0EAA31244C9
|
||||
:2048FA00BDF0A3D5F0EE0244B612449D75F004C31244BDE0FAA31244BDE0A36A7004D5F0B7
|
||||
:20491A00EFD30244B612449DC3E0A398E0A399E0A39400E0A394000244B612449DC3E0A36F
|
||||
:20493A0038E0A339E0A33400E0A334000244B675F004E07004A3D5F0F9F58222A3A3A3E07F
|
||||
:02495A00332206
|
||||
:04495C0075C90B22EC
|
||||
:20496000C0E0C007C006C0D075D000AEDAAFDB74012EF5DAE43FF5DBD0D0D006D007D0E0C1
|
||||
:2049800032C007C006C005C004C000AEDAAFDB784AEEF208EFF27848E5E2F27849E5E3F27E
|
||||
:2049A000EEB5DAE7EFB5DBE37848E2FC08E2FD08E2FE08E28C828D838EF0D000D004D005C5
|
||||
:2049C000D006D0072285E28222E4F5DAF5DBF5E4F5E5F5E6F5E7F5E275E40543D84043B885
|
||||
:2049E0000222AF82AE83ADF0FC784CEFF2EE08F2ED08F2EC08F21249817850C0E0E582F2A1
|
||||
:204A0000E58308F2E5F008F2D0E008F2124981AA82AB83AEF0FF7850D3E29AF4B3FAB30875
|
||||
:204A2000E29BF4B3FBB308E29EF4B3FEB308E29FF4FF784CC3E29A08E29B08E29E08E29FAF
|
||||
:034A400050CA2237
|
||||
:204A430053C07F53A1FE53BEFC3243870122AF82AE83ADF0FC7854EFF2EE08F2ED08F2EC40
|
||||
:204A630008F290FAA6E4F090FAA7F090FAA874DFF090FAA974BEF090FAAAE054E0F090FA88
|
||||
:204A8300AAE0541FF090FAAB7407F090FAACE054E0F090FAACE0549F4420F090FAACE05485
|
||||
:204AA3007FF090FAADE054FC4402F090FAADE054FBF090FAADE054F7F090FAADE054CFF015
|
||||
:204AC30090FAADE0543F4440F07854E2F5F008E242F008E242F008E245F0701B7B0175133C
|
||||
:204AE3006F7514FC85141590FAA6E515F07A6F90FAA7EAF0024B857854C3E2943F08E2946F
|
||||
:204B03000008E2940008E29400500C7854743FF2E408F208F208F27854E225E0F51608E24F
|
||||
:204B230033F51708E233F51808E233F519E5162516F516E51733F517E51833F518E51933F4
|
||||
:204B4300F519747DC0E0E4C0E08516828517838518F0E5191247607854C0E0E582F2E58382
|
||||
:204B630008F2E5F008F2D0E008F2158115817B007D687EFC8E0590FAA6EDF07E6890FAA702
|
||||
:204B8300EEF053C07F53A1FE43A11075A8A0EB70147854E2F5F008E242F008E242F008E2DB
|
||||
:204BA30045F070012253BEFBE5BE30E5FBE5C654384441F5C6E5C630E6FB43BE0453C67F9B
|
||||
:204BC3007854C3E2F5F074F095F008E2F5F074FF95F008E2F5F0E495F008E2F5F0E495F05C
|
||||
:204BE300501B7DF07EFF7854E22410F208E23400F208E234FFF208E234FFF280117854E21C
|
||||
:204C0300FD08E2FE7854E4F208F208F208F2EB60067A007C0080047A107C008AA175C000EB
|
||||
:204C230043D6817AA67CFA8AD48CD575D60175A204E5A570FC75A2028EA48DA3AEA5EEB5B4
|
||||
:204C4300A50280FA43C702EB60077B0075BE07800375BE06000000E5BE5403600875D701B2
|
||||
:204C6300004387010053C7FDE5BE30E5FB75BE00E5BE30E5FB75C679E5BE30E6FB7E007D53
|
||||
:1B4C830000000DBD80FB0EBE80F575C639E5C620E6FB75C63875BE04024B91E8
|
||||
:0E7677000606060606060407070707070704AF
|
||||
:204C9E00AF8275BB0074304FF5B575B473E5B420E6FBE5B430E7FBAEBA7F00ADBB7C0090BC
|
||||
:204CBE00FAB2EC4EF0ED4FA3F08FB522C21590FAB2E0FEA3E08E82C4C582C4540F6582C569
|
||||
:204CDE0082540FC5826582C582F58374E2C0E07404C0E0124451AC82AD83AEF0FF15811589
|
||||
:204CFE008190FAB0E0FAA3E0FB74FFC0E07407C0E08A828B83124451A882A983AAF0FB1594
|
||||
:204D1E00811581ECC398FCED99FDEE9AFEEF9BFF747DC0E08C828D838EF0EF124412AC82D7
|
||||
:204D3E00AD83AEF0FF1581EFC40354F8CEC403CE6ECE54F8CE6EFFEDC40354074EFEEDC4BE
|
||||
:204D5E000354F8CCC403CC6CCC54F8CC6CFDEF30E70FD215C3E49CFCE49DFDE49EFEE49F12
|
||||
:204D7E00FF90FAAEE0C0E0A3E0C0E08C828D838EF0EF124760AC82AD83AEF0FF15811581D0
|
||||
:204D9E0074FF2CFC74033DFDE43EFEE43FFF74FFC0E07407C0E08C828D838EF0EF124760F5
|
||||
:164DBE00AC821581158190FAB4ECF030150790FAB4C3E49CF0228C
|
||||
:204DD400E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB82
|
||||
:204DF400004380040022C007C006AF82BF64004027BF6A00502290DF097421F090DF0A74E9
|
||||
:204E14003BF090DF0B7413F08F06EE249CFE90DF0675F003A4F0802F90DF097422F090DF94
|
||||
:204E34000A74BBF090DF0B7413F0BFC8004013BFE100500EEF2438FF90DF0675F00CA4F0A8
|
||||
:204E5400800590DF06E4F0D006D00722C00775E10490DF3BE0B401FCD00722124E607F000D
|
||||
:204E74008F057EDFEFC390753F938D828E83F00FBF200040EB90DF237488F090DF247431C5
|
||||
:204E9400F090DF257409F090DF2E748EF075911075ED00759D0075EF0322C007AF82C3EFC1
|
||||
:204EB4006480946250047FE2800EC3748A8FF063F08095F050027F0A741E2FC31390755F53
|
||||
:204ED4009390DF2EF0D00722C007C006AE82AF838ED48FD575D601000000000000000000A4
|
||||
:204EF400D006D0072275D68100000000000000000022C007C006C005AE82AF83124EF98F45
|
||||
:204F14000590FC78EDF090FC79EEF07E767FFC8E828F83124EDCD005D006D00722C007C0BC
|
||||
:204F340006C005AE82AF83124EF98F0590FC7EEDF090FC7FEEF07E7E7FFC8E828F83124E7A
|
||||
:204F5400DCD005D006D00722301604E5EF700122124E6053C0FE43B801E5ED75F080A424C0
|
||||
:204F7400B6F58274FA35F0F583124F0675E1022253B8FE124EF9124E6075D10053C0FE2269
|
||||
:204F9400AE82AF837CFF7DFF124F848E828F83124F3175E90075E103E5E920E42375820F59
|
||||
:204FB400C005C004124C9ED004D00590FAB2E0FEA3E0FFC3EE9CEF9D50DE8E048F0580D88E
|
||||
:204FD400124EF9C005C004124F5CD004D0057423C0E08C828D831248A615817404C0E01260
|
||||
:204FF40043EFAC82AD83158190F0E7ECF0EDA3F022C025C0E0C0F0C082C083C007C006C08B
|
||||
:2050140005C004C003C002C001C000C0D075D000E5D130E040E5ED75F080A424B6FE74FA31
|
||||
:2050340035F0FF53D1FE8E828F83E0FD248240200D0DED2EF582E43FF583E0FF30E711E5DE
|
||||
:20505400ED04FF8FEDBF030375ED00E5EF14F5EF124F5C800F7474C0E07475C0E0125A46CE
|
||||
:205074001581158153C0FED0D0D000D001D002D003D004D005D006D007D083D082D0F0D06E
|
||||
:20509400E0D02532201806124F84C21622201605D216024F5C22E59D75F080A424B6FE748F
|
||||
:2050B400FA35F0FF8E828F83E0FD7403B5EF047582FF228D037C0074022BF9E43CFAE92EB1
|
||||
:2050D400F582EA3FF583E0FA747F5AD39494F4FABA7F0040047AFF8003EA2AFA90F0BFEAE4
|
||||
:2050F400F00BBB00010CEB2EF582EC3FF583E0A2E71324B390F0C0F00EBE00010FC005C0C2
|
||||
:2051140006C00790F95B124630158115811581E59D04FF8F9DBF0303759D00D21910AF024C
|
||||
:20513400C219E5EFFF04F5EFA21992AFEF7007C005124F5CD0058D8222D21A10AF02C21A52
|
||||
:10515400AFEF75EF03A21A92AFEF7003024F5C2218
|
||||
:20753F00D3917D044522000F0022BB131D3B1373A7650700181E1CC700B0B610EA2A001F2E
|
||||
:20755F00030506080B0E191C242527293855408D8A84CAC4C0646D612069727120756E6553
|
||||
:09757F00787065637465640A000C
|
||||
:10768500DFD900008080131A0000DFD9207E134265
|
||||
:1700E10090FC477456F090FC487412F090FC4903F090FC4A7485F0AA
|
||||
:20516400E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FBEE
|
||||
:20518400004380040022C007C006C005C004C003C002C001C000E582785BF27E00C21C7806
|
||||
:2051A4005CE4F2C006785CE2C0E09010001243EFAA82AB831581785DEAF2EB08F2785F74E8
|
||||
:2051C40004F2E408F2785DE2FA08E2FBE4FCFE7404C0E0E4C0E0744BC0E074FCC0E08A826C
|
||||
:2051E4008B838CF0EE1206E1E58124FCF5817404C0E07447C0E074FCC0E090FC4B1245C4C9
|
||||
:20520400158115811581921DD006201D030252EE785FE2FB08E2FCC3941040030252EEC07B
|
||||
:2052240006785D795FE3C5F0E225F0FB09E3C5F008E235F0FAE4FCFE7402C0E0E4C0E07497
|
||||
:205244004BC0E074FCC0E08B828A838CF0EE1206E1E58124FCF58190FC4BE0F51A74FFB5E8
|
||||
:205264001A05D0060252EED006785BE2B51A5D90FC4CE0FCBC020040531C1C8C06785AC3D8
|
||||
:20528400E29C5004785AE2FCC0067B007858E2F51B08E2F51C785DE2FD08E2FF74022DFD4D
|
||||
:2052A400E43FFF785FE22DFD08E23FFA7E007F00C004C003C01BC01C8D828A838EF0EF12EC
|
||||
:2052C40006E1E58124FCF581D21CD00690FC4CE0FF7D00785FE2FB08E2FCEF2BFBED3CFC1B
|
||||
:2052E400785FEBF2EC08F2025214785CE22401F2785CE2B40A0050030251A7301C048E0735
|
||||
:2053040080027FFF8F82D000D001D002D003D004D005D006D00722758204C007C006C0056D
|
||||
:20532400C004C003C002C001C0001217C412539CD000D001D002D003D004D005D006D00715
|
||||
:20534400301B26C007C006C005C004C003C002C001C0001216E912539CD000D001D002D067
|
||||
:2053640003D004D005D006D007758204C007C006C005C004C003C002C001C0001217FD751E
|
||||
:205384008200125C24D000D001D002D003D004D005D006D007D2AF22D21B785874A2F2747D
|
||||
:2053A400FD08F2785A7407F275822A12518AE582FF30E71B785874A2F274FD08F2785A7484
|
||||
:2053C40006F275820112518AE582FF30E701227404C0E0E4C0E0C0E090FDB212459815814C
|
||||
:2053E400158115817404C0E074B2C0E074FDC0E090FDA41245C4158115811581921E501D63
|
||||
:205404007404C0E074B2C0E074FDC0E0906A721245C4158115811581921E40012290F9575D
|
||||
:205424007444F090F9567467F090FDA4E0FF90F953F090FDA5E0FE90F952F090FDA6E090BC
|
||||
:20544400F951F090FDA7E090F950F090FDA4E4F07D007C00C006C005C007C00474A2C0E067
|
||||
:2054640074FDC0E0E4C0E07488C0E07475C0E0125A46E58124F7F58190F950E0FF7E0090FF
|
||||
:20548400F951E0FD7C00C007C006C005C0047496C0E07475C0E0125A46E58124FAF58190E0
|
||||
:2054A400FDA2E024BF90F955F090FDA3E024BF90F954F090F956E0FF7E0090F957E0FD7C83
|
||||
:2054C40000C007C006C005C00474A0C0E07475C0E07436C0E074FCC0E0125ABFE58124F86E
|
||||
:2054E400F58190F954E0FF7E0090F955E0FD7C00C007C006C005C00474A0C0E07475C0E06E
|
||||
:20550400743AC0E074FCC0E0125ABFE58124F8F58190F952E0FF7E0090F953E0FD7C00C0D9
|
||||
:2055240007C006C005C00474A0C0E07475C0E0743EC0E074FCC0E0125ABFE58124F8F5814F
|
||||
:2055440090F950E0FF7E0090F951E0FD7C00C007C006C005C00474A0C0E07475C0E07442D5
|
||||
:20556400C0E074FCC0E0125ABFE58124F8F581785874AEF274FA08F2785A7402F2758212C5
|
||||
:2055840012518AE58230E70122785874B0F274FA08F2785A7402F275820912518AE582306D
|
||||
:2055A400E70122C21B229055B57416C39582F5F02275F020C2ADC2AC43AE0100E5AE20E7EB
|
||||
:2055C400FB05AD05ADD5F0F09000008583AD8582ACA375AB2275F00275F900E5F830E1FB18
|
||||
:2055E40053F8FDE5F820E0FBC0F9D5F0EB43AE02E5AE20E6FBD0E0D0AFF5AFE5AE20E6FB30
|
||||
:2056040053AEFDE5AE20E7FBE583B440BE75C90B80FEC007C006C005C004C0031255AAAC7C
|
||||
:2056240082AD83AEF0FF8E03C003C004C00590FDA212463015811581158175D6FF75A8005A
|
||||
:2056440075C70390FDA2E473D003D004D005D006D00722C007C00675A80075B800759A0050
|
||||
:2056640075C70075BE00E5BE30E5FB75C679E5BE30E6FB7F007E00000EBE80FB0FBF80F515
|
||||
:2056840075C639E5C620E6FB75C63875BE04D006D0072243B404E5B4540C600280F8E5BCFE
|
||||
:2056A40065BDF58222125697C082125697C082125697C082125697D083D0F0D0E022C000C4
|
||||
:0B56C4008582BC7861E2F5BCD00022BA
|
||||
:20758800534E20257325303278253032780025303278253032780A002530325825303258C6
|
||||
:0175A80000E2
|
||||
:2056CF00E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB7E
|
||||
:2056EF00004380040022C007C083C082858107C004C003C002C001C00074F42581F8868380
|
||||
:20570F0018868218860018E0A36013B4250B7C007A00E0A36008B425161259D780E9D0007F
|
||||
:20572F00D001D002D003D004D082D083D00722B4630518E61880E2FB4420B46D3AEB5420C5
|
||||
:20574F0003F9C083C0821259737C0874FF2C93C083C082FAC47B02540F29905A06931259EB
|
||||
:20576F00D7EADBF3D082D083DC06D082D0838097743A1259D780D4EBB42A09BA009B740168
|
||||
:20578F004CFC808EB43007BA0004740680F2FB24D0501224F6400E240AFB740A8AF0A42B66
|
||||
:2057AF00FA740480DBBB6C0DEC54086004741080CF740880CBBB733CEC5408C083C08270EC
|
||||
:2057CF000512597A8003125973EC54047009E0A360981259D780F7BA0002808EE0A3600AC7
|
||||
:2057EF001259D7DAF780830258C774201259D7DAF9025779EB4420B478EDC083C082125990
|
||||
:20580F0090C083C082E5F023F90324FF2582F582E5833400F583E054F0701119E0700D19E7
|
||||
:20582F001582E582B4FF021583D5F0EAB9000109EC5420600B09EC54026005742D1259D73E
|
||||
:20584F00EC54046018EAC39940136011FAEC5402C4032420F582E5821259D7DAF9EC5420D9
|
||||
:20586F00600B19EC54027005742D1259D7EB542003FAD082D083E904C313FC142582F58209
|
||||
:20588F00E5833400F583E954016005E079018005E07902FBC4540F2AC083C082905A0693B4
|
||||
:2058AF00D082D0831259D7EBD9EB1582E582B4FF021583DCDB025779BB640674204CFC80EE
|
||||
:2058CF0008BB75028003025716C083C082125990C0F07408C395F0244FF9E434FCFBE0A39B
|
||||
:2058EF001259CCF0A31259CCD5F0F31259CCF5F0EC54206028E5F054807006EC54DFFC8022
|
||||
:20590F001CD0F0C0F07408C395F0244FF582E434FCF583C3E0F9E499F0A3D5F0F775F00ADB
|
||||
:20592F00E4F0A3D5F0FBD0E0C403FB90FC5775F00AE0F9540F24FBE950022403F954F0243F
|
||||
:20594F00B0E950022430F0A3D5F0E690FC4FC375F012E033F0A3D5F0F9DBD090FC5775F04F
|
||||
:20596F000A02581086831886821822E61860F5648060F164C0600585938380EA7583FF80B4
|
||||
:20598F00E5EC5401701F88F07583FFEC5418600A5410600418181818181818888218E5F0AB
|
||||
:2059AF00C398F5F022EC5418600E5410600575F00880B175F00480AC75F00280A7C583CB13
|
||||
:2059CF00C583C582C9C58222C083C082C001C0008F008682188683181818188601188600B4
|
||||
:2059EF001259FBD000D001D082D08322C082C083850082850183223031323334353637383F
|
||||
:205A0F003941424344454630313233343536373839616263646566C007C006C005C004FF32
|
||||
:205A2F00BF0A0675820D12435C8F8212435CD004D005D006D00722C007C001C000A20B9212
|
||||
:205A4F001FE58124FAFF200B03124370C007E58124F9F8E6C0E008E6C0E0E4C0E0C0E09098
|
||||
:205A6F005A261256F5E58124FBF581201F03124385D000D001D00722C007C006C005C00473
|
||||
:205A8F00C003C001AC82FF8C018F0487060987071974012EFBE43FFDA70309A7058E828F2D
|
||||
:205AAF0083ECF0D001D003D004D005D006D00722C007C006C005C001C000E58124F6FFE525
|
||||
:205ACF008124F8FE7D00C007E58124F5F8E6C0E008E6C0E0C006C005905A871256F5E5818E
|
||||
:195AEF0024FBF58124F8F88682088683E4F0D000D001D005D006D00722C3
|
||||
:0200F800C22024
|
||||
:205B0800E58620E0FB225390FD00225380FB0022E58620E0FB004390020022E58620E0FB40
|
||||
:205B2800004380040022C007AF82E58620E0FB53807F008F82125CAB00E58620E0FB438071
|
||||
:205B480080D0072253BEFC32AE82AF838E828F83E493FD74012EFBE43FFCEDFA6052539054
|
||||
:205B6800FD008B828C83E493FD0BBB00010CE58620E0FB53807F008D82125CAB00E5862052
|
||||
:205B8800E0FB438080EA14FDED6015E58620E0FB8B828C83E493F5C1A3AB82AC831D80E84F
|
||||
:205BA8008B068C07E58620E0FB0043900200809C2230200122D220758201125C244390027C
|
||||
:205BC8005380BF43F42875C20075C5317586009000FDE4F5F01249E24390049000FDE4F55F
|
||||
:205BE800F01249E22090FD9075A9125B505390FD00E58620E0FB53807F00758204125CABAC
|
||||
:205C080000E58620E0FB4380803090FDE58620E0FB00439002009075B5025B50E582601697
|
||||
:205C280090F953E054F0600122438FC143FDC143F62E43FE2E2253F4D790F953E0FF54F030
|
||||
:205C4800600B53807E5390D100D2860022538F3A53FD3A53F6D153FED122202001229076E5
|
||||
:205C680041125B50758200125C24C22022125BB95390FD003021067E137F0080047E107F93
|
||||
:205C880000E58620E0FB53807F008E82125CAB00E58620E0FB438080E58620E0FB00439039
|
||||
:205CA800020022C007AF82E58620E0FB8FC1D007227EFF7FFF744EC0E07476C0E0125A4678
|
||||
:205CC8001581158190764BC007C006125B50D006D00720902F900032E4F5F0C007C006123F
|
||||
:205CE8004A5112565775820F124C9ED006D00790FAB2E0FCA3E0FDC3EC9EED9F50D48C066C
|
||||
:205D08008D0780CE7423C0E08E828F831248A615817404C0E01243EFAC82AD83158190F0DA
|
||||
:205D2800E9ECF0EDA3F07582011217C4125C621219A27460C0E07476C0E0125A4615811539
|
||||
:025D48008122B6
|
||||
:2075A900050107000900040607070F0002008F046180012802302902501702820802602212
|
||||
:2075C900102001010103040906060A040419030409102101010103840986460A844419039A
|
||||
:2075E9004409102201010143040986460A84441983040910250A0A0102140D1414010000D3
|
||||
:207609000000000010264A4A0182540D54540100000000000010270A0A0102140D14140172
|
||||
:20762900000000000000102401810183840986460A84441903040900028200050102000027
|
||||
:2076490000000112005570646174696E6720646973706C61790A0055706461746520636F5D
|
||||
:087669006D706C6574650A0088
|
||||
:205D4A00AE82AF837C007D007B10EF235401FAEE2EFEEF33FFEC2CFCED33FDEA60034304F2
|
||||
:205D6A00017862C3E2F5F0EC95F008E2F5F0ED95F040117862D3E29CF4B3FCB308E29DF4B5
|
||||
:0B5D8A00FD430601DBC48E828F8322E4
|
||||
:205D9500AC82AD83AEF0FF33E433FB6013C3E49CF556E49DF557E49EF558E49FF5598008B8
|
||||
:205DB5008C568D578E588F59AC56AD57AE58AF597867E233E433FA60207864E2D3F43400E8
|
||||
:205DD500F55608E2F43400F55708E2F43400F55808E2F43400F55980117864E2F55608E2C2
|
||||
:205DF500F55708E2F55808E2F559786CE556F2E55708F2E55808F2E55908F28C828D838E71
|
||||
:205E1500F0EFC003C002125E697868C0E0E582F2E58308F2E5F008F2D0E008F2D002D003D7
|
||||
:205E3500EA6B60207868E2D3F43400FA08E2F43400FB08E2F43400FE08E2F434008A828BFB
|
||||
:145E5500838EF0227868E2F58208E2F58308E2F5F008E222A0
|
||||
:205E6900AF82AE83ADF0FC7870EFF2EE08F2ED08F2EC08F27A007B007E007F007D20787326
|
||||
:205E8900E2235401FC7870E225E0F208E233F208E233F208E233F2EA2AFAEB33FBEE33FE6F
|
||||
:205EA900EF33FFEC6003430201786CC3E2F5F0EA95F008E2F5F0EB95F008E2F5F0EE95F0C5
|
||||
:205EC90008E2F5F0EF95F04022786CD3E29AF4B3FAB308E29BF4B3FBB308E29EF4B3FEB3D3
|
||||
:1D5EE90008E29FF4FF7870E24401F2DD917870E2F58208E2F58308E2F5F008E22233
|
||||
:0600B200E478FFF6D8FD22
|
||||
:200090007924E94400601B7A0190767178627593FCE493F2A308B800020593D9F4DAF275C7
|
||||
:0200B00093FFBC
|
||||
:1B5F060020F71130F6138883A88220F509F6A8837583002280FEF280F5F0229A
|
||||
:205F2100AA83AB828BF090F075E0A4F8A9F08AF0E0A429F98BF0A3E0A429F58388822222D0
|
||||
:205F4100AF82AE83ADF0FC787BEFF2EE08F2ED08F2EC08F2787BE2FF7879E28FF0A4FFAD46
|
||||
:205F6100F07881EFF208EDF2787BE2FF7877E28FF0A4FFADF0787FEFF208EDF27882E2FF71
|
||||
:205F8100787EE2FE7877E28EF0A42FFF7882F2787DE2FE7878E28EF0A42F7882F27881E25E
|
||||
:205FA100FE08E2FF787DE2FD7877E28DF0A4ABF02EFEEB3FFF7881EEF208EFF2787CE2FDAE
|
||||
:205FC1007878E28DF0A4ABF02EFEEB3FFF7881EEF208EFF2787CE2FF7879E28FF0A4787E5A
|
||||
:205FE100F2787CE2FF7877E28FF0A4FFADF0787CEFF208EDF2787BE2FF787AE28FF0A4784A
|
||||
:206001007AF2787BE2FF7878E28FF0A4FFADF07878EFF208EDF27877E4F2787BF2787FE273
|
||||
:20602100F55A08E2F55B08E2F55C08E2F55D787BE2FA08E2FB08E2FE08E2FFEA255AF55A22
|
||||
:20604100EB355BF55BEE355CF55CEF355DF55D787FE55AF208E55BF208E55CF208E55DF2F8
|
||||
:20606100787FE208E208E208E27877E2FC08E2FD08E2FE08E2FFEC255AFCED355BFDEE35FF
|
||||
:0C6081005CFEEF355D8C828D838EF0227A
|
||||
:20608D00AE82AF837D007C007884E2235401FB70357883E225E0F208E233F27883C3E2F52A
|
||||
:2060AD00F0EE95F008E2F5F0EF95F050147883E2F5F008E2C313C5F01318F2C5F008F28046
|
||||
:2060CD00050C8C0580C27883C3E2F5F0EE95F008E2F5F0EF95F0400E7883D3E29EF4B3FE53
|
||||
:2060ED00B308E29FF4FF7883E2F5F008E2C313C5F01318F2C5F008F28D041DEC70C88E827F
|
||||
:03610D008F83225B
|
||||
:20611000AD82AE83AFF07888E2F5F008E245F07004900000227888E2FB08E2FC1BBBFF01CB
|
||||
:206130001CEB4C6069C003C0048D5A8E5B8F5C855A82855B83855CF012628FFA7885E2F58B
|
||||
:206150005D08E2F55E08E2F55F855D82855E83855FF012628FFCEAB504028006D004D003E8
|
||||
:20617000802C7401255AFAE4355BFBAC5C8A058B068C077401255DFAE4355EFBAC5F7885E0
|
||||
:20619000EAF2EB08F2EC08F2D004D003808E8D828E838FF012628FFD7F007885E2FB08E2B1
|
||||
:1A61B000FC08E2FE8B828C838EF012628FFB7E00EDC39BF582EF9EF58322F2
|
||||
:2061CA00AE82E583FF33E433FD6009C3E49EFBE49FFC80048E038F04788BE233E433FF6079
|
||||
:2061EA0010788AE2D3F43400FA08E2F43400FE8007788AE2FA08E2FE7862EAF2EE08F28B26
|
||||
:20620A00828C83C007C005125D4AAC82AE83D005D007EF6D600AC3E49CF582E49EF58322F7
|
||||
:05622A008C828E83222E
|
||||
:2000B800788CE84400600A79007593F0E4F309D8FC78D6E8440B600C790C90F08CE4F0A370
|
||||
:0400D800D8FCD9FA7D
|
||||
:0F008100E4737581641262ABE582600302007E56
|
||||
:20622F00758911758800758B00758D0020B0FD20B0FA20B0F720B0F420B0F130B0FDD28E21
|
||||
:20624F0020B0FD30B0FD20B0FD30B0FDC28EE58D25E0FFE58B2354014FF58DE58D25E0FFE6
|
||||
:20626F00E58B232354014FF58DE58DF4F58DE58D04F58D858D8B758921758780759852229A
|
||||
:1C628F0020F71430F6148883A88220F507E6A88375830022E280F7E49322E0221E
|
||||
:0462AB0075820022D6
|
||||
:00000001FF
|
||||
BIN
binaries/Tag/chroma29_ota_0010.bin
Normal file
BIN
binaries/Tag/chroma29_ota_0010.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/chroma42_8176_full_0010.bin
Normal file
BIN
binaries/Tag/chroma42_8176_full_0010.bin
Normal file
Binary file not shown.
1020
binaries/Tag/chroma42_8176_full_0010.hex
Normal file
1020
binaries/Tag/chroma42_8176_full_0010.hex
Normal file
File diff suppressed because it is too large
Load Diff
BIN
binaries/Tag/chroma42_8176_full_0011.bin
Normal file
BIN
binaries/Tag/chroma42_8176_full_0011.bin
Normal file
Binary file not shown.
1025
binaries/Tag/chroma42_8176_full_0011.hex
Normal file
1025
binaries/Tag/chroma42_8176_full_0011.hex
Normal file
File diff suppressed because it is too large
Load Diff
BIN
binaries/Tag/chroma42_8176_ota_0010.bin
Normal file
BIN
binaries/Tag/chroma42_8176_ota_0010.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/chroma42_8176_ota_0011.bin
Normal file
BIN
binaries/Tag/chroma42_8176_ota_0011.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/chroma42_full_0010.bin
Normal file
BIN
binaries/Tag/chroma42_full_0010.bin
Normal file
Binary file not shown.
1022
binaries/Tag/chroma42_full_0010.hex
Normal file
1022
binaries/Tag/chroma42_full_0010.hex
Normal file
File diff suppressed because it is too large
Load Diff
BIN
binaries/Tag/chroma42_ota_0010.bin
Normal file
BIN
binaries/Tag/chroma42_ota_0010.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/chroma74y_full_0010.bin
Normal file
BIN
binaries/Tag/chroma74y_full_0010.bin
Normal file
Binary file not shown.
1068
binaries/Tag/chroma74y_full_0010.hex
Normal file
1068
binaries/Tag/chroma74y_full_0010.hex
Normal file
File diff suppressed because it is too large
Load Diff
BIN
binaries/Tag/chroma74y_ota_0010.bin
Normal file
BIN
binaries/Tag/chroma74y_ota_0010.bin
Normal file
Binary file not shown.
@@ -2,18 +2,33 @@
|
||||
{
|
||||
"00": {
|
||||
"type": "SOL_M2_154_SSD",
|
||||
"version": "0027",
|
||||
"md5": "0cf7b60327ff2b0318185be2e8ba82a0"
|
||||
"version": "0029",
|
||||
"md5": "dafaaffbeefa29f16e9941bb531868d2"
|
||||
},
|
||||
"01": {
|
||||
"type": "SOL_M2_29_SSD",
|
||||
"version": "0027",
|
||||
"md5": "a051ee5d5517b3e8d3d09ae1e076eabc"
|
||||
"version": "0029",
|
||||
"md5": "6f5eae3a7d96eb8e15a3fa15353ec75b"
|
||||
},
|
||||
"02": {
|
||||
"type": "SOL_M2_42_SSD",
|
||||
"version": "0027",
|
||||
"md5": "94aa727296a4c480a6702ea612288b4c"
|
||||
"version": "0029",
|
||||
"md5": "fa8ac165ac0a9a1855ffdc2fa7c66528"
|
||||
},
|
||||
"12": {
|
||||
"type": "SOL_M2_42_UC",
|
||||
"version": "0029",
|
||||
"md5": "b2b50c89add8f94c2b445c387609e212"
|
||||
},
|
||||
"03": {
|
||||
"type": "SOL_M2_22_SSD",
|
||||
"version": "0029",
|
||||
"md5": "14662c9bc79d36316e5becd201537f59"
|
||||
},
|
||||
"04": {
|
||||
"type": "SOL_M2_26_SSD",
|
||||
"version": "0029",
|
||||
"md5": "5caafca1428359b9516747f9a6c7fb45"
|
||||
},
|
||||
"05": {
|
||||
"type": "SOL_M2_75_ota",
|
||||
@@ -22,8 +37,8 @@
|
||||
},
|
||||
"11": {
|
||||
"type": "SOL_M2_29_UC",
|
||||
"version": "0027",
|
||||
"md5": "aba3e35ef2bb63066d47e924bccd64f0"
|
||||
"version": "0029",
|
||||
"md5": "804c8613d87a3917237ce138e77e1ba4"
|
||||
},
|
||||
"21": {
|
||||
"type": "SOL_M2_29_LT",
|
||||
@@ -107,21 +122,21 @@
|
||||
},
|
||||
"80": {
|
||||
"type": "chroma74y_ota",
|
||||
"version": "0007",
|
||||
"md5": "00616787b718375159a7ba709546bada"
|
||||
"version": "0010",
|
||||
"md5": "4baff1e9eba6949c26ea11dbbd105039"
|
||||
},
|
||||
"82": {
|
||||
"type": "chroma29_ota",
|
||||
"version": "0007",
|
||||
"md5": "e583ec6bd715282dfbd4d9af0fb8c77c"
|
||||
"version": "0010",
|
||||
"md5": "0d4af3e5285ca20ac56926e6fdd71dbc"
|
||||
},
|
||||
"83": {
|
||||
"type": "chroma42_ota",
|
||||
"version": "0007",
|
||||
"md5": "ca1c7736bc327a779fe3269329db2a02",
|
||||
"version": "0010",
|
||||
"md5": "bf4b7dad8acfab2f1504c4b57b8806db",
|
||||
"type_1": "chroma42_8176_ota",
|
||||
"version_1": "0007",
|
||||
"md5_1": "170a59e493fad0b630588186cee47274"
|
||||
"version_1": "0011",
|
||||
"md5_1": "aeb07164835e9d16485c63d9de61b603"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -7,12 +7,6 @@
|
||||
#define SOLUM_42_SSD1619 0x02
|
||||
#define SOLUM_SEG_UK 0xF0
|
||||
#define SOLUM_SEG_EU 0xF1
|
||||
#define RESERVED_TESTING 0xFE
|
||||
#define SOLUM_NODISPLAY 0xFF
|
||||
#define ESP32_C6 0xC6
|
||||
|
||||
|
||||
|
||||
|
||||
// overflow
|
||||
#define SOLUM_M2_BWR_16 0x20
|
||||
@@ -24,8 +18,6 @@
|
||||
#define SOLUM_M2_BW_75 0x26
|
||||
#define SOLUM_M2_BW_29 0x27
|
||||
|
||||
|
||||
|
||||
#define SOLUM_M3_BWR_97 0x2E
|
||||
#define SOLUM_M3_BWR_43 0x2F
|
||||
|
||||
@@ -50,7 +42,6 @@
|
||||
#define SOLUM_M3_BWR_116 0x37
|
||||
#define SOLUM_M3_BWY_116 0x3F
|
||||
|
||||
|
||||
// M3 Tags overflow
|
||||
#define SOLUM_M3_BW_29 0x40
|
||||
#define SOLUM_M3_BWR_58 0x41
|
||||
@@ -80,7 +71,6 @@
|
||||
#define GICI_BLE_TFT_21_BW 0xBA
|
||||
#define GICI_BLE_EPD_BWR_29_SILABS 0xBD
|
||||
#define GICI_BLE_UNKNOWN 0xBF
|
||||
#define ATC_MI_THERMOMETER 0xBE
|
||||
|
||||
// Solum types - customer data byte 16 in M3 (nRF) UICR
|
||||
#define STYPE_SIZE_016 0x40
|
||||
@@ -98,6 +88,16 @@
|
||||
#define STYPE_SIZE_097 0x64
|
||||
#define STYPE_SIZE_013 0x4D
|
||||
|
||||
// Various types
|
||||
#define ATC_MI_THERMOMETER 0xBE
|
||||
#define RESERVED_TESTING 0xFE
|
||||
#define SOLUM_NODISPLAY 0xFF
|
||||
#define ESP32_C6 0xC6
|
||||
|
||||
#define BWRY_29 0xC0
|
||||
#define ACEP_40 0xC1
|
||||
#define SPECTRA_73 0xC2
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
#define CAPABILITY_HAS_WAKE_BUTTON 0x20
|
||||
#define CAPABILITY_HAS_NFC 0x40
|
||||
#define CAPABILITY_NFC_WAKE 0x80
|
||||
#define CAPABILITY_IS_BLE 0x0100
|
||||
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define DATATYPE_IMG_BMP 2 // ** deprecated
|
||||
@@ -117,10 +118,14 @@
|
||||
#define DATATYPE_IMG_DIFF 0x10 // always 1BPP ** deprecated
|
||||
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
|
||||
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
|
||||
#define DATATYPE_IMG_RAW_3BPP 0x22 // ACEP
|
||||
#define DATATYPE_IMG_RAW_4BPP 0x23 // Spectra
|
||||
#define DATATYPE_IMG_ZLIB 0x30 // compressed format.
|
||||
// [uint32_t uncompressed size][2 byte zlib header][zlib compressed image]
|
||||
// image format: [uint8_t header length][uint16_t width][uint16_t height][uint8_t bpp (lower 4)][img data]
|
||||
|
||||
#define DATATYPE_IMG_G5 0x31 // G5 compressed 1BPP
|
||||
|
||||
#define DATATYPE_UK_SEGMENTED 0x51 // Segmented data for the UK Segmented display type (contained in availableData Reply)
|
||||
#define DATATYPE_EU_SEGMENTED 0x52 // Segmented data for the EU/DE Segmented display type (contained in availableData Reply)
|
||||
#define DATATYPE_NFC_RAW_CONTENT 0xA0 // raw memory content for the NT3H1101
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 2,
|
||||
"version": 4,
|
||||
"name": "M2 1.54\"",
|
||||
"width": 152,
|
||||
"height": 152,
|
||||
@@ -10,9 +10,10 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 2,
|
||||
"options": [ "button", "customlut" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 15, 17, 18, 19, 20, 21, 27 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 17, 18, 19, 20, 21, 27 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 76, 9, "fonts/calibrib30" ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 2,
|
||||
"version": 4,
|
||||
"name": "M2 2.9\"",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
@@ -10,9 +10,10 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 2,
|
||||
"options": [ "button", "customlut" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 148, -3, "Signika-SB.ttf", 60 ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 4,
|
||||
"version": 5,
|
||||
"name": "M2 4.2\"",
|
||||
"width": 400,
|
||||
"height": 300,
|
||||
@@ -10,6 +10,7 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 1,
|
||||
"options": [ "button" ],
|
||||
"contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20, 27 ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 3,
|
||||
"version": 6,
|
||||
"name": "M2 2.2\"",
|
||||
"width": 212,
|
||||
"height": 104,
|
||||
@@ -10,45 +10,45 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 2,
|
||||
"options": [ "button", "customlut" ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 106, 2, "Signika-SB.ttf", 40 ],
|
||||
"date": [ 106, 60, "Signika-SB.ttf", 30 ]
|
||||
"weekday": [ 106, 5, "fonts/calibrib40", 40 ],
|
||||
"date": [ 106, 55, "fonts/calibrib30", 30 ]
|
||||
},
|
||||
"2": {
|
||||
"fonts": [ "Signika-SB.ttf", 150, 150, 150, 115, 90, 70 ],
|
||||
"xy": [ 106, 52 ]
|
||||
"fonts": [ "Signika-SB.ttf", 135, 135, 100, 90, 70, 50 ],
|
||||
"xy": [ 106, 44 ]
|
||||
},
|
||||
"16": {
|
||||
"location": [ 7, 15, "t0_14b_tf" ],
|
||||
"title": [ 210, 11, "glasstown_nbp_tf" ],
|
||||
"cols": [ 4, 121, 10, "glasstown_nbp_tf" ],
|
||||
"bars": [ 10, 110, 8 ]
|
||||
"location": [ 4, 10, "glasstown_nbp_tf" ],
|
||||
"title": [ 165, 10, "glasstown_nbp_tf" ],
|
||||
"cols": [ 4, 101, 8, "glasstown_nbp_tf" ],
|
||||
"bars": [ 5, 90, 6 ]
|
||||
},
|
||||
"4": {
|
||||
"location": [ 5, 3, "fonts/bahnschrift30" ],
|
||||
"wind": [ 245, 3, "fonts/bahnschrift30" ],
|
||||
"temp": [ 10, 60, "fonts/bahnschrift70" ],
|
||||
"icon": [ 240, 20, 70, 2 ],
|
||||
"dir": [ 210, -12, 40 ],
|
||||
"location": [ 5, 3, "fonts/calibrib16.vlw" ],
|
||||
"wind": [ 190, 5, "fonts/bahnschrift30" ],
|
||||
"temp": [ 5, 30, "fonts/calibrib70" ],
|
||||
"icon": [ 190, 25, 50, 2 ],
|
||||
"dir": [ 165, -12, 40 ],
|
||||
"umbrella": [ 175, -50, 25 ]
|
||||
},
|
||||
"8": {
|
||||
"location": [ 5, 12, "t0_14b_tf" ],
|
||||
"column": [ 5, 51 ],
|
||||
"day": [ 28, 18, "fonts/twcondensed20", 41, 108 ],
|
||||
"icon": [ 28, 55, 30 ],
|
||||
"wind": [ 18, 26 ],
|
||||
"line": [ 20, 128 ]
|
||||
"column": [ 4, 53 ],
|
||||
"day": [ 28, 18, "fonts/twcondensed20", 38, 88 ],
|
||||
"icon": [ 28, 48, 25 ],
|
||||
"wind": [ 18, 24 ],
|
||||
"line": [ 20, 100 ]
|
||||
},
|
||||
"9": {
|
||||
"title": [ 8, 2, "bahnschrift20.vlw", 25 ],
|
||||
"items": 5,
|
||||
"line": [ 8, 25, "REFSAN12.vlw" ],
|
||||
"title": [ 3, 2, "fonts/calibrib16", 25 ],
|
||||
"items": 4,
|
||||
"line": [ 3, 20, "tahoma9.vlw" ],
|
||||
"desc": [ 0, 5, "", 1 ]
|
||||
},
|
||||
"10": {
|
||||
@@ -58,26 +58,26 @@
|
||||
"11": {
|
||||
"mode": 0,
|
||||
"days": 1,
|
||||
"title": [ 10, 2, "fonts/bahnschrift20" ],
|
||||
"date": [ 245, 2 ],
|
||||
"items": 7,
|
||||
"red": [ 0, 21, 256, 14 ],
|
||||
"line": [ 10, 32, 15, "t0_14b_tf", 50 ]
|
||||
"title": [ 5, 2, "fonts/calibrib16.vlw" ],
|
||||
"date": [ 205, 2 ],
|
||||
"items": 8,
|
||||
"red": [ 0, 21, 211, 10 ],
|
||||
"line": [ 5, 21, 11, "tahoma9.vlw", 50 ]
|
||||
},
|
||||
"21": [
|
||||
{ "text": [ 10, 5, "OpenEpaperLink AP", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 50, "IP address:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 110, 50, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 100, 50, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 70, "Channel:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 110, 70, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 100, 70, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 90, "Tag count:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 110, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
{ "text": [ 100, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
],
|
||||
"27": {
|
||||
"bars": [ 26, 216, 80, 20 ],
|
||||
"bars": [ 20, 180, 65, 12, 10 ],
|
||||
"time": [ "tahoma9.vlw" ],
|
||||
"yaxis": [ "tahoma9.vlw", 6, 6 ],
|
||||
"head": [ "bahnschrift20.vlw" ]
|
||||
"yaxis": [ "tahoma9.vlw", 2, 6 ],
|
||||
"head": [ "fonts/calibrib16.vlw" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 4,
|
||||
"name": "M2 2.6\"",
|
||||
"width": 296,
|
||||
"height": 152,
|
||||
@@ -10,44 +10,46 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 2,
|
||||
"options": [ "button", "customlut" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 148, -3, "Signika-SB.ttf", 60 ],
|
||||
"date": [ 148, 65, "Signika-SB.ttf", 48 ]
|
||||
"weekday": [ 148, 9, "Signika-SB.ttf", 60 ],
|
||||
"date": [ 148, 73, "Signika-SB.ttf", 48 ]
|
||||
},
|
||||
"2": {
|
||||
"fonts": [ "Signika-SB.ttf", 150, 150, 150, 120, 100, 80 ],
|
||||
"xy": [ 148, 53 ]
|
||||
"fonts": [ "Signika-SB.ttf", 170, 170, 170, 120, 100, 80 ],
|
||||
"xy": [ 148, 62 ]
|
||||
},
|
||||
"16": {
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"title": [ 247, 11, "glasstown_nbp_tf" ],
|
||||
"cols": [ 1, 125, 12, "glasstown_nbp_tf" ],
|
||||
"bars": [ 5, 111, 10 ]
|
||||
"cols": [ 1, 149, 12, "glasstown_nbp_tf" ],
|
||||
"bars": [ 5, 135, 10 ]
|
||||
},
|
||||
"4": {
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"wind": [ 280, 5, "fonts/bahnschrift30" ],
|
||||
"temp": [ 5, 65, "fonts/bahnschrift70" ],
|
||||
"icon": [ 285, 20, 70, 2 ],
|
||||
"temp": [ 5, 58, "fonts/calibrib90" ],
|
||||
"icon": [ 280, 35, 80, 2 ],
|
||||
"dir": [ 235, -12, 40 ],
|
||||
"umbrella": [ 190, -50, 25 ]
|
||||
"umbrella": [ 190, -30, 25 ]
|
||||
},
|
||||
"8": {
|
||||
"location": [ 5, 12, "t0_14b_tf" ],
|
||||
"column": [ 5, 59 ],
|
||||
"day": [ 30, 18, "fonts/twcondensed20", 41, 108 ],
|
||||
"day": [ 30, 20, "fonts/twcondensed20", 41, 105 ],
|
||||
"rain": [ 34, 130 ],
|
||||
"icon": [ 30, 55, 30 ],
|
||||
"wind": [ 18, 26 ],
|
||||
"line": [ 20, 128 ]
|
||||
"line": [ 20, 150 ]
|
||||
},
|
||||
"9": {
|
||||
"title": [ 2, 0, "bahnschrift20.vlw", 25 ],
|
||||
"title": [ 3, 2, "bahnschrift20.vlw", 25 ],
|
||||
"items": 8,
|
||||
"line": [ 1, 25, "REFSAN12.vlw" ],
|
||||
"line": [ 3, 25, "REFSAN12.vlw" ],
|
||||
"desc": [ 0, 5, "", 1 ]
|
||||
},
|
||||
"10": {
|
||||
@@ -59,7 +61,7 @@
|
||||
"days": 1,
|
||||
"title": [ 5, 2, "fonts/bahnschrift20" ],
|
||||
"date": [ 290, 2 ],
|
||||
"items": 7,
|
||||
"items": 9,
|
||||
"red": [ 0, 21, 296, 14 ],
|
||||
"line": [ 5, 32, 15, "t0_14b_tf", 50 ]
|
||||
},
|
||||
@@ -73,7 +75,7 @@
|
||||
{ "text": [ 120, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
],
|
||||
"27": {
|
||||
"bars": [ 9, 288, 90, 11 ],
|
||||
"bars": [ 9, 288, 90, 11, 15 ],
|
||||
"time": [ "tahoma9.vlw" ],
|
||||
"yaxis": [ "tahoma9.vlw", 0, 6 ],
|
||||
"head": [ "calibrib30.vlw" ]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"name": "M2 7.4\"",
|
||||
"width": 640,
|
||||
"height": 384,
|
||||
@@ -54,7 +54,7 @@
|
||||
"gridparam": [ 3, 17, 30, "calibrib16.vlw", "tahoma9.vlw", 14 ]
|
||||
},
|
||||
"27": {
|
||||
"bars": [ 18, 612, 350, 20 ],
|
||||
"bars": [ 18, 612, 330, 20, 22 ],
|
||||
"time": [ "calibrib16.vlw" ],
|
||||
"yaxis": [ "calibrib16.vlw", 1, 12 ],
|
||||
"head": [ "calibrib30.vlw" ]
|
||||
|
||||
19
resources/tagtypes/06.json
Normal file
19
resources/tagtypes/06.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": 3,
|
||||
"name": "Opticon 2.2\"",
|
||||
"width": 250,
|
||||
"height": 128,
|
||||
"rotatebuffer": 3,
|
||||
"bpp": 2,
|
||||
"colortable": {
|
||||
"white": [ 255, 255, 255 ],
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ],
|
||||
"yellow": [ 255, 255, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 0,
|
||||
"options": [ "led" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"usetemplate": 177
|
||||
}
|
||||
19
resources/tagtypes/07.json
Normal file
19
resources/tagtypes/07.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": 3,
|
||||
"name": "Opticon 2.9\"",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
"rotatebuffer": 3,
|
||||
"bpp": 2,
|
||||
"colortable": {
|
||||
"white": [ 255, 255, 255 ],
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ],
|
||||
"yellow": [ 255, 255, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 2,
|
||||
"options": [ "led" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"usetemplate": 1
|
||||
}
|
||||
18
resources/tagtypes/08.json
Normal file
18
resources/tagtypes/08.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "Opticon 4.2\"",
|
||||
"width": 400,
|
||||
"height": 300,
|
||||
"rotatebuffer": 2,
|
||||
"bpp": 2,
|
||||
"colortable": {
|
||||
"white": [ 255, 255, 255 ],
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 1,
|
||||
"options": [ ],
|
||||
"contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20, 27 ],
|
||||
"usetemplate": 2
|
||||
}
|
||||
18
resources/tagtypes/09.json
Normal file
18
resources/tagtypes/09.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "Opticon 7.5\"",
|
||||
"width": 640,
|
||||
"height": 384,
|
||||
"rotatebuffer": 2,
|
||||
"bpp": 2,
|
||||
"colortable": {
|
||||
"white": [ 255, 255, 255 ],
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 1,
|
||||
"options": [ ],
|
||||
"contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20, 27 ],
|
||||
"usetemplate" : 5
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 3,
|
||||
"name": "M2 2.9\" (UC8151)",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
@@ -10,8 +10,9 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 0,
|
||||
"options": [ "button" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"usetemplate": 1
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"name": "M2 4.2\" UC",
|
||||
"width": 400,
|
||||
"height": 300,
|
||||
@@ -10,6 +10,7 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 1,
|
||||
"options": [ "button" ],
|
||||
"contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20, 27 ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"name": "ST‐GM29XXF 2.9\"",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
@@ -12,6 +12,6 @@
|
||||
"highlight_color": 5,
|
||||
"shortlut": 0,
|
||||
"options": [ "button", "customlut" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21 ],
|
||||
"usetemplate": 1
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"name": "M2 2.7\"",
|
||||
"width": 264,
|
||||
"height": 176,
|
||||
@@ -10,6 +10,7 @@
|
||||
"black": [ 0, 0, 0 ],
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"shortlut": 0,
|
||||
"options": [ "button" ],
|
||||
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20 ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 3,
|
||||
"name": "ST‐GM29MT1 2.9\"",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
@@ -9,9 +9,10 @@
|
||||
"white": [ 255, 255, 255 ],
|
||||
"black": [ 0, 0, 0 ]
|
||||
},
|
||||
"g5_compression": "29",
|
||||
"highlight_color": 5,
|
||||
"shortlut": 0,
|
||||
"options": [ "button", "customlut" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21 ],
|
||||
"usetemplate": 1
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"name": "M3 1.6\"",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
@@ -14,7 +14,7 @@
|
||||
"shortlut": 0,
|
||||
"zlib_compression": "27",
|
||||
"options": [ "button" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 15, 17, 18, 19, 20, 21 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 17, 18, 19, 20, 21 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 100, 5, "fonts/calibrib40" ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"name": "M3 1.3\" Peghook",
|
||||
"width": 144,
|
||||
"height": 200,
|
||||
@@ -14,7 +14,7 @@
|
||||
"shortlut": 0,
|
||||
"zlib_compression": "27",
|
||||
"options": [ "button" ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 15, 17, 18, 19, 20, 21 ],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 17, 18, 19, 20, 21 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 72, 12, "fonts/calibrib28" ],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"name": "M3 2.2 Lite\"",
|
||||
"width": 250,
|
||||
"height": 128,
|
||||
@@ -13,7 +13,7 @@
|
||||
"shortlut": 0,
|
||||
"zlib_compression": "27",
|
||||
"options": [ "led" ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
|
||||
"template": {
|
||||
"1": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 3,
|
||||
"name": "HS BW 2.13\"",
|
||||
"width": 256,
|
||||
"height": 128,
|
||||
@@ -10,8 +10,9 @@
|
||||
"black": [ 0, 0, 0 ]
|
||||
},
|
||||
"shortlut": 0,
|
||||
"zlib_compression": "27",
|
||||
"options": [ "led" ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
|
||||
"template": {
|
||||
"1": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 2,
|
||||
"version": 4,
|
||||
"name": "HS BWR 2.13\"",
|
||||
"width": 256,
|
||||
"height": 128,
|
||||
@@ -11,8 +11,9 @@
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"shortlut": 0,
|
||||
"zlib_compression": "27",
|
||||
"options": [ "led" ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
|
||||
"template": {
|
||||
"1": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": 2,
|
||||
"version": 5,
|
||||
"name": "HS BWR 2.66\"",
|
||||
"width": 296,
|
||||
"height": 152,
|
||||
@@ -11,73 +11,74 @@
|
||||
"red": [ 255, 0, 0 ]
|
||||
},
|
||||
"shortlut": 0,
|
||||
"zlib_compression": "27",
|
||||
"options": [ "led" ],
|
||||
"contentids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 27 ],
|
||||
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 128, 3, "Signika-SB.ttf", 50 ],
|
||||
"date": [ 128, 62, "Signika-SB.ttf", 40 ]
|
||||
"weekday": [ 148, 9, "Signika-SB.ttf", 60 ],
|
||||
"date": [ 148, 73, "Signika-SB.ttf", 48 ]
|
||||
},
|
||||
"2": {
|
||||
"fonts": [ "Signika-SB.ttf", 150, 150, 150, 115, 90, 70 ],
|
||||
"xy": [ 128, 53 ]
|
||||
"fonts": [ "Signika-SB.ttf", 170, 170, 170, 120, 100, 80 ],
|
||||
"xy": [ 148, 62 ]
|
||||
},
|
||||
"16": {
|
||||
"location": [ 7, 15, "t0_14b_tf" ],
|
||||
"title": [ 210, 11, "glasstown_nbp_tf" ],
|
||||
"cols": [ 4, 121, 10, "glasstown_nbp_tf" ],
|
||||
"bars": [ 10, 110, 8 ]
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"title": [ 247, 11, "glasstown_nbp_tf" ],
|
||||
"cols": [ 1, 149, 12, "glasstown_nbp_tf" ],
|
||||
"bars": [ 5, 135, 10 ]
|
||||
},
|
||||
"4": {
|
||||
"location": [ 5, 3, "fonts/bahnschrift30" ],
|
||||
"wind": [ 245, 3, "fonts/bahnschrift30" ],
|
||||
"temp": [ 10, 60, "fonts/bahnschrift70" ],
|
||||
"icon": [ 240, 20, 70, 2 ],
|
||||
"dir": [ 210, -12, 40 ],
|
||||
"umbrella": [ 175, -50, 25 ]
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"wind": [ 280, 5, "fonts/bahnschrift30" ],
|
||||
"temp": [ 5, 58, "fonts/calibrib90" ],
|
||||
"icon": [ 280, 35, 80, 2 ],
|
||||
"dir": [ 235, -12, 40 ],
|
||||
"umbrella": [ 190, -30, 25 ]
|
||||
},
|
||||
"8": {
|
||||
"location": [ 5, 12, "t0_14b_tf" ],
|
||||
"column": [ 5, 51 ],
|
||||
"day": [ 28, 18, "fonts/twcondensed20", 41, 108 ],
|
||||
"icon": [ 28, 55, 30 ],
|
||||
"column": [ 5, 59 ],
|
||||
"day": [ 30, 20, "fonts/twcondensed20", 41, 105 ],
|
||||
"rain": [ 34, 130 ],
|
||||
"icon": [ 30, 55, 30 ],
|
||||
"wind": [ 18, 26 ],
|
||||
"line": [ 20, 128 ]
|
||||
"line": [ 20, 150 ]
|
||||
},
|
||||
"9": {
|
||||
"title": [ 8, 2, "bahnschrift20.vlw", 25 ],
|
||||
"items": 5,
|
||||
"line": [ 8, 25, "REFSAN12.vlw" ],
|
||||
"title": [ 3, 2, "bahnschrift20.vlw", 25 ],
|
||||
"items": 8,
|
||||
"line": [ 3, 25, "REFSAN12.vlw" ],
|
||||
"desc": [ 0, 5, "", 1 ]
|
||||
},
|
||||
"10": {
|
||||
"title": [ 128, 2, "calibrib16.vlw" ],
|
||||
"pos": [ 128, 16 ]
|
||||
"title": [ 149, 5, "fonts/bahnschrift20" ],
|
||||
"pos": [ 149, 27 ]
|
||||
},
|
||||
"11": {
|
||||
"mode": 0,
|
||||
"days": 1,
|
||||
"title": [ 10, 2, "fonts/bahnschrift20" ],
|
||||
"date": [ 245, 2 ],
|
||||
"items": 7,
|
||||
"red": [ 0, 21, 256, 14 ],
|
||||
"line": [ 10, 32, 15, "t0_14b_tf", 50 ]
|
||||
"title": [ 5, 2, "fonts/bahnschrift20" ],
|
||||
"date": [ 290, 2 ],
|
||||
"items": 9,
|
||||
"red": [ 0, 21, 296, 14 ],
|
||||
"line": [ 5, 32, 15, "t0_14b_tf", 50 ]
|
||||
},
|
||||
"21": [
|
||||
{ "text": [ 10, 5, "OpenEpaperLink AP", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 50, "IP address:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 110, 50, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 70, "Channel:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 110, 70, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 90, "Tag count:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 110, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
{ "text": [ 5, 5, "OpenEpaperLink AP", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 50, "IP address:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 50, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 70, "Channel:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 70, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 90, "Tag count:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
],
|
||||
"27": {
|
||||
"bars": [ 26, 216, 80, 20 ],
|
||||
"bars": [ 9, 288, 90, 11, 15 ],
|
||||
"time": [ "tahoma9.vlw" ],
|
||||
"yaxis": [ "tahoma9.vlw", 6, 6 ],
|
||||
"head": [ "bahnschrift20.vlw" ]
|
||||
"yaxis": [ "tahoma9.vlw", 0, 6 ],
|
||||
"head": [ "calibrib30.vlw" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user