Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MCP23017 with DCS BIOS #99

Closed
hectorlee opened this issue Nov 18, 2016 · 6 comments
Closed

MCP23017 with DCS BIOS #99

hectorlee opened this issue Nov 18, 2016 · 6 comments

Comments

@hectorlee
Copy link

Is there support for the MCP23017 and DCS BIOS? Been trying to figure out how to interface the Adafruit library with DCS BIOS.

@lancer2000
Copy link

See my code

vars:

Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;
Adafruit_MCP23017 mcp3;

Setup:

mcp1.begin(0);    
   for (int thisPin1 = 0; thisPin1 < 16; thisPin1++)  {    
  mcp1.pinMode(thisPin1, INPUT);
  mcp1.pullUp(thisPin1, HIGH); 
    }

   mcp2.begin(2);    
  for (int thisPin2 = 0; thisPin2 < 16; thisPin2++)  {    
  mcp2.pinMode(thisPin2, INPUT);
  mcp2.pullUp(thisPin2, HIGH);
  }

   mcp3.begin(4);    
 for (int thisPin1 = 0; thisPin1 < 16; thisPin1++)  {    
  mcp3.pinMode(thisPin1, INPUT);
  mcp3.pullUp(thisPin1, HIGH); 
    }
DcsBios::setup();

procedures:

Adafruit_MCP23017 NumToChip(byte num) {
 switch (num) {     
    case 1:
      return mcp1;
    case 2:
      return mcp2;
    case 3:
      return mcp3;
 }
}

void Led(unsigned int address, unsigned int addressLed, unsigned int value, unsigned int mask, int chip, int pin) {
  bool is_on;

  if (address == addressLed) {
    is_on = (value & mask);
    if (is_on == 1) {
      NumToChip(chip).digitalWrite(pin, HIGH);
    }
    else {
      NumToChip(chip).digitalWrite(pin, LOW);
    }
  } 
}

void Switch2Pos(char* msg, double arg, int chip, int pin) {
  char state = NumToChip(chip).digitalRead(pin); // reads the Pin of the MCP
  if (state != lastState[chip][pin]) {
    sendDcsBiosMessage(msg, state == 0 ? "1" : "0");
  }
  lastState[chip][pin] = state;
}

char Switch3Pos_readState(int chip, int pinA, int pinB) {
  if (NumToChip(chip).digitalRead(pinA) == LOW) return 0;
  if (NumToChip(chip).digitalRead(pinB) == LOW) return 2;
  return 1;
}

void Switch3Pos(char* msg, double arg, int chip, int pinA, int pinB) {
  char state = Switch3Pos_readState(chip, pinA, pinB);
  if (state != lastState[chip][pinA]) {
    if (state == 0)
      sendDcsBiosMessage(msg, "0");
    if (state == 1)
      sendDcsBiosMessage(msg, "1");
    if (state == 2)
      sendDcsBiosMessage(msg, "2");
  }
  lastState[chip][pinA] = state;
}

char SwitchMultiPosRead(const byte* pinsArray, byte chip, char numberOfPins)
{
  char i;
  for (i = 0; i < numberOfPins; i++) {
    if (NumToChip(chip).digitalRead(pinsArray[i]) == LOW) return i;
  }
  return 0;
}

void SwitchMultiPos(char* msg, const byte* pinsArray, byte chip, char numberOfPins) {
  char i;
  char state = SwitchMultiPosRead(pinsArray, chip, numberOfPins);
  if (state != lastState[chip][pinsArray[0]]) {
    char buf[7];
    utoa(state, buf, 10);
    sendDcsBiosMessage(msg, buf);    
  }
 lastState[chip][pinsArray[0]] = state;
}

Example of use:

Switch2Pos ("WEAPONS_AUTO_TURN_BTN", 0, 1, 0);
  Switch2Pos ("WEAPONS_FORWARD_HEMI_TARGET_BTN", 0, 1, 1);
  Switch2Pos ("WEAPONS_GROUND_TARGET_BTN", 0, 1, 2);
  Switch2Pos ("WEAPONS_AIRBORNE_TARGET_BTN", 0, 1, 3);
  Switch2Pos ("WEAPONS_TARGET_RESET_BTN", 0, 1, 4);
  Switch2Pos ("WEAPONS_TRAINING_MODE", 0, 1, 5);

@hectorlee
Copy link
Author

awesome! Thanks. Missed the possibility of using sendDcsBiosMessage().

Your "example of use" is meant to be in the loop()? Not like the regular statements with the dcsbios namespace right? That's how I got it working.

You left out the part to init the lastState array in case someone is reading this.

Why do you have double arg for your switches. I see you are not using it, was/is there a feature you were/are planning for?

@lancer2000
Copy link

lancer2000 commented Nov 19, 2016

I have send You only important parts of my code, lastState array i have definied: int lastState[3][16];

Yes, my example of use must be in loop. Inputs i must have in loop(), but outputs before, example:

DcsBios::IntegerBuffer weaponsAutoTurnLedBuffer(0x1910, 0x2000, 13, onWeaponsAutoTurnLedChange);
void onWeaponsAutoTurnLedChange(unsigned int newValue) {
    lc.setLed(0,4,7,newValue);
}

I'm not remember for what is the first arg in Switch2Pos. I got this from somebody

@hectorlee
Copy link
Author

No problem. I got it working anyway but decided it would be useful to note that for anyone else who reads this.

Would be useful if this method was documented in the official documents or implemented as an official method as well. Thanks a lot for your help.

@jboecker
Copy link
Member

So far, there is no built-in support for any kind of I/O expander. Getting this right requires careful planning (keeping in mind that whatever I implement into the "official" library, I'll have to support in the future).

The current version of the Arduino library is optimized for ease of use first, efficiency second. Once we add I/O expanders into the mix, it will become easier to reach the resource limits (especially the 2K RAM) on the ATMega328, so making efficient use of memory will become more important.

As an example, a DcsBios::Switch2Pos needs seven bytes of RAM plus the space to store the message string, which is another 10 to 20 bytes. (Replacing that string with a two- or four-byte numerical identifier is on the road map for DCS-BIOS 2.0.) Assuming 25 bytes per switch, adding five 16-Bit I/O expanders would allow you to exceed the amount of available RAM with two-position switches, at which point the compiler would refuse to build the sketch. The problem is what happens before that: when you get close to the limit but do not exceed it, the sketch will still compile, but the 2K RAM on the microcontroller won't be enough to hold all that data plus the call stack, so the call stack will overwrite part of the heap memory, at which point you get undefined behavior (i.e. very hard to debug problems). Unfortunately, it is not easy to determine exactly how large the stack will get in advance, either.

The most memory-efficient implementation I can think of would only need a single bit of RAM to store the last state (so you could pack the state for 8 Switch2Pos into one byte of memory). I could write some library code for that, but using it would require a working knowledge of C++.

The challenge is to find a middle ground where we have code that is reasonably efficient but still allows us to use C++ language features to hide the complexity, so copy-and-paste from the reference docs continues to be a thing.

@hectorlee
Copy link
Author

I see. Understand regarding needing to keep memory use down. I guess since not everyone will be using GPIO expanders then it would be better to keep it a separate item. I'm quite fine coding it separately for now. Maybe this current method could be documented/linked to from the official docs for people to know how to manually use GPIO expanders.

@jboecker jboecker closed this as completed May 2, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants