/* digio.c - Bit digital I/O.
 *  Copyright (C) 2022 by Jed Marti
 *   This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see https://www.gnu.org/licenses/.
 */


#include <C8051F380.h>
#include <stdint.h>

#include "config.h"
#include "lfxmit.h"
#include "storage.h"
#include "serial.h"

extern __bit              errorThrown;
extern __xdata floatOrInt IACC;
extern __xdata uint16_t   iONE;
extern __xdata uint16_t   iZERO;
extern uint16_t           DREG;

// Port control bit names values.
enum {
      in,
      out
};

enum {
      pp,
      od
};



#define port  IACC.i8.b8a
#define inout IACC.i8.b8b
#define ppod  IACC.i8.b8c
#define c     IACC.i8.b8d
void runDigDirection(void)
//     We have a direction command. The three values can be in any order:
//        DIRECTION [DIG0 | DIG1] [IN | OUT] [PP | OD];
// The defaults are dig0, in, open drain. In configuration, the port pins have to be on
// the same port (P2). 
{
  port = dig0;
  inout = in;
  ppod = od;

 loop:
  incPC();
  c = getPByte();
  if (c == DIG0) port = dig0;
  else if (c == DIG1) port = dig1;
  else if (c == IN) inout = in;
  else if (c == OUT) inout = out;
  else if (c == PP) ppod = pp;
  else if (c == OD) ppod = od;
  else if (c == SEMICOLON) goto setup;
  else
  {
    putstring("DIRECTION missing keyword\n");
    errorThrown = 1;
    return;
  }
  goto loop;


 setup:
  if (ppod == od) P2MDOUT &= ~port;
  else P2MDOUT |= port;
  if (inout == in) P2 |= port;
  else P2 &= ~port;
}

#undef port
#undef inout
#undef ppod
#undef c



static void digBit(__bit bt)
// Used below for pushing 0/1.
{
  if (bt) pushST(iONE);
  else pushST(iZERO);
}



void readDIG0(void)   { digBit(dig0bit); }
void readDIG1(void)   { digBit(dig1bit); }
void readRed(void)    { digBit(LED0); }
void readYellow(void) { digBit(LED1); }
void readGreen(void)  { digBit(LED2); }
void readBlue(void)   { digBit(LED3); }


void anyChar(void)
// Returns 1 if serial port has a character waiting and 0 if not.
{
  if (RI0 == 1) pushST(iONE);
  else pushST(iZERO);
}



static void set(void)
// Used below. Get the expression value into IACC. 0 is both 0 in int and float. Anything
// else (a string even) will be a 1.
{
  DREG = popST();
  getIACC();
}



void setDIG0(void)
// The result of DIG0 = ?;
{
  set();
  if (IACC.i == 0) dig0bit = 0;
  else dig0bit = 1;
}



void setDIG1(void)
// The result of DIG1 = ?;
{
  set();
  if (IACC.i == 0) dig1bit = 0;
  else dig1bit = 1;
}



void setRed(void)
// The result of RED = ?;
{
  set();
  if (IACC.i == 0) LED0 = 0;
  else LED0 = 1;
}
  


void setYellow(void)
// The result of YELLOW = ?;
{
  set();
  if (IACC.i == 0) LED1 = 0;
  else LED1 = 1;
}
  


void setGreen(void)
// The result of GREEN = ?
{
  set();
  if (IACC.i == 0) LED2 = 0;
  else LED2 = 1;
}



void setBlue(void)
// The result of BLUE = ?
{
  set();
  if (IACC.i == 0) LED3 = 0;
  else LED3 = 1;
}




// EOF
