/**
	@file
	boardout - a max object shell (Arduino UNO board outputs)
 
	@ingroup	examples
 */


// Firmata-for-Max Library headers
#include "maxlib.h"

// required Max core headers
#include "ext.h"							// standard Max include, always required
#include "ext_obex.h"						// required for new style Max object


////////////////////////// object struct
typedef struct boardout
{
    // the Max object itself (must be first)
    t_object                    ob;
    
    // Arduino board connection
    board_t                     *board_ob;
    
    
    // selected pins to write
    long                        pinsCount;
    long                        pinsArray[TOTAL_OUT_PINS];
    long                        valuesArray[TOTAL_OUT_PINS];
    long                        modesArray[TOTAL_OUT_PINS];
    
    // boardin attributes:
    t_symbol                    *att_portname;
    t_symbol                    *att_baudrate;
    long                        att_digitalPins[TOTAL_OUT_PINS], digitalPinsCount;
    long                        att_servoPins[TOTAL_OUT_PINS], servoPinsCount;
    long                        att_pwmPins[TOTAL_OUT_PINS], pwmPinsCount;
    
    // hardware attributes:
    t_symbol                    *att_pin_modes[TOTAL_OUT_PINS];
    
} t_boardout;

///////////////////////// function prototypes
//// standard set
void *boardout_new(t_symbol *s, long argc, t_atom *argv);
void boardout_free(t_boardout *x);
void boardout_assist(t_boardout *x, void *b, long m, long a, char *s);
void boardout_print(t_boardout *x);

//privates
void boardout_printAvailPorts(t_boardout *x);
void boardout_updatePin(t_boardout *x, int index, int val);
void boardout_updateServo(t_boardout *x, int index, int val);
void boardout_updateDigital(t_boardout *x, int index, int val);
void boardout_updatePwm(t_boardout *x, int index, int val);
int  boardout_parseArgs(t_boardout *x, long argc, t_atom *argv);
int  boardout_getBaudRate(t_boardout *x);
bool boardout_pinNumAlreadyExists(t_boardout *x, int pin);
int  boardout_getBoard(t_boardout *x);
int  boardout_pinDigitalRange(int pin);
int  boardout_pinAnalogRange(int pin);
int  boardout_pinPwmRange(int pin);

//internals
//t_max_err boardout_digitalPins_get(t_boardout *x, t_object *attr, long *argc, t_atom **argv);
t_max_err boardout_digitalPins_set(t_boardout *x, t_object *attr, long argc, t_atom *argv);
//t_max_err boardout_servoPins_get(t_boardout *x, t_object *attr, long *argc, t_atom **argv);
t_max_err boardout_servoPins_set(t_boardout *x, t_object *attr, long argc, t_atom *argv);
//t_max_err boardout_pwmPins_get(t_boardout *x, t_object *attr, long *argc, t_atom **argv);
t_max_err boardout_pwmPins_set(t_boardout *x, t_object *attr, long argc, t_atom *argv);

void boardout_in1(t_boardout *x, long n);
void boardout_in2(t_boardout *x, long n);
void boardout_in3(t_boardout *x, long n);
void boardout_in4(t_boardout *x, long n);
void boardout_in5(t_boardout *x, long n);
void boardout_in6(t_boardout *x, long n);
void boardout_in7(t_boardout *x, long n);
void boardout_in8(t_boardout *x, long n);
void boardout_in9(t_boardout *x, long n);
void boardout_in10(t_boardout *x, long n);
void boardout_in11(t_boardout *x, long n);
void boardout_in12(t_boardout *x, long n);


//////////////////////// global class pointer variable
void *boardout_class;

