1<?php
2/**
3 * Register Plugin: display pretty pictures of registers
4 *
5 * @license   GPL-3
6 * @author    Mike Frysinger <vapier@gentoo.org>
7 */
8
9if (!defined("DOKU_PLUGIN")) define("DOKU_PLUGIN", DOKU_INC."lib/plugins/");
10require_once(DOKU_PLUGIN . "syntax.php");
11require_once(DOKU_PLUGIN . "register/register.php");
12
13class syntax_plugin_register extends DokuWiki_Syntax_Plugin
14{
15	public function getInfo()
16	{
17        return confToHash(dirname(__FILE__).'/info.txt');
18	}
19	public function getType() { return "protected"; }
20	public function getSort() { return 333; }
21	public function connectTo($mode)
22	{
23		$this->Lexer->addEntryPattern("<register>", $mode, "plugin_register");
24	}
25	public function postConnect()
26	{
27		/*
28		$keywords = array(
29			"register", "long desc", "short desc", "perms", "addr", "reset",
30			"length", "bit range", "bit name", "bit desc", "bit flags"
31		);
32		foreach ($keywords as $k)
33			$this->Lexer->addPattern("$k = ", "plugin_register");
34		*/
35		$this->Lexer->addExitPattern("</register>", "plugin_register");
36	}
37
38	public function handle($match, $state, $pos, &$handler)
39	{
40		switch ($state) {
41		/*1*/case DOKU_LEXER_ENTER:     return array($state, $match);
42		/*2*/case DOKU_LEXER_MATCHED:   return array();
43		/*3*/case DOKU_LEXER_UNMATCHED: return array($state, $match);
44		/*4*/case DOKU_LEXER_EXIT:      return array($state, $match);
45		/*5*/case DOKU_LEXER_SPECIAL:   return array();
46		}
47		return false;
48	}
49
50	/* XXX: remember, php error will not flush renderer and thus no debug messages */
51	private $debug = 0;
52	private function _msg(&$renderer, $type, $msg)
53	{
54		$bt = debug_backtrace();
55		$renderer->doc .= "<br><b>{register plugin $type}:".$bt[2]["function"]."():".$bt[1]["line"].": $msg</b><br>";
56		unset($bt);
57	}
58	private function err(&$renderer, $msg) { $this->_msg($renderer, "error", $msg); }
59	private function dbg(&$renderer, $msg) { if ($this->debug) $this->_msg($renderer, "debug", $msg); }
60
61	private function get_output_pieces(&$renderer, $match)
62	{
63		global $conf;
64
65		$dir = $conf["mediadir"] . "/register";
66		$hash = md5(serialize($match));
67		$file = "$dir/$hash.png";
68		$url = DOKU_BASE . "lib/exe/fetch.php?cache=$cache&amp;media=" . urlencode("register:$hash.png");
69
70		if (!io_mkdir_p($dir)) {
71			$this->err($renderer, "failed to create output dir '$dir'");
72			return false;
73		}
74
75		return array($file, $url);
76	}
77	private function push_bit(&$bits, &$bit)
78	{
79		if (!array_key_exists("name", $bit))
80			$bit["name"] = "ERROR:UNDEF";
81		if (!array_key_exists("desc", $bit))
82			$bit["desc"] = "";
83		if (!array_key_exists("flags", $bit))
84			$bit["flags"] = "";
85		$range = explode(" ", $bit["range"]);
86		if (count($range) == 1)
87			$range[1] = $range[0];
88		array_push($bits, array($range[0], $range[1], $bit["name"], $bit["desc"], $bit["flags"]));
89		$bit = array();
90	}
91	private function parse_match(&$renderer, $match)
92	{
93		$keys = array();
94		$bits = array();
95		$bit = array();
96		$lines = explode("\n", $match);
97		foreach ($lines as $l) {
98			if ($l == "")
99				continue;
100			$this->dbg($renderer, "line: $l");
101			$val = strstr($l, " = ");
102			$key = substr($l, 0, strlen($l) - strlen($val));
103			$val = str_replace("\\n", "\n", substr($val, 3));
104			if ($key == "xml")
105				return $this->parse_match_xml($renderer, $match);
106			if (substr($key, 0, 4) == "bit ") {
107				$subkey = substr($key, 4);
108				if ($subkey == "range" && count($bit) > 0)
109					$this->push_bit($bits, $bit);
110				$bit[$subkey] = $val;
111				$this->dbg($renderer, "BIT[$subkey] = $val");
112			} else {
113				$keys[$key] = $val;
114				$this->dbg($renderer, "KEY[$key] = $val");
115			}
116		}
117		if (count($bit) > 0)
118			$this->push_bit($bits, $bit);
119		if (!array_key_exists("long desc", $keys))
120			$keys["long desc"] = "";
121		if (!array_key_exists("addr", $keys))
122			$keys["addr"] = "";
123		if (!array_key_exists("reset", $keys))
124			$keys["reset"] = "undef";
125		if (!array_key_exists("perms", $keys))
126			$keys["perms"] = "";
127		if (!array_key_exists("short desc", $keys))
128			$keys["short desc"] = "";
129		return array($keys, $bits);
130	}
131	private function parse_match_xml(&$renderer, $match)
132	{
133		$xml_path = DOKU_PLUGIN . "register/xml/";
134
135		$lines = explode("\n", $match);
136		foreach ($lines as $l) {
137			$val = strstr($l, " = ");
138			$key = substr($l, 0, strlen($l) - strlen($val));
139			$val = str_replace("\\n", "\n", substr($val, 3));
140			$keys[$key] = $val;
141		}
142
143		if (eregi_replace("[-.a-z0-9]*", "", $keys["xml"]) != "") {
144			$this->err($renderer, "invalid xml file name '".$keys["xml"]."'");
145			return false;
146		}
147
148		$keys["xml"] .= (substr($keys["xml"], -4) == ".xml" ? "" : ".xml");
149		if (file_exists($xml_path . "ADSP-" . $keys["xml"]))
150			$keys["xml"] = "ADSP-" . $keys["xml"];
151		$xml = $xml_path . $keys["xml"];
152		$this->dbg($renderer, "XML = $xml");
153
154		$fp = fopen($xml, "r");
155		if (!$fp) {
156			$this->err($renderer, "unable to read xml file '$xml'");
157			return false;
158		}
159		global $adi_xml_search, $adi_xml_state, $adi_xml_result;
160		$adi_xml_search = $keys["register"];
161		$adi_xml_state = 1;
162		$adi_xml_result = array();
163		$xml_parser = xml_parser_create();
164		xml_set_element_handler($xml_parser, "adi_register_xml_parse", "");
165		while (($data = fread($fp, 8192)) && $adi_xml_state) {
166			if (!xml_parse($xml_parser, $data, feof($fp))) {
167				$this->err($renderer, "XML error: %s at line %d",
168					xml_error_string(xml_get_error_code($xml_parser)),
169					xml_get_current_line_number($xml_parser));
170			}
171		}
172		xml_parser_free($xml_parser);
173		fclose($fp);
174
175		$attrs = $adi_xml_result["attrs"];
176		$keys["long desc"] = $attrs["DESCRIPTION"];
177		$keys["short desc"] = $attrs["DEF-COMMENT"]; /*DEF-HEADER*/
178		$keys["addr"] = $attrs["WRITE-ADDRESS"];
179		$keys["length"] = $attrs["BIT-SIZE"];
180		$keys["reset"] = "undef";
181		$bits = array_reverse($adi_xml_result["bits"]);
182		return array($keys, $bits);
183	}
184	private function generate_image(&$renderer, $match, $file)
185	{
186		/* if the output file exists, nothing for us to do */
187		if (is_readable($file))
188			return true;
189
190		$ret = $this->parse_match($renderer, $match);
191		if (!$ret)
192			return false;
193		list($keys, $bits) = $ret;
194
195		/*
196			register = WDOG_CTL
197			long desc = Watchdog Control Register
198			short desc = moo
199			perms = RW
200			addr = 0xFFC00200
201			reset = 0x0AD0
202			length = 16
203			bit range = 15 15
204			bit name = WDR0
205			bit desc = 0 - Watchdog timer has not expired\n1 - Watchdog timer has expired
206			bit flags = W1C
207			bit range = 11 4
208			bit name = WDEN
209			bit desc = 0xAD - Counter disabled\nAll other values - Counter enabled
210		*/
211
212		$reg = new register(
213			$keys["register"], $keys["long desc"], $keys["addr"], $keys["reset"],
214			$keys["length"], $keys["perms"], $keys["short desc"],
215			$bits
216		);
217		if (!$reg->render($file))
218			return false;
219		unset($reg);
220
221		/* pass the WDOG_CTL back up for "alt" in <img>  ? */
222		//return array($keys["register"], $keys["long desc"]);
223		return true;
224	}
225	public function render($mode, &$renderer, $data)
226	{
227		if ($mode != "xhtml")
228			return false;
229
230		/* convert the stuff returned from handle() */
231		if (gettype($data) != "array") {
232			$this->err($renderer, "incoming data from handle() is not an array");
233			return false;
234		}
235		list($state, $match) = $data;
236		$this->dbg($renderer, "state: $state match: $match");
237		if ($state != DOKU_LEXER_UNMATCHED)
238			return true;	/* nothing to do */
239
240		/* setup the file / url locations */
241		$pieces = $this->get_output_pieces($renderer, $match);
242		if ($pieces == false) {
243			$this->err($renderer, "get_output_pieces() failed");
244			return false;
245		}
246		list($file, $url) = $pieces;
247
248		/* generate the image */
249		if (!$this->generate_image($renderer, $match, $file)) {
250			$this->err($renderer, "generate_image() failed");
251			return false;
252		}
253
254		/* present the image! */
255		$renderer->doc .= "<img src='$url' class='media' title='Register Bit Breakout' alt='Register'/>";
256		return true;
257	}
258}
259
260function adi_register_xml_parse($parser, $name, $attrs)
261{
262	global $adi_xml_search, $adi_xml_state, $adi_xml_result;
263
264	if ($name != "REGISTER")
265		return false;
266
267	switch ($adi_xml_state) {
268	case 1:
269		if ($attrs["NAME"] == $adi_xml_search) {
270			$adi_xml_result["attrs"] = $attrs;
271			$adi_xml_result["bits"] = array();
272			$adi_xml_state = 2;
273		}
274		break;
275
276	case 2:
277		if ($attrs["PARENT"] != $adi_xml_search) {
278			$adi_xml_state = 0;
279			return false;
280		}
281		$adi_xml_result["bits"][$attrs["BIT-POSITION"]] = array(
282			$attrs["BIT-POSITION"] - 1 + $attrs["BIT-SIZE"],
283			$attrs["BIT-POSITION"],
284			$attrs["NAME"],
285			$attrs["DESCRIPTION"],
286			""
287		);
288		break;
289	}
290}
291
292?>
293