webdemo.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * Copyright (C) 2001-2006 by egnite Software GmbH
  3. * Copyright (C) 2009 by egnite GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*
  36. * $Id: webdemo.c 5545 2014-01-12 19:47:48Z olereinhardt $
  37. *
  38. * WARNING! Do not use any part of Basemon for your own applications. WARNING!
  39. *
  40. * This is not a typical application sample. It overrides parts of Nut/OS to
  41. * keep it running on broken hardware.
  42. */
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <dev/nicrtl.h>
  46. #include <dev/lanc111.h>
  47. #include <dev/urom.h>
  48. #include <sys/timer.h>
  49. #include <sys/thread.h>
  50. #include <sys/confnet.h>
  51. #include <sys/socket.h>
  52. #include <arpa/inet.h>
  53. #include <net/route.h>
  54. #include <pro/httpd.h>
  55. #include <pro/dhcp.h>
  56. #include <sys/atom.h>
  57. #include "basemon.h"
  58. #include "webdemo.h"
  59. #ifdef __AVR__ /* TODO: This function is called from webserver thread!!! Broken for other CPUs? */
  60. static char *states[] = { "TRM",
  61. "<FONT COLOR=#CC0000>RUN</FONT>",
  62. "<FONT COLOR=#339966>RDY</FONT>",
  63. "SLP"
  64. };
  65. /*
  66. * Thread list CGI.
  67. */
  68. static int ShowThreads(FILE * stream, REQUEST * req)
  69. {
  70. NUTTHREADINFO *tdp = nutThreadList;
  71. static prog_char head_P[] = "<HTML><HEAD><TITLE>Nut/OS Threads</TITLE>" "</HEAD><BODY><h1>Nut/OS Threads</h1>\r\n";
  72. static prog_char ttop_P[] = "<TABLE BORDER><TR><TH>Handle</TH>"
  73. "<TH>Name</TH><TH>Priority</TH>"
  74. "<TH>Status</TH><TH>Event<BR>Queue</TH>" "<TH>Timer</TH><TH>Stack-<BR>pointer</TH>" "<TH>Free<BR>Stack</TH></TR>\r\n";
  75. static prog_char tbot_P[] = "</TABLE></BODY></HTML>";
  76. static prog_char tfmt_P[] = "<TR><TD>%04X</TD><TD>%s</TD><TD>%u</TD>"
  77. "<TD>%s</TD><TD>%04X</TD><TD>%04X</TD>" "<TD>%04X</TD><TD>%u</TD><TD>%s</TD></TR>\r\n";
  78. NutHttpSendHeaderTop(stream, req, 200, "Ok");
  79. NutHttpSendHeaderBottom(stream, req, "text/html", -1);
  80. fputs_P(head_P, stream);
  81. fputs_P(ttop_P, stream);
  82. while (tdp) {
  83. fprintf_P(stream, tfmt_P, (unsigned int)tdp, tdp->td_name, tdp->td_priority,
  84. states[tdp->td_state], (unsigned int)tdp->td_queue, (unsigned int)tdp->td_timer,
  85. (unsigned int)tdp->td_sp,
  86. (unsigned int) tdp->td_sp - (unsigned int) tdp->td_memory, *((uint32_t *) tdp->td_memory) != DEADBEEF ? "Corr" : "OK");
  87. tdp = tdp->td_next;
  88. }
  89. fputs_P(tbot_P, stream);
  90. fflush(stream);
  91. return 0;
  92. }
  93. /*
  94. * Timer list CGI.
  95. */
  96. static int ShowTimer(FILE * stream, REQUEST * req)
  97. {
  98. NUTTIMERINFO *tnp;
  99. uint32_t ticks_left;
  100. uint32_t crystal;
  101. static prog_char head_P[] = "<HTML><HEAD><TITLE>Nut/OS Timers</TITLE>" "</HEAD><BODY>";
  102. static prog_char cfmt_P[] = "\r\nCPU running at %u.%04u MHz<br>\r\n";
  103. static prog_char ttop_P[] = "<TABLE BORDER><TR><TH>Handle</TH>"
  104. "<TH>Countdown</TH><TH>Tick Reload</TH>" "<TH>Callback<BR>Address</TH>" "<TH>Callback<BR>Argument</TH></TR>\r\n";
  105. static prog_char tfmt_P[] = "<TR><TD>%04X</TD><TD>%lu</TD><TD>%lu</TD>" "<TD>%04X</TD><TD>%04X</TD></TR>\r\n";
  106. static prog_char tbot_P[] = "</TABLE></BODY></HTML>";
  107. NutHttpSendHeaderTop(stream, req, 200, "Ok");
  108. NutHttpSendHeaderBottom(stream, req, "text/html", -1);
  109. fputs_P(head_P, stream);
  110. crystal = NutGetCpuClock();
  111. fprintf_P(stream, cfmt_P, (int) (crystal / 1000000UL), (int) ((crystal - (crystal / 1000000UL) * 1000000UL) / 100));
  112. if ((tnp = nutTimerList) != 0) {
  113. fputs_P(ttop_P, stream);
  114. ticks_left = 0;
  115. while (tnp) {
  116. ticks_left += tnp->tn_ticks_left;
  117. fprintf_P(stream, tfmt_P, (unsigned int)tnp, ticks_left, tnp->tn_ticks, (unsigned int)tnp->tn_callback, (unsigned int)tnp->tn_arg);
  118. tnp = tnp->tn_next;
  119. }
  120. }
  121. fputs_P(tbot_P, stream);
  122. fflush(stream);
  123. return 0;
  124. }
  125. /*
  126. * Socket list CGI.
  127. */
  128. static int ShowSockets(FILE * stream, REQUEST * req)
  129. {
  130. extern TCPSOCKET *tcpSocketList;
  131. TCPSOCKET *ts;
  132. static prog_char head_P[] = "<HTML><HEAD><TITLE>Show Threads</TITLE>"
  133. "</HEAD><BODY><TABLE BORDER><TR>" "<TH>Handle</TH><TH>Type</TH><TH>Local</TH>" "<TH>Remote</TH><TH>Status</TH></TR>\r\n";
  134. static prog_char fmt1_P[] = "<TR><TD>%04X</TD><TD>TCP</TD><TD>%s:%u</TD>";
  135. static prog_char fmt2_P[] = "<TD>%s:%u</TD><TD>";
  136. static prog_char estb_P[] = "<FONT COLOR=#CC0000>ESTABL</FONT>";
  137. static prog_char tbot_P[] = "</TABLE></BODY></HTML>\r\n";
  138. NutHttpSendHeaderTop(stream, req, 200, "Ok");
  139. NutHttpSendHeaderBottom(stream, req, "text/html", -1);
  140. fputs_P(head_P, stream);
  141. /* TODO: Its a bad idea to loop through the socket list while there are scheduling points in this loop.
  142. It may lead to a race condition.
  143. */
  144. NutEnterCritical();
  145. for (ts = tcpSocketList; ts; ts = ts->so_next) {
  146. fprintf_P(stream, fmt1_P, (unsigned int)ts, inet_ntoa(ts->so_local_addr), ntohs(ts->so_local_port));
  147. fprintf_P(stream, fmt2_P, inet_ntoa(ts->so_remote_addr), ntohs(ts->so_remote_port));
  148. switch (ts->so_state) {
  149. case TCPS_LISTEN:
  150. fputs("LISTEN", stream);
  151. break;
  152. case TCPS_SYN_SENT:
  153. fputs("SYNSENT", stream);
  154. break;
  155. case TCPS_SYN_RECEIVED:
  156. fputs("SYNRCVD", stream);
  157. break;
  158. case TCPS_ESTABLISHED:
  159. fputs_P(estb_P, stream);
  160. break;
  161. case TCPS_FIN_WAIT_1:
  162. fputs("FINWAIT1", stream);
  163. break;
  164. case TCPS_FIN_WAIT_2:
  165. fputs("FINWAIT2", stream);
  166. break;
  167. case TCPS_CLOSE_WAIT:
  168. fputs("CLOSEWAIT", stream);
  169. break;
  170. case TCPS_CLOSING:
  171. fputs("CLOSING", stream);
  172. break;
  173. case TCPS_LAST_ACK:
  174. fputs("LASTACK", stream);
  175. break;
  176. case TCPS_TIME_WAIT:
  177. fputs("TIMEWAIT", stream);
  178. break;
  179. case TCPS_CLOSED:
  180. fputs("CLOSED", stream);
  181. break;
  182. case TCPS_DESTROY:
  183. fputs("DESTROY", stream);
  184. break;
  185. default:
  186. fputs("?UNK?", stream);
  187. break;
  188. }
  189. fputs("</TD></TR>\r\n", stream);
  190. }
  191. NutExitCritical();
  192. fputs_P(tbot_P, stream);
  193. fflush(stream);
  194. return 0;
  195. }
  196. static void DoCheckboxes(FILE * stream, char * name, uint8_t val)
  197. {
  198. uint8_t i;
  199. static prog_char ttop_P[] = "<tr><td>%s</td>";
  200. static prog_char tfmt_P[] = "<td><input type=\"checkbox\"" " name=\"%s\" value=\"%u\" ";
  201. static prog_char tchk_P[] = " checked=\"checked\"";
  202. fprintf_P(stream, ttop_P, name);
  203. for (i = 8; i-- > 0;) {
  204. fprintf_P(stream, tfmt_P, name, i);
  205. if (val & _BV(i))
  206. fputs_P(tchk_P, stream);
  207. fputs("></td>\r\n", stream);
  208. }
  209. fputs("</tr>\r\n", stream);
  210. }
  211. /*
  212. * Socket list CGI.
  213. */
  214. static int ShowPorts(FILE * stream, REQUEST * req)
  215. {
  216. static prog_char ttop_P[] = "<HTML><HEAD><TITLE>Show Ports</TITLE>"
  217. "</HEAD><BODY>"
  218. "<form action=\"cgi-bin/setports.cgi\" "
  219. "enctype=\"text/plain\"> <TABLE BORDER>"
  220. "<tr><td>Bit</td><td>7</td><td>6</td>" "<td>5</td><td>4</td><td>3</td><td>2</td>" "<td>1</td><td>0</td></tr>\r\n";
  221. #if defined (__AVR__)
  222. static prog_char trow_P[] = "<tr></tr>";
  223. #endif
  224. static prog_char tbot_P[] = "</table></form>\r\n</body>\r\n</html>";
  225. NutHttpSendHeaderTop(stream, req, 200, "Ok");
  226. NutHttpSendHeaderBottom(stream, req, "text/html", -1);
  227. fputs_P(ttop_P, stream);
  228. #if defined (__AVR__)
  229. DoCheckboxes(stream, "DDRA", inb(DDRA));
  230. DoCheckboxes(stream, "PINA", inb(PINA));
  231. DoCheckboxes(stream, "PORTA", inb(PORTA));
  232. fputs_P(trow_P, stream);
  233. DoCheckboxes(stream, "DDRB", inb(DDRB));
  234. DoCheckboxes(stream, "PINB", inb(PINB));
  235. DoCheckboxes(stream, "PORTB", inb(PORTB));
  236. fputs_P(trow_P, stream);
  237. DoCheckboxes(stream, "PORTC", inb(PORTC));
  238. fputs_P(trow_P, stream);
  239. DoCheckboxes(stream, "DDRD", inb(DDRD));
  240. DoCheckboxes(stream, "PIND", inb(PIND));
  241. DoCheckboxes(stream, "PORTD", inb(PORTD));
  242. fputs_P(trow_P, stream);
  243. DoCheckboxes(stream, "DDRE", inb(DDRE));
  244. DoCheckboxes(stream, "PINE", inb(PINE));
  245. DoCheckboxes(stream, "PORTE", inb(PORTE));
  246. fputs_P(trow_P, stream);
  247. DoCheckboxes(stream, "PINF", inb(PINF));
  248. #endif
  249. fputs_P(tbot_P, stream);
  250. fflush(stream);
  251. return 0;
  252. }
  253. #endif /* #ifdef __AVR__ */
  254. THREAD(WebDemo, arg)
  255. {
  256. #ifdef __AVR__
  257. TCPSOCKET *sock;
  258. FILE *stream;
  259. IFNET *ifn = 0;
  260. uint32_t ip_addr; /* ICCAVR bugfix */
  261. static prog_char netfail_P[] = "\nFailed to configure network " /* */
  262. "interface: Ethernut stopped!\n\x07";
  263. static prog_char dhcpfail_P[] = "\nFailed to configure network " /* */
  264. "via DHCP: Ethernut stopped!\n\x07";
  265. /*
  266. * Register Realtek controller at address 8300 hex
  267. * and interrupt 5.
  268. */
  269. #if defined(__AVR__)
  270. if(nic == 1)
  271. NutRegisterDevice(&devEth0, 0x8300, 5);
  272. #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega2561__)
  273. else
  274. NutRegisterDevice(&devSmsc111, 0, 0);
  275. #endif
  276. #endif
  277. /*
  278. * Configure lan interface.
  279. */
  280. ip_addr = inet_addr(my_ip);
  281. if (ip_addr) {
  282. if (NutNetIfConfig("eth0", my_mac, ip_addr, inet_addr(my_mask))) {
  283. printf_P(netfail_P);
  284. if (uart_bs >= 0) {
  285. for (;;)
  286. NutSleep(1000);
  287. } else {
  288. #if defined (__AVR__)
  289. asm("cli");
  290. asm("call 0");
  291. #endif
  292. }
  293. }
  294. } else if (NutDhcpIfConfig("eth0", my_mac, 60000)) {
  295. printf_P(dhcpfail_P);
  296. if (uart_bs >= 0) {
  297. for (;;)
  298. NutSleep(1000);
  299. } else {
  300. #if defined (__AVR__)
  301. asm("cli");
  302. asm("call 0");
  303. #endif
  304. }
  305. }
  306. printf("MAC %02X-%02X-%02X-%02X-%02X-%02X\nIP %s",
  307. confnet.cdn_mac[0], confnet.cdn_mac[1],
  308. confnet.cdn_mac[2], confnet.cdn_mac[3], confnet.cdn_mac[4], confnet.cdn_mac[5],
  309. inet_ntoa(confnet.cdn_ip_addr));
  310. printf("\nMask %s", inet_ntoa(confnet.cdn_ip_mask));
  311. /*
  312. * Add optional default route.
  313. */
  314. if (inet_addr(my_ip) && inet_addr(my_gate)) {
  315. if (uart_bs >= 0)
  316. printf("\nAdd gateway %s", my_gate);
  317. #if defined (__AVR__)
  318. NutIpRouteAdd(0, 0, inet_addr(my_gate), &devEth0);
  319. #endif
  320. }
  321. else if (confnet.cdn_gateway && uart_bs >= 0)
  322. printf("\nGate %s", inet_ntoa(confnet.cdn_gateway));
  323. #if defined (__AVR__)
  324. if(nic == 1)
  325. ifn = (IFNET *) (devEth0.dev_icb);
  326. #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega2561__)
  327. else
  328. ifn = (IFNET *) (devSmsc111.dev_icb);
  329. #endif
  330. #endif
  331. printf("\nHTTP server running. URL http://%s/\n", inet_ntoa(ifn->if_local_ip));
  332. /*
  333. * Register our device for the file system.
  334. */
  335. NutRegisterDevice(&devUrom, 0, 0);
  336. /*
  337. * Register CGI routines.
  338. */
  339. NutRegisterCgi("threads.cgi", ShowThreads);
  340. NutRegisterCgi("timer.cgi", ShowTimer);
  341. NutRegisterCgi("sockets.cgi", ShowSockets);
  342. NutRegisterCgi("ports.cgi", ShowPorts);
  343. /*
  344. * Now loop endless for connections.
  345. */
  346. for (;;) {
  347. /*
  348. * Create a socket.
  349. */
  350. sock = NutTcpCreateSocket();
  351. /*
  352. * Listen on port 80. If we return,
  353. * we got a client.
  354. */
  355. NutTcpAccept(sock, 80);
  356. /*
  357. * Create a stream from the socket, so we can use stdio.
  358. */
  359. stream = _fdopen((int) sock, "r+b");
  360. /*
  361. * Process http request.
  362. */
  363. NutHttpProcessRequest(stream);
  364. /*
  365. * Destroy our device.
  366. */
  367. fclose(stream);
  368. /*
  369. * Close our socket.
  370. */
  371. NutTcpCloseSocket(sock);
  372. }
  373. #endif
  374. while(1); /* Keep compiler happy */
  375. }