void ext_main(void *r)
{
    t_class *c;
    
    c = class_new("cr.boardout", (method)boardout_new, (method)boardout_free,
                  (long)sizeof(t_boardout),
                  0L /* leave NULL!! */, A_GIMME, 0);
    
    /* you CAN'T call this from the patcher */
    class_addmethod(c, (method)boardout_assist,      "assist",  A_CANT,     0);
    class_addmethod(c, (method)boardout_print,       "print",               0);
    
    class_addmethod(c, (method)boardout_in1,         "in1",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in2,         "in2",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in3,         "in3",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in4,         "in4",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in5,         "in5",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in6,         "in6",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in7,         "in7",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in8,         "in8",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in9,         "in9",     A_LONG,     0);
    class_addmethod(c, (method)boardout_in10,        "in10",    A_LONG,     0);
    class_addmethod(c, (method)boardout_in11,        "in11",    A_LONG,     0);
    class_addmethod(c, (method)boardout_in12,        "in12",    A_LONG,     0);
    
    class_register(CLASS_BOX, c); /* CLASS_NOBOX */
    boardout_class = c;
    
    // set attributes
    
    CLASS_ATTR_SYM(c, "portname", 0, t_boardout, att_portname);
    CLASS_ATTR_LABEL(c, "portname", 0, "Serial Port");
    //CLASS_ATTR_ENUM(c, "portname", 0, "");
    // Disable editing attribute in Inspector - Read Only!
    CLASS_ATTR_ACCESSORS(c, "portname", NULL, NULL);
    
    //char* baudratestr = "\"300\" \"1200\" \"2400\" \"4800\" \"9600\" \"14400\" \"19200\" \"28800\" \"38400\" \"57600\" \"115200\"";
    CLASS_ATTR_SYM(c, "baud", 0, t_boardout, att_baudrate);
    CLASS_ATTR_LABEL(c, "baud", 0, "Baud Rate (analog)");
    //CLASS_ATTR_ENUM(c, "baud", 0, baudratestr);
    CLASS_ATTR_ACCESSORS(c, "baud", NULL /*boardout_att_baudrate_get*/, NULL /*boardout_att_baudrate_set*/);
    
    CLASS_ATTR_LONG_VARSIZE(c, "digitalPins", 0, t_boardout, att_digitalPins, digitalPinsCount, TOTAL_OUT_PINS);
    CLASS_ATTR_LABEL(c, "digitalPins", 0, "Digital Pins (read only)");
    // Disable editing attribute in Inspector - Read Only!
    CLASS_ATTR_ACCESSORS(c, "digitalPins", NULL /*boardout_digitalPins_get*/, boardout_digitalPins_set);
    
    CLASS_ATTR_LONG_VARSIZE(c, "servoPins", 0, t_boardout, att_servoPins, servoPinsCount, TOTAL_OUT_PINS);
    CLASS_ATTR_LABEL(c, "servoPins", 0, "Servo Pins (read only)");
    // Disable editing attribute in Inspector - Read Only!
    CLASS_ATTR_ACCESSORS(c, "servoPins", NULL /*boardout_servoPins_get*/, boardout_servoPins_set);
    
    CLASS_ATTR_LONG_VARSIZE(c, "pwmPins", 0, t_boardout, att_pwmPins, pwmPinsCount, TOTAL_OUT_PINS);
    CLASS_ATTR_LABEL(c, "pwmPins", 0, "pwm Pins (read only)");
    // Disable editing attribute in Inspector - Read Only!
    CLASS_ATTR_ACCESSORS(c, "pwmPins", NULL /*boardout_pwmPins_get*/, boardout_pwmPins_set);
    
    // attributes order of appearance  in the inspector
    CLASS_ATTR_ORDER(c, "portname", 0, "1");
    CLASS_ATTR_ORDER(c, "baud", 0, "2");
    CLASS_ATTR_ORDER(c, "digitalPins", 0, "3");
    CLASS_ATTR_ORDER(c, "servoPins", 0, "4");
    CLASS_ATTR_ORDER(c, "pwmPins", 0, "5");
    
    post("Arduino UNO boardout object created (Writer).");
    
}

void boardout_assist(t_boardout *x, void *b, long m, long a, char *s)
{
    if (m == ASSIST_INLET) { // inlet
        
        if(a == 0) {
            sprintf(s, "inlet %ld - no pins", a);
        }
        else {
            
            char *str;
            
            // pin index is inlet-1
            int index = a-1;
            int pin = x->pinsArray[index];
            
            switch(x->modesArray[index]) {
                case MODE_OUTPUT:
                    sprintf(s, "pin D%d mode DIGITAL", pin);
                    break;
                case MODE_SERVO:
                    if(pin > 13)
                        sprintf(s, "pin %d (A%d) mode SERVO", pin+PIN_OFFSET, pin+PIN_OFFSET-20);
                    else
                        sprintf(s, "pin D%d mode SERVO", pin);
                    break;
                case MODE_PWM:
                    sprintf(s, "pin D%d mode PWM", pin);
                    break;
                default:
                    sprintf(s, "pin D%d mode UNKNOWN", pin);
                    str = "UNKNOWN";
            }
        }
    }
    else {	// outlet
        sprintf(s, "I am outlet %ld", a);
    }
}

void boardout_free(t_boardout *x)
{
    if(x == NULL) return;
    
    if(x->att_portname) {
        
        if(x->att_portname->s_thing) {
            board_mgr_t *mgr = ((board_mgr_t *)(x->att_portname->s_thing));
            if(mgr->board_out != NULL) { // && mgr->board_out == x->board_ob) {
                
                //release the boardin connection
                //post("disconnecting boardout object"); //debug
                mgr->board_out = NULL;
                //post("boardout disconnected"); //debug
            }
            //debug
            else {
                post("error, boardout wasn't found");
            }
            
            if(mgr->board_in == NULL) {
                
                // no reader board is connected, release the port altogether
                //post("closing the port"); //debug
                int val = maxclient_shutdown(x->board_ob);  // close port
                if(val == -1) {
                    post("error shutting down, %s", x->board_ob->err_msg);
                    return;
                }
                //debug
                //else {
                //    post("boardout shut down");
                //}
                x->att_portname->s_thing = NULL;
                free(mgr);
                //mgr->board = NULL;
                //mgr->board_out = NULL;
            }
            //debug
            //else {
            //    post("boardin object found");
            //}
        }
        
        //debug
        //else {
        //post("port is not in use by any other board object");
        //}
    }
    
    //debug
    //else {
    //    post("no portname found");
    //}
    
    
    //if (x->board_ob != NULL) {
    //   free(x->board_ob);
    //   post("board object deleted");
    //}
    
    //post("boardout object deleted"); //debug
    
}

void *boardout_new(t_symbol *s, long argc, t_atom *argv)
{
    t_boardout *x = (t_boardout *)object_alloc(boardout_class);
    
    if(x == NULL) {
        post( "Max is out of memory, could not create new boardout object.");
        return NULL;
    }
    
    x->board_ob = NULL;
    
    // parse input arguments to set up object
    if (boardout_parseArgs(x, argc, argv) == -1) {
        //Error - Invalid arguments
        object_error((t_object *)x, "Boardout args are invalid, could not create new boardout object.");
        //object_free(x);
        return (x);
    }
    
    
    // init all pin modes to DIGITAL MODE at first
    for (int i = 0; i < TOTAL_OUT_PINS; ++i) {
        x->att_pin_modes[i] = gensym("DIGITAL");
    }
    
    // debug:
    //if(x->att_portname && x->att_baudrate) {
    //    object_post((t_object *)x, "port name: %s\t rate: %d", x->att_portname->s_name, atoi(x->att_baudrate->s_name));
    //}
    
    // connect to port (board) and set board configuration as requested
    int len_config = x->digitalPinsCount + x->servoPinsCount + x->pwmPinsCount;
    int pins[len_config];
    int modes[len_config];
    
    int len = 0;
    // digital pins
    for(int i=0; i<x->digitalPinsCount; ++i) {
        pins[len] = x->att_digitalPins[i];
        modes[len] = MODE_OUTPUT;
        len++;
    }
    // servo pins
    for(int i=0; i<x->servoPinsCount; ++i) {
        pins[len] = x->att_servoPins[i];
        modes[len] = MODE_SERVO;
        len++;
    }
    // pwm pins
    for(int i=0; i<x->pwmPinsCount; ++i) {
        pins[len] = x->att_pwmPins[i];
        modes[len] = MODE_PWM;
        len++;
    }
    
    // create pin integer inlets
    for (int i = x->pinsCount; i > 0; --i) {
        // create int inlets from right to left (highest-right to 1-left):
        intin(x, i);
    }
    
    if( ! x->att_portname)
        return (x);
    // create a new writing board and init
    int result = boardout_getBoard(x);
    if(result != 0) {
        object_error((t_object *)x, "Boardout couldn't create a connection to board");
        return (x);
    }
    
    result = maxclient_connect(x->board_ob, len_config, pins, modes, OUT_BOARD);
    if( result != 0) {
        object_error((t_object *)x, "Boardout couldn't connect to board.");
        return (x);
    }
    
    return (x);
}

void boardout_print(t_boardout *x){
    boardout_printAvailPorts(x);
}

