Merge pull request #97 from cyberman54/master

sync master -> dev
This commit is contained in:
Verkehrsrot 2018-06-12 20:02:03 +02:00 committed by GitHub
commit 442326385b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1221 additions and 2309 deletions

View File

@ -11,11 +11,11 @@
; ---> SELECT TARGET PLATFORM HERE! <---
[platformio]
;env_default = heltec
env_default = heltec
;env_default = ttgov1
;env_default = ttgov2
;env_default = ttgov21
env_default = ttgobeam
;env_default = ttgobeam
;env_default = lopy
;env_default = lopy4
;env_default = fipy

View File

@ -5,52 +5,56 @@
#include <driver/adc.h>
#include <esp_adc_cal.h>
#define DEFAULT_VREF 1100 // to be done: use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64 // we do multisampling
#define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate
#define NO_OF_SAMPLES 64 // we do multisampling
// Local logging tag
static const char TAG[] = "main";
static void print_char_val_type(esp_adc_cal_value_t val_type)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
ESP_LOGI(TAG,"ADC characterization based on Two Point values stored in eFuse");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
ESP_LOGI(TAG,"ADC characterization based on reference voltage stored in eFuse");
} else {
ESP_LOGI(TAG,"ADC characterization based on default reference voltage");
}
static void print_char_val_type(esp_adc_cal_value_t val_type) {
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
ESP_LOGI(TAG,
"ADC characterization based on Two Point values stored in eFuse");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
ESP_LOGI(TAG,
"ADC characterization based on reference voltage stored in eFuse");
} else {
ESP_LOGI(TAG, "ADC characterization based on default reference voltage");
}
}
uint16_t read_voltage(void)
{
static const adc1_channel_t channel = HAS_BATTERY_PROBE;
static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_1;
uint16_t read_voltage(void) {
static const adc1_channel_t channel = HAS_BATTERY_PROBE;
static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_1;
//configure ADC1
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
ESP_ERROR_CHECK(adc1_config_channel_atten(channel, atten));
// configure ADC1
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
ESP_ERROR_CHECK(adc1_config_channel_atten(channel, atten));
//calibrate ADC1
esp_adc_cal_characteristics_t *adc_chars = (esp_adc_cal_characteristics_t *) calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
print_char_val_type(val_type);
// calibrate ADC1
esp_adc_cal_characteristics_t *adc_chars =
(esp_adc_cal_characteristics_t *)calloc(
1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(
unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
print_char_val_type(val_type);
//multisample ADC1
uint32_t adc_reading = 0;
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw(channel);
}
// multisample ADC1
uint32_t adc_reading = 0;
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw(channel);
}
adc_reading /= NO_OF_SAMPLES;
adc_reading /= NO_OF_SAMPLES;
//Convert adc_reading to voltage in mV
uint16_t voltage = (uint16_t) esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
#ifdef BATT_FACTOR
voltage *= BATT_FACTOR;
#endif
ESP_LOGI(TAG,"Raw: %d / Voltage: %dmV", adc_reading, voltage);
return voltage;
// Convert adc_reading to voltage in mV
uint16_t voltage =
(uint16_t)esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
#ifdef BATT_FACTOR
voltage *= BATT_FACTOR;
#endif
ESP_LOGI(TAG, "Raw: %d / Voltage: %dmV", adc_reading, voltage);
return voltage;
}
#endif // HAS_BATTERY_PROBE

View File

@ -1,4 +1,4 @@
/* switches wifi antenna, if board has switch to select internal and external antenna */
/* switches wifi antenna, if board has switch internal / external antenna */
#ifdef HAS_ANTENNA_SWITCH
@ -7,35 +7,32 @@
// Local logging tag
static const char TAG[] = "wifi";
typedef enum {
ANTENNA_INT = 0,
ANTENNA_EXT
} antenna_type_t;
typedef enum { ANTENNA_INT = 0, ANTENNA_EXT } antenna_type_t;
void antenna_init(void) {
gpio_config_t gpioconf = {.pin_bit_mask = 1ull << HAS_ANTENNA_SWITCH,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE};
gpio_config(&gpioconf);
gpio_config_t gpioconf = {.pin_bit_mask = 1ull << HAS_ANTENNA_SWITCH,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE};
gpio_config(&gpioconf);
}
void antenna_select (const uint8_t _ant) {
if (HAS_ANTENNA_SWITCH < 32) {
if (_ant == ANTENNA_EXT) {
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1 << HAS_ANTENNA_SWITCH);
} else {
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1 << HAS_ANTENNA_SWITCH);
}
} else {
if (_ant == ANTENNA_EXT) {
GPIO_REG_WRITE(GPIO_OUT1_W1TS_REG, 1 << (HAS_ANTENNA_SWITCH & 31));
} else {
GPIO_REG_WRITE(GPIO_OUT1_W1TC_REG, 1 << (HAS_ANTENNA_SWITCH & 31));
}
}
ESP_LOGI(TAG, "Wifi Antenna switched to %s", _ant ? "external" : "internal");
void antenna_select(const uint8_t _ant) {
if (HAS_ANTENNA_SWITCH < 32) {
if (_ant == ANTENNA_EXT) {
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1 << HAS_ANTENNA_SWITCH);
} else {
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1 << HAS_ANTENNA_SWITCH);
}
} else {
if (_ant == ANTENNA_EXT) {
GPIO_REG_WRITE(GPIO_OUT1_W1TS_REG, 1 << (HAS_ANTENNA_SWITCH & 31));
} else {
GPIO_REG_WRITE(GPIO_OUT1_W1TC_REG, 1 << (HAS_ANTENNA_SWITCH & 31));
}
}
ESP_LOGI(TAG, "Wifi Antenna switched to %s", _ant ? "external" : "internal");
}
#endif

View File

