// Pin header footprint for a RP2040-based controller board from AliExpress.
// Doesn't really have a name, it's just "the purple one with USB-C".
// The pinout differs from the Raspberry Pi Pico!
// -------------------------------
// Params
//  orientation: if up (default), the controller will be on the front side of the PCB, otherwise on the back side

module.exports = {
    params: {
        designator: 'MCU',
        orientation: 'up',

        // Right side of pins (with USB port at the top), top to bottom
        VBUS: {type: 'net', value: 'VBUS'},
        VIN: {type: 'net', value: 'VIN'},
        GND: {type: 'net', value: 'GND'},
        '3V3_EN': {type: 'net', value: '3V3_EN'},
        '3V3': {type: 'net', value: '3V3'},
        // (GND pin)
        RUN: {type: 'net', value: 'RUN'},  // Reset pin: Pull down to reset
        GP29: {type: 'net', value: 'GP29'},  // also: ADC3
        GP28: {type: 'net', value: 'GP28'},  // also: ADC2
        GP27: {type: 'net', value: 'GP27'},  // also: ADC1
        GP26: {type: 'net', value: 'GP26'},  // also: ADC0
        AGND: {type: 'net', value: 'AGND'},
        GP25: {type: 'net', value: 'GP25'},
        GP24: {type: 'net', value: 'GP24'},
        GP23: {type: 'net', value: 'GP23'},
        GP22: {type: 'net', value: 'GP22'},
        GP21: {type: 'net', value: 'GP21'},
        GP20: {type: 'net', value: 'GP20'},
        GP19: {type: 'net', value: 'GP19'},
        GP18: {type: 'net', value: 'GP18'},

        // Left side of pins (with USB port at the top), top to bottom
        GP0: {type: 'net', value: 'GP0'},
        GP1: {type: 'net', value: 'GP1'},
        GP2: {type: 'net', value: 'GP2'},
        GP3: {type: 'net', value: 'GP3'},
        GP4: {type: 'net', value: 'GP4'},
        // (GND pin)
        GP5: {type: 'net', value: 'GP5'},
        GP6: {type: 'net', value: 'GP6'},
        GP7: {type: 'net', value: 'GP7'},
        GP8: {type: 'net', value: 'GP8'},
        GP9: {type: 'net', value: 'GP9'},
        GP10: {type: 'net', value: 'GP10'},
        GP11: {type: 'net', value: 'GP11'},
        GP12: {type: 'net', value: 'GP12'},
        // (GND pin)
        GP13: {type: 'net', value: 'GP13'},
        GP14: {type: 'net', value: 'GP14'},
        GP15: {type: 'net', value: 'GP15'},
        GP16: {type: 'net', value: 'GP16'},
        GP17: {type: 'net', value: 'GP17'},
    },
    body: p => {
        let def_neg, def_pos, side, mirror;
        if (p.orientation === 'down') {
            def_neg = '';
            def_pos = '-';
            side = 'B';
            mirror = 'mirror';
        } else {
            def_neg = '-';
            def_pos = '';
            side = 'F';
            mirror = '';
        }

        const PINS_PER_SIDE = 20;
        const PINS_PER_SIDE_HALF = 10;

        const pins_left = [
            'GP0', 'GP1', 'GP2', 'GP3', 'GP4', 'GND', 'GP5', 'GP6', 'GP7', 'GP8',
            'GP9', 'GP10', 'GP11', 'GP12', 'GND', 'GP13', 'GP14', 'GP15', 'GP16', 'GP17',
        ];
        const pins_right = [
            'VBUS', 'VIN', 'GND', '3V3_EN', '3V3', 'GND', 'RUN', 'GP29', 'GP28', 'GP27',
            'GP26', 'AGND', 'GP25', 'GP24', 'GP23', 'GP22', 'GP21', 'GP20', 'GP19', 'GP18',
        ];

        function pin_pos_y(pin_number) {
            // Fucking floating points...
            return (254 * (pin_number - PINS_PER_SIDE_HALF) + 127) / 100;
        }

        function pin_labels(pin_names, right_side) {
            const sign = right_side ? def_pos : def_neg;
            const justify = right_side ? 'right' : 'left';
            let pin_label_body = '';

            for (let i = 0; i < PINS_PER_SIDE; i++) {
                pin_label_body += `
                    (fp_text user ${pin_names[i]} (at ${sign}7.62 ${pin_pos_y(i)} ${p.r}) (unlocked yes) (layer ${side}.SilkS)
                        (effects (font (size 0.8 0.8) (thickness 0.15)) (justify ${justify} ${mirror}))
                    )`;
            }
            return pin_label_body;
        }

        function pin_pads(pin_names, right_side) {
            const sign = right_side ? def_pos : def_neg;
            const offset = right_side ? 21 : 1;
            let pin_pad_body = '';

            for (let i = 0; i < PINS_PER_SIDE; i++) {
                pin_pad_body += `
                    (pad ${i + offset} thru_hole circle (at ${sign}8.89 ${pin_pos_y(i)} 0)
                        (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.Mask) ${p[pin_names[i]]}
                    )`;
            }
            return pin_pad_body;
        }

        return `
            (module RP2040_USB_C_Purple (layer F.Cu) (tedit 66A6C4CD)
                ${p.at /* parametric position */}

                ${'' /* footprint reference */}
                (fp_text reference "${p.ref}" (at 0 0) (layer ${side}.SilkS) ${p.ref_hide} (effects (font (size 1.27 1.27) (thickness 0.15))))
                (fp_text value "" (at 0 0) (layer ${side}.SilkS) hide (effects (font (size 1.27 1.27) (thickness 0.15))))

                ${'' /* component outline */}
                (fp_line (start -10.16 -28.6) (end  10.16 -28.6) (layer ${side}.SilkS) (width 0.15))
                (fp_line (start  10.16 -28.6) (end  10.16  25.4) (layer ${side}.SilkS) (width 0.15))
                (fp_line (start  10.16  25.4) (end -10.16  25.4) (layer ${side}.SilkS) (width 0.15))
                (fp_line (start -10.16  25.4) (end -10.16 -28.6) (layer ${side}.SilkS) (width 0.15))

                ${'' /* pin labels */}
                ${pin_labels(pins_left, false)}
                ${pin_labels(pins_right, true)}

                ${'' /* pin pads */}
                ${pin_pads(pins_left, false)}
                ${pin_pads(pins_right, true)}
            )
        `;
    }
}
