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&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