void boardout_updatePin(t_boardout *x, int inlet, int val) {
    
    char *str;
    
    // pin index is inlet-1
    int index = inlet-1;
    
    switch(x->modesArray[index]) {
        case MODE_OUTPUT:
            boardout_updateDigital(x, index, val);
            str = "DIGITAL";
            break;
        case MODE_SERVO:
            boardout_updateServo(x, index, val);
            str = "SERVO";
            break;
        case MODE_PWM:
            boardout_updatePwm(x, index, val);
            str = "PWM";
            break;
        default:
            str = "UNKNOWN";
            post("unidentified mode selected"); // error
    }
    
    //object_post((t_object *)x, "%s pin %ld: %ld", str, x->pinsArray[index], x>valuesArray[index]); //debug
    
}

void boardout_updateDigital(t_boardout *x, int index, int val) {
    val = (val>0? 1 : 0);
    x->valuesArray[index] = val;
    int pin = x->pinsArray[index];
    maxclient_toggleDigital(x->board_ob, pin, val);
}

void boardout_updateServo(t_boardout *x, int index, int val) {
    if (val < 0) val = 0;
    if (val > 170) val = 170;
    x->valuesArray[index] = val;
    int pin = x->pinsArray[index];
    maxclient_moveServo(x->board_ob, pin, val);
}

void boardout_updatePwm(t_boardout *x, int index, int val) {
    if (val < 0) val = 0;
    if (val > 170) val = 170;
    x->valuesArray[index] = val;
    int pin = x->pinsArray[index];
    maxclient_movePwm(x->board_ob, pin, val);
}


/*
 PRIVATE INTERNAL FUNCTIONS
 */

int boardout_parseArgs(t_boardout *x, long argc, t_atom *argv)
{
    // get updated list of available ports
    char *ports_avail[MAX_PORTS];
    int num_ports = serial_portlist(ports_avail, MAX_PORTS);
    
    // set baud rate to default
    char str[20];
    sprintf(str, "%d", DEFAUTLT_BAUD);
    x->att_baudrate = gensym(str);
    
    // parse input arguments
    int i = 0;
    
    // check if the first argument is the port index
    if(argv->a_type == A_SYM){
        char *portCh = atom_getsym(argv)->s_name;
        //object_post((t_object *)x, "port char: %c", portCh[0]); //debug
        int index = portCh[0]-'a';
        //object_post((t_object *)x, "port index: %d", index);  //debug
        
        if (index >= 0 && index < num_ports) {
            //strncpy(x->portname, ports_avail[index], MAX_PORT_NAME);
            x->att_portname = gensym(ports_avail[index]);
            if(x->att_portname->s_thing == NULL) {
                // the port is not in use by other boardin/out objects
                board_mgr_t *mgr = (board_mgr_t*)malloc(sizeof(board_mgr_t)); //newPortMgr(IN_BOARD);
                mgr->board_out = NULL;
                mgr->board_in = NULL;
                mgr->board = NULL;
                x->att_portname->s_thing = (t_object*)mgr;
            }
            //x->att_portname->s_thing = NULL;  //TODO add ref to the serial port
            //object_post((t_object *)x, "port name is: (%s)", x->att_portname->s_name); // debug
            //object_post((t_object *)x, "port thing is: (%s)", x->att_portname->s_thing); //debug
            i = 1;
        }
    }
    
    // Parse DIGITAL SERVO PWM pins lists
    bool servoFound = false, digitalFound = false, pwmFound = false;
    x->pinsCount = 0;
    x->pwmPinsCount = 0;
    x->servoPinsCount = 0;
    x->digitalPinsCount = 0;
    
    for (; i < argc; i++) {
        
        if((argv+i)->a_type == A_SYM) {
            
            t_symbol *s = atom_getsym(argv+i);
            
            // if the symbol is digital
            if( ! strcmp_case_insensitive(s->s_name, "@digital")) {
                //post("Found DIGITAL");
                digitalFound = true;
                servoFound = false;
                pwmFound = false;
            }
            // if symbol is servo
            else if( ! strcmp_case_insensitive(s->s_name, "@servo")) {
                //post("Found SERVO");
                servoFound = true;
                digitalFound = false;
                pwmFound = false;
            }
            // if symbol is pwm
            else if( ! strcmp_case_insensitive(s->s_name, "@pwm")) {
                //post("Found PWM");
                pwmFound = true;
                servoFound = false;
                digitalFound = false;
            }
            // if symbol is baud
            else if( ! strcmp_case_insensitive(s->s_name, "@baud")) {
                //post("Found BAUD");
                digitalFound = false;
                servoFound = false;
                pwmFound = false;
                // check if the baud rate was entered as input
                if((argv+i+1)->a_type == A_LONG) {
                    // move to the next input atom for the baud rate
                    i++;
                    //x->baudrate = atom_getlong(argv+i);
                }
            }
            else {
                // otherwise, unknown attribute symbol
                digitalFound = false;
                servoFound = false;
                pwmFound = false;
                // error
                object_error((t_object *)x, "forbidden argument %s", s->s_name);
                //return -1;
            }
        }
        
        else if((argv+i)->a_type == A_LONG) {
            
            int pin = atom_getlong(argv+i);
            
            if((servoFound || digitalFound || pwmFound) && x->pinsCount < TOTAL_OUT_PINS) {
                
                if(servoFound) {
                    if(boardout_pinAnalogRange(pin)) {
                        // if the pin is analog, then substruct PIN_OFFSET
                        // Digital pins [D0-D13] are numbered  0-13 indexed as  0-13 in Firmata
                        // Analog  pins [A0-A5]  are numbered 20-25 indexed as 14-19 in Firmata
                        pin -= PIN_OFFSET;
                    }
                    else if (!boardout_pinDigitalRange(pin)) {
                        // error
                        object_error((t_object *)x, "Invalid pin number %d, servo pins range [0-13, 20-25]", pin);
                        return 0;
                    }
                }
                
                if(pwmFound && !boardout_pinPwmRange(pin)) {
                    // error
                    object_error((t_object *)x, "Invalid pin number %d, pwm pins range [3,5,6,9,10,11]", pin);
                    return 0;
                }
                
                if(digitalFound && !boardout_pinDigitalRange(pin)) {
                    // error
                    object_error((t_object *)x, "Invalid pin number %d, digital pins range [0-13]", pin);
                    return 0;
                }
                
                // also check if the requested pin already exists
                if(boardout_pinNumAlreadyExists(x, pin)) {
                    // error
                    object_error((t_object *)x, "forbidden argument, pin %d already exists", pin);
                }
                
                // we verified the pin does not exist, add it now
                else {
                    x->pinsArray[x->pinsCount] = pin;
                    x->valuesArray[x->pinsCount] = 0;
                    if(servoFound) {
                        x->modesArray[x->pinsCount] = MODE_SERVO;
                        x->att_servoPins[x->servoPinsCount] = pin;
                        x->servoPinsCount++;
                    }
                    else if(digitalFound) {
                        x->modesArray[x->pinsCount] = MODE_OUTPUT;
                        x->att_digitalPins[x->digitalPinsCount] = pin;
                        x->digitalPinsCount++;
                    }
                    else if(pwmFound) {
                        x->modesArray[x->pinsCount] = MODE_PWM;
                        x->att_pwmPins[x->pwmPinsCount] = pin;
                        x->pwmPinsCount++;
                    }
                    
                    x->pinsCount++;
                }
            }
            
            else {
                // error
                if(x->pinsCount >= TOTAL_OUT_PINS) {
                    object_error((t_object *)x, "forbidden argument, too many pins requested");
                    //return -1;
                }
                object_error((t_object *)x, "forbidden argument, number %d is out of context", pin);
                //return -1;
            }
        }
        
        else {
            // error
            object_error((t_object *)x, "forbidden argument, expected format:");
            object_error((t_object *)x, "[port] [@digital pins_list] [@servo pins_list] [@pwm pins_list]");
            //return -1;
            
        }
    }
    return 0;
}

void boardout_printAvailPorts(t_boardout *x) {
    
    char *ports_avail[MAX_PORTS];
    
    int num_ports = serial_portlist(ports_avail, MAX_PORTS);
    
    for(int i=0; i<num_ports; ++i) {
        object_post((t_object *)x, "port %c: %s", i+'a', ports_avail[i]);
    }
}

bool boardout_pinNumAlreadyExists(t_boardout *x, int pin) {
    
    for (int i = 0; i<x->digitalPinsCount; ++i) {
        if(x->att_digitalPins[i] == pin)
            return true;
    }
    
    for (int i = 0; i<x->servoPinsCount; ++i) {
        if(x->att_servoPins[i] == pin)
            return true;
    }
    
    for (int i = 0; i<x->pwmPinsCount; ++i) {
        if(x->att_pwmPins[i] == pin)
            return true;
    }
    
    return false;
}

