miner.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. <?php
  2. session_start();
  3. #
  4. global $miner, $port, $readonly, $notify, $rigs, $socktimeoutsec;
  5. global $checklastshare, $hidefields;
  6. #
  7. # Don't touch these 2 - see $rigs below
  8. $miner = null;
  9. $port = null;
  10. #
  11. # Set $readonly to true to force miner.php to be readonly
  12. # Set $readonly to false then it will check BFGMiner 'privileged'
  13. $readonly = false;
  14. #
  15. # Set $notify to false to NOT attempt to display the notify command
  16. # Set $notify to true to attempt to display the notify command
  17. # If your older version of BFGMiner returns an 'Invalid command'
  18. # coz it doesn't have notify - it just shows the error status table
  19. $notify = true;
  20. #
  21. # set $checklastshare to true to do the following checks:
  22. # If a device's last share is 12x expected ago then display as an error
  23. # If a device's last share is 8x expected ago then display as a warning
  24. # If either of the above is true, also display the whole line highlighted
  25. # This assumes shares are 1 difficulty shares
  26. $checklastshare = true;
  27. #
  28. # Set $rigs to an array of your BFGMiner rigs that are running
  29. # format: 'IP:Port' or 'Host:Port'
  30. # If you only have one rig, it will just show the detail of that rig
  31. # If you have more than one rig it will show a summary of all the rigs
  32. # with buttons to show the details of each rig
  33. # e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028');
  34. $rigs = array('127.0.0.1:4028');
  35. #
  36. # This should be OK for most cases
  37. # However, the longer it is the longer you have to wait while php
  38. # hangs if the target cgminer isn't runnning or listening
  39. # Feel free to increase it if your network is very slow
  40. # Also, on some windows PHP, apparently the $usec is ignored
  41. $socktimeoutsec = 10;
  42. #
  43. # List of fields NOT to be displayed
  44. # You can use this to hide data you don't want to see or don't want
  45. # shown on a public web page
  46. # The list of sections are: SUMMARY, POOL, PGA, GPU, NOTIFY, CONFIG
  47. # See the web page for the list of field names (the table headers)
  48. # It is an array of 'SECTION.Field Name' => 1
  49. # This example would hide the slightly more sensitive pool information
  50. #$hidefields = array('POOL.URL' => 1, 'POOL.User' => 1);
  51. $hidefields = array();
  52. #
  53. $here = $_SERVER['PHP_SELF'];
  54. #
  55. global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
  56. #
  57. $tablebegin = '<tr><td><table border=1 cellpadding=5 cellspacing=0>';
  58. $tableend = '</table></td></tr>';
  59. $warnfont = '<font color=red><b>';
  60. $warnoff = '</b></font>';
  61. $dfmt = 'H:i:s j-M-Y \U\T\CP';
  62. #
  63. # This below allows you to put your own settings into a seperate file
  64. # so you don't need to update miner.php with your preferred settings
  65. # every time a new version is released
  66. # Just create the file 'myminer.php' in the same directory as
  67. # 'miner.php' - and put your own settings in there
  68. if (file_exists('myminer.php'))
  69. include_once('myminer.php');
  70. #
  71. # Ensure it is only ever shown once
  72. global $showndate;
  73. $showndate = false;
  74. #
  75. # For summary page to stop retrying failed rigs
  76. global $rigerror;
  77. $rigerror = array();
  78. #
  79. function htmlhead($checkapi)
  80. {
  81. global $error, $readonly, $here;
  82. if ($readonly === false && $checkapi === true)
  83. {
  84. $access = api('privileged');
  85. if ($error != null
  86. || !isset($access['STATUS']['STATUS'])
  87. || $access['STATUS']['STATUS'] != 'S')
  88. $readonly = true;
  89. }
  90. ?>
  91. <html><head><title>Mine</title>
  92. <style type='text/css'>
  93. td { color:blue; font-family:verdana,arial,sans; font-size:13pt; }
  94. td.h { color:blue; font-family:verdana,arial,sans; font-size:13pt; background:#d0ffff }
  95. td.err { color:black; font-family:verdana,arial,sans; font-size:13pt; background:#ff3050 }
  96. td.warn { color:black; font-family:verdana,arial,sans; font-size:13pt; background:#ffb050 }
  97. td.sta { color:green; font-family:verdana,arial,sans; font-size:13pt; }
  98. td.tot { color:blue; font-family:verdana,arial,sans; font-size:13pt; background:#fff8f2 }
  99. td.lst { color:blue; font-family:verdana,arial,sans; font-size:13pt; background:#ffffdd }
  100. </style>
  101. </head><body bgcolor=#ecffff>
  102. <script type='text/javascript'>
  103. function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location="<?php echo $here ?>"+a}
  104. <?php
  105. if ($readonly === false && $checkapi === true)
  106. {
  107. ?>
  108. function prc(a,m){pr('?arg='+a,m)}
  109. function prs(a,r){var c=a.substr(3);var z=c.split('|',2);var m=z[0].substr(0,1).toUpperCase()+z[0].substr(1)+' GPU '+z[1];prc(a+'&rig='+r,m)}
  110. function prs2(a,n,r){var v=document.getElementById('gi'+n).value;var c=a.substr(3);var z=c.split('|',2);var m='Set GPU '+z[1]+' '+z[0].substr(0,1).toUpperCase()+z[0].substr(1)+' to '+v;prc(a+','+v+'&rig='+r,m)}
  111. <?php
  112. }
  113. ?>
  114. </script>
  115. <table width=100% height=100% border=0 cellpadding=0 cellspacing=0 summary='Mine'>
  116. <tr><td align=center valign=top>
  117. <table border=0 cellpadding=4 cellspacing=0 summary='Mine'>
  118. <?php
  119. }
  120. #
  121. global $error;
  122. $error = null;
  123. #
  124. function getsock($addr, $port)
  125. {
  126. global $error, $socktimeoutsec;
  127. $socket = null;
  128. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  129. if ($socket === false || $socket === null)
  130. {
  131. $error = socket_strerror(socket_last_error());
  132. $msg = "socket create(TCP) failed";
  133. $error = "ERR: $msg '$error'\n";
  134. return null;
  135. }
  136. // Ignore if this fails since the socket connect may work anyway
  137. // and nothing is gained by aborting if the option cannot be set
  138. // since we don't know in advance if it can connect
  139. socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $socktimeoutsec, 'usec' => 0));
  140. $res = socket_connect($socket, $addr, $port);
  141. if ($res === false)
  142. {
  143. $error = socket_strerror(socket_last_error());
  144. $msg = "socket connect($addr,$port) failed";
  145. $error = "ERR: $msg '$error'\n";
  146. socket_close($socket);
  147. return null;
  148. }
  149. return $socket;
  150. }
  151. #
  152. function readsockline($socket)
  153. {
  154. $line = '';
  155. while (true)
  156. {
  157. $byte = socket_read($socket, 1);
  158. if ($byte === false || $byte === '')
  159. break;
  160. if ($byte === "\0")
  161. break;
  162. $line .= $byte;
  163. }
  164. return $line;
  165. }
  166. #
  167. function api($cmd)
  168. {
  169. global $miner, $port, $hidefields;
  170. $socket = getsock($miner, $port);
  171. if ($socket != null)
  172. {
  173. socket_write($socket, $cmd, strlen($cmd));
  174. $line = readsockline($socket);
  175. socket_close($socket);
  176. if (strlen($line) == 0)
  177. {
  178. $error = "WARN: '$cmd' returned nothing\n";
  179. return $line;
  180. }
  181. # print "$cmd returned '$line'\n";
  182. $data = array();
  183. $objs = explode('|', $line);
  184. foreach ($objs as $obj)
  185. {
  186. if (strlen($obj) > 0)
  187. {
  188. $items = explode(',', $obj);
  189. $item = $items[0];
  190. $id = explode('=', $items[0], 2);
  191. if (count($id) == 1 or !ctype_digit($id[1]))
  192. $name = $id[0];
  193. else
  194. $name = $id[0].$id[1];
  195. if (strlen($name) == 0)
  196. $name = 'null';
  197. $sectionname = preg_replace('/\d/', '', $name);
  198. if (isset($data[$name]))
  199. {
  200. $num = 1;
  201. while (isset($data[$name.$num]))
  202. $num++;
  203. $name .= $num;
  204. }
  205. $counter = 0;
  206. foreach ($items as $item)
  207. {
  208. $id = explode('=', $item, 2);
  209. if (isset($hidefields[$sectionname.'.'.$id[0]]))
  210. continue;
  211. if (count($id) == 2)
  212. $data[$name][$id[0]] = $id[1];
  213. else
  214. $data[$name][$counter] = $id[0];
  215. $counter++;
  216. }
  217. }
  218. }
  219. return $data;
  220. }
  221. return null;
  222. }
  223. #
  224. function getparam($name, $both = false)
  225. {
  226. $a = null;
  227. if (isset($_POST[$name]))
  228. $a = $_POST[$name];
  229. if (($both === true) and ($a === null))
  230. {
  231. if (isset($_GET[$name]))
  232. $a = $_GET[$name];
  233. }
  234. if ($a == '' || $a == null)
  235. return null;
  236. // limit to 1K just to be safe
  237. return substr($a, 0, 1024);
  238. }
  239. #
  240. function classlastshare($when, $alldata, $warnclass, $errorclass)
  241. {
  242. global $checklastshare;
  243. if ($checklastshare === false)
  244. return '';
  245. if ($when == 0)
  246. return '';
  247. if (!isset($alldata['MHS av']))
  248. return '';
  249. if (!isset($alldata['Last Share Time']))
  250. return '';
  251. $expected = pow(2, 32) / ($alldata['MHS av'] * pow(10, 6));
  252. $howlong = $when - $alldata['Last Share Time'];
  253. if ($howlong < 1)
  254. $howlong = 1;
  255. if ($howlong > ($expected * 12))
  256. return $errorclass;
  257. if ($howlong > ($expected * 8))
  258. return $warnclass;
  259. return '';
  260. }
  261. #
  262. function fmt($section, $name, $value, $when, $alldata)
  263. {
  264. global $dfmt;
  265. if ($alldata == null)
  266. $alldata = array();
  267. $errorclass = ' class=err';
  268. $warnclass = ' class=warn';
  269. $lstclass = ' class=lst';
  270. $b = '&nbsp;';
  271. $ret = $value;
  272. $class = '';
  273. if ($value === null)
  274. $ret = $b;
  275. else
  276. switch ($section.'.'.$name)
  277. {
  278. case 'GPU.Last Share Time':
  279. case 'PGA.Last Share Time':
  280. if ($value == 0
  281. || (isset($alldata['Last Share Pool']) && $alldata['Last Share Pool'] == -1))
  282. {
  283. $ret = 'Never';
  284. $class = $warnclass;
  285. }
  286. else
  287. {
  288. $ret = date('H:i:s', $value);
  289. $class = classlastshare($when, $alldata, $warnclass, $errorclass);
  290. }
  291. break;
  292. case 'POOL.Last Share Time':
  293. if ($value == 0)
  294. $ret = 'Never';
  295. else
  296. $ret = date('H:i:s d-M', $value);
  297. break;
  298. case 'GPU.Last Share Pool':
  299. case 'PGA.Last Share Pool':
  300. if ($value == -1)
  301. {
  302. $ret = 'None';
  303. $class = $warnclass;
  304. }
  305. break;
  306. case 'SUMMARY.Elapsed':
  307. $s = $value % 60;
  308. $value -= $s;
  309. $value /= 60;
  310. if ($value == 0)
  311. $ret = $s.'s';
  312. else
  313. {
  314. $m = $value % 60;
  315. $value -= $m;
  316. $value /= 60;
  317. if ($value == 0)
  318. $ret = sprintf("%dm$b%02ds", $m, $s);
  319. else
  320. {
  321. $h = $value % 24;
  322. $value -= $h;
  323. $value /= 24;
  324. if ($value == 0)
  325. $ret = sprintf("%dh$b%02dm$b%02ds", $h, $m, $s);
  326. else
  327. {
  328. if ($value == 1)
  329. $days = '';
  330. else
  331. $days = 's';
  332. $ret = sprintf("%dday$days$b%02dh$b%02dm$b%02ds", $value, $h, $m, $s);
  333. }
  334. }
  335. }
  336. break;
  337. case 'NOTIFY.Last Well':
  338. if ($value == '0')
  339. {
  340. $ret = 'Never';
  341. $class = $warnclass;
  342. }
  343. else
  344. $ret = date('H:i:s', $value);
  345. break;
  346. case 'NOTIFY.Last Not Well':
  347. if ($value == '0')
  348. $ret = 'Never';
  349. else
  350. {
  351. $ret = date('H:i:s', $value);
  352. $class = $errorclass;
  353. }
  354. break;
  355. case 'NOTIFY.Reason Not Well':
  356. if ($value != 'None')
  357. $class = $errorclass;
  358. break;
  359. case 'GPU.Utility':
  360. case 'PGA.Utility':
  361. case 'SUMMARY.Utility':
  362. $ret = $value.'/m';
  363. if ($value == 0)
  364. $class = $warnclass;
  365. break;
  366. case 'PGA.Temperature':
  367. $ret = $value.'&deg;C';
  368. break;
  369. case 'GPU.Temperature':
  370. $ret = $value.'&deg;C';
  371. case 'GPU.GPU Clock':
  372. case 'GPU.Memory Clock':
  373. case 'GPU.GPU Voltage':
  374. case 'GPU.GPU Activity':
  375. if ($value == 0)
  376. $class = $warnclass;
  377. break;
  378. case 'GPU.Fan Percent':
  379. if ($value == 0)
  380. $class = $warnclass;
  381. else
  382. {
  383. if ($value == 100)
  384. $class = $errorclass;
  385. else
  386. if ($value > 85)
  387. $class = $warnclass;
  388. }
  389. break;
  390. case 'GPU.Fan Speed':
  391. if ($value == 0)
  392. $class = $warnclass;
  393. else
  394. if (isset($alldata['Fan Percent']))
  395. {
  396. $test = $alldata['Fan Percent'];
  397. if ($test == 100)
  398. $class = $errorclass;
  399. else
  400. if ($test > 85)
  401. $class = $warnclass;
  402. }
  403. break;
  404. case 'GPU.MHS av':
  405. case 'PGA.MHS av':
  406. case 'SUMMARY.MHS av':
  407. case 'GPU.Total MH':
  408. case 'PGA.Total MH':
  409. case 'SUMMARY.Total MH':
  410. case 'SUMMARY.Getworks':
  411. case 'GPU.Accepted':
  412. case 'PGA.Accepted':
  413. case 'SUMMARY.Accepted':
  414. case 'GPU.Rejected':
  415. case 'PGA.Rejected':
  416. case 'SUMMARY.Rejected':
  417. case 'SUMMARY.Local Work':
  418. case 'POOL.Getworks':
  419. case 'POOL.Accepted':
  420. case 'POOL.Rejected':
  421. case 'POOL.Discarded':
  422. $parts = explode('.', $value, 2);
  423. if (count($parts) == 1)
  424. $dec = '';
  425. else
  426. $dec = '.'.$parts[1];
  427. $ret = number_format($parts[0]).$dec;
  428. break;
  429. case 'GPU.Status':
  430. case 'PGA.Status':
  431. case 'POOL.Status':
  432. if ($value != 'Alive')
  433. $class = $errorclass;
  434. break;
  435. case 'GPU.Enabled':
  436. case 'PGA.Enabled':
  437. if ($value != 'Y')
  438. $class = $warnclass;
  439. break;
  440. case 'STATUS.When':
  441. $ret = date($dfmt, $value);
  442. break;
  443. }
  444. if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')
  445. $class = $errorclass;
  446. if ($class == '' && $section != 'POOL')
  447. $class = classlastshare($when, $alldata, $lstclass, $lstclass);
  448. return array($ret, $class);
  449. }
  450. #
  451. global $poolcmd;
  452. $poolcmd = array( 'Switch to' => 'switchpool',
  453. 'Enable' => 'enablepool',
  454. 'Disable' => 'disablepool' );
  455. #
  456. function showhead($cmd, $item, $values)
  457. {
  458. global $poolcmd, $readonly;
  459. echo '<tr>';
  460. foreach ($values as $name => $value)
  461. {
  462. if ($name == '0' or $name == '')
  463. $name = '&nbsp;';
  464. echo "<td valign=bottom class=h>$name</td>";
  465. }
  466. if ($cmd == 'pools' && $readonly === false)
  467. foreach ($poolcmd as $name => $pcmd)
  468. echo "<td valign=bottom class=h>$name</td>";
  469. echo '</tr>';
  470. }
  471. #
  472. function details($cmd, $list, $rig)
  473. {
  474. global $tablebegin, $tableend, $dfmt;
  475. global $poolcmd, $readonly;
  476. global $showndate;
  477. $when = 0;
  478. $stas = array('S' => 'Success', 'W' => 'Warning', 'I' => 'Informational', 'E' => 'Error', 'F' => 'Fatal');
  479. echo $tablebegin;
  480. if ($showndate === false)
  481. {
  482. echo '<tr><td class=sta>Date: '.date($dfmt).'</td></tr>';
  483. echo $tableend.$tablebegin;
  484. $showndate = true;
  485. }
  486. if (isset($list['STATUS']))
  487. {
  488. echo '<tr>';
  489. echo '<td>Computer: '.$list['STATUS']['Description'].'</td>';
  490. if (isset($list['STATUS']['When']))
  491. {
  492. echo '<td>When: '.date($dfmt, $list['STATUS']['When']).'</td>';
  493. $when = $list['STATUS']['When'];
  494. }
  495. $sta = $list['STATUS']['STATUS'];
  496. echo '<td>Status: '.$stas[$sta].'</td>';
  497. echo '<td>Message: '.$list['STATUS']['Msg'].'</td>';
  498. echo '</tr>';
  499. }
  500. $section = '';
  501. foreach ($list as $item => $values)
  502. {
  503. if ($item == 'STATUS')
  504. continue;
  505. $sectionname = preg_replace('/\d/', '', $item);
  506. if ($sectionname != $section)
  507. {
  508. echo $tableend.$tablebegin;
  509. showhead($cmd, $item, $values);
  510. $section = $sectionname;
  511. }
  512. echo '<tr>';
  513. foreach ($values as $name => $value)
  514. {
  515. list($showvalue, $class) = fmt($section, $name, $value, $when, $values);
  516. echo "<td$class>$showvalue</td>";
  517. }
  518. if ($cmd == 'pools' && $readonly === false)
  519. {
  520. reset($values);
  521. $pool = current($values);
  522. foreach ($poolcmd as $name => $pcmd)
  523. {
  524. echo '<td>';
  525. if ($pool === false)
  526. echo '&nbsp;';
  527. else
  528. {
  529. echo "<input type=button value='Pool $pool'";
  530. echo " onclick='prc(\"$pcmd|$pool&rig=$rig\",\"$name Pool $pool\")'>";
  531. }
  532. echo '</td>';
  533. }
  534. }
  535. echo '</tr>';
  536. }
  537. echo $tableend;
  538. }
  539. #
  540. global $devs;
  541. $devs = null;
  542. #
  543. function gpubuttons($count, $rig)
  544. {
  545. global $tablebegin, $tableend;
  546. global $devs;
  547. $basic = array( 'GPU', 'Enable', 'Disable', 'Restart' );
  548. $options = array( 'intensity' => 'Intensity',
  549. 'fan' => 'Fan Percent',
  550. 'engine' => 'GPU Clock',
  551. 'mem' => 'Memory Clock',
  552. 'vddc' => 'GPU Voltage' );
  553. echo $tablebegin.'<tr>';
  554. foreach ($basic as $head)
  555. echo "<td>$head</td>";
  556. foreach ($options as $name => $des)
  557. echo "<td nowrap>$des</td>";
  558. $n = 0;
  559. for ($c = 0; $c < $count; $c++)
  560. {
  561. echo '</tr><tr>';
  562. foreach ($basic as $name)
  563. {
  564. echo '<td>';
  565. if ($name == 'GPU')
  566. echo $c;
  567. else
  568. {
  569. echo "<input type=button value='$name $c' onclick='prs(\"gpu";
  570. echo strtolower($name);
  571. echo "|$c\",$rig)'>";
  572. }
  573. echo '</td>';
  574. }
  575. foreach ($options as $name => $des)
  576. {
  577. echo '<td>';
  578. if (!isset($devs["GPU$c"][$des]))
  579. echo '&nbsp;';
  580. else
  581. {
  582. $value = $devs["GPU$c"][$des];
  583. echo "<input type=button value='Set $c:' onclick='prs2(\"gpu$name|$c\",$n,$rig)'>";
  584. echo "<input size=7 type=text name=gi$n value='$value' id=gi$n>";
  585. $n++;
  586. }
  587. echo '</td>';
  588. }
  589. }
  590. echo '</tr>'.$tableend;
  591. }
  592. #
  593. function processgpus($rig)
  594. {
  595. global $error;
  596. global $warnfont, $warnoff;
  597. $gpus = api('gpucount');
  598. if ($error != null)
  599. echo '<tr><td>Error getting GPU count: '.$warnfont.$error.$warnoff.'</td></tr>';
  600. else
  601. {
  602. if (!isset($gpus['GPUS']['Count']))
  603. echo '<tr><td>No GPU count returned: '.$warnfont.$gpus['STATUS']['STATUS'].' '.$gpus['STATUS']['Msg'].$ro.'</td></tr>';
  604. else
  605. {
  606. $count = $gpus['GPUS']['Count'];
  607. if ($count == 0)
  608. echo '<tr><td>No GPUs</td></tr>';
  609. else
  610. gpubuttons($count, $rig);
  611. }
  612. }
  613. }
  614. #
  615. function process($cmds, $rig)
  616. {
  617. global $error, $devs;
  618. global $warnfont, $warnoff;
  619. foreach ($cmds as $cmd => $des)
  620. {
  621. $process = api($cmd);
  622. if ($error != null)
  623. {
  624. echo "<tr><td colspan=100>Error getting $des: ";
  625. echo $warnfont.$error.$warnoff.'</td></tr>';
  626. break;
  627. }
  628. else
  629. {
  630. details($cmd, $process, $rig);
  631. echo '<tr><td><br><br></td></tr>';
  632. if ($cmd == 'devs')
  633. $devs = $process;
  634. }
  635. }
  636. }
  637. #
  638. # $head is a hack but this is just a demo anyway :)
  639. function doforeach($cmd, $des, $sum, $head, $datetime)
  640. {
  641. global $miner, $port;
  642. global $error, $readonly, $notify, $rigs;
  643. global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
  644. global $rigerror;
  645. $when = 0;
  646. $header = $head;
  647. $anss = array();
  648. $count = 0;
  649. $preverr = count($rigerror);
  650. foreach ($rigs as $rig)
  651. {
  652. if (isset($rigerror[$rig]))
  653. continue;
  654. $parts = explode(':', $rig, 2);
  655. if (count($parts) == 2)
  656. {
  657. $miner = $parts[0];
  658. $port = $parts[1];
  659. $ans = api($cmd);
  660. if ($error != null)
  661. {
  662. echo "<tr><td colspan=100>Error on rig $count getting $des: ";
  663. echo $warnfont.$error.$warnoff.'</td></tr>';
  664. $rigerror[$rig] = $error;
  665. $error = null;
  666. }
  667. else
  668. $anss[$count] = $ans;
  669. }
  670. $count++;
  671. }
  672. if (count($anss) == 0)
  673. {
  674. echo '<tr><td>Failed to access any rigs successfully';
  675. if ($preverr > 0)
  676. echo ' (or rigs had previous errors)';
  677. echo '</td></tr>';
  678. return;
  679. }
  680. if ($datetime)
  681. {
  682. echo '<tr><td class=sta>Date: '.date($dfmt).'</td></tr>';
  683. echo $tableend.$tablebegin;
  684. $dthead = array('' => 1, 'STATUS' => 1, 'Description' => 1, 'When' => 1, 'API' => 1, 'CGMiner' => 1);
  685. showhead('', null, $dthead);
  686. foreach ($anss as $rig => $ans)
  687. {
  688. echo '<tr>';
  689. foreach ($ans as $item => $row)
  690. {
  691. if ($item != 'STATUS' && $item != 'VERSION')
  692. continue;
  693. foreach ($dthead as $name => $x)
  694. {
  695. if ($item == 'STATUS' && $name == '')
  696. echo "<td align=right><input type=button value='Rig $rig' onclick='pr(\"?rig=$rig\",null)'></td>";
  697. else
  698. {
  699. if (isset($row[$name]))
  700. {
  701. list($showvalue, $class) = fmt('STATUS', $name, $row[$name], $when, null);
  702. echo "<td$class align=right>$showvalue</td>";
  703. }
  704. }
  705. }
  706. }
  707. echo '</tr>';
  708. }
  709. echo $tableend;
  710. echo '<tr><td><br><br></td></tr>';
  711. echo $tablebegin;
  712. return;
  713. }
  714. $total = array();
  715. foreach ($anss as $rig => $ans)
  716. {
  717. foreach ($ans as $item => $row)
  718. {
  719. if ($item == 'STATUS')
  720. continue;
  721. if (count($row) > count($header))
  722. {
  723. $header = $head;
  724. foreach ($row as $name => $value)
  725. if (!isset($header[$name]))
  726. $header[$name] = '';
  727. }
  728. if ($sum != null)
  729. foreach ($sum as $name)
  730. {
  731. if (isset($row[$name]))
  732. {
  733. if (isset($total[$name]))
  734. $total[$name] += $row[$name];
  735. else
  736. $total[$name] = $row[$name];
  737. }
  738. }
  739. }
  740. }
  741. if ($sum != null)
  742. $anss['total']['total'] = $total;
  743. showhead('', null, $header);
  744. $section = '';
  745. foreach ($anss as $rig => $ans)
  746. {
  747. $when = 0;
  748. if (isset($ans['STATUS']['When']))
  749. $when = $ans['STATUS']['When'];
  750. foreach ($ans as $item => $row)
  751. {
  752. if ($item == 'STATUS')
  753. continue;
  754. echo '<tr>';
  755. $newsection = preg_replace('/\d/', '', $item);
  756. if ($newsection != 'total')
  757. $section = $newsection;
  758. foreach ($header as $name => $x)
  759. {
  760. if ($name == '')
  761. {
  762. if ($rig === 'total')
  763. echo "<td align=right class=tot>Total:</td>";
  764. else
  765. echo "<td align=right><input type=button value='Rig $rig' onclick='pr(\"?rig=$rig\",null)'></td>";
  766. }
  767. else
  768. {
  769. if (isset($row[$name]))
  770. $value = $row[$name];
  771. else
  772. $value = null;
  773. list($showvalue, $class) = fmt($section, $name, $value, $when, $row);
  774. if ($rig === 'total' and $class == '')
  775. $class = ' class=tot';
  776. echo "<td$class align=right>$showvalue</td>";
  777. }
  778. }
  779. echo '</tr>';
  780. }
  781. }
  782. }
  783. #
  784. function doOne($rig, $preprocess)
  785. {
  786. global $error, $readonly, $notify;
  787. global $rigs;
  788. htmlhead(true);
  789. $error = null;
  790. echo "<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td>";
  791. echo "<input type=button value='Refresh' onclick='pr(\"?rig=$rig\",null)'></td>";
  792. if (count($rigs) > 1)
  793. echo "<td><input type=button value='Summary' onclick='pr(\"\",null)'></td>";
  794. echo "<td width=100%>&nbsp;</td><td>";
  795. if ($readonly === false)
  796. {
  797. $msg = 'Quit BFGMiner';
  798. if (count($rigs) > 1)
  799. $msg .= " Rig $rig";
  800. echo "<input type=button value='Quit' onclick='prc(\"quit&rig=$rig\",\"$msg\")'>";
  801. }
  802. echo "</td></tr></table></td></tr>";
  803. if ($preprocess != null)
  804. process(array($preprocess => $preprocess), $rig);
  805. $cmds = array( 'devs' => 'device list',
  806. 'summary' => 'summary information',
  807. 'pools' => 'pool list');
  808. if ($notify)
  809. $cmds['notify'] = 'device status';
  810. $cmds['config'] = 'BFGMiner config';
  811. process($cmds, $rig);
  812. if ($error == null && $readonly === false)
  813. processgpus($rig);
  814. }
  815. #
  816. function display()
  817. {
  818. global $tablebegin, $tableend;
  819. global $miner, $port;
  820. global $error, $readonly, $notify, $rigs;
  821. $rig = trim(getparam('rig', true));
  822. $arg = trim(getparam('arg', true));
  823. $preprocess = null;
  824. if ($arg != null and $arg != '')
  825. {
  826. $num = null;
  827. if ($rig != null and $rig != '')
  828. {
  829. if ($rig >= 0 and $rig < count($rigs))
  830. $num = $rig;
  831. }
  832. else
  833. if (count($rigs) == 0)
  834. $num = 0;
  835. if ($num != null)
  836. {
  837. $parts = explode(':', $rigs[$num], 2);
  838. if (count($parts) == 2)
  839. {
  840. $miner = $parts[0];
  841. $port = $parts[1];
  842. $preprocess = $arg;
  843. }
  844. }
  845. }
  846. if ($rigs == null or count($rigs) == 0)
  847. {
  848. echo "<tr><td>No rigs defined</td></tr>";
  849. return;
  850. }
  851. if (count($rigs) == 1)
  852. {
  853. $parts = explode(':', $rigs[0], 2);
  854. if (count($parts) == 2)
  855. {
  856. $miner = $parts[0];
  857. $port = $parts[1];
  858. doOne(0, $preprocess);
  859. }
  860. else
  861. echo '<tr><td>Invalid "$rigs" array</td></tr>';
  862. return;
  863. }
  864. if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs))
  865. {
  866. $parts = explode(':', $rigs[$rig], 2);
  867. if (count($parts) == 2)
  868. {
  869. $miner = $parts[0];
  870. $port = $parts[1];
  871. doOne($rig, $preprocess);
  872. }
  873. else
  874. echo '<tr><td>Invalid "$rigs" array</td></tr>';
  875. return;
  876. }
  877. htmlhead(false);
  878. echo "<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td>";
  879. echo "<input type=button value='Refresh' onclick='pr(\"\",null)'>";
  880. echo "</td></tr></table></td></tr>";
  881. if ($preprocess != null)
  882. process(array($preprocess => $preprocess), $rig);
  883. echo $tablebegin;
  884. doforeach('version', 'rig summary', array(), array(), true);
  885. $sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH');
  886. doforeach('summary', 'summary information', $sum, array(), false);
  887. echo $tableend;
  888. echo '<tr><td><br><br></td></tr>';
  889. echo $tablebegin;
  890. doforeach('devs', 'device list', $sum, array(''=>'','ID'=>'','Name'=>''), false);
  891. echo $tableend;
  892. echo '<tr><td><br><br></td></tr>';
  893. echo $tablebegin;
  894. doforeach('pools', 'pool list', $sum, array(''=>''), false);
  895. echo $tableend;
  896. }
  897. #
  898. display();
  899. #
  900. ?>
  901. </table></td></tr></table>
  902. </body></html>