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