mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-10 07:02:11 +00:00
Merge branch 'master' into tft-gui-work
This commit is contained in:
commit
4b3fe7662b
58
boards/wio-t1000-s.json
Normal file
58
boards/wio-t1000-s.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v7.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x8029"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"],
|
||||
["0x239A", "0x802A"]
|
||||
],
|
||||
"usb_product": "WIO-BOOT",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "Seeed_WIO_WM1110",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "7.3.0",
|
||||
"sd_fwid": "0x0123"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "Seeed WIO WM1110",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink",
|
||||
"cmsis-dap",
|
||||
"blackmagic"
|
||||
],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://www.seeedstudio.com/LoRaWAN-Tracker-c-1938.html",
|
||||
"vendor": "Seeed Studio"
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit 10494bf328ac051fc4add9ddeb677eebf337b531
|
||||
Subproject commit 7f90178f183820e288aec41133144f30723228fe
|
@ -43,6 +43,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
||||
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
|
||||
#if defined(HELTEC_CAPSULE_SENSOR_V3)
|
||||
this->userButton = OneButton(pin, false, false);
|
||||
#elif defined(BUTTON_ACTIVE_LOW) // change by WayenWeng
|
||||
this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
|
||||
#else
|
||||
this->userButton = OneButton(pin, true, true);
|
||||
#endif
|
||||
@ -51,8 +53,12 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
||||
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
#ifdef BUTTON_SENSE_TYPE // change by WayenWeng
|
||||
pinMode(pin, BUTTON_SENSE_TYPE);
|
||||
#else
|
||||
pinMode(pin, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
|
||||
userButton.attachClick(userButtonPressed);
|
||||
|
@ -7,8 +7,12 @@
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
#define Port Serial2
|
||||
#else
|
||||
#ifdef USER_DEBUG_PORT // change by WayenWeng
|
||||
#define Port USER_DEBUG_PORT
|
||||
#else
|
||||
#define Port Serial
|
||||
#endif
|
||||
#endif
|
||||
// Defaulting to the formerly removed phone_timeout_secs value of 15 minutes
|
||||
#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL
|
||||
|
||||
|
@ -400,8 +400,13 @@ bool GPS::setup()
|
||||
int msglen = 0;
|
||||
|
||||
if (!didSerialInit) {
|
||||
#ifdef GNSS_Airoha // change by WayenWeng
|
||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
probe(GPS_BAUDRATE);
|
||||
LOG_INFO("GPS setting to %d.\n", GPS_BAUDRATE);
|
||||
}
|
||||
#else
|
||||
#if !defined(GPS_UC6580)
|
||||
|
||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]);
|
||||
gnssModel = probe(serialSpeeds[speedSelect]);
|
||||
@ -772,6 +777,7 @@ bool GPS::setup()
|
||||
LOG_INFO("GNSS module configuration saved!\n");
|
||||
}
|
||||
}
|
||||
#endif // !GNSS_Airoha
|
||||
didSerialInit = true;
|
||||
}
|
||||
|
||||
@ -865,7 +871,7 @@ void GPS::writePinStandby(bool standby)
|
||||
|
||||
// Determine the new value for the pin
|
||||
// Normally: active HIGH for awake
|
||||
#if PIN_GPS_STANDBY_INVERTED
|
||||
#ifdef PIN_GPS_STANDBY_INVERTED
|
||||
bool val = standby;
|
||||
#else
|
||||
bool val = !standby;
|
||||
@ -1169,6 +1175,9 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
_serial_gps->updateBaudRate(serialSpeed);
|
||||
}
|
||||
#endif
|
||||
#ifdef GNSS_Airoha // add by WayenWeng
|
||||
return GNSS_MODEL_UNKNOWN;
|
||||
#else
|
||||
#ifdef GPS_DEBUG
|
||||
for (int i = 0; i < 20; i++) {
|
||||
getACK("$GP", 200);
|
||||
@ -1315,6 +1324,7 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
}
|
||||
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#endif // !GNSS_Airoha
|
||||
}
|
||||
|
||||
GPS *GPS::createGps()
|
||||
@ -1476,6 +1486,11 @@ bool GPS::factoryReset()
|
||||
*/
|
||||
bool GPS::lookForTime()
|
||||
{
|
||||
#ifdef GNSS_Airoha // add by WayenWeng
|
||||
uint8_t fix = reader.fixQuality();
|
||||
uint32_t now = millis();
|
||||
#endif
|
||||
|
||||
auto ti = reader.time;
|
||||
auto d = reader.date;
|
||||
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
|
||||
@ -1510,6 +1525,13 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
*/
|
||||
bool GPS::lookForLocation()
|
||||
{
|
||||
#ifdef GNSS_Airoha // add by WayenWeng
|
||||
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
|
||||
uint8_t fix = reader.fixQuality();
|
||||
uint32_t now = millis();
|
||||
}
|
||||
#endif
|
||||
|
||||
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
||||
// the 2D/3D fixType (see NMEAGPS.h)
|
||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||
|
@ -328,6 +328,13 @@ void setup()
|
||||
digitalWrite(RESET_OLED, 1);
|
||||
#endif
|
||||
|
||||
#ifdef PERIPHERAL_WARMUP_MS
|
||||
// Some peripherals may require additional time to stabilize after power is connected
|
||||
// e.g. I2C on Heltec Vision Master
|
||||
LOG_INFO("Waiting for peripherals to stabilize\n");
|
||||
delay(PERIPHERAL_WARMUP_MS);
|
||||
#endif
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
|
@ -144,7 +144,7 @@ class MeshService
|
||||
/// returns 0 to allow further processing
|
||||
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
||||
#endif
|
||||
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
|
||||
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it
|
||||
/// needs to keep the packet around it makes a copy
|
||||
int handleFromRadio(const meshtastic_MeshPacket *p);
|
||||
friend class RoutingModule;
|
||||
|
@ -10,6 +10,8 @@ typedef uint32_t NodeNum;
|
||||
typedef uint32_t PacketId; // A packet sequence number
|
||||
|
||||
#define NODENUM_BROADCAST UINT32_MAX
|
||||
#define NODENUM_BROADCAST_NO_LORA \
|
||||
1 // Reserved to only deliver packets over high speed (non-lora) transports, such as MQTT or BLE mesh (not yet implemented)
|
||||
#define ERRNO_OK 0
|
||||
#define ERRNO_NO_INTERFACES 33
|
||||
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
||||
|
@ -439,7 +439,6 @@ void NodeDB::initModuleConfigIntervals()
|
||||
moduleConfig.telemetry.power_update_interval = 0;
|
||||
moduleConfig.neighbor_info.update_interval = 0;
|
||||
moduleConfig.paxcounter.paxcounter_update_interval = 0;
|
||||
moduleConfig.neighbor_info.update_interval = 0;
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultChannels()
|
||||
|
@ -176,6 +176,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
/* Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design,
|
||||
specifically adapted for the Meshtatic project */
|
||||
meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69,
|
||||
/* Sensecap Indicator from Seeed Studio. ESP32-S3 device with TFT and RP2040 coprocessor */
|
||||
meshtastic_HardwareModel_SENSECAP_INDICATOR = 70,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "SerialModule.h"
|
||||
#include "GeoCoord.h"
|
||||
#include "MeshService.h"
|
||||
#include "NMEAWPL.h"
|
||||
#include "NodeDB.h"
|
||||
@ -66,7 +67,7 @@ SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("Seria
|
||||
static Print *serialPrint = &Serial2;
|
||||
#endif
|
||||
|
||||
char serialBytes[meshtastic_Constants_DATA_PAYLOAD_LEN];
|
||||
char serialBytes[512];
|
||||
size_t serialPayloadSize;
|
||||
|
||||
SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
|
||||
@ -198,8 +199,12 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(TTGO_T_ECHO) && !defined(CANARYONE)
|
||||
else {
|
||||
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
|
||||
processWXSerial();
|
||||
|
||||
} else {
|
||||
while (Serial2.available()) {
|
||||
serialPayloadSize = Serial2.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
serialModuleRadio->sendPayload();
|
||||
@ -213,6 +218,27 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends telemetry packet over the mesh network.
|
||||
*
|
||||
* @param m The telemetry data to be sent
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws None
|
||||
*/
|
||||
void SerialModule::sendTelemetry(meshtastic_Telemetry m)
|
||||
{
|
||||
meshtastic_MeshPacket *p = router->allocForSending();
|
||||
p->decoded.portnum = meshtastic_PortNum_TELEMETRY_APP;
|
||||
p->decoded.payload.size =
|
||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Telemetry_msg, &m);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new mesh packet for use as a reply to a received packet.
|
||||
*
|
||||
@ -357,4 +383,162 @@ uint32_t SerialModule::getBaudRate()
|
||||
}
|
||||
return BAUD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the received weather station serial data, extract wind, voltage, and temperature information,
|
||||
* calculate averages and send telemetry data over the mesh network.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void SerialModule::processWXSerial()
|
||||
{
|
||||
#if !defined(TTGO_T_ECHO) && !defined(CANARYONE)
|
||||
static unsigned int lastAveraged = 0;
|
||||
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
|
||||
static double dir_sum_sin = 0;
|
||||
static double dir_sum_cos = 0;
|
||||
static float velSum = 0;
|
||||
static float gust = 0;
|
||||
static float lull = -1;
|
||||
static int velCount = 0;
|
||||
static int dirCount = 0;
|
||||
static char windDir[4] = "xxx"; // Assuming windDir is 3 characters long + null terminator
|
||||
static char windVel[5] = "xx.x"; // Assuming windVel is 4 characters long + null terminator
|
||||
static char windGust[5] = "xx.x"; // Assuming windGust is 4 characters long + null terminator
|
||||
static char batVoltage[5] = "0.0V";
|
||||
static char capVoltage[5] = "0.0V";
|
||||
static float batVoltageF = 0;
|
||||
static float capVoltageF = 0;
|
||||
bool gotwind = false;
|
||||
|
||||
while (Serial2.available()) {
|
||||
// clear serialBytes buffer
|
||||
memset(serialBytes, '\0', sizeof(serialBytes));
|
||||
// memset(formattedString, '\0', sizeof(formattedString));
|
||||
serialPayloadSize = Serial2.readBytes(serialBytes, 512);
|
||||
// check for a strings we care about
|
||||
// example output of serial data fields from the WS85
|
||||
// WindDir = 79
|
||||
// WindSpeed = 0.5
|
||||
// WindGust = 0.6
|
||||
// GXTS04Temp = 24.4
|
||||
if (serialPayloadSize > 0) {
|
||||
// Define variables for line processing
|
||||
int lineStart = 0;
|
||||
int lineEnd = -1;
|
||||
|
||||
// Process each byte in the received data
|
||||
for (size_t i = 0; i < serialPayloadSize; i++) {
|
||||
// go until we hit the end of line and then process the line
|
||||
if (serialBytes[i] == '\n') {
|
||||
lineEnd = i;
|
||||
// Extract the current line
|
||||
char line[meshtastic_Constants_DATA_PAYLOAD_LEN];
|
||||
memset(line, '\0', sizeof(line));
|
||||
memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
|
||||
|
||||
if (strstr(line, "Wind") != NULL) // we have a wind line
|
||||
{
|
||||
gotwind = true;
|
||||
// Find the positions of "=" signs in the line
|
||||
char *windDirPos = strstr(line, "WindDir = ");
|
||||
char *windSpeedPos = strstr(line, "WindSpeed = ");
|
||||
char *windGustPos = strstr(line, "WindGust = ");
|
||||
|
||||
if (windDirPos != NULL) {
|
||||
// Extract data after "=" for WindDir
|
||||
strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = "
|
||||
double radians = toRadians(strtof(windDir, nullptr));
|
||||
dir_sum_sin += sin(radians);
|
||||
dir_sum_cos += cos(radians);
|
||||
dirCount++;
|
||||
} else if (windSpeedPos != NULL) {
|
||||
// Extract data after "=" for WindSpeed
|
||||
strcpy(windVel, windSpeedPos + 15); // Add 15 to skip "WindSpeed = "
|
||||
float newv = strtof(windVel, nullptr);
|
||||
velSum += newv;
|
||||
velCount++;
|
||||
if (newv < lull || lull == -1)
|
||||
lull = newv;
|
||||
|
||||
} else if (windGustPos != NULL) {
|
||||
strcpy(windGust, windGustPos + 15); // Add 15 to skip "WindSpeed = "
|
||||
float newg = strtof(windGust, nullptr);
|
||||
if (newg > gust)
|
||||
gust = newg;
|
||||
}
|
||||
|
||||
// these are also voltage data we care about possibly
|
||||
} else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
|
||||
char *batVoltagePos = strstr(line, "BatVoltage = ");
|
||||
if (batVoltagePos != NULL) {
|
||||
strcpy(batVoltage, batVoltagePos + 17); // 18 for ws 80, 17 for ws85
|
||||
batVoltageF = strtof(batVoltage, nullptr);
|
||||
break; // last possible data we want so break
|
||||
}
|
||||
} else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
|
||||
char *capVoltagePos = strstr(line, "CapVoltage = ");
|
||||
if (capVoltagePos != NULL) {
|
||||
strcpy(capVoltage, capVoltagePos + 17); // 18 for ws 80, 17 for ws85
|
||||
capVoltageF = strtof(capVoltage, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Update lineStart for the next line
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// clear the input buffer
|
||||
while (Serial2.available() > 0) {
|
||||
Serial2.read(); // Read and discard the bytes in the input buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gotwind) {
|
||||
|
||||
LOG_INFO("WS85 : %i %.1fg%.1f %.1fv %.1fv\n", atoi(windDir), strtof(windVel, nullptr), strtof(windGust, nullptr),
|
||||
batVoltageF, capVoltageF);
|
||||
}
|
||||
if (gotwind && millis() - lastAveraged > averageIntervalMillis) {
|
||||
// calulate averages and send to the mesh
|
||||
float velAvg = 1.0 * velSum / velCount;
|
||||
|
||||
double avgSin = dir_sum_sin / dirCount;
|
||||
double avgCos = dir_sum_cos / dirCount;
|
||||
|
||||
double avgRadians = atan2(avgSin, avgCos);
|
||||
float dirAvg = toDegrees(avgRadians);
|
||||
|
||||
if (dirAvg < 0) {
|
||||
dirAvg += 360.0;
|
||||
}
|
||||
lastAveraged = millis();
|
||||
|
||||
// make a telemetry packet with the data
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
m.which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
m.variant.environment_metrics.wind_speed = velAvg;
|
||||
m.variant.environment_metrics.wind_direction = dirAvg;
|
||||
m.variant.environment_metrics.wind_gust = gust;
|
||||
m.variant.environment_metrics.wind_lull = lull;
|
||||
m.variant.environment_metrics.voltage =
|
||||
capVoltageF > batVoltageF ? capVoltageF : batVoltageF; // send the larger of the two voltage values.
|
||||
|
||||
LOG_INFO("WS85 Transmit speed=%fm/s, direction=%d , lull=%f, gust=%f, voltage=%f\n",
|
||||
m.variant.environment_metrics.wind_speed, m.variant.environment_metrics.wind_direction,
|
||||
m.variant.environment_metrics.wind_lull, m.variant.environment_metrics.wind_gust,
|
||||
m.variant.environment_metrics.voltage);
|
||||
|
||||
sendTelemetry(m);
|
||||
|
||||
// reset counters and gust/lull
|
||||
velSum = velCount = dirCount = 0;
|
||||
dir_sum_sin = dir_sum_cos = 0;
|
||||
gust = 0;
|
||||
lull = -1;
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
@ -28,6 +28,8 @@ class SerialModule : public StreamAPI, private concurrency::OSThread
|
||||
|
||||
private:
|
||||
uint32_t getBaudRate();
|
||||
void sendTelemetry(meshtastic_Telemetry m);
|
||||
void processWXSerial();
|
||||
};
|
||||
|
||||
extern SerialModule *serialModule;
|
||||
|
@ -33,6 +33,9 @@
|
||||
#include "Sensor/SHT31Sensor.h"
|
||||
#include "Sensor/SHT4XSensor.h"
|
||||
#include "Sensor/SHTC3Sensor.h"
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
#include "Sensor/T1000xSensor.h"
|
||||
#endif
|
||||
#include "Sensor/TSL2591Sensor.h"
|
||||
#include "Sensor/VEML7700Sensor.h"
|
||||
|
||||
@ -53,6 +56,9 @@ AHT10Sensor aht10Sensor;
|
||||
MLX90632Sensor mlx90632Sensor;
|
||||
DFRobotLarkSensor dfRobotLarkSensor;
|
||||
NAU7802Sensor nau7802Sensor;
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
T1000xSensor t1000xSensor;
|
||||
#endif
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
@ -92,6 +98,9 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
LOG_INFO("Environment Telemetry: Initializing\n");
|
||||
// it's possible to have this module enabled, only for displaying values on the screen.
|
||||
// therefore, we should only enable the sensor loop if measurement is also enabled
|
||||
#ifdef T1000X_SENSOR_EN // add by WayenWeng
|
||||
result = t1000xSensor.runOnce();
|
||||
#else
|
||||
if (dfRobotLarkSensor.hasSensor())
|
||||
result = dfRobotLarkSensor.runOnce();
|
||||
if (bmp085Sensor.hasSensor())
|
||||
@ -132,6 +141,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
result = mlx90632Sensor.runOnce();
|
||||
if (nau7802Sensor.hasSensor())
|
||||
result = nau7802Sensor.runOnce();
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
@ -282,6 +292,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
m->time = getTime();
|
||||
m->which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
|
||||
#ifdef T1000X_SENSOR_EN // add by WayenWeng
|
||||
valid = valid && t1000xSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
#else
|
||||
if (dfRobotLarkSensor.hasSensor()) {
|
||||
valid = valid && dfRobotLarkSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
@ -371,6 +385,7 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return valid && hasSensor;
|
||||
}
|
||||
|
||||
@ -551,4 +566,4 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
116
src/modules/Telemetry/Sensor/T1000xSensor.cpp
Normal file
116
src/modules/Telemetry/Sensor/T1000xSensor.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(T1000X_SENSOR_EN)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "T1000xSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_Sensor.h>
|
||||
|
||||
#define T1000X_SENSE_SAMPLES 15
|
||||
#define T1000X_LIGHT_REF_VCC 2400
|
||||
|
||||
#define HEATER_NTC_BX 4250 // thermistor coefficient B
|
||||
#define HEATER_NTC_RP 8250 // ohm, series resistance to thermistor
|
||||
#define HEATER_NTC_KA 273.15 // 25 Celsius at Kelvin
|
||||
#define NTC_REF_VCC 3000 // mV, output voltage of LDO
|
||||
|
||||
// ntc res table
|
||||
uint32_t ntc_res2[136] = {
|
||||
113347, 107565, 102116, 96978, 92132, 87559, 83242, 79166, 75316, 71677, 68237, 64991, 61919, 59011, 56258, 53650, 51178,
|
||||
48835, 46613, 44506, 42506, 40600, 38791, 37073, 35442, 33892, 32420, 31020, 29689, 28423, 27219, 26076, 24988, 23951,
|
||||
22963, 22021, 21123, 20267, 19450, 18670, 17926, 17214, 16534, 15886, 15266, 14674, 14108, 13566, 13049, 12554, 12081,
|
||||
11628, 11195, 10780, 10382, 10000, 9634, 9284, 8947, 8624, 8315, 8018, 7734, 7461, 7199, 6948, 6707, 6475,
|
||||
6253, 6039, 5834, 5636, 5445, 5262, 5086, 4917, 4754, 4597, 4446, 4301, 4161, 4026, 3896, 3771, 3651,
|
||||
3535, 3423, 3315, 3211, 3111, 3014, 2922, 2834, 2748, 2666, 2586, 2509, 2435, 2364, 2294, 2228, 2163,
|
||||
2100, 2040, 1981, 1925, 1870, 1817, 1766, 1716, 1669, 1622, 1578, 1535, 1493, 1452, 1413, 1375, 1338,
|
||||
1303, 1268, 1234, 1202, 1170, 1139, 1110, 1081, 1053, 1026, 999, 974, 949, 925, 902, 880, 858,
|
||||
};
|
||||
|
||||
int8_t ntc_temp2[136] = {
|
||||
-30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8,
|
||||
-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
|
||||
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
|
||||
};
|
||||
|
||||
T1000xSensor::T1000xSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "T1000x") {}
|
||||
|
||||
int32_t T1000xSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s\n", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
void T1000xSensor::setup()
|
||||
{
|
||||
// Set up oversampling and filter initialization
|
||||
}
|
||||
|
||||
float T1000xSensor::getLux()
|
||||
{
|
||||
uint32_t lux_vot = 0;
|
||||
float lux_level = 0;
|
||||
|
||||
for (uint32_t i = 0; i < T1000X_SENSE_SAMPLES; i++) {
|
||||
lux_vot += analogRead(T1000X_LUX_PIN);
|
||||
}
|
||||
lux_vot = lux_vot / T1000X_SENSE_SAMPLES;
|
||||
lux_vot = ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * lux_vot;
|
||||
|
||||
if (lux_vot <= 80)
|
||||
lux_level = 0;
|
||||
else if (lux_vot >= 2480)
|
||||
lux_level = 100;
|
||||
else
|
||||
lux_level = 100 * (lux_vot - 80) / T1000X_LIGHT_REF_VCC;
|
||||
|
||||
return lux_level;
|
||||
}
|
||||
|
||||
float T1000xSensor::getTemp()
|
||||
{
|
||||
uint32_t vcc_vot = 0, ntc_vot = 0;
|
||||
|
||||
uint8_t u8i = 0;
|
||||
float Vout = 0, Rt = 0, temp = 0;
|
||||
float Temp = 0;
|
||||
|
||||
for (uint32_t i = 0; i < T1000X_SENSE_SAMPLES; i++) {
|
||||
vcc_vot += analogRead(T1000X_VCC_PIN);
|
||||
}
|
||||
vcc_vot = vcc_vot / T1000X_SENSE_SAMPLES;
|
||||
vcc_vot = 2 * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * vcc_vot;
|
||||
|
||||
for (uint32_t i = 0; i < T1000X_SENSE_SAMPLES; i++) {
|
||||
ntc_vot += analogRead(T1000X_NTC_PIN);
|
||||
}
|
||||
ntc_vot = ntc_vot / T1000X_SENSE_SAMPLES;
|
||||
ntc_vot = ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * ntc_vot;
|
||||
|
||||
Vout = ntc_vot;
|
||||
Rt = (HEATER_NTC_RP * vcc_vot) / Vout - HEATER_NTC_RP;
|
||||
for (u8i = 0; u8i < 136; u8i++) {
|
||||
if (Rt >= ntc_res2[u8i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
temp = ntc_temp2[u8i - 1] + 1 * (ntc_res2[u8i - 1] - Rt) / (float)(ntc_res2[u8i - 1] - ntc_res2[u8i]);
|
||||
Temp = (temp * 100 + 5) / 100; // half adjust
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
bool T1000xSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.temperature = getTemp();
|
||||
measurement->variant.environment_metrics.lux = getLux();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
22
src/modules/Telemetry/Sensor/T1000xSensor.h
Normal file
22
src/modules/Telemetry/Sensor/T1000xSensor.h
Normal file
@ -0,0 +1,22 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
|
||||
class T1000xSensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
T1000xSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual float getLux();
|
||||
virtual float getTemp();
|
||||
};
|
||||
|
||||
#endif
|
@ -188,12 +188,10 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
|
||||
mqtt = this;
|
||||
|
||||
if (*moduleConfig.mqtt.root) {
|
||||
statusTopic = moduleConfig.mqtt.root + statusTopic;
|
||||
cryptTopic = moduleConfig.mqtt.root + cryptTopic;
|
||||
jsonTopic = moduleConfig.mqtt.root + jsonTopic;
|
||||
mapTopic = moduleConfig.mqtt.root + mapTopic;
|
||||
} else {
|
||||
statusTopic = "msh" + statusTopic;
|
||||
cryptTopic = "msh" + cryptTopic;
|
||||
jsonTopic = "msh" + jsonTopic;
|
||||
mapTopic = "msh" + mapTopic;
|
||||
@ -216,7 +214,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
|
||||
enabled = true;
|
||||
runASAP = true;
|
||||
reconnectCount = 0;
|
||||
publishStatus();
|
||||
publishNodeInfo();
|
||||
}
|
||||
// preflightSleepObserver.observe(&preflightSleep);
|
||||
} else {
|
||||
@ -281,7 +279,7 @@ void MQTT::reconnect()
|
||||
runASAP = true;
|
||||
reconnectCount = 0;
|
||||
|
||||
publishStatus();
|
||||
publishNodeInfo();
|
||||
return; // Don't try to connect directly to the server
|
||||
}
|
||||
#if HAS_NETWORKING
|
||||
@ -330,15 +328,14 @@ void MQTT::reconnect()
|
||||
LOG_INFO("Attempting to connect directly to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr,
|
||||
serverPort, mqttUsername, mqttPassword);
|
||||
|
||||
auto myStatus = (statusTopic + owner.id);
|
||||
bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword, myStatus.c_str(), 1, true, "offline");
|
||||
bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword);
|
||||
if (connected) {
|
||||
LOG_INFO("MQTT connected\n");
|
||||
enabled = true; // Start running background process again
|
||||
runASAP = true;
|
||||
reconnectCount = 0;
|
||||
|
||||
publishStatus();
|
||||
publishNodeInfo();
|
||||
sendSubscriptions();
|
||||
} else {
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
@ -437,14 +434,10 @@ int32_t MQTT::runOnce()
|
||||
return 30000;
|
||||
}
|
||||
|
||||
/// FIXME, include more information in the status text
|
||||
void MQTT::publishStatus()
|
||||
void MQTT::publishNodeInfo()
|
||||
{
|
||||
auto myStatus = (statusTopic + owner.id);
|
||||
bool ok = publish(myStatus.c_str(), "online", true);
|
||||
LOG_INFO("published online=%d\n", ok);
|
||||
// TODO: NodeInfo broadcast over MQTT only (NODENUM_BROADCAST_NO_LORA)
|
||||
}
|
||||
|
||||
void MQTT::publishQueuedMessages()
|
||||
{
|
||||
if (!mqttQueue.isEmpty()) {
|
||||
@ -680,8 +673,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
|
||||
msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux);
|
||||
msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux);
|
||||
msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq);
|
||||
msgPayload["wind_speed"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_speed);
|
||||
msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed);
|
||||
msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
|
||||
msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust);
|
||||
msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull);
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
|
||||
msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
|
||||
msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
|
||||
|
@ -81,10 +81,9 @@ class MQTT : private concurrency::OSThread
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
std::string statusTopic = "/2/stat/"; // For "online"/"offline" message
|
||||
std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID
|
||||
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
|
||||
std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages
|
||||
std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID
|
||||
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
|
||||
std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages
|
||||
|
||||
// For map reporting (only applies when enabled)
|
||||
const uint32_t default_map_position_precision = 14; // defaults to max. offset of ~1459m
|
||||
@ -110,9 +109,10 @@ class MQTT : private concurrency::OSThread
|
||||
/// Called when a new publish arrives from the MQTT server
|
||||
std::string meshPacketToJson(meshtastic_MeshPacket *mp);
|
||||
|
||||
void publishStatus();
|
||||
void publishQueuedMessages();
|
||||
|
||||
void publishNodeInfo();
|
||||
|
||||
// Check if we should report unencrypted information about our node for consumption by a map
|
||||
void perhapsReportToMap();
|
||||
|
||||
|
144
src/platform/nrf52/BLEDfuScure.cpp
Normal file
144
src/platform/nrf52/BLEDfuScure.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file BLEDfu.cpp
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "BLEDfuSecure.h"
|
||||
#include "bluefruit.h"
|
||||
|
||||
#define DFU_REV_APPMODE 0x0001
|
||||
|
||||
const uint16_t UUID16_SVC_DFU_OTA = 0xFE59;
|
||||
|
||||
const uint8_t UUID128_CHR_DFU_CONTROL[16] = {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F,
|
||||
0x60, 0x4F, 0x15, 0xF3, 0x03, 0x00, 0xC9, 0x8E};
|
||||
|
||||
extern "C" void bootloader_util_app_start(uint32_t start_addr);
|
||||
|
||||
static uint16_t crc16(const uint8_t *data_p, uint8_t length)
|
||||
{
|
||||
uint8_t x;
|
||||
uint16_t crc = 0xFFFF;
|
||||
|
||||
while (length--) {
|
||||
x = crc >> 8 ^ *data_p++;
|
||||
x ^= x >> 4;
|
||||
crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x << 5)) ^ ((uint16_t)x);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_write_t *request)
|
||||
{
|
||||
if ((request->handle == chr->handles().value_handle) && (request->op != BLE_GATTS_OP_PREP_WRITE_REQ) &&
|
||||
(request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) && (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) {
|
||||
BLEConnection *conn = Bluefruit.Connection(conn_hdl);
|
||||
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE};
|
||||
|
||||
if (!chr->indicateEnabled(conn_hdl)) {
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
|
||||
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
|
||||
return;
|
||||
}
|
||||
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
|
||||
|
||||
enum { START_DFU = 1 };
|
||||
if (request->data[0] == START_DFU) {
|
||||
// Peer data information so that bootloader could re-connect after reboot
|
||||
typedef struct {
|
||||
ble_gap_addr_t addr;
|
||||
ble_gap_irk_t irk;
|
||||
ble_gap_enc_key_t enc_key;
|
||||
uint8_t sys_attr[8];
|
||||
uint16_t crc16;
|
||||
} peer_data_t;
|
||||
|
||||
VERIFY_STATIC(offsetof(peer_data_t, crc16) == 60);
|
||||
|
||||
/* Save Peer data
|
||||
* Peer data address is defined in bootloader linker @0x20007F80
|
||||
* - If bonded : save Security information
|
||||
* - Otherwise : save Address for direct advertising
|
||||
*
|
||||
* TODO may force bonded only for security reason
|
||||
*/
|
||||
peer_data_t *peer_data = (peer_data_t *)(0x20007F80UL);
|
||||
varclr(peer_data);
|
||||
|
||||
// Get CCCD
|
||||
uint16_t sysattr_len = sizeof(peer_data->sys_attr);
|
||||
sd_ble_gatts_sys_attr_get(conn_hdl, peer_data->sys_attr, &sysattr_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
|
||||
|
||||
// Get Bond Data or using Address if not bonded
|
||||
peer_data->addr = conn->getPeerAddr();
|
||||
|
||||
if (conn->secured()) {
|
||||
bond_keys_t bkeys;
|
||||
if (conn->loadBondKey(&bkeys)) {
|
||||
peer_data->addr = bkeys.peer_id.id_addr_info;
|
||||
peer_data->irk = bkeys.peer_id.id_info;
|
||||
peer_data->enc_key = bkeys.own_enc;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate crc
|
||||
peer_data->crc16 = crc16((uint8_t *)peer_data, offsetof(peer_data_t, crc16));
|
||||
|
||||
// Initiate DFU Sequence and reboot into DFU OTA mode
|
||||
Bluefruit.Advertising.restartOnDisconnect(false);
|
||||
conn->disconnect();
|
||||
|
||||
NRF_POWER->GPREGRET = 0xB1;
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLEDfuSecure::BLEDfuSecure(void) : BLEService(UUID16_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) {}
|
||||
|
||||
err_t BLEDfuSecure::begin(void)
|
||||
{
|
||||
// Invoke base class begin()
|
||||
VERIFY_STATUS(BLEService::begin());
|
||||
|
||||
_chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_INDICATE);
|
||||
_chr_control.setMaxLen(23);
|
||||
_chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb);
|
||||
VERIFY_STATUS(_chr_control.begin());
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
55
src/platform/nrf52/BLEDfuSecure.h
Normal file
55
src/platform/nrf52/BLEDfuSecure.h
Normal file
@ -0,0 +1,55 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file BLEDfu.h
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#ifndef BLEDFUSECURE_H_
|
||||
#define BLEDFUSECURE_H_
|
||||
|
||||
#include "bluefruit_common.h"
|
||||
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
|
||||
class BLEDfuSecure : public BLEService
|
||||
{
|
||||
protected:
|
||||
BLECharacteristic _chr_control;
|
||||
|
||||
public:
|
||||
BLEDfuSecure(void);
|
||||
|
||||
virtual err_t begin(void);
|
||||
};
|
||||
|
||||
#endif /* BLEDFUSECURE_H_ */
|
@ -1,4 +1,5 @@
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "BLEDfuSecure.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
@ -15,8 +16,12 @@ static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16))
|
||||
|
||||
static BLEDis bledis; // DIS (Device Information Service) helper class instance
|
||||
static BLEBas blebas; // BAS (Battery Service) helper class instance
|
||||
|
||||
#ifndef BLE_DFU_SECURE
|
||||
static BLEDfu bledfu; // DFU software update helper service
|
||||
#else
|
||||
static BLEDfuSecure bledfusecure; // DFU software update helper service
|
||||
#endif
|
||||
|
||||
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
||||
// process at once
|
||||
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
|
||||
@ -247,8 +252,13 @@ void NRF52Bluetooth::setup()
|
||||
// Set the connect/disconnect callback handlers
|
||||
Bluefruit.Periph.setConnectCallback(onConnect);
|
||||
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
|
||||
#ifndef BLE_DFU_SECURE
|
||||
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
bledfu.begin(); // Install the DFU helper
|
||||
#else
|
||||
bledfusecure.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // add by WayenWeng
|
||||
bledfusecure.begin(); // Install the DFU helper
|
||||
#endif
|
||||
// Configure and Start the Device Information Service
|
||||
LOG_INFO("Configuring the Device Information Service\n");
|
||||
bledis.setModel(optstr(HW_VERSION));
|
||||
|
@ -377,4 +377,4 @@ SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
*/
|
@ -3,8 +3,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint8_t LED_BUILTIN = 35;
|
||||
#define BUILTIN_LED LED_BUILTIN // backward compatibility
|
||||
static const uint8_t LED_BUILTIN = -1; // Board has no built-in LED, despite what schematic shows
|
||||
#define BUILTIN_LED LED_BUILTIN // backward compatibility
|
||||
#define LED_BUILTIN LED_BUILTIN
|
||||
|
||||
static const uint8_t TX = 43;
|
||||
@ -56,6 +56,6 @@ static const uint8_t T14 = 14;
|
||||
|
||||
static const uint8_t RST_LoRa = 12;
|
||||
static const uint8_t BUSY_LoRa = 13;
|
||||
static const uint8_t DIO0 = 14;
|
||||
static const uint8_t DIO1 = 14;
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
|
@ -1,14 +1,11 @@
|
||||
// #define LED_PIN 18
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
// Enable bus for external periherals
|
||||
// I2C
|
||||
#define I2C_SDA SDA
|
||||
#define I2C_SCL SCL
|
||||
|
||||
// Display (E-Ink)
|
||||
#define USE_EINK
|
||||
|
||||
/*
|
||||
* eink display pins
|
||||
*/
|
||||
#define PIN_EINK_CS 5
|
||||
#define PIN_EINK_BUSY 1
|
||||
#define PIN_EINK_DC 2
|
||||
@ -16,33 +13,30 @@
|
||||
#define PIN_EINK_SCLK 4
|
||||
#define PIN_EINK_MOSI 6
|
||||
|
||||
/*
|
||||
* SPI interfaces
|
||||
*/
|
||||
// SPI
|
||||
#define SPI_INTERFACES_COUNT 2
|
||||
#define PIN_SPI_MISO 10 // MISO
|
||||
#define PIN_SPI_MOSI 11 // MOSI
|
||||
#define PIN_SPI_SCK 9 // SCK
|
||||
|
||||
#define PIN_SPI_MISO 10 // MISO P0.17
|
||||
#define PIN_SPI_MOSI 11 // MOSI P0.15
|
||||
#define PIN_SPI_SCK 9 // SCK P0.13
|
||||
|
||||
#define VEXT_ENABLE 18 // powers the oled display and the lora antenna boost
|
||||
#define VEXT_ON_VALUE 1
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
// Power
|
||||
#define VEXT_ENABLE 18 // Powers the E-Ink display, and the 3.3V supply to the I2C QuickLink connector
|
||||
#define PERIPHERAL_WARMUP_MS 1000 // Make sure I2C QuickLink has stable power before continuing
|
||||
#define VEXT_ON_VALUE HIGH
|
||||
#define ADC_CTRL 46
|
||||
#define ADC_CTRL_ENABLED HIGH
|
||||
#define BATTERY_PIN 7
|
||||
#define ADC_CHANNEL ADC1_GPIO7_CHANNEL
|
||||
#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1
|
||||
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high
|
||||
#define ADC_MULTIPLIER 4.9 * 1.03
|
||||
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5
|
||||
|
||||
// LoRa
|
||||
#define USE_SX1262
|
||||
|
||||
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 12
|
||||
#define LORA_DIO1 14 // SX1262 IRQ
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
|
@ -5,8 +5,6 @@ board = wio-sdk-wm1110
|
||||
|
||||
# Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board)
|
||||
build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB
|
||||
|
||||
; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110
|
||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||
|
15
variants/wio-t1000-s/platformio.ini
Normal file
15
variants/wio-t1000-s/platformio.ini
Normal file
@ -0,0 +1,15 @@
|
||||
; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921
|
||||
[env:wio-t1000-s]
|
||||
extends = nrf52840_base
|
||||
board = wio-t1000-s
|
||||
board_level = extra
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-t1000-s -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110
|
||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-t1000-s>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
upload_protocol = jlink
|
64
variants/wio-t1000-s/variant.cpp
Normal file
64
variants/wio-t1000-s/variant.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "variant.h"
|
||||
#include "nrf.h"
|
||||
#include "wiring_constants.h"
|
||||
#include "wiring_digital.h"
|
||||
|
||||
const uint32_t g_ADigitalPinMap[] = {
|
||||
// P0
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
|
||||
// P1
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||
|
||||
void initVariant()
|
||||
{
|
||||
// LED1 & LED2
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
pinMode(PIN_3V3_EN, OUTPUT);
|
||||
digitalWrite(PIN_3V3_EN, HIGH);
|
||||
|
||||
pinMode(PIN_3V3_ACC_EN, OUTPUT);
|
||||
digitalWrite(PIN_3V3_ACC_EN, LOW);
|
||||
|
||||
pinMode(BUZZER_EN_PIN, OUTPUT);
|
||||
digitalWrite(BUZZER_EN_PIN, HIGH);
|
||||
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
|
||||
pinMode(GPS_VRTC_EN, OUTPUT);
|
||||
digitalWrite(GPS_VRTC_EN, HIGH);
|
||||
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RESET, LOW);
|
||||
|
||||
pinMode(GPS_SLEEP_INT, OUTPUT);
|
||||
digitalWrite(GPS_SLEEP_INT, HIGH);
|
||||
|
||||
pinMode(GPS_RTC_INT, OUTPUT);
|
||||
digitalWrite(GPS_RTC_INT, LOW);
|
||||
|
||||
pinMode(GPS_RESETB_OUT, INPUT);
|
||||
}
|
161
variants/wio-t1000-s/variant.h
Normal file
161
variants/wio-t1000-s/variant.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _VARIANT_WIO_SDK_WM1110_
|
||||
#define _VARIANT_WIO_SDK_WM1110_
|
||||
|
||||
/** Master clock frequency */
|
||||
#define VARIANT_MCK (64000000ul)
|
||||
|
||||
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||
// define USE_LFRC // Board uses RC for LF
|
||||
|
||||
#define BLE_DFU_SECURE // we use the 7.x softdevice signing keys
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// Number of pins defined in PinDescription array
|
||||
#define PINS_COUNT (48)
|
||||
#define NUM_DIGITAL_PINS (48)
|
||||
#define NUM_ANALOG_INPUTS (6)
|
||||
#define NUM_ANALOG_OUTPUTS (0)
|
||||
|
||||
#define PIN_3V3_EN (32 + 6) // P1.6, Power to Sensors
|
||||
#define PIN_3V3_ACC_EN (32 + 7) // P1.7, Power to Acc
|
||||
|
||||
#define PIN_LED1 (0 + 24) // P0.24
|
||||
#define LED_PIN PIN_LED1
|
||||
#define LED_BUILTIN -1
|
||||
#define LED_BLUE -1 // Actually green
|
||||
#define LED_STATE_ON 1 // State when LED is lit
|
||||
|
||||
#define BUTTON_PIN (0 + 6) // P0.6
|
||||
#define BUTTON_ACTIVE_LOW false
|
||||
#define BUTTON_ACTIVE_PULLUP false
|
||||
#define BUTTON_SENSE_TYPE INPUT_SENSE_HIGH
|
||||
|
||||
#define HAS_WIRE 0
|
||||
|
||||
#define WIRE_INTERFACES_COUNT 1
|
||||
|
||||
#define PIN_WIRE_SDA (0 + 26) // P0.26
|
||||
#define PIN_WIRE_SCL (0 + 27) // P0.27
|
||||
|
||||
/*
|
||||
* Serial interfaces
|
||||
*/
|
||||
#define PIN_SERIAL1_RX (0 + 14) // P0.14
|
||||
#define PIN_SERIAL1_TX (0 + 13) // P0.13
|
||||
|
||||
#define PIN_SERIAL2_RX (0 + 17) // P0.17
|
||||
#define PIN_SERIAL2_TX (0 + 16) // P0.16
|
||||
|
||||
#define USER_DEBUG_PORT Serial2
|
||||
|
||||
#define SPI_INTERFACES_COUNT 1
|
||||
|
||||
#define PIN_SPI_MISO (32 + 8) // P1.08
|
||||
#define PIN_SPI_MOSI (32 + 9) // P1.09
|
||||
#define PIN_SPI_SCK (0 + 11) // P0.11
|
||||
#define PIN_SPI_NSS (0 + 12) // P0.12
|
||||
|
||||
#define LORA_RESET (32 + 10) // P1.10 // RST
|
||||
#define LORA_DIO1 (32 + 1) // P1.01 // IRQ
|
||||
#define LORA_DIO2 (0 + 7) // P0.07 // BUSY
|
||||
#define LORA_SCK PIN_SPI_SCK
|
||||
#define LORA_MISO PIN_SPI_MISO
|
||||
#define LORA_MOSI PIN_SPI_MOSI
|
||||
#define LORA_CS PIN_SPI_NSS
|
||||
|
||||
// supported modules list
|
||||
#define USE_LR1110
|
||||
|
||||
#define LR1110_IRQ_PIN LORA_DIO1
|
||||
#define LR1110_NRESER_PIN LORA_RESET
|
||||
#define LR1110_BUSY_PIN LORA_DIO2
|
||||
#define LR1110_SPI_NSS_PIN LORA_CS
|
||||
#define LR1110_SPI_SCK_PIN LORA_SCK
|
||||
#define LR1110_SPI_MOSI_PIN LORA_MOSI
|
||||
#define LR1110_SPI_MISO_PIN LORA_MISO
|
||||
|
||||
#define LR11X0_DIO3_TCXO_VOLTAGE 1.6
|
||||
#define LR11X0_DIO_AS_RF_SWITCH
|
||||
#define LR11X0_DIO_RF_SWITCH_CONFIG 0x0f, 0x0, 0x09, 0x0B, 0x0A, 0x0, 0x4, 0x0
|
||||
|
||||
#define HAS_GPS 1
|
||||
#define GNSS_Airoha
|
||||
#define GPS_RX_PIN PIN_SERIAL1_RX
|
||||
#define GPS_TX_PIN PIN_SERIAL1_TX
|
||||
|
||||
#define GPS_BAUDRATE 115200
|
||||
|
||||
#define PIN_GPS_EN (32 + 11) // P1.11
|
||||
#define GPS_EN_ACTIVE HIGH
|
||||
|
||||
#define PIN_GPS_RESET (32 + 15) // P1.15
|
||||
#define GPS_RESET_MODE HIGH
|
||||
|
||||
#define GPS_VRTC_EN (0 + 8) // P0.8, awlays high
|
||||
#define GPS_SLEEP_INT (32 + 12) // P1.12, awlays high
|
||||
#define GPS_RTC_INT (0 + 15) // P0.15, normal is LOW, wake by HIGH
|
||||
#define GPS_RESETB_OUT (32 + 14) // P1.14, awlays input pull_up
|
||||
|
||||
// #define GPS_THREAD_INTERVAL 50
|
||||
#define GPS_FIX_HOLD_TIME 15000 // ms
|
||||
|
||||
#define BATTERY_PIN 2
|
||||
// #define ADC_CHANNEL ADC1_GPIO2_CHANNEL
|
||||
#define ADC_MULTIPLIER (2.0F)
|
||||
|
||||
#define ADC_RESOLUTION 14
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||
// #define BATTERY_SENSE_RESOLUTION 4096.0
|
||||
|
||||
#undef AREF_VOLTAGE
|
||||
#define AREF_VOLTAGE 3.0
|
||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||
|
||||
// #define ADC_CTRL (32 + 6)
|
||||
// #define ADC_CTRL_ENABLED HIGH
|
||||
|
||||
// Buzzer
|
||||
#define BUZZER_EN_PIN (32 + 5) // P1.05, awlays high
|
||||
#define PIN_BUZZER (0 + 25) // P0.25, pwm output
|
||||
|
||||
#define T1000X_SENSOR_EN
|
||||
#define T1000X_VCC_PIN (0 + 4) // P0.4
|
||||
#define T1000X_NTC_PIN (0 + 31) // P0.31
|
||||
#define T1000X_LUX_PIN (0 + 29) // P0.29
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif // _VARIANT_WIO_SDK_WM1110_
|
@ -2,7 +2,6 @@
|
||||
[env:wio-tracker-wm1110]
|
||||
extends = nrf52840_base
|
||||
board = wio-tracker-wm1110
|
||||
; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110
|
||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||
|
Loading…
Reference in New Issue
Block a user