This commit is contained in:
soapysoltionss 2023-10-31 14:34:45 +08:00
commit 2a38789890
27 changed files with 1574 additions and 266 deletions

View File

@ -5,6 +5,7 @@ add_subdirectory(line_sensor)
add_subdirectory(car)
add_subdirectory(ultrasonic_sensor)
add_subdirectory(magnetometer)
add_subdirectory(frontend)
add_executable(rtos_car rtos_car.c)
@ -20,6 +21,7 @@ target_include_directories(rtos_car PRIVATE
${CMAKE_CURRENT_LIST_DIR}/motor
${CMAKE_CURRENT_LIST_DIR}/line_sensor
${CMAKE_CURRENT_LIST_DIR}/ultrasonic_sensor
${CMAKE_CURRENT_LIST_DIR}/frontend
)
target_link_libraries(rtos_car
pico_cyw43_arch_lwip_sys_freertos

View File

@ -10,6 +10,18 @@
#define ALPHA ( 0.01f ) // Complementary
// Filter Constant
// LSM303DLHC temperature compensation coefficients
#define SCALE_Z ( 1.0f ) // Scale for Z-axis
#define OFFSET_Z ( 3.0f ) // Offset for Z-axis
#define TEMPERATURE_OFFSET ( 25.0f ) // Reference
// temperature for
// calibration
#define TEMPERATURE_COEFFICIENT_Z ( 0.33f ) // Temperature
// coefficient for
// Z-axis
/**
* @brief The orientation of the car
*/

View File

@ -18,42 +18,67 @@
#define DIRECTION_LEFT_FORWARD (1U << DIRECTION_PIN_LEFT_IN4)
#define DIRECTION_LEFT_BACKWARD (1U << DIRECTION_PIN_LEFT_IN3)
#define DIRECTION_FORWARD (DIRECTION_RIGHT_FORWARD | DIRECTION_LEFT_FORWARD)
#define DIRECTION_BACKWARD (DIRECTION_RIGHT_BACKWARD | DIRECTION_LEFT_BACKWARD)
#define DIRECTION_LEFT (DIRECTION_RIGHT_FORWARD | DIRECTION_LEFT_BACKWARD)
#define DIRECTION_RIGHT (DIRECTION_RIGHT_BACKWARD | DIRECTION_LEFT_FORWARD)
#define SPEED_PIN_RIGHT 15U
#define SPEED_PIN_LEFT 16U
#define PWM_CLK_DIV 250.f
#define PWM_WRAP 5000U
/*
* ultimate gain Ku about 14, ultimate period Tu about 8 * 50 = 400ms
* Ku = 14, Tu = 400ms,
* Kp = 0.6 * Ku = 8.4
* Ki = Kp / Tu = 0.021
* Kd = Kp * Tu / 8 = 42
*/
#define PID_KP 8.4f
#define PID_KI 0.021f // 0.005f
#define PID_KD 42.f // 0.05f
#define MAX_SPEED 4900U
#define MIN_SPEED 0U // To be changed
/*!
* @brief Structure for the motor speed
* @param target_speed The target speed of the wheel, in cm/s
* @param pwm_level The pwm level of the wheel, from 0 to 5000
* @param sem The semaphore for the wheel
* @param p_slice_num The pointer to the slice number of the wheel
* @param channel The pwm channel of the wheel, left A or right B
* @brief Structure for the motor speed parameters
* @param target_speed_cms Target speed in cm/s
* @param current_speed_cms Current speed in cm/s
* @param distance_cm Distance travelled in cm
*/
typedef struct {
float target_speed_cms;
float current_speed_cms;
uint16_t pwm_level;
SemaphoreHandle_t sem;
uint slice_num;
uint pwm_channel;
float distance;
float current_cms;
float distance_cm;
} motor_speed_t;
/*!
* @brief Structure for the motor PWM parameters
* @param slice_num PWM slice number
* @param pwm_channel PWM channel, either A or B
* @param pwm_level PWM level, from 0 to 5000
*/
typedef struct {
uint slice_num;
uint channel;
uint16_t level;
} motor_pwm_t;
/*!
* @brief Structure for the motor PID parameters
* @param pid_kp Proportional gain
* @param pid_ki Integral gain
* @param pid_kd Derivative gain
*/
typedef struct {
float kp_value;
float ki_value;
float kd_value;
} motor_pid_t;
/*!
* @brief Structure for the motor parameters
* @param speed Motor speed parameters
* @param sem Semaphore for the motor speed
* @param pwm Motor PWM parameters
* @param pid Motor PID parameters
*/
typedef struct {
motor_speed_t speed;
SemaphoreHandle_t sem;
motor_pwm_t pwm;
motor_pid_t pid;
} motor_t;
#endif /* MOTOR_CONFIG_H */

View File

@ -0,0 +1,39 @@
add_executable(
frontend
frontend.c
)
#message("Running makefsdata python script")
#execute_process(COMMAND
# py makefsdata.py
# WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
#)
message("Running makefsdata C script")
execute_process(COMMAND
gcc makefsdata.c -o makefsdata.exe
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
message("Generating htmldata.c")
execute_process(COMMAND
./makefsdata.exe
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(
frontend
hardware_adc
pico_stdlib
#FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
pico_cyw43_arch_lwip_threadsafe_background
pico_lwip_http
)
target_include_directories(frontend PRIVATE
#../config
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}../config
)
pico_enable_stdio_usb(frontend 1)
pico_add_extra_outputs(frontend)

View File

@ -0,0 +1,143 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES 1
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_CORE_AFFINITY 0
#endif
/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

60
frtos/frontend/cgi.h Normal file
View File

@ -0,0 +1,60 @@
#include "lwip/apps/httpd.h"
#include "pico/cyw43_arch.h"
#include "stdio.h"
// CGI handler for start/stop car
const char * cgi_status_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
{
// Check if an request for LED has been made (/led.cgi?led=x)
// check if start/stop car button
if (strcmp(pcParam[0] , "status") == 0){
// Look at the argument to check if LED is to be turned on (x=1) or off (x=0)
if(strcmp(pcValue[0], "0") == 0){
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
printf("CAR STOP"); // call car stop func
}else if(strcmp(pcValue[0], "1") == 0){
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
printf("CAR START"); // call car start func
}
}
// Send the index page back to the user
return "/index.shtml";
}
// CGI handler for speed control
const char * cgi_speed_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
{
// Check if an request for LED has been made (/led.cgi?led=x)
// check for speed increment/decrement control
if (strcmp(pcParam[0] , "speed") == 0){
if(strcmp(pcValue[0], "0") == 0){
printf("SPEED Decrease"); // call speed decrement
}else if(strcmp(pcValue[0], "1") == 0){
printf("Speed Increase"); // call speed increment
}
}
// Send the index page back to the user
return "/index.shtml";
}
// tCGI Struct
// Fill this with all of the CGI requests and their respective handlers
static const tCGI cgi_handlers[] = {
{
// Html request for "/status.cgi" triggers cgi_handler
"/status.cgi", cgi_status_handler
},
{
// Html request for "/speed.cgi" triggers cgi_handler
"/speed.cgi", cgi_speed_handler
},
};
void cgi_init(void)
{
http_set_cgi_handlers(cgi_handlers, 2);
}

56
frtos/frontend/frontend.c Normal file
View File

@ -0,0 +1,56 @@
#include "lwip/apps/httpd.h"
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "lwipopts.h"
#include "ssi.h"
#include "cgi.h"
#include "lwip/inet.h"
//#include "FreeRTOS.h"
//#include "task.h"
#include "lwip/sockets.h"
// WIFI Credentials - take care if pushing to GitHub!
const char WIFI_SSID[] = "XXX";
const char WIFI_PASSWORD[] = "XXX";
void print_ip_address() {
struct netif *netif = netif_list;
while (netif != NULL) {
if (netif_is_up(netif)) {
printf("IP Address: %s\n", ipaddr_ntoa(&(netif->ip_addr)));
}
netif = netif->next;
}
}
int main() {
stdio_init_all();
cyw43_arch_init();
cyw43_arch_enable_sta_mode();
// Connect to the WiFI network - loop until connected
while(cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000) != 0){
printf("Attempting to connect...\n");
}
// Print a success message once connected
printf("Connected! \n");
// Print the assigned IP address
print_ip_address();
// Initialize web server
httpd_init();
printf("Http server initialized\n");
// Configure SSI and CGI handler
ssi_init();
printf("SSI Handler initialized\n");
cgi_init();
printf("CGI Handler initialized\n");
// Infinite loop
while(1);
}

View File

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
}
h1 {
color: #333;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.buttons {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.button {
padding: 10px 20px;
font-size: 18px;
background-color: #0074d9;
color: white;
border: none;
cursor: pointer;
}
.speed {
font-size: 24px;
margin-top: 20px;
}
.speed-control {
display: flex;
align-items: center;
justify-content: center;
}
.output {
font-size: 24px;
margin-top: 20px;
}
.pid-output {
font-size: 24px;
margin-top: 20px;
}
.orientation-output {
font-size: 24px;
margin-top: 20px;
}
.maze-map {
margin-top: 20px;
width: 200px;
height: 200px;
border: 1px solid #333;
}
</style>
</head>
<body>
<h1>Car Control Panel</h1>
<div class="container">
<div class="time">
<p id="elapsed-time">0 seconds</p>
</div>
<div class="buttons">
<a href="/status.cgi?status=1" ><button class="button" >Start</button></a>
<a href="/status.cgi?status=0" ><button class="button" >Stop</button></a>
</div>
<div class="speed">
<p>Speed: <!--#speed--></span></p>
<div class="speed-control">
<a href="/speed.cgi?speed=0" ><button class="button" >-</button></a>
<a href="/speed.cgi?speed=1" ><button class="button" >+</button></a>
</div>
</div>
<div class="output">
<p>Barcode Scanner Output: <!--#barcode--></span></p>
</div>
<div class="pid-output">
<p>PID Controller Output: <!--#pid--></p>
</div>
<div class="orientation-output">
<p>Orientation: <!--#orient--></p>
</div>
<div class="maze-map" id="maze-map">
<!-- maze map part -->
</div>
</div>
<script>
// Function to update and display elapsed time
function updateElapsedTime() {
// Check if the start time is stored in localStorage
let startTime = localStorage.getItem('startTime');
if (!startTime) {
// If no start time is stored, set the current time as the start time
startTime = Date.now();
localStorage.setItem('startTime', startTime);
}
// Calculate the elapsed time in seconds
const currentTime = Date.now();
const elapsedTime = Math.floor((currentTime - startTime) / 1000);
// Update the displayed elapsed time
document.getElementById('elapsed-time').textContent = `${elapsedTime} seconds`;
}
// Call the updateElapsedTime function when the page loads
window.onload = updateElapsedTime;
// Update the elapsed time every second
setInterval(updateElapsedTime, 1000);
</script>
</body>
</html>

