All mbed code for control over dive planes, pump motor, valve motor, BCUs, UART interface, etc.

Dependencies:   mbed ESC mbed MODDMA

robotic_fish_6/ButtonBoard.cpp

Committer:
juansal12
Date:
2020-01-14
Revision:
0:c3a329a5b05d

File content as of revision 0:c3a329a5b05d:

// buttons.cpp

#include "ButtonBoard.h"

extern "C" void mbed_reset();

ButtonBoard::ButtonBoard(PinName sda, PinName scl, PinName int1, PinName int2) :
    _i2c(sda, scl),
    _int1(int1),
    _int2(int2),
    _callbackFunction(NULL),
    _button_state(0)
{
    // Initialize callback table
    for (int i=0; i < BTTN_COUNT; i++)
    {
        _callback_table_valid[i] = false;
    }
    
    // Set I2C frequency to fast-mode 400KHz
    _i2c.frequency(400000L);
    
    ///// Configuration
    bool bd1_failure = false;
    bool bd2_failure = false;
    
    // Configure input latching
    out_buf[0] = 0x44;  // Input latch register
    out_buf[1] = 0x00;  // Don't need latching on output
    out_buf[1] = 0x00;  // Latch them all
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 3);
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 3);
    
    // Disable pull-ups
    out_buf[0] = 0x46;  // Pull-up/down enable register
    out_buf[1] = 0x00;  // Don't need on outputs
    out_buf[2] = 0x00;  // Don't need
    out_buf[3] = 0xFF;  // Select pull-ups
    out_buf[4] = 0xFF;
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 5);
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 5);
    
    // Configure outputs as open-drain
    out_buf[0] = 0x4F;  // Output port config register
    out_buf[1] = 0x02;  // Port 1 to open drain
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 2);
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 2);
    
    // Reset output register high
    _led_ports = 0xFFFF; // All LED's off
    out_buf[0] = 0x02; // Output register
    out_buf[1] = _led_ports & 0xFF; 
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 2);
    out_buf[2] = _led_ports>>8;
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 2);
    
    // Configure ports as input or outputs
    out_buf[0] = 0x06;  // Configuration registers
    out_buf[1] = 0x00;  // Port 1 -> Output
    out_buf[2] = 0xFF;  // Port 2 <- Input 
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 3); 
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 3); 
    
    // Read input registers to clear interrupts
    out_buf[0] = 0x00; // Input registers
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 1, true); 
    bd1_failure |= _i2c.read(ADDR_BOARD_1, out_buf, 2);  // Read registers
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 1, true); 
    bd2_failure |= _i2c.read(ADDR_BOARD_2, out_buf, 2);  // Read registers
    
    // Disable interrupt masking on inputs
    out_buf[0] = 0x4A;  // Interrupt mask register
    out_buf[1] = 0xFF;  // Mask outputs
    out_buf[2] = 0xFF;  // Don't mask inputs
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 3);
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 3);
    
    // Disable interrupt masking on inputs
    out_buf[0] = 0x4A;  // Interrupt mask register
    out_buf[1] = 0xFF;  // Mask outputs
    out_buf[2] = 0x00;  // Don't mask inputs
    bd1_failure |= _i2c.write(ADDR_BOARD_1, out_buf, 3);
    bd2_failure |= _i2c.write(ADDR_BOARD_2, out_buf, 3);
    
    if (bd1_failure)
    {
        // serial.printf("Nack recieved while configuring button board 1\n");
        bd1_failure = false;
    }
    if (bd2_failure)
    {
        // serial.printf("Nack recieved while configuring button board 2\n");
        bd2_failure = false;
    }
    
    // Enable mbed interrupt lines
    _int1.fall(this, &ButtonBoard::_int1_handler);
    _int2.fall(this, &ButtonBoard::_int2_handler);
    _int1.mode(PullUp);
    _int2.mode(PullUp);
    
    // Register callbacks
    //registerCallback(BTTN_RESET, &mbed_reset);
    
}

ButtonBoard::~ButtonBoard()
{
}

void ButtonBoard::_int1_handler()
{
    _fall_handler(ADDR_BOARD_1);
}

void ButtonBoard::_int2_handler()
{
    _fall_handler(ADDR_BOARD_2);
}

