Skip to content

Commit eb7d8a1

Browse files
Merge pull request #392 from oss-slu/380-refactor-adcconverterhelper
first submission of complete test, helper and controller
2 parents e170adf + 348a086 commit eb7d8a1

6 files changed

Lines changed: 216 additions & 113 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.opensourcewithslu.components.controllers;
2+
3+
import com.pi4j.io.spi.Spi;
4+
import com.opensourcewithslu.inputdevices.ADC0834ConverterHelper;
5+
import io.micronaut.http.annotation.Controller;
6+
import io.micronaut.http.annotation.Get;
7+
import jakarta.inject.Named;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
/**
12+
* ADC0834ConverterController provides an endpoint to read values from the ADC0834.
13+
*/
14+
@Controller("/adc0834")
15+
public class ADC0834ConverterController {
16+
private static final Logger log = LoggerFactory.getLogger(ADC0834ConverterController.class);
17+
private final ADC0834ConverterHelper adcConverterHelper;
18+
19+
/**
20+
* Constructor for ADC0834ConverterController.
21+
*
22+
* @param spi SPI interface
23+
*/
24+
public ADC0834ConverterController(@Named("adc0834") Spi spi) {
25+
this.adcConverterHelper = new ADC0834ConverterHelper(spi);
26+
log.info("ADC0834ConverterController initialized with SPI");
27+
}
28+
29+
/**
30+
* Endpoint to get the digital value from the specified ADC0834 channel.
31+
*
32+
* @param channel The ADC channel to read (0-3).
33+
* @return The digital value read from the ADC0834.
34+
*/
35+
@Get("/read/{channel}")
36+
public int readValue(int channel) {
37+
int value = adcConverterHelper.readValue(channel);
38+
log.info("Value retrieved from ADC0834: {}", value);
39+
return value;
40+
}
41+
42+
/**
43+
* Endpoint to get the voltage from the specified ADC0834 channel.
44+
*
45+
* @param channel The ADC channel to read (0-3).
46+
* @param referenceVoltage The reference voltage for the ADC.
47+
* @return The voltage value read from the ADC0834.
48+
*/
49+
@Get("/voltage/{channel}/{referenceVoltage}")
50+
public double readVoltage(int channel, double referenceVoltage) {
51+
double voltage = adcConverterHelper.readVoltage(channel, referenceVoltage);
52+
log.info("Voltage retrieved from ADC0834 channel {}: {}V", channel, voltage);
53+
return voltage;
54+
}
55+
}

components/src/main/java/com/opensourcewithslu/components/controllers/ADCConverterController.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

components/src/main/resources/application.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ pi4j:
1010
address: 8 # <3>
1111
baud: 500000 # <4>
1212
reset-pin: 25 # <5>
13-
thermistor-adc: # Configuration for Thermistor ADC
14-
name: Thermistor ADC # <1>
13+
adc0834: # Configuration for ADC0834
14+
name: ADC0834 # <1>
1515
address: 17 # <2> # SPI channel 0
1616
baud: 1000000 # <3> # 1 MHz SPI clock speed
1717
mode: SPI_MODE_0
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.opensourcewithslu.inputdevices;
2+
3+
import com.pi4j.io.spi.Spi;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
/**
8+
* The ADC0834ConverterHelper class interfaces with the ADC0834 analog-to-digital converter using SPI.
9+
* It provides methods to read digital values and voltages from the specified channel.
10+
*/
11+
public class ADC0834ConverterHelper {
12+
private static final Logger log = LoggerFactory.getLogger(ADC0834ConverterHelper.class);
13+
private final Spi spi;
14+
15+
/**
16+
* Constructor for ADC0834ConverterHelper.
17+
* @param spi The SPI interface.
18+
*/
19+
public ADC0834ConverterHelper(Spi spi) {
20+
this.spi = spi;
21+
log.info("ADC0834ConverterHelper initialized with SPI");
22+
}
23+
24+
/**
25+
* Reads the digital value from the specified channel (0-3) of the ADC0834.
26+
* @param channel The ADC channel to read (0-3).
27+
* @return The 8-bit digital value (0-255).
28+
* @throws IllegalArgumentException if channel is invalid.
29+
*/
30+
public int readValue(int channel) {
31+
if (channel < 0 || channel > 3) {
32+
log.error("Invalid channel: {}. Must be 0-3.", channel);
33+
throw new IllegalArgumentException("Channel must be between 0 and 3");
34+
}
35+
36+
// ADC0834 control byte: Start bit (1), single-ended (1), channel select (2 bits), reserved (0)
37+
byte controlByte = (byte) (0b10000000 | (channel << 5));
38+
byte[] txBuffer = new byte[] { controlByte, 0 }; // Second byte for clocking out data
39+
byte[] rxBuffer = new byte[2];
40+
41+
try {
42+
spi.transfer(txBuffer, rxBuffer);
43+
int digitalValue = rxBuffer[1] & 0xFF; // 8-bit result
44+
log.info("Read channel {}: raw value = {}", channel, digitalValue);
45+
return digitalValue;
46+
} catch (Exception e) {
47+
log.error("Failed to read from ADC0834 on channel {}: {}", channel, e.getMessage());
48+
throw new RuntimeException("SPI communication error", e);
49+
}
50+
}
51+
52+
/**
53+
* Reads the voltage from the specified channel using the provided reference voltage.
54+
* @param channel The ADC channel to read (0-3).
55+
* @param referenceVoltage The reference voltage (e.g., 3.3V or 5.0V).
56+
* @return The measured voltage.
57+
* @throws IllegalArgumentException if channel or referenceVoltage is invalid.
58+
*/
59+
public double readVoltage(int channel, double referenceVoltage) {
60+
if (referenceVoltage <= 0) {
61+
log.error("Invalid reference voltage: {}. Must be positive.", referenceVoltage);
62+
throw new IllegalArgumentException("Reference voltage must be positive");
63+
}
64+
65+
int rawValue = readValue(channel);
66+
double voltage = (rawValue / 255.0) * referenceVoltage;
67+
log.info("Channel {} voltage: {}V (raw = {}, ref = {}V)", channel, voltage, rawValue, referenceVoltage);
68+
return voltage;
69+
}
70+
}

pi4micronaut-utils/src/main/java/com/opensourcewithslu/inputdevices/ADCConverterHelper.java

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.opensourcewithslu.inputdevices;
2+
3+
import com.pi4j.context.Context;
4+
import com.pi4j.io.spi.Spi;
5+
import com.pi4j.io.spi.SpiConfig;
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
import org.mockito.Mockito;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
import static org.mockito.ArgumentMatchers.any;
14+
import static org.mockito.Mockito.*;
15+
16+
public class ADC0834ConverterHelperTest {
17+
private static final Logger log = LoggerFactory.getLogger(ADC0834ConverterHelperTest.class);
18+
19+
private Context mockContext;
20+
private Spi mockSpi;
21+
private ADC0834ConverterHelper adc;
22+
23+
@BeforeEach
24+
public void setUp() {
25+
mockContext = Mockito.mock(Context.class);
26+
mockSpi = Mockito.mock(Spi.class);
27+
when(mockContext.create(any(SpiConfig.class))).thenReturn(mockSpi);
28+
adc = new ADC0834ConverterHelper(mockSpi);
29+
}
30+
31+
@Test
32+
public void testReadValueValidChannel() throws Exception {
33+
// Mock the transfer(byte[], byte[]) method
34+
doAnswer(invocation -> {
35+
byte[] txBuffer = invocation.getArgument(0);
36+
byte[] rxBuffer = invocation.getArgument(1);
37+
// Simulate ADC0834 response - 8-bit value in rxBuffer[1]
38+
rxBuffer[0] = 0x00; // First byte unused
39+
rxBuffer[1] = (byte) 0x80; // 8-bit value: 128 (decimal)
40+
return null;
41+
}).when(mockSpi).transfer(any(byte[].class), any(byte[].class));
42+
43+
int value = adc.readValue(2);
44+
assertEquals(128, value, "ADC value should be 128 (8-bit)");
45+
}
46+
47+
@Test
48+
public void testReadValueInvalidChannelLow() {
49+
Exception exception = assertThrows(IllegalArgumentException.class, () -> adc.readValue(-1));
50+
assertEquals("Channel must be between 0 and 3", exception.getMessage());
51+
}
52+
53+
@Test
54+
public void testReadValueInvalidChannelHigh() {
55+
Exception exception = assertThrows(IllegalArgumentException.class, () -> adc.readValue(4));
56+
assertEquals("Channel must be between 0 and 3", exception.getMessage());
57+
}
58+
59+
@Test
60+
public void testReadVoltageValid() throws Exception {
61+
// Mock the transfer method to return value 128
62+
doAnswer(invocation -> {
63+
byte[] txBuffer = invocation.getArgument(0);
64+
byte[] rxBuffer = invocation.getArgument(1);
65+
rxBuffer[0] = 0x00;
66+
rxBuffer[1] = (byte) 0x80; // 128 in decimal
67+
return null;
68+
}).when(mockSpi).transfer(any(byte[].class), any(byte[].class));
69+
70+
double voltage = adc.readVoltage(1, 3.3);
71+
// Expected: (128 / 255.0) * 3.3 = 1.654...
72+
assertEquals(3.3 * (128.0 / 255.0), voltage, 0.001, "Voltage should be correctly calculated (8-bit)");
73+
}
74+
75+
@Test
76+
public void testReadVoltageInvalidReference() {
77+
Exception exception = assertThrows(IllegalArgumentException.class, () -> adc.readVoltage(0, 0));
78+
assertEquals("Reference voltage must be positive", exception.getMessage());
79+
}
80+
81+
@Test
82+
public void testSpiCommunicationFailure() throws Exception {
83+
// Mock transfer to throw exception
84+
doThrow(new RuntimeException("SPI error")).when(mockSpi).transfer(any(byte[].class), any(byte[].class));
85+
86+
Exception exception = assertThrows(RuntimeException.class, () -> adc.readValue(0));
87+
assertTrue(exception.getMessage().contains("SPI"), "Expected SPI-related error");
88+
}
89+
}

0 commit comments

Comments
 (0)