diff --git a/.gitignore b/.gitignore index dc2c599..a6db7c8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ Module.symvers modules.order *.tcl~ +**built-in.a +**.dtbo \ No newline at end of file diff --git a/on_chip_RAM/Kbuild b/on_chip_RAM/Kbuild new file mode 100644 index 0000000..51927d0 --- /dev/null +++ b/on_chip_RAM/Kbuild @@ -0,0 +1,2 @@ +ccflags-y := -I$(src)/../../../../../component_library/include +obj-m := dma_test.o diff --git a/on_chip_RAM/Makefile b/on_chip_RAM/Makefile new file mode 100644 index 0000000..5aa8a55 --- /dev/null +++ b/on_chip_RAM/Makefile @@ -0,0 +1,10 @@ +KDIR ?= ~/linux-socfpga +default: driver overlay +driver: + $(MAKE) -C $(KDIR) ARCH=arm M=$(CURDIR) CROSS_COMPILE=arm-linux-gnueabihf- +overlay: + dtc -I dts -O dtb -o dma.dtbo dma.dts +clean: + $(MAKE) -C $(KDIR) ARCH=arm M=$(CURDIR) clean +help: + $(MAKE) -C $(KDIR) ARCH=arm M=$(CURDIR) help diff --git a/on_chip_RAM/custom_functions.h b/on_chip_RAM/custom_functions.h new file mode 100644 index 0000000..38e7c95 --- /dev/null +++ b/on_chip_RAM/custom_functions.h @@ -0,0 +1,173 @@ +/** @file custom_functions.h + + File containing fixed point to/from string conversions and custom strcat for drivers. + + A few functions were copy pasted into multiple device drivers. Now as long as this file + is included, those functions can be used without the need for copy paste. Also any changes made + in this file apply anywhere that function is used, vs needing to copy paste that change to all + files. These functions are based off Ray's code, but changed to be (hopefully) more readable + and better commented. + + @author Aaron Koenigsberg based off Ray's code + @date 2019 + @copyright 2019 Audio Logic + + 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. + + DeveloperName + Audio Logic + 985 Technology Blvd + Bozeman, MT 59718 + openspeech@flatearthinc.com +*/ + + +#ifndef UTIL_FUNCS_H_ +#define UTIL_FUNCS_H_ + +#include + + +#define ARBITRARY_CUTOFF_LEN 9 + +/** fp_to_string: Based off Ray's fp_to_string. Turns a uint32_t interpreted as a fixed point into a string. + +@param buf, buffer in which to fill the string. It is assumed to have enough space. If a buflen parameter were passed it would +be simple to add a check to make sure that no writing goes past the bound of the array. + +@param fp_num, the uint32_t to be interpreted as a fixed point to be translated into a string + +@param fractional_bits, the number of fractional bits for the interpretation. No consideration is made to check that it +is a sensible number. i.e. less than 32, more than 0. + +@param is_signed, whether or not to interpret the first bit as a sign. If true, the first bit is inspected then dumped. + +@param num_decimals, number of decimals to write to the string. + +@returns the length of the buffered string. +*/ +int fp_to_string(char * buf, uint32_t fp_num, size_t fractional_bits, bool is_signed, uint8_t num_decimals) { + int buf_index = 0; + int int_mag = 1; + int int_part; + int frac_part; + int i = 0; + int32_t int_mask = 0x00000000; // intMask turns into a bitstring with 0's in the location of the integer part of fp_num + for (i = 0; i < fractional_bits; i++) { + int_mask = int_mask << 1; + int_mask += 1; + } + if (is_signed) { // if it signed, need to add '-' to the buffer as well as remove that bit from the bitstring + if (fp_num & 0x80000000) { + buf[buf_index++] = '-'; + } + fp_num = fp_num & 0x7fffffff; + } + int_part = (fp_num >> fractional_bits); // shift away the fractional bits + while (int_part / int_mag > 9) { // find the magnitude of the integer part + int_mag *= 10; + } + while (int_mag > 0) { // decrement the magnitude as we move one digit at a time from 'intPart' to the string + // common int to ascii conversion, since ints are sequential in ascii + buf[buf_index++] = (char)(int_part / int_mag + '0'); + int_part %= int_mag; // remove the first digit + int_mag /= 10; // decrease by one order of magnitude + } + buf[buf_index++] = '.'; + // get rid of the integer part. Also drop the last bit, not sure why this has to happen but if it doesn't there are some errors. + // I believe that this results in ever so slightly incorrectly translated nums, but idk + frac_part = (fp_num & int_mask) >> 1; + for (i = 0; i < num_decimals; ++i) { + frac_part *= 10; // shift the digit up, (maybe related to why dropping the last bit above?) + buf[buf_index++] = (frac_part >> (fractional_bits - 1)) + '0'; // inspect the digit that moved past the point + frac_part &= int_mask >> 1; // get rid of any bits that move past the point + } + buf[buf_index] = '\0'; + return buf_index; +} + +/** set_fixed_num. Based off Ray's set_fixed_num. Converts a given string to a uint32_t interpreted as a fixed point. + +@param s, the string to be converted. + +@param num_fractional_bits, the number of fractional bits in the fixed point. No consideration is made to validate. + +@param is_signed, whether or not to interpret the string as a signed or not. + +@returns returns a uint32_t that is a fixed point representation based on the num_fractional_bits and is_signed params. +*/ +uint32_t set_fixed_num(const char * s, int num_fractional_bits, bool is_signed) { + int int_part_decimal = 0; + int frac_part_decimal = 0; + int frac_len = 0; + int frac_comp = 1; + int string_index = 0; + int point_index = 0; // point index will keep track of where the point is + bool seen_point = false; + uint32_t accumulator = 0; + int i; + // get the info from the string + while (s[string_index] != '\0') { + if (s[string_index] == '.') { // if the point is found, need to switch from int accumulating to fraction + point_index = string_index; + seen_point = true; + } + else if (string_index == 0 && s[0] == '-') { // if its the first char and its a negative sign, don't sweat + // I don't think anything needs to happen here. + } + else if (!seen_point) { + int_part_decimal *= 10; // shift digits left, then add the new digit + // common ascii to int conversion trick, since ints are sequential in ascii + int_part_decimal += (int)(s[string_index] - '0'); + } + else if (frac_len < ARBITRARY_CUTOFF_LEN) { // do not allow the len of the fraction to exceed 9. + frac_part_decimal *= 10; // shift digits left, then add the new digit + frac_part_decimal += (int)(s[string_index] - '0'); + // common ascii to int conversion trick, since ints are sequential in ascii + frac_len++; // need to keep track of the length + frac_comp *= 10; + } + else { + break; + } + string_index++; + } + + while (frac_len < ARBITRARY_CUTOFF_LEN) { // if the fraction len < 9 we want to make it 9 + frac_part_decimal *= 10; + frac_len++; + frac_comp *= 10; + } + // convert the decimal fraction to binary info. 32 is arbitrary, it is the precision of the conversion. extra + // precision beyond the number of fractional bits in the fixed point num will be truncated off. + for (i = 0; i < num_fractional_bits; i++) { + // if frac part divided by frac comp is greater than 1, a 1 should be appended to bitstring + if (frac_part_decimal / frac_comp) { + accumulator += 0x00000001; + frac_part_decimal -= frac_comp; + } + frac_part_decimal *= 2; + accumulator = accumulator << 1; + } + accumulator += int_part_decimal << num_fractional_bits; + if (is_signed && s[0] == '-') { + accumulator |= 0x80000000; // if its a signed int and theres a negative sign flip the first bit of accumulator + } + return accumulator; +} + +char *strcat2(char *dst, char *src) { + char *cp = dst; + while (*cp != '\0') { + cp++; + } + // copies from src to cp, until the null char of src is copied. + while ((*cp++ = *src++) != '\0'); + return dst; +} + +#endif diff --git a/on_chip_RAM/dma.dts b/on_chip_RAM/dma.dts new file mode 100644 index 0000000..638a812 --- /dev/null +++ b/on_chip_RAM/dma.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +&base_fpga_region { + #address-cells = <2>; + #size-cells = <1>; + ranges = < 0x00000000 0x00000000 0xc0000000 0x20000000>, + <0x00000000 0x00000000 0xc0000000 0x00010000>; + + dma_test: dma-test@000000000 { + compatible = "al,dma-test-1.0", "dev,al-dma-test"; + reg = <0x00000000 0x00000000 0x00010000>; + }; + + +}; diff --git a/on_chip_RAM/dma_test.c b/on_chip_RAM/dma_test.c new file mode 100644 index 0000000..6e6692f --- /dev/null +++ b/on_chip_RAM/dma_test.c @@ -0,0 +1,294 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for put_user */ +#include +#include "custom_functions.h" + +static struct class *cl; +static dev_t dev_num; + +/* Device struct */ +struct fe_dma_dev { + struct cdev cdev; + void __iomem *regs; + char *name; + unsigned int address; + unsigned int memory; +}; + + +#define SUCCESS 0 +#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */ +#define BUF_LEN 80 /* Max length of the message from the device */ + +static int Device_Open = 0; /* Is device open? Used to prevent multiple + access to the device */ +static char msg[BUF_LEN]; /* The msg the device will give when asked */ +static char *msg_Ptr; + +static int dma_init(void); +static void dma_exit(void); +static int dma_probe(struct platform_device *pdev); +static int dma_remove(struct platform_device *pdev); +static ssize_t dma_read(struct file *file, char *buffer, size_t len, loff_t *offset); +static ssize_t dma_write(struct file *file, const char *buffer, size_t len, loff_t *offset); +static int dma_open(struct inode *inode, struct file *file); +static int dma_release(struct inode *inode, struct file *file); + +static ssize_t name_read (struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t address_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t address_read (struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t memory_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t memory_read (struct device *dev, struct device_attribute *attr, char *buf); +typedef struct fe_dma_dev fe_dma_dev_t; +/* ID Matching struct */ +static struct of_device_id fe_dma_dt_ids[] = { + { + .compatible = "dev,al-dma-test" + }, + { } +}; + +/* Platform driver struct */ +static struct platform_driver dma_platform = { + .probe = dma_probe, + .remove = dma_remove, + .driver = { + .name = "Flat Earth DMA Driver", + .owner = THIS_MODULE, + .of_match_table = fe_dma_dt_ids + } +}; + +/* File ops struct */ +static const struct file_operations fe_dma_fops = { + .owner = THIS_MODULE, + .read = dma_read, + .write = dma_write, + .open = dma_open, + .release = dma_release, +}; + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Autogen dev, sizeof(fe_dma_dev_t), GFP_KERNEL); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + pr_err("IORESOURCE_MEM (register space) does not exist\n"); + goto bad_exit_return; } + fe_dma_devp->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(fe_dma_devp->regs)) { + ret_val = PTR_ERR(fe_dma_devp->regs); + goto bad_exit_return; + } + platform_set_drvdata(pdev, (void *)fe_dma_devp); + fe_dma_devp->name = devm_kzalloc(&pdev->dev, 50, GFP_KERNEL); + if (fe_dma_devp->name == NULL) + goto bad_mem_alloc; + strcpy(fe_dma_devp->name, (char *)pdev->name); + pr_info("%s\n", (char *)pdev->name); + status = alloc_chrdev_region(&dev_num, 0, 1, "fe_dma_"); + if (status != 0) + goto bad_alloc_chrdev_region; + + cl = class_create(THIS_MODULE, device_name); + if (cl == NULL) + goto bad_class_create; + cdev_init(&fe_dma_devp->cdev, &fe_dma_fops); + status = cdev_add(&fe_dma_devp->cdev, dev_num, 1); + if (status != 0) + goto bad_cdev_add; + + sprintf(deviceMinor, "%d", MINOR(dev_num)); + strcat(device_name, deviceMinor); + pr_info("%s\n", device_name); + device_obj = device_create_with_groups(cl, NULL, dev_num, NULL, dma_groups, device_name); + if (device_obj == NULL) + goto bad_device_create; + dev_set_drvdata(device_obj, fe_dma_devp); + pr_info("dma exit\n"); + return 0; +bad_device_create: +bad_cdev_add: + cdev_del(&fe_dma_devp->cdev); +bad_class_create: + class_destroy(cl); +bad_alloc_chrdev_region: + unregister_chrdev_region(dev_num, 1); +bad_mem_alloc: +bad_exit_return: + pr_info("dma_probe bad exit\n"); + return ret_val; +} + + +static int dma_open(struct inode *inode, struct file *file) { + static int counter = 0; + if (Device_Open) return -EBUSY; + + Device_Open++; + sprintf(msg,"I already told you %d times Hello world!\n", counter++); + msg_Ptr = msg; + //MOD_INC_USE_COUNT; + + return SUCCESS; +} + +static int dma_release(struct inode *inode, struct file *file) { + Device_Open --; /* We're now ready for our next caller */ + + /* Decrement the usage count, or else once you opened the file, you'll + never get get rid of the module. */ + //MOD_DEC_USE_COUNT; + + return 0; +} + +static ssize_t dma_read(struct file *file, char *buffer, size_t len, loff_t *offset) { + /* Number of bytes actually written to the buffer */ + int bytes_read = 0; + char temp[80]; + int count = 0, n; + /* If we're at the end of the message, return 0 signifying end of file */ + if (*msg_Ptr == 0) return 0; + + + n = sprintf(temp,"%s", msg_Ptr); + + + /* Actually put the data into the buffer */ + while (len && *msg_Ptr) { + + if(len < 5 && count < 150){ + strcat(msg_Ptr, temp); + len = len + n; + count ++; + printk("Made it in"); + } + /* The buffer is in the user data segment, not the kernel segment; + * assignment won't work. We have to use put_user which copies data from + * the kernel data segment to the user data segment. */ + put_user(*(msg_Ptr++), buffer++); + + len--; + bytes_read++; + } + + /* Most read functions return the number of bytes put into the buffer */ + return bytes_read; +} + +static ssize_t dma_write(struct file *file, const char *buffer, size_t len, loff_t *offset) { + printk ("<1>Sorry, this operation isn't supported.\n"); + return -EINVAL; +} +static ssize_t name_read(struct device *dev, struct device_attribute *attr, char *buf) { + fe_dma_dev_t * devp = (fe_dma_dev_t *)dev_get_drvdata(dev); + sprintf(buf, "%s\n", devp->name); + return strlen(buf); +} + +static ssize_t address_read(struct device *dev, struct device_attribute *attr, char *buf) { + fe_dma_dev_t * devp = (fe_dma_dev_t *)dev_get_drvdata(dev); + fp_to_string(buf, devp->address, 0, false, 1); + sprintf(buf, "%u\n", devp->address); + return strlen(buf); +} + +static ssize_t address_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + unsigned int tempValue = 0; + fe_dma_dev_t *devp = (fe_dma_dev_t *)dev_get_drvdata(dev); + + sscanf(buf, "%u", &tempValue); + devp->address = tempValue; + return count; +} + +static ssize_t memory_read(struct device *dev, struct device_attribute *attr, char *buf) { + fe_dma_dev_t * devp = (fe_dma_dev_t *)dev_get_drvdata(dev); + char temp[4]; + //int i; + sprintf(buf," "); + + //for(i = 0; i < 256; i++){ + devp->memory = ioread32((u32 *)devp->regs + devp->address); + sprintf(temp, "%u", devp->memory); + strcat(buf, temp); + // strcat(buf, " "); + //} + //sprintf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory, devp->memory); + //devp->address = devp->address + 1; + return strlen(buf); +} + +static ssize_t memory_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + unsigned int data, addr; + fe_dma_dev_t *devp = (fe_dma_dev_t *)dev_get_drvdata(dev); + sscanf(buf, "%u %u", &addr, &data); + iowrite32(data, (u32 *)devp->regs + addr); + + devp->address = addr; + return count; +} + +static int dma_remove(struct platform_device *pdev) { + fe_dma_dev_t *dev = (fe_dma_dev_t *)platform_get_drvdata(pdev); + pr_info("dma_remove enter\n"); + device_destroy(cl, dev_num); + cdev_del(&dev->cdev); + class_destroy(cl); + unregister_chrdev_region(dev_num, 2); + pr_info("dma_remove exit\n"); + return 0; +} + + +static void dma_exit(void) { + pr_info("Flat Earth dma module exit\n"); + platform_driver_unregister(&dma_platform); + pr_info("Flat Earth dma module successfully unregistered\n"); +} diff --git a/on_chip_RAM/userspace_driver/.gitignore b/on_chip_RAM/userspace_driver/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/on_chip_RAM/userspace_driver/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/on_chip_RAM/userspace_driver/CMakeLists.txt b/on_chip_RAM/userspace_driver/CMakeLists.txt new file mode 100644 index 0000000..55067f8 --- /dev/null +++ b/on_chip_RAM/userspace_driver/CMakeLists.txt @@ -0,0 +1,24 @@ +project(lws-minimal-ws-server C) +cmake_minimum_required(VERSION 2.8) +find_package(libwebsockets CONFIG REQUIRED) +list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR}) +include(CheckCSourceCompiles) +include(LwsCheckRequirements) + +set(SAMP lws-minimal-ws-server) +set(SRCS dma_perf.c) + +set(requirements 1) +require_lws_config(LWS_ROLE_WS 1 requirements) +require_lws_config(LWS_WITH_SERVER 1 requirements) + +if (requirements) + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS}) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS}) + endif() +endif() \ No newline at end of file diff --git a/on_chip_RAM/userspace_driver/README.md b/on_chip_RAM/userspace_driver/README.md new file mode 100644 index 0000000..5132072 --- /dev/null +++ b/on_chip_RAM/userspace_driver/README.md @@ -0,0 +1,30 @@ +# lws minimal ws server + +## build + +``` + $ cmake . && make +``` + +## Commandline Options + +Option|Meaning +---|--- +-d|Set logging verbosity +-s|Serve using TLS selfsigned cert (ie, connect to it with https://...) +-h|Strict Host: header checking against vhost name (localhost) and port +-v|Connection validity use 3s / 10s instead of default 5m / 5m10s + +## usage + +``` + $ ./lws-minimal-ws-server +[2018/03/04 09:30:02:7986] USER: LWS minimal ws server | visit http://localhost:7681 +[2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on +``` + +Visit http://localhost:7681 on multiple browser windows + +Text you type in any browser window is sent to all of them. + +For simplicity of this example, only one line of text is cached at the server. diff --git a/on_chip_RAM/userspace_driver/dma_perf.c b/on_chip_RAM/userspace_driver/dma_perf.c new file mode 100644 index 0000000..7a7fb40 --- /dev/null +++ b/on_chip_RAM/userspace_driver/dma_perf.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + + +#include +#include +#include +#include +#include + + +#include "minimal-ws-server.c" + +#define DEVICE_ADDRESS +#define DEVICE_MEMORY "/sys/class/fe_dma/fe_dma0/memory" + +struct wait_arg_struct { + int * continueWait; + int * ready; +}; + +extern int interrupted; +int active; + +void* persistentReadRAM(); +void* wait(void * arguments); +int readRAM(int addr, char buf[], int len); +void initializeRAM(); +int socket_connect(char *host, in_port_t port); +void * connect_to_deployment_manager(); + +static char f[16]; + +int main(int argc, const char **argv) { + pthread_t thread_id, dm_connection_thread; + const int readLen = 16; + char e[readLen]; + + initializeRAM(); + signal(SIGINT, sigint_handler); + + pthread_create(&thread_id, NULL, &persistentReadRAM, NULL); + + attach_message_receive_callback(&send_message_all_clients); + start_socket(argc, argv); + + while(interrupted == 0); + + return 0; +} + +void* persistentReadRAM(){ + pthread_t thread_id; + struct timeval time2; + struct timeval t0; + int * status, *readNow; + unsigned int i = 0, n = 0; + // float timeTemp; + int val, len; + + struct wait_arg_struct wait_args; + const int readLen = 16; + char e[readLen]; + + status = &interrupted; + wait_args.continueWait = status; + wait_args.ready = readNow; + + pthread_create(&thread_id, NULL, &wait, (void *) &wait_args); + + do{ + if(*readNow) { + *readNow = 0; + len = readRAM(n++, f, readLen); + + if(active) { + send_message_all_clients(f, len); + + } + if(i++ == 1000){ + i = 0; + } + if(n == 256){ + n = 0; + } + } + usleep(50); + } while(*status == 0); + + return NULL; +} + +void* wait(void * arguments) { + int *continueWait, *ready; + unsigned int i; + struct wait_arg_struct *args = (struct wait_arg_struct *) arguments; + continueWait = args->continueWait; + ready = args->ready; + + do { + usleep(1000 * 1000); + *ready = 1; + } while(*continueWait == 0); + + return NULL; +} + +int readRAM(int addr, char buf[], int len) { + struct timeval t0, t1; + unsigned int i; + int size; + char addr_c[8]; + int mem_fd, addr_fd; + + #ifdef DEVICE_ADDRESS + sprintf(addr_c, "%d", addr); + if( ((addr_fd = open( DEVICE_ADDRESS, ( O_WRONLY) )) == -1) ) { + printf( "ERROR: could not open \""DEVICE_ADDRESS"\"...\n" ); + return -1; + } + + #endif + + if( ((mem_fd = open( DEVICE_MEMORY, ( O_RDONLY) )) == -1) ) { + printf( "ERROR: could not open \""DEVICE_MEMORY"\"...\n" ); + return -1; + } + #ifdef DEVICE_ADDRESS + write(addr_fd, addr_c, 8); + close(addr_fd); + #endif + + size = read(mem_fd, buf, len); + if(size < len) { + buf[size] = '\0'; + } + else { + buf[len - 1] = '\0'; + } + close(mem_fd); + + return size; +} +#ifdef DEVICE_ADDRESS +void initializeRAM() { + unsigned int i; + int fd, addr_fd; + + if( ( fd = open( DEVICE_MEMORY, ( O_WRONLY) ) ) == -1 ) { + printf( "ERROR: could not open to write \""DEVICE_MEMORY"\"...\n" ); + return; + } + printf("Opened the device!\n"); + + char d[1536]; + for(i = 0; i < 512; i++){ + sprintf(d, "%u %u", i, i); + write(fd, &d, 1536); + } + + close(fd); + return; +} +#else +void initializeRAM() {} +#endif \ No newline at end of file diff --git a/on_chip_RAM/userspace_driver/minimal-ws-server.c b/on_chip_RAM/userspace_driver/minimal-ws-server.c new file mode 100644 index 0000000..8ffae63 --- /dev/null +++ b/on_chip_RAM/userspace_driver/minimal-ws-server.c @@ -0,0 +1,118 @@ +/* + * lws-minimal-ws-server + * + * Written in 2010-2019 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates the most minimal http server you can make with lws, + * with an added websocket chat server. + * + * To keep it simple, it serves stuff in the subdirectory "./mount-origin" of + * the directory it was started in. + * You can change that by changing mount.origin. + */ + +#include +#include +#include + +#define LWS_PLUGIN_STATIC +#include "protocol_lws_minimal.c" + +static struct lws_protocols protocols[] = { + { "http", lws_callback_http_dummy, 0, 0 }, + LWS_PLUGIN_PROTOCOL_MINIMAL, + { NULL, NULL, 0, 0 } /* terminator */ +}; + +static const lws_retry_bo_t retry = { + .secs_since_valid_ping = 3, + .secs_since_valid_hangup = 10, +}; + +int interrupted; + +static const struct lws_http_mount mount = { + /* .mount_next */ NULL, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .origin */ "./mount-origin", /* serve from dir */ + /* .def */ "index.html", /* default filename */ + /* .protocol */ NULL, + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ NULL, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 0, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, +}; + +void sigint_handler(int sig) +{ + interrupted = 1; +} + +int start_socket(int argc, const char **argv) +{ + struct lws_context_creation_info info; + struct lws_context *context; + const char *p; + int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE + /* for LLL_ verbosity above NOTICE to be built into lws, + * lws must have been configured and built with + * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ + /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ + /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ + /* | LLL_DEBUG */; + + signal(SIGINT, sigint_handler); + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS minimal ws server | visit http://localhost:7681 (-s = use TLS / https)\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.protocols = protocols; + info.vhost_name = "localhost"; + info.options = + LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; + +#if defined(LWS_WITH_TLS) + if (lws_cmdline_option(argc, argv, "-s")) { + lwsl_user("Server using TLS\n"); + info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.ssl_cert_filepath = "localhost-100y.cert"; + info.ssl_private_key_filepath = "localhost-100y.key"; + } +#endif + + if (lws_cmdline_option(argc, argv, "-h")) + info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK; + + if (lws_cmdline_option(argc, argv, "-v")) + info.retry_and_idle_policy = &retry; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (n >= 0 && !interrupted) + n = lws_service(context, 0); + + lws_context_destroy(context); + + return 0; +} diff --git a/on_chip_RAM/userspace_driver/mount-origin/example.js b/on_chip_RAM/userspace_driver/mount-origin/example.js new file mode 100644 index 0000000..8a5c456 --- /dev/null +++ b/on_chip_RAM/userspace_driver/mount-origin/example.js @@ -0,0 +1,66 @@ + +function get_appropriate_ws_url(extra_url) +{ + var pcol; + var u = document.URL; + + /* + * We open the websocket encrypted if this page came on an + * https:// url itself, otherwise unencrypted + */ + + if (u.substring(0, 5) === "https") { + pcol = "wss://"; + u = u.substr(8); + } else { + pcol = "ws://"; + if (u.substring(0, 4) === "http") + u = u.substr(7); + } + + u = u.split("/"); + + /* + "/xxx" bit is for IE10 workaround */ + console.log(pcol + u[0] + "/" + extra_url) + return pcol + u[0] + "/" + extra_url; +} + +function new_ws(urlpath, protocol) +{ + return new WebSocket(urlpath, protocol); +} + +document.addEventListener("DOMContentLoaded", function() { + + var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal"); + try { + ws.onopen = function() { + document.getElementById("m").disabled = 0; + document.getElementById("b").disabled = 0; + }; + + ws.onmessage =function got_packet(msg) { + document.getElementById("r").value = + document.getElementById("r").value + msg.data + "\n"; + document.getElementById("r").scrollTop = + document.getElementById("r").scrollHeight; + }; + + ws.onclose = function(){ + document.getElementById("m").disabled = 1; + document.getElementById("b").disabled = 1; + }; + } catch(exception) { + alert("

Error " + exception); + } + + function sendmsg() + { + ws.send(document.getElementById("m").value); + document.getElementById("m").value = ""; + } + + document.getElementById("b").addEventListener("click", sendmsg); + +}, false); + diff --git a/on_chip_RAM/userspace_driver/mount-origin/favicon.ico b/on_chip_RAM/userspace_driver/mount-origin/favicon.ico new file mode 100644 index 0000000..c0cc2e3 Binary files /dev/null and b/on_chip_RAM/userspace_driver/mount-origin/favicon.ico differ diff --git a/on_chip_RAM/userspace_driver/mount-origin/index.html b/on_chip_RAM/userspace_driver/mount-origin/index.html new file mode 100644 index 0000000..9c1dc9a --- /dev/null +++ b/on_chip_RAM/userspace_driver/mount-origin/index.html @@ -0,0 +1,19 @@ + + + + + + + +
+ + LWS chat minimal ws server example.
+ Chat is sent to all browsers open on this page. +
+
+
+ + + + + diff --git a/on_chip_RAM/userspace_driver/mount-origin/libwebsockets.org-logo.svg b/on_chip_RAM/userspace_driver/mount-origin/libwebsockets.org-logo.svg new file mode 100644 index 0000000..ef241b3 --- /dev/null +++ b/on_chip_RAM/userspace_driver/mount-origin/libwebsockets.org-logo.svg @@ -0,0 +1,66 @@ + + + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/on_chip_RAM/userspace_driver/mount-origin/strict-csp.svg b/on_chip_RAM/userspace_driver/mount-origin/strict-csp.svg new file mode 100644 index 0000000..cd128f1 --- /dev/null +++ b/on_chip_RAM/userspace_driver/mount-origin/strict-csp.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/on_chip_RAM/userspace_driver/protocol_lws_minimal.c b/on_chip_RAM/userspace_driver/protocol_lws_minimal.c new file mode 100644 index 0000000..f8bba00 --- /dev/null +++ b/on_chip_RAM/userspace_driver/protocol_lws_minimal.c @@ -0,0 +1,215 @@ +/* + * ws protocol handler plugin for "lws-minimal" + * + * Written in 2010-2019 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This version holds a single message at a time, which may be lost if a new + * message comes. See the minimal-ws-server-ring sample for the same thing + * but using an lws_ring ringbuffer to hold up to 8 messages at a time. + */ + +#if !defined (LWS_PLUGIN_STATIC) +#define LWS_DLL +#define LWS_INTERNAL +#include +#endif + +#include + +/* one of these created for each message */ + +struct msg { + void *payload; /* is malloc'd */ + size_t len; +}; + +/* one of these is created for each client connecting to us */ + +struct per_session_data__minimal { + struct per_session_data__minimal *pss_list; + struct lws *wsi; + int last; /* the last message number we sent */ +}; + +/* one of these is created for each vhost our protocol is used with */ + +struct per_vhost_data__minimal { + struct lws_context *context; + struct lws_vhost *vhost; + const struct lws_protocols *protocol; + + struct per_session_data__minimal *pss_list; /* linked-list of live pss*/ + + struct msg amsg; /* the one pending message... */ + int current; /* the current message number we are caching */ +}; + +typedef unsigned char* message_type; +void (*receive_pointer_function)(message_type,uint length); +void attach_message_receive_callback(const void* handler_callback) +{ + receive_pointer_function = handler_callback; +} + +/* destroys the message when everyone has had a copy of it */ + +static void +__minimal_destroy_message(void *_msg) +{ + struct msg *msg = _msg; + + free(msg->payload); + msg->payload = NULL; + msg->len = 0; +} + +struct per_vhost_data__minimal *g_vhd; + +extern int active; + +static int +callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct per_session_data__minimal *pss = + (struct per_session_data__minimal *)user; + struct per_vhost_data__minimal *vhd = + (struct per_vhost_data__minimal *) + lws_protocol_vh_priv_get(lws_get_vhost(wsi), + lws_get_protocol(wsi)); + g_vhd = vhd; + int m; + + switch (reason) { + case LWS_CALLBACK_PROTOCOL_INIT: + printf("Hello1\n"); + vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), + lws_get_protocol(wsi), + sizeof(struct per_vhost_data__minimal)); + vhd->context = lws_get_context(wsi); + vhd->protocol = lws_get_protocol(wsi); + vhd->vhost = lws_get_vhost(wsi); + break; + + case LWS_CALLBACK_ESTABLISHED: + printf("Hello2\n"); + /* add ourselves to the list of live pss held in the vhd */ + lws_ll_fwd_insert(pss, pss_list, vhd->pss_list); + pss->wsi = wsi; + pss->last = vhd->current; + active = 1; + printf("Connection made\n"); + break; + + case LWS_CALLBACK_CLOSED: + printf("Hello3\n"); + /* remove our closing pss from the list of live pss */ + lws_ll_fwd_remove(struct per_session_data__minimal, pss_list, + pss, vhd->pss_list); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + printf("Hello4\n"); + if (!vhd->amsg.payload) + break; + + if (pss->last == vhd->current) + break; + + /* notice we allowed for LWS_PRE in the payload already */ + m = lws_write(wsi, ((unsigned char *)vhd->amsg.payload) + + LWS_PRE, vhd->amsg.len, LWS_WRITE_TEXT); + if (m < (int)vhd->amsg.len) { + lwsl_err("ERROR %d writing to ws\n", m); + return -1; + } + + pss->last = vhd->current; + break; + + case LWS_CALLBACK_RECEIVE: + printf("Hello5\n"); + (receive_pointer_function)((message_type)in,len); + break; + + default: + printf("Hello6\n"); + break; + } + + return 0; +} + +void +send_message_all_clients(char* message, uint length) +{ + if (g_vhd->amsg.payload) + __minimal_destroy_message(&g_vhd->amsg); + + g_vhd->amsg.len = length; + /* notice we over-allocate by LWS_PRE */ + g_vhd->amsg.payload = malloc(LWS_PRE + length); + + if (!g_vhd->amsg.payload) { + lwsl_user("OOM: dropping\n"); + return; + } + + memcpy((char *)g_vhd->amsg.payload + LWS_PRE, message, length); + g_vhd->current++; + + /* + * let everybody know we want to write something on them + * as soon as they are ready + */ + lws_start_foreach_llp(struct per_session_data__minimal **, + ppss, g_vhd->pss_list) { + lws_callback_on_writable((*ppss)->wsi); + } lws_end_foreach_llp(ppss, pss_list); + +} + + +#define LWS_PLUGIN_PROTOCOL_MINIMAL \ + { \ + "lws-minimal", \ + callback_minimal, \ + sizeof(struct per_session_data__minimal), \ + 128, \ + 0, NULL, 0 \ + } +#if !defined (LWS_PLUGIN_STATIC) + +/* boilerplate needed if we are built as a dynamic plugin */ + +static const struct lws_protocols protocols[] = { + LWS_PLUGIN_PROTOCOL_MINIMAL +}; + +int +init_protocol_minimal(struct lws_context *context, + struct lws_plugin_capability *c) +{ + if (c->api_magic != LWS_PLUGIN_API_MAGIC) { + lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, + c->api_magic); + return 1; + } + + c->protocols = protocols; + c->count_protocols = LWS_ARRAY_SIZE(protocols); + c->extensions = NULL; + c->count_extensions = 0; + + return 0; +} + +int +destroy_protocol_minimal(struct lws_context *context) +{ + return 0; +} +#endif \ No newline at end of file