@ -14,7 +14,8 @@ https://github.com/nkolban/esp32-snippets/tree/master/BLE/scanner
#include <esp_blufi_api.h> // needed for BLE_ADDR types, do not remove
#include <bt_types.h>
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
#define BT_BD_ADDR_HEX(addr) \
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
// local Tag for logging
static const char TAG[] = "bluetooth";
@ -23,208 +24,257 @@ static const char TAG[] = "bluetooth";
bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type);
const char *bt_addr_t_to_string(esp_ble_addr_type_t type) {
switch(type) {
case BLE_ADDR_TYPE_PUBLIC:
return "BLE_ADDR_TYPE_PUBLIC";
case BLE_ADDR_TYPE_RANDOM:
return "BLE_ADDR_TYPE_RANDOM";
case BLE_ADDR_TYPE_RPA_PUBLIC:
return "BLE_ADDR_TYPE_RPA_PUBLIC";
case BLE_ADDR_TYPE_RPA_RANDOM:
return "BLE_ADDR_TYPE_RPA_RANDOM";
default:
return "Unknown addr_t";
}
switch (type) {
case BLE_ADDR_TYPE_PUBLIC:
return "BLE_ADDR_TYPE_PUBLIC";
case BLE_ADDR_TYPE_RANDOM:
return "BLE_ADDR_TYPE_RANDOM";
case BLE_ADDR_TYPE_RPA_PUBLIC:
return "BLE_ADDR_TYPE_RPA_PUBLIC";
case BLE_ADDR_TYPE_RPA_RANDOM:
return "BLE_ADDR_TYPE_RPA_RANDOM";
default:
return "Unknown addr_t";
}
} // bt_addr_t_to_string
const char *btsig_gap_type(uint32_t gap_type) {
switch (gap_type)
{
case 0x01: return "Flags";
case 0x02: return "Incomplete List of 16-bit Service Class UUIDs";
case 0x03: return "Complete List of 16-bit Service Class UUIDs";
case 0x04: return "Incomplete List of 32-bit Service Class UUIDs";
case 0x05: return "Complete List of 32-bit Service Class UUIDs";
case 0x06: return "Incomplete List of 128-bit Service Class UUIDs";
case 0x07: return "Complete List of 128-bit Service Class UUIDs";
case 0x08: return "Shortened Local Name";
case 0x09: return "Complete Local Name";
case 0x0A: return "Tx Power Level";
case 0x0D: return "Class of Device";
case 0x0E: return "Simple Pairing Hash C/C-192";
case 0x0F: return "Simple Pairing Randomizer R/R-192";
case 0x10: return "Device ID/Security Manager TK Value";
case 0x11: return "Security Manager Out of Band Flags";
case 0x12: return "Slave Connection Interval Range";
case 0x14: return "List of 16-bit Service Solicitation UUIDs";
case 0x1F: return "List of 32-bit Service Solicitation UUIDs";
case 0x15: return "List of 128-bit Service Solicitation UUIDs";
case 0x16: return "Service Data - 16-bit UUID";
case 0x20: return "Service Data - 32-bit UUID";
case 0x21: return "Service Data - 128-bit UUID";
case 0x22: return "LE Secure Connections Confirmation Value";
case 0x23: return "LE Secure Connections Random Value";
case 0x24: return "URI";
case 0x25: return "Indoor Positioning";
case 0x26: return "Transport Discovery Data";
case 0x17: return "Public Target Address";
case 0x18: return "Random Target Address";
case 0x19: return "Appearance";
case 0x1A: return "Advertising Interval";
case 0x1B: return "LE Bluetooth Device Address";
case 0x1C: return "LE Role";
case 0x1D: return "Simple Pairing Hash C-256";
case 0x1E: return "Simple Pairing Randomizer R-256";
case 0x3D: return "3D Information Data";
case 0xFF: return "Manufacturer Specific Data";
default:
return "Unknown type";
}
switch (gap_type) {
case 0x01:
return "Flags";
case 0x02:
return "Incomplete List of 16-bit Service Class UUIDs";
case 0x03:
return "Complete List of 16-bit Service Class UUIDs";
case 0x04:
return "Incomplete List of 32-bit Service Class UUIDs";
case 0x05:
return "Complete List of 32-bit Service Class UUIDs";
case 0x06:
return "Incomplete List of 128-bit Service Class UUIDs";
case 0x07:
return "Complete List of 128-bit Service Class UUIDs";
case 0x08:
return "Shortened Local Name";
case 0x09:
return "Complete Local Name";
case 0x0A:
return "Tx Power Level";
case 0x0D:
return "Class of Device";
case 0x0E:
return "Simple Pairing Hash C/C-192";
case 0x0F:
return "Simple Pairing Randomizer R/R-192";
case 0x10:
return "Device ID/Security Manager TK Value";
case 0x11:
return "Security Manager Out of Band Flags";
case 0x12:
return "Slave Connection Interval Range";
case 0x14:
return "List of 16-bit Service Solicitation UUIDs";
case 0x1F:
return "List of 32-bit Service Solicitation UUIDs";
case 0x15:
return "List of 128-bit Service Solicitation UUIDs";
case 0x16:
return "Service Data - 16-bit UUID";
case 0x20:
return "Service Data - 32-bit UUID";
case 0x21:
return "Service Data - 128-bit UUID";
case 0x22:
return "LE Secure Connections Confirmation Value";
case 0x23:
return "LE Secure Connections Random Value";
case 0x24:
return "URI";
case 0x25:
return "Indoor Positioning";
case 0x26:
return "Transport Discovery Data";
case 0x17:
return "Public Target Address";
case 0x18:
return "Random Target Address";
case 0x19:
return "Appearance";
case 0x1A:
return "Advertising Interval";
case 0x1B:
return "LE Bluetooth Device Address";
case 0x1C:
return "LE Role";
case 0x1D:
return "Simple Pairing Hash C-256";
case 0x1E:
return "Simple Pairing Randomizer R-256";
case 0x3D:
return "3D Information Data";
case 0xFF:
return "Manufacturer Specific Data";
default:
return "Unknown type";
}
} // btsig_gap_type
// using IRAM_:ATTR here to speed up callback function
IRAM_ATTR void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param;
ESP_LOGD(TAG, "BT payload rcvd -> type: 0x%.2x -> %s", *p->scan_rst.ble_adv, btsig_gap_type(*p->scan_rst.ble_adv));
IRAM_ATTR void gap_callback_handler(esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t *param) {
esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param;
switch (event)
{
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
// restart scan
ESP_ERROR_CHECK(esp_ble_gap_start_scanning(BLESCANTIME));
break;
case ESP_GAP_BLE_SCAN_RESULT_EVT:
// evaluate scan results
if ( p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_CMPL_EVT) // Inquiry complete, scan is done
{ // restart scan
ESP_ERROR_CHECK(esp_ble_gap_start_scanning(BLESCANTIME));
return;
}
if (p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) // Inquiry result for a peer device
{ // evaluate sniffed packet
ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", BT_BD_ADDR_HEX(p->scan_rst.bda));
ESP_LOGD(TAG, "Addr_type : %s", bt_addr_t_to_string(p->scan_rst.ble_addr_type));
ESP_LOGD(TAG, "RSSI : %d", p->scan_rst.rssi);
ESP_LOGD(TAG, "BT payload rcvd -> type: 0x%.2x -> %s", *p->scan_rst.ble_adv,
btsig_gap_type(*p->scan_rst.ble_adv));
if ((cfg.rssilimit) && (p->scan_rst.rssi < cfg.rssilimit )) { // rssi is negative value
ESP_LOGI(TAG, "BLTH RSSI %d -> ignoring (limit: %d)", p->scan_rst.rssi, cfg.rssilimit);
break;
}
switch (event) {
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
// restart scan
ESP_ERROR_CHECK(esp_ble_gap_start_scanning(BLESCANTIME));
break;
#ifdef VENDORFILTER
if ((p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RANDOM) || (p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RPA_RANDOM)) {
ESP_LOGD(TAG, "BT device filtered");
break;
}
case ESP_GAP_BLE_SCAN_RESULT_EVT:
// evaluate scan results
if (p->scan_rst.search_evt ==
ESP_GAP_SEARCH_INQ_CMPL_EVT) // Inquiry complete, scan is done
{ // restart scan
ESP_ERROR_CHECK(esp_ble_gap_start_scanning(BLESCANTIME));
return;
}
#endif
if (p->scan_rst.search_evt ==
ESP_GAP_SEARCH_INQ_RES_EVT) // Inquiry result for a peer device
{ // evaluate sniffed packet
ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x",
BT_BD_ADDR_HEX(p->scan_rst.bda));
ESP_LOGD(TAG, "Addr_type : %s",
bt_addr_t_to_string(p->scan_rst.ble_addr_type));
ESP_LOGD(TAG, "RSSI : %d", p->scan_rst.rssi);
// add this device and show new count total if it was not previously added
mac_add((uint8_t *) p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE);
/* to be improved in vendorfilter if:
// you can search for elements in the payload using the
// function esp_ble_resolve_adv_data()
//
// Like this, that scans for the "Complete name" (looking inside the payload buffer)
// uint8_t len;
// uint8_t *data = esp_ble_resolve_adv_data(p->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &len);
filter BLE devices using their advertisements to get filter alternative to vendor OUI
if vendorfiltering is on, we ...
- want to count: mobile phones and tablets
- don't want to count: beacons, peripherals (earphones, headsets, printers), cars and machines
see
https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEAdvertisedDevice.cpp
http://www.libelium.com/products/meshlium/smartphone-detection/
https://www.question-defense.com/2013/01/12/bluetooth-cod-bluetooth-class-of-deviceclass-of-service-explained
https://www.bluetooth.com/specifications/assigned-numbers/baseband
"The Class of Device (CoD) in case of Bluetooth which allows us to differentiate the type of
device (smartphone, handsfree, computer, LAN/network AP). With this parameter we can
differentiate among pedestrians and vehicles."
*/
} // evaluate sniffed packet
break;
default:
if ((cfg.rssilimit) &&
(p->scan_rst.rssi < cfg.rssilimit)) { // rssi is negative value
ESP_LOGI(TAG, "BLTH RSSI %d -> ignoring (limit: %d)", p->scan_rst.rssi,
cfg.rssilimit);
break;
}
}
#ifdef VENDORFILTER
if ((p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RANDOM) ||
(p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RPA_RANDOM)) {
ESP_LOGD(TAG, "BT device filtered");
break;
}
#endif
// add this device and show new count total if it was not previously added
mac_add((uint8_t *)p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE);
/* to be improved in vendorfilter if:
// you can search for elements in the payload using the
// function esp_ble_resolve_adv_data()
//
// Like this, that scans for the "Complete name" (looking inside the
payload buffer)
// uint8_t len;
// uint8_t *data = esp_ble_resolve_adv_data(p->scan_rst.ble_adv,
ESP_BLE_AD_TYPE_NAME_CMPL, &len);
filter BLE devices using their advertisements to get filter alternative to
vendor OUI if vendorfiltering is on, we ...
- want to count: mobile phones and tablets
- don't want to count: beacons, peripherals (earphones, headsets,
printers), cars and machines see
https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEAdvertisedDevice.cpp
http://www.libelium.com/products/meshlium/smartphone-detection/
https://www.question-defense.com/2013/01/12/bluetooth-cod-bluetooth-class-of-deviceclass-of-service-explained
https://www.bluetooth.com/specifications/assigned-numbers/baseband
"The Class of Device (CoD) in case of Bluetooth which allows us to
differentiate the type of device (smartphone, handsfree, computer,
LAN/network AP). With this parameter we can differentiate among
pedestrians and vehicles."
*/
} // evaluate sniffed packet
break;
default:
break;
}
} // gap_callback_handler
esp_err_t register_ble_callback(void) {
ESP_LOGI(TAG, "Register GAP callback");
// This function is called to occur gap event, such as scan result.
//register the scan callback function to the gap module
ESP_ERROR_CHECK(esp_ble_gap_register_callback(&gap_callback_handler));
ESP_LOGI(TAG, "Register GAP callback");
static esp_ble_scan_params_t ble_scan_params =
{
.scan_type = BLE_SCAN_TYPE_PASSIVE,
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
#ifdef VENDORFILTER
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR,
// ADV_IND, ADV_NONCONN_IND, ADV_SCAN_IND packets are used for broadcasting
// data in broadcast applications (e.g., Beacons), so we don't want them in vendorfilter mode
#else
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
#endif
// This function is called to occur gap event, such as scan result.
// register the scan callback function to the gap module
ESP_ERROR_CHECK(esp_ble_gap_register_callback(&gap_callback_handler));
.scan_interval = (uint16_t) (cfg.blescantime * 10 / 0.625), // Time = N * 0.625 msec
.scan_window = (uint16_t) (BLESCANWINDOW / 0.625) // Time = N * 0.625 msec
};
static esp_ble_scan_params_t ble_scan_params = {
.scan_type = BLE_SCAN_TYPE_PASSIVE,
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
ESP_LOGI(TAG, "Set GAP scan parameters");
#ifdef VENDORFILTER
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR,
// ADV_IND, ADV_NONCONN_IND, ADV_SCAN_IND packets are used for broadcasting
// data in broadcast applications (e.g., Beacons), so we don't want them in
// vendorfilter mode
#else
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
#endif
// This function is called to set scan parameters.
ESP_ERROR_CHECK(esp_ble_gap_set_scan_params(&ble_scan_params));
return ESP_OK;
.scan_interval =
(uint16_t)(cfg.blescantime * 10 / 0.625), // Time = N * 0.625 msec
.scan_window = (uint16_t)(BLESCANWINDOW / 0.625) // Time = N * 0.625 msec
};
ESP_LOGI(TAG, "Set GAP scan parameters");
// This function is called to set scan parameters.
ESP_ERROR_CHECK(esp_ble_gap_set_scan_params(&ble_scan_params));
return ESP_OK;
} // register_ble_callback
void start_BLEscan(void){
ESP_LOGI(TAG, "Initializing bluetooth scanner ...");
void start_BLEscan(void) {
ESP_LOGI(TAG, "Initializing bluetooth scanner ...");
// Initialize BT controller to allocate task and other resource.
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
bt_cfg.controller_task_stack_size = BLESTACKSIZE; // set BT stack size to value configured in paxcounter.conf
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BTDM));
// Initialize BT controller to allocate task and other resource.
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
bt_cfg.controller_task_stack_size =
BLESTACKSIZE; // set BT stack size to value configured in paxcounter.conf
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BTDM));
// Init and alloc the resource for bluetooth stack, must be done prior to every bluetooth stuff
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
// Init and alloc the resource for bluetooth stack, must be done prior to
// every bluetooth stuff
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
// Register callback function for capturing bluetooth packets
ESP_ERROR_CHECK(register_ble_callback());
// Register callback function for capturing bluetooth packets
ESP_ERROR_CHECK(register_ble_callback());
ESP_LOGI(TAG, "Bluetooth scanner started");
ESP_LOGI(TAG, "Bluetooth scanner started");
} // start_BLEscan
void stop_BLEscan(void){
ESP_LOGI(TAG, "Shutting down bluetooth scanner ...");
ESP_ERROR_CHECK(esp_ble_gap_register_callback(NULL));
ESP_ERROR_CHECK(esp_bluedroid_disable());
ESP_ERROR_CHECK(esp_bluedroid_deinit());
ESP_ERROR_CHECK(esp_bt_controller_disable());
ESP_ERROR_CHECK(esp_bt_controller_deinit());
ESP_LOGI(TAG, "Bluetooth scanner stopped");
void stop_BLEscan(void) {
ESP_LOGI(TAG, "Shutting down bluetooth scanner ...");
ESP_ERROR_CHECK(esp_ble_gap_register_callback(NULL));
ESP_ERROR_CHECK(esp_bluedroid_disable());
ESP_ERROR_CHECK(esp_bluedroid_deinit());
ESP_ERROR_CHECK(esp_bt_controller_disable());
ESP_ERROR_CHECK(esp_bt_controller_deinit());
ESP_LOGI(TAG, "Bluetooth scanner stopped");
} // stop_BLEscan
#endif // BLECOUNTER

View File

@ -13,130 +13,151 @@ esp_err_t err;
// defined in antenna.cpp
#ifdef HAS_ANTENNA_SWITCH
void antenna_select(const uint8_t _ant);
void antenna_select(const uint8_t _ant);
#endif
// populate cfg vars with factory settings
void defaultConfig() {
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora spreadfactor defined in paxcounter.conf
cfg.txpower = 15; // 2-15, lora tx power
cfg.adrmode = 1; // 0=disabled, 1=enabled
cfg.screensaver = 0; // 0=disabled, 1=enabled
cfg.screenon = 1; // 0=disabled, 1=enabled
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
cfg.sendcycle = SEND_SECS; // payload send cycle [seconds/2]
cfg.wifichancycle = WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
cfg.blescantime = BLESCANINTERVAL / 10; // BT channel scan cycle duration [seconds/100], default 1 (= 10ms)
cfg.blescan = 1; // 0=disabled, 1=enabled
cfg.wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4)
cfg.vendorfilter = 1; // 0=disabled, 1=enabled
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
cfg.gpsmode = 1; // 0=disabled, 1=enabled
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora sf, see pacounter.conf
cfg.txpower = 15; // 2-15, lora tx power
cfg.adrmode = 1; // 0=disabled, 1=enabled
cfg.screensaver = 0; // 0=disabled, 1=enabled
cfg.screenon = 1; // 0=disabled, 1=enabled
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
cfg.sendcycle = SEND_SECS; // payload send cycle [seconds/2]
cfg.wifichancycle =
WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
cfg.blescantime =
BLESCANINTERVAL /
10; // BT channel scan cycle [seconds/100], default 1 (= 10ms)
cfg.blescan = 1; // 0=disabled, 1=enabled
cfg.wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4)
cfg.vendorfilter = 1; // 0=disabled, 1=enabled
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
cfg.gpsmode = 1; // 0=disabled, 1=enabled
strncpy( cfg.version, PROGVERSION, sizeof(cfg.version)-1 );
strncpy(cfg.version, PROGVERSION, sizeof(cfg.version) - 1);
}
void open_storage() {
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
}
ESP_ERROR_CHECK(err);
// Open
ESP_LOGI(TAG, "Opening NVS");
err = nvs_open("config", NVS_READWRITE, &my_handle);
if (err != ESP_OK)
ESP_LOGI(TAG, "Error (%d) opening NVS handle", err);
else
ESP_LOGI(TAG, "Done");
// Open
ESP_LOGI(TAG, "Opening NVS");
err = nvs_open("config", NVS_READWRITE, &my_handle);
if (err != ESP_OK)
ESP_LOGI(TAG, "Error (%d) opening NVS handle", err);
else
ESP_LOGI(TAG, "Done");
}
// erase all keys and values in NVRAM
void eraseConfig() {
ESP_LOGI(TAG, "Clearing settings in NVS");
open_storage();
if (err == ESP_OK) {
nvs_erase_all(my_handle);
nvs_commit(my_handle);
nvs_close(my_handle);
ESP_LOGI(TAG, "Done");}
else {
ESP_LOGW(TAG, "NVS erase failed"); }
ESP_LOGI(TAG, "Clearing settings in NVS");
open_storage();
if (err == ESP_OK) {
nvs_erase_all(my_handle);
nvs_commit(my_handle);
nvs_close(my_handle);
ESP_LOGI(TAG, "Done");
} else {
ESP_LOGW(TAG, "NVS erase failed");
}
}
// save current configuration from RAM to NVRAM
void saveConfig() {
ESP_LOGI(TAG, "Storing settings in NVS");
open_storage();
if (err == ESP_OK) {
int8_t flash8 = 0;
int16_t flash16 = 0;
size_t required_size;
char storedversion[10];
ESP_LOGI(TAG, "Storing settings in NVS");
open_storage();
if (err == ESP_OK) {
int8_t flash8 = 0;
int16_t flash16 = 0;
size_t required_size;
char storedversion[10];
if( nvs_get_str(my_handle, "version", storedversion, &required_size) != ESP_OK || strcmp(storedversion, cfg.version) != 0 )
nvs_set_str(my_handle, "version", cfg.version);
if (nvs_get_str(my_handle, "version", storedversion, &required_size) !=
ESP_OK ||
strcmp(storedversion, cfg.version) != 0)
nvs_set_str(my_handle, "version", cfg.version);
if( nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK || flash8 != cfg.lorasf )
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
if (nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK ||
flash8 != cfg.lorasf)
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
if( nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK || flash8 != cfg.txpower )
nvs_set_i8(my_handle, "txpower", cfg.txpower);
if (nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK ||
flash8 != cfg.txpower)
nvs_set_i8(my_handle, "txpower", cfg.txpower);
if( nvs_get_i8(my_handle, "adrmode", &flash8) != ESP_OK || flash8 != cfg.adrmode )
nvs_set_i8(my_handle, "adrmode", cfg.adrmode);
if (nvs_get_i8(my_handle, "adrmode", &flash8) != ESP_OK ||
flash8 != cfg.adrmode)
nvs_set_i8(my_handle, "adrmode", cfg.adrmode);
if( nvs_get_i8(my_handle, "screensaver", &flash8) != ESP_OK || flash8 != cfg.screensaver )
nvs_set_i8(my_handle, "screensaver", cfg.screensaver);
if (nvs_get_i8(my_handle, "screensaver", &flash8) != ESP_OK ||
flash8 != cfg.screensaver)
nvs_set_i8(my_handle, "screensaver", cfg.screensaver);
if( nvs_get_i8(my_handle, "screenon", &flash8) != ESP_OK || flash8 != cfg.screenon )
nvs_set_i8(my_handle, "screenon", cfg.screenon);
if (nvs_get_i8(my_handle, "screenon", &flash8) != ESP_OK ||
flash8 != cfg.screenon)
nvs_set_i8(my_handle, "screenon", cfg.screenon);
if( nvs_get_i8(my_handle, "countermode", &flash8) != ESP_OK || flash8 != cfg.countermode )
nvs_set_i8(my_handle, "countermode", cfg.countermode);
if (nvs_get_i8(my_handle, "countermode", &flash8) != ESP_OK ||
flash8 != cfg.countermode)
nvs_set_i8(my_handle, "countermode", cfg.countermode);
if( nvs_get_i8(my_handle, "sendcycle", &flash8) != ESP_OK || flash8 != cfg.sendcycle )
nvs_set_i8(my_handle, "sendcycle", cfg.sendcycle);
if (nvs_get_i8(my_handle, "sendcycle", &flash8) != ESP_OK ||
flash8 != cfg.sendcycle)
nvs_set_i8(my_handle, "sendcycle", cfg.sendcycle);
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) != ESP_OK || flash8 != cfg.wifichancycle )
nvs_set_i8(my_handle, "wifichancycle", cfg.wifichancycle);
if (nvs_get_i8(my_handle, "wifichancycle", &flash8) != ESP_OK ||
flash8 != cfg.wifichancycle)
nvs_set_i8(my_handle, "wifichancycle", cfg.wifichancycle);
if( nvs_get_i8(my_handle, "blescantime", &flash8) != ESP_OK || flash8 != cfg.blescantime )
nvs_set_i8(my_handle, "blescantime", cfg.blescantime);
if (nvs_get_i8(my_handle, "blescantime", &flash8) != ESP_OK ||
flash8 != cfg.blescantime)
nvs_set_i8(my_handle, "blescantime", cfg.blescantime);
if( nvs_get_i8(my_handle, "blescanmode", &flash8) != ESP_OK || flash8 != cfg.blescan )
nvs_set_i8(my_handle, "blescanmode", cfg.blescan);
if (nvs_get_i8(my_handle, "blescanmode", &flash8) != ESP_OK ||
flash8 != cfg.blescan)
nvs_set_i8(my_handle, "blescanmode", cfg.blescan);
if( nvs_get_i8(my_handle, "wifiant", &flash8) != ESP_OK || flash8 != cfg.wifiant )
nvs_set_i8(my_handle, "wifiant", cfg.wifiant);
if (nvs_get_i8(my_handle, "wifiant", &flash8) != ESP_OK ||
flash8 != cfg.wifiant)
nvs_set_i8(my_handle, "wifiant", cfg.wifiant);
if( nvs_get_i8(my_handle, "vendorfilter", &flash8) != ESP_OK || flash8 != cfg.vendorfilter )
nvs_set_i8(my_handle, "vendorfilter", cfg.vendorfilter);
if (nvs_get_i8(my_handle, "vendorfilter", &flash8) != ESP_OK ||
flash8 != cfg.vendorfilter)
nvs_set_i8(my_handle, "vendorfilter", cfg.vendorfilter);
if( nvs_get_i8(my_handle, "rgblum", &flash8) != ESP_OK || flash8 != cfg.rgblum )
nvs_set_i8(my_handle, "rgblum", cfg.rgblum);
if (nvs_get_i8(my_handle, "rgblum", &flash8) != ESP_OK ||
flash8 != cfg.rgblum)
nvs_set_i8(my_handle, "rgblum", cfg.rgblum);
if( nvs_get_i8(my_handle, "gpsmode", &flash8) != ESP_OK || flash8 != cfg.gpsmode )
if (nvs_get_i8(my_handle, "gpsmode", &flash8) != ESP_OK ||
flash8 != cfg.gpsmode)
nvs_set_i8(my_handle, "gpsmode", cfg.gpsmode);
if( nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK || flash16 != cfg.rssilimit )
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
if (nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK ||
flash16 != cfg.rssilimit)
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
err = nvs_commit(my_handle);
nvs_close(my_handle);
if ( err == ESP_OK ) {
ESP_LOGI(TAG, "Done");
} else {
ESP_LOGW(TAG, "NVS config write failed");
}
err = nvs_commit(my_handle);
nvs_close(my_handle);
if (err == ESP_OK) {
ESP_LOGI(TAG, "Done");
} else {
ESP_LOGW(TAG, "Error (%d) opening NVS handle", err);
ESP_LOGW(TAG, "NVS config write failed");
}
} else {
ESP_LOGW(TAG, "Error (%d) opening NVS handle", err);
}
}
// set and save cfg.version
@ -152,31 +173,33 @@ void loadConfig() {
ESP_LOGI(TAG, "Reading settings from NVS");
open_storage();
if (err != ESP_OK) {
ESP_LOGW(TAG,"Error (%d) opening NVS handle, storing defaults", err);
saveConfig(); } // saves factory settings to NVRAM
ESP_LOGW(TAG, "Error (%d) opening NVS handle, storing defaults", err);
saveConfig();
} // saves factory settings to NVRAM
else {
int8_t flash8 = 0;
int8_t flash8 = 0;
int16_t flash16 = 0;
size_t required_size;
// check if configuration stored in NVRAM matches PROGVERSION
if( nvs_get_str(my_handle, "version", NULL, &required_size) == ESP_OK ) {
if (nvs_get_str(my_handle, "version", NULL, &required_size) == ESP_OK) {
nvs_get_str(my_handle, "version", cfg.version, &required_size);
ESP_LOGI(TAG, "NVRAM settings version = %s", cfg.version);
if (strcmp(cfg.version, PROGVERSION)) {
ESP_LOGI(TAG, "migrating NVRAM settings to new version %s", PROGVERSION);
ESP_LOGI(TAG, "migrating NVRAM settings to new version %s",
PROGVERSION);
nvs_close(my_handle);
migrateVersion();
}
} else {
ESP_LOGI(TAG, "new version %s, deleting NVRAM settings", PROGVERSION);
nvs_close(my_handle);
eraseConfig();
migrateVersion();
ESP_LOGI(TAG, "new version %s, deleting NVRAM settings", PROGVERSION);
nvs_close(my_handle);
eraseConfig();
migrateVersion();
}
// overwrite defaults with valid values from NVRAM
if( nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK) {
cfg.lorasf = flash8;
ESP_LOGI(TAG, "lorasf = %d", flash8);
} else {
@ -184,7 +207,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "txpower", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "txpower", &flash8) == ESP_OK) {
cfg.txpower = flash8;
ESP_LOGI(TAG, "txpower = %d", flash8);
} else {
@ -192,7 +215,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "adrmode", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "adrmode", &flash8) == ESP_OK) {
cfg.adrmode = flash8;
ESP_LOGI(TAG, "adrmode = %d", flash8);
} else {
@ -200,7 +223,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "screensaver", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "screensaver", &flash8) == ESP_OK) {
cfg.screensaver = flash8;
ESP_LOGI(TAG, "screensaver = %d", flash8);
} else {
@ -208,7 +231,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "screenon", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "screenon", &flash8) == ESP_OK) {
cfg.screenon = flash8;
ESP_LOGI(TAG, "screenon = %d", flash8);
} else {
@ -216,7 +239,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "countermode", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "countermode", &flash8) == ESP_OK) {
cfg.countermode = flash8;
ESP_LOGI(TAG, "countermode = %d", flash8);
} else {
@ -224,7 +247,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "sendcycle", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "sendcycle", &flash8) == ESP_OK) {
cfg.sendcycle = flash8;
ESP_LOGI(TAG, "sendcycle = %d", flash8);
} else {
@ -232,7 +255,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "wifichancycle", &flash8) == ESP_OK) {
cfg.wifichancycle = flash8;
ESP_LOGI(TAG, "wifichancycle = %d", flash8);
} else {
@ -240,7 +263,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "wifiant", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "wifiant", &flash8) == ESP_OK) {
cfg.wifiant = flash8;
ESP_LOGI(TAG, "wifiantenna = %d", flash8);
} else {
@ -248,7 +271,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "vendorfilter", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "vendorfilter", &flash8) == ESP_OK) {
cfg.vendorfilter = flash8;
ESP_LOGI(TAG, "vendorfilter = %d", flash8);
} else {
@ -256,7 +279,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "rgblum", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "rgblum", &flash8) == ESP_OK) {
cfg.rgblum = flash8;
ESP_LOGI(TAG, "rgbluminosity = %d", flash8);
} else {
@ -264,7 +287,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "blescantime", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "blescantime", &flash8) == ESP_OK) {
cfg.blescantime = flash8;
ESP_LOGI(TAG, "blescantime = %d", flash8);
} else {
@ -272,7 +295,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "blescanmode", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "blescanmode", &flash8) == ESP_OK) {
cfg.blescan = flash8;
ESP_LOGI(TAG, "BLEscanmode = %d", flash8);
} else {
@ -280,7 +303,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i16(my_handle, "rssilimit", &flash16) == ESP_OK ) {
if (nvs_get_i16(my_handle, "rssilimit", &flash16) == ESP_OK) {
cfg.rssilimit = flash16;
ESP_LOGI(TAG, "rssilimit = %d", flash16);
} else {
@ -288,7 +311,7 @@ void loadConfig() {
saveConfig();
}
if( nvs_get_i8(my_handle, "gpsmode", &flash8) == ESP_OK ) {
if (nvs_get_i8(my_handle, "gpsmode", &flash8) == ESP_OK) {
cfg.gpsmode = flash8;
ESP_LOGI(TAG, "GPSmode = %d", flash8);
} else {
@ -300,9 +323,9 @@ void loadConfig() {
ESP_LOGI(TAG, "Done");
// put actions to be triggered after config loaded here
#ifdef HAS_ANTENNA_SWITCH // set antenna type, if device has one
antenna_select(cfg.wifiant);
#endif
}
#ifdef HAS_ANTENNA_SWITCH // set antenna type, if device has one
antenna_select(cfg.wifiant);
#endif
}
}

View File

@ -8,12 +8,12 @@
// OLED Display
#ifdef HAS_DISPLAY
#include <U8x8lib.h>
#include <U8x8lib.h>
#endif
//GPS
// GPS
#ifdef HAS_GPS
#include <TinyGPS++.h>
#include <TinyGPS++.h>
#endif
// LMIC-Arduino LoRaWAN Stack
@ -22,7 +22,7 @@
// LED controls
#ifdef HAS_RGB_LED
#include <SmartLeds.h>
#include <SmartLeds.h>
#endif
#include "rgb_led.h"
@ -31,34 +31,34 @@
// Struct holding devices's runtime configuration
typedef struct {
uint8_t lorasf; // 7-12, lora spreadfactor
uint8_t txpower; // 2-15, lora tx power
uint8_t adrmode; // 0=disabled, 1=enabled
uint8_t screensaver; // 0=disabled, 1=enabled
uint8_t screenon; // 0=disabled, 1=enabled
uint8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed
int16_t rssilimit; // threshold for rssilimiter, negative value!
uint8_t sendcycle; // payload send cycle [seconds/2]
uint8_t wifichancycle; // wifi channel switch cycle [seconds/100]
uint8_t blescantime; // BLE scan cycle duration [seconds]
uint8_t blescan; // 0=disabled, 1=enabled
uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4)
uint8_t vendorfilter; // 0=disabled, 1=enabled
uint8_t rgblum; // RGB Led luminosity (0..100%)
uint8_t gpsmode; // 0=disabled, 1=enabled
char version[10]; // Firmware version
} configData_t;
uint8_t lorasf; // 7-12, lora spreadfactor
uint8_t txpower; // 2-15, lora tx power
uint8_t adrmode; // 0=disabled, 1=enabled
uint8_t screensaver; // 0=disabled, 1=enabled
uint8_t screenon; // 0=disabled, 1=enabled
uint8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed
int16_t rssilimit; // threshold for rssilimiter, negative value!
uint8_t sendcycle; // payload send cycle [seconds/2]
uint8_t wifichancycle; // wifi channel switch cycle [seconds/100]
uint8_t blescantime; // BLE scan cycle duration [seconds]
uint8_t blescan; // 0=disabled, 1=enabled
uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4)
uint8_t vendorfilter; // 0=disabled, 1=enabled
uint8_t rgblum; // RGB Led luminosity (0..100%)
uint8_t gpsmode; // 0=disabled, 1=enabled
char version[10]; // Firmware version
} configData_t;
#ifdef HAS_GPS
typedef struct {
uint32_t latitude;
uint32_t longitude;
uint8_t satellites;
uint16_t hdop;
uint16_t altitude;
} gpsStatus_t;
extern gpsStatus_t gps_status; // struct for storing gps data
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
typedef struct {
uint32_t latitude;
uint32_t longitude;
uint8_t satellites;
uint16_t hdop;
uint16_t altitude;
} gpsStatus_t;
extern gpsStatus_t gps_status; // struct for storing gps data
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
#endif
extern configData_t cfg;
@ -68,6 +68,7 @@ extern char display_lora[], display_lmic[];
extern int countermode, screensaver, adrmode, lorasf, txpower, rlim;
extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters
extern std::set<uint16_t> macs;
extern hw_timer_t * channelSwitch; // hardware timer used for wifi channel switching
extern xref2u1_t rcmd_data; // buffer for rcommand results size
extern u1_t rcmd_data_size; // buffer for rcommand results size
extern hw_timer_t
*channelSwitch; // hardware timer used for wifi channel switching
extern xref2u1_t rcmd_data; // buffer for rcommand results size
extern u1_t rcmd_data_size; // buffer for rcommand results size

