1 /*
2 VeroRoute - Qt based Veroboard/Perfboard/PCB layout & routing application.
3
4 Copyright (C) 2017 Alex Lawrow ( dralx@users.sourceforge.net )
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #pragma once
21
22 #include "Persist.h"
23
24 // "Pin" is a base class for "CompElement" and "Element".
25 // A component's spatial layout (or "Footprint") is a two-dimensional array of "CompElement" objects.
26 // The "Board" object used for designing a circuit is a two-dimensional array of "Element" objects.
27 //
28 // There are 3 parts to the description of a "Pin":
29 //
30 // 1) The pin character "m_pinChar" is just a pinIndex in the range 0 to 254.
31 // Places with no pin (e.g. the middle of a resistor) have m_pinChar of 255 and an invalid pinIndex.
32 //
33 // 2) The surface occupancy "m_surface" models the interaction between a component and the board surface.
34 //
35 // SURFACE_FREE ==> the board surface is not occupied.
36 // SURFACE_GAP ==> the gap between IC pins.
37 // SURFACE_WIRE_END ==> a wire (endpoint).
38 // SURFACE_WIRE ==> a wire (not endpoint).
39 // SURFACE_PLUG ==> e.g. resistor/diode/pad etc. Can be placed in a "GAP".
40 // SURFACE_FULL ==> the board surface is fully occupied. Nothing else can be placed there.
41 // SURFACE_NOPAINT ==> If this bit is set, then no paint can be applied.
42 // SURFACE_HOLE ==> SURFACE_FULL + SURFACE_NOPAINT
43 //
44 // 3) The hole occupancy "m_holeUse" models the interaction between a component and the board holes.
45 //
46 // HOLE_FREE ==> the hole is not occupied.
47 // HOLE_WIRE ==> the hole is occupied by one wire.
48 // HOLE_FULL ==> the hole is fully occupied. (By a regular component pin, or by 2 wires).
49
50 static const uchar BAD_PINCHAR = 255;
51 static const size_t BAD_PININDEX = static_cast<size_t>(-1);
52
53 static const uchar SURFACE_FREE = 0;
54 static const uchar SURFACE_GAP = 1;
55 static const uchar SURFACE_WIRE_END = 2; // Hence: "SURFACE_WIRE_END + SURFACE_WIRE_END == SURFACE_WIRE"
56 static const uchar SURFACE_WIRE = 4; // Hence: "SURFACE_WIRE + SURFACE_WIRE == SURFACE_PLUG"
57 static const uchar SURFACE_PLUG = 8;
58 static const uchar SURFACE_FULL = 9; // Hence: "SURFACE_PLUG + SURFACE_GAP == SURFACE_FULL"
59 static const uchar SURFACE_NOPAINT = 16; // Should only be used as part of SURFACE_HOLE
60 static const uchar SURFACE_HOLE = 25; // Hence: "SURFACE_FULL + SURFACE_NOPAINT = SURFACE_HOLE"
61
62 static const uchar HOLE_FREE = 0;
63 static const uchar HOLE_WIRE = 1; // Hence: "HOLE_WIRE + HOLE_WIRE == HOLE_FULL"
64 static const uchar HOLE_FULL = 2;
65
GetPinIndexFromLegacyPinChar(const uchar & c)66 static size_t GetPinIndexFromLegacyPinChar(const uchar& c) // Legacy VRT format had messy mapping of pinChar to pinIndex
67 {
68 if ( c < '1' ) return BAD_PININDEX; // Handles the '.', '-', '+' characters used by GetMakeInstructions()
69 if ( c <= '9' ) return c - '1'; // Char '1' to '9' ==> Index 0 to 8
70 if ( c <= '@' ) return 61 + c - ':'; // Char ':' to '@' ==> Index 61 to 67
71 if ( c <= 'Z' ) return 9 + c - 'A'; // Char 'A' to 'Z' ==> Index 9 to 34
72 if ( c <= '`' ) return 68 + c - '['; // Char '[' to '`' ==> Index 68 to 73
73 if ( c <= 'z' ) return 35 + c - 'a'; // Char 'a' to 'z' ==> Index 35 to 60
74 else return 74 + c - '{'; // Char '{' to 255 ==> Index 74 to 206
75 }
76
GetSurfaceFromLegacySurfaceChar(const uchar & c)77 static uchar GetSurfaceFromLegacySurfaceChar(const uchar& c)
78 {
79 // The following are the old SURFACE codes before the introduction of SURFACE_WIRE_END and SURFACE_WIRE
80 switch( c )
81 {
82 case 0: return SURFACE_FREE;
83 case 1: return SURFACE_GAP;
84 case 2: return SURFACE_PLUG;
85 case 3: return SURFACE_FULL;
86 case 4: return SURFACE_NOPAINT;
87 case 7: return SURFACE_HOLE;
88 default: assert(0); return SURFACE_FREE;
89 }
90 }
91
92 class Pin : public Persist, public Merge
93 {
94 public:
95 Pin(uchar pinChar = BAD_PINCHAR, uchar surface = SURFACE_FREE, uchar holeUse = HOLE_FREE)
m_pinChar(pinChar)96 : m_pinChar(pinChar)
97 , m_surface(surface)
98 , m_holeUse(holeUse)
99 {}
Pin(const Pin & o)100 Pin(const Pin& o) { *this = o; }
~Pin()101 virtual ~Pin() {}
102 Pin& operator=(const Pin& o)
103 {
104 m_pinChar = o.m_pinChar;
105 m_surface = o.m_surface;
106 m_holeUse = o.m_holeUse;
107 return *this;
108 }
109 bool operator==(const Pin& o) const // Compare persisted info
110 {
111 return m_pinChar == o.m_pinChar
112 && m_surface == o.m_surface
113 && m_holeUse == o.m_holeUse;
114 }
115 bool operator!=(const Pin& o) const
116 {
117 return !(*this == o);
118 }
SetPinIndex(const size_t & i)119 void SetPinIndex(const size_t& i) { m_pinChar = ( i >= BAD_PINCHAR ) ? BAD_PINCHAR : static_cast<uchar> (i); }
SetSurface(const uchar & c)120 void SetSurface(const uchar& c) { m_surface = c; }
SetHoleUse(const uchar & c)121 void SetHoleUse(const uchar& c) { m_holeUse = c; }
SetOccupancy(const bool & bWire)122 void SetOccupancy(const bool& bWire) // Helper
123 {
124 if ( bWire )
125 {
126 SetSurface( GetIsPin() ? SURFACE_WIRE_END : SURFACE_WIRE ); // Set surface occupancy for pins/non-pins
127 SetHoleUse( GetIsPin() ? HOLE_WIRE : HOLE_FREE ); // Set hole occupancy for pins/non-pins
128 }
129 else
130 {
131 SetHoleUse( GetIsPin() ? HOLE_FULL : HOLE_FREE ); // Set hole occupancy for pins/non-pins
132 }
133 }
GetPinIndex()134 size_t GetPinIndex() const { return ( m_pinChar == BAD_PINCHAR ) ? BAD_PININDEX : m_pinChar; }
GetSurface()135 const uchar& GetSurface() const { return m_surface; }
GetHoleUse()136 const uchar& GetHoleUse() const { return m_holeUse; }
GetIsPin()137 bool GetIsPin() const { return m_pinChar != BAD_PINCHAR; }
GetIsHole()138 bool GetIsHole() const { return m_surface == SURFACE_HOLE; }
139
140 // Merge interface functions
UpdateMergeOffsets(MergeOffsets &)141 virtual void UpdateMergeOffsets(MergeOffsets&) override
142 {
143 }
ApplyMergeOffsets(const MergeOffsets &)144 virtual void ApplyMergeOffsets(const MergeOffsets&) override
145 {
146 }
Merge(const Pin & o)147 void Merge(const Pin& o)
148 {
149 *this = o;
150 }
151 // Persist interface functions
Load(DataStream & inStream)152 virtual void Load(DataStream& inStream) override
153 {
154 inStream.Load(m_pinChar);
155 inStream.Load(m_surface);
156 if ( inStream.GetVersion() < VRT_VERSION_4 ) // Remap m_pinChar if file is older than VRT_VERSION_4
157 SetPinIndex( GetPinIndexFromLegacyPinChar(m_pinChar) );
158 if ( inStream.GetVersion() < VRT_VERSION_26 ) // Remap m_surface if file is older than VRT_VERSION_26
159 SetSurface( GetSurfaceFromLegacySurfaceChar(m_surface) );
160 m_holeUse = GetIsPin() ? HOLE_FULL : HOLE_FREE;
161 if ( inStream.GetVersion() >= VRT_VERSION_26 )
162 inStream.Load(m_holeUse); // Added in VRT_VERSION_26
163 if ( inStream.GetVersion() <= VRT_VERSION_39 )
164 if ( GetIsPin() && m_holeUse == HOLE_FREE ) m_holeUse = HOLE_FULL; // Bug-fix non-wire hole-use
165 }
Save(DataStream & outStream)166 virtual void Save(DataStream& outStream) override
167 {
168 outStream.Save(m_pinChar); // New mapping from VRT_VERSION_4
169 outStream.Save(m_surface); // New mapping from VRT_VERSION_26
170 outStream.Save(m_holeUse); // Added in VRT_VERSION_26
171 }
172 private:
173 // Data
174 uchar m_pinChar;
175 uchar m_surface;
176 uchar m_holeUse;
177 };
178