diff --git a/inc/main.h b/inc/main.h index 231e5eb..9644316 100644 --- a/inc/main.h +++ b/inc/main.h @@ -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; diff --git a/mocks/MockADC/MockADC.c b/mocks/MockADC/MockADC.c index dcf8f8f..8465365 100644 --- a/mocks/MockADC/MockADC.c +++ b/mocks/MockADC/MockADC.c @@ -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){ diff --git a/mocks/MockADC/MockADC.h b/mocks/MockADC/MockADC.h index 6c95934..c1d1be6 100644 --- a/mocks/MockADC/MockADC.h +++ b/mocks/MockADC/MockADC.h @@ -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); diff --git a/otto.sh b/otto.sh index 50416ce..0d10fca 100755 --- a/otto.sh +++ b/otto.sh @@ -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" diff --git a/src/ADC/ADC.c b/src/ADC/ADC.c index 0e2075b..e441bf7 100644 --- a/src/ADC/ADC.c +++ b/src/ADC/ADC.c @@ -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; diff --git a/src/ADC/ADC.h b/src/ADC/ADC.h index 896c8ff..bc64912 100644 --- a/src/ADC/ADC.h +++ b/src/ADC/ADC.h @@ -13,10 +13,16 @@ #include #include +/** + * @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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa33018..60a4ac6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,8 @@ add_executable(${PROJECT_NAME} ) target_link_libraries(${PROJECT_NAME} - RegEdit + #RegEdit + #ADC #timer ) diff --git a/src/main.c b/src/main.c index ddaf568..89176aa 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); } diff --git a/tests/ADC/test_ADC.cpp b/tests/ADC/test_ADC.cpp index 7c4ce42..a523296 100644 --- a/tests/ADC/test_ADC.cpp +++ b/tests/ADC/test_ADC.cpp @@ -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); } diff --git a/tests/MockADC/test_MockADC.cpp b/tests/MockADC/test_MockADC.cpp index 8b0b5ee..bb8d250 100644 --- a/tests/MockADC/test_MockADC.cpp +++ b/tests/MockADC/test_MockADC.cpp @@ -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); }