384
frtos/frontend/htmldata.c Normal file
View File

@ -0,0 +1,384 @@
static const unsigned char data_index_shtml[] = {
/* ./index.shtml */
0x2F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x2E, 0x73, 0x68, 0x74, 0x6D, 0x6C, 0x00,
0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x30, 0x20, 0x32,
0x30, 0x30, 0x20, 0x4F, 0x4B, 0x0D, 0x0A, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x3A, 0x20, 0x6C, 0x77, 0x49, 0x50, 0x2F,
0x70, 0x72, 0x65, 0x2D, 0x30, 0x2E, 0x36, 0x20, 0x28, 0x68,
0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E,
0x73, 0x69, 0x63, 0x73, 0x2E, 0x73, 0x65, 0x2F, 0x7E, 0x61,
0x64, 0x61, 0x6D, 0x2F, 0x6C, 0x77, 0x69, 0x70, 0x2F, 0x29,
0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D,
0x74, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x74, 0x65, 0x78, 0x74,
0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x0D, 0x0A, 0x0D, 0x0A,
0x3C, 0x21, 0x44, 0x4F, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20,
0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x0D, 0x0A, 0x3C, 0x68, 0x74,
0x6D, 0x6C, 0x3E, 0x0D, 0x0A, 0x3C, 0x68, 0x65, 0x61, 0x64,
0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x73, 0x74,
0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x7B,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x66,
0x61, 0x6D, 0x69, 0x6C, 0x79, 0x3A, 0x20, 0x41, 0x72, 0x69,
0x61, 0x6C, 0x2C, 0x20, 0x73, 0x61, 0x6E, 0x73, 0x2D, 0x73,
0x65, 0x72, 0x69, 0x66, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74,
0x65, 0x78, 0x74, 0x2D, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3A,
0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D,
0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x68, 0x31, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63,
0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x33, 0x33, 0x33,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x2E, 0x63, 0x6F, 0x6E, 0x74, 0x61,
0x69, 0x6E, 0x65, 0x72, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x3A, 0x20, 0x66,
0x6C, 0x65, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C,
0x65, 0x78, 0x2D, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,
0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x6F, 0x6C, 0x75, 0x6D, 0x6E,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
0x2D, 0x69, 0x74, 0x65, 0x6D, 0x73, 0x3A, 0x20, 0x63, 0x65,
0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2E, 0x62,
0x75, 0x74, 0x74, 0x6F, 0x6E, 0x73, 0x20, 0x7B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x3A,
0x20, 0x66, 0x6C, 0x65, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6A, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x2D, 0x63, 0x6F,
0x6E, 0x74, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x63, 0x65, 0x6E,
0x74, 0x65, 0x72, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x61,
0x70, 0x3A, 0x20, 0x32, 0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2D, 0x74,
0x6F, 0x70, 0x3A, 0x20, 0x32, 0x30, 0x70, 0x78, 0x3B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D,
0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x2E, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x20,
0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69,
0x6E, 0x67, 0x3A, 0x20, 0x31, 0x30, 0x70, 0x78, 0x20, 0x32,
0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F,
0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x31,
0x38, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61,
0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2D, 0x63,
0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x30, 0x30, 0x37,
0x34, 0x64, 0x39, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F,
0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65,
0x72, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x63, 0x75, 0x72, 0x73, 0x6F, 0x72, 0x3A, 0x20,
0x70, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D,
0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x2E, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x7B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69,
0x7A, 0x65, 0x3A, 0x20, 0x32, 0x34, 0x70, 0x78, 0x3B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2D,
0x74, 0x6F, 0x70, 0x3A, 0x20, 0x32, 0x30, 0x70, 0x78, 0x3B,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x2E, 0x73, 0x70, 0x65, 0x65, 0x64, 0x2D,
0x63, 0x6F, 0x6E, 0x74, 0x72, 0x6F, 0x6C, 0x20, 0x7B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79,
0x3A, 0x20, 0x66, 0x6C, 0x65, 0x78, 0x3B, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x2D, 0x69, 0x74, 0x65,
0x6D, 0x73, 0x3A, 0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x69,
0x66, 0x79, 0x2D, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74,
0x3A, 0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D,
0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x2E, 0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20,
0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D,
0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x32, 0x34, 0x70, 0x78,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69,
0x6E, 0x2D, 0x74, 0x6F, 0x70, 0x3A, 0x20, 0x32, 0x30, 0x70,
0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x2E, 0x70, 0x69, 0x64, 0x2D,
0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x7B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A,
0x65, 0x3A, 0x20, 0x32, 0x34, 0x70, 0x78, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2D, 0x74,
0x6F, 0x70, 0x3A, 0x20, 0x32, 0x30, 0x70, 0x78, 0x3B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D,
0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x2E, 0x6F, 0x72, 0x69, 0x65, 0x6E, 0x74, 0x61,
0x74, 0x69, 0x6F, 0x6E, 0x2D, 0x6F, 0x75, 0x74, 0x70, 0x75,
0x74, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x6E,
0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x32, 0x34,
0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x61, 0x72,
0x67, 0x69, 0x6E, 0x2D, 0x74, 0x6F, 0x70, 0x3A, 0x20, 0x32,
0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2E, 0x6D, 0x61,
0x7A, 0x65, 0x2D, 0x6D, 0x61, 0x70, 0x20, 0x7B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2D, 0x74,
0x6F, 0x70, 0x3A, 0x20, 0x32, 0x30, 0x70, 0x78, 0x3B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20,
0x32, 0x30, 0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, 0x32, 0x30,
0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F,
0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x31, 0x70, 0x78, 0x20,
0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x23, 0x33, 0x33, 0x33,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F,
0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x3C, 0x2F,
0x68, 0x65, 0x61, 0x64, 0x3E, 0x0D, 0x0A, 0x3C, 0x62, 0x6F,
0x64, 0x79, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C,
0x68, 0x31, 0x3E, 0x43, 0x61, 0x72, 0x20, 0x43, 0x6F, 0x6E,
0x74, 0x72, 0x6F, 0x6C, 0x20, 0x50, 0x61, 0x6E, 0x65, 0x6C,
0x3C, 0x2F, 0x68, 0x31, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6C, 0x61, 0x73,
0x73, 0x3D, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E,
0x65, 0x72, 0x22, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x63,
0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x74, 0x69, 0x6D, 0x65,
0x22, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x70, 0x20, 0x69,
0x64, 0x3D, 0x22, 0x65, 0x6C, 0x61, 0x70, 0x73, 0x65, 0x64,
0x2D, 0x74, 0x69, 0x6D, 0x65, 0x22, 0x3E, 0x30, 0x20, 0x73,
0x65, 0x63, 0x6F, 0x6E, 0x64, 0x73, 0x3C, 0x2F, 0x70, 0x3E,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3C, 0x2F, 0x64, 0x69, 0x76, 0x3E, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x64, 0x69, 0x76,
0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x62, 0x75,
0x74, 0x74, 0x6F, 0x6E, 0x73, 0x22, 0x3E, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x3C, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3D, 0x22,
0x2F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2E, 0x63, 0x67,
0x69, 0x3F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3D, 0x31,
0x22, 0x20, 0x3E, 0x3C, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E,
0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x62, 0x75,
0x74, 0x74, 0x6F, 0x6E, 0x22, 0x20, 0x3E, 0x53, 0x74, 0x61,
0x72, 0x74, 0x3C, 0x2F, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E,
0x3E, 0x3C, 0x2F, 0x61, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x3C, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66,
0x3D, 0x22, 0x2F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2E,
0x63, 0x67, 0x69, 0x3F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x3D, 0x30, 0x22, 0x20, 0x3E, 0x3C, 0x62, 0x75, 0x74, 0x74,
0x6F, 0x6E, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22,
0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x22, 0x20, 0x3E, 0x53,
0x74, 0x6F, 0x70, 0x3C, 0x2F, 0x62, 0x75, 0x74, 0x74, 0x6F,
0x6E, 0x3E, 0x3C, 0x2F, 0x61, 0x3E, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69,
0x76, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6C, 0x61,
0x73, 0x73, 0x3D, 0x22, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22,
0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x70, 0x3E, 0x53, 0x70,
0x65, 0x65, 0x64, 0x3A, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x23,
0x73, 0x70, 0x65, 0x65, 0x64, 0x2D, 0x2D, 0x3E, 0x3C, 0x2F,
0x73, 0x70, 0x61, 0x6E, 0x3E, 0x3C, 0x2F, 0x70, 0x3E, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6C,
0x61, 0x73, 0x73, 0x3D, 0x22, 0x73, 0x70, 0x65, 0x65, 0x64,
0x2D, 0x63, 0x6F, 0x6E, 0x74, 0x72, 0x6F, 0x6C, 0x22, 0x3E,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x61,
0x20, 0x68, 0x72, 0x65, 0x66, 0x3D, 0x22, 0x2F, 0x73, 0x70,
0x65, 0x65, 0x64, 0x2E, 0x63, 0x67, 0x69, 0x3F, 0x73, 0x70,
0x65, 0x65, 0x64, 0x3D, 0x30, 0x22, 0x20, 0x3E, 0x3C, 0x62,
0x75, 0x74, 0x74, 0x6F, 0x6E, 0x20, 0x63, 0x6C, 0x61, 0x73,
0x73, 0x3D, 0x22, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x22,
0x20, 0x3E, 0x2D, 0x3C, 0x2F, 0x62, 0x75, 0x74, 0x74, 0x6F,
0x6E, 0x3E, 0x3C, 0x2F, 0x61, 0x3E, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x3C, 0x61, 0x20, 0x68, 0x72, 0x65,
0x66, 0x3D, 0x22, 0x2F, 0x73, 0x70, 0x65, 0x65, 0x64, 0x2E,
0x63, 0x67, 0x69, 0x3F, 0x73, 0x70, 0x65, 0x65, 0x64, 0x3D,
0x31, 0x22, 0x20, 0x3E, 0x3C, 0x62, 0x75, 0x74, 0x74, 0x6F,
0x6E, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x62,
0x75, 0x74, 0x74, 0x6F, 0x6E, 0x22, 0x20, 0x3E, 0x2B, 0x3C,
0x2F, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x3E, 0x3C, 0x2F,
0x61, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69,
0x76, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69, 0x76, 0x3E, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x64,
0x69, 0x76, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22,
0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x3E, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x3C, 0x70, 0x3E, 0x42, 0x61, 0x72, 0x63, 0x6F,
0x64, 0x65, 0x20, 0x53, 0x63, 0x61, 0x6E, 0x6E, 0x65, 0x72,
0x20, 0x4F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3A, 0x20, 0x3C,
0x21, 0x2D, 0x2D, 0x23, 0x62, 0x61, 0x72, 0x63, 0x6F, 0x64,
0x65, 0x2D, 0x2D, 0x3E, 0x3C, 0x2F, 0x73, 0x70, 0x61, 0x6E,
0x3E, 0x3C, 0x2F, 0x70, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69, 0x76,
0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6C, 0x61, 0x73,
0x73, 0x3D, 0x22, 0x70, 0x69, 0x64, 0x2D, 0x6F, 0x75, 0x74,
0x70, 0x75, 0x74, 0x22, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C,
0x70, 0x3E, 0x50, 0x49, 0x44, 0x20, 0x43, 0x6F, 0x6E, 0x74,
0x72, 0x6F, 0x6C, 0x6C, 0x65, 0x72, 0x20, 0x4F, 0x75, 0x74,
0x70, 0x75, 0x74, 0x3A, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x23,
0x70, 0x69, 0x64, 0x2D, 0x2D, 0x3E, 0x3C, 0x2F, 0x70, 0x3E,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3C, 0x2F, 0x64, 0x69, 0x76, 0x3E, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x64, 0x69, 0x76,
0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x6F, 0x72,
0x69, 0x65, 0x6E, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2D,
0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x3E, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x3C, 0x70, 0x3E, 0x4F, 0x72, 0x69, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x3C, 0x21,
0x2D, 0x2D, 0x23, 0x6F, 0x72, 0x69, 0x65, 0x6E, 0x74, 0x2D,
0x2D, 0x3E, 0x3C, 0x2F, 0x70, 0x3E, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69,
0x76, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6C, 0x61,
0x73, 0x73, 0x3D, 0x22, 0x6D, 0x61, 0x7A, 0x65, 0x2D, 0x6D,
0x61, 0x70, 0x22, 0x20, 0x69, 0x64, 0x3D, 0x22, 0x6D, 0x61,
0x7A, 0x65, 0x2D, 0x6D, 0x61, 0x70, 0x22, 0x3E, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x6D, 0x61, 0x7A,
0x65, 0x20, 0x6D, 0x61, 0x70, 0x20, 0x70, 0x61, 0x72, 0x74,
0x20, 0x2D, 0x2D, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69, 0x76, 0x3E,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x64, 0x69,
0x76, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46,
0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F,
0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x61, 0x6E,
0x64, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x20,
0x65, 0x6C, 0x61, 0x70, 0x73, 0x65, 0x64, 0x20, 0x74, 0x69,
0x6D, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E,
0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6C, 0x61,
0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6D, 0x65, 0x28, 0x29,
0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43,
0x68, 0x65, 0x63, 0x6B, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x69,
0x6D, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x74, 0x6F, 0x72,
0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x6F, 0x63, 0x61,
0x6C, 0x53, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72,
0x74, 0x54, 0x69, 0x6D, 0x65, 0x20, 0x3D, 0x20, 0x6C, 0x6F,
0x63, 0x61, 0x6C, 0x53, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65,
0x2E, 0x67, 0x65, 0x74, 0x49, 0x74, 0x65, 0x6D, 0x28, 0x27,
0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x27,
0x29, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
0x20, 0x28, 0x21, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69,
0x6D, 0x65, 0x29, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x49, 0x66, 0x20, 0x6E,
0x6F, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x69,
0x6D, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x74, 0x6F, 0x72,
0x65, 0x64, 0x2C, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68,
0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20,
0x74, 0x69, 0x6D, 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x69,
0x6D, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x20,
0x3D, 0x20, 0x44, 0x61, 0x74, 0x65, 0x2E, 0x6E, 0x6F, 0x77,
0x28, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x53, 0x74, 0x6F, 0x72,
0x61, 0x67, 0x65, 0x2E, 0x73, 0x65, 0x74, 0x49, 0x74, 0x65,
0x6D, 0x28, 0x27, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69,
0x6D, 0x65, 0x27, 0x2C, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
0x54, 0x69, 0x6D, 0x65, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20,
0x43, 0x61, 0x6C, 0x63, 0x75, 0x6C, 0x61, 0x74, 0x65, 0x20,
0x74, 0x68, 0x65, 0x20, 0x65, 0x6C, 0x61, 0x70, 0x73, 0x65,
0x64, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x69, 0x6E, 0x20,
0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x73, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x63, 0x75, 0x72,
0x72, 0x65, 0x6E, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x20, 0x3D,
0x20, 0x44, 0x61, 0x74, 0x65, 0x2E, 0x6E, 0x6F, 0x77, 0x28,
0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73,
0x74, 0x20, 0x65, 0x6C, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54,
0x69, 0x6D, 0x65, 0x20, 0x3D, 0x20, 0x4D, 0x61, 0x74, 0x68,
0x2E, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x28, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6E, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x20,
0x2D, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6D,
0x65, 0x29, 0x20, 0x2F, 0x20, 0x31, 0x30, 0x30, 0x30, 0x29,
0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20,
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x65, 0x64,
0x20, 0x65, 0x6C, 0x61, 0x70, 0x73, 0x65, 0x64, 0x20, 0x74,
0x69, 0x6D, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x63,
0x75, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x67, 0x65, 0x74, 0x45,
0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x42, 0x79, 0x49, 0x64,
0x28, 0x27, 0x65, 0x6C, 0x61, 0x70, 0x73, 0x65, 0x64, 0x2D,
0x74, 0x69, 0x6D, 0x65, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78,
0x74, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x3D,
0x20, 0x60, 0x24, 0x7B, 0x65, 0x6C, 0x61, 0x70, 0x73, 0x65,
0x64, 0x54, 0x69, 0x6D, 0x65, 0x7D, 0x20, 0x73, 0x65, 0x63,
0x6F, 0x6E, 0x64, 0x73, 0x60, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F,
0x2F, 0x20, 0x43, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65,
0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6C, 0x61,
0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6D, 0x65, 0x20, 0x66,
0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x77, 0x68,
0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x67,
0x65, 0x20, 0x6C, 0x6F, 0x61, 0x64, 0x73, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x6E,
0x64, 0x6F, 0x77, 0x2E, 0x6F, 0x6E, 0x6C, 0x6F, 0x61, 0x64,
0x20, 0x3D, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45,
0x6C, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6D, 0x65,
0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6C, 0x61,
0x70, 0x73, 0x65, 0x64, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20,
0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x65, 0x63, 0x6F,
0x6E, 0x64, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x74, 0x65, 0x72,
0x76, 0x61, 0x6C, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x45, 0x6C, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6D,
0x65, 0x2C, 0x20, 0x31, 0x30, 0x30, 0x30, 0x29, 0x3B, 0x0D,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C,
0x2F, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F,
0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0D, 0x0A, 0x3C, 0x2F, 0x68,
0x74, 0x6D, 0x6C, 0x3E, 0x0D, 0x0A, };
const struct fsdata_file file_index_shtml[] = {{ NULL, data_index_shtml, data_index_shtml + 13, sizeof(data_index_shtml) - 13, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT }};
#define FS_ROOT file_index_shtml
#define FS_NUMFILES 1

