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

OutputMemory.h « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a027b059d734c49f059f45fb46349d8831455ae4 (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
150
151
152
153
154
/*
 * OutputMemory.h
 *
 *  Created on: 10 Jan 2016
 *      Authors: David and Christian
 */

#ifndef OUTPUTMEMORY_H_
#define OUTPUTMEMORY_H_

#include "RepRapFirmware.h"
#include "MessageType.h"
#include "Storage/FileData.h"

const size_t OUTPUT_STACK_DEPTH = 4;	// Number of OutputBuffer chains that can be pushed onto one stack instance

class OutputStack;

// This class is used to hold data for sending (either for Serial or Network destinations)
class OutputBuffer
{
	public:
		friend class OutputStack;

		OutputBuffer(OutputBuffer *n) : next(n) { }

		void Append(OutputBuffer *other);
		OutputBuffer *Next() const { return next; }
		bool IsReferenced() const { return isReferenced; }
		void IncreaseReferences(size_t refs);

		const char *Data() const { return data; }
		const char *UnreadData() const { return data + bytesRead; }
		size_t DataLength() const { return dataLength; }	// How many bytes have been written to this instance?
		size_t Length() const;								// How many bytes have been written to the whole chain?

		char& operator[](size_t index);
		char operator[](size_t index) const;
		const char *Read(size_t len);
		void Taken(size_t len) { bytesRead += len; }
		size_t BytesLeft() const { return dataLength - bytesRead; }	// How many bytes have not been sent yet?

		size_t printf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
		size_t vprintf(const char *fmt, va_list vargs);
		size_t catf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));

		size_t copy(const char c);
		size_t copy(const char *src);
		size_t copy(const char *src, size_t len);

		size_t cat(const char c);
		size_t cat(const char *src);
		size_t cat(const char *src, size_t len);
		size_t cat(StringRef &str);

		size_t EncodeString(const char *src, size_t srcLength, bool allowControlChars, bool encapsulateString = true);
		size_t EncodeString(const StringRef& str, bool allowControlChars, bool encapsulateString = true);
		size_t EncodeReply(OutputBuffer *src, bool allowControlChars);

		uint32_t GetAge() const;

		// Write the buffer to file returning true if successful
		bool WriteToFile(FileData& f) const;

		// Initialise the output buffers manager
		static void Init();

		// Allocate an unused OutputBuffer instance. Returns true on success or false if no instance could be allocated.
		static bool Allocate(OutputBuffer *&buf);

		// Get the number of bytes left for allocation. If writingBuffer is not NULL, this returns the number of free bytes for
		// continuous writes, i.e. for writes that need to allocate an extra OutputBuffer instance to finish the message.
		static size_t GetBytesLeft(const OutputBuffer *writingBuffer);

		// Truncate an OutputBuffer instance to free up more memory. Returns the number of released bytes.
		static size_t Truncate(OutputBuffer *buffer, size_t bytesNeeded);

		// Release one OutputBuffer instance. Returns the next item from the chain or nullptr if this was the last instance.
		static OutputBuffer *Release(OutputBuffer *buf);

		// Release all OutputBuffer objects in a chain
		static void ReleaseAll(OutputBuffer *buf);

		static void Diagnostics(MessageType mtype);

	private:

		OutputBuffer *next;
		OutputBuffer *last;

		uint32_t whenQueued;

		char data[OUTPUT_BUFFER_SIZE];
		size_t dataLength, bytesRead;

		bool isReferenced;
		size_t references;

		static OutputBuffer * volatile freeOutputBuffers;		// Messages may also be sent by ISRs,
		static volatile size_t usedOutputBuffers;				// so make these volatile.
		static volatile size_t maxUsedOutputBuffers;
};

inline uint32_t OutputBuffer::GetAge() const
{
	return millis() - whenQueued;
}

// This class is used to manage references to OutputBuffer chains for all output destinations
class OutputStack
{
	public:
		OutputStack() : count(0) { }

		// Is there anything on this stack?
		bool IsEmpty() const { return count == 0; }

		// Clear the reference list
		void Clear() { count = 0; }

		// Push an OutputBuffer chain
		void Push(OutputBuffer *buffer);

		// Pop an OutputBuffer chain or return NULL if none is available
		OutputBuffer *Pop();

		// Returns the first item from the stack or NULL if none is available
		OutputBuffer *GetFirstItem() const;

		// Set the first item of the stack. If it's NULL, then the first item will be removed
		void SetFirstItem(OutputBuffer *buffer);

		// Returns the last item from the stack or NULL if none is available
		OutputBuffer *GetLastItem() const;

		// Get the total length of all queued buffers
		size_t DataLength() const;

		// Append another OutputStack to this instance. If no more space is available,
		// all OutputBuffers that can't be added are automatically released
		void Append(OutputStack *stack);

		// Increase the number of references for each OutputBuffer on the stack
		void IncreaseReferences(size_t num);

		// Release all buffers and clean up
		void ReleaseAll();

	private:
		volatile size_t count;
		OutputBuffer * volatile items[OUTPUT_STACK_DEPTH];
};

#endif /* OUTPUTMEMORY_H_ */