rusEFI
The most advanced open source ECU
wifi_console.cpp
Go to the documentation of this file.
1 #include "pch.h"
2 
3 #if EFI_WIFI
4 
5 #include "driver/include/m2m_wifi.h"
6 #include "socket/include/socket.h"
7 
8 #include "thread_controller.h"
9 #include "tunerstudio.h"
10 
11 static int listenerSocket = -1;
12 static int connectionSocket = -1;
13 
14 chibios_rt::BinarySemaphore isrSemaphore(/* taken =*/ true);
15 
16 void os_hook_isr() {
17  isrSemaphore.signalI();
18 }
19 
20 // TX Helper data
21 static const uint8_t* sendBuffer;
22 static size_t sendSize;
23 bool sendRequest = false;
24 chibios_rt::BinarySemaphore sendDoneSemaphore(/* taken =*/ true);
25 
26 // RX Helper data
27 static uint8_t recvBuffer[512];
28 static input_queue_t wifiIqueue;
29 
30 static bool socketReady = false;
31 
32 class WifiChannel final : public TsChannelBase {
33 public:
34  WifiChannel()
35  : TsChannelBase("WiFi")
36  {
37  }
38 
39  bool isReady() const override {
40  return socketReady;
41  }
42 
43  void write(const uint8_t* buffer, size_t size, bool /*isEndOfPacket*/) final override {
44  while (size > 0) {
45  // Write at most SOCKET_BUFFER_MAX_LENGTH bytes at a time
46  size_t chunkSize = size > SOCKET_BUFFER_MAX_LENGTH ? SOCKET_BUFFER_MAX_LENGTH : size;
47 
48  // Write this chunk
50  sendSize = chunkSize;
51  sendRequest = true;
52  isrSemaphore.signal();
53 
54  // Step buffer/size for the next chunk
55  buffer += chunkSize;
56  size -= chunkSize;
57 
58  // Wait for this chunk to complete
59  sendDoneSemaphore.wait();
60  }
61  }
62 
63  size_t readTimeout(uint8_t* buffer, size_t size, int timeout) override {
64  return iqReadTimeout(&wifiIqueue, buffer, size, timeout);
65  }
66 };
67 
68 static NO_CACHE WifiChannel wifiChannel;
69 
70 class WifiHelperThread : public ThreadController<4096> {
71 public:
72  WifiHelperThread() : ThreadController("WiFi", WIFI_THREAD_PRIORITY) {}
73  void ThreadTask() override {
74  while (true)
75  {
76  m2m_wifi_handle_events(nullptr);
77 
78  if (socketReady && sendRequest) {
79  send(connectionSocket, (void*)sendBuffer, sendSize, 0);
80  sendRequest = false;
81  } else {
82  isrSemaphore.wait(TIME_MS2I(1));
83  }
84  }
85  }
86 };
87 
88 static NO_CACHE WifiHelperThread wifiHelper;
89 
90 static tstrWifiInitParam param;
91 
92 static tstrM2MAPConfig apConfig;
93 
94 void wifiCallback(uint8 u8MsgType, void* pvMsg) {
95  switch (u8MsgType) {
96  case M2M_WIFI_REQ_DHCP_CONF: {
97  auto& dhcpInfo = *reinterpret_cast<tstrM2MIPConfig*>(pvMsg);
98  uint8_t* addr = reinterpret_cast<uint8_t*>(&dhcpInfo.u32StaticIP);
99  efiPrintf("WiFi client connected DHCP IP is %d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
100  } break;
101  default:
102  efiPrintf("WifiCallback: %d", (int)u8MsgType);
103  break;
104  }
105 }
106 
107 static NO_CACHE uint8_t rxBuf[512];
108 
109 static void socketCallback(SOCKET sock, uint8_t u8Msg, void* pvMsg) {
110  switch (u8Msg) {
111  case SOCKET_MSG_BIND: {
112  auto bindMsg = reinterpret_cast<tstrSocketBindMsg*>(pvMsg);
113 
114  if (bindMsg && bindMsg->status == 0) {
115  // Socket bind complete, now listen!
116  listen(sock, 1);
117  }
118  } break;
119  case SOCKET_MSG_LISTEN: {
120  auto listenMsg = reinterpret_cast<tstrSocketListenMsg*>(pvMsg);
121  if (listenMsg && listenMsg->status == 0) {
122  // Listening, now accept a connection
123  accept(sock, nullptr, nullptr);
124  }
125  } break;
126  case SOCKET_MSG_ACCEPT: {
127  auto acceptMsg = reinterpret_cast<tstrSocketAcceptMsg*>(pvMsg);
128  if (acceptMsg && (acceptMsg->sock >= 0)) {
129  connectionSocket = acceptMsg->sock;
130 
131  recv(connectionSocket, &rxBuf, 1, 0);
132 
133  socketReady = true;
134  }
135  } break;
136  case SOCKET_MSG_RECV: {
137  auto recvMsg = reinterpret_cast<tstrSocketRecvMsg*>(pvMsg);
138  if (recvMsg && (recvMsg->s16BufferSize > 0)) {
139  {
140  chibios_rt::CriticalSectionLocker csl;
141 
142  for (size_t i = 0; i < recvMsg->s16BufferSize; i++) {
143  iqPutI(&wifiIqueue, rxBuf[i]);
144  }
145  }
146 
147  size_t nextRecv;
148  if (recvMsg->u16RemainingSize < 1) {
149  // Always try to read at least 1 byte
150  nextRecv = 1;
151  } else if (recvMsg->u16RemainingSize > sizeof(rxBuf)) {
152  // Remaining is too big for the buffer, so just read one buffer worth
153  nextRecv = sizeof(rxBuf);
154  } else {
155  // The full thing will fit, try to read it
156  nextRecv = recvMsg->u16RemainingSize;
157  }
158 
159  // start the next recv
160  recv(sock, &rxBuf, nextRecv, 0);
161  } else {
162  close(sock);
163 
164  socketReady = false;
165 
166  {
167  chibios_rt::CriticalSectionLocker csl;
168  iqResetI(&wifiIqueue);
169  }
170  }
171  } break;
172  case SOCKET_MSG_SEND: {
173  // Send completed, notify caller!
174  chibios_rt::CriticalSectionLocker csl;
175  sendDoneSemaphore.signalI();
176  } break;
177  }
178 }
179 
180 struct WifiConsoleThread : public TunerstudioThread {
181  WifiConsoleThread() : TunerstudioThread("WiFi Console") { }
182 
183  TsChannelBase* setupChannel() override {
184  // Initialize the WiFi module
185  param.pfAppWifiCb = wifiCallback;
186  if (M2M_SUCCESS != m2m_wifi_init(&param)) {
187  return nullptr;
188  }
189 
190  strcpy(apConfig.au8SSID, "FOME EFI");
191  apConfig.u8ListenChannel = 1;
192  apConfig.u8SecType = M2M_WIFI_SEC_OPEN;
193  apConfig.u8SsidHide = 0;
194 
195  // IP Address
196  apConfig.au8DHCPServerIP[0] = 192;
197  apConfig.au8DHCPServerIP[1] = 168;
198  apConfig.au8DHCPServerIP[2] = 1;
199  apConfig.au8DHCPServerIP[3] = 1;
200 
201  // Trigger AP
202  if (M2M_SUCCESS != m2m_wifi_enable_ap(&apConfig)) {
203  return nullptr;
204  }
205 
206  // Start the helper thread
207  wifiHelper.start();
208 
209  // Set up the socket APIs
210  socketInit();
211  registerSocketCallback(socketCallback, nullptr);
212 
213  // Start listening on the socket
214  sockaddr_in address;
215  address.sin_family = AF_INET;
216  address.sin_port = _htons(17999);
217  address.sin_addr.s_addr = 0;
218 
219  listenerSocket = socket(AF_INET, SOCK_STREAM, SOCKET_CONFIG_SSL_OFF);
220  bind(listenerSocket, (sockaddr*)&address, sizeof(address));
221 
222  return &wifiChannel;
223  }
224 };
225 
226 static NO_CACHE WifiConsoleThread wifiThread;
227 
229  iqObjectInit(&wifiIqueue, recvBuffer, sizeof(recvBuffer), nullptr, nullptr);
230 
231  wifiThread.start();
232 }
233 
234 #endif // EFI_WIFI
constexpr uint8_t addr
Definition: ads1015.cpp:5
A base class for a controller that requires its own thread.
virtual void ThreadTask()=0
ThreadController(const char *name, tprio_t priority)
virtual bool isReady() const
virtual void write(const uint8_t *buffer, size_t size, bool isEndOfPacket=false)=0
virtual size_t readTimeout(uint8_t *buffer, size_t size, int timeout)=0
TsChannelBase(const char *name)
virtual TsChannelBase * setupChannel()=0
static FIL FDLogFile NO_CACHE
Definition: mmc_card.cpp:116
composite packet size
static BigBufferHandle buffer
static NO_CACHE WifiChannel wifiChannel
static bool socketReady
static int connectionSocket
static tstrWifiInitParam param
static NO_CACHE WifiHelperThread wifiHelper
static const uint8_t * sendBuffer
static NO_CACHE WifiConsoleThread wifiThread
static void socketCallback(SOCKET sock, uint8_t u8Msg, void *pvMsg)
void wifiCallback(uint8 u8MsgType, void *pvMsg)
void os_hook_isr()
static size_t sendSize
static int listenerSocket
static NO_CACHE uint8_t rxBuf[512]
static input_queue_t wifiIqueue
bool sendRequest
static uint8_t recvBuffer[512]
void startWifiConsole()
chibios_rt::BinarySemaphore sendDoneSemaphore(true)
chibios_rt::BinarySemaphore isrSemaphore(true)
static tstrM2MAPConfig apConfig