/* dload - Dot command for downloading files on the Spectrum Next Copyright (C) 2025 Ian Cowburn (ianc@noddybox.co.uk) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -------------------------------------------------------------------------- Wifi interface */ #include #include #include #include #include "wifi.h" #define MAX_PROTOCOL_LEN 10 #define MAX_HOSTNAME_LEN 255 #define MAX_PATH_LEN 255 /* ---------------------------------------- PRIVATE ROUTINES */ static WifiStatus SendToModem(const char *buffer, size_t len) { while(len) { WifiStatus status; if ((status = SendByte(*buffer)) != eWifiOK) { return status; } buffer++; len--; } return eWifiOK; } static WifiStatus ConnectToModem(void) { return eWifiTimeout; } static void Copy(const char *from, const char *to, char *buff, size_t maxlen) { while(maxlen && ((to && from != to) || (!to && *from))) { *buff++ = *from++; maxlen--; } if (maxlen) { *buff = 0; } else { *--buff = 0; } } static int ParseURL(const char *url, char *hostname, char *path, int *port, int *ssl) { char protocol[MAX_PROTOCOL_LEN]; const char *double_slash; const char *colon; const char *slash; double_slash = strstr(url, "//"); if (double_slash && double_slash != url) { Copy(url, double_slash - 1, protocol, MAX_PROTOCOL_LEN); } else { strcpy(protocol, "http"); } colon = strchr(double_slash ? double_slash + 2 : url, ':'); slash = strchr(double_slash ? double_slash + 2 : url, '/'); if (colon) { char buff[10]; Copy(colon + 1, slash, buff, 10); *port = atoi(buff); Copy(double_slash ? double_slash + 2 : url, colon, hostname, MAX_HOSTNAME_LEN); } else { if (strcmp(protocol, "http") == 0) { *port = 80; } else if (strcmp(protocol, "https") == 0) { *port = 443; } else { return 0; } Copy(double_slash ? double_slash + 2 : url, slash, hostname, MAX_HOSTNAME_LEN); } *ssl = (strcmp(protocol, "https") == 0); if (slash) { Copy(slash, NULL, path, MAX_PATH_LEN); } else { strcpy(path, "/"); } if (!hostname[0]) { return 0; } return 1; } static void Chomp(char *p) { size_t l = strlen(p); while(l && (p[l - 1] == '\r' || p[l - 1] == '\n')) { p[--l] = 0; } } static WifiStatus ReadLine(char *buff, size_t maxlen) { size_t len = 0; WifiStatus status; unsigned char c; while(len < maxlen && ((status = GetByte(&c)) == eWifiOK)) { buff[len++] = c; buff[len] = 0; if (len > 1) { if (buff[len - 1] == '\n' && buff[len - 2] == '\r') { Chomp(buff); return eWifiOK; } } } return eWifiFailedToReceive; } static WifiStatus SendATCommand(const char *command) { char line[80]; WifiStatus status; if((status = SendToModem(command, strlen(command))) != eWifiOK) { return status; } if((status = ReadLine(line, sizeof line)) != eWifiOK) { return status; } return strcmp("OK", line) == 0 ? eWifiOK : eWifiFailedToSendCommand; } /* ---------------------------------------- PUBLIC ROUTINES */ WifiStatus WifiConnect(void) { return ConnectToModem(); } WifiStatus ConnectURL(int is_post, const char *url, size_t *content_length) { char hostname[MAX_HOSTNAME_LEN]; char path[MAX_PATH_LEN]; int port; int ssl; WifiStatus status; if (!ParseURL(url, hostname, path, &port, &ssl)) { return eWifiInvalidURL; } if ((status = SendATCommand("AT+CIPMUX=0\r\n")) != eWifiOK) { return status; }` return eWifiTimeout; } WifiStatus SendFormatted(const char *format, ...) { char buff[256]; va_list va; va_start(va, format); vsnprintf(buff, sizeof buff, format, va); va_end(va); return SendToModem(buff, strlen(buff)); } WifiStatus SendByte(unsigned char c) { return eWifiTimeout; } WifiStatus GetByte(unsigned char *c) { *c = 0; return eWifiTimeout; } /* vim: ai sw=4 ts=8 expandtab */