/*
 * Copyright 2018 Martin Åberg
 *
 * This file is part of Footag.
 *
 * Footag 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.
 *
 * Footag 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 <http://www.gnu.org/licenses/>.
 */

#ifndef FOOTAG_IPC7351B_H
#define FOOTAG_IPC7351B_H

/*
 * This is an implementation of
 *   "IPC-7351B: Generic Requirements for Surface Mount Design and
 *   Land Pattern Standard"
 *
 * The document is available for purchase from IPC.
 *
 * The following parts of the standard are covered by the implementation:
 *   - Land pattern dimension and spacing calculations
 *   - Courtyard properties
 *
 * These parts are not implemented:
 *   - Land pattern naming convention
 * 
 * Note also that the following items are not part of IPC-7351B or this
 * implementation:
 *   - Silk screen
 *   - Assembly outline
 *
 * This implementation uses metric mm units exclusively.
 */

#include <footag/footol.h>

/*
 * The following lead dimensions convention is used in IPC-7351B. It applies to
 * different lead types.
 *
 *    | -------- l -------- |
 * _   _______       _______
 *    |       |     |       |
 * w  |       |     |       |  -
 * _  |_______|     |_______|  |
 *
 *                           pitch
 * _   _______       _______
 *    |       |     |       |  |
 * w  |       |     |       |  -
 * _  |_______|     |_______|
 *
 *    | - t - |
 *
 * The convention is used for describing leads and their relation.
 */
struct ipcb_comp {
        /* lead termination end to lead termination end */
        struct footol l;
        /* lead length */
        struct footol t;
        /* width of lead or termination */
        struct footol w;
};

/* Lead types are somewhat related to solder joint goal tables. */
enum ipcb_leadtype {
        IPCB_LEADTYPE_CHIP,
        IPCB_LEADTYPE_MOLDED,
        IPCB_LEADTYPE_GULLWING,
        IPCB_LEADTYPE_SIDECONCAVE,
        IPCB_LEADTYPE_NUM,
};

/*
 * - Density level {A,B,C} (Land pattern geometry variation)
 * or if you prefer:
 * - {Maximum (Most),Median (Nominal),Minimum (Least)} {Land
 *   protrusion,material condition}
 */
enum ipcb_density {
        IPCB_DENSITY_M,
        IPCB_DENSITY_N,
        IPCB_DENSITY_L,
        IPCB_DENSITY_NUM,
};

static const char IPCB_DENSITY_TO_CHAR[IPCB_DENSITY_NUM] = {'M','N','L'};

/* Attributes related to library policy. These are component independent. */
struct ipcb_attr {
        enum ipcb_density density;
        /* PCB fabrication tolerance */
        double f;
        /* Part placement tolerance */
        double p;
};

/* Output parameters generated by land dimension calculation functions. */

struct ipcb_ref {
        const char *where;
        const char *what;
};

/*
 * "Two-side" style
 *
 * Land dimensions convention used by the library
 *
 *    | - h - |
 * _   _______       _______
 *    |       |     |       |
 * w  |       |     |       |
 * _  |_______|     |_______|
 *
 *        | -- dist -- |
 */
struct ipcb_twospec {
        struct ipcb_ref ref;
        double smin;
        double zmax, gmin, xmax;
        double round;
        double cyexc;
        /* user friendly */
        struct {
                /* length between pad centers */
                double dist;
                double w;
                double h;
        } land;
};

/* BGA style */
struct ipcb_bgaspec {
        struct ipcb_ref ref;
        double diam;
};

/*
 * Calculate land dimensions for two-side style
 *
 * comp:        component dimensions
 * attr:        library policy attributes
 * spec:        result
 * return:      0 iff success
 */

int ipcb_get_chip(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_melf(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_molded(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

/* concave leads on sides and not at the corners */
int ipcb_get_sideconcave(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_concavearray(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_convexarray(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_flatarray(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_gullwing(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr,
        double pitch
);

int ipcb_get_jlead(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_son(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_qfn(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

int ipcb_get_pson(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr,
        double pullback
);

int ipcb_get_capae(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr,
        double height
);

int ipcb_get_sodfl(
        struct ipcb_twospec *spec,
        const struct ipcb_comp *comp,
        const struct ipcb_attr *attr
);

/*
 * Calculate land dimensions for BGA style
 *
 * diam:        nominal ball diameter
 * spec:        result
 * return:      0 iff success
 */
int ipcb_get_bga(
        struct ipcb_bgaspec *spec,
        double diam,
        int collapsing
);

#endif

