Java SE Embedded on ARM: Complete Development Guide

Introduction

Java SE Embedded is a specialized Java runtime optimized for ARM-based embedded devices with constrained resources. This comprehensive guide covers development, deployment, and optimization for ARM embedded systems.

Project Setup and Configuration

Maven Dependencies for Cross-Compilation

<!-- pom.xml -->
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<pi4j.version>2.3.0</pi4j.version>
<logback.version>1.4.11</logback.version>
</properties>
<dependencies>
<!-- Pi4J for GPIO access (Raspberry Pi) -->
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-core</artifactId>
<version>${pi4j.version}</version>
</dependency>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-plugin-raspberrypi</artifactId>
<version>${pi4j.version}</version>
</dependency>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-plugin-pigpio</artifactId>
<version>${pi4j.version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- HTTP Client -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
<!-- Embedded Database -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.42.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
<compilerArgs>
<arg>-Xlint:unchecked</arg>
<arg>-Xlint:deprecation</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.embedded.MainApplication</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Core Embedded Framework

System Monitor and Resource Management

package com.embedded.core;
import java.lang.management.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SystemMonitor {
private final ScheduledExecutorService scheduler;
private final AtomicBoolean isMonitoring;
private final Runtime runtime;
private final OperatingSystemMXBean osBean;
private final MemoryMXBean memoryBean;
// Resource thresholds (adjust based on your device)
private static final double MEMORY_THRESHOLD = 0.85; // 85%
private static final double CPU_THRESHOLD = 0.80;    // 80%
private static final long DISK_THRESHOLD = 50 * 1024 * 1024; // 50MB
public SystemMonitor() {
this.scheduler = Executors.newScheduledThreadPool(1);
this.isMonitoring = new AtomicBoolean(false);
this.runtime = Runtime.getRuntime();
this.osBean = ManagementFactory.getOperatingSystemMXBean();
this.memoryBean = ManagementFactory.getMemoryMXBean();
}
public void startMonitoring() {
if (isMonitoring.compareAndSet(false, true)) {
scheduler.scheduleAtFixedRate(this::monitorSystem, 0, 5, TimeUnit.SECONDS);
SystemLogger.info("System monitoring started");
}
}
public void stopMonitoring() {
if (isMonitoring.compareAndSet(true, false)) {
scheduler.shutdown();
SystemLogger.info("System monitoring stopped");
}
}
private void monitorSystem() {
try {
SystemMetrics metrics = collectMetrics();
checkThresholds(metrics);
logMetrics(metrics);
} catch (Exception e) {
SystemLogger.error("Error monitoring system: " + e.getMessage());
}
}
private SystemMetrics collectMetrics() {
SystemMetrics metrics = new SystemMetrics();
// Memory metrics
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
long maxMemory = runtime.maxMemory();
metrics.setMemoryUsed(usedMemory);
metrics.setMemoryTotal(totalMemory);
metrics.setMemoryMax(maxMemory);
metrics.setMemoryUsage((double) usedMemory / totalMemory);
// CPU metrics (approximation)
if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
com.sun.management.OperatingSystemMXBean sunOsBean = 
(com.sun.management.OperatingSystemMXBean) osBean;
metrics.setCpuLoad(sunOsBean.getSystemCpuLoad());
metrics.setProcessCpuLoad(sunOsBean.getProcessCpuLoad());
}
// Thread metrics
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
metrics.setThreadCount(threadBean.getThreadCount());
metrics.setDaemonThreadCount(threadBean.getDaemonThreadCount());
// GC metrics
for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
metrics.addGcCollectionCount(gc.getCollectionCount());
metrics.addGcCollectionTime(gc.getCollectionTime());
}
return metrics;
}
private void checkThresholds(SystemMetrics metrics) {
// Memory threshold check
if (metrics.getMemoryUsage() > MEMORY_THRESHOLD) {
SystemLogger.warn("High memory usage: " + 
String.format("%.2f%%", metrics.getMemoryUsage() * 100));
triggerMemoryCleanup();
}
// CPU threshold check
if (metrics.getCpuLoad() > CPU_THRESHOLD) {
SystemLogger.warn("High CPU usage: " + 
String.format("%.2f%%", metrics.getCpuLoad() * 100));
}
// Thread count monitoring
if (metrics.getThreadCount() > 100) {
SystemLogger.warn("High thread count: " + metrics.getThreadCount());
}
}
private void triggerMemoryCleanup() {
SystemLogger.info("Initiating memory cleanup");
System.gc(); // Suggest garbage collection
// Additional cleanup actions
MemoryManager.getInstance().cleanupCaches();
}
private void logMetrics(SystemMetrics metrics) {
if (SystemLogger.isDebugEnabled()) {
SystemLogger.debug(String.format(
"Memory: %d/%d MB (%.1f%%) | Threads: %d | CPU: %.1f%%",
metrics.getMemoryUsed() / (1024 * 1024),
metrics.getMemoryTotal() / (1024 * 1024),
metrics.getMemoryUsage() * 100,
metrics.getThreadCount(),
metrics.getCpuLoad() * 100
));
}
}
public static class SystemMetrics {
private long memoryUsed;
private long memoryTotal;
private long memoryMax;
private double memoryUsage;
private double cpuLoad;
private double processCpuLoad;
private int threadCount;
private int daemonThreadCount;
private long gcCollectionCount;
private long gcCollectionTime;
// Getters and setters
public long getMemoryUsed() { return memoryUsed; }
public void setMemoryUsed(long memoryUsed) { this.memoryUsed = memoryUsed; }
public long getMemoryTotal() { return memoryTotal; }
public void setMemoryTotal(long memoryTotal) { this.memoryTotal = memoryTotal; }
public long getMemoryMax() { return memoryMax; }
public void setMemoryMax(long memoryMax) { this.memoryMax = memoryMax; }
public double getMemoryUsage() { return memoryUsage; }
public void setMemoryUsage(double memoryUsage) { this.memoryUsage = memoryUsage; }
public double getCpuLoad() { return cpuLoad; }
public void setCpuLoad(double cpuLoad) { this.cpuLoad = cpuLoad; }
public double getProcessCpuLoad() { return processCpuLoad; }
public void setProcessCpuLoad(double processCpuLoad) { this.processCpuLoad = processCpuLoad; }
public int getThreadCount() { return threadCount; }
public void setThreadCount(int threadCount) { this.threadCount = threadCount; }
public int getDaemonThreadCount() { return daemonThreadCount; }
public void setDaemonThreadCount(int daemonThreadCount) { this.daemonThreadCount = daemonThreadCount; }
public long getGcCollectionCount() { return gcCollectionCount; }
public void addGcCollectionCount(long count) { this.gcCollectionCount += count; }
public long getGcCollectionTime() { return gcCollectionTime; }
public void addGcCollectionTime(long time) { this.gcCollectionTime += time; }
}
}

GPIO Management for Raspberry Pi

package com.embedded.gpio;
import com.pi4j.Pi4J;
import com.pi4j.context.Context;
import com.pi4j.io.gpio.digital.*;
import com.pi4j.io.i2c.I2C;
import com.pi4j.io.i2c.I2CConfig;
import com.pi4j.io.i2c.I2CProvider;
import com.pi4j.io.spi.Spi;
import com.pi4j.io.spi.SpiConfig;
import com.pi4j.io.spi.SpiProvider;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class GPIOManager {
private final Context pi4j;
private final Map<String, DigitalOutput> outputPins;
private final Map<String, DigitalInput> inputPins;
private final ScheduledExecutorService scheduler;
private final SystemLogger logger;
// Common pin configurations
private static final DigitalState LED_ON = DigitalState.HIGH;
private static final DigitalState LED_OFF = DigitalState.LOW;
public GPIOManager() {
this.pi4j = Pi4J.newAutoContext();
this.outputPins = new ConcurrentHashMap<>();
this.inputPins = new ConcurrentHashMap<>();
this.scheduler = Executors.newScheduledThreadPool(2);
this.logger = SystemLogger.getInstance();
initializeDefaultPins();
}
private void initializeDefaultPins() {
// Initialize common pins for embedded projects
setupOutputPin("LED_STATUS", 17);    // Status LED
setupOutputPin("RELAY_1", 18);       // Relay control
setupInputPin("BUTTON_1", 27);       // Button input
setupInputPin("SENSOR_1", 22);       // Sensor input
logger.info("GPIO Manager initialized with default pins");
}
public void setupOutputPin(String name, int address) {
try {
DigitalOutputConfig config = DigitalOutput.newConfigBuilder(pi4j)
.id(name)
.name(name)
.address(address)
.provider("pigpio-digital-output")
.initial(DigitalState.LOW)
.shutdown(DigitalState.LOW)
.build();
DigitalOutput output = pi4j.create(config);
outputPins.put(name, output);
logger.info("Output pin configured: " + name + " on GPIO " + address);
} catch (Exception e) {
logger.error("Failed to setup output pin " + name + ": " + e.getMessage());
}
}
public void setupInputPin(String name, int address) {
try {
DigitalInputConfig config = DigitalInput.newConfigBuilder(pi4j)
.id(name)
.name(name)
.address(address)
.provider("pigpio-digital-input")
.pull(PullResistance.PULL_UP)
.debounce(3000L) // 3ms debounce
.build();
DigitalInput input = pi4j.create(config);
inputPins.put(name, input);
// Add listener for input changes
input.addListener(event -> {
handleInputChange(name, event.state());
});
logger.info("Input pin configured: " + name + " on GPIO " + address);
} catch (Exception e) {
logger.error("Failed to setup input pin " + name + ": " + e.getMessage());
}
}
private void handleInputChange(String pinName, DigitalState state) {
logger.debug("Input " + pinName + " changed to: " + state);
// Handle specific input events
switch (pinName) {
case "BUTTON_1":
handleButtonPress(state);
break;
case "SENSOR_1":
handleSensorTrigger(state);
break;
}
}
private void handleButtonPress(DigitalState state) {
if (state == DigitalState.LOW) { // Assuming pull-up resistor
logger.info("Button pressed");
// Toggle status LED on button press
togglePin("LED_STATUS");
}
}
private void handleSensorTrigger(DigitalState state) {
if (state == DigitalState.HIGH) {
logger.info("Sensor triggered");
// Add sensor-specific logic here
}
}
public void setPinState(String pinName, DigitalState state) {
DigitalOutput output = outputPins.get(pinName);
if (output != null) {
output.state(state);
logger.debug("Set " + pinName + " to: " + state);
} else {
logger.warn("Output pin not found: " + pinName);
}
}
public void togglePin(String pinName) {
DigitalOutput output = outputPins.get(pinName);
if (output != null) {
DigitalState current = output.state();
DigitalState newState = (current == DigitalState.HIGH) ? 
DigitalState.LOW : DigitalState.HIGH;
output.state(newState);
logger.debug("Toggled " + pinName + " to: " + newState);
}
}
public DigitalState getInputState(String pinName) {
DigitalInput input = inputPins.get(pinName);
return (input != null) ? input.state() : DigitalState.UNKNOWN;
}
public void blinkPin(String pinName, long durationMs, int count) {
scheduler.submit(() -> {
try {
for (int i = 0; i < count; i++) {
setPinState(pinName, LED_ON);
Thread.sleep(durationMs);
setPinState(pinName, LED_OFF);
if (i < count - 1) {
Thread.sleep(durationMs);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Blink operation interrupted for pin: " + pinName);
}
});
}
public void setupPWMPin(String pinName, int address) {
try {
// Pi4J v2.0+ PWM support
// Note: Actual implementation depends on Pi4J version and platform
logger.info("PWM pin configured: " + pinName + " on GPIO " + address);
} catch (Exception e) {
logger.error("Failed to setup PWM pin " + pinName + ": " + e.getMessage());
}
}
public I2C setupI2CDevice(int bus, int deviceAddress) {
try {
I2CProvider i2CProvider = pi4j.provider("pigpio-i2c");
I2CConfig i2cConfig = I2C.newConfigBuilder(pi4j)
.id("I2C-" + deviceAddress)
.bus(bus)
.device(deviceAddress)
.build();
return i2CProvider.create(i2cConfig);
} catch (Exception e) {
logger.error("Failed to setup I2C device: " + e.getMessage());
return null;
}
}
public void shutdown() {
// Turn off all outputs
for (DigitalOutput output : outputPins.values()) {
output.state(DigitalState.LOW);
}
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
pi4j.shutdown();
logger.info("GPIO Manager shutdown completed");
}
}

Embedded Sensor Framework

Sensor Manager

package com.embedded.sensors;
import com.embedded.core.SystemLogger;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SensorManager {
private final Map<String, Sensor> sensors;
private final ScheduledExecutorService scheduler;
private final ObjectMapper objectMapper;
private final SystemLogger logger;
private final String configFile;
private volatile boolean isRunning = false;
public SensorManager(String configFile) {
this.sensors = new ConcurrentHashMap<>();
this.scheduler = Executors.newScheduledThreadPool(3);
this.objectMapper = new ObjectMapper();
this.logger = SystemLogger.getInstance();
this.configFile = configFile;
loadSensorConfig();
}
private void loadSensorConfig() {
try {
File config = new File(configFile);
if (config.exists()) {
List<SensorConfig> configs = objectMapper.readValue(
config, new TypeReference<List<SensorConfig>>() {});
for (SensorConfig sensorConfig : configs) {
registerSensor(createSensorFromConfig(sensorConfig));
}
logger.info("Loaded " + sensors.size() + " sensors from config");
} else {
logger.warn("Sensor config file not found: " + configFile);
setupDefaultSensors();
}
} catch (IOException e) {
logger.error("Failed to load sensor config: " + e.getMessage());
setupDefaultSensors();
}
}
private void setupDefaultSensors() {
// Register default sensors for common embedded scenarios
registerSensor(new TemperatureSensor("TEMP_1", 1000));
registerSensor(new HumiditySensor("HUMIDITY_1", 2000));
registerSensor(new MotionSensor("MOTION_1", 500));
logger.info("Default sensors configured");
}
private Sensor createSensorFromConfig(SensorConfig config) {
switch (config.getType()) {
case "temperature":
return new TemperatureSensor(config.getId(), config.getInterval());
case "humidity":
return new HumiditySensor(config.getId(), config.getInterval());
case "motion":
return new MotionSensor(config.getId(), config.getInterval());
case "light":
return new LightSensor(config.getId(), config.getInterval());
default:
logger.warn("Unknown sensor type: " + config.getType());
return new DummySensor(config.getId(), config.getInterval());
}
}
public void registerSensor(Sensor sensor) {
sensors.put(sensor.getId(), sensor);
logger.info("Registered sensor: " + sensor.getId());
}
public void unregisterSensor(String sensorId) {
Sensor sensor = sensors.remove(sensorId);
if (sensor != null) {
sensor.stop();
logger.info("Unregistered sensor: " + sensorId);
}
}
public void startMonitoring() {
if (isRunning) return;
isRunning = true;
for (Sensor sensor : sensors.values()) {
startSensorMonitoring(sensor);
}
logger.info("Sensor monitoring started");
}
public void stopMonitoring() {
if (!isRunning) return;
isRunning = false;
for (Sensor sensor : sensors.values()) {
sensor.stop();
}
scheduler.shutdown();
logger.info("Sensor monitoring stopped");
}
private void startSensorMonitoring(Sensor sensor) {
scheduler.scheduleAtFixedRate(() -> {
try {
SensorReading reading = sensor.read();
if (reading != null) {
processSensorReading(reading);
}
} catch (Exception e) {
logger.error("Error reading sensor " + sensor.getId() + ": " + e.getMessage());
}
}, 0, sensor.getInterval(), TimeUnit.MILLISECONDS);
}
private void processSensorReading(SensorReading reading) {
// Log the reading
logger.debug(String.format("Sensor %s: %.2f %s", 
reading.getSensorId(), reading.getValue(), reading.getUnit()));
// Check thresholds and trigger alerts
checkThresholds(reading);
// Store reading in database
SensorDataStore.getInstance().storeReading(reading);
// Notify listeners
SensorEvent event = new SensorEvent(reading);
SensorEventBus.getInstance().publish(event);
}
private void checkThresholds(SensorReading reading) {
Sensor sensor = sensors.get(reading.getSensorId());
if (sensor != null && sensor.hasThresholds()) {
SensorThresholds thresholds = sensor.getThresholds();
if (reading.getValue() > thresholds.getMaxValue()) {
triggerAlert(reading, "MAX_THRESHOLD_EXCEEDED");
} else if (reading.getValue() < thresholds.getMinValue()) {
triggerAlert(reading, "MIN_THRESHOLD_EXCEEDED");
}
}
}
private void triggerAlert(SensorReading reading, String alertType) {
SensorAlert alert = new SensorAlert(
reading.getSensorId(),
alertType,
reading.getValue(),
System.currentTimeMillis(),
"Threshold violation detected"
);
logger.warn("Sensor alert: " + alert);
// Send alert via available channels
AlertManager.getInstance().sendAlert(alert);
}
public SensorReading getLatestReading(String sensorId) {
Sensor sensor = sensors.get(sensorId);
return (sensor != null) ? sensor.getLastReading() : null;
}
public Map<String, SensorReading> getAllLatestReadings() {
Map<String, SensorReading> readings = new HashMap<>();
for (Sensor sensor : sensors.values()) {
readings.put(sensor.getId(), sensor.getLastReading());
}
return readings;
}
public void calibrateSensor(String sensorId) {
Sensor sensor = sensors.get(sensorId);
if (sensor != null && sensor instanceof Calibratable) {
((Calibratable) sensor).calibrate();
logger.info("Calibrated sensor: " + sensorId);
} else {
logger.warn("Sensor does not support calibration: " + sensorId);
}
}
}
// Sensor base classes and interfaces
abstract class Sensor {
protected final String id;
protected final long interval;
protected volatile SensorReading lastReading;
protected volatile boolean running = false;
public Sensor(String id, long interval) {
this.id = id;
this.interval = interval;
}
public abstract SensorReading read();
public abstract String getUnit();
public abstract SensorType getType();
public void stop() {
running = false;
}
// Getters
public String getId() { return id; }
public long getInterval() { return interval; }
public SensorReading getLastReading() { return lastReading; }
public boolean hasThresholds() { return false; }
public SensorThresholds getThresholds() { return null; }
}
class SensorReading {
private final String sensorId;
private final double value;
private final String unit;
private final long timestamp;
private final Map<String, Object> metadata;
public SensorReading(String sensorId, double value, String unit) {
this.sensorId = sensorId;
this.value = value;
this.unit = unit;
this.timestamp = System.currentTimeMillis();
this.metadata = new HashMap<>();
}
// Getters and setters
public String getSensorId() { return sensorId; }
public double getValue() { return value; }
public String getUnit() { return unit; }
public long getTimestamp() { return timestamp; }
public Map<String, Object> getMetadata() { return metadata; }
public void addMetadata(String key, Object value) { metadata.put(key, value); }
}
interface Calibratable {
void calibrate();
}
enum SensorType {
TEMPERATURE,
HUMIDITY,
PRESSURE,
MOTION,
LIGHT,
PROXIMITY,
OTHER
}
// Example sensor implementations
class TemperatureSensor extends Sensor {
private static final Random random = new Random();
public TemperatureSensor(String id, long interval) {
super(id, interval);
}
@Override
public SensorReading read() {
// Simulate temperature reading (replace with actual sensor code)
double temperature = 20.0 + (random.nextDouble() * 10.0); // 20-30°C
SensorReading reading = new SensorReading(id, temperature, "°C");
lastReading = reading;
return reading;
}
@Override
public String getUnit() {
return "°C";
}
@Override
public SensorType getType() {
return SensorType.TEMPERATURE;
}
}
class HumiditySensor extends Sensor {
private static final Random random = new Random();
public HumiditySensor(String id, long interval) {
super(id, interval);
}
@Override
public SensorReading read() {
// Simulate humidity reading
double humidity = 40.0 + (random.nextDouble() * 30.0); // 40-70%
SensorReading reading = new SensorReading(id, humidity, "%");
lastReading = reading;
return reading;
}
@Override
public String getUnit() {
return "%";
}
@Override
public SensorType getType() {
return SensorType.HUMIDITY;
}
}
class MotionSensor extends Sensor {
private static final Random random = new Random();
private int motionCount = 0;
public MotionSensor(String id, long interval) {
super(id, interval);
}
@Override
public SensorReading read() {
// Simulate motion detection (10% chance)
boolean motionDetected = random.nextDouble() < 0.1;
if (motionDetected) {
motionCount++;
}
SensorReading reading = new SensorReading(id, motionDetected ? 1 : 0, "bool");
reading.addMetadata("motionCount", motionCount);
lastReading = reading;
return reading;
}
@Override
public String getUnit() {
return "bool";
}
@Override
public SensorType getType() {
return SensorType.MOTION;
}
}
// Configuration classes
class SensorConfig {
private String id;
private String type;
private long interval;
private Map<String, Object> parameters;
// Getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public long getInterval() { return interval; }
public void setInterval(long interval) { this.interval = interval; }
public Map<String, Object> getParameters() { return parameters; }
public void setParameters(Map<String, Object> parameters) { this.parameters = parameters; }
}
class SensorThresholds {
private double minValue;
private double maxValue;
private String unit;
// Getters and setters
public double getMinValue() { return minValue; }
public void setMinValue(double minValue) { this.minValue = minValue; }
public double getMaxValue() { return maxValue; }
public void setMaxValue(double maxValue) { this.maxValue = maxValue; }
public String getUnit() { return unit; }
public void setUnit(String unit) { this.unit = unit; }
}

Power Management

package com.embedded.power;
import com.embedded.core.SystemLogger;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class PowerManager {
private final ScheduledExecutorService scheduler;
private final AtomicBoolean isMonitoring;
private final SystemLogger logger;
// Power states
private volatile PowerState currentState = PowerState.NORMAL;
private volatile double batteryLevel = 100.0;
private volatile boolean isCharging = false;
// Power thresholds
private static final double LOW_BATTERY_THRESHOLD = 20.0;
private static final double CRITICAL_BATTERY_THRESHOLD = 10.0;
public PowerManager() {
this.scheduler = Executors.newScheduledThreadPool(1);
this.isMonitoring = new AtomicBoolean(false);
this.logger = SystemLogger.getInstance();
}
public void startPowerMonitoring() {
if (isMonitoring.compareAndSet(false, true)) {
scheduler.scheduleAtFixedRate(this::monitorPower, 0, 30, TimeUnit.SECONDS);
logger.info("Power monitoring started");
}
}
public void stopPowerMonitoring() {
if (isMonitoring.compareAndSet(true, false)) {
scheduler.shutdown();
logger.info("Power monitoring stopped");
}
}
private void monitorPower() {
try {
updateBatteryInfo();
checkPowerState();
logPowerStatus();
} catch (Exception e) {
logger.error("Error monitoring power: " + e.getMessage());
}
}
private void updateBatteryInfo() {
// Read battery information from system
// This is platform-specific - here's an example for Linux
try {
// Read from /sys/class/power_supply (Linux)
batteryLevel = readBatteryLevel();
isCharging = readChargingStatus();
} catch (Exception e) {
// Fallback to simulated values for development
batteryLevel = Math.max(0, batteryLevel - 0.1);
isCharging = batteryLevel < 95.0;
}
}
private double readBatteryLevel() throws IOException {
// Linux battery level reading example
try (BufferedReader reader = new BufferedReader(
new FileReader("/sys/class/power_supply/BAT0/capacity"))) {
return Double.parseDouble(reader.readLine().trim());
} catch (Exception e) {
throw new IOException("Cannot read battery level", e);
}
}
private boolean readChargingStatus() throws IOException {
// Linux charging status reading example
try (BufferedReader reader = new BufferedReader(
new FileReader("/sys/class/power_supply/BAT0/status"))) {
String status = reader.readLine().trim();
return "Charging".equalsIgnoreCase(status);
} catch (Exception e) {
throw new IOException("Cannot read charging status", e);
}
}
private void checkPowerState() {
PowerState newState = determinePowerState();
if (newState != currentState) {
PowerState oldState = currentState;
currentState = newState;
handlePowerStateTransition(oldState, newState);
}
}
private PowerState determinePowerState() {
if (batteryLevel <= CRITICAL_BATTERY_THRESHOLD) {
return PowerState.CRITICAL;
} else if (batteryLevel <= LOW_BATTERY_THRESHOLD) {
return PowerState.LOW;
} else if (isCharging) {
return PowerState.CHARGING;
} else {
return PowerState.NORMAL;
}
}
private void handlePowerStateTransition(PowerState oldState, PowerState newState) {
logger.info(String.format("Power state changed: %s -> %s (Battery: %.1f%%)", 
oldState, newState, batteryLevel));
switch (newState) {
case LOW:
enablePowerSavingMode();
break;
case CRITICAL:
enableCriticalPowerMode();
break;
case CHARGING:
disablePowerSavingMode();
break;
}
}
private void enablePowerSavingMode() {
logger.warn("Enabling power saving mode");
// Reduce CPU frequency
executeCommand("sudo cpufreq-set -g powersave");
// Reduce screen brightness
executeCommand("echo 50 | sudo tee /sys/class/backlight/*/brightness");
// Disable non-essential services
ServiceManager.getInstance().stopNonEssentialServices();
}
private void enableCriticalPowerMode() {
logger.error("Enabling critical power mode - preparing for shutdown");
// Further reduce power consumption
executeCommand("sudo cpufreq-set -g powersave");
executeCommand("echo 10 | sudo tee /sys/class/backlight/*/brightness");
// Stop all non-critical services
ServiceManager.getInstance().stopAllButCriticalServices();
// Schedule shutdown if not charging
if (!isCharging) {
scheduler.schedule(this::initiateShutdown, 2, TimeUnit.MINUTES);
}
}
private void disablePowerSavingMode() {
logger.info("Disabling power saving mode");
// Restore normal CPU frequency
executeCommand("sudo cpufreq-set -g ondemand");
// Restore screen brightness
executeCommand("echo 100 | sudo tee /sys/class/backlight/*/brightness");
// Restart services
ServiceManager.getInstance().restartStoppedServices();
}
private void initiateShutdown() {
if (!isCharging && batteryLevel <= 5.0) {
logger.error("Initiating emergency shutdown - battery critically low");
executeCommand("sudo shutdown -h now");
}
}
private void executeCommand(String command) {
try {
Runtime.getRuntime().exec(command);
} catch (IOException e) {
logger.error("Failed to execute command: " + command + " - " + e.getMessage());
}
}
private void logPowerStatus() {
if (logger.isDebugEnabled()) {
logger.debug(String.format(
"Battery: %.1f%% | Charging: %s | State: %s",
batteryLevel, isCharging, currentState
));
}
}
public double getBatteryLevel() {
return batteryLevel;
}
public boolean isCharging() {
return isCharging;
}
public PowerState getPowerState() {
return currentState;
}
public enum PowerState {
NORMAL,
LOW,
CRITICAL,
CHARGING
}
}

Main Application

```java
package com.embedded

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper