Merge branch 'dev'

This commit is contained in:
Jake Goodwin 2025-02-23 11:54:34 -08:00
commit b64c306250
10 changed files with 192 additions and 186 deletions

View File

@ -32,8 +32,8 @@
//Addresses in the eeprom for the two switch states
#define ROM_SP_ADR 0x0
#define ROM_SS1_ADR 0x1
#define ROM_SS2_ADR 0x2
#define POSITION1_ADR 0x1
#define POSITION2_ADR 0x2
#define ROM_EP_ADR 0x3
//Debounce check number.
@ -89,7 +89,6 @@ typedef struct {
uint8_t timer_enabled: 1;
uint8_t pressed_ticks;
uint8_t input_pin;
uint8_t output_pin;
}btn_state;

View File

@ -16,22 +16,16 @@ int fake_index = 0;
static bool is_setup = false;
void ADC_SetPin(uint8_t pin_num)
{
return;
}
void ADC_Setup(void)
{
is_setup = true;
return;
}
void ADC_Init(uint8_t pin_num)
void ADC_Init(uint8_t adc_chan)
{
mock_c()->actualCall("ADC_Init")
->withUnsignedIntParameters("pin_num", pin_num);
->withUnsignedIntParameters("adc_chan", adc_chan);
}
void ADC_Enable(void)
@ -44,10 +38,10 @@ void ADC_Disable()
mock_c()->actualCall("ADC_Disable");
}
uint16_t ADC_ReadValue_Impl(uint8_t pin_num)
uint16_t ADC_ReadValue_Impl(void)
{
mock_c()->actualCall("ADC_ReadValue_Impl")
->withUnsignedIntParameters("pin_num", pin_num);
mock_c()->actualCall("ADC_ReadValue_Impl");
if(fake_index == 0){
return 0;
@ -55,7 +49,7 @@ uint16_t ADC_ReadValue_Impl(uint8_t pin_num)
return fake_data[--fake_index];
}
uint16_t (*ADC_ReadValue)(uint8_t pin_num) = ADC_ReadValue_Impl;
uint16_t (*ADC_ReadValue)(void) = ADC_ReadValue_Impl;
void MockADC_PushValue(uint16_t value){

View File

@ -15,12 +15,11 @@
void ADC_Setup(void);
void ADC_SetPin(uint8_t pin_num);
void ADC_Init(uint8_t pin_num);
void ADC_Init(uint8_t adc_chan);
void ADC_Enable(void);
void ADC_Disable(void);
extern uint16_t (*ADC_ReadValue)(uint8_t pin_num);
extern uint16_t (*ADC_ReadValue)(void);
void MockADC_PushValue(uint16_t value);
void MockADC_ZeroIndex(void);

11
otto.sh
View File

@ -224,12 +224,19 @@ run_c_tests () {
make AllTests && ./tests/AllTests -c -v
}
run_mock_tests () {
format_source_code
clear_cmake_cache
cmake -DUNIT_TESTING=ON -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE} ../
make Mock_Tests && ./tests/Mock_Tests -c -v
}
print_menu () {
echo "BUILD MENU:"
echo "0. Add Mock Module"
echo "1. Run Tests"
echo "2. Build Project(hex)"
echo "3. User Option"
echo "3. Run MockTests"
echo "4. Flash to AVR"
echo "5. Add new module to project"
echo "6. Delete module from project"
@ -264,7 +271,7 @@ main() {
3)
echo "You selected Option 3"
valid_choice=true
build_hex_optimized
run_mock_tests
;;
4)
echo "You selected Option 4"

View File

@ -13,15 +13,30 @@
#include "RegEdit.h"
#include "avr/io.h"
#define MAX_PIN_NUM 7
#define MAX_CHANNEL_NUM 3
static bool IsInvalidPin(uint8_t pin_num) {
if (pin_num > MAX_PIN_NUM) {
static bool IsInvalidChannel(uint8_t adc_chan) {
if (adc_chan > MAX_CHANNEL_NUM) {
return true;
}
return false;
}
uint8_t ADC_GetChannelPinNum(uint8_t adc_chan) {
switch (adc_chan) {
case 0:
return PB5;
case 1:
return PB2;
case 2:
return PB4;
case 3:
return PB3;
default:
return 255; /*return invalid pin num.*/
}
}
void ADC_Setup(void) {
// Clear the register, set VCC as ref, ADC0 as channel and
// leave result right adjusted.
@ -36,62 +51,61 @@ void ADC_Setup(void) {
RegEdit_AND_Num((void *)&ADCSRB, (1 << ADTS2) | (0 << ADTS1) | (1 << ADTS0));
}
void ADC_Init(uint8_t pin_num) {
void ADC_Init(uint8_t adc_chan) {
if (IsInvalidPin(pin_num)) {
if (IsInvalidChannel(adc_chan)) {
return;
}
// get the associated pin number.
uint8_t pin_num = ADC_GetChannelPinNum(adc_chan);
// set the direction to input
// RegEdit_ClearBit((void *)&PORTA.DIR, pin_num);
RegEdit_ClearBit((void *)&DDRB, pin_num);
// Disable the pull-up resistor
// RegEdit_ClearBit((void *)&PORTA.OUT, pin_num);
RegEdit_ClearBit((void *)&PORTB, pin_num);
// Disable input buffer
// We do some kinda nasty address addition but it saves
// memory and means we don't need a switch statment.
// RegEdit_SetBit((void *)(&PORTA.PIN0CTRL) + pin_num,
// PORT_ISC_INPUT_DISABLE_gc);
// Set the adc mux reg for our channel.
// Clear the existing mux bits.
RegEdit_AND_Num((void *)&ADMUX, 0xFC);
// Set the correct bits
RegEdit_OR_Num((void *)&ADMUX, adc_chan);
}
void ADC_Enable(void) {
// Set the enable bit in the CTRLA register
// RegEdit_SetBit((void *)&ADC0.CTRLA, 0);
RegEdit_SetBit((void *)&ADCSRA, ADEN);
}
void ADC_Disable() {
// Clear the enable ADC flag
// RegEdit_ClearBit((void *)&ADC0.CTRLA, 0);
RegEdit_ClearBit((void *)&ADCSRA, ADEN);
}
void ADC_SetPin(uint8_t pin_num) {
if (IsInvalidPin(pin_num)) {
return;
uint16_t ADC_ReadValue_Impl(void) {
// start conversion.
RegEdit_SetBit((void *)&ADCSRA, ADSC);
/* Wait until ADC conversion done or it times out. */
uint8_t cycles = 1;
while (1) {
if (!RegEdit_IsBitSet((void *)&ADCSRA, ADSC)) {
break;
}
// if It times out return an invalid value for a 12bit ADC.
else if (cycles >= ADC_WAIT_TIMEOUT) {
return UINT16_MAX;
}
cycles++;
}
// RegEdit_ClearRegister((void *)&ADC0.MUXPOS);
// RegEdit_SetNum((void *)&ADC0.MUXPOS, pin_num);
}
uint16_t ADC_ReadValue_Impl(uint8_t pin_num) {
// RegEdit_SetNum((void *)&ADC0.COMMAND, ADC_STCONV_bm);
/* Wait until ADC conversion done */
/*
while (!(ADC0.INTFLAGS & ADC_RESRDY_bm)) {
;
}
*/
/* Clear the interrupt flag by writing 1: */
// ADC0.INTFLAGS = ADC_RESRDY_bm;
// uint16_t adc_val = (uint16_t)ADC0.RES;
uint16_t adc_val = 0;
adc_val = adc_val >> 5;
return adc_val;
uint16_t val = ADC;
return val;
}
// Set the default for the function pointer.
uint16_t (*ADC_ReadValue)(uint8_t pin_num) = ADC_ReadValue_Impl;
uint16_t (*ADC_ReadValue)(void) = ADC_ReadValue_Impl;

View File

@ -13,10 +13,16 @@
#include <stdbool.h>
#include <stdint.h>
/**
* @brief The number of loop cycles it waits for ADC conversion before
* timing out.
*/
#define ADC_WAIT_TIMEOUT 16
/**
* @brief Initializes the AVR hardware in order to accept
* Input for ADC usage.
* @param pin_num The number of the pin 0-7 you are initializing.
* @param adc_chan The channel of the pin 0-7 you are initializing.
*
* This function only makes use of PORTA by default. It sets the direction
* register to input, disables the pull-up resistor and also diables interrupts
@ -25,7 +31,13 @@
* This in turn helps reduce noise when using the ADC.
*
*/
void ADC_Init(uint8_t pin_num);
void ADC_Init(uint8_t adc_chan);
/**
* @brief Returns the pin number for the adc channel or 255 on an error.
* @param The ADC channel.
*/
uint8_t ADC_GetChannelPinNum(uint8_t adc_chan);
/**
* @brief Enables the ADC
@ -40,12 +52,11 @@ void ADC_Disable();
/**
* @brief Reads ADC value into variable
*
* @param pin_num The bin number of the ADC pin being read.
*
* This function depends on the ADC already being initialized and enabled
* before being called.
*/
extern uint16_t (*ADC_ReadValue)(uint8_t pin_num);
extern uint16_t (*ADC_ReadValue)();
/**
* @brief Sets up the ADC
@ -58,11 +69,4 @@ extern uint16_t (*ADC_ReadValue)(uint8_t pin_num);
*/
void ADC_Setup(void);
/**
* @brief Sets the pin used in the MUX for ADC0.
*
* @param pin_num The number of the pin in Port A.
*/
void ADC_SetPin(uint8_t pin_num);
#endif // ADC_H

View File

@ -3,7 +3,8 @@ add_executable(${PROJECT_NAME}
)
target_link_libraries(${PROJECT_NAME}
RegEdit
#RegEdit
#ADC
#timer
)

View File

@ -1,5 +1,4 @@
#ifndef F_CPU
#error "F_CPU not defined: defaulting to 9.6MHz"
#define F_CPU 1200000UL
#endif
@ -34,7 +33,7 @@ volatile uint16_t tick_count;
// #############################
static inline void InitTimer0(void);
static void InitBtn(btn_state *b, uint8_t input_pin, uint8_t output_pin);
static void InitBtn(btn_state *b, uint8_t input_pin);
static void ClearButtonTimer(btn_state *b);
static void StartButtonTimer(btn_state *b);
static void CheckButtonLongpress(btn_state *b);
@ -51,7 +50,6 @@ int main() {
while (1) {
UpdateButtonOutput(&btn1);
UpdateButtonInput(&btn1);
//MotorMoveTo(0);
}
return 0;
@ -65,7 +63,7 @@ void InitProg(void) {
/*Set the debounced state to all high*/
debounced_state = 0xFF;
InitBtn(&btn1, BUTTON_PIN, PIN_ACTIVE1);
InitBtn(&btn1, BUTTON_PIN);
/*Wait 5ms for pull-up resistors voltage to become stable.*/
_delay_ms(5);
@ -76,11 +74,11 @@ void InitProg(void) {
// Checks against a bit pattern we defined to represent the start of data.
if (eeprom_read_byte((uint8_t *)ROM_SP_ADR) == START_PATTERN) {
MotorMoveTo(eeprom_read_byte((uint8_t *)ROM_SS1_ADR));
MotorMoveTo(eeprom_read_byte((uint8_t *)POSITION1_ADR));
} else {
// otherwise we write the init values for the start pattern and states.
eeprom_write_byte((uint8_t *)ROM_SP_ADR, START_PATTERN);
eeprom_write_byte((uint8_t *)ROM_SS1_ADR, 0x7F);
eeprom_write_byte((uint8_t *)POSITION1_ADR, 0x7F);
}
InitTimer0();
@ -96,17 +94,18 @@ uint8_t ReadSpeed(void) {
while (ADCSRA & (1 << ADSC)) {
} // Wait for conversion to finish
uint8_t val = (uint8_t)(ADC >> 2);
//Map the speed value to the 100%-50% duty cycle range.
//val = (uint8_t)( (float)val / 255.0 ) * 100;
//Normally a bitshift of 2 is done for 8bit ADC values,
//however we want to divide by two after this as well so we
//do a third shift followed by an addition of 127 to yield a mapping of
//approximatly 50%-96.6% duty cycle range.
uint8_t val = (uint8_t)(ADC >> 3) + 127;
return val;
}
// change to ReadFader(void)
uint16_t ReadFader(void) {
// Initialize ADC
// Initialize ADC
ADMUX = (1 << MUX1) | (1 << MUX0); // Select ADC3 (PB3)
ADCSRA = (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0); // Enable ADC, prescaler 8
@ -129,21 +128,22 @@ static inline uint8_t diff(uint8_t a, uint8_t b) {
return b - a;
}
void MotorSetSavePos() {
void MotorSetSavePos(uint8_t *ADR) {
uint8_t pos = (uint8_t)(ReadFader() >> 2);
eeprom_write_byte((uint8_t *)ROM_SS1_ADR, pos);
//eeprom_write_byte((uint8_t *)ADR, pos);
eeprom_update_byte((uint8_t *)ADR, pos);
return;
}
uint8_t MotorGetSavedPos(void) {
return (uint8_t)eeprom_read_byte((uint8_t *)ROM_SS1_ADR);
uint8_t MotorGetSavedPos(uint8_t *ADR) {
return (uint8_t)eeprom_read_byte((uint8_t *)POSITION1_ADR);
}
void MotorMoveTo(uint8_t target) {
uint8_t on_delay = ReadSpeed();
uint8_t pos = (uint8_t)(ReadFader() >> 2);
uint8_t idx =0;
uint8_t idx = 0;
while (diff(target, pos) > 8) {
on_delay = ReadSpeed();
@ -159,7 +159,7 @@ void MotorMoveTo(uint8_t target) {
_delay_us(MOTOR_PULSE);
}
MotorCoast();
for (;idx < 255; idx++) {
for (; idx < 255; idx++) {
_delay_us(MOTOR_PULSE);
}
}
@ -191,21 +191,17 @@ void MotorCoast(void) {
*/
/*This is kinda like our button constructor*/
static void InitBtn(btn_state *b, uint8_t input_pin, uint8_t output_pin) {
static void InitBtn(btn_state *b, uint8_t input_pin) {
b->is_long_pressed = 0;
b->is_pressed = 0;
b->is_active = 0;
b->pressed_ticks = 0;
b->timer_enabled = 0;
b->input_pin = input_pin;
b->output_pin = output_pin;
/*Configure the buttons inputs and outputs*/
DDRB &= ~(1 << b->input_pin);
PORTB |= (1 << b->input_pin);
DDRB |= (1 << b->output_pin);
PORTB &= ~(1 << b->output_pin);
}
static void ClearButtonTimer(btn_state *b) {
@ -249,6 +245,7 @@ static void UpdateButtonOutput(btn_state *b) {
/*Then start the timer and update the output*/
// ToggleOutput(b);
StartButtonTimer(b);
return;
}
@ -268,12 +265,21 @@ static void UpdateButtonOutput(btn_state *b) {
else if (!b->is_pressed) {
/*If the button was released on a long press.*/
if (b->is_long_pressed) {
MotorSetSavePos();
MotorSetSavePos((uint8_t *)POSITION1_ADR);
}
/*If the button pres was a short one.*/
else if (!b->is_long_pressed) {
if (b->is_active) {
MotorMoveTo(MotorGetSavedPos());
/*Save the current position into position 2 EEPROM*/
MotorSetSavePos((uint8_t *)POSITION2_ADR);
/*If already in saved position then go back to original pos.*/
if(diff(MotorGetSavedPos((uint8_t *)POSITION1_ADR), ReadFader()) > 8){
MotorMoveTo(MotorGetSavedPos((uint8_t *)POSITION1_ADR));
}
else{
MotorMoveTo(MotorGetSavedPos((uint8_t *)POSITION1_ADR));
}
} else {
MotorCoast();
}

View File

@ -73,116 +73,100 @@ TEST(test_ADC, ADC_SetupSetsRegisters)
ADC_Setup();
}
TEST(test_ADC, ADC_InitPortbADC3UsesCorrectRegisters)
TEST(test_ADC, ADC_InitRejectsInvalidChannels)
{
//PB3/ADC3
//Check it disables the pin's digital circuitry
//Check that the ADC pin is selected in ADMUX
//
/*
//Check for setting the direction to input.
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &PORTA.DIR)
.withUnsignedIntParameter("bit_num", 7);
//Check that the pullup is off
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &PORTA.OUT)
.withUnsignedIntParameter("bit_num", 7);
//Set the ISC(input sense config) to disable digital input
//buffering and reduce the noise on ADC usage.
mock().expectOneCall("RegEdit_SetBit")
.withPointerParameter("reg", (void *) &PORTA.PIN7CTRL)
.withUnsignedIntParameter("bit_num", PORT_ISC_INPUT_DISABLE_gc);
*/
ADC_Init(7);
for(uint8_t i = 4; i < 255; i++){
ADC_Init(i);
}
}
TEST(test_ADC, ADC_InitPortAPin0UsesCorrectRegisters)
TEST(test_ADC, ADC_InitPortbWorksWithValidChannels)
{
/*
//Check for setting the direction to input.
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &PORTA.DIR)
.withUnsignedIntParameter("bit_num", 0);
//Check that the pullup is off
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &PORTA.OUT)
.withUnsignedIntParameter("bit_num", 0);
uint8_t pin_num;
//Set the ISC(input sense config) to disable digital input
//buffering and reduce the noise on ADC usage.
mock().expectOneCall("RegEdit_SetBit")
.withPointerParameter("reg", (void *) &PORTA.PIN0CTRL)
.withUnsignedIntParameter("bit_num", PORT_ISC_INPUT_DISABLE_gc);
for(uint8_t adc_channel = 0; adc_channel <= 3; adc_channel++)
{
pin_num = ADC_GetChannelPinNum(adc_channel);
*/
//ADC_Init(0);
//Check it disables the pin's digital circuitry
//Check it sets the pin for input
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &DDRB)
.withUnsignedIntParameter("bit_num", pin_num);
//Check that the pull-up resistor is disabled.
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &PORTB)
.withUnsignedIntParameter("bit_num", pin_num);
//Check that the ADC pin is selected in ADMUX
//Clears the last two bits first.
mock().expectOneCall("RegEdit_AND_Num")
.withPointerParameter("reg", (void *) &ADMUX)
.withUnsignedIntParameter("num", 0xFC);
//Selects the ADC pin/channel
mock().expectOneCall("RegEdit_OR_Num")
.withPointerParameter("reg", (void *) &ADMUX)
.withUnsignedIntParameter("num", adc_channel);
ADC_Init(adc_channel);
}
}
TEST(test_ADC, ADC_InitDoesNothingOnHighPinNumbers)
{
//mock().expectNoCall("RegEdit_SetBit");
//ADC_Init(8);
}
TEST(test_ADC, ADC_EnablePasses)
{
/*
mock().expectOneCall("RegEdit_SetBit")
.withPointerParameter("reg", (void *) &ADC0.CTRLA)
.withUnsignedIntParameter("bit_num", 0);
*/
//ADC_Enable();
mock().expectOneCall("RegEdit_SetBit")
.withPointerParameter("reg", (void *) &ADCSRA)
.withUnsignedIntParameter("bit_num", ADEN);
ADC_Enable();
}
TEST(test_ADC, ADC_DisablePasses)
{
/*
mock().expectOneCall("RegEdit_ClearBit")
.withPointerParameter("reg", (void *) &ADC0.CTRLA)
.withUnsignedIntParameter("bit_num", 0);
*/
//ADC_Disable();
.withPointerParameter("reg", (void *) &ADCSRA)
.withUnsignedIntParameter("bit_num", ADEN);
ADC_Disable();
}
TEST(test_ADC, ADC_SetPinSetsRightRegisters)
TEST(test_ADC, ADC_ReadValueImplimentationTimesOut)
{
/*
//It clears existing MUXPOS register values.
mock().expectOneCall("RegEdit_ClearRegister")
.withPointerParameter("reg", (void *) &ADC0.MUXPOS);
//Expect the start conversion bit to be set.
mock().expectOneCall("RegEdit_SetBit")
.withPointerParameter("reg", (void *) &ADCSRA)
.withUnsignedIntParameter("bit_num", ADSC);
//It Correctly sets the pin number.
mock().expectOneCall("RegEdit_SetNum")
.withPointerParameter("reg", (void *) &ADC0.MUXPOS)
.withUnsignedIntParameter("num", 4);
*/
//ADC_SetPin(4);
//Check that it can time out.
//Expect it to read the start bit
mock().expectNCalls(ADC_WAIT_TIMEOUT, "RegEdit_IsBitSet")
.withPointerParameter("reg", (void *) &ADCSRA)
.withUnsignedIntParameter("bit_num", ADSC);
//Check that it return the "error" value
uint16_t value = ADC_ReadValue();
CHECK_EQUAL_TEXT(UINT16_MAX, value, "ERROR: Should return UINT16_MAX!");
}
TEST(test_ADC, ADC_SetPinFailsOnInvalidPin)
{
//ADC_SetPin(8);
}
static uint16_t ADC_ReadValueFake(uint8_t pin_num)
static uint16_t ADC_ReadValueFake()
{
return 512;
}
TEST_GROUP(test_ADCRead)
TEST_GROUP(test_ADCReadPtrSwap)
{
void setup()
{
@ -195,9 +179,9 @@ TEST_GROUP(test_ADCRead)
}
};
TEST(test_ADCRead, FunctionPointerSwapWorks)
TEST(test_ADCReadPtrSwap, FunctionPointerSwapWorks)
{
uint16_t value = ADC_ReadValue(0);
uint16_t value = ADC_ReadValue();
LONGS_EQUAL(512, value);
}

View File

@ -30,9 +30,9 @@ TEST_GROUP(test_MockADC)
TEST(test_MockADC, ADC_InitExpects)
{
mock().expectOneCall("ADC_Init")
.withUnsignedIntParameter("pin_num", 7);
.withUnsignedIntParameter("adc_chan", 0);
ADC_Init(7);
ADC_Init(0);
}
TEST(test_MockADC, ADC_EnableExpects)
@ -55,10 +55,9 @@ TEST(test_MockADC, ADC_ReadValue)
MockADC_ZeroIndex();
MockADC_PushValue(512);
mock().expectOneCall("ADC_ReadValue_Impl")
.withUnsignedIntParameter("pin_num", 0x2);
mock().expectOneCall("ADC_ReadValue_Impl");
uint16_t val = ADC_ReadValue(0x2);
uint16_t val = ADC_ReadValue();
LONGS_EQUAL(512, val);
}
@ -68,10 +67,9 @@ TEST(test_MockADC, ADC_ReadValueReturnsZeroOnEmptyBuffer)
MockADC_ZeroIndex();
mock().expectOneCall("ADC_ReadValue_Impl")
.withUnsignedIntParameter("pin_num", 0x2)
.andReturnValue(0x0000);
uint16_t val = ADC_ReadValue(0x2);
uint16_t val = ADC_ReadValue();
LONGS_EQUAL(0, val);
}