Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PortControl.cpp « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 7af80de548d638f717fa9587fe256a8b89410da4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
 * PortControl.cpp
 *
 *  Created on: 15 Jun 2017
 *      Author: David
 */

#include "PortControl.h"
#include "GCodes/GCodeBuffer.h"
#include "Movement/Move.h"
#include "Movement/DDA.h"

#if SUPPORT_IOBITS

PortControl::PortControl()
{
}

void PortControl::Init()
{
	numConfiguredPorts = 0;
	advanceMillis = 0;
	advanceClocks = 0;
	currentPortState = 0;
}

void PortControl::Exit()
{
	UpdatePorts(0);
	numConfiguredPorts = 0;
}

void PortControl::Spin(bool full)
{
	if (numConfiguredPorts != 0)
	{
		cpu_irq_disable();
		const DDA * cdda = reprap.GetMove().GetCurrentDDA();
		if (cdda == nullptr)
		{
			// Movement has stopped, so turn all ports off
			cpu_irq_enable();
			UpdatePorts(0);
		}
		else
		{
			const uint32_t now = Platform::GetInterruptClocks() + advanceClocks;
			uint32_t moveEndTime = cdda->GetMoveStartTime();
			DDA::DDAState st = cdda->GetState();
			do
			{
				moveEndTime += cdda->GetClocksNeeded();
				if ((int32_t)(moveEndTime - now) >= 0)
				{
					break;
				}
				cdda = cdda->GetNext();
				st = cdda->GetState();
			} while (st == DDA::executing || st == DDA::frozen);
			cpu_irq_enable();

			const IoBits_t bits = (st == DDA::executing || st == DDA::frozen || st == DDA::provisional) ? cdda->GetIoBits() : 0;
			UpdatePorts(bits);
		}
	}
}

bool PortControl::Configure(GCodeBuffer& gb, const StringRef& reply)
{
	bool seen = false;
	if (gb.Seen('P'))
	{
		seen = true;
		UpdatePorts(0);
		numConfiguredPorts = 0;
		uint32_t portNumbers[MaxPorts];
		size_t numPorts = MaxPorts;
		gb.GetUnsignedArray(portNumbers, numPorts, false);
		for (size_t i = 0; i < numPorts; ++i)
		{
			const uint32_t pnum = portNumbers[i];
			if (pnum > HighestLogicalPin)
			{
				reply.printf("Port number %ld out of range", pnum);
				return true;
			}
			IoPort& pm = portMap[i];
			if (!pm.Set((LogicalPin)pnum, PinAccess::write, false))
			{
				reply.printf("Port number %ld is not available", pnum);
				return true;
			}
			pm.WriteDigital(false);				// ensure the port is off
			if (i >= numConfiguredPorts)
			{
				numConfiguredPorts = i + 1;
			}
		}
	}
	if (gb.Seen('T'))
	{
		seen = true;
		advanceMillis = (unsigned int)constrain<int>(gb.GetIValue(), 0, 1000);
		advanceClocks = (advanceMillis * (uint64_t)DDA::stepClockRate)/1000;
	}
	if (!seen)
	{
		reply.printf("Advance %ums, ", advanceMillis);
		if (numConfiguredPorts == 0)
		{
			reply.cat("no port mapping configured");
		}
		else
		{
			reply.cat("port numbers");
			for (size_t i = 0; i < numConfiguredPorts; ++i)
			{
				reply.catf(" %u", (unsigned int)portMap[i].GetLogicalPin());
			}
		}
	}
	return false;
}

void PortControl::UpdatePorts(IoBits_t newPortState)
{
	if (newPortState != currentPortState)
	{
		const IoBits_t bitsToClear = currentPortState & ~newPortState;
		const IoBits_t bitsToSet = newPortState & ~currentPortState;
		for (size_t i = 0; i < numConfiguredPorts; ++i)
		{
			const IoBits_t mask = 1u << i;
			if (bitsToClear & mask)
			{
				portMap[i].WriteDigital(false);
			}
			else if (bitsToSet & mask)
			{
				portMap[i].WriteDigital(true);
			}
		}
		currentPortState = newPortState;
	}
}

#endif

// End