int boardout_getBoard(t_boardout *x) {
    
    if(!x || !x->att_portname || !x->att_portname->s_thing) return 1;
    
    // requested port is not connected to by any other board object, then
    // create a new Arduino board object,  initialise and connect to (serial) port
    
    board_mgr_t *mgr = ((board_mgr_t *)(x->att_portname->s_thing));
    if(mgr->board_out != NULL) {
        
        // error - there is already another boardout object connected
        object_error((t_object *)x, "connect: port name: %s is already occupied with another boardout object!", x->att_portname->s_name);
        return -1;
    }
    
    else if(mgr->board_in != NULL) {
        
        // there is already a boardin object connected
        //object_post((t_object *)x, "connect: boardin found");   // debug
        //object_post((t_object *)x, "x->board_object=%s", x->board_ob); //debug
        x->board_ob = mgr->board;
        mgr->board_out = x;
    }
    
    else {
        
        object_post((t_object *)x, "NEW BOARD IS BEING CREATED");
        
        char err_return[4000];
        x->board_ob = maxclient_newboard(x->att_portname->s_name, atoi(x->att_baudrate->s_name), err_return);
        // verify succeful memory allocation
        if(x->board_ob == NULL) {
            // error there is already another boardout object connected
            object_error((t_object *)x, "Max could not create new boardout object.");
            object_error((t_object *)x, "%s", err_return);
            return -1;
        }
        
        //board_mgr_t *mgr = (board_mgr_t*)malloc(sizeof(board_mgr_t));
        mgr->board = x->board_ob;
        mgr->board_out = x;
    }
    
    return 0;
}

int boardout_pinDigitalRange(int pin) {
    return ((pin < 14 && pin >=0)? 1 : 0);
}

int boardout_pinAnalogRange(int pin) {
    return ((pin < 26 && pin >=20)? 1 : 0);
}

int boardout_pinPwmRange(int pin) {
    // range = {3, 5, 6, 9, 10, 11};
    return ((pin==3 || pin==5 || pin==6 || pin==9 || pin==10 || pin==11)? 1 : 0);
}


/*
 INTERNALS
 */

t_max_err boardout_digitalPins_get(t_boardout *x, t_object *attr, long *argc, t_atom **argv) {
    return MAX_ERR_NONE;
}

t_max_err boardout_digitalPins_set(t_boardout *x, t_object *attr, long argc, t_atom *argv) {
    return MAX_ERR_NONE;
}

t_max_err boardout_servoPins_get(t_boardout *x, t_object *attr, long *argc, t_atom **argv) {
    return MAX_ERR_NONE;
}

t_max_err boardout_servoPins_set(t_boardout *x, t_object *attr, long argc, t_atom *argv) {
    return MAX_ERR_NONE;
}

t_max_err boardout_pwmPins_get(t_boardout *x, t_object *attr, long argc, t_atom *argv) {
    return MAX_ERR_NONE;
}

t_max_err boardout_pwmPins_set(t_boardout *x, t_object *attr, long argc, t_atom *argv) {
    return MAX_ERR_NONE;
}

void boardout_in1(t_boardout *x, long n) {
    boardout_updatePin(x, 1, n);
}

void boardout_in2(t_boardout *x, long n) {
    boardout_updatePin(x, 2, n);
}

void boardout_in3(t_boardout *x, long n) {
    boardout_updatePin(x, 3, n);
}

void boardout_in4(t_boardout *x, long n) {
    boardout_updatePin(x, 4, n);
}

void boardout_in5(t_boardout *x, long n) {
    boardout_updatePin(x, 5, n);
}

void boardout_in6(t_boardout *x, long n) {
    boardout_updatePin(x, 6, n);
}

void boardout_in7(t_boardout *x, long n) {
    boardout_updatePin(x, 7, n);
}

void boardout_in8(t_boardout *x, long n) {
    boardout_updatePin(x, 8, n);
}

void boardout_in9(t_boardout *x, long n) {
    boardout_updatePin(x, 9, n);
}

void boardout_in10(t_boardout *x, long n) {
    boardout_updatePin(x, 10, n);
}

void boardout_in11(t_boardout *x, long n) {
    boardout_updatePin(x, 11, n);
}

void boardout_in12(t_boardout *x, long n) {
    boardout_updatePin(x, 12, n);
}

