EtherShield.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*! \mainpage Arduino ENC28J60 EtherShield Library
  2. \section Introduction
  3. This library is derived from original code by Guido Socher and Pascal Stang, and hence licensed as GPL2. See http://www.gnu.org/licenses/gpl.html
  4. It comprises a C++ class wrapper and a number of C files. It still follows pretty much the same structure as the original code that it was based on.
  5. The Arduino EtherShield Library was initially created by Xing Yu of Nuelectronics, http://www.nuelectronics.com/estore/index.php?main_page=product_info&cPath=1&products_id=4
  6. The library was heavily modified and improved by Andrew D. Lindsay (http://blog.thiseldo.co.uk) with extra code from the Tuxgraphics.org ethernet library (http://www.tuxgraphics.org/electronics/200905/embedded-tcp-ip-stack.shtml), which also originated from the Pascal Stang code.
  7. Further additions include the DHCP implementation with some assistance from JCW at http://jeelabs.org which is now used in their own version of the library for their EtherCard at http://jeelabs.net/projects/hardware/wiki/Ether_Card.
  8. The library is now being used successfully with the Nanode, as minimal Ethernet connected Arduino compatible board, details available from http://wiki.london.hackspace.org.uk/view/Project:Nanode
  9. \section Download
  10. Download the latest library and examples from https://github.com/thiseldo/EtherShield
  11. To fully utilise the Nanode board, you will also require a library that can access the onboard MAC address chip.
  12. One such library is available from https://github.com/thiseldo/NanodeMAC and is used in the examples provided with this library.
  13. \section Instalation
  14. The library .zip file downloaded from https://github.com/thiseldo/EtherShield should be renamed to EtherShield.zip or EtherShield.tar.gz depending on the archive file you're downloading.
  15. The file should be extracted to the sketchbook/libraries/ folder so that there is a subdirectory called EtherSheild containing all the files from the archive.
  16. \section License
  17. This library is free software; you can redistribute it and/or
  18. modify it under the terms of the GNU Lesser General Public
  19. License as published by the Free Software Foundation; either
  20. version 2.1 of the License, or (at your option) any later version.
  21. This library is distributed in the hope that it will be useful,
  22. but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  24. Lesser General Public License for more details.
  25. A copy of the GNU Lesser General Public
  26. License is available from http://www.gnu.org/licenses/gpl.html; or write to the Free Software
  27. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  28. */
  29. #include "ip_config.h"
  30. #include "enc28j60.h"
  31. #include "ip_arp_udp_tcp.h"
  32. #include "websrv_help_functions.h"
  33. #ifdef DNS_client
  34. #include "dnslkup.h"
  35. #endif
  36. #ifdef DHCP_client
  37. #include "dhcp.h"
  38. #endif
  39. #include "EtherShield.h"
  40. /**
  41. * Initialise SPI, separate from main initialisation so that
  42. * multiple SPI devices can be used together
  43. */
  44. void ES_enc28j60SpiInit(SPI_HandleTypeDef *hspi){
  45. // ENC28J60_SPI1_Configuration();
  46. enc28j60_set_spi(hspi);
  47. }
  48. /**
  49. * Initialise the ENC28J60 using default chip select pin
  50. * Flash the 2 MagJack LEDs
  51. */
  52. void ES_enc28j60Init( uint8_t* macaddr ) {
  53. /*initialize enc28j60*/
  54. enc28j60Init( macaddr );
  55. enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
  56. HAL_Delay(10);
  57. int f;
  58. for( f=0; f<3; f++ ) {
  59. // 0x880 is PHLCON LEDB=on, LEDA=on
  60. // enc28j60PhyWrite(PHLCON,0b0011 1000 1000 00 00);
  61. enc28j60PhyWrite(PHLCON,0x3880);
  62. HAL_Delay(500);
  63. // 0x990 is PHLCON LEDB=off, LEDA=off
  64. // enc28j60PhyWrite(PHLCON,0b0011 1001 1001 00 00);
  65. enc28j60PhyWrite(PHLCON,0x3990);
  66. HAL_Delay(500);
  67. }
  68. // 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
  69. // enc28j60PhyWrite(PHLCON,0b0011 0100 0111 01 10);
  70. enc28j60PhyWrite(PHLCON,0x3476);
  71. HAL_Delay(100);
  72. }
  73. void ES_enc28j60clkout(uint8_t clk){
  74. enc28j60clkout(clk);
  75. }
  76. uint8_t ES_enc28j60linkup(void) {
  77. return enc28j60linkup();
  78. }
  79. void ES_enc28j60EnableBroadcast( void ) {
  80. enc28j60EnableBroadcast();
  81. }
  82. void ES_enc28j60DisableBroadcast( void ) {
  83. enc28j60DisableBroadcast();
  84. }
  85. void ES_enc28j60EnableMulticast( void ) {
  86. enc28j60EnableMulticast();
  87. }
  88. void ES_enc28j60DisableMulticast( void ) {
  89. enc28j60DisableMulticast();
  90. }
  91. uint8_t ES_enc28j60Read( uint8_t address ) {
  92. return enc28j60Read( address );
  93. }
  94. uint8_t ES_enc28j60Revision(void) {
  95. return enc28j60getrev();
  96. }
  97. void ES_enc28j60PhyWrite(uint8_t address, uint16_t data){
  98. enc28j60PhyWrite(address, data);
  99. }
  100. uint16_t ES_enc28j60PacketReceive(uint16_t len, uint8_t* packet){
  101. return enc28j60PacketReceive(len, packet);
  102. }
  103. void ES_enc28j60PacketSend(uint16_t len, uint8_t* packet){
  104. enc28j60PacketSend(len, packet);
  105. }
  106. void ES_init_ip_arp_udp_tcp(uint8_t *mymac,uint8_t *myip,uint16_t wwwp){
  107. init_ip_arp_udp_tcp(mymac,myip,wwwp);
  108. }
  109. uint8_t ES_eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len) {
  110. return eth_type_is_arp_and_my_ip(buf,len);
  111. }
  112. uint8_t ES_eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len) {
  113. return eth_type_is_ip_and_my_ip(buf, len);
  114. }
  115. void ES_make_echo_reply_from_request(uint8_t *buf,uint16_t len) {
  116. make_echo_reply_from_request(buf,len);
  117. }
  118. void ES_make_tcp_synack_from_syn(uint8_t *buf) {
  119. make_tcp_synack_from_syn(buf);
  120. }
  121. void ES_make_tcp_ack_from_any(uint8_t *buf,int16_t datlentoack,uint8_t addflags ) {
  122. void make_tcp_ack_from_any(uint8_t *buf,int16_t datlentoack,uint8_t addflags );
  123. }
  124. void ES_make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen ) {
  125. make_tcp_ack_with_data(buf, dlen);
  126. }
  127. void ES_make_tcp_ack_with_data_noflags(uint8_t *buf,uint16_t dlen ) {
  128. make_tcp_ack_with_data_noflags(buf, dlen);
  129. }
  130. uint16_t ES_build_tcp_data(uint8_t *buf, uint16_t srcPort ) {
  131. return build_tcp_data( buf, srcPort );
  132. }
  133. void ES_send_tcp_data(uint8_t *buf,uint16_t dlen ) {
  134. send_tcp_data(buf, dlen);
  135. }
  136. void ES_send_udp_data2(uint8_t *buf, uint8_t *destmac,uint16_t dlen,uint16_t source_port, uint8_t *dest_ip, uint16_t dest_port) {
  137. send_udp_prepare(buf,source_port, dest_ip, dest_port);
  138. uint8_t i;
  139. for(i = 0; i< 6; i++ )
  140. buf[ETH_DST_MAC+i] = destmac[i];
  141. send_udp_transmit(buf,dlen);
  142. }
  143. void ES_send_udp_data1(uint8_t *buf,uint16_t dlen,uint16_t source_port, uint8_t *dest_ip, uint16_t dest_port) {
  144. send_udp_prepare(buf,source_port, dest_ip, dest_port);
  145. send_udp_transmit(buf,dlen);
  146. }
  147. void ES_init_len_info(uint8_t *buf) {
  148. init_len_info(buf);
  149. }
  150. /*void ES_fill_buf_p(uint8_t *buf,uint16_t len, const prog_char *progmem_s) {
  151. fill_buf_p(buf, len, progmem_s);
  152. }*/
  153. uint16_t ES_checksum(uint8_t *buf, uint16_t len,uint8_t type) {
  154. return checksum(buf, len, type);
  155. }
  156. void ES_fill_ip_hdr_checksum(uint8_t *buf) {
  157. fill_ip_hdr_checksum(buf);
  158. }
  159. uint16_t ES_get_tcp_data_pointer(void) {
  160. return get_tcp_data_pointer();
  161. }
  162. uint16_t ES_packetloop_icmp_tcp(uint8_t *buf,uint16_t plen) {
  163. return packetloop_icmp_tcp(buf,plen);
  164. }
  165. /*uint16_t ES_fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s){
  166. return fill_tcp_data_p(buf, pos, progmem_s);
  167. }*/
  168. uint16_t ES_fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s){
  169. return fill_tcp_data(buf,pos, s);
  170. }
  171. uint16_t ES_fill_tcp_data_len(uint8_t *buf,uint16_t pos, const char *s, uint16_t len ){
  172. return fill_tcp_data_len(buf,pos, s, len);
  173. }
  174. void ES_www_server_reply(uint8_t *buf,uint16_t dlen) {
  175. www_server_reply(buf,dlen);
  176. }
  177. uint8_t ES_client_store_gw_mac(uint8_t *buf) {
  178. return client_store_gw_mac(buf);
  179. }
  180. void ES_client_set_gwip(uint8_t *gwipaddr) {
  181. client_set_gwip(gwipaddr);
  182. }
  183. void ES_client_set_wwwip(uint8_t *wwwipaddr) {
  184. //client_set_wwwip(wwwipaddr);
  185. client_tcp_set_serverip(wwwipaddr);
  186. }
  187. void ES_client_tcp_set_serverip(uint8_t *ipaddr) {
  188. client_tcp_set_serverip(ipaddr);
  189. }
  190. void ES_client_arp_whohas(uint8_t *buf,uint8_t *ip_we_search) {
  191. client_arp_whohas(buf, ip_we_search);
  192. }
  193. #if defined (TCP_client) || defined (WWW_client) || defined (NTP_client)
  194. uint8_t ES_client_tcp_req(uint8_t (*result_callback)(uint8_t fd,uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data),uint16_t (*datafill_callback)(uint8_t fd),uint16_t port ) {
  195. return client_tcp_req( result_callback, datafill_callback, port );
  196. }
  197. void ES_tcp_client_send_packet(uint8_t *buf,uint16_t dest_port, uint16_t src_port, uint8_t flags, uint8_t max_segment_size,
  198. uint8_t clear_seqck, uint16_t next_ack_num, uint16_t dlength, uint8_t *dest_mac, uint8_t *dest_ip){
  199. tcp_client_send_packet(buf, dest_port, src_port, flags, max_segment_size, clear_seqck, next_ack_num, dlength,dest_mac,dest_ip);
  200. }
  201. uint16_t ES_tcp_get_dlength( uint8_t *buf ){
  202. return tcp_get_dlength(buf);
  203. }
  204. #endif // TCP_client WWW_Client etc
  205. #ifdef WWW_client
  206. // ----- http get
  207. void ES_client_browse_url(char *urlbuf, char *urlbuf_varpart, char *hoststr,
  208. void (*callback)(uint8_t,uint16_t,uint16_t)) {
  209. client_browse_url(urlbuf, urlbuf_varpart, hoststr, callback);
  210. }
  211. void ES_client_http_post(char *urlbuf, char *hoststr, char *additionalheaderline,
  212. char *method, char *postval,void (*callback)(uint8_t,uint16_t)) {
  213. client_http_post(urlbuf, hoststr, additionalheaderline, method, postval,callback);
  214. }
  215. #endif // WWW_client
  216. #ifdef NTP_client
  217. void ES_client_ntp_request(uint8_t *buf,uint8_t *ntpip,uint8_t srcport) {
  218. client_ntp_request(buf,ntpip,srcport);
  219. }
  220. uint8_t ES_client_ntp_process_answer(uint8_t *buf,uint32_t *time,uint8_t dstport_l) {
  221. return client_ntp_process_answer(buf,time,dstport_l);
  222. }
  223. #endif // NTP_client
  224. void ES_register_ping_rec_callback(void (*callback)(uint8_t *srcip)) {
  225. register_ping_rec_callback(callback);
  226. }
  227. #ifdef PING_client
  228. void ES_client_icmp_request(uint8_t *buf,uint8_t *destip) {
  229. client_icmp_request(buf,destip);
  230. }
  231. uint8_t ES_packetloop_icmp_checkreply(uint8_t *buf,uint8_t *ip_monitoredhost) {
  232. return packetloop_icmp_checkreply(buf,ip_monitoredhost);
  233. }
  234. #endif // PING_client
  235. #ifdef WOL_client
  236. void ES_send_wol(uint8_t *buf,uint8_t *wolmac) {
  237. send_wol(buf,wolmac);
  238. }
  239. #endif // WOL_client
  240. #ifdef FROMDECODE_websrv_help
  241. uint8_t ES_find_key_val(char *str,char *strbuf, uint16_t maxlen,char *key) {
  242. return find_key_val(str,strbuf, maxlen,key);
  243. }
  244. void ES_urldecode(char *urlbuf) {
  245. urldecode(urlbuf);
  246. }
  247. #endif
  248. #ifdef URLENCODE_websrv_help
  249. void ES_urlencode(char *str,char *urlbuf) {
  250. urlencode(str,urlbuf);
  251. }
  252. #endif
  253. uint8_t ES_parse_ip(uint8_t *bytestr,char *str) {
  254. return parse_ip(bytestr,str);
  255. }
  256. void ES_mk_net_str(char *resultstr,uint8_t *bytestr,uint16_t len,char separator,uint8_t base) {
  257. mk_net_str(resultstr,bytestr,len,separator,base);
  258. }
  259. uint8_t ES_client_waiting_gw() {
  260. return( client_waiting_gw() );
  261. }
  262. #ifdef DNS_client
  263. uint8_t ES_dnslkup_haveanswer(void)
  264. {
  265. return( dnslkup_haveanswer() );
  266. }
  267. uint8_t ES_dnslkup_get_error_info(void)
  268. {
  269. return( dnslkup_get_error_info() );
  270. }
  271. uint8_t * ES_dnslkup_getip(void)
  272. {
  273. return(dnslkup_getip() );
  274. }
  275. void ES_dnslkup_set_dnsip(uint8_t *dnsipaddr) {
  276. dnslkup_set_dnsip(dnsipaddr);
  277. }
  278. void ES_dnslkup_request(uint8_t *buf,uint8_t *hostname) {
  279. return( dnslkup_request(buf, hostname) );
  280. }
  281. uint8_t ES_udp_client_check_for_dns_answer(uint8_t *buf,uint16_t plen){
  282. return( udp_client_check_for_dns_answer( buf, plen) );
  283. }
  284. // Perform all processing to resolve a hostname to IP address.
  285. // Returns 1 for successful Name resolution, 0 otherwise
  286. uint8_t resolveHostname(uint8_t *buf, uint16_t buffer_size, uint8_t *hostname ) {
  287. uint16_t dat_p;
  288. int plen = 0;
  289. long lastDnsRequest = HAL_GetTick();
  290. uint8_t dns_state = DNS_STATE_INIT;
  291. bool gotAddress = FALSE;
  292. uint8_t dnsTries = 3; // After 10 attempts fail gracefully so other action can be carried out
  293. while( !gotAddress ) {
  294. // handle ping and wait for a tcp packet
  295. plen = enc28j60PacketReceive(buffer_size, buf);
  296. dat_p=packetloop_icmp_tcp(buf,plen);
  297. // We have a packet
  298. // Check if IP data
  299. if (dat_p == 0) {
  300. if (client_waiting_gw() ) {
  301. // No ARP received for gateway
  302. continue;
  303. }
  304. // It has IP data
  305. if (dns_state==DNS_STATE_INIT) {
  306. dns_state=DNS_STATE_REQUESTED;
  307. lastDnsRequest = HAL_GetTick();
  308. dnslkup_request(buf,hostname);
  309. continue;
  310. }
  311. if (dns_state!=DNS_STATE_ANSWER){
  312. // retry every minute if dns-lookup failed:
  313. if (HAL_GetTick() > (lastDnsRequest + 60000L) ){
  314. if( --dnsTries <= 0 )
  315. return 0; // Failed to allocate address
  316. dns_state=DNS_STATE_INIT;
  317. lastDnsRequest = HAL_GetTick();
  318. }
  319. // don't try to use client before
  320. // we have a result of dns-lookup
  321. continue;
  322. }
  323. }
  324. else {
  325. if (dns_state==DNS_STATE_REQUESTED && udp_client_check_for_dns_answer( buf, plen ) ){
  326. dns_state=DNS_STATE_ANSWER;
  327. //client_set_wwwip(dnslkup_getip());
  328. client_tcp_set_serverip(dnslkup_getip());
  329. gotAddress = TRUE;
  330. }
  331. }
  332. }
  333. return 1;
  334. }
  335. #endif // DNS_client
  336. #ifdef DHCP_client
  337. void ES_dhcp_start(uint8_t *buf, uint8_t *macaddrin, uint8_t *ipaddrin,
  338. uint8_t *maskin, uint8_t *gwipin, uint8_t *dhcpsvrin, uint8_t *dnssvrin ) {
  339. dhcp_start(buf, macaddrin, ipaddrin, maskin, gwipin, dhcpsvrin, dnssvrin );
  340. }
  341. uint8_t ES_dhcp_state(void)
  342. {
  343. return( dhcp_state() );
  344. }
  345. uint8_t ES_check_for_dhcp_answer(uint8_t *buf,uint16_t plen){
  346. return( check_for_dhcp_answer( buf, plen) );
  347. }
  348. // Utility functions
  349. // Perform all processing to get an IP address plus other addresses returned, e.g. gw, dns, dhcp server.
  350. // Returns 1 for successful IP address allocation, 0 otherwise
  351. uint8_t allocateIPAddress(uint8_t *buf, uint16_t buffer_size, uint8_t *mymac, uint16_t myport, uint8_t *myip, uint8_t *mynetmask, uint8_t *gwip, uint8_t *dnsip, uint8_t *dhcpsvrip ) {
  352. uint16_t dat_p;
  353. int plen = 0;
  354. long lastDhcpRequest = HAL_GetTick();
  355. uint8_t dhcpState = 0;
  356. bool gotIp = FALSE;
  357. uint8_t dhcpTries = 10; // After 10 attempts fail gracefully so other action can be carried out
  358. dhcp_start( buf, mymac, myip, mynetmask,gwip, dnsip, dhcpsvrip );
  359. while( !gotIp ) {
  360. // handle ping and wait for a tcp packet
  361. plen = enc28j60PacketReceive(buffer_size, buf);
  362. dat_p=packetloop_icmp_tcp(buf,plen);
  363. if(dat_p==0) {
  364. check_for_dhcp_answer( buf, plen);
  365. dhcpState = dhcp_state();
  366. // we are idle here
  367. if( dhcpState != DHCP_STATE_OK ) {
  368. if (HAL_GetTick() > (lastDhcpRequest + 10000L) ){
  369. lastDhcpRequest = HAL_GetTick();
  370. if( --dhcpTries <= 0 )
  371. return 0; // Failed to allocate address
  372. // send dhcp
  373. dhcp_start( buf, mymac, myip, mynetmask,gwip, dnsip, dhcpsvrip );
  374. }
  375. } else {
  376. if( !gotIp ) {
  377. gotIp = TRUE;
  378. //init the ethernet/ip layer:
  379. init_ip_arp_udp_tcp(mymac, myip, myport);
  380. // Set the Router IP
  381. client_set_gwip(gwip); // e.g internal IP of dsl router
  382. // Set the DNS server IP address if required, or use default
  383. dnslkup_set_dnsip( dnsip );
  384. }
  385. }
  386. }
  387. }
  388. return 1;
  389. }
  390. #endif // DHCP_client
  391. void ES_enc28j60PowerUp(){
  392. enc28j60PowerUp();
  393. }
  394. void ES_enc28j60PowerDown(){
  395. enc28j60PowerDown();
  396. }
  397. // TCP functions broken out here for testing
  398. uint8_t ES_nextTcpState( uint8_t *buf, uint16_t plen ) {
  399. return nextTcpState(buf, plen );
  400. }
  401. uint8_t ES_currentTcpState( ) {
  402. return currentTcpState( );
  403. }
  404. uint8_t ES_tcpActiveOpen( uint8_t *buf,uint16_t plen,
  405. uint8_t (*result_callback)(uint8_t fd,uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data),
  406. uint16_t (*datafill_callback)(uint8_t fd),
  407. uint16_t port ) {
  408. return tcpActiveOpen(buf, plen, result_callback, datafill_callback, port );
  409. }
  410. void ES_tcpPassiveOpen( uint8_t *buf,uint16_t plen ) {
  411. tcpPassiveOpen(buf, plen );
  412. }
  413. void ES_tcpClose( uint8_t *buf,uint16_t plen ) {
  414. tcpClose(buf, plen );
  415. }
  416. // End