void ButtonBoard::_fall_handler(char board)
{    
    char int_status;
    char input_port;
    char masked_port;
    
    int board_offset;
    if (board == ADDR_BOARD_1)
    {
        board_offset = 0;
    }
    else
    {
        board_offset = BTTN_COUNT_BOARD_1;
    }
    
    // Poll board for interrupt source byte and input reg byte
    out_buf[0] = 0x4d; // Port 1 Interrupt status
    _i2c.write(board, out_buf, 1);
    _i2c.read(board, &int_status, 1);
    
    out_buf[0] = 0x01; // Port 1 input register
    _i2c.write(board, out_buf, 1);
    _i2c.read(board, &input_port, 1);
    
    // Use int status to mask input port (input goes low when button depressed)
    // int status will always indicate which button changed
    // masked_port will also indicate button if button is pressed, but will be 0 if button is released
    masked_port = int_status & (~input_port);
    if(masked_port)
        _button_state |= int_status;
    else
        _button_state &= ~int_status;
    
    for (int i=0; i<8; i++)
    {
        // For every high bit in masked port
        if (masked_port & (1<<i))
        {
            // Call corresponding callback
            int cb_i = i+board_offset;
            if (_callback_table_valid[cb_i] == true)
            {
                _callback_table[cb_i].call();
            }
        }
    }
    // Call master callback
    if(_callbackFunction != NULL)
        _callbackFunction(int_status, masked_port, _button_state);
}


void ButtonBoard::registerCallback(uint32_t button, FunctionPointer p)
{
    if (button < BTTN_COUNT)
    { 
        _callback_table[button] = p;
        _callback_table_valid[button] = true;
    }
}

void ButtonBoard::registerCallback(void (*p)(char buttonMask, bool pressed, char curState))
{
    _callbackFunction = p;
}

//void ButtonBoard::setLED(uint32_t led, bool val)
//{
//    if (led > BTTN_COUNT)
//    {
//        // invalid, skip
//        return;
//    }
//    
//    char board;
//    
//    if (led < BTTN_COUNT_BOARD_1)
//    {
//        // Address first board
//        board = ADDR_BOARD_1;
//    }
//    else
//    {
//        // Address second board
//        board = ADDR_BOARD_2;
//        led = led - BTTN_COUNT_BOARD_1;
//    }
//    
//    bool fail = false;
//    
//    // Read port state
//    char port_state;
//    out_buf[0] = 0x02; // Port 0 output register
//    
//    fail |= _i2c.write(board, out_buf, 1, true);
//    fail |= _i2c.read(board, &port_state, 1);
//    
//    if (val == true)
//    {
//        // Turn LED on by clearing bit
//        port_state &= ~(1<<led);
//    }
//    else
//    {
//        // Turn LED off by raising bit
//        port_state |= (1<<led);
//    }
//    
//    // Now write to board
//    out_buf[0] = 0x02; // Port 0 output register
//    out_buf[1] = port_state;
//    
//    fail |= _i2c.write(board, out_buf, 2);
//    
//    if (fail)
//    {
//        // serial.printf("Nack recieved when writing LED %d on Board %d", led, board);
//    }
//    else
//    {
//        _led_ports = port_state<<(8*board) + _led_ports & (~(0xFF<<(8*board)));
//    }
//}

void ButtonBoard::setLEDs(char mask, bool turnOn, char board /* = ADDR_BOARD_1 */)
{
    bool fail = false;
    
    // Read port state
    char port_state;
    out_buf[0] = 0x02; // Port 0 output register
    
    fail |= _i2c.write(board, out_buf, 1, true);
    fail |= _i2c.read(board, &port_state, 1);
    
    if(turnOn == true)
    {
        // Turn LEDs on by clearing bits
        port_state &= ~(mask);
    }
    else
    {
        // Turn LEDs off by raising bits
        port_state |= (mask);
    }
    
    // Now write to board
    out_buf[0] = 0x02; // Port 0 output register
    out_buf[1] = port_state;
    
    fail |= _i2c.write(board, out_buf, 2);
    
    if(fail)
    {
        // serial.printf("Nack recieved when writing LED %d on Board %d", led, board);
        //printf("button board write failed\n");
    }
    else
    {
        //_led_ports = port_state<<(8*board) + _led_ports & (~(0xFF<<(8*board)));
        _led_ports = port_state;
    }
}

char ButtonBoard::getLEDs(char ledMask, char board /* = ADDR_BOARD_1 */)
{
    return ~_led_ports & ledMask;
//    bool fail = false;
//    
//    // Read port state
//    char port_state;
//    out_buf[0] = 0x02; // Port 0 output register
//    
//    fail |= _i2c.write(board, out_buf, 1, true);
//    fail |= _i2c.read(board, &port_state, 1);
//    
//    return ~port_state & ledMask;
}

char ButtonBoard::getButtons(char buttonMask, char board /* = ADDR_BOARD_1 */)
{
    return _button_state & buttonMask;
}

//uint16_t ButtonBoard::readInputs()
//{
//    char b1_p1;
//    char b2_p1;
//    
//    out_buf[0] = 0x01;
//    _i2c.write(ADDR_BOARD_1, out_buf, 1, true);
//    _i2c.read(ADDR_BOARD_1, &b1_p1, 1);
//    
//    _i2c.write(ADDR_BOARD_2, out_buf, 1, true);
//    _i2c.read(ADDR_BOARD_2, &b2_p1, 1);
//    
//    uint16_t out = (b2_p1<<8) | b1_p1;
//    
//    return out;
//}