93
frtos/frontend/lwipopts.h Normal file
View File

@ -0,0 +1,93 @@
// Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)]
// allow override in some examples
#ifndef NO_SYS
#define NO_SYS 1
#endif
// allow override in some examples
#ifndef LWIP_SOCKET
#define LWIP_SOCKET 0
#endif
#if PICO_CYW43_ARCH_POLL
#define MEM_LIBC_MALLOC 1
#else
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#endif
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
// #define ETH_PAD_SIZE 2
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define PPP_DEBUG LWIP_DBG_OFF
#define SLIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
// This section enables HTTPD server with SSI, SGI
// and tells server which converted HTML files to use
#define LWIP_HTTPD 1
#define LWIP_HTTPD_SSI 1
#define LWIP_HTTPD_CGI 1
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
#define HTTPD_FSDATA_FILE "htmldata.c"

129
frtos/frontend/makefsdata.c Normal file
View File

@ -0,0 +1,129 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Function to encode a string to hexadecimal
void stringToHex(const char* input, char* file, int length) {
for (int i = 0; i < length; i++) {
sprintf(file + 2 * i, "%02X", input[i]);
}
}
int main() {
FILE *file;
file = fopen("htmldata.c", "w");
const char *folder[] = {
//Add your file path here
"./html_files/index.shtml"
};
const char *files[] = {
"./index.shtml"
};
char *varnames[100] = {
};
int fileCount = sizeof(files)/sizeof(files[0]);
for(int i = 0; i< fileCount ;i++){
char header[1024];
char fvar[256];
if (strstr(files[i], "404")) {
snprintf(header, sizeof(header), "HTTP/1.0 404 File not found\r\n");
} else {
snprintf(header, sizeof(header), "HTTP/1.0 200 OK\r\n");
}
snprintf(header + strlen(header), sizeof(header) - strlen(header),
"Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n");
// Add content-type based on files extension
if (strstr(files[i], ".html") || strstr(files[i], ".shtml")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: text/html\r\n");
} else if (strstr(files[i], ".jpg")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: image/jpeg\r\n");
} else if (strstr(files[i], ".gif")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: image/gif\r\n");
} else if (strstr(files[i], ".png")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: image/png\r\n");
} else if (strstr(files[i], ".class")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: application/octet-stream\r\n");
} else if (strstr(files[i], ".js")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: text/javascript\r\n");
} else if (strstr(files[i], ".css")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: text/css\r\n");
} else if (strstr(files[i], ".svg")) {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: image/svg+xml\r\n");
} else {
snprintf(header + strlen(header), sizeof(header) - strlen(header), "Content-type: text/plain\r\n");
}
snprintf(header + strlen(header), sizeof(header) - strlen(header), "\r\n");
// Create a variable name for the files[i]
strcpy(fvar, files[i] + 1); // Remove the leading dot in the filename
for (int j = 0; fvar[j]; j++) {
if (fvar[j] == '/' || fvar[j] == '\\') {
fvar[j] = '_';
} else if (fvar[j] == '.') {
fvar[j] = '_';
}
}
fprintf(file, "static const unsigned char data%s[] = {\n", fvar);
fprintf(file, "\t/* %s */\n\t", files[i]);
// Encode the filename as hexadecimal
char hexFileName[2 * strlen(files[i]) + 1];
stringToHex(files[i] + 1, hexFileName, strlen(files[i]) - 1);
int count = 0;
for (int j = 0; hexFileName[j]; j++) {
fprintf(file, "0x%c%c, ", hexFileName[j], hexFileName[j + 1]);
j++;
count++;
}
fprintf(file, "0x00,\n\t");
// Encode the HTTP header as hexadecimal
char hexHeader[2 * strlen(header) + 1];
stringToHex(header, hexHeader, strlen(header));
count = 0;
for (int j = 0; hexHeader[j]; j++) {
fprintf(file, "0x%c%c, ", hexHeader[j], hexHeader[j + 1]);
j++;
count++;
if (count == 10) {
fprintf(file, "\n\t");
count = 0;
}
}
fprintf(file, "\n\t");
// Encode the file content as hexadecimal
FILE* filePtr = fopen(folder[i], "rb");
count = 0;
if (filePtr) {
int ch;
while ((ch = fgetc(filePtr)) != EOF) {
fprintf(file, "0x%02X, ", ch);
count++;
if (count == 10) {
fprintf(file, "\n\t");
count = 0;
}
}
fclose(filePtr);
}
fprintf(file, "};\n\n");
varnames[i] = malloc(strlen(fvar) + 1);
strcpy(varnames[i], fvar);
fprintf(file, "const struct fsdata_file file%s[] = {{ %s, data%s, data%s + %d, sizeof(data%s) - %d, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT }};\n",
fvar,"NULL", fvar, fvar, strlen(files[i]) , fvar, strlen(files[i]));
}
fprintf(file, "\n#define FS_ROOT file%s\n",varnames[fileCount - 1] );
fprintf(file, "#define FS_NUMFILES %d\n", fileCount);
fclose(file);
}

Binary file not shown.

View File

@ -0,0 +1,106 @@
#!/usr/bin/python3
# This script is by @rspeir on GitHub:
# https://github.com/krzmaz/pico-w-webserver-example/pull/1/files/4b3e78351dd236f213da9bebbb20df690d470476#diff-e675c4a367e382db6f9ba61833a58c62029d8c71c3156a9f238b612b69de279d
# Renamed output to avoid linking incorrect file
import os
import binascii
#Create file to write output into
output = open('htmldata.c', 'w')
#Traverse directory, generate list of files
files = list()
os.chdir('./html_files')
for(dirpath, dirnames, filenames) in os.walk('.'):
files += [os.path.join(dirpath, file) for file in filenames]
filenames = list()
varnames = list()
#Generate appropriate HTTP headers
for file in files:
if '404' in file:
header = "HTTP/1.0 404 File not found\r\n"
else:
header = "HTTP/1.0 200 OK\r\n"
header += "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"
if '.html' in file:
header += "Content-type: text/html\r\n"
elif '.shtml' in file:
header += "Content-type: text/html\r\n"
elif '.jpg' in file:
header += "Content-type: image/jpeg\r\n"
elif '.gif' in file:
header += "Content-type: image/gif\r\n"
elif '.png' in file:
header += "Content-type: image/png\r\n"
elif '.class' in file:
header += "Content-type: application/octet-stream\r\n"
elif '.js' in file:
header += "Content-type: text/javascript\r\n"
elif '.css' in file:
header += "Content-type: text/css\r\n"
elif '.svg' in file:
header += "Content-type: image/svg+xml\r\n"
else:
header += "Content-type: text/plain\r\n"
header += "\r\n"
fvar = file[1:] #remove leading dot in filename
fvar = fvar.replace('/', '_') #replace *nix path separator with underscore
fvar = fvar.replace('\\', '_') #replace DOS path separator with underscore
fvar = fvar.replace('.', '_') #replace file extension dot with underscore
output.write("static const unsigned char data{}[] = {{\n".format(fvar))
output.write("\t/* {} */\n\t".format(file))
#first set of hex data encodes the filename
b = bytes(file[1:].replace('\\', '/'), 'utf-8') #change DOS path separator to forward slash
for byte in binascii.hexlify(b, b' ', 1).split():
output.write("0x{}, ".format(byte.decode()))
output.write("0,\n\t")
#second set of hex data is the HTTP header/mime type we generated above
b = bytes(header, 'utf-8')
count = 0
for byte in binascii.hexlify(b, b' ', 1).split():
output.write("0x{}, ".format(byte.decode()))
count = count + 1
if(count == 10):
output.write("\n\t")
count = 0
output.write("\n\t")
#finally, dump raw hex data from files
with open(file, 'rb') as f:
count = 0
while(byte := f.read(1)):
byte = binascii.hexlify(byte)
output.write("0x{}, ".format(byte.decode()))
count = count + 1
if(count == 10):
output.write("\n\t")
count = 0
output.write("};\n\n")
filenames.append(file[1:])
varnames.append(fvar)
for i in range(len(filenames)):
prevfile = "NULL"
if(i > 0):
prevfile = "file" + varnames[i-1]
output.write("const struct fsdata_file file{0}[] = {{{{ {1}, data{2}, ".format(varnames[i], prevfile, varnames[i]))
output.write("data{} + {}, ".format(varnames[i], len(filenames[i]) + 1))
output.write("sizeof(data{}) - {}, ".format(varnames[i], len(filenames[i]) + 1))
output.write("FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}};\n")
output.write("\n#define FS_ROOT file{}\n".format(varnames[-1]))
output.write("#define FS_NUMFILES {}\n".format(len(filenames)))

56
frtos/frontend/ssi.h Normal file
View File

@ -0,0 +1,56 @@
#include "lwip/apps/httpd.h"
#include "pico/cyw43_arch.h"
#include "hardware/adc.h"
#include "pico/stdlib.h"
// SSI tags - tag length limited to 8 bytes by default
const char * ssi_tags[] = {"speed","barcode","pid","orient"};
u16_t ssi_handler(int iIndex, char *pcInsert, int iInsertLen) {
size_t printed;
switch (iIndex) {
case 0: // Speed
{
// call getSpeed() function
const float Speed = adc_read() * 3.3f / (1 << 12);
printed = snprintf(pcInsert, iInsertLen, "%f ",Speed);
}
break;
case 1: // barcode
{
// call getBarcodeOutput() function
const char* barC = "36" ;
printed = snprintf(pcInsert, iInsertLen, "%s", barC);
}
break;
case 2: //PID
{
// whatever to display for PID
const char* PID = "54" ;
printed = snprintf(pcInsert, iInsertLen, "%s", PID);
}
break;
case 3: //Orientation
{
// call getOrientation() function
const char* orien = "South" ;
printed = snprintf(pcInsert, iInsertLen, "%s", orien);
}
break;
default:
printed = 0;
break;
}
return (u16_t)printed;
}
// Initialise the SSI handler
void ssi_init() {
// Initialise ADC (internal pin)
adc_init();
adc_set_temp_sensor_enabled(true);
adc_select_input(4);
http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags));
}

View File