View File

@ -7,74 +7,73 @@ static const char TAG[] = "main";
// read GPS data and cast to global struct
void gps_read() {
gps_status.latitude = (uint32_t) (gps.location.lat() * 1000000);
gps_status.longitude = (uint32_t) (gps.location.lng() * 1000000);
gps_status.satellites = (uint8_t) gps.satellites.value();
gps_status.hdop = (uint16_t) gps.hdop.value();
gps_status.altitude = (uint16_t) gps.altitude.meters();
gps_status.latitude = (uint32_t)(gps.location.lat() * 1000000);
gps_status.longitude = (uint32_t)(gps.location.lng() * 1000000);
gps_status.satellites = (uint8_t)gps.satellites.value();
gps_status.hdop = (uint16_t)gps.hdop.value();
gps_status.altitude = (uint16_t)gps.altitude.meters();
}
// GPS serial feed FreeRTos Task
void gps_loop(void * pvParameters) {
void gps_loop(void *pvParameters) {
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
// initialize and, if needed, configure, GPS
#if defined GPS_SERIAL
HardwareSerial GPS_Serial(1);
#elif defined GPS_I2C
// to be done
#endif
// initialize and, if needed, configure, GPS
#if defined GPS_SERIAL
HardwareSerial GPS_Serial(1);
#elif defined GPS_I2C
// to be done
#endif
while(1) {
while (1) {
if (cfg.gpsmode)
{
#if defined GPS_SERIAL
// serial connect to GPS device
GPS_Serial.begin(GPS_SERIAL);
while(cfg.gpsmode) {
// feed GPS decoder with serial NMEA data from GPS device
while (GPS_Serial.available()) {
gps.encode(GPS_Serial.read());
}
vTaskDelay(1/portTICK_PERIOD_MS); // reset watchdog
}
// after GPS function was disabled, close connect to GPS device
GPS_Serial.end();
if (cfg.gpsmode) {
#if defined GPS_SERIAL
#elif defined GPS_I2C
// I2C connect to GPS device with 100 kHz
Wire.begin(GPS_I2C_PINS, 100000);
Wire.beginTransmission(GPS_I2C_ADDRESS_WRITE);
Wire.write(0x00);
// serial connect to GPS device
GPS_Serial.begin(GPS_SERIAL);
i2c_ret == Wire.beginTransmission(GPS_I2C_ADDRESS_READ);
if (i2c_ret == 0) { // check if device seen on i2c bus
while(cfg.gpsmode) {
// feed GPS decoder with serial NMEA data from GPS device
while (Wire.available()) {
Wire.requestFrom(GPS_I2C_ADDRESS_READ, 255);
gps.encode(Wire.read());
vTaskDelay(1/portTICK_PERIOD_MS); // reset watchdog
}
}
// after GPS function was disabled, close connect to GPS device
Wire.endTransmission();
Wire.setClock(400000); // Set back to 400KHz to speed up OLED
}
#endif
while (cfg.gpsmode) {
// feed GPS decoder with serial NMEA data from GPS device
while (GPS_Serial.available()) {
gps.encode(GPS_Serial.read());
}
vTaskDelay(1/portTICK_PERIOD_MS); // reset watchdog
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
}
// after GPS function was disabled, close connect to GPS device
GPS_Serial.end();
} // end of infinite loop
#elif defined GPS_I2C
// I2C connect to GPS device with 100 kHz
Wire.begin(GPS_I2C_PINS, 100000);
Wire.beginTransmission(GPS_I2C_ADDRESS_WRITE);
Wire.write(0x00);
i2c_ret == Wire.beginTransmission(GPS_I2C_ADDRESS_READ);
if (i2c_ret == 0) { // check if device seen on i2c bus
while (cfg.gpsmode) {
// feed GPS decoder with serial NMEA data from GPS device
while (Wire.available()) {
Wire.requestFrom(GPS_I2C_ADDRESS_READ, 255);
gps.encode(Wire.read());
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
}
}
// after GPS function was disabled, close connect to GPS device
Wire.endTransmission();
Wire.setClock(400000); // Set back to 400KHz to speed up OLED
}
#endif
}
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
} // end of infinite loop
} // gps_loop()
#endif // HAS_GPS

View File

@ -19,6 +19,4 @@
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
#define DIO1 GPIO_NUM_32 // Lora1 <-> HPD13A IO1 // !! NEEDS EXTERNAL WIRING !!
#define DIO2 \
LMIC_UNUSED_PIN // Lora2 <-> HPD13A IO2 // needs external wiring, but not
// necessary for LoRa, only FSK
#define DIO2 LMIC_UNUSED_PIN // Lora2 <-> HPD13A IO2 // not needed for LoRa

View File

@ -1,28 +1,31 @@
/************************************************************
* LMIC LoRaWAN configuration
*
*
* Read the values from TTN console (or whatever applies), insert them here,
* and rename this file to src/loraconf.h
*
*
* Note that DEVEUI, APPEUI and APPKEY should all be specified in MSB format.
* (This is different from standard LMIC-Arduino which expects DEVEUI and APPEUI in LSB format.)
* (This is different from standard LMIC-Arduino which expects DEVEUI and APPEUI
* in LSB format.)
* Set your DEVEUI here, if you have one. You can leave this untouched,
* Set your DEVEUI here, if you have one. You can leave this untouched,
* then the DEVEUI will be generated during runtime from device's MAC adress
* and will be displayed on device's screen as well as on serial console.
*
* NOTE: Use MSB format (as displayed in TTN console, so you can cut & paste from there)
*
* NOTE: Use MSB format (as displayed in TTN console, so you can cut & paste
* from there)
* For TTN, APPEUI in MSB format always starts with 0x70, 0xB3, 0xD5
*
* Note: If using a board with Microchip 24AA02E64 Uinique ID for deveui,
* the DEVEUI will be overwriten by the one contained in the Microchip module
*
*
************************************************************/
#include <Arduino.h>
static const u1_t DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t DEVEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const u1_t APPEUI[8]={ 0x70, 0xB3, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t APPEUI[8] = {0x70, 0xB3, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00};
static const u1_t APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t APPKEY[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

View File

@ -211,8 +211,7 @@ void onEvent(ev_t ev) {
case EV_JOINED:
strcpy_P(buff, PSTR("JOINED"));
sprintf(display_lora,
" "); // clear previous lmic status message from display
sprintf(display_lora, " "); // clear previous lmic status
// set data rate adaptation
LMIC_setAdrMode(cfg.adrmode);
@ -229,8 +228,7 @@ void onEvent(ev_t ev) {
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK")
: PSTR("TX COMPLETE"));
sprintf(display_lora,
" "); // clear previous lmic status message from display
sprintf(display_lora, " "); // clear previous lmic status
if (LMIC.dataLen) {
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",

View File

@ -2,9 +2,9 @@
#define LORAWAN_H
void onEvent(ev_t ev);
void do_send(osjob_t* j);
void gen_lora_deveui(uint8_t * pdeveui);
void RevBytes(unsigned char* b, size_t c);
void do_send(osjob_t *j);
void gen_lora_deveui(uint8_t *pdeveui);
void RevBytes(unsigned char *b, size_t c);
void get_hard_deveui(uint8_t *pdeveui);
#endif

View File

@ -3,114 +3,134 @@
#include "globals.h"
#ifdef VENDORFILTER
#include "vendor_array.h"
#include "vendor_array.h"
#endif
// Local logging tag
static const char TAG[] = "wifi";
static wifi_country_t wifi_country = {.cc=WIFI_MY_COUNTRY, .schan=WIFI_CHANNEL_MIN, .nchan=WIFI_CHANNEL_MAX, .policy=WIFI_COUNTRY_POLICY_MANUAL};
static wifi_country_t wifi_country = {.cc = WIFI_MY_COUNTRY,
.schan = WIFI_CHANNEL_MIN,
.nchan = WIFI_CHANNEL_MAX,
.policy = WIFI_COUNTRY_POLICY_MANUAL};
// globals
uint16_t salt;
uint16_t reset_salt(void) {
salt = random(65536); // get new 16bit random for salting hashes and set global salt var
return salt;
salt = random(65536); // get new 16bit random for salting hashes
return salt;
}
bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
char buff[16]; // temporary buffer for printf
bool added = false;
uint32_t addr2int, vendor2int; // temporary buffer for MAC and Vendor OUI
uint16_t hashedmac; // temporary buffer for generated hash value
char buff[16]; // temporary buffer for printf
bool added = false;
uint32_t addr2int, vendor2int; // temporary buffer for MAC and Vendor OUI
uint16_t hashedmac; // temporary buffer for generated hash value
// only last 3 MAC Address bytes are used for MAC address anonymization
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0
addr2int = ( (uint32_t)paddr[2] ) | ( (uint32_t)paddr[3] << 8 ) | ( (uint32_t)paddr[4] << 16 ) | ( (uint32_t)paddr[5] << 24 );
// only last 3 MAC Address bytes are used for MAC address anonymization
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0
addr2int = ((uint32_t)paddr[2]) | ((uint32_t)paddr[3] << 8) |
((uint32_t)paddr[4] << 16) | ((uint32_t)paddr[5] << 24);
#ifdef VENDORFILTER
vendor2int = ( (uint32_t)paddr[2] ) | ( (uint32_t)paddr[1] << 8 ) | ( (uint32_t)paddr[0] << 16 );
// use OUI vendor filter list only on Wifi, not on BLE
if ( (sniff_type==MAC_SNIFF_BLE) || std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() )
{
#endif
#ifdef VENDORFILTER
vendor2int = ((uint32_t)paddr[2]) | ((uint32_t)paddr[1] << 8) |
((uint32_t)paddr[0] << 16);
// use OUI vendor filter list only on Wifi, not on BLE
if ((sniff_type == MAC_SNIFF_BLE) ||
std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end()) {
#endif
// salt and hash MAC, and if new unique one, store identifier in container and increment counter on display
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
addr2int += (uint32_t)salt; // add 16-bit salt to pseudo MAC
snprintf(buff, sizeof(buff), "%08X", addr2int); // convert unsigned 32-bit salted MAC to 8 digit hex string
hashedmac = rokkit(&buff[3], 5); // hash MAC last string value, use 5 chars to fit hash in uint16_t container
auto newmac = macs.insert(hashedmac); // add hashed MAC to total container if new unique
added = newmac.second ? true:false; // true if hashed MAC is unique in container
// salt and hash MAC, and if new unique one, store identifier in container
// and increment counter on display
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
addr2int += (uint32_t)salt; // add 16-bit salt to pseudo MAC
snprintf(
buff, sizeof(buff), "%08X",
addr2int); // convert unsigned 32-bit salted MAC to 8 digit hex string
hashedmac = rokkit(&buff[3], 5); // hash MAC last string value, use 5 chars
// to fit hash in uint16_t container
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
added = newmac.second ? true
: false; // true if hashed MAC is unique in container
// Count only if MAC was not yet seen
if (added) {
// increment counter and one blink led
if (sniff_type == MAC_SNIFF_WIFI ) {
macs_wifi++; // increment Wifi MACs counter
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
blink_LED(COLOR_GREEN, 50);
#endif
}
#ifdef BLECOUNTER
else if (sniff_type == MAC_SNIFF_BLE ) {
macs_ble++; // increment BLE Macs counter
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
blink_LED(COLOR_MAGENTA, 50);
#endif
}
#endif
}
// increment counter and one blink led
if (sniff_type == MAC_SNIFF_WIFI) {
macs_wifi++; // increment Wifi MACs counter
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
blink_LED(COLOR_GREEN, 50);
#endif
}
#ifdef BLECOUNTER
else if (sniff_type == MAC_SNIFF_BLE) {
macs_ble++; // increment BLE Macs counter
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
blink_LED(COLOR_MAGENTA, 50);
#endif
}
#endif
}
// Log scan result
ESP_LOGI(TAG, "%s %s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLTH:%d -> %d Bytes left",
added ? "new " : "known",
sniff_type==MAC_SNIFF_WIFI ? "WiFi":"BLTH",
rssi, buff, hashedmac, macs_wifi, macs_ble,
ESP.getFreeHeap());
ESP_LOGI(TAG,
"%s %s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLTH:%d -> "
"%d Bytes left",
added ? "new " : "known",
sniff_type == MAC_SNIFF_WIFI ? "WiFi" : "BLTH", rssi, buff,
hashedmac, macs_wifi, macs_ble, ESP.getFreeHeap());
#ifdef VENDORFILTER
} else {
// Very noisy
// ESP_LOGD(TAG, "Filtered MAC %02X:%02X:%02X:%02X:%02X:%02X", paddr[0],paddr[1],paddr[2],paddr[3],paddr[5],paddr[5]);
}
#endif
#ifdef VENDORFILTER
} else {
// Very noisy
// ESP_LOGD(TAG, "Filtered MAC %02X:%02X:%02X:%02X:%02X:%02X",
// paddr[0],paddr[1],paddr[2],paddr[3],paddr[5],paddr[5]);
}
#endif
// True if MAC WiFi/BLE was new
return added; // function returns bool if a new and unique Wifi or BLE mac was counted (true) or not (false)
// True if MAC WiFi/BLE was new
return added; // function returns bool if a new and unique Wifi or BLE mac was
// counted (true) or not (false)
}
void wifi_sniffer_init(void) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
cfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM
wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg
ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country)); // set locales for RF and channels
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
//ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
cfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM
wifi_promiscuous_filter_t filter = {
.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg
ESP_ERROR_CHECK(
esp_wifi_set_country(&wifi_country)); // set locales for RF and channels
ESP_ERROR_CHECK(
esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
// ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
ESP_ERROR_CHECK(
esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
}
void wifi_sniffer_set_channel(uint8_t channel) {
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
}
// using IRAM_:ATTR here to speed up callback function
IRAM_ATTR void wifi_sniffer_packet_handler(void* buff, wifi_promiscuous_pkt_type_t type) {
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload;
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
if ((cfg.rssilimit) && (ppkt->rx_ctrl.rssi < cfg.rssilimit )) { // rssi is negative value
ESP_LOGI(TAG, "WiFi RSSI %d -> ignoring (limit: %d)", ppkt->rx_ctrl.rssi, cfg.rssilimit);
} else {
uint8_t *p = (uint8_t *) hdr->addr2;
mac_add(p, ppkt->rx_ctrl.rssi, MAC_SNIFF_WIFI) ;
}
}
IRAM_ATTR void wifi_sniffer_packet_handler(void *buff,
wifi_promiscuous_pkt_type_t type) {
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
const wifi_ieee80211_packet_t *ipkt =
(wifi_ieee80211_packet_t *)ppkt->payload;
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
if ((cfg.rssilimit) &&
(ppkt->rx_ctrl.rssi < cfg.rssilimit)) { // rssi is negative value
ESP_LOGI(TAG, "WiFi RSSI %d -> ignoring (limit: %d)", ppkt->rx_ctrl.rssi,
cfg.rssilimit);
} else {
uint8_t *p = (uint8_t *)hdr->addr2;
mac_add(p, ppkt->rx_ctrl.rssi, MAC_SNIFF_WIFI);
}
}

View File

@ -5,21 +5,21 @@
#include <esp_wifi.h>
#define MAC_SNIFF_WIFI 0
#define MAC_SNIFF_BLE 1
#define MAC_SNIFF_BLE 1
typedef struct {
unsigned frame_ctrl:16;
unsigned duration_id:16;
uint8_t addr1[6]; /* receiver address */
uint8_t addr2[6]; /* sender address */
uint8_t addr3[6]; /* filtering address */
unsigned sequence_ctrl:16;
uint8_t addr4[6]; /* optional */
unsigned frame_ctrl : 16;
unsigned duration_id : 16;
uint8_t addr1[6]; /* receiver address */
uint8_t addr2[6]; /* sender address */
uint8_t addr3[6]; /* filtering address */
unsigned sequence_ctrl : 16;
uint8_t addr4[6]; /* optional */
} wifi_ieee80211_mac_hdr_t;
typedef struct {
wifi_ieee80211_mac_hdr_t hdr;
uint8_t payload[0]; /* network data ended with 4 bytes csum (CRC32) */
wifi_ieee80211_mac_hdr_t hdr;
uint8_t payload[0]; /* network data ended with 4 bytes csum (CRC32) */
} wifi_ieee80211_packet_t;
uint16_t reset_salt(void);
@ -28,6 +28,6 @@ void wifi_sniffer_set_channel(uint8_t channel);
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
// function defined in rokkithash.cpp
uint32_t rokkit(const char * , int );
uint32_t rokkit(const char *, int);
#endif

View File

@ -1,6 +1,5 @@
/*
ESP32-Paxcounter
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>

View File

@ -10,15 +10,12 @@
//--- Declarations ---
enum led_states {
LED_OFF,
LED_ON
};
enum led_states { LED_OFF, LED_ON };
#if defined(CFG_eu868)
const char lora_datarate[] = {"1211100908077BFSNA"};
#elif defined(CFG_us915)
const char lora_datarate[] = {"100908078CNA121110090807"};
const char lora_datarate[] = {"1211100908077BFSNA"};
#elif defined(CFG_us915)
const char lora_datarate[] = {"100908078CNA121110090807"};
#endif
//--- Prototypes ---
@ -28,14 +25,13 @@ void reset_counters(void);
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
void led_loop(void);
// defined in blescan.cpp
#ifdef BLECOUNTER
void start_BLEscan(void);
void stop_BLEscan(void);
void start_BLEscan(void);
void stop_BLEscan(void);
#endif
//defined in gpsread.cpp
// defined in gpsread.cpp
#ifdef HAS_GPS
void gps_read(void);
void gps_loop(void *pvParameters);

View File

@ -1,6 +1,7 @@
// remote command interpreter
// parses multiple number of command / value pairs from LoRaWAN remote command port (RCMDPORT)
// checks commands and executes each command with 1 argument per command
// parses multiple number of command / value pairs from LoRaWAN remote command
// port (RCMDPORT) checks commands and executes each command with 1 argument per
// command
// Basic Config
#include "globals.h"
@ -14,297 +15,351 @@ static const char TAG[] = "main";
// table of remote commands and assigned functions
typedef struct {
const uint8_t nam;
void (*func)(uint8_t);
const bool store;
const uint8_t nam;
void (*func)(uint8_t);
const bool store;
} cmd_t;
// function defined in antenna.cpp
#ifdef HAS_ANTENNA_SWITCH
void antenna_select(const uint8_t _ant);
void antenna_select(const uint8_t _ant);
#endif
// function defined in adcread.cpp
#ifdef HAS_BATTERY_PROBE
uint32_t read_voltage(void);
uint32_t read_voltage(void);
#endif
// function sends result of get commands to LoRaWAN network
void do_transmit(osjob_t* j){
// check if there is a pending TX/RX job running, if yes then reschedule transmission
if (LMIC.opmode & OP_TXRXPEND) {
ESP_LOGI(TAG, "LoRa busy, rescheduling");
sprintf(display_lmic, "LORA BUSY");
os_setTimedCallback(&rcmdjob, os_getTime()+sec2osticks(RETRANSMIT_RCMD), do_transmit);
}
LMIC_setTxData2(RCMDPORT, rcmd_data, rcmd_data_size, 0); // send data unconfirmed on RCMD Port
ESP_LOGI(TAG, "%d bytes queued to send", rcmd_data_size);
sprintf(display_lmic, "PACKET QUEUED");
void do_transmit(osjob_t *j) {
// check if there is a pending TX/RX job running, if yes then reschedule
// transmission
if (LMIC.opmode & OP_TXRXPEND) {
ESP_LOGI(TAG, "LoRa busy, rescheduling");
sprintf(display_lmic, "LORA BUSY");
os_setTimedCallback(&rcmdjob, os_getTime() + sec2osticks(RETRANSMIT_RCMD),
do_transmit);
}
LMIC_setTxData2(RCMDPORT, rcmd_data, rcmd_data_size,
0); // send data unconfirmed on RCMD Port
ESP_LOGI(TAG, "%d bytes queued to send", rcmd_data_size);
sprintf(display_lmic, "PACKET QUEUED");
}
// help function to transmit result of get commands, since callback function do_transmit() cannot have params
void transmit(xref2u1_t mydata, u1_t mydata_size){
rcmd_data = mydata;
rcmd_data_size = mydata_size;
do_transmit(&rcmdjob);
// help function to transmit result of get commands, since callback function
// do_transmit() cannot have params
void transmit(xref2u1_t mydata, u1_t mydata_size) {
rcmd_data = mydata;
rcmd_data_size = mydata_size;
do_transmit(&rcmdjob);
}
// help function to assign LoRa datarates to numeric spreadfactor values
void switch_lora (uint8_t sf, uint8_t tx) {
if ( tx > 20 ) return;
cfg.txpower = tx;
switch (sf) {
case 7: LMIC_setDrTxpow(DR_SF7,tx); cfg.lorasf=sf; break;
case 8: LMIC_setDrTxpow(DR_SF8,tx); cfg.lorasf=sf; break;
case 9: LMIC_setDrTxpow(DR_SF9,tx); cfg.lorasf=sf; break;
case 10: LMIC_setDrTxpow(DR_SF10,tx); cfg.lorasf=sf; break;
case 11:
#if defined(CFG_eu868)
LMIC_setDrTxpow(DR_SF11,tx); cfg.lorasf=sf; break;
#elif defined(CFG_us915)
LMIC_setDrTxpow(DR_SF11CR,tx); cfg.lorasf=sf; break;
#endif
case 12:
#if defined(CFG_eu868)
LMIC_setDrTxpow(DR_SF12,tx); cfg.lorasf=sf; break;
#elif defined(CFG_us915)
LMIC_setDrTxpow(DR_SF12CR,tx); cfg.lorasf=sf; break;
#endif
default: break;
}
void switch_lora(uint8_t sf, uint8_t tx) {
if (tx > 20)
return;
cfg.txpower = tx;
switch (sf) {
case 7:
LMIC_setDrTxpow(DR_SF7, tx);
cfg.lorasf = sf;
break;
case 8:
LMIC_setDrTxpow(DR_SF8, tx);
cfg.lorasf = sf;
break;
case 9:
LMIC_setDrTxpow(DR_SF9, tx);
cfg.lorasf = sf;
break;
case 10:
LMIC_setDrTxpow(DR_SF10, tx);
cfg.lorasf = sf;
break;
case 11:
#if defined(CFG_eu868)
LMIC_setDrTxpow(DR_SF11, tx);
cfg.lorasf = sf;
break;
#elif defined(CFG_us915)
LMIC_setDrTxpow(DR_SF11CR, tx);
cfg.lorasf = sf;
break;
#endif
case 12:
#if defined(CFG_eu868)
LMIC_setDrTxpow(DR_SF12, tx);
cfg.lorasf = sf;
break;
#elif defined(CFG_us915)
LMIC_setDrTxpow(DR_SF12CR, tx);
cfg.lorasf = sf;
break;
#endif
default:
break;
}
}
// set of functions that can be triggered by remote commands
void set_reset(uint8_t val) {
switch (val) {
case 0: // restart device
ESP_LOGI(TAG, "Remote command: restart device");
sprintf(display_lora, "Reset pending");
vTaskDelay(10000/portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server
esp_restart();
break;
case 1: // reset MAC counter
ESP_LOGI(TAG, "Remote command: reset MAC counter");
reset_counters(); // clear macs
reset_salt(); // get new salt
sprintf(display_lora, "Reset counter");
break;
case 2: // reset device to factory settings
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
sprintf(display_lora, "Factory reset");
eraseConfig();
break;
}
switch (val) {
case 0: // restart device
ESP_LOGI(TAG, "Remote command: restart device");
sprintf(display_lora, "Reset pending");
vTaskDelay(
10000 /
portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server
esp_restart();
break;
case 1: // reset MAC counter
ESP_LOGI(TAG, "Remote command: reset MAC counter");
reset_counters(); // clear macs
reset_salt(); // get new salt
sprintf(display_lora, "Reset counter");
break;
case 2: // reset device to factory settings
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
sprintf(display_lora, "Factory reset");
eraseConfig();
break;
}
};
void set_rssi(uint8_t val) {
cfg.rssilimit = val * -1;
ESP_LOGI(TAG, "Remote command: set RSSI limit to %d", cfg.rssilimit);
};
cfg.rssilimit = val * -1;
ESP_LOGI(TAG, "Remote command: set RSSI limit to %d", cfg.rssilimit);
};
void set_sendcycle(uint8_t val) {
cfg.sendcycle = val;
ESP_LOGI(TAG, "Remote command: set payload send cycle to %d seconds", cfg.sendcycle*2);
};
cfg.sendcycle = val;
ESP_LOGI(TAG, "Remote command: set payload send cycle to %d seconds",
cfg.sendcycle * 2);
};
void set_wifichancycle(uint8_t val) {
cfg.wifichancycle = val;
// modify wifi channel rotation IRQ
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 10000, true); // reload interrupt after each trigger of channel switch cycle
ESP_LOGI(TAG, "Remote command: set Wifi channel switch interval to %.1f seconds", cfg.wifichancycle/float(100));
};
cfg.wifichancycle = val;
// modify wifi channel rotation IRQ
timerAlarmWrite(
channelSwitch, cfg.wifichancycle * 10000,
true); // reload interrupt after each trigger of channel switch cycle
ESP_LOGI(TAG,
"Remote command: set Wifi channel switch interval to %.1f seconds",
cfg.wifichancycle / float(100));
};
void set_blescantime(uint8_t val) {
cfg.blescantime = val;
ESP_LOGI(TAG, "Remote command: set BLE scan time to %.1f seconds", cfg.blescantime/float(100));
#ifdef BLECOUNTER
// stop & restart BLE scan task to apply new parameter
if (cfg.blescan)
{
stop_BLEscan();
start_BLEscan();
}
#endif
cfg.blescantime = val;
ESP_LOGI(TAG, "Remote command: set BLE scan time to %.1f seconds",
cfg.blescantime / float(100));
#ifdef BLECOUNTER
// stop & restart BLE scan task to apply new parameter
if (cfg.blescan) {
stop_BLEscan();
start_BLEscan();
}
#endif
};
void set_countmode(uint8_t val) {
switch (val) {
case 0: // cyclic unconfirmed
cfg.countermode = 0;
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic unconfirmed");
break;
case 1: // cumulative
cfg.countermode = 1;
ESP_LOGI(TAG, "Remote command: set counter mode to cumulative");
break;
default: // cyclic confirmed
cfg.countermode = 2;
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic confirmed");
break;
}
switch (val) {
case 0: // cyclic unconfirmed
cfg.countermode = 0;
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic unconfirmed");
break;
case 1: // cumulative
cfg.countermode = 1;
ESP_LOGI(TAG, "Remote command: set counter mode to cumulative");
break;
default: // cyclic confirmed
cfg.countermode = 2;
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic confirmed");
break;
}
};
void set_screensaver(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set screen saver to %s ", val ? "on" : "off");
switch (val) {
case 1: cfg.screensaver = val; break;
default: cfg.screensaver = 0; break;
}
ESP_LOGI(TAG, "Remote command: set screen saver to %s ", val ? "on" : "off");
switch (val) {
case 1:
cfg.screensaver = val;
break;
default:
cfg.screensaver = 0;
break;
}
};
void set_display(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set screen to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.screenon = val; break;
default: cfg.screenon = 0; break;
}
ESP_LOGI(TAG, "Remote command: set screen to %s", val ? "on" : "off");
switch (val) {
case 1:
cfg.screenon = val;
break;
default:
cfg.screenon = 0;
break;
}
};
void set_gps(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set GPS to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.gpsmode = val; break;
default: cfg.gpsmode = 0; break;
}
ESP_LOGI(TAG, "Remote command: set GPS to %s", val ? "on" : "off");
switch (val) {
case 1:
cfg.gpsmode = val;
break;
default:
cfg.gpsmode = 0;
break;
}
};
void set_lorasf(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set LoRa SF to %d", val);
switch_lora(val, cfg.txpower);
ESP_LOGI(TAG, "Remote command: set LoRa SF to %d", val);
switch_lora(val, cfg.txpower);
};
void set_loraadr(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.adrmode = val; break;
default: cfg.adrmode = 0; break;
}
LMIC_setAdrMode(cfg.adrmode);
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val ? "on" : "off");
switch (val) {
case 1:
cfg.adrmode = val;
break;
default:
cfg.adrmode = 0;
break;
}
LMIC_setAdrMode(cfg.adrmode);
};
void set_blescan(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set BLE scanner to %s", val ? "on" : "off");
switch (val) {
case 0:
cfg.blescan = 0;
macs_ble = 0; // clear BLE counter
#ifdef BLECOUNTER
stop_BLEscan();
#endif
break;
default:
cfg.blescan = 1;
#ifdef BLECOUNTER
start_BLEscan();
#endif
break;
}
ESP_LOGI(TAG, "Remote command: set BLE scanner to %s", val ? "on" : "off");
switch (val) {
case 0:
cfg.blescan = 0;
macs_ble = 0; // clear BLE counter
#ifdef BLECOUNTER
stop_BLEscan();
#endif
break;
default:
cfg.blescan = 1;
#ifdef BLECOUNTER
start_BLEscan();
#endif
break;
}
};
void set_wifiant(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set Wifi antenna to %s", val ? "external" : "internal");
switch (val) {
case 1: cfg.wifiant = val; break;
default: cfg.wifiant = 0; break;
}
#ifdef HAS_ANTENNA_SWITCH
antenna_select(cfg.wifiant);
#endif
ESP_LOGI(TAG, "Remote command: set Wifi antenna to %s",
val ? "external" : "internal");
switch (val) {
case 1:
cfg.wifiant = val;
break;
default:
cfg.wifiant = 0;
break;
}
#ifdef HAS_ANTENNA_SWITCH
antenna_select(cfg.wifiant);
#endif
};
void set_vendorfilter(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set vendorfilter mode to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.vendorfilter = val; break;
default: cfg.vendorfilter = 0; break;
}
ESP_LOGI(TAG, "Remote command: set vendorfilter mode to %s",
val ? "on" : "off");
switch (val) {
case 1:
cfg.vendorfilter = val;
break;
default:
cfg.vendorfilter = 0;
break;
}
};
void set_rgblum(uint8_t val) {
// Avoid wrong parameters
cfg.rgblum = (val>=0 && val<=100) ? (uint8_t) val : RGBLUMINOSITY;
ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %d", cfg.rgblum);
// Avoid wrong parameters
cfg.rgblum = (val >= 0 && val <= 100) ? (uint8_t)val : RGBLUMINOSITY;
ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %d", cfg.rgblum);
};
void set_lorapower(uint8_t val) {
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %d", val);
switch_lora(cfg.lorasf, val);
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %d", val);
switch_lora(cfg.lorasf, val);
};
void get_config (uint8_t val) {
ESP_LOGI(TAG, "Remote command: get configuration");
transmit((byte*)&cfg, sizeof(cfg));
void get_config(uint8_t val) {
ESP_LOGI(TAG, "Remote command: get configuration");
transmit((byte *)&cfg, sizeof(cfg));
};
void get_uptime (uint8_t val) {
ESP_LOGI(TAG, "Remote command: get uptime");
transmit((byte*)&uptimecounter, sizeof(uptimecounter));
void get_uptime(uint8_t val) {
ESP_LOGI(TAG, "Remote command: get uptime");
transmit((byte *)&uptimecounter, sizeof(uptimecounter));
};
void get_cputemp (uint8_t val) {
ESP_LOGI(TAG, "Remote command: get cpu temperature");
float temp = temperatureRead();
transmit((byte*)&temp, sizeof(temp));
void get_cputemp(uint8_t val) {
ESP_LOGI(TAG, "Remote command: get cpu temperature");
float temp = temperatureRead();
transmit((byte *)&temp, sizeof(temp));
};
void get_voltage (uint8_t val) {
ESP_LOGI(TAG, "Remote command: get battery voltage");
#ifdef HAS_BATTERY_PROBE
uint16_t voltage = read_voltage();
#else
uint16_t voltage = 0;
#endif
transmit((byte*)&voltage, sizeof(voltage));
void get_voltage(uint8_t val) {
ESP_LOGI(TAG, "Remote command: get battery voltage");
#ifdef HAS_BATTERY_PROBE
uint16_t voltage = read_voltage();
#else
uint16_t voltage = 0;
#endif
transmit((byte *)&voltage, sizeof(voltage));
};
void get_gps (uint8_t val) {
ESP_LOGI(TAG, "Remote command: get gps status");
#ifdef HAS_GPS
gps_read();
transmit((byte*)&gps_status, sizeof(gps_status));
ESP_LOGI(TAG, "lat=%f / lon=%f | Sats=%u | HDOP=%u | Alti=%u", gps_status.latitude / 1000000, gps_status.longitude / 1000000, gps_status.satellites, gps_status.hdop, gps_status.altitude);
#else
ESP_LOGE(TAG, "GPS not present");
#endif
void get_gps(uint8_t val) {
ESP_LOGI(TAG, "Remote command: get gps status");
#ifdef HAS_GPS
gps_read();
transmit((byte *)&gps_status, sizeof(gps_status));
ESP_LOGI(TAG, "lat=%f / lon=%f | Sats=%u | HDOP=%u | Alti=%u",
gps_status.latitude / 1000000, gps_status.longitude / 1000000,
gps_status.satellites, gps_status.hdop, gps_status.altitude);
#else
ESP_LOGE(TAG, "GPS not present");
#endif
};
// assign previously defined functions to set of numeric remote commands
// format: opcode, function, flag (1 = do make settings persistent / 0 = don't)
//
cmd_t table[] = {
{0x01, set_rssi, true},
{0x02, set_countmode, true},
{0x03, set_gps, true},
{0x04, set_display, true},
{0x05, set_lorasf, true},
{0x06, set_lorapower, true},
{0x07, set_loraadr, true},
{0x08, set_screensaver, true},
{0x09, set_reset, false},
{0x0a, set_sendcycle, true},
{0x0b, set_wifichancycle, true},
{0x0c, set_blescantime, true},
{0x0d, set_vendorfilter, false},
{0x0e, set_blescan, true},
{0x0f, set_wifiant, true},
{0x10, set_rgblum, true},
{0x80, get_config, false},
{0x81, get_uptime, false},
{0x82, get_cputemp, false},
{0x83, get_voltage, false},
{0x84, get_gps, false}
};
//
cmd_t table[] = {{0x01, set_rssi, true}, {0x02, set_countmode, true},
{0x03, set_gps, true}, {0x04, set_display, true},
{0x05, set_lorasf, true}, {0x06, set_lorapower, true},
{0x07, set_loraadr, true}, {0x08, set_screensaver, true},
{0x09, set_reset, false}, {0x0a, set_sendcycle, true},
{0x0b, set_wifichancycle, true}, {0x0c, set_blescantime, true},
{0x0d, set_vendorfilter, false}, {0x0e, set_blescan, true},
{0x0f, set_wifiant, true}, {0x10, set_rgblum, true},
{0x80, get_config, false}, {0x81, get_uptime, false},
{0x82, get_cputemp, false}, {0x83, get_voltage, false},
{0x84, get_gps, false}};
// check and execute remote command
void rcommand(uint8_t cmd, uint8_t arg) {
int i = sizeof(table) / sizeof(table[0]); // number of commands in command table
bool store_flag = false;
while(i--) {
if(cmd == table[i].nam) { // check if valid command
table[i].func(arg); // then execute assigned function
if ( table[i].store ) store_flag = true; // set save flag if function needs to store configuration
break; // exit check loop, since command was found
}
int i =
sizeof(table) / sizeof(table[0]); // number of commands in command table
bool store_flag = false;
while (i--) {
if (cmd == table[i].nam) { // check if valid command
table[i].func(arg); // then execute assigned function
if (table[i].store)
store_flag =
true; // set save flag if function needs to store configuration
break; // exit check loop, since command was found
}
if (store_flag) saveConfig(); // if save flag is set: store new configuration in NVS to make it persistent
}
if (store_flag)
saveConfig(); // if save flag is set: store new configuration in NVS to make
// it persistent
}

View File

@ -6,23 +6,22 @@
// RGB Led instance
SmartLed rgb_led(LED_WS2812, 1, HAS_RGB_LED);
float rgb_CalcColor(float p, float q, float t)
{
if (t < 0.0f)
t += 1.0f;
if (t > 1.0f)
t -= 1.0f;
float rgb_CalcColor(float p, float q, float t) {
if (t < 0.0f)
t += 1.0f;
if (t > 1.0f)
t -= 1.0f;
if (t < 1.0f / 6.0f)
return p + (q - p) * 6.0f * t;
if (t < 1.0f / 6.0f)
return p + (q - p) * 6.0f * t;
if (t < 0.5f)
return q;
if (t < 0.5f)
return q;
if (t < 2.0f / 3.0f)
return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f);
if (t < 2.0f / 3.0f)
return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f);
return p;
return p;
}
// ------------------------------------------------------------------------
@ -30,45 +29,41 @@ float rgb_CalcColor(float p, float q, float t)
// HslColor using H, S, L values (0.0 - 1.0)
// L should be limited to between (0.0 - 0.5)
// ------------------------------------------------------------------------
RGBColor rgb_hsl2rgb(float h, float s, float l)
{
RGBColor RGB_color;
float r;
float g;
float b;
RGBColor rgb_hsl2rgb(float h, float s, float l) {
RGBColor RGB_color;
float r;
float g;
float b;
if (s == 0.0f || l == 0.0f)
{
r = g = b = l; // achromatic or black
}
else
{
float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
float p = 2.0f * l - q;
r = rgb_CalcColor(p, q, h + 1.0f / 3.0f);
g = rgb_CalcColor(p, q, h);
b = rgb_CalcColor(p, q, h - 1.0f / 3.0f);
}
if (s == 0.0f || l == 0.0f) {
r = g = b = l; // achromatic or black
} else {
float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
float p = 2.0f * l - q;
r = rgb_CalcColor(p, q, h + 1.0f / 3.0f);
g = rgb_CalcColor(p, q, h);
b = rgb_CalcColor(p, q, h - 1.0f / 3.0f);
}
RGB_color.R = (uint8_t)(r * 255.0f);
RGB_color.G = (uint8_t)(g * 255.0f);
RGB_color.B = (uint8_t)(b * 255.0f);
RGB_color.R = (uint8_t)(r * 255.0f);
RGB_color.G = (uint8_t)(g * 255.0f);
RGB_color.B = (uint8_t)(b * 255.0f);
return RGB_color;
return RGB_color;
}
void rgb_set_color(uint16_t hue) {
if (hue == COLOR_NONE) {
// Off
rgb_led[0] = Rgb(0,0,0);
rgb_led[0] = Rgb(0, 0, 0);
} else {
// see http://www.workwithcolor.com/blue-color-hue-range-01.htm
// H (is color from 0..360) should be between 0.0 and 1.0
// S is saturation keep it to 1
// L is brightness should be between 0.0 and 0.5
// cfg.rgblum is between 0 and 100 (percent)
RGBColor target = rgb_hsl2rgb( hue / 360.0f, 1.0f, 0.005f * cfg.rgblum);
//uint32_t color = target.R<<16 | target.G<<8 | target.B;
RGBColor target = rgb_hsl2rgb(hue / 360.0f, 1.0f, 0.005f * cfg.rgblum);
// uint32_t color = target.R<<16 | target.G<<8 | target.B;
rgb_led[0] = Rgb(target.R, target.G, target.B);
}
// Show

View File

@ -3,27 +3,26 @@
// value for HSL color
// see http://www.workwithcolor.com/blue-color-hue-range-01.htm
#define COLOR_RED 0
#define COLOR_ORANGE 30
#define COLOR_ORANGE_YELLOW 45
#define COLOR_YELLOW 60
#define COLOR_YELLOW_GREEN 90
#define COLOR_GREEN 120
#define COLOR_GREEN_CYAN 165
#define COLOR_CYAN 180
#define COLOR_CYAN_BLUE 210
#define COLOR_BLUE 240
#define COLOR_BLUE_MAGENTA 275
#define COLOR_MAGENTA 300
#define COLOR_PINK 350
#define COLOR_WHITE 360
#define COLOR_NONE 999
#define COLOR_RED 0
#define COLOR_ORANGE 30
#define COLOR_ORANGE_YELLOW 45
#define COLOR_YELLOW 60
#define COLOR_YELLOW_GREEN 90
#define COLOR_GREEN 120
#define COLOR_GREEN_CYAN 165
#define COLOR_CYAN 180
#define COLOR_CYAN_BLUE 210
#define COLOR_BLUE 240
#define COLOR_BLUE_MAGENTA 275
#define COLOR_MAGENTA 300
#define COLOR_PINK 350
#define COLOR_WHITE 360
#define COLOR_NONE 999
struct RGBColor
{
uint8_t R;
uint8_t G;
uint8_t B;
struct RGBColor {
uint8_t R;
uint8_t G;
uint8_t B;
};
// Exported Functions

View File

@ -36,48 +36,52 @@
#include <inttypes.h>
uint32_t rokkit(const char * data, int len) {
uint32_t rokkit(const char *data, int len) {
uint32_t hash, tmp;
int rem;
if (len <= 0 || data == 0) return 0;
hash = len;
rem = len & 3;
len >>= 2;
if (len <= 0 || data == 0)
return 0;
hash = len;
rem = len & 3;
len >>= 2;
/* Main loop */
while (len > 0) {
hash += *((uint16_t*)data);
tmp = (*((uint16_t*)(data+2)) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*2;
hash += hash >> 11;
len--;
}
/* Main loop */
while (len > 0) {
hash += *((uint16_t *)data);
tmp = (*((uint16_t *)(data + 2)) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * 2;
hash += hash >> 11;
len--;
}
/* Handle end cases */
switch (rem) {
case 3: hash += *((uint16_t*)data);
hash ^= hash << 16;
hash ^= ((signed char)data[2]) << 18;
hash += hash >> 11;
break;
case 2: hash += *((uint16_t*)data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += (signed char)*data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
/* Handle end cases */
switch (rem) {
case 3:
hash += *((uint16_t *)data);
hash ^= hash << 16;
hash ^= ((signed char)data[2]) << 18;
hash += hash >> 11;
break;
case 2:
hash += *((uint16_t *)data);
hash ^= hash << 11;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
break;
case 1:
hash += (signed char)*data;
hash ^= hash << 10;
hash += hash >> 1;
}
return hash;
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}

File diff suppressed because it is too large Load Diff