@ -15,13 +15,34 @@
*
* @param params
*/
//void
//monitor_left_sensor_task(__unused void *params) {
// for (;;)
// {
// if (xSemaphoreTake(g_left_sensor_sem, portMAX_DELAY) == pdTRUE)
// {
// if (left_sensor_triggered == pdTRUE)
// {
// printf("left sensor triggered\n");
// // Get Current State
// state_t state = gpio_get(LEFT_SENSOR_PIN);
//
// xMessageBufferSend(left_sensor_msg_buffer,
// &state,
// sizeof(state_t),
// 0);
// // Reset the flag
// left_sensor_triggered = pdFALSE;
// }
// }
// }
//}
void
monitor_left_sensor_task(__unused void *params) {
for (;;)
{
if (xSemaphoreTake(g_left_sensor_sem, portMAX_DELAY) == pdTRUE)
{
if (left_sensor_triggered == pdTRUE)
{
printf("left sensor triggered\n");
// Get Current State
@ -31,9 +52,6 @@ monitor_left_sensor_task(__unused void *params) {
&state,
sizeof(state_t),
0);
// Reset the flag
left_sensor_triggered = pdFALSE;
}
}
}
}
@ -46,12 +64,32 @@ monitor_left_sensor_task(__unused void *params) {
*
* @param params
*/
//void
//monitor_right_sensor_task(void *params) {
// for (;;) {
// if (xSemaphoreTake(g_right_sensor_sem, portMAX_DELAY) == pdTRUE) {
// // Check the flag or receive the message
// if (right_sensor_triggered == pdTRUE) {
// printf("right sensor triggered\n");
// // Get Current State
// state_t state = gpio_get(RIGHT_SENSOR_PIN);
//
// xMessageBufferSend(right_sensor_msg_buffer,
// &state,
// sizeof(state_t),
// 0);
// // Reset the flag
// right_sensor_triggered = pdFALSE;
// }
// }
// }
//}
void
monitor_right_sensor_task(void *params) {
for (;;) {
if (xSemaphoreTake(g_right_sensor_sem, portMAX_DELAY) == pdTRUE) {
// Check the flag or receive the message
if (right_sensor_triggered == pdTRUE) {
printf("right sensor triggered\n");
// Get Current State
state_t state = gpio_get(RIGHT_SENSOR_PIN);
@ -60,9 +98,6 @@ monitor_right_sensor_task(void *params) {
&state,
sizeof(state_t),
0);
// Reset the flag
right_sensor_triggered = pdFALSE;
}
}
}
}

View File

@ -24,17 +24,17 @@ launch()
irq_set_enabled(IO_IRQ_BANK0, true);
// struct repeating_timer g_left_sensor_timer;
// add_repeating_timer_ms(LINE_SENSOR_READ_DELAY,
// h_left_sensor_timer_handler,
// NULL,
// &g_left_sensor_timer);
//
// struct repeating_timer g_right_sensor_timer;
// add_repeating_timer_ms(LINE_SENSOR_READ_DELAY,
// h_right_sensor_timer_handler,
// NULL,
// &g_right_sensor_timer);
struct repeating_timer g_left_sensor_timer;
add_repeating_timer_ms(LINE_SENSOR_READ_DELAY,
h_left_sensor_timer_handler,
NULL,
&g_left_sensor_timer);
struct repeating_timer g_right_sensor_timer;
add_repeating_timer_ms(LINE_SENSOR_READ_DELAY,
h_right_sensor_timer_handler,
NULL,
&g_right_sensor_timer);
TaskHandle_t h_monitor_left_sensor_task;
xTaskCreate(monitor_left_sensor_task,

View File

@ -28,15 +28,7 @@
#define LSM303_TEMP_OUT_H_M 0x31
#define LSM303_TEMP_OUT_L_M 0x32
// LSM303DLHC temperature compensation coefficients
#define SCALE_Z 0.9 // Scale factor for Z-axis
#define OFFSET_Z 5.0 // Offset for Z-axis
#define TEMPERATURE_OFFSET 25.0 // Reference temperature for calibration
#define TEMPERATURE_COEFFICIENT_Z 0.33
#define OFFSET_Z 5.0
#define SCALE_Z 0.9
#define ACCEL_ADDR 0x19
#define MAG_ADDR 0x1E

View File

@ -6,15 +6,13 @@
*
* @details The direction of the car is calculated using the roll, pitch and yaw
* The roll and pitch are calculated using the accelerometer data
* The yaw is calculated using the magnetometer data
* The yaw is calculated using the magnetometer and accelerometer data
* The roll, pitch and yaw are combined to calculate the direction
* of the car
*
* The direction of the car is calculated using the complementary
* filter
* of the car with a complementary filter and compensating for the
* temperature.
*
* The complementary filter is used to combine the accelerometer
* and magnetometer data to calculate the direction of the car
* and magnetometer data (yaw) to calculate the direction of the car
*
* Source:
* https://www.nxp.com/docs/en/application-note/AN3461.pdf

View File

@ -30,9 +30,9 @@ main (void)
{
stdio_usb_init();
sleep_ms(2000);
// sleep_ms(2000);
printf("Test started!\n");
// printf("Test started!\n");
magnetometer_init();
launch();

View File

@ -19,12 +19,55 @@
void
set_wheel_direction(uint32_t direction)
{
static const uint32_t mask = DIRECTION_LEFT_FORWARD |
DIRECTION_LEFT_BACKWARD |
DIRECTION_RIGHT_FORWARD |
DIRECTION_RIGHT_BACKWARD;
static const uint32_t mask
= DIRECTION_LEFT_FORWARD | DIRECTION_LEFT_BACKWARD
| DIRECTION_RIGHT_FORWARD | DIRECTION_RIGHT_BACKWARD;
gpio_put_masked(mask, 0U);
gpio_set_mask(direction);
}
/*!
* @brief Turn the wheel, must set the priority higher than the motor PID task
* @param direction The direction of the wheel
* @param direction_after The direction of the wheel after turning
* @param speed_after The speed of the wheel after turning
*/
void
turn_wheel(uint32_t direction)
{
set_wheel_speed(0u);
vTaskDelay(pdMS_TO_TICKS(1000));
float initial_right = g_motor_right.speed.distance_cm;
float initial_left = g_motor_left.speed.distance_cm;
set_wheel_direction(direction);
set_wheel_speed(3500u);
for (;;)
{
// gap between wheels = 11.3cm, to turn 90 degrees, need to travel
// 11.3 * pi / 4 = 8.9cm
if (g_motor_left.speed.distance_cm - initial_left >= 6.8f)
{
g_motor_left.pwm.level = 0;
pwm_set_chan_level(g_motor_left.pwm.slice_num,
g_motor_left.pwm.channel,
g_motor_left.pwm.level);
}
if (g_motor_right.speed.distance_cm - initial_right >= 6.8f)
{
g_motor_right.pwm.level = 0;
pwm_set_chan_level(g_motor_right.pwm.slice_num,
g_motor_right.pwm.channel,
g_motor_right.pwm.level);
}
if (g_motor_left.pwm.level == 0u && g_motor_right.pwm.level == 0u)
{
break;
}
}
vTaskDelay(pdMS_TO_TICKS(1000));
}

View File

@ -19,20 +19,23 @@
#include "motor_config.h"
motor_speed_t g_motor_speed_left = { .pwm_level = 2500u,
.pwm_channel = PWM_CHAN_A,
.distance = 0.0f,};
motor_t g_motor_left = { .pwm.level = 0u,
.pwm.channel = PWM_CHAN_A,
.speed.distance_cm = 0.0f };
motor_speed_t g_motor_speed_right = { .pwm_level = 2500u,
.pwm_channel = PWM_CHAN_B,
.distance = 0.0f,};
motor_t g_motor_right = { .pwm.level = 0u,
.pwm.channel = PWM_CHAN_B,
.speed.distance_cm = 0.0f,
.pid.kp_value = 1000.f,
.pid.ki_value = 0.0f,
.pid.kd_value = 10000.0f,};
void
motor_init(void)
{
// Semaphore
g_motor_speed_left.sem = xSemaphoreCreateBinary();
g_motor_speed_right.sem = xSemaphoreCreateBinary();
g_motor_left.sem = xSemaphoreCreateBinary();
g_motor_right.sem = xSemaphoreCreateBinary();
gpio_init(SPEED_PIN_RIGHT);
gpio_init(SPEED_PIN_LEFT);
@ -54,21 +57,21 @@ motor_init(void)
gpio_set_function(PWM_PIN_LEFT, GPIO_FUNC_PWM);
gpio_set_function(PWM_PIN_RIGHT, GPIO_FUNC_PWM);
g_motor_speed_left.slice_num = pwm_gpio_to_slice_num(PWM_PIN_LEFT);
g_motor_speed_right.slice_num = pwm_gpio_to_slice_num(PWM_PIN_RIGHT);
g_motor_left.pwm.slice_num = pwm_gpio_to_slice_num(PWM_PIN_LEFT);
g_motor_right.pwm.slice_num = pwm_gpio_to_slice_num(PWM_PIN_RIGHT);
// NOTE: PWM clock is 125MHz for raspberrypi pico w by default
// 125MHz / 250 = 500kHz
pwm_set_clkdiv(g_motor_speed_left.slice_num, PWM_CLK_DIV);
pwm_set_clkdiv(g_motor_speed_right.slice_num, PWM_CLK_DIV);
pwm_set_clkdiv(g_motor_left.pwm.slice_num, PWM_CLK_DIV);
pwm_set_clkdiv(g_motor_right.pwm.slice_num, PWM_CLK_DIV);
// have them to be 500kHz / 5000 = 100Hz
pwm_set_wrap(g_motor_speed_left.slice_num, (PWM_WRAP - 1U));
pwm_set_wrap(g_motor_speed_right.slice_num, (PWM_WRAP - 1U));
pwm_set_wrap(g_motor_left.pwm.slice_num, (PWM_WRAP - 1U));
pwm_set_wrap(g_motor_right.pwm.slice_num, (PWM_WRAP - 1U));
pwm_set_enabled(g_motor_speed_left.slice_num, true);
pwm_set_enabled(g_motor_speed_right.slice_num, true);
pwm_set_enabled(g_motor_left.pwm.slice_num, true);
pwm_set_enabled(g_motor_right.pwm.slice_num, true);
}
#endif /* MOTOR_INIT_H */

View File

@ -16,18 +16,18 @@
* @return The control signal
*/
float
compute_pid(const volatile float *target_speed,
const volatile float *current_speed,
float *integral,
float *prev_error)
compute_pid(float *integral, float *prev_error)
{
float error = *target_speed - *current_speed;
float error
= g_motor_left.speed.distance_cm - g_motor_right.speed.distance_cm;
*integral += error;
float derivative = error - *prev_error;
float control_signal
= PID_KP * error + PID_KI * (*integral) + PID_KD * derivative;
float control_signal = g_motor_right.pid.kp_value * error
+ g_motor_right.pid.ki_value * (*integral)
+ g_motor_right.pid.kd_value * derivative;
*prev_error = error;
@ -35,37 +35,42 @@ compute_pid(const volatile float *target_speed,
}
void
motor_pid_task(void *p_param)
motor_pid_task(__unused void *p_param)
{
motor_speed_t *p_motor_speed = p_param;
float integral = 0.0f;
float prev_error = 0.0f;
for (;;)
{
float control_signal = compute_pid(&(p_motor_speed->target_speed_cms),
&(p_motor_speed->current_speed_cms),
&integral, &prev_error);
if (p_motor_speed->pwm_level + control_signal > MAX_SPEED)
if (g_motor_left.pwm.level == 0u)
{
p_motor_speed->pwm_level = MAX_SPEED;
}
else if (p_motor_speed->pwm_level + control_signal < MIN_SPEED)
{
p_motor_speed->pwm_level = MIN_SPEED;
}
else
{
p_motor_speed->pwm_level = p_motor_speed->pwm_level + control_signal;
g_motor_right.pwm.level = 0;
pwm_set_chan_level(g_motor_right.pwm.slice_num,
g_motor_right.pwm.channel,
g_motor_right.pwm.level);
vTaskDelay(pdMS_TO_TICKS(50));
continue;
}
// printf("control signal: %f\n", control_signal);
// printf("new pwm: %hu\n\n", p_motor_speed->pwm_level);
float control_signal = compute_pid(&integral, &prev_error);
pwm_set_chan_level(p_motor_speed->slice_num,
p_motor_speed->pwm_channel,
p_motor_speed->pwm_level);
float temp = (float) g_motor_right.pwm.level + control_signal * 0.05f;
if (temp > MAX_SPEED)
{
temp = MAX_SPEED;
}
if (temp < MIN_SPEED)
{
temp = MIN_SPEED;
}
g_motor_right.pwm.level = (uint16_t) temp;
pwm_set_chan_level(g_motor_right.pwm.slice_num,
g_motor_right.pwm.channel,
g_motor_right.pwm.level);
vTaskDelay(pdMS_TO_TICKS(50));
}

View File

@ -17,7 +17,7 @@ h_wheel_sensor_isr_handler(void)
gpio_acknowledge_irq(SPEED_PIN_LEFT, GPIO_IRQ_EDGE_FALL);
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(g_motor_speed_left.sem,
xSemaphoreGiveFromISR(g_motor_left.sem,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
@ -27,7 +27,7 @@ h_wheel_sensor_isr_handler(void)
gpio_acknowledge_irq(SPEED_PIN_RIGHT, GPIO_IRQ_EDGE_FALL);
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(g_motor_speed_right.sem,
xSemaphoreGiveFromISR(g_motor_right.sem,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
@ -42,8 +42,8 @@ h_wheel_sensor_isr_handler(void)
void
monitor_wheel_speed_task(void *pvParameters)
{
volatile motor_speed_t *p_motor_speed = NULL;
p_motor_speed = (motor_speed_t *)pvParameters;
volatile motor_t *p_motor = NULL;
p_motor = (motor_t *)pvParameters;
uint64_t curr_time = 0u;
uint64_t prev_time = 0u;
@ -51,7 +51,7 @@ monitor_wheel_speed_task(void *pvParameters)
for (;;)
{
if (xSemaphoreTake(p_motor_speed->sem, pdMS_TO_TICKS(100))
if (xSemaphoreTake(p_motor->sem, pdMS_TO_TICKS(100))
== pdTRUE)
{
curr_time = time_us_64();
@ -62,20 +62,56 @@ monitor_wheel_speed_task(void *pvParameters)
// distance = circumference / 20
// circumference = 2 * pi * 3.25 cm = 20.4203522483 cm
// distance = 20.4203522483 cm / 20 = 1.02101761242 cm
p_motor_speed->current_speed_cms = (float) (1.02101761242f /
(elapsed_time /
1000000.f));
p_motor->speed.current_cms
= (float) (1021017.61242f / elapsed_time);
p_motor_speed->distance += 1.02101761242f;
// printf("speed: %f cm/s\n", p_motor_speed->current_speed_cms);
p_motor->speed.distance_cm += 1.02101761242f;
}
else
{
p_motor_speed->current_speed_cms = 0.f;
// printf("stopped\n");
p_motor->speed.current_cms = 0.f;
}
}
}
// printf("distance: %f cm\n", p_motor_speed->distance);
/*!
* @brief Set the distance to travel before stopping, must be called after
* setting the speed and direction.
* @param distance_cm distance to travel in cm
*/
void
distance_to_stop(float distance_cm)
{
float initial = g_motor_right.speed.distance_cm;
printf("initial: %f\n", initial);
for (;;)
{
if (g_motor_right.speed.distance_cm - initial >= distance_cm)
{
g_motor_right.pwm.level = 0;
g_motor_left.pwm.level = 0;
break;
}
// vTaskDelay(pdMS_TO_TICKS(50));
}
}
/*!
* @brief Set the speed of the wheels
* @param pwm_level The pwm_level of the wheels, from 0 to 5000
*/
void
set_wheel_speed(uint32_t pwm_level)
{
g_motor_right.pwm.level = pwm_level;
g_motor_left.pwm.level = pwm_level;
pwm_set_chan_level(g_motor_right.pwm.slice_num,
g_motor_right.pwm.channel,
g_motor_right.pwm.level);
pwm_set_chan_level(g_motor_left.pwm.slice_num,
g_motor_left.pwm.channel,
g_motor_left.pwm.level);
}

View File

@ -4,25 +4,35 @@
#include "motor_direction.h"
#include "motor_pid.h"
#define WHEEL_SPEED_PRIO (tskIDLE_PRIORITY + 1UL)
#define WHEEL_SPEED_PRIO (tskIDLE_PRIORITY + 2UL)
#define WHEEL_CONTROL_PRIO (tskIDLE_PRIORITY + 2UL)
#define WHEEL_PID_PRIO (tskIDLE_PRIORITY + 2UL)
void
test_speed_change_task(void *p_param)
static void
motor_control_task(__unused void *p_param)
{
for (;;)
{
g_motor_speed_left.target_speed_cms = 15.0f;
g_motor_speed_right.target_speed_cms = 15.0f;
vTaskDelay(pdMS_TO_TICKS(5000));
set_wheel_direction(DIRECTION_FORWARD);
set_wheel_speed(3000u);
distance_to_stop(30);
// g_motor_speed_left.target_speed_cms = 20.0f;
// g_motor_speed_right.target_speed_cms = 20.0f;
// vTaskDelay(pdMS_TO_TICKS(5000));
set_wheel_direction(DIRECTION_BACKWARD);
set_wheel_speed(3000u);
distance_to_stop(30);
g_motor_speed_left.target_speed_cms = 0.0f;
g_motor_speed_right.target_speed_cms = 0.0f;
vTaskDelay(pdMS_TO_TICKS(5000));
turn_wheel(DIRECTION_LEFT);
set_wheel_direction(DIRECTION_FORWARD);
set_wheel_speed(3000u);
distance_to_stop(30);
turn_wheel(DIRECTION_RIGHT);
set_wheel_direction(DIRECTION_FORWARD);
set_wheel_speed(3000u);
distance_to_stop(30);
set_wheel_speed(0u);
vTaskDelay(pdMS_TO_TICKS(3000));
}
}
@ -39,23 +49,18 @@ launch()
irq_set_enabled(IO_IRQ_BANK0, true);
// set_wheel_direction(DIRECTION_FORWARD);
// set_wheel_speed(3000);
// Left wheel
//
// TaskHandle_t h_monitor_left_wheel_speed_task_handle = NULL;
// xTaskCreate(monitor_wheel_speed_task,
// "monitor_left_wheel_speed_task",
// configMINIMAL_STACK_SIZE,
// (void *)&g_motor_speed_left,
// WHEEL_SPEED_PRIO,
// &h_monitor_left_wheel_speed_task_handle);
// TaskHandle_t h_motor_pid_left_task_handle = NULL;
// xTaskCreate(motor_pid_task,
// "motor_pid_task",
// configMINIMAL_STACK_SIZE,
// (void *)&g_motor_speed_left,
// WHEEL_SPEED_PRIO,
// &h_motor_pid_left_task_handle);
TaskHandle_t h_monitor_left_wheel_speed_task_handle = NULL;
xTaskCreate(monitor_wheel_speed_task,
"monitor_left_wheel_speed_task",
configMINIMAL_STACK_SIZE,
(void *)&g_motor_left,
WHEEL_SPEED_PRIO,
&h_monitor_left_wheel_speed_task_handle);
// Right wheel
//
@ -63,7 +68,7 @@ launch()
xTaskCreate(monitor_wheel_speed_task,
"monitor_wheel_speed_task",
configMINIMAL_STACK_SIZE,
(void *)&g_motor_speed_right,
(void *)&g_motor_right,
WHEEL_SPEED_PRIO,
&h_monitor_right_wheel_speed_task_handle);
@ -71,19 +76,18 @@ launch()
xTaskCreate(motor_pid_task,
"motor_pid_task",
configMINIMAL_STACK_SIZE,
(void *)&g_motor_speed_right,
WHEEL_SPEED_PRIO,
(void *)&g_motor_right,
WHEEL_PID_PRIO,
&h_motor_pid_right_task_handle);
// Test speed change
//
TaskHandle_t h_test_speed_change_task_handle = NULL;
xTaskCreate(test_speed_change_task,
"test_speed_change_task",
// control task
TaskHandle_t h_motor_turning_task_handle = NULL;
xTaskCreate(motor_control_task,
"motor_turning_task",
configMINIMAL_STACK_SIZE,
NULL,
WHEEL_SPEED_PRIO,
&h_test_speed_change_task_handle);
WHEEL_CONTROL_PRIO,
&h_motor_turning_task_handle);
vTaskStartScheduler();
}
@ -93,11 +97,10 @@ main(void)
{
stdio_usb_init();
sleep_ms(2000);
sleep_ms(4000);
printf("Test started!\n");
motor_init();
set_wheel_direction(DIRECTION_LEFT_FORWARD | DIRECTION_RIGHT_FORWARD);
launch();

View File

@ -109,6 +109,8 @@ main (void)
line_sensor_setup();
init_ultrasonic();
initialize_car_state(); // TODO: Could be common functionality, To confirm
// during Integration
launch();

View File

@ -3,89 +3,15 @@
#include "task.h"
#include <stdio.h>
#define TRIG_PIN 0
#define ECHO_PIN 1
int16_t counter = 0;
void
init_ultrasonic(void)
{
// Set up the echo pin
gpio_init(ECHO_PIN);
gpio_set_dir(ECHO_PIN, GPIO_IN);
// Set up the trigger pin
gpio_init(TRIG_PIN);
gpio_set_dir(TRIG_PIN, GPIO_OUT);
}
float
KalmanFilter(float U)
{
static float R = 10; // noise convariance can be 10, higher better smooth
static float H = 1; // Measurement Map scalar
static float Q = 10; // initial estimated convariance
static float P = 0; // initial error covariance
static float U_hat = 0; // initial estimated state
static float K = 0; // initial Kalman gain
// Predict
//
K = P * H / (H * P * H + R); // Update Kalman gain
U_hat = U_hat + K * (U - H * U_hat); // Update estimated state
// Update error covariance
//
P = (1 - K * H) * P + Q;
return U_hat;
}
void
distance_task(__unused void *params)
{
while (true)
{
vTaskDelay(1000);
// Trigger the ultrasonic sensor
gpio_put(TRIG_PIN, 1);
sleep_us(10); // Keep the trigger on for 10 microseconds
gpio_put(TRIG_PIN, 0);
// Wait for the echo pulse to start
while (gpio_get(ECHO_PIN) == 0)
tight_loop_contents();
// Measure the pulse width (time taken for the echo to return)
uint32_t start_time = time_us_32();
while (gpio_get(ECHO_PIN) == 1)
tight_loop_contents();
uint32_t end_time = time_us_32();
// Calculate the distance (in centimeters)
uint32_t pulse_duration = end_time - start_time;
float distance = pulse_duration * 0.017; // Speed of sound at ~343 m/s
// printf("Distance: %.2f cm\n", distance);
// printf("Kalman Filtered Distance: %.2f cm\n", KalmanFilter(distance));
printf("%d,%.2f,%.2f\n", counter++, distance, KalmanFilter(distance));
// If gonna bang wall
//
if (distance < 5)
{
printf("Collision Imminent!\n");
// Proc stop
//
}
}
}
#include "ultrasonic_sensor.h"
void
vLaunch(void)
{
gpio_set_irq_enabled_with_callback(ECHO_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, echo_handler);
irq_set_enabled(IO_IRQ_BANK0, true);
TaskHandle_t disttask;
xTaskCreate(distance_task,
"TestDistThread",
@ -94,8 +20,6 @@ vLaunch(void)
1,
&disttask);
// Start the tasks and timer running.
//
vTaskStartScheduler();
}
@ -104,7 +28,7 @@ main(void)
{
stdio_init_all();
init_ultrasonic();
sleep_ms(3000);
sleep_ms(1000);
vLaunch();
return 0;

View File

@ -9,40 +9,73 @@
#include "ultrasonic_init.h"
void distance_task(__unused void *params)
volatile uint32_t start_time;
volatile uint32_t end_time;
volatile bool echo_rising = false;
float
KalmanFilter(float U)
{
static float R = 10; // noise convariance can be 10, higher better smooth
static float H = 1; // Measurement Map scalar
static float Q = 10; // initial estimated convariance
static float P = 0; // initial error covariance
static float U_hat = 0; // initial estimated state
static float K = 0; // initial Kalman gain
// Predict
//
K = P * H / (H * P * H + R); // Update Kalman gain
U_hat = U_hat + K * (U - H * U_hat); // Update estimated state
// Update error covariance
//
P = (1 - K * H) * P + Q;
return U_hat;
}
void
echo_handler()
{
if (gpio_get(ECHO_PIN))
{
start_time = time_us_32();
echo_rising = true;
}
else
{
end_time = time_us_32();
echo_rising = false;
}
}
void
distance_task(__unused void *params)
{
while (true)
{
vTaskDelay(500);
vTaskDelay(1000);
// Trigger the ultrasonic sensor
gpio_put(TRIG_PIN, 1);
sleep_us(10); // Keep the trigger on for 10 microseconds
sleep_us(10);
gpio_put(TRIG_PIN, 0);
// Wait for the echo pulse to start
while (gpio_get(ECHO_PIN) == 0)
while (echo_rising)
{
tight_loop_contents();
// Measure the pulse width (time taken for the echo to return)
uint32_t start_time = time_us_32();
while (gpio_get(ECHO_PIN) == 1)
tight_loop_contents();
uint32_t end_time = time_us_32();
}
// Calculate the distance (in centimeters)
uint32_t pulse_duration = end_time - start_time;
float distance = pulse_duration * 0.017; // Speed of sound at ~343 m/s
float distance = (pulse_duration * 0.034 / 2) * 1.125; // Speed of sound in cm/us
printf("Distance: %.2f cm\n", distance);
// printf("Distance: %.2f cm\n", distance);
printf("Kalman Filtered Distance: %.2f cm\n", KalmanFilter(distance));
// If gonna bang wall
//
if (distance < 5)
{
printf("Collision Imminent!\n");
// Proc stop